aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorYounan Zhang <zyn7109@gmail.com>2025-01-21 14:16:17 +0800
committerGitHub <noreply@github.com>2025-01-21 14:16:17 +0800
commitf07e5162d0e67ec980e0ea282cf294f377407b10 (patch)
tree22a13be1969bcc3b787b82802662193944f8260c /clang/lib/Sema
parent5cde6d2fdf1e2ededf10ac0a30187c3359a93828 (diff)
downloadllvm-f07e5162d0e67ec980e0ea282cf294f377407b10.zip
llvm-f07e5162d0e67ec980e0ea282cf294f377407b10.tar.gz
llvm-f07e5162d0e67ec980e0ea282cf294f377407b10.tar.bz2
[Clang] Delegate part of SetupConstraintScope's job to LambdaScopeForCallOperatorInstantiationRAII (#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
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaConcept.cpp12
-rw-r--r--clang/lib/Sema/SemaLambda.cpp28
2 files changed, 18 insertions, 22 deletions
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 539de00..6a40a59 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 0c5467c..87b3ca5 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);
}