diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6849,9 +6849,17 @@ LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, bool ExplicitParams, - bool ExplicitResultType, bool Mutable); + CXXMethodDecl *CreateLambdaCallOperator(SourceRange IntroducerRange, + CXXRecordDecl *Class); + void CompleteLambdaCallOperator(CXXMethodDecl *Method, SourceLocation Loc, + Expr *TrailingRequiresClause, + TypeSourceInfo *MethodTyInfo, + ConstexprSpecKind ConstexprKind, + ArrayRef Params, + bool HasExplicitResultType); + /// Perform initialization analysis of the init-capture and perform /// any implicit conversions such as an lvalue-to-rvalue conversion if /// not being used to initialize a reference. diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -540,11 +540,9 @@ SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, - bool ExplicitParams, bool ExplicitResultType, - bool Mutable) { + bool ExplicitParams, bool Mutable) { buildLambdaScopeCaptures(LSI, CallOperator, IntroducerRange, CaptureDefault, CaptureDefaultLoc, ExplicitParams, Mutable); - buildLambdaScopeReturnType(*this, LSI, CallOperator, ExplicitResultType); } void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) { @@ -953,28 +951,76 @@ return MethodTyInfo; } -static CXXMethodDecl *CreateMethod(Sema &S, SourceRange IntroducerRange, - CXXRecordDecl *Class) { +CXXMethodDecl *Sema::CreateLambdaCallOperator(SourceRange IntroducerRange, + CXXRecordDecl *Class) { + // C++11 [expr.prim.lambda]p5: // The closure type for a lambda-expression has a public inline function // call operator (13.5.4) whose parameters and return type are described // by the lambda-expression's parameter-declaration-clause and // trailing-return-type respectively. DeclarationName MethodName = - S.Context.DeclarationNames.getCXXOperatorName(OO_Call); + Context.DeclarationNames.getCXXOperatorName(OO_Call); DeclarationNameLoc MethodNameLoc = DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange.getBegin()); CXXMethodDecl *Method = CXXMethodDecl::Create( - S.Context, Class, SourceLocation(), + Context, Class, SourceLocation(), DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), MethodNameLoc), - QualType(), nullptr, SC_None, S.getCurFPFeatures().isFPConstrained(), + QualType(), nullptr, SC_None, getCurFPFeatures().isFPConstrained(), /*isInline=*/true, ConstexprSpecKind::Unspecified, SourceLocation(), nullptr); Method->setAccess(AS_public); return Method; } +void Sema::CompleteLambdaCallOperator(CXXMethodDecl *Method, SourceLocation Loc, + Expr *TrailingRequiresClause, + TypeSourceInfo *MethodTyInfo, + ConstexprSpecKind ConstexprKind, + ArrayRef Params, + bool HasExplicitResultType) { + + LambdaScopeInfo *const LSI = getCurrentLambdaScopeUnsafe(*this); + + if (TrailingRequiresClause) + Method->setTrailingRequiresClause(TrailingRequiresClause); + + TemplateParameterList *TemplateParams = + getGenericLambdaTemplateParameterList(LSI, *this); + + auto DC = Method->getLexicalDeclContext(); + Method->setLexicalDeclContext(LSI->Lambda); + if (TemplateParams) { + FunctionTemplateDecl *const TemplateMethod = FunctionTemplateDecl::Create( + Context, LSI->Lambda, Method->getLocation(), Method->getDeclName(), + TemplateParams, Method); + TemplateMethod->setAccess(AS_public); + Method->setDescribedFunctionTemplate(TemplateMethod); + LSI->Lambda->addDecl(TemplateMethod); + TemplateMethod->setLexicalDeclContext(DC); + } else { + LSI->Lambda->addDecl(Method); + } + LSI->Lambda->setLambdaIsGeneric(TemplateParams); + LSI->Lambda->setLambdaTypeInfo(MethodTyInfo); + + Method->setLexicalDeclContext(DC); + Method->setLocation(Loc); + Method->setTypeSourceInfo(MethodTyInfo); + Method->setType(buildTypeForLambdaCallOperator(*this, LSI->Lambda, + TemplateParams, MethodTyInfo)); + Method->setConstexprKind(ConstexprKind); + if (!Params.empty()) { + CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false); + Method->setParams(Params); + for (auto P : Method->parameters()) + P->setOwningFunction(Method); + } + + buildLambdaScopeReturnType(*this, LSI, Method, HasExplicitResultType); +} + void Sema::ActOnLambdaIntroducer(LambdaIntroducer &Intro, Scope *CurrentScope) { LambdaScopeInfo *const LSI = getCurLambda(); @@ -1016,7 +1062,7 @@ // by the lambda-expression's parameter-declaration-clause and // trailing-return-type respectively. - CXXMethodDecl *Method = CreateMethod(*this, Intro.Range, Class); + CXXMethodDecl *Method = CreateLambdaCallOperator(Intro.Range, Class); LSI->CallOperator = Method; Method->setLexicalDeclContext(CurContext); @@ -1312,40 +1358,9 @@ CXXRecordDecl *Class = LSI->Lambda; CXXMethodDecl *Method = LSI->CallOperator; - if (auto *C = ParamInfo.getTrailingRequiresClause()) - Method->setTrailingRequiresClause(C); - - TemplateParameterList *TemplateParams = - getGenericLambdaTemplateParameterList(LSI, *this); - - auto DC = Method->getLexicalDeclContext(); - Method->setLexicalDeclContext(Class); - if (TemplateParams) { - FunctionTemplateDecl *const TemplateMethod = FunctionTemplateDecl::Create( - Context, Class, Method->getLocation(), Method->getDeclName(), - TemplateParams, Method); - TemplateMethod->setAccess(AS_public); - Method->setDescribedFunctionTemplate(TemplateMethod); - Class->addDecl(TemplateMethod); - TemplateMethod->setLexicalDeclContext(DC); - } else { - Class->addDecl(Method); - } - Method->setLexicalDeclContext(DC); - Class->setLambdaIsGeneric(TemplateParams); - TypeSourceInfo *MethodTyInfo = getLambdaType( *this, Intro, ParamInfo, getCurScope(), TypeLoc, ExplicitResultType); - Class->setLambdaTypeInfo(MethodTyInfo); - Method->setInnerLocStart(LambdaLoc); - Method->setLocation(Intro.Range.getBegin()); - Method->setTypeSourceInfo(MethodTyInfo); - Method->setType(buildTypeForLambdaCallOperator(*this, Class, TemplateParams, - MethodTyInfo)); - Method->setConstexprKind(ParamInfo.getDeclSpec().getConstexprSpecifier()); - buildLambdaScopeReturnType(*this, LSI, Method, ExplicitResultType); - LSI->ExplicitParams = ParamInfo.getNumTypeObjects() != 0; if (ParamInfo.isFunctionDeclarator() != 0 && @@ -1359,14 +1374,15 @@ } } - ContextRAII ManglingContext(*this, Class->getDeclContext()); + Method->setInnerLocStart(LambdaLoc); + CompleteLambdaCallOperator( + Method, Intro.Range.getBegin(), ParamInfo.getTrailingRequiresClause(), + MethodTyInfo, ParamInfo.getDeclSpec().getConstexprSpecifier(), Params, + ExplicitResultType); - CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false); + ContextRAII ManglingContext(*this, Class->getDeclContext()); - if (LSI->ExplicitParams) { - Method->setParams(Params); - CheckCXXDefaultArguments(Method); - } + CheckCXXDefaultArguments(Method); // This represents the function body for the lambda function, check if we // have to apply optnone due to a pragma. diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12966,44 +12966,6 @@ 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. - auto TPL = getDerived().TransformTemplateParameterList( - E->getTemplateParameterList()); - LSI->GLTemplateParameterList = TPL; - - // Transform the type of the original lambda's call operator. - // The transformation MUST be done in the CurrentInstantiationScope since - // it introduces a mapping of the original to the newly created - // transformed parameters. - TypeSourceInfo *NewCallOpTSI = nullptr; - { - TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); - FunctionProtoTypeLoc OldCallOpFPTL = - OldCallOpTSI->getTypeLoc().getAs(); - - TypeLocBuilder NewCallOpTLBuilder; - SmallVector ExceptionStorage; - TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. - QualType NewCallOpType = TransformFunctionProtoType( - NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(), - [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { - return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, - ExceptionStorage, Changed); - }); - if (NewCallOpType.isNull()) - return ExprError(); - NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, - NewCallOpType); - } - - // Transform the trailing requires clause - ExprResult NewTrailingRequiresClause; - if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause()) - // FIXME: Concepts: Substitution into requires clause should only happen - // when checking satisfaction. - NewTrailingRequiresClause = getDerived().TransformExpr(TRC); - // Create the local class that will describe the lambda. // FIXME: DependencyKind below is wrong when substituting inside a templated @@ -13019,10 +12981,8 @@ DependencyKind = CXXRecordDecl::LDK_NeverDependent; CXXRecordDecl *OldClass = E->getLambdaClass(); - CXXRecordDecl *Class = - getSema().createLambdaClosureType(E->getIntroducerRange(), NewCallOpTSI, - DependencyKind, E->getCaptureDefault()); - + CXXRecordDecl *Class = getSema().createLambdaClosureType( + E->getIntroducerRange(), nullptr, DependencyKind, E->getCaptureDefault()); getDerived().transformedLocalDecl(OldClass, {Class}); Optional> Mangling; @@ -13032,35 +12992,19 @@ OldClass->getDeviceLambdaManglingNumber(), OldClass->getLambdaContextDecl()); - // Build the call operator. - CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( - Class, E->getIntroducerRange(), NewCallOpTSI, - E->getCallOperator()->getEndLoc(), - NewCallOpTSI->getTypeLoc().castAs().getParams(), - E->getCallOperator()->getConstexprKind(), - NewTrailingRequiresClause.get()); - - LSI->CallOperator = NewCallOperator; + CXXMethodDecl *NewCallOperator = + getSema().CreateLambdaCallOperator(E->getIntroducerRange(), Class); + NewCallOperator->setLexicalDeclContext(getSema().CurContext); - getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); - getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); - - // Number the lambda for linkage purposes if necessary. - getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling); + // Enter the scope of the lambda. + getSema().buildLambdaScope(LSI, NewCallOperator, E->getIntroducerRange(), + E->getCaptureDefault(), E->getCaptureDefaultLoc(), + E->hasExplicitParameters(), E->isMutable()); // Introduce the context of the call operator. Sema::ContextRAII SavedContext(getSema(), NewCallOperator, /*NewThisContext*/false); - // Enter the scope of the lambda. - getSema().buildLambdaScope(LSI, NewCallOperator, - E->getIntroducerRange(), - E->getCaptureDefault(), - E->getCaptureDefaultLoc(), - E->hasExplicitParameters(), - E->hasExplicitResultType(), - E->isMutable()); - bool Invalid = false; // Transform captures. @@ -13182,6 +13126,60 @@ } getSema().finishLambdaExplicitCaptures(LSI); + // Transform the template parameters, and add them to the current + // instantiation scope. The null case is handled correctly. + auto TPL = getDerived().TransformTemplateParameterList( + E->getTemplateParameterList()); + LSI->GLTemplateParameterList = TPL; + + // Transform the type of the original lambda's call operator. + // The transformation MUST be done in the CurrentInstantiationScope since + // it introduces a mapping of the original to the newly created + // transformed parameters. + TypeSourceInfo *NewCallOpTSI = nullptr; + { + TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); + FunctionProtoTypeLoc OldCallOpFPTL = + OldCallOpTSI->getTypeLoc().getAs(); + + TypeLocBuilder NewCallOpTLBuilder; + SmallVector ExceptionStorage; + TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. + QualType NewCallOpType = TransformFunctionProtoType( + NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(), + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, + ExceptionStorage, Changed); + }); + if (NewCallOpType.isNull()) + return ExprError(); + NewCallOpTSI = + NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); + } + + // Transform the trailing requires clause + ExprResult NewTrailingRequiresClause; + if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause()) + // FIXME: Concepts: Substitution into requires clause should only happen + // when checking satisfaction. + NewTrailingRequiresClause = getDerived().TransformExpr(TRC); + + getSema().CompleteLambdaCallOperator( + NewCallOperator, E->getCallOperator()->getLocation(), + NewTrailingRequiresClause.get(), NewCallOpTSI, + E->getCallOperator()->getConstexprKind(), + NewCallOpTSI->getTypeLoc().castAs().getParams(), + E->hasExplicitResultType()); + + getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); + getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); + + { + // Number the lambda for linkage purposes if necessary. + Sema::ContextRAII ManglingContext(getSema(), Class->getDeclContext()); + getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling); + } + // FIXME: Sema's lambda-building mechanism expects us to push an expression // evaluation context even if we're not transforming the function body. getSema().PushExpressionEvaluationContext( diff --git a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp --- a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp +++ b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp @@ -163,6 +163,35 @@ [&]() requires is_same {}(); } +template +void dependent_init_capture(T x = 0) { + [ y = x + 1, x ]() mutable -> decltype(y + x) requires(is_same && is_same) { + return y; + } + (); + [ y = x + 1, x ]() -> decltype(y + x) requires(is_same && is_same) { + return y; + } + (); +} + +template +struct extract_type { + using type = T; +}; + +template +void dependent_variadic_capture(T... x) { + [... y = x, x... ](auto...) mutable -> typename extract_type::type requires((is_same && ...) && (is_same && ...)) { + return 0; + } + (x...); + [... y = x, x... ](auto...) -> typename extract_type::type requires((is_same && ...) && (is_same && ...)) { + return 0; + } + (x...); +} + void test_dependent() { int v = 0; int & r = v; @@ -170,6 +199,8 @@ dependent(v); dependent(r); dependent(cr); + dependent_init_capture(0); + dependent_variadic_capture(1, 2, 3, 4); } void test_CWG2569_tpl(auto a) {