aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-02-07 10:09:13 +0000
committerDouglas Gregor <dgregor@apple.com>2012-02-07 10:09:13 +0000
commit01d08018b7cf5ce1601707cfd7a84d22015fc04e (patch)
tree26fbc3189050b39b3027ced93cc16a038386732f /lib/Sema/SemaExpr.cpp
parent1e01ac4e4b8981942514ca8e1916bccef99a7ae2 (diff)
Introduce basic ASTs for lambda expressions. This covers:
- Capturing variables by-reference and by-copy within a lambda - The representation of lambda captures - The creation of the non-static data members in the lambda class that store the captured variables - The initialization of the non-static data members from the captured variables - Pretty-printing lambda expressions There are a number of FIXMEs, both explicit and implied, including: - Creating a field for a capture of 'this' - Improved diagnostics for initialization failures when capturing variables by copy - Dealing with temporaries created during said initialization - Template instantiation - AST (de-)serialization - Binding and returning the lambda expression; turning it into a proper temporary - Lots and lots of semantic constraints - Parameter pack captures git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149977 91177308-0d34-0410-b5e6-96231b3b80d8
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(