Skip to content

Commit ecc7e6c

Browse files
authored
[Clang] Handle instantiating captures in addInstantiatedCapturesToScope() (llvm#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 llvm#128175
1 parent 83ddb43 commit ecc7e6c

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

clang/lib/Sema/SemaConcept.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,9 +711,32 @@ bool Sema::addInstantiatedCapturesToScope(
711711

712712
unsigned Instantiated = 0;
713713

714+
// FIXME: This is a workaround for not having deferred lambda body
715+
// instantiation.
716+
// When transforming a lambda's body, if we encounter another call to a
717+
// nested lambda that contains a constraint expression, we add all of the
718+
// outer lambda's instantiated captures to the current instantiation scope to
719+
// facilitate constraint evaluation. However, these captures don't appear in
720+
// the CXXRecordDecl until after the lambda expression is rebuilt, so we
721+
// pull them out from the corresponding LSI.
722+
LambdaScopeInfo *InstantiatingScope = nullptr;
723+
if (LambdaPattern->capture_size() && !LambdaClass->capture_size()) {
724+
for (FunctionScopeInfo *Scope : llvm::reverse(FunctionScopes)) {
725+
auto *LSI = dyn_cast<LambdaScopeInfo>(Scope);
726+
if (!LSI ||
727+
LSI->CallOperator->getTemplateInstantiationPattern() != PatternDecl)
728+
continue;
729+
InstantiatingScope = LSI;
730+
break;
731+
}
732+
assert(InstantiatingScope);
733+
}
734+
714735
auto AddSingleCapture = [&](const ValueDecl *CapturedPattern,
715736
unsigned Index) {
716-
ValueDecl *CapturedVar = LambdaClass->getCapture(Index)->getCapturedVar();
737+
ValueDecl *CapturedVar =
738+
InstantiatingScope ? InstantiatingScope->Captures[Index].getVariable()
739+
: LambdaClass->getCapture(Index)->getCapturedVar();
717740
assert(CapturedVar->isInitCapture());
718741
Scope.InstantiatedLocal(CapturedPattern, CapturedVar);
719742
};

clang/test/SemaTemplate/concepts-lambda.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,21 @@ void test() {
307307
}
308308

309309
}
310+
311+
namespace GH128175 {
312+
313+
template <class> void f() {
314+
[i{0}] {
315+
[&] {
316+
[&] {
317+
[]()
318+
requires true
319+
{}();
320+
}();
321+
}();
322+
}();
323+
}
324+
325+
template void f<int>();
326+
327+
}

0 commit comments

Comments
 (0)