[Clang] Handle instantiating captures in addInstantiatedCapturesToScope() (#128478)

addInstantiatedCapturesToScope() might be called when transforming a
lambda body. In this situation, it would look into all the lambda's
parents and figure out all the instantiated captures. However, the
instantiated captures are not visible from lambda's class decl until the
lambda is rebuilt (i.e. after the lambda body transform). So this patch
corrects that by also examining the LambdaScopeInfo, serving as a
workaround for not having deferred lambda body instantiation in Clang
20, to avoid regressing some real-world use cases.

Fixes #128175
This commit is contained in:
Younan Zhang
2025-02-25 14:35:07 +08:00
committed by GitHub
parent 83ddb43cad
commit ecc7e6ce4c
2 changed files with 42 additions and 1 deletions

View File

@@ -711,9 +711,32 @@ bool Sema::addInstantiatedCapturesToScope(
unsigned Instantiated = 0;
// FIXME: This is a workaround for not having deferred lambda body
// instantiation.
// When transforming a lambda's body, if we encounter another call to a
// nested lambda that contains a constraint expression, we add all of the
// outer lambda's instantiated captures to the current instantiation scope to
// facilitate constraint evaluation. However, these captures don't appear in
// the CXXRecordDecl until after the lambda expression is rebuilt, so we
// pull them out from the corresponding LSI.
LambdaScopeInfo *InstantiatingScope = nullptr;
if (LambdaPattern->capture_size() && !LambdaClass->capture_size()) {
for (FunctionScopeInfo *Scope : llvm::reverse(FunctionScopes)) {
auto *LSI = dyn_cast<LambdaScopeInfo>(Scope);
if (!LSI ||
LSI->CallOperator->getTemplateInstantiationPattern() != PatternDecl)
continue;
InstantiatingScope = LSI;
break;
}
assert(InstantiatingScope);
}
auto AddSingleCapture = [&](const ValueDecl *CapturedPattern,
unsigned Index) {
ValueDecl *CapturedVar = LambdaClass->getCapture(Index)->getCapturedVar();
ValueDecl *CapturedVar =
InstantiatingScope ? InstantiatingScope->Captures[Index].getVariable()
: LambdaClass->getCapture(Index)->getCapturedVar();
assert(CapturedVar->isInitCapture());
Scope.InstantiatedLocal(CapturedPattern, CapturedVar);
};

View File

@@ -307,3 +307,21 @@ void test() {
}
}
namespace GH128175 {
template <class> void f() {
[i{0}] {
[&] {
[&] {
[]()
requires true
{}();
}();
}();
}();
}
template void f<int>();
}