From 51d7df37f879c620054622b383b5401e69b0852a Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 26 Apr 2019 02:11:23 +0000 Subject: [PATCH] PR41607: Don't forget to substitute outer template arguments into a class-scope explicit specialization of a class template. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359266 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclTemplate.h | 19 +++++++++++++++++++ lib/Sema/SemaTemplateInstantiate.cpp | 14 +++++++++----- .../explicit-specialization-member.cpp | 17 +++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 902e096841..3ac3f37469 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -1746,6 +1746,20 @@ public: return getSpecializationKind() == TSK_ExplicitSpecialization; } + /// Is this an explicit specialization at class scope (within the class that + /// owns the primary template)? For example: + /// + /// \code + /// template struct Outer { + /// template struct Inner; + /// template<> struct Inner; // class-scope explicit specialization + /// }; + /// \endcode + bool isClassScopeExplicitSpecialization() const { + return isExplicitSpecialization() && + isa(getLexicalDeclContext()); + } + /// True if this declaration is an explicit specialization, /// explicit instantiation declaration, or explicit instantiation /// definition. @@ -2581,6 +2595,11 @@ public: return getSpecializationKind() == TSK_ExplicitSpecialization; } + bool isClassScopeExplicitSpecialization() const { + return isExplicitSpecialization() && + isa(getLexicalDeclContext()); + } + /// True if this declaration is an explicit specialization, /// explicit instantiation declaration, or explicit instantiation /// definition. diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index e8f1dcca59..c7457354b3 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -66,9 +66,12 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, if (!Ctx) { Ctx = D->getDeclContext(); - // Add template arguments from a variable template instantiation. - if (VarTemplateSpecializationDecl *Spec = - dyn_cast(D)) { + // Add template arguments from a variable template instantiation. For a + // class-scope explicit specialization, there are no template arguments + // at this level, but there may be enclosing template arguments. + VarTemplateSpecializationDecl *Spec = + dyn_cast(D); + if (Spec && !Spec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa(Spec)) @@ -111,8 +114,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, while (!Ctx->isFileContext()) { // Add template arguments from a class template instantiation. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(Ctx)) { + ClassTemplateSpecializationDecl *Spec + = dyn_cast(Ctx); + if (Spec && !Spec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa(Spec)) diff --git a/test/SemaTemplate/explicit-specialization-member.cpp b/test/SemaTemplate/explicit-specialization-member.cpp index e8165ac9ca..e84364a508 100644 --- a/test/SemaTemplate/explicit-specialization-member.cpp +++ b/test/SemaTemplate/explicit-specialization-member.cpp @@ -62,3 +62,20 @@ namespace SpecLoc { template<> float A::n; // expected-error {{different type}} template<> void A::f() throw(); // expected-error {{does not match}} } + +namespace PR41607 { + template struct Outer { + template struct Inner; + template<> struct Inner<> { + static constexpr int f() { return N; } + }; + + template static int a; // expected-note 2{{}} + template<> static constexpr int a<> = 42; + }; + static_assert(Outer<123>::Inner<>::f() == 123, ""); + static_assert(Outer<123>::Inner<>::f() != 125, ""); + // FIXME: The class-scope explicit specialization of the variable template doesn't work! + static_assert(Outer<123>::a<> == 42, ""); // expected-error {{}} expected-note {{}} + static_assert(Outer<123>::a<> != 43, ""); // expected-error {{}} expected-note {{}} +} -- 2.40.0