Author: rsmith Date: Thu Apr 25 19:11:23 2019 New Revision: 359266 URL: http://llvm.org/viewvc/llvm-project?rev=359266&view=rev Log: PR41607: Don't forget to substitute outer template arguments into a class-scope explicit specialization of a class template.
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp Modified: cfe/trunk/include/clang/AST/DeclTemplate.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=359266&r1=359265&r2=359266&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclTemplate.h (original) +++ cfe/trunk/include/clang/AST/DeclTemplate.h Thu Apr 25 19:11:23 2019 @@ -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<typename T> struct Outer { + /// template<typename U> struct Inner; + /// template<> struct Inner; // class-scope explicit specialization + /// }; + /// \endcode + bool isClassScopeExplicitSpecialization() const { + return isExplicitSpecialization() && + isa<CXXRecordDecl>(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<CXXRecordDecl>(getLexicalDeclContext()); + } + /// True if this declaration is an explicit specialization, /// explicit instantiation declaration, or explicit instantiation /// definition. Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=359266&r1=359265&r2=359266&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Apr 25 19:11:23 2019 @@ -66,9 +66,12 @@ Sema::getTemplateInstantiationArgs(Named if (!Ctx) { Ctx = D->getDeclContext(); - // Add template arguments from a variable template instantiation. - if (VarTemplateSpecializationDecl *Spec = - dyn_cast<VarTemplateSpecializationDecl>(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<VarTemplateSpecializationDecl>(D); + if (Spec && !Spec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa<VarTemplatePartialSpecializationDecl>(Spec)) @@ -111,8 +114,9 @@ Sema::getTemplateInstantiationArgs(Named while (!Ctx->isFileContext()) { // Add template arguments from a class template instantiation. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) { + ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Ctx); + if (Spec && !Spec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa<ClassTemplatePartialSpecializationDecl>(Spec)) Modified: cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp?rev=359266&r1=359265&r2=359266&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp (original) +++ cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp Thu Apr 25 19:11:23 2019 @@ -62,3 +62,20 @@ namespace SpecLoc { template<> float A<int>::n; // expected-error {{different type}} template<> void A<int>::f() throw(); // expected-error {{does not match}} } + +namespace PR41607 { + template<int N> struct Outer { + template<typename...> struct Inner; + template<> struct Inner<> { + static constexpr int f() { return N; } + }; + + template<typename...> 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 {{}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits