]> granicus.if.org Git - clang/commitdiff
When checking for the necessary 'template<>' headers based on the
authorDouglas Gregor <dgregor@apple.com>
Wed, 11 May 2011 23:26:17 +0000 (23:26 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 11 May 2011 23:26:17 +0000 (23:26 +0000)
nested of an out-of-line declaration, only require a 'template<>'
header for each enclosing class template that hasn't been previously
specialized; previously, we were requiring 'template<>' for enclosing
class templates and members of class templates that hadn't been
previously specialized. Fixes <rdar://problem/9422013>.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131207 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp [new file with mode: 0644]

index d76ca76693e2f280ef62f6bdbf078b87e8dd9224..a9b8af28c7c775bd89f747133e29bbd3052bf19d 100644 (file)
@@ -1614,6 +1614,11 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
     // expect to see.
     TemplateParameterList *ExpectedTemplateParams = 0;
 
+    // C++0x [temp.expl.spec]p15:
+    //   A member or a member template may be nested within many enclosing 
+    //   class templates. In an explicit specialization for such a member, the 
+    //   member declaration shall be preceded by a template<> for each 
+    //   enclosing class template that is explicitly specialized.
     if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) {
       if (ClassTemplatePartialSpecializationDecl *Partial
             = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
@@ -1637,10 +1642,11 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
           break;
       } else if (Record->getTemplateSpecializationKind()) {
         if (Record->getTemplateSpecializationKind() 
-                                                  != TSK_ExplicitSpecialization)
-          NeedEmptyTemplateHeader = true;
-        else
-          break;
+                                                != TSK_ExplicitSpecialization &&
+            TypeIdx == NumTypes - 1)
+          IsExplicitSpecialization = true;
+        
+        continue;
       }
     } else if (const TemplateSpecializationType *TST
                                      = T->getAs<TemplateSpecializationType>()) {
index 733aaee7545485707ef9f4a30ad1e5606ce65a3d..a34eccd3f2f6cbf8328b4061216f2c55856f1107 100644 (file)
@@ -165,3 +165,4 @@ namespace PR9877 {
   const int X<0>::Y::Z;
   template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}}
 }
+
index a5ecf5fcd9d23b920a86187a0591088e937a46a9..72f33df7efa42b48945269a7fbefe4c389bbed31 100644 (file)
@@ -20,3 +20,14 @@ NonDefaultConstructible &test(bool b) {
   return b? X<NonDefaultConstructible, int>::member // expected-note{{instantiation}}
           : X<NonDefaultConstructible, long>::member;
 }
+
+namespace rdar9422013 {
+  template<int>
+  struct X {
+    struct Inner {
+      static unsigned array[17];
+    };
+  };
+
+  template<> unsigned X<1>::Inner::array[]; // okay
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp
new file mode 100644 (file)
index 0000000..f49190e
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+template<class T> struct A {
+       struct B { };
+       template<class U> struct C { };
+};
+     template<> struct A<int> {
+       void f(int);
+};
+void h() {
+  A<int> a;
+  a.f(16);
+}
+// A<int>::f must be defined somewhere
+// template<> not used for a member of an // explicitly specialized class template
+void A<int>::f(int) { /* ... */ }
+  template<> struct A<char>::B {
+    void f();
+};
+// template<> also not used when defining a member of // an explicitly specialized member class
+void A<char>::B::f() { /* ... */ }
+  template<> template<class U> struct A<char>::C {
+    void f();
+};
+
+template<>
+template<class U> void A<char>::C<U>::f() { /* ... */ }
+  template<> struct A<short>::B {
+    void f();
+};
+template<> void A<short>::B::f() { /* ... */ } // expected-error{{no function template matches function template specialization 'f'}}
+  template<> template<class U> struct A<short>::C {
+    void f();
+};
+template<class U> void A<short>::C<U>::f() { /* ... */ } // expected-error{{template parameter list matching the non-templated nested type 'A<short>' should be empty ('template<>')}}