diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 8a77cbf8c9477..a7b609f7f3ce4 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -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(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); }; diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp b/clang/test/SemaTemplate/concepts-lambda.cpp index 306f86cfcb28f..dcb09c76d26b6 100644 --- a/clang/test/SemaTemplate/concepts-lambda.cpp +++ b/clang/test/SemaTemplate/concepts-lambda.cpp @@ -307,3 +307,21 @@ void test() { } } + +namespace GH128175 { + +template void f() { + [i{0}] { + [&] { + [&] { + []() + requires true + {}(); + }(); + }(); + }(); +} + +template void f(); + +}