diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -257,6 +257,9 @@ (`#64172 `_) and (`#64723 `_). + Fix crash when parsing the requires clause of some generic lambdas. + (`#64689 `_`) + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. 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 @@ -7216,6 +7216,11 @@ CXXMethodDecl *CreateLambdaCallOperator(SourceRange IntroducerRange, CXXRecordDecl *Class); + + void AddTemplateParametersToLambdaCallOperator( + CXXMethodDecl *CallOperator, CXXRecordDecl *Class, + TemplateParameterList *TemplateParams); + void CompleteLambdaCallOperator( CXXMethodDecl *Method, SourceLocation LambdaLoc, SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause, 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 @@ -912,6 +912,17 @@ return Method; } +void Sema::AddTemplateParametersToLambdaCallOperator( + CXXMethodDecl *CallOperator, CXXRecordDecl *Class, + TemplateParameterList *TemplateParams) { + assert(TemplateParams && "no template parameters"); + FunctionTemplateDecl *TemplateMethod = FunctionTemplateDecl::Create( + Context, Class, CallOperator->getLocation(), CallOperator->getDeclName(), + TemplateParams, CallOperator); + TemplateMethod->setAccess(AS_public); + CallOperator->setDescribedFunctionTemplate(TemplateMethod); +} + void Sema::CompleteLambdaCallOperator( CXXMethodDecl *Method, SourceLocation LambdaLoc, SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause, @@ -930,11 +941,11 @@ DeclContext *DC = Method->getLexicalDeclContext(); Method->setLexicalDeclContext(LSI->Lambda); if (TemplateParams) { - FunctionTemplateDecl *TemplateMethod = FunctionTemplateDecl::Create( - Context, LSI->Lambda, Method->getLocation(), Method->getDeclName(), - TemplateParams, Method); - TemplateMethod->setAccess(AS_public); - Method->setDescribedFunctionTemplate(TemplateMethod); + FunctionTemplateDecl *TemplateMethod = + Method->getDescribedFunctionTemplate(); + assert(TemplateMethod && + "AddTemplateParametersToLambdaCallOperator should have been called"); + LSI->Lambda->addDecl(TemplateMethod); TemplateMethod->setLexicalDeclContext(DC); } else { @@ -1262,6 +1273,17 @@ PushOnScopeChains(Param, LambdaScope, false); } + // After the parameter list, we may parse a noexcept/requires/trailing return + // type which need to know whether the call operator constiture a dependent + // context, so we need to setup the FunctionTemplateDecl of generic lambdas + // now. + TemplateParameterList *TemplateParams = + getGenericLambdaTemplateParameterList(LSI, *this); + if (TemplateParams) { + AddTemplateParametersToLambdaCallOperator(LSI->CallOperator, LSI->Lambda, + TemplateParams); + LSI->Lambda->setLambdaIsGeneric(true); + } LSI->AfterParameterList = true; } 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 @@ -13558,6 +13558,9 @@ auto TPL = getDerived().TransformTemplateParameterList( E->getTemplateParameterList()); LSI->GLTemplateParameterList = TPL; + if (TPL) + getSema().AddTemplateParametersToLambdaCallOperator(NewCallOperator, Class, + TPL); // Transform the type of the original lambda's call operator. // The transformation MUST be done in the CurrentInstantiationScope since diff --git a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp --- a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp +++ b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp @@ -70,3 +70,20 @@ } } + +namespace GH64689 { +void f(); +void foo() { + [](int) + noexcept(requires(int t) { f(); }) + -> decltype(requires(int t) { f(); }) + requires requires(int t) { f(); } + {return {};}.operator()(0); + [](auto) + noexcept(requires(int t) { f(); }) + -> decltype(requires(int t) { f(); }) + requires requires(int t) { f(); } + {return {};}(1); +} + +}