-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[Clang] Delegate part of SetupConstraintScope's job to LambdaScopeForCallOperatorInstantiationRAII #123687
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…CallOperatorInstantiationRAII 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.
@llvm/pr-subscribers-clang Author: Younan Zhang (zyn0217) ChangesNow 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 I think this also makes the structure clearer. Fixes #123441 Full diff: https://github.com/llvm/llvm-project/pull/123687.diff 5 Files Affected:
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);
+}
+
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
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 #123441