Skip to content

Commit bfddbda

Browse files
authored
Fix out of line Concept-comparisons of NestedNameSpecifiers (#65993)
As reported in GH65810, we don't properly collect ALL of the template parameters in a nested name specifier, and were only doing the 'inner level'. This patch makes sure we collect from all levels. Fixes: #65810
1 parent 91464e1 commit bfddbda

File tree

3 files changed

+69
-7
lines changed

3 files changed

+69
-7
lines changed

clang/docs/ReleaseNotes.rst

+4
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ Bug Fixes to C++ Support
275275
(`#65067 <https://github.com/llvm/llvm-project/issues/65067>`_ and
276276
`#63675 <https://github.com/llvm/llvm-project/issues/63675>`_)
277277

278+
- Clang now properly handles out of line template specializations when there is
279+
a non-template inner-class between the function and the class template.
280+
(`#65810 <https://github.com/llvm/llvm-project/issues/65810>`_)
281+
278282
Bug Fixes to AST Handling
279283
^^^^^^^^^^^^^^^^^^^^^^^^^
280284
- Fixed an import failure of recursive friend class template.

clang/lib/Sema/SemaTemplateInstantiate.cpp

+17-7
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,25 @@ Response HandleFunction(const FunctionDecl *Function,
230230
Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
231231
MultiLevelTemplateArgumentList &Result) {
232232
if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) {
233+
Result.addOuterTemplateArguments(
234+
const_cast<FunctionTemplateDecl *>(FTD),
235+
const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
236+
/*Final=*/false);
237+
233238
NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier();
234-
const Type *Ty;
235-
const TemplateSpecializationType *TSTy;
236-
if (NNS && (Ty = NNS->getAsType()) &&
237-
(TSTy = Ty->getAs<TemplateSpecializationType>()))
238-
Result.addOuterTemplateArguments(const_cast<FunctionTemplateDecl *>(FTD),
239-
TSTy->template_arguments(),
240-
/*Final=*/false);
239+
240+
while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
241+
if (NNS->isInstantiationDependent()) {
242+
if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>())
243+
Result.addOuterTemplateArguments(
244+
const_cast<FunctionTemplateDecl *>(FTD), TSTy->template_arguments(),
245+
/*Final=*/false);
246+
}
247+
248+
NNS = NNS->getPrefix();
249+
}
241250
}
251+
242252
return Response::ChangeDecl(FTD->getLexicalDeclContext());
243253
}
244254

clang/test/SemaTemplate/concepts-out-of-line-def.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -418,3 +418,51 @@ template<typename T> concept A = true;
418418
template<typename T> struct X { A<T> auto f(); };
419419
template<typename T> A<T> auto X<T>::f() {}
420420
}
421+
422+
namespace GH65810 {
423+
template<typename Param>
424+
concept TrivialConcept =
425+
requires(Param param) {
426+
(void)param;
427+
};
428+
429+
template <typename T>
430+
struct Base {
431+
class InnerClass;
432+
};
433+
434+
template <typename T>
435+
class Base<T>::InnerClass {
436+
template <typename Param>
437+
requires TrivialConcept<Param>
438+
int func(Param param) const;
439+
};
440+
441+
template <typename T>
442+
template <typename Param>
443+
requires TrivialConcept<Param>
444+
int Base<T>::InnerClass::func(Param param) const {
445+
return 0;
446+
}
447+
448+
template<typename T>
449+
struct Outermost {
450+
struct Middle {
451+
template<typename U>
452+
struct Innermost {
453+
template <typename Param>
454+
requires TrivialConcept<Param>
455+
int func(Param param) const;
456+
};
457+
};
458+
};
459+
460+
template <typename T>
461+
template <typename U>
462+
template <typename Param>
463+
requires TrivialConcept<Param>
464+
int Outermost<T>::Middle::Innermost<U>::func(Param param) const {
465+
return 0;
466+
}
467+
468+
} // namespace GH65810

0 commit comments

Comments
 (0)