aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r--lib/Sema/SemaExpr.cpp78
1 files changed, 72 insertions, 6 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c21979758d..f656f90ea5 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -9637,11 +9637,77 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
byRef = hasBlocksAttr || type->isReferenceType();
}
- // Build a copy expression if we are capturing by copy and the copy
- // might be non-trivial.
+ // Build a copy expression if we are capturing by copy into a
+ // block and the copy might be non-trivial.
Expr *copyExpr = 0;
const RecordType *rtype;
- if (!byRef && getLangOptions().CPlusPlus &&
+ if (isLambda) {
+ CXXRecordDecl *Lambda = cast<LambdaScopeInfo>(CSI)->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.
+ 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();
+ }
+ } else if (!byRef && getLangOptions().CPlusPlus &&
(rtype = type.getNonReferenceType()->getAs<RecordType>())) {
// The capture logic needs the destructor, so make sure we mark it.
// Usually this is unnecessary because most local variables have
@@ -9654,10 +9720,10 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
// According to the blocks spec, the capture of a variable from
// the stack requires a const copy constructor. This is not true
// of the copy/move done to move a __block variable to the heap.
- // There is no equivalent language in the C++11 specification of lambdas.
- if (isBlock)
- type.addConst();
+ type.addConst();
+ // FIXME: Add an initialized entity for lambda capture.
+ // FIXME: Won't work for arrays, although we do need this behavior.
Expr *declRef = new (Context) DeclRefExpr(var, type, VK_LValue, loc);
ExprResult result =
PerformCopyInitialization(