https://github.com/0x59616e updated https://github.com/llvm/llvm-project/pull/65193:
>From 3eafb85ff74271456cba24ea5892dd5660c1d332 Mon Sep 17 00:00:00 2001 From: Sheng <ox596...@gmail.com> Date: Wed, 30 Aug 2023 11:44:23 +0800 Subject: [PATCH] [clang][Sema] Fix a bug when instantiating a lambda with requires clause Instantiating a lambda at a scope different from its definition scope will paralyze clang if the trailing require clause refers to local variables of that definition scope. This patch fixes this by re-adding the local variables to `LocalInstantiationScope`. Fixes #64462 --- clang/lib/Sema/SemaConcept.cpp | 59 ++++++++++++++++++++++++++++++++++ clang/test/SemaCXX/pr64462.cpp | 20 ++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 clang/test/SemaCXX/pr64462.cpp diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index d1fa8e7831225b7..e48e0f743927a17 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -567,6 +567,58 @@ bool Sema::addInstantiatedCapturesToScope( return false; } +static void addDeclsFromParentScope(Sema &S, FunctionDecl *FD, + LocalInstantiationScope &Scope) { + assert(isLambdaCallOperator(FD) && "FD must be a lambda call operator"); + + LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(S.getFunctionScopes().back()); + + auto captureVar = [&](VarDecl *VD) { + LSI->addCapture(VD, /*isBlock=*/false, /*isByref=*/false, + /*isNested=*/false, VD->getBeginLoc(), SourceLocation(), + VD->getType(), /*Invalid=*/false); + }; + + FD = dyn_cast<FunctionDecl>(FD->getParent()->getParent()); + + if (!FD || !FD->isTemplateInstantiation()) + return; + + FunctionDecl *Pattern = FD->getPrimaryTemplate()->getTemplatedDecl(); + + for (unsigned I = 0; I < Pattern->getNumParams(); ++I) { + ParmVarDecl *PVD = Pattern->getParamDecl(I); + if (!PVD->isParameterPack()) { + Scope.InstantiatedLocal(PVD, FD->getParamDecl(I)); + captureVar(FD->getParamDecl(I)); + continue; + } + + Scope.MakeInstantiatedLocalArgPack(PVD); + + for (ParmVarDecl *Inst : FD->parameters().drop_front(I)) { + Scope.InstantiatedLocalPackArg(PVD, Inst); + captureVar(Inst); + } + } + + for (auto *decl : Pattern->decls()) { + if (!isa<VarDecl>(decl) || isa<ParmVarDecl>(decl)) + continue; + + IdentifierInfo *II = cast<NamedDecl>(decl)->getIdentifier(); + auto it = llvm::find_if(FD->decls(), [&](Decl *inst) { + VarDecl *VD = dyn_cast<VarDecl>(inst); + return VD && VD->isLocalVarDecl() && VD->getIdentifier() == II; + }); + + assert(it != FD->decls().end() && "Cannot find the instantiated variable."); + + Scope.InstantiatedLocal(decl, *it); + captureVar(cast<VarDecl>(*it)); + } +} + bool Sema::SetupConstraintScope( FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) { @@ -684,6 +736,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, CtxToSave = CtxToSave->getNonTransparentContext(); } + const bool shouldAddDeclsFromParentScope = !CtxToSave->Encloses(CurContext); ContextRAII SavedContext{*this, CtxToSave}; LocalInstantiationScope Scope(*this, !ForOverloadResolution || isLambdaCallOperator(FD)); @@ -705,6 +758,9 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, LambdaScopeForCallOperatorInstantiationRAII LambdaScope( *this, const_cast<FunctionDecl *>(FD), *MLTAL, Scope); + if (isLambdaCallOperator(FD) && shouldAddDeclsFromParentScope) + addDeclsFromParentScope(*this, const_cast<FunctionDecl *>(FD), Scope); + return CheckConstraintSatisfaction( FD, {FD->getTrailingRequiresClause()}, *MLTAL, SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), @@ -896,6 +952,9 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( LambdaScopeForCallOperatorInstantiationRAII LambdaScope( *this, const_cast<FunctionDecl *>(Decl), *MLTAL, Scope); + if (isLambdaCallOperator(Decl)) + addDeclsFromParentScope(*this, Decl, Scope); + llvm::SmallVector<Expr *, 1> Converted; return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL, PointOfInstantiation, Satisfaction); diff --git a/clang/test/SemaCXX/pr64462.cpp b/clang/test/SemaCXX/pr64462.cpp new file mode 100644 index 000000000000000..cc8b5510d1a823a --- /dev/null +++ b/clang/test/SemaCXX/pr64462.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s + +auto c1(auto f, auto ...fs) { + constexpr bool a = true; + // expected-note@+2{{because substituted constraint expression is ill-formed: no matching function for call to 'c1'}} + // expected-note@+1{{candidate template ignored: constraints not satisfied [with auto:1 = bool}} + return [](auto) requires a && (c1(fs...)) {}; +} + +auto c2(auto f, auto ...fs) { + constexpr bool a = true; + // expected-note@+2{{because substituted constraint expression is ill-formed: no matching function for call to 'c2'}} + // expected-note@+1{{candidate function not viable: constraints not satisfied}} + return []() requires a && (c2(fs...)) {}; +} + +void foo() { + c1(true)(true); // expected-error {{no matching function for call to object of type}} + c2(true)(); // expected-error {{no matching function for call to object of type}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits