Factor the logic for capturing variables in a lambda into its own

function; it's going to get longer soon. No functionality change.

llvm-svn: 150132
This commit is contained in:
Douglas Gregor 2012-02-09 01:56:40 +00:00
parent 6a4617bb01
commit abecb9ce3c
1 changed files with 88 additions and 82 deletions

View File

@ -9534,6 +9534,90 @@ static bool shouldAddConstForScope(CapturingScopeInfo *CSI, VarDecl *VD) {
return false;
}
/// \brief Capture the given variable in the given lambda expression.
static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
VarDecl *Var, QualType Type,
SourceLocation Loc, bool ByRef) {
CXXRecordDecl *Lambda = LSI->Lambda;
QualType FieldType;
if (ByRef) {
// C++11 [expr.prim.lambda]p15:
// An entity is captured by reference if it is implicitly or
// explicitly captured but not captured by copy. It is
// unspecified whether additional unnamed non-static data
// members are declared in the closure type for entities
// captured by reference.
FieldType = S.Context.getLValueReferenceType(Type.getNonReferenceType());
} else {
// C++11 [expr.prim.lambda]p14:
// For each entity captured by copy, an unnamed non-static
// data member is declared in the closure type. The
// declaration order of these members is unspecified. The type
// of such a data member is the type of the corresponding
// captured entity if the entity is not a reference to an
// object, or the referenced type otherwise. [Note: If the
// captured entity is a reference to a function, the
// corresponding data member is also a reference to a
// function. - end note ]
if (const ReferenceType *RefType = Type->getAs<ReferenceType>()) {
if (!RefType->getPointeeType()->isFunctionType())
FieldType = RefType->getPointeeType();
else
FieldType = Type;
} else {
FieldType = Type;
}
}
// Build the non-static data member.
FieldDecl *Field
= FieldDecl::Create(S.Context, Lambda, Loc, Loc, 0, FieldType,
S.Context.getTrivialTypeSourceInfo(FieldType, Loc),
0, false, false);
Field->setImplicit(true);
Field->setAccess(AS_private);
// C++11 [expr.prim.lambda]p21:
// When the lambda-expression is evaluated, the entities that
// are captured by copy are used to direct-initialize each
// corresponding non-static data member of the resulting closure
// object. (For array members, the array elements are
// direct-initialized in increasing subscript order.) These
// initializations are performed in the (unspecified) order in
// which the non-static data members are declared.
//
// FIXME: Introduce an initialization entity for lambda captures.
// FIXME: Totally broken for arrays.
// Introduce a new evaluation context for the initialization, so that
// temporaries introduced as part of the capture
S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
Expr *Ref = new (S.Context) DeclRefExpr(Var, Type.getNonReferenceType(),
VK_LValue, Loc);
InitializedEntity InitEntity
= InitializedEntity::InitializeMember(Field, /*Parent=*/0);
InitializationKind InitKind
= InitializationKind::CreateDirect(Loc, Loc, Loc);
InitializationSequence Init(S, InitEntity, InitKind, &Ref, 1);
ExprResult Result(true);
if (!Init.Diagnose(S, InitEntity, InitKind, &Ref, 1))
Result = Init.Perform(S, InitEntity, InitKind,
MultiExprArg(S, &Ref, 1));
// If this initialization requires any cleanups (e.g., due to a
// default argument to a copy constructor), note that for the
// lambda.
if (S.ExprNeedsCleanups)
LSI->ExprNeedsCleanups = true;
// Exit the expression evaluation context used for the capture.
S.CleanupVarDeclMarking();
S.DiscardCleanupsInEvaluationContext();
S.PopExpressionEvaluationContext();
return Result;
}
// Check if the variable needs to be captured; if so, try to perform
// the capture.
// FIXME: Add support for explicit captures.
@ -9652,88 +9736,10 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
Expr *copyExpr = 0;
const RecordType *rtype;
if (isLambda) {
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
CXXRecordDecl *Lambda = LSI->Lambda;
QualType FieldType;
if (byRef) {
// C++11 [expr.prim.lambda]p15:
// An entity is captured by reference if it is implicitly or
// explicitly captured but not captured by copy. It is
// unspecified whether additional unnamed non-static data
// members are declared in the closure type for entities
// captured by reference.
FieldType = Context.getLValueReferenceType(type.getNonReferenceType());
} else {
// C++11 [expr.prim.lambda]p14:
//
// For each entity captured by copy, an unnamed non-static
// data member is declared in the closure type. The
// declaration order of these members is unspecified. The type
// of such a data member is the type of the corresponding
// captured entity if the entity is not a reference to an
// object, or the referenced type otherwise. [Note: If the
// captured entity is a reference to a function, the
// corresponding data member is also a reference to a
// function. - end note ]
if (const ReferenceType *RefType
= type->getAs<ReferenceType>()) {
if (!RefType->getPointeeType()->isFunctionType())
FieldType = RefType->getPointeeType();
else
FieldType = type;
} else {
FieldType = type;
}
}
// Build the non-static data member.
FieldDecl *Field
= FieldDecl::Create(Context, Lambda, loc, loc, 0, FieldType,
Context.getTrivialTypeSourceInfo(FieldType, loc),
0, false, false);
Field->setImplicit(true);
Field->setAccess(AS_private);
// C++11 [expr.prim.lambda]p21:
// When the lambda-expression is evaluated, the entities that
// are captured by copy are used to direct-initialize each
// corresponding non-static data member of the resulting closure
// object. (For array members, the array elements are
// direct-initialized in increasing subscript order.) These
// initializations are performed in the (unspecified) order in
// which the non-static data members are declared.
//
// FIXME: Introduce an initialization entity for lambda captures.
// FIXME: Totally broken for arrays.
// Introduce a new evaluation context for the initialization, so that
// temporaries introduced as part of the capture
PushExpressionEvaluationContext(PotentiallyEvaluated);
Expr *Ref = new (Context) DeclRefExpr(var, type.getNonReferenceType(),
VK_LValue, loc);
InitializedEntity InitEntity
= InitializedEntity::InitializeMember(Field, /*Parent=*/0);
InitializationKind InitKind
= InitializationKind::CreateDirect(loc, loc, loc);
InitializationSequence Init(*this, InitEntity, InitKind, &Ref, 1);
if (!Init.Diagnose(*this, InitEntity, InitKind, &Ref, 1)) {
ExprResult Result = Init.Perform(*this, InitEntity, InitKind,
MultiExprArg(*this, &Ref, 1));
if (!Result.isInvalid())
copyExpr = Result.take();
}
// If this initialization requires any cleanups (e.g., due to a
// default argument to a copy constructor), note that for the
// lambda.
if (ExprNeedsCleanups)
LSI->ExprNeedsCleanups = true;
// Exit the expression evaluation context used for the capture.
CleanupVarDeclMarking();
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
ExprResult Result = captureInLambda(*this, cast<LambdaScopeInfo>(CSI),
var, type, loc, byRef);
if (!Result.isInvalid())
copyExpr = Result.take();
} else if (!byRef && getLangOptions().CPlusPlus &&
(rtype = type.getNonReferenceType()->getAs<RecordType>())) {
// The capture logic needs the destructor, so make sure we mark it.