diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 78 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 81 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 7 |
3 files changed, 156 insertions, 10 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( diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 30b0529df9..cd2c210a39 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4895,6 +4895,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // at this point, but we need something to attach child declarations to. QualType MethodTy; TypeSourceInfo *MethodTyInfo; + bool ExplicitParams = true; if (ParamInfo.getNumTypeObjects() == 0) { // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a lambda-declarator, it is as @@ -4904,6 +4905,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, MethodTy = Context.getFunctionType(Context.DependentTy, /*Args=*/0, /*NumArgs=*/0, EPI); MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); + ExplicitParams = false; } else { assert(ParamInfo.isFunctionDeclarator() && "lambda-declarator is a function"); @@ -4967,9 +4969,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval; else if (Intro.Default == LCD_ByRef) LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref; - + LSI->IntroducerRange = Intro.Range; + LSI->ExplicitParams = ExplicitParams; LSI->Mutable = (Method->getTypeQualifiers() & Qualifiers::Const) == 0; - + // Handle explicit captures. for (llvm::SmallVector<LambdaCapture, 4>::const_iterator C = Intro.Captures.begin(), @@ -5116,8 +5119,78 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) { ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope) { - // FIXME: Implement + // Leave the expression-evaluation context. + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); + + // Leave the context of the lambda. + PopDeclContext(); + + // FIXME: End-of-lambda checking + + // Collect information from the lambda scope. + llvm::SmallVector<LambdaExpr::Capture, 4> Captures; + llvm::SmallVector<Expr *, 4> CaptureInits; + LambdaCaptureDefault CaptureDefault; + CXXRecordDecl *Class; + SourceRange IntroducerRange; + bool ExplicitParams; + { + LambdaScopeInfo *LSI = getCurLambda(); + Class = LSI->Lambda; + IntroducerRange = LSI->IntroducerRange; + ExplicitParams = LSI->ExplicitParams; + + // Translate captures. + for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) { + LambdaScopeInfo::Capture From = LSI->Captures[I]; + assert(!From.isBlockCapture() && "Cannot capture __block variables"); + bool IsImplicit = I >= LSI->NumExplicitCaptures; + + // Handle 'this' capture. + if (From.isThisCapture()) { + Captures.push_back(LambdaExpr::Capture(From.getLocation(), + IsImplicit, + LCK_This)); + CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(), + getCurrentThisType(), + /*isImplicit=*/true)); + continue; + } + + VarDecl *Var = From.getVariable(); + // FIXME: Handle pack expansions. + LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; + Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, + Kind, Var)); + CaptureInits.push_back(From.getCopyExpr()); + } + + switch (LSI->ImpCaptureStyle) { + case CapturingScopeInfo::ImpCap_None: + CaptureDefault = LCD_None; + break; + + case CapturingScopeInfo::ImpCap_LambdaByval: + CaptureDefault = LCD_ByCopy; + break; + + case CapturingScopeInfo::ImpCap_LambdaByref: + CaptureDefault = LCD_ByRef; + break; + + case CapturingScopeInfo::ImpCap_Block: + llvm_unreachable("block capture in lambda"); + break; + } + + PopFunctionScopeInfo(); + } + + Expr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, + CaptureDefault, Captures, ExplicitParams, + CaptureInits, Body->getLocEnd()); + (void)Lambda; Diag(StartLoc, diag::err_lambda_unsupported); - ActOnLambdaError(StartLoc, CurScope); return ExprError(); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f011b1b8a2..ca72bc7d26 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -7620,6 +7620,13 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( template<typename Derived> ExprResult +TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { + assert(false && "Lambda expressions cannot be instantiated (yet)"); + return ExprError(); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( CXXUnresolvedConstructExpr *E) { TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo()); |