diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3a029e3a0e1ea..3dce7f6a8f9d5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -288,6 +288,8 @@ Bug Fixes in This Version Fixes (`#67603 `_) - Fixes a crash caused by a multidimensional array being captured by a lambda (`#67722 `_). +- Fixes a crash when instantiating a lambda with requires clause. + (`#64462 `_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5bef0335f7891..bb05c45391b54 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7383,7 +7383,8 @@ class Sema final { public: LambdaScopeForCallOperatorInstantiationRAII( Sema &SemasRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL, - LocalInstantiationScope &Scope); + LocalInstantiationScope &Scope, + bool ShouldAddDeclsFromParentScope = true); }; /// Check whether the given expression is a valid constraint expression. @@ -7409,6 +7410,11 @@ class Sema final { llvm::ContextualFoldingSet SatisfactionCache; + /// Introduce the instantiated local variables into the local + /// instantiation scope. + void addInstantiatedLocalVarsToScope(FunctionDecl *Function, + const FunctionDecl *PatternDecl, + LocalInstantiationScope &Scope); /// Introduce the instantiated function parameters into the local /// instantiation scope, and set the parameter names to those used /// in the template. diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 036548b68247b..0ef03293b46ff 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -702,8 +702,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, } ContextRAII SavedContext{*this, CtxToSave}; - LocalInstantiationScope Scope(*this, !ForOverloadResolution || - isLambdaCallOperator(FD)); + LocalInstantiationScope Scope(*this, !ForOverloadResolution); std::optional MLTAL = SetupConstraintCheckingTemplateArgumentsAndScope( const_cast(FD), {}, Scope); @@ -720,7 +719,8 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); LambdaScopeForCallOperatorInstantiationRAII LambdaScope( - *this, const_cast(FD), *MLTAL, Scope); + *this, const_cast(FD), *MLTAL, Scope, + ForOverloadResolution); return CheckConstraintSatisfaction( FD, {FD->getTrailingRequiresClause()}, *MLTAL, diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 6fd91bda61af5..421048aaff5c9 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -2296,33 +2296,55 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation, return BuildBlock; } +static FunctionDecl *getPatternFunctionDecl(FunctionDecl *FD) { + if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) { + while (FD->getInstantiatedFromMemberFunction()) + FD = FD->getInstantiatedFromMemberFunction(); + return FD; + } + + if (FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) + return FD->getInstantiatedFromDecl(); + + FunctionTemplateDecl *FTD = FD->getPrimaryTemplate(); + if (!FTD) + return nullptr; + + while (FTD->getInstantiatedFromMemberTemplate()) + FTD = FTD->getInstantiatedFromMemberTemplate(); + + return FTD->getTemplatedDecl(); +} + Sema::LambdaScopeForCallOperatorInstantiationRAII:: LambdaScopeForCallOperatorInstantiationRAII( - Sema &SemasRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL, - LocalInstantiationScope &Scope) - : FunctionScopeRAII(SemasRef) { + Sema &SemaRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL, + LocalInstantiationScope &Scope, bool ShouldAddDeclsFromParentScope) + : FunctionScopeRAII(SemaRef) { if (!isLambdaCallOperator(FD)) { FunctionScopeRAII::disable(); return; } - if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) { - FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate(); - if (const auto *FromMemTempl = - PrimaryTemplate->getInstantiatedFromMemberTemplate()) { - SemasRef.addInstantiatedCapturesToScope( - FD, FromMemTempl->getTemplatedDecl(), Scope, MLTAL); - } - } + SemaRef.RebuildLambdaScopeInfo(cast(FD)); - else if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization || - FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) { - FunctionDecl *InstantiatedFrom = - FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization - ? FD->getInstantiatedFromMemberFunction() - : FD->getInstantiatedFromDecl(); - SemasRef.addInstantiatedCapturesToScope(FD, InstantiatedFrom, Scope, MLTAL); - } + FunctionDecl *Pattern = getPatternFunctionDecl(FD); + if (Pattern) { + SemaRef.addInstantiatedCapturesToScope(FD, Pattern, Scope, MLTAL); + + FunctionDecl *ParentFD = FD; + while (ShouldAddDeclsFromParentScope) { + + ParentFD = + dyn_cast(getLambdaAwareParentOfDeclContext(ParentFD)); + Pattern = + dyn_cast(getLambdaAwareParentOfDeclContext(Pattern)); - SemasRef.RebuildLambdaScopeInfo(cast(FD)); + if (!FD || !Pattern) + break; + + SemaRef.addInstantiatedParametersToScope(ParentFD, Pattern, Scope, MLTAL); + SemaRef.addInstantiatedLocalVarsToScope(ParentFD, Pattern, Scope); + } + } } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index e4974b168482b..0b2b775f19a01 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4523,6 +4523,36 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, return NewTInfo; } +/// Introduce the instantiated local variables into the local +/// instantiation scope. +void Sema::addInstantiatedLocalVarsToScope(FunctionDecl *Function, + const FunctionDecl *PatternDecl, + LocalInstantiationScope &Scope) { + LambdaScopeInfo *LSI = cast(getFunctionScopes().back()); + + for (auto *decl : PatternDecl->decls()) { + if (!isa(decl) || isa(decl)) + continue; + + VarDecl *VD = cast(decl); + IdentifierInfo *II = VD->getIdentifier(); + + auto it = llvm::find_if(Function->decls(), [&](Decl *inst) { + VarDecl *InstVD = dyn_cast(inst); + return InstVD && InstVD->isLocalVarDecl() && + InstVD->getIdentifier() == II; + }); + + if (it == Function->decls().end()) + continue; + + Scope.InstantiatedLocal(VD, *it); + LSI->addCapture(cast(*it), /*isBlock=*/false, /*isByref=*/false, + /*isNested=*/false, VD->getLocation(), SourceLocation(), + VD->getType(), /*Invalid=*/false); + } +} + /// Introduce the instantiated function parameters into the local /// instantiation scope, and set the parameter names to those used /// in the template. diff --git a/clang/test/SemaCXX/pr64462.cpp b/clang/test/SemaCXX/pr64462.cpp new file mode 100644 index 0000000000000..7cffb3583dcd4 --- /dev/null +++ b/clang/test/SemaCXX/pr64462.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s + +auto c1(auto f, auto ...fs) { + constexpr bool a = true; + return [](auto) requires a { + constexpr bool b = true; + return []() requires a && b { + constexpr bool c = true; + return [](auto) requires a && b && c { + constexpr bool d = true; + // expected-note@+2{{because substituted constraint expression is ill-formed: no matching function for call to 'c1'}} + // expected-note@+1{{candidate function not viable: constraints not satisfied}} + return []() requires a && b && c && d && (c1(fs...)) {}; + }; + }(); + }(1); +} + +void foo() { + c1(true)(1.0)(); // expected-error{{no matching function for call to object of type}} +}