diff options
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 8 | ||||
-rw-r--r-- | clang/lib/Analysis/UninitializedValues.cpp | 2 | ||||
-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 | ||||
-rw-r--r-- | clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp | 7 | ||||
-rw-r--r-- | clang/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp | 5 | ||||
-rw-r--r-- | clang/test/SemaCXX/PR23334.cpp | 10 | ||||
-rw-r--r-- | clang/test/SemaCXX/cxx1y-generic-lambdas.cpp | 6 | ||||
-rw-r--r-- | clang/test/SemaCXX/uninitialized.cpp | 9 |
12 files changed, 255 insertions, 265 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 41b6025f5da..c38226abc67 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4794,8 +4794,12 @@ public: /// ActOnLambdaExpr - This is called when the body of a lambda expression /// was successfully completed. ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, - Scope *CurScope, - bool IsInstantiation = false); + Scope *CurScope); + + /// \brief Complete a lambda-expression having processed and attached the + /// lambda body. + ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, + sema::LambdaScopeInfo *LSI); /// \brief Define the "body" of the conversion from a lambda object to a /// function pointer. diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp index 3c7bc4ea297..f2f791957aa 100644 --- a/clang/lib/Analysis/UninitializedValues.cpp +++ b/clang/lib/Analysis/UninitializedValues.cpp @@ -36,7 +36,7 @@ using namespace clang; static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() && !vd->isExceptionVariable() && !vd->isInitCapture() && - vd->getDeclContext() == dc) { + !vd->isImplicit() && vd->getDeclContext() == dc) { QualType ty = vd->getType(); return ty->isScalarType() || ty->isVectorType() || ty->isRecordType(); } 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> diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp index 647c76d604e..872248e77e6 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp @@ -24,7 +24,6 @@ template<typename T> struct Boom { Boom(const Boom&) { T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \ - // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} \ // expected-error{{cannot initialize a variable of type 'double *' with an rvalue of type 'int'}} } void tickle() const; @@ -34,9 +33,11 @@ void odr_used(P &p, Boom<int> boom_int, Boom<float> boom_float, Boom<double> boom_double) { const std::type_info &ti1 = typeid([=,&p]() -> P& { boom_int.tickle(); return p; }()); // expected-note{{in instantiation of member function 'Boom<int>::Boom' requested here}} + // This does not cause the instantiation of the Boom copy constructor, + // because the copy-initialization of the capture of boom_float occurs in an + // unevaluated operand. const std::type_info &ti2 - = typeid([=]() -> int { boom_float.tickle(); return 0; }()); // expected-error{{lambda expression in an unevaluated operand}} \ - // expected-note{{in instantiation of member function 'Boom<float>::Boom' requested here}} + = typeid([=]() -> int { boom_float.tickle(); return 0; }()); // expected-error{{lambda expression in an unevaluated operand}} auto foo = [=]() -> int { boom_double.tickle(); return 0; }; // expected-note{{in instantiation of member function 'Boom<double>::Boom' requested here}} } diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp index 90cbf02b2a6..c18bb7d1921 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp @@ -69,8 +69,7 @@ namespace p2 { template<typename T> struct Boom { Boom(const Boom&) { - T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \ - // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} + T* x = 1; // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} } void tickle() const; }; @@ -79,7 +78,7 @@ namespace p2 { void odr_used(R &r, Boom<T> boom) { const std::type_info &ti = typeid([=,&r] () -> R& { // expected-error{{lambda expression in an unevaluated operand}} - boom.tickle(); // expected-note{{in instantiation of member function}} + boom.tickle(); return r; }()); } diff --git a/clang/test/SemaCXX/PR23334.cpp b/clang/test/SemaCXX/PR23334.cpp new file mode 100644 index 00000000000..cd6b4f4551f --- /dev/null +++ b/clang/test/SemaCXX/PR23334.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-unused + +// This must be at the start of the file (the failure depends on a SmallPtrSet +// not having been reallocated yet). +void fn1() { + // expected-no-diagnostics + constexpr int kIsolationClass = 0; + const int kBytesPerConnection = 0; + [=] { kIsolationClass, kBytesPerConnection, kBytesPerConnection; }; +} diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp index 90ecf6904e5..f4c67fbba0c 100644 --- a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp +++ b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp @@ -899,8 +899,10 @@ struct X1 { int L2 = ([](auto i) { return i; })(2); void fooG(T i = ([] (auto i) { return i; })(2)) { } int BG : ([](auto i) { return i; })(3); //expected-error{{not an integral constant}}\ - //expected-note{{non-literal type}} - int arrG[([](auto i) { return i; })(3)]; //expected-error{{must have a constant size}} + //expected-note{{non-literal type}}\ + //expected-error{{inside of a constant expression}} + int arrG[([](auto i) { return i; })(3)]; //expected-error{{must have a constant size}} \ + //expected-error{{inside of a constant expression}} int (*fpG)(T) = [](auto i) { return i; }; void fooptrG(T (*fp)(char) = [](auto c) { return 0; }) { } template<class U = char> int fooG2(T (*fp)(U) = [](auto a) { return 0; }) { return 0; } diff --git a/clang/test/SemaCXX/uninitialized.cpp b/clang/test/SemaCXX/uninitialized.cpp index f02357419f5..5769a0c028c 100644 --- a/clang/test/SemaCXX/uninitialized.cpp +++ b/clang/test/SemaCXX/uninitialized.cpp @@ -1428,3 +1428,12 @@ class A { A(int (*) [7]) : a(rvalueref::notmove(a)) {} }; } + +void array_capture(bool b) { + const char fname[] = "array_capture"; + if (b) { + int unused; // expected-warning {{unused variable}} + } else { + [fname]{}; + } +} |