diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-04-27 21:27:54 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-04-27 21:27:54 +0000 |
commit | c38498f0469aba6a0fb63d99ad398cdf788c5696 (patch) | |
tree | ed7df3fc6de1b03134e8350a770ac565f5824b60 /clang/lib/Sema | |
parent | 5b395243132dc3463c23daea1f215237565ce85f (diff) | |
download | bcm5719-llvm-c38498f0469aba6a0fb63d99ad398cdf788c5696.tar.gz bcm5719-llvm-c38498f0469aba6a0fb63d99ad398cdf788c5696.zip |
PR23334: Perform semantic checking of lambda capture initialization in the right context.
Previously we'd try to perform checks on the captures from the middle of
parsing the lambda's body, at the point where we detected that a variable
needed to be captured. This was wrong in a number of subtle ways. In
PR23334, we couldn't correctly handle the list of potential odr-uses
resulting from the capture, and our attempt to recover from that resulted
in a use-after-free.
We now defer building the initialization expression until we leave the lambda
body and return to the enclosing context, where the initialization does the
right thing. This patch only covers lambda-expressions, but we should apply
the same change to blocks and captured statements too.
llvm-svn: 235921
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 153 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 187 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 80 |
5 files changed, 219 insertions, 254 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 58e78387fd8..e11b4e14c58 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10587,6 +10587,23 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, Context.adjustDeducedFunctionResultType( FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); } + } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) { + auto *LSI = getCurLambda(); + if (LSI->HasImplicitReturnType) { + deduceClosureReturnType(*LSI); + + // C++11 [expr.prim.lambda]p4: + // [...] if there are no return statements in the compound-statement + // [the deduced type is] the type void + QualType RetType = + LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType; + + // Update the return type to the deduced type. + const FunctionProtoType *Proto = + FD->getType()->getAs<FunctionProtoType>(); + FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(), + Proto->getExtProtoInfo())); + } } // The only way to be included in UndefinedButUsed is if there is an diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d18aeab57a0..493ebe78269 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12534,13 +12534,11 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, } /// \brief Create a field within the lambda class for the variable -/// being captured. Handle Array captures. -static ExprResult addAsFieldToClosureType(Sema &S, - LambdaScopeInfo *LSI, - VarDecl *Var, QualType FieldType, - QualType DeclRefType, - SourceLocation Loc, - bool RefersToCapturedVariable) { +/// being captured. +static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var, + QualType FieldType, QualType DeclRefType, + SourceLocation Loc, + bool RefersToCapturedVariable) { CXXRecordDecl *Lambda = LSI->Lambda; // Build the non-static data member. @@ -12551,111 +12549,8 @@ static ExprResult addAsFieldToClosureType(Sema &S, Field->setImplicit(true); Field->setAccess(AS_private); Lambda->addDecl(Field); - - // 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. - - // Introduce a new evaluation context for the initialization, so - // that temporaries introduced as part of the capture are retained - // to be re-"exported" from the lambda expression itself. - EnterExpressionEvaluationContext scope(S, Sema::PotentiallyEvaluated); - - // C++ [expr.prim.labda]p12: - // An entity captured by a lambda-expression is odr-used (3.2) in - // the scope containing the lambda-expression. - Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, - DeclRefType, VK_LValue, Loc); - Var->setReferenced(true); - Var->markUsed(S.Context); - - // When the field has array type, create index variables for each - // dimension of the array. We use these index variables to subscript - // the source array, and other clients (e.g., CodeGen) will perform - // the necessary iteration with these index variables. - SmallVector<VarDecl *, 4> IndexVariables; - QualType BaseType = FieldType; - QualType SizeType = S.Context.getSizeType(); - LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size()); - while (const ConstantArrayType *Array - = S.Context.getAsConstantArrayType(BaseType)) { - // Create the iteration variable for this array index. - IdentifierInfo *IterationVarName = nullptr; - { - SmallString<8> Str; - llvm::raw_svector_ostream OS(Str); - OS << "__i" << IndexVariables.size(); - IterationVarName = &S.Context.Idents.get(OS.str()); - } - VarDecl *IterationVar - = VarDecl::Create(S.Context, S.CurContext, Loc, Loc, - IterationVarName, SizeType, - S.Context.getTrivialTypeSourceInfo(SizeType, Loc), - SC_None); - IndexVariables.push_back(IterationVar); - LSI->ArrayIndexVars.push_back(IterationVar); - - // Create a reference to the iteration variable. - ExprResult IterationVarRef - = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc); - assert(!IterationVarRef.isInvalid() && - "Reference to invented variable cannot fail!"); - IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get()); - assert(!IterationVarRef.isInvalid() && - "Conversion of invented variable cannot fail!"); - - // Subscript the array with this iteration variable. - ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr( - Ref, Loc, IterationVarRef.get(), Loc); - if (Subscript.isInvalid()) { - S.CleanupVarDeclMarking(); - S.DiscardCleanupsInEvaluationContext(); - return ExprError(); - } - - Ref = Subscript.get(); - BaseType = Array->getElementType(); - } - - // Construct the entity that we will be initializing. For an array, this - // will be first element in the array, which may require several levels - // of array-subscript entities. - SmallVector<InitializedEntity, 4> Entities; - Entities.reserve(1 + IndexVariables.size()); - Entities.push_back( - InitializedEntity::InitializeLambdaCapture(Var->getIdentifier(), - Field->getType(), Loc)); - for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) - Entities.push_back(InitializedEntity::InitializeElement(S.Context, - 0, - Entities.back())); - - InitializationKind InitKind - = InitializationKind::CreateDirect(Loc, Loc, Loc); - InitializationSequence Init(S, Entities.back(), InitKind, Ref); - ExprResult Result(true); - if (!Init.Diagnose(S, Entities.back(), InitKind, Ref)) - Result = Init.Perform(S, Entities.back(), InitKind, Ref); - - // 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(); - return Result; } - - /// \brief Capture the given variable in the lambda. static bool captureInLambda(LambdaScopeInfo *LSI, VarDecl *Var, @@ -12733,14 +12628,9 @@ static bool captureInLambda(LambdaScopeInfo *LSI, } // Capture this variable in the lambda. - Expr *CopyExpr = nullptr; - if (BuildAndDiagnose) { - ExprResult Result = addAsFieldToClosureType(S, LSI, Var, - CaptureType, DeclRefType, Loc, - RefersToCapturedVariable); - if (!Result.isInvalid()) - CopyExpr = Result.get(); - } + if (BuildAndDiagnose) + addAsFieldToClosureType(S, LSI, Var, CaptureType, DeclRefType, Loc, + RefersToCapturedVariable); // Compute the type of a reference to this captured variable. if (ByRef) @@ -12759,18 +12649,20 @@ static bool captureInLambda(LambdaScopeInfo *LSI, // Add the capture. if (BuildAndDiagnose) LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable, - Loc, EllipsisLoc, CaptureType, CopyExpr); + Loc, EllipsisLoc, CaptureType, /*CopyExpr=*/nullptr); return true; } -bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, - TryCaptureKind Kind, SourceLocation EllipsisLoc, - bool BuildAndDiagnose, - QualType &CaptureType, - QualType &DeclRefType, - const unsigned *const FunctionScopeIndexToStopAt) { - bool Nested = Var->isInitCapture(); +bool Sema::tryCaptureVariable( + VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind, + SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, + QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) { + // An init-capture is notionally from the context surrounding its + // declaration, but its parent DC is the lambda class. + DeclContext *VarDC = Var->getDeclContext(); + if (Var->isInitCapture()) + VarDC = VarDC->getParent(); DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt @@ -12786,9 +12678,9 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, } - // If the variable is declared in the current context (and is not an - // init-capture), there is no need to capture it. - if (!Nested && Var->getDeclContext() == DC) return true; + // If the variable is declared in the current context, there is no need to + // capture it. + if (VarDC == DC) return true; // Capture global variables if it is required to use private copy of this // variable. @@ -12806,6 +12698,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, // the variable. CaptureType = Var->getType(); DeclRefType = CaptureType.getNonReferenceType(); + bool Nested = false; bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = MaxFunctionScopesIndex; do { @@ -13006,7 +12899,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, FunctionScopesIndex--; DC = ParentDC; Explicit = false; - } while (!Var->getDeclContext()->Equals(DC)); + } while (!VarDC->Equals(DC)); // Walk back down the scope stack, (e.g. from outer lambda to inner lambda) // computing the type of the capture at each step, checking type-specific diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 147dd7ef210..80c6df0dd56 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -837,7 +837,8 @@ FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) { } void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, - Declarator &ParamInfo, Scope *CurScope) { + Declarator &ParamInfo, + Scope *CurScope) { // Determine if we're within a context where we know that the lambda will // be dependent, because there are template parameters in scope. bool KnownDependent = false; @@ -930,12 +931,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, PushDeclContext(CurScope, Method); // Build the lambda scope. - buildLambdaScope(LSI, Method, - Intro.Range, - Intro.Default, Intro.DefaultLoc, - ExplicitParams, - ExplicitResultType, - !Method->isConst()); + buildLambdaScope(LSI, Method, Intro.Range, Intro.Default, Intro.DefaultLoc, + ExplicitParams, ExplicitResultType, !Method->isConst()); // C++11 [expr.prim.lambda]p9: // A lambda-expression whose smallest enclosing scope is a block scope is a @@ -1137,7 +1134,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, bool IsInstantiation) { - LambdaScopeInfo *LSI = getCurLambda(); + LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(FunctionScopes.back()); // Leave the expression-evaluation context. DiscardCleanupsInEvaluationContext(); @@ -1379,10 +1376,109 @@ static void addBlockPointerConversion(Sema &S, Conversion->setImplicit(true); Class->addDecl(Conversion); } + +static ExprResult performLambdaVarCaptureInitialization( + Sema &S, LambdaScopeInfo::Capture &Capture, + FieldDecl *Field, + SmallVectorImpl<VarDecl *> &ArrayIndexVars, + SmallVectorImpl<unsigned> &ArrayIndexStarts) { + assert(Capture.isVariableCapture() && "not a variable capture"); + + auto *Var = Capture.getVariable(); + SourceLocation Loc = Capture.getLocation(); + + // 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. + + // C++ [expr.prim.lambda]p12: + // An entity captured by a lambda-expression is odr-used (3.2) in + // the scope containing the lambda-expression. + ExprResult RefResult = S.BuildDeclarationNameExpr( + CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var); + if (RefResult.isInvalid()) + return ExprError(); + Expr *Ref = RefResult.get(); + + QualType FieldType = Field->getType(); + + // When the variable has array type, create index variables for each + // dimension of the array. We use these index variables to subscript + // the source array, and other clients (e.g., CodeGen) will perform + // the necessary iteration with these index variables. + // + // FIXME: This is dumb. Add a proper AST representation for array + // copy-construction and use it here. + SmallVector<VarDecl *, 4> IndexVariables; + QualType BaseType = FieldType; + QualType SizeType = S.Context.getSizeType(); + ArrayIndexStarts.push_back(ArrayIndexVars.size()); + while (const ConstantArrayType *Array + = S.Context.getAsConstantArrayType(BaseType)) { + // Create the iteration variable for this array index. + IdentifierInfo *IterationVarName = nullptr; + { + SmallString<8> Str; + llvm::raw_svector_ostream OS(Str); + OS << "__i" << IndexVariables.size(); + IterationVarName = &S.Context.Idents.get(OS.str()); + } + VarDecl *IterationVar = VarDecl::Create( + S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType, + S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None); + IterationVar->setImplicit(); + IndexVariables.push_back(IterationVar); + ArrayIndexVars.push_back(IterationVar); + + // Create a reference to the iteration variable. + ExprResult IterationVarRef = + S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc); + assert(!IterationVarRef.isInvalid() && + "Reference to invented variable cannot fail!"); + IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get()); + assert(!IterationVarRef.isInvalid() && + "Conversion of invented variable cannot fail!"); + + // Subscript the array with this iteration variable. + ExprResult Subscript = + S.CreateBuiltinArraySubscriptExpr(Ref, Loc, IterationVarRef.get(), Loc); + if (Subscript.isInvalid()) + return ExprError(); + + Ref = Subscript.get(); + BaseType = Array->getElementType(); + } + + // Construct the entity that we will be initializing. For an array, this + // will be first element in the array, which may require several levels + // of array-subscript entities. + SmallVector<InitializedEntity, 4> Entities; + Entities.reserve(1 + IndexVariables.size()); + Entities.push_back(InitializedEntity::InitializeLambdaCapture( + Var->getIdentifier(), FieldType, Loc)); + for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) + Entities.push_back( + InitializedEntity::InitializeElement(S.Context, 0, Entities.back())); + + InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc); + InitializationSequence Init(S, Entities.back(), InitKind, Ref); + return Init.Perform(S, Entities.back(), InitKind, Ref); +} ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, - Scope *CurScope, - bool IsInstantiation) { + Scope *CurScope) { + LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back()); + ActOnFinishFunctionBody(LSI.CallOperator, Body); + return BuildLambdaExpr(StartLoc, Body->getLocEnd(), &LSI); +} + +ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, + LambdaScopeInfo *LSI) { // Collect information from the lambda scope. SmallVector<LambdaCapture, 4> Captures; SmallVector<Expr *, 4> CaptureInits; @@ -1398,7 +1494,6 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, SmallVector<VarDecl *, 4> ArrayIndexVars; SmallVector<unsigned, 4> ArrayIndexStarts; { - LambdaScopeInfo *LSI = getCurLambda(); CallOperator = LSI->CallOperator; Class = LSI->Lambda; IntroducerRange = LSI->IntroducerRange; @@ -1409,8 +1504,20 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, ArrayIndexVars.swap(LSI->ArrayIndexVars); ArrayIndexStarts.swap(LSI->ArrayIndexStarts); + CallOperator->setLexicalDeclContext(Class); + Decl *TemplateOrNonTemplateCallOperatorDecl = + CallOperator->getDescribedFunctionTemplate() + ? CallOperator->getDescribedFunctionTemplate() + : cast<Decl>(CallOperator); + + TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class); + Class->addDecl(TemplateOrNonTemplateCallOperatorDecl); + + PopExpressionEvaluationContext(); + // Translate captures. - for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) { + auto CurField = Class->field_begin(); + for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I, ++CurField) { LambdaScopeInfo::Capture From = LSI->Captures[I]; assert(!From.isBlockCapture() && "Cannot capture __block variables"); bool IsImplicit = I >= LSI->NumExplicitCaptures; @@ -1432,10 +1539,18 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, } VarDecl *Var = From.getVariable(); - LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; + LambdaCaptureKind Kind = From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef; Captures.push_back(LambdaCapture(From.getLocation(), IsImplicit, Kind, Var, From.getEllipsisLoc())); - CaptureInits.push_back(From.getInitExpr()); + Expr *Init = From.getInitExpr(); + if (!Init) { + auto InitResult = performLambdaVarCaptureInitialization( + *this, From, *CurField, ArrayIndexVars, ArrayIndexStarts); + if (InitResult.isInvalid()) + return ExprError(); + Init = InitResult.get(); + } + CaptureInits.push_back(Init); } switch (LSI->ImpCaptureStyle) { @@ -1458,48 +1573,6 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, } CaptureDefaultLoc = LSI->CaptureDefaultLoc; - // C++11 [expr.prim.lambda]p4: - // If a lambda-expression does not include a - // trailing-return-type, it is as if the trailing-return-type - // denotes the following type: - // - // Skip for C++1y return type deduction semantics which uses - // different machinery. - // FIXME: Refactor and Merge the return type deduction machinery. - // FIXME: Assumes current resolution to core issue 975. - if (LSI->HasImplicitReturnType && !getLangOpts().CPlusPlus14) { - deduceClosureReturnType(*LSI); - - // - if there are no return statements in the - // compound-statement, or all return statements return - // either an expression of type void or no expression or - // braced-init-list, the type void; - if (LSI->ReturnType.isNull()) { - LSI->ReturnType = Context.VoidTy; - } - - // Create a function type with the inferred return type. - const FunctionProtoType *Proto - = CallOperator->getType()->getAs<FunctionProtoType>(); - QualType FunctionTy = Context.getFunctionType( - LSI->ReturnType, Proto->getParamTypes(), Proto->getExtProtoInfo()); - CallOperator->setType(FunctionTy); - } - // C++ [expr.prim.lambda]p7: - // The lambda-expression's compound-statement yields the - // function-body (8.4) of the function call operator [...]. - ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation); - CallOperator->setLexicalDeclContext(Class); - Decl *TemplateOrNonTemplateCallOperatorDecl = - CallOperator->getDescribedFunctionTemplate() - ? CallOperator->getDescribedFunctionTemplate() - : cast<Decl>(CallOperator); - - TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class); - Class->addDecl(TemplateOrNonTemplateCallOperatorDecl); - - PopExpressionEvaluationContext(); - // C++11 [expr.prim.lambda]p6: // The closure type for a lambda-expression with no lambda-capture // has a public non-virtual non-explicit const conversion function @@ -1534,7 +1607,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, - ArrayIndexStarts, Body->getLocEnd(), + ArrayIndexStarts, EndLoc, ContainsUnexpandedParameterPack); if (!CurContext->isDependentContext()) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index f93a848b74f..eec13c581d4 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -714,6 +714,20 @@ namespace { } void transformedLocalDecl(Decl *Old, Decl *New) { + // If we've instantiated the call operator of a lambda or the call + // operator template of a generic lambda, update the "instantiation of" + // information. + auto *NewMD = dyn_cast<CXXMethodDecl>(New); + if (NewMD && isLambdaCallOperator(NewMD)) { + auto *OldMD = dyn_cast<CXXMethodDecl>(Old); + if (auto *NewTD = NewMD->getDescribedFunctionTemplate()) + NewTD->setInstantiatedFromMemberTemplate( + OldMD->getDescribedFunctionTemplate()); + else + NewMD->setInstantiationOfMemberFunction(OldMD, + TSK_ImplicitInstantiation); + } + SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New); } @@ -816,28 +830,6 @@ namespace { return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E); } - ExprResult TransformLambdaScope(LambdaExpr *E, - CXXMethodDecl *NewCallOperator, - ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) { - CXXMethodDecl *const OldCallOperator = E->getCallOperator(); - // In the generic lambda case, we set the NewTemplate to be considered - // an "instantiation" of the OldTemplate. - if (FunctionTemplateDecl *const NewCallOperatorTemplate = - NewCallOperator->getDescribedFunctionTemplate()) { - - FunctionTemplateDecl *const OldCallOperatorTemplate = - OldCallOperator->getDescribedFunctionTemplate(); - NewCallOperatorTemplate->setInstantiatedFromMemberTemplate( - OldCallOperatorTemplate); - } else - // For a non-generic lambda we set the NewCallOperator to - // be an instantiation of the OldCallOperator. - NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator, - TSK_ImplicitInstantiation); - - return inherited::TransformLambdaScope(E, NewCallOperator, - InitCaptureExprsAndTypes); - } TemplateParameterList *TransformTemplateParameterList( TemplateParameterList *OrigTPL) { if (!OrigTPL || !OrigTPL->size()) return OrigTPL; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index df0e4b316d7..704cef36d44 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -619,11 +619,6 @@ public: StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E); - - typedef std::pair<ExprResult, QualType> InitCaptureInfoTy; - /// \brief Transform the captures and body of a lambda expression. - ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator, - ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes); TemplateParameterList *TransformTemplateParameterList( TemplateParameterList *TPL) { @@ -9131,9 +9126,10 @@ ExprResult TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // Transform any init-capture expressions before entering the scope of the // lambda body, because they are not semantically within that scope. + typedef std::pair<ExprResult, QualType> InitCaptureInfoTy; SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes; InitCaptureExprsAndTypes.resize(E->explicit_capture_end() - - E->explicit_capture_begin()); + E->explicit_capture_begin()); for (LambdaExpr::capture_iterator C = E->capture_begin(), CEnd = E->capture_end(); C != CEnd; ++C) { @@ -9159,12 +9155,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { std::make_pair(NewExprInitResult, NewInitCaptureType); } - LambdaScopeInfo *LSI = getSema().PushLambdaScope(); - Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); - // Transform the template parameters, and add them to the current // instantiation scope. The null case is handled correctly. - LSI->GLTemplateParameterList = getDerived().TransformTemplateParameterList( + auto TPL = getDerived().TransformTemplateParameterList( E->getTemplateParameterList()); // Transform the type of the original lambda's call operator. @@ -9192,6 +9185,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { NewCallOpType); } + LambdaScopeInfo *LSI = getSema().PushLambdaScope(); + Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); + LSI->GLTemplateParameterList = TPL; + // Create the local class that will describe the lambda. CXXRecordDecl *Class = getSema().createLambdaClosureType(E->getIntroducerRange(), @@ -9208,34 +9205,22 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { LSI->CallOperator = NewCallOperator; getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); - - // TransformLambdaScope will manage the function scope, so we can disable the - // cleanup. - FuncScopeCleanup.disable(); - - return getDerived().TransformLambdaScope(E, NewCallOperator, - InitCaptureExprsAndTypes); -} - -template<typename Derived> -ExprResult -TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E, - CXXMethodDecl *CallOperator, - ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) { - bool Invalid = false; + getDerived().transformedLocalDecl(E->getCallOperator(), NewCallOperator); // Introduce the context of the call operator. - Sema::ContextRAII SavedContext(getSema(), CallOperator, + Sema::ContextRAII SavedContext(getSema(), NewCallOperator, /*NewThisContext*/false); - LambdaScopeInfo *const LSI = getSema().getCurLambda(); // Enter the scope of the lambda. - getSema().buildLambdaScope(LSI, CallOperator, E->getIntroducerRange(), - E->getCaptureDefault(), - E->getCaptureDefaultLoc(), - E->hasExplicitParameters(), - E->hasExplicitResultType(), - E->isMutable()); + getSema().buildLambdaScope(LSI, NewCallOperator, + E->getIntroducerRange(), + E->getCaptureDefault(), + E->getCaptureDefaultLoc(), + E->hasExplicitParameters(), + E->hasExplicitResultType(), + E->isMutable()); + + bool Invalid = false; // Transform captures. bool FinishedExplicitCaptures = false; @@ -9261,7 +9246,6 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E, // Rebuild init-captures, including the implied field declaration. if (C->isInitCapture()) { - InitCaptureInfoTy InitExprTypePair = InitCaptureExprsAndTypes[C - E->capture_begin()]; ExprResult Init = InitExprTypePair.first; @@ -9348,28 +9332,34 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E, if (!FinishedExplicitCaptures) getSema().finishLambdaExplicitCaptures(LSI); - // Enter a new evaluation context to insulate the lambda from any // cleanups from the enclosing full-expression. getSema().PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); - if (Invalid) { - getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/nullptr, - /*IsInstantiation=*/true); - return ExprError(); - } - // Instantiate the body of the lambda expression. - StmtResult Body = getDerived().TransformStmt(E->getBody()); + StmtResult Body = + Invalid ? StmtError() : getDerived().TransformStmt(E->getBody()); + + // ActOnLambda* will pop the function scope for us. + FuncScopeCleanup.disable(); + if (Body.isInvalid()) { + SavedContext.pop(); getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/nullptr, /*IsInstantiation=*/true); return ExprError(); } - return getSema().ActOnLambdaExpr(E->getLocStart(), Body.get(), - /*CurScope=*/nullptr, - /*IsInstantiation=*/true); + // Copy the LSI before ActOnFinishFunctionBody removes it. + // FIXME: This is dumb. Store the lambda information somewhere that outlives + // the call operator. + auto LSICopy = *LSI; + getSema().ActOnFinishFunctionBody(NewCallOperator, Body.get(), + /*IsInstantiation*/ true); + SavedContext.pop(); + + return getSema().BuildLambdaExpr(E->getLocStart(), Body.get()->getLocEnd(), + &LSICopy); } template<typename Derived> |