Skip to content

[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

Merged
merged 1 commit into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 10 additions & 10 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
28 changes: 12 additions & 16 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
13 changes: 13 additions & 0 deletions clang/test/SemaTemplate/concepts-lambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

}
Loading