]> granicus.if.org Git - clang/commitdiff
PR41607: Don't forget to substitute outer template arguments into a
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 26 Apr 2019 02:11:23 +0000 (02:11 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 26 Apr 2019 02:11:23 +0000 (02:11 +0000)
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
lib/Sema/SemaTemplateInstantiate.cpp
test/SemaTemplate/explicit-specialization-member.cpp

index 902e096841c8559431540e5ba2a2d3e44346b37a..3ac3f37469cb6f9cf3fa2da5f392d0f27a14448c 100644 (file)
@@ -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.
index e8f1dcca59c859f5effcb6487008f59f6e6e0e56..c7457354b3323d15a62e796478e6eb45464f5b2d 100644 (file)
@@ -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<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(NamedDecl *D,
 
   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))
index e8165ac9ca7ad2ac634e38605b07a6c1afa6bce9..e84364a50865b4e40ff3aa4c2329ac1bbd75a8fa 100644 (file)
@@ -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 {{}}
+}