diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index cc8b2c3808933..23b1fc578c6f4 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -275,6 +275,10 @@ Bug Fixes to C++ Support (`#65067 `_` and `#63675 `_`) +- Clang now properly handles out of line template specializations when there is + a non-template inner-class between the function and the class template. + (`#65810 `_) + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 3b1731edec952..c723e47ffca8e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -230,15 +230,25 @@ Response HandleFunction(const FunctionDecl *Function, Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD, MultiLevelTemplateArgumentList &Result) { if (!isa(FTD->getDeclContext())) { + Result.addOuterTemplateArguments( + const_cast(FTD), + const_cast(FTD)->getInjectedTemplateArgs(), + /*Final=*/false); + NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier(); - const Type *Ty; - const TemplateSpecializationType *TSTy; - if (NNS && (Ty = NNS->getAsType()) && - (TSTy = Ty->getAs())) - Result.addOuterTemplateArguments(const_cast(FTD), - TSTy->template_arguments(), - /*Final=*/false); + + while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { + if (NNS->isInstantiationDependent()) { + if (const auto *TSTy = Ty->getAs()) + Result.addOuterTemplateArguments( + const_cast(FTD), TSTy->template_arguments(), + /*Final=*/false); + } + + NNS = NNS->getPrefix(); + } } + return Response::ChangeDecl(FTD->getLexicalDeclContext()); } diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp index 4688c28b48930..f067c02ca48f5 100644 --- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp +++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp @@ -418,3 +418,51 @@ template concept A = true; template struct X { A auto f(); }; template A auto X::f() {} } + +namespace GH65810 { +template +concept TrivialConcept = +requires(Param param) { + (void)param; +}; + +template +struct Base { + class InnerClass; +}; + +template +class Base::InnerClass { + template + requires TrivialConcept + int func(Param param) const; +}; + +template +template +requires TrivialConcept +int Base::InnerClass::func(Param param) const { + return 0; +} + +template +struct Outermost { + struct Middle { + template + struct Innermost { + template + requires TrivialConcept + int func(Param param) const; + }; + }; +}; + +template +template +template +requires TrivialConcept +int Outermost::Middle::Innermost::func(Param param) const { + return 0; +} + +} // namespace GH65810