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 @@ -6828,15 +6828,6 @@ unsigned LambdaDependencyKind, LambdaCaptureDefault CaptureDefault); - /// Start the definition of a lambda expression. - CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, - SourceRange IntroducerRange, - TypeSourceInfo *MethodType, - SourceLocation EndLoc, - ArrayRef Params, - ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause); - /// Number lambda for linkage purposes if necessary. void handleLambdaNumbering( CXXRecordDecl *Class, CXXMethodDecl *Method, @@ -6849,9 +6840,16 @@ LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, bool ExplicitParams, - bool ExplicitResultType, bool Mutable); + CXXMethodDecl *CreateLambdaCallOperator(SourceRange IntroducerRange, + CXXRecordDecl *Class); + void CompleteLambdaCallOperator( + CXXMethodDecl *Method, SourceLocation LambdaLoc, + SourceLocation CallOperatorLoc, 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 @@ -377,76 +377,6 @@ return MethodType; } -/// Start the definition of a lambda expression. -/// In this overload, we do not know the type yet -CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, - SourceRange IntroducerRange, - TypeSourceInfo *MethodTypeInfo, - SourceLocation EndLoc, - ArrayRef Params, - ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause) { - - LambdaScopeInfo *LSI = getCurLambda(); - - TemplateParameterList *TemplateParams = - getGenericLambdaTemplateParameterList(LSI, *this); - - // At this point, we may not know the type of the lambda, if we have not - // parsed a trailing return type yet - QualType MethodType = MethodTypeInfo - ? buildTypeForLambdaCallOperator( - *this, Class, TemplateParams, MethodTypeInfo) - : QualType(); - - // 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 = - Context.DeclarationNames.getCXXOperatorName(OO_Call); - DeclarationNameLoc MethodNameLoc = - DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange); - CXXMethodDecl *Method = CXXMethodDecl::Create( - Context, Class, EndLoc, - DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), - MethodNameLoc), - MethodType, MethodTypeInfo, SC_None, getCurFPFeatures().isFPConstrained(), - /*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause); - Method->setAccess(AS_public); - if (!TemplateParams) - Class->addDecl(Method); - - // Temporarily set the lexical declaration context to the current - // context, so that the Scope stack matches the lexical nesting. - Method->setLexicalDeclContext(CurContext); - // Create a function template if we have a template parameter list - FunctionTemplateDecl *const TemplateMethod = - TemplateParams - ? FunctionTemplateDecl::Create(Context, Class, Method->getLocation(), - MethodName, TemplateParams, Method) - : nullptr; - if (TemplateMethod) { - TemplateMethod->setAccess(AS_public); - Method->setDescribedFunctionTemplate(TemplateMethod); - Class->addDecl(TemplateMethod); - TemplateMethod->setLexicalDeclContext(CurContext); - } - - // Add parameters. - if (!Params.empty()) { - Method->setParams(Params); - CheckParmsForFunctionDef(Params, - /*CheckParameterNames=*/false); - - for (auto P : Method->parameters()) - P->setOwningFunction(Method); - } - - return Method; -} - void Sema::handleLambdaNumbering( CXXRecordDecl *Class, CXXMethodDecl *Method, Optional> Mangling) { @@ -517,12 +447,11 @@ } } -static void buildLambdaScopeCaptures(LambdaScopeInfo *LSI, - CXXMethodDecl *CallOperator, - SourceRange IntroducerRange, - LambdaCaptureDefault CaptureDefault, - SourceLocation CaptureDefaultLoc, - bool ExplicitParams, bool Mutable) { +void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, + SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, + bool ExplicitParams, bool Mutable) { LSI->CallOperator = CallOperator; CXXRecordDecl *LambdaClass = CallOperator->getParent(); LSI->Lambda = LambdaClass; @@ -536,17 +465,6 @@ LSI->Mutable = Mutable; } -void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, - SourceRange IntroducerRange, - LambdaCaptureDefault CaptureDefault, - SourceLocation CaptureDefaultLoc, - bool ExplicitParams, bool ExplicitResultType, - bool Mutable) { - buildLambdaScopeCaptures(LSI, CallOperator, IntroducerRange, CaptureDefault, - CaptureDefaultLoc, ExplicitParams, Mutable); - buildLambdaScopeReturnType(*this, LSI, CallOperator, ExplicitResultType); -} - void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) { LSI->finishedExplicitCaptures(); } @@ -953,28 +871,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 LambdaLoc, + SourceLocation CallOperatorLoc, 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(LambdaLoc); + Method->setInnerLocStart(CallOperatorLoc); + 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 +982,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); @@ -1297,55 +1263,24 @@ SmallVector Params; bool ExplicitResultType; - SourceLocation TypeLoc, LambdaLoc; + SourceLocation TypeLoc, CallOperatorLoc; if (ParamInfo.getNumTypeObjects() == 0) { - LambdaLoc = TypeLoc = Intro.Range.getEnd(); + CallOperatorLoc = TypeLoc = Intro.Range.getEnd(); } else { unsigned index; ParamInfo.isFunctionDeclarator(index); const auto &Object = ParamInfo.getTypeObject(index); TypeLoc = Object.Loc.isValid() ? Object.Loc : ParamInfo.getSourceRange().getEnd(); - LambdaLoc = ParamInfo.getSourceRange().getEnd(); + CallOperatorLoc = ParamInfo.getSourceRange().getEnd(); } 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 +1294,15 @@ } } - ContextRAII ManglingContext(*this, Class->getDeclContext()); + CompleteLambdaCallOperator(Method, Intro.Range.getBegin(), CallOperatorLoc, + 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(), + E->getCallOperator()->getInnerLocStart(), 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/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp @@ -43,10 +43,21 @@ }(5); } -struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}} +struct Incomplete; // expected-note 2{{forward declaration of 'Incomplete'}} void test_result_type(int N) { auto l1 = [] () -> Incomplete { }; // expected-error{{incomplete result type 'Incomplete' in lambda expression}} typedef int vla[N]; auto l2 = [] () -> vla { }; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}} } + +template +void test_result_type_tpl(int N) { + auto l1 = []() -> T {}; // expected-error{{incomplete result type 'Incomplete' in lambda expression}} + typedef int vla[N]; + auto l2 = []() -> vla {}; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}} +} + +void test_result_type_call() { + test_result_type_tpl(10); // expected-note {{requested here}} +} 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) {