llvmbot wrote: @llvm/pr-subscribers-clang
<details> <summary>Changes</summary> Instantiating a lambda at a scope different from where it is defined will paralyze clang if the trailing require clause refers to local variables. This patch fixes this by re-adding the local variables to `LocalInstantiationScope`. Fixes #64462 -- Full diff: https://github.com/llvm/llvm-project/pull/65193.diff 2 Files Affected: - (modified) clang/lib/Sema/SemaConcept.cpp (+61) - (added) clang/test/SemaCXX/pr64462.cpp (+20) <pre> diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index d1fa8e7831225b7..45a25cdcb88c8d3 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -567,6 +567,59 @@ 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()); + FunctionDecl *Pattern = nullptr; + + if (!FD || !FD->isTemplateInstantiation()) + return; + + 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,9 +737,11 @@ 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)); + std::optional<MultiLevelTemplateArgumentList> MLTAL = SetupConstraintCheckingTemplateArgumentsAndScope( const_cast<FunctionDecl *>(FD), {}, Scope); @@ -705,6 +760,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 +954,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}} +} </pre> </details> https://github.com/llvm/llvm-project/pull/65193 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits