Skip to content

Commit

Permalink
[Clang] Realize generic lambda call operators are dependent sooner
Browse files Browse the repository at this point in the history
When parsing a trailing return type / noexcept / constraint
of a generic lambda, we need to know that we are in a dependent
context. We currently don't because we only create a TemplateDecl
for the call operator one its fully parsed.

This patch attach a template decl to the call operator as soon
as the parameter declaration clause is parsed - the point at which
we  have collected all template parameters

Fixes #64689

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D159358
  • Loading branch information
cor3ntin committed Sep 2, 2023
1 parent f4f40c6 commit 890f11d
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 5 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ Bug Fixes to C++ Support
(`#64172 <https://github.com/llvm/llvm-project/issues/64172>`_) and
(`#64723 <https://github.com/llvm/llvm-project/issues/64723>`_).

Fix crash when parsing the requires clause of some generic lambdas.
(`#64689 <https://github.com/llvm/llvm-project/issues/64689>`_`)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an import failure of recursive friend class template.
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -7216,6 +7216,11 @@ class Sema final {

CXXMethodDecl *CreateLambdaCallOperator(SourceRange IntroducerRange,
CXXRecordDecl *Class);

void AddTemplateParametersToLambdaCallOperator(
CXXMethodDecl *CallOperator, CXXRecordDecl *Class,
TemplateParameterList *TemplateParams);

void CompleteLambdaCallOperator(
CXXMethodDecl *Method, SourceLocation LambdaLoc,
SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause,
Expand Down
32 changes: 27 additions & 5 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,17 @@ CXXMethodDecl *Sema::CreateLambdaCallOperator(SourceRange IntroducerRange,
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,
Expand All @@ -930,11 +941,11 @@ void Sema::CompleteLambdaCallOperator(
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 {
Expand Down Expand Up @@ -1262,6 +1273,17 @@ void Sema::ActOnLambdaClosureParameters(
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;
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -13558,6 +13558,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
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
Expand Down
17 changes: 17 additions & 0 deletions clang/test/SemaCXX/cxx2a-template-lambdas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,20 @@ static_assert(B<>(42) == 42);
}

}

namespace GH64689 {
void f();
void foo() {
[]<typename T>(int)
noexcept(requires(int t) { f(); })
-> decltype(requires(int t) { f(); })
requires requires(int t) { f(); }
{return {};}.operator()<int>(0);
[](auto)
noexcept(requires(int t) { f(); })
-> decltype(requires(int t) { f(); })
requires requires(int t) { f(); }
{return {};}(1);
}

}

0 comments on commit 890f11d

Please sign in to comment.