https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/123687
Now that the RAII object has a dedicate logic for handling nested lambdas, where the inner lambda could reference any captures/variables/parameters from the outer lambda, we can shift the responsibility for managing lambdas away from `SetupConstraintScope()`. I think this also makes the structure clearer. Fixes https://github.com/llvm/llvm-project/issues/123441 >From 3e6a524122d6c248e2a0daa1cd2a383e76b16330 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 21 Jan 2025 13:26:05 +0800 Subject: [PATCH] [Clang] Delegate part of SetupConstraintScope's job to LambdaScopeForCallOperatorInstantiationRAII Now that the RAII object has a dedicate logic for handling nested lambdas, where the inner lambda could reference any captures/variables/parameters from the outer lambda, we can shift the responsibility for managing lambdas away from SetupConstraintScope(). This also makes the structure clearer I think. --- clang/docs/ReleaseNotes.rst | 1 + clang/include/clang/Sema/Sema.h | 20 +++++++-------- clang/lib/Sema/SemaConcept.cpp | 12 ++++----- clang/lib/Sema/SemaLambda.cpp | 28 +++++++++------------ clang/test/SemaTemplate/concepts-lambda.cpp | 13 ++++++++++ 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b02ac467cd3a22..73c16ee0093e72 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -961,6 +961,7 @@ Bug Fixes to C++ Support - Fixed a crash caused by the incorrect construction of template arguments for CTAD alias guides when type constraints are applied. (#GH122134) - Fixed canonicalization of pack indexing types - Clang did not always recognized identical pack indexing. (#GH123033) +- Fixed a nested lambda substitution issue for constraint evaluation. (#GH123441) Bug Fixes to AST Handling diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a41f16f6dc8c9b..9fa33d6ca76ba5 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -13841,6 +13841,13 @@ class Sema final : public SemaBase { LocalInstantiationScope &Scope, const MultiLevelTemplateArgumentList &TemplateArgs); + /// Introduce the instantiated captures of the lambda into the local + /// instantiation scope. + bool addInstantiatedCapturesToScope( + FunctionDecl *Function, const FunctionDecl *PatternDecl, + LocalInstantiationScope &Scope, + const MultiLevelTemplateArgumentList &TemplateArgs); + int ParsingClassDepth = 0; class SavePendingParsedClassStateRAII { @@ -14521,16 +14528,9 @@ class Sema final : public SemaBase { // The current stack of constraint satisfactions, so we can exit-early. llvm::SmallVector<SatisfactionStackEntryTy, 10> SatisfactionStack; - /// Introduce the instantiated captures of the lambda into the local - /// instantiation scope. - bool addInstantiatedCapturesToScope( - FunctionDecl *Function, const FunctionDecl *PatternDecl, - LocalInstantiationScope &Scope, - const MultiLevelTemplateArgumentList &TemplateArgs); - - /// Used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in - /// the case of lambdas) set up the LocalInstantiationScope of the current - /// function. + /// Used by SetupConstraintCheckingTemplateArgumentsAndScope to set up the + /// LocalInstantiationScope of the current non-lambda function. For lambdas, + /// use LambdaScopeForCallOperatorInstantiationRAII. bool SetupConstraintScope(FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 539de00bd104f5..6a40a59c977d78 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -752,6 +752,9 @@ bool Sema::SetupConstraintScope( FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, const MultiLevelTemplateArgumentList &MLTAL, LocalInstantiationScope &Scope) { + assert(!isLambdaCallOperator(FD) && + "Use LambdaScopeForCallOperatorInstantiationRAII to handle lambda " + "instantiations"); if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) { FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate(); InstantiatingTemplate Inst( @@ -777,14 +780,8 @@ bool Sema::SetupConstraintScope( // If this is a member function, make sure we get the parameters that // reference the original primary template. - // We walk up the instantiated template chain so that nested lambdas get - // handled properly. - // We should only collect instantiated parameters from the primary template. - // Otherwise, we may have mismatched template parameter depth! if (FunctionTemplateDecl *FromMemTempl = PrimaryTemplate->getInstantiatedFromMemberTemplate()) { - while (FromMemTempl->getInstantiatedFromMemberTemplate()) - FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate(); if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(), Scope, MLTAL)) return true; @@ -834,6 +831,9 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope( /*RelativeToPrimary=*/true, /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); + // Lambdas are handled by LambdaScopeForCallOperatorInstantiationRAII. + if (isLambdaCallOperator(FD)) + return MLTAL; if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope)) return std::nullopt; diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 0c5467cfd54af1..87b3ca53cefaf2 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -2408,35 +2408,31 @@ Sema::LambdaScopeForCallOperatorInstantiationRAII:: if (!ShouldAddDeclsFromParentScope) return; - FunctionDecl *InnermostFD = FD, *InnermostFDPattern = FDPattern; llvm::SmallVector<std::pair<FunctionDecl *, FunctionDecl *>, 4> - ParentInstantiations; - while (true) { + InstantiationAndPatterns; + while (FDPattern && FD) { + InstantiationAndPatterns.emplace_back(FDPattern, FD); + FDPattern = dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FDPattern)); FD = dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FD)); - - if (!FDPattern || !FD) - break; - - ParentInstantiations.emplace_back(FDPattern, FD); } // Add instantiated parameters and local vars to scopes, starting from the // outermost lambda to the innermost lambda. This ordering ensures that - // parameters in inner lambdas can correctly depend on those defined - // in outer lambdas, e.g. auto L = [](auto... x) { - // return [](decltype(x)... y) { }; // `y` depends on `x` - // }; + // the outer instantiations can be found when referenced from within inner + // lambdas. + // + // auto L = [](auto... x) { + // return [](decltype(x)... y) { }; // Instantiating y needs x + // }; + // - for (const auto &[FDPattern, FD] : llvm::reverse(ParentInstantiations)) { + for (auto [FDPattern, FD] : llvm::reverse(InstantiationAndPatterns)) { SemaRef.addInstantiatedParametersToScope(FD, FDPattern, Scope, MLTAL); SemaRef.addInstantiatedLocalVarsToScope(FD, FDPattern, Scope); if (isLambdaCallOperator(FD)) SemaRef.addInstantiatedCapturesToScope(FD, FDPattern, Scope, MLTAL); } - - SemaRef.addInstantiatedCapturesToScope(InnermostFD, InnermostFDPattern, Scope, - MLTAL); } diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp b/clang/test/SemaTemplate/concepts-lambda.cpp index 829a71bc703feb..306f86cfcb28f2 100644 --- a/clang/test/SemaTemplate/concepts-lambda.cpp +++ b/clang/test/SemaTemplate/concepts-lambda.cpp @@ -294,3 +294,16 @@ void foo() { } } // namespace GH110721 + +namespace GH123441 { + +void test() { + auto L = [](auto... x) { + return [](decltype(x)... y) + requires true + {}; + }; + L(0, 1)(1, 2); +} + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits