r359266 - PR41607: Don't forget to substitute outer template arguments into a

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 25 19:11:24 PDT 2019


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 {{}}
+}




More information about the cfe-commits mailing list