From c6d86b6b45a8e40457286c78321a4680b459e800 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 10 Nov 2020 15:52:36 -0800 Subject: [PATCH] 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). --- clang/lib/Sema/SemaExpr.cpp | 7 ++++++- clang/lib/Sema/SemaTemplateInstantiate.cpp | 7 ++++++- .../SemaTemplate/instantiate-member-specialization.cpp | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaTemplate/instantiate-member-specialization.cpp diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2888395..99a3e77 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 03670e2..0b7fe0c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -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); diff --git a/clang/test/SemaTemplate/instantiate-member-specialization.cpp b/clang/test/SemaTemplate/instantiate-member-specialization.cpp new file mode 100644 index 0000000..b9bc243 --- /dev/null +++ b/clang/test/SemaTemplate/instantiate-member-specialization.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++20 -verify %s +// expected-no-diagnostics + +namespace FunctionTemplate { + template struct S { + template 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().template foo<1>()(2) == 2); +} -- 2.7.4