Properly collect template arguments from a class-scope function template

specialization.

Fixes a crash-on-valid if further template parameters are introduced
within the specialization (by a generic lambda).
This commit is contained in:
Richard Smith 2020-11-10 15:52:36 -08:00
parent c052510c0b
commit c6d86b6b45
3 changed files with 28 additions and 2 deletions

View File

@ -16800,7 +16800,11 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
bool FirstInstantiation = PointOfInstantiation.isInvalid();
if (FirstInstantiation) {
PointOfInstantiation = Loc;
Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
if (auto *MSI = Func->getMemberSpecializationInfo())
MSI->setPointOfInstantiation(Loc);
// FIXME: Notify listener.
else
Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
} else if (TSK != TSK_ImplicitInstantiation) {
// Use the point of use as the point of instantiation, instead of the
// point of explicit instantiation (which we track as the actual point
@ -18040,6 +18044,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
PointOfInstantiation = Loc;
if (MSI)
MSI->setPointOfInstantiation(PointOfInstantiation);
// FIXME: Notify listener.
else
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}

View File

@ -141,7 +141,12 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
TSK_ExplicitSpecialization)
break;
if (const TemplateArgumentList *TemplateArgs
if (!RelativeToPrimary && Function->getTemplateSpecializationKind() ==
TSK_ExplicitSpecialization) {
// This is an implicit instantiation of an explicit specialization. We
// don't get any template arguments from this function but might get
// some from an enclosing template.
} else if (const TemplateArgumentList *TemplateArgs
= Function->getTemplateSpecializationArgs()) {
// Add the template arguments for this specialization.
Result.addOuterTemplateArguments(TemplateArgs);

View File

@ -0,0 +1,16 @@
// RUN: %clang_cc1 -std=c++20 -verify %s
// expected-no-diagnostics
namespace FunctionTemplate {
template<typename> struct S {
template<int> auto foo();
// Check that we don't confuse the depth-1 level-0 parameter of the generic
// lambda with the depth-1 level-0 parameter of the primary 'foo' template.
template<> constexpr auto foo<1>() {
return [](auto x) { return x; };
}
};
static_assert(S<void>().template foo<1>()(2) == 2);
}