Skip to content

Commit f07e516

Browse files
authored
[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 #123441
1 parent 5cde6d2 commit f07e516

File tree

5 files changed

+42
-32
lines changed

5 files changed

+42
-32
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,7 @@ Bug Fixes to C++ Support
965965
- Fixed a crash caused by the incorrect construction of template arguments for CTAD alias guides when type
966966
constraints are applied. (#GH122134)
967967
- Fixed canonicalization of pack indexing types - Clang did not always recognized identical pack indexing. (#GH123033)
968+
- Fixed a nested lambda substitution issue for constraint evaluation. (#GH123441)
968969

969970

970971
Bug Fixes to AST Handling

clang/include/clang/Sema/Sema.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13841,6 +13841,13 @@ class Sema final : public SemaBase {
1384113841
LocalInstantiationScope &Scope,
1384213842
const MultiLevelTemplateArgumentList &TemplateArgs);
1384313843

13844+
/// Introduce the instantiated captures of the lambda into the local
13845+
/// instantiation scope.
13846+
bool addInstantiatedCapturesToScope(
13847+
FunctionDecl *Function, const FunctionDecl *PatternDecl,
13848+
LocalInstantiationScope &Scope,
13849+
const MultiLevelTemplateArgumentList &TemplateArgs);
13850+
1384413851
int ParsingClassDepth = 0;
1384513852

1384613853
class SavePendingParsedClassStateRAII {
@@ -14521,16 +14528,9 @@ class Sema final : public SemaBase {
1452114528
// The current stack of constraint satisfactions, so we can exit-early.
1452214529
llvm::SmallVector<SatisfactionStackEntryTy, 10> SatisfactionStack;
1452314530

14524-
/// Introduce the instantiated captures of the lambda into the local
14525-
/// instantiation scope.
14526-
bool addInstantiatedCapturesToScope(
14527-
FunctionDecl *Function, const FunctionDecl *PatternDecl,
14528-
LocalInstantiationScope &Scope,
14529-
const MultiLevelTemplateArgumentList &TemplateArgs);
14530-
14531-
/// Used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in
14532-
/// the case of lambdas) set up the LocalInstantiationScope of the current
14533-
/// function.
14531+
/// Used by SetupConstraintCheckingTemplateArgumentsAndScope to set up the
14532+
/// LocalInstantiationScope of the current non-lambda function. For lambdas,
14533+
/// use LambdaScopeForCallOperatorInstantiationRAII.
1453414534
bool
1453514535
SetupConstraintScope(FunctionDecl *FD,
1453614536
std::optional<ArrayRef<TemplateArgument>> TemplateArgs,

clang/lib/Sema/SemaConcept.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,9 @@ bool Sema::SetupConstraintScope(
752752
FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
753753
const MultiLevelTemplateArgumentList &MLTAL,
754754
LocalInstantiationScope &Scope) {
755+
assert(!isLambdaCallOperator(FD) &&
756+
"Use LambdaScopeForCallOperatorInstantiationRAII to handle lambda "
757+
"instantiations");
755758
if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
756759
FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
757760
InstantiatingTemplate Inst(
@@ -777,14 +780,8 @@ bool Sema::SetupConstraintScope(
777780

778781
// If this is a member function, make sure we get the parameters that
779782
// reference the original primary template.
780-
// We walk up the instantiated template chain so that nested lambdas get
781-
// handled properly.
782-
// We should only collect instantiated parameters from the primary template.
783-
// Otherwise, we may have mismatched template parameter depth!
784783
if (FunctionTemplateDecl *FromMemTempl =
785784
PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
786-
while (FromMemTempl->getInstantiatedFromMemberTemplate())
787-
FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate();
788785
if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(),
789786
Scope, MLTAL))
790787
return true;
@@ -834,6 +831,9 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
834831
/*RelativeToPrimary=*/true,
835832
/*Pattern=*/nullptr,
836833
/*ForConstraintInstantiation=*/true);
834+
// Lambdas are handled by LambdaScopeForCallOperatorInstantiationRAII.
835+
if (isLambdaCallOperator(FD))
836+
return MLTAL;
837837
if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
838838
return std::nullopt;
839839

clang/lib/Sema/SemaLambda.cpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2408,35 +2408,31 @@ Sema::LambdaScopeForCallOperatorInstantiationRAII::
24082408
if (!ShouldAddDeclsFromParentScope)
24092409
return;
24102410

2411-
FunctionDecl *InnermostFD = FD, *InnermostFDPattern = FDPattern;
24122411
llvm::SmallVector<std::pair<FunctionDecl *, FunctionDecl *>, 4>
2413-
ParentInstantiations;
2414-
while (true) {
2412+
InstantiationAndPatterns;
2413+
while (FDPattern && FD) {
2414+
InstantiationAndPatterns.emplace_back(FDPattern, FD);
2415+
24152416
FDPattern =
24162417
dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FDPattern));
24172418
FD = dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FD));
2418-
2419-
if (!FDPattern || !FD)
2420-
break;
2421-
2422-
ParentInstantiations.emplace_back(FDPattern, FD);
24232419
}
24242420

24252421
// Add instantiated parameters and local vars to scopes, starting from the
24262422
// outermost lambda to the innermost lambda. This ordering ensures that
2427-
// parameters in inner lambdas can correctly depend on those defined
2428-
// in outer lambdas, e.g. auto L = [](auto... x) {
2429-
// return [](decltype(x)... y) { }; // `y` depends on `x`
2430-
// };
2423+
// the outer instantiations can be found when referenced from within inner
2424+
// lambdas.
2425+
//
2426+
// auto L = [](auto... x) {
2427+
// return [](decltype(x)... y) { }; // Instantiating y needs x
2428+
// };
2429+
//
24312430

2432-
for (const auto &[FDPattern, FD] : llvm::reverse(ParentInstantiations)) {
2431+
for (auto [FDPattern, FD] : llvm::reverse(InstantiationAndPatterns)) {
24332432
SemaRef.addInstantiatedParametersToScope(FD, FDPattern, Scope, MLTAL);
24342433
SemaRef.addInstantiatedLocalVarsToScope(FD, FDPattern, Scope);
24352434

24362435
if (isLambdaCallOperator(FD))
24372436
SemaRef.addInstantiatedCapturesToScope(FD, FDPattern, Scope, MLTAL);
24382437
}
2439-
2440-
SemaRef.addInstantiatedCapturesToScope(InnermostFD, InnermostFDPattern, Scope,
2441-
MLTAL);
24422438
}

clang/test/SemaTemplate/concepts-lambda.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,16 @@ void foo() {
294294
}
295295

296296
} // namespace GH110721
297+
298+
namespace GH123441 {
299+
300+
void test() {
301+
auto L = [](auto... x) {
302+
return [](decltype(x)... y)
303+
requires true
304+
{};
305+
};
306+
L(0, 1)(1, 2);
307+
}
308+
309+
}

0 commit comments

Comments
 (0)