[clang] [Clang] Delegate part of SetupConstraintScope's job to LambdaScopeForCallOperatorInstantiationRAII (PR #123687)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 20 21:35:11 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Younan Zhang (zyn0217)
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/123687.diff
5 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+1)
- (modified) clang/include/clang/Sema/Sema.h (+10-10)
- (modified) clang/lib/Sema/SemaConcept.cpp (+6-6)
- (modified) clang/lib/Sema/SemaLambda.cpp (+12-16)
- (modified) clang/test/SemaTemplate/concepts-lambda.cpp (+13)
``````````diff
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);
+}
+
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/123687
More information about the cfe-commits
mailing list