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
// 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)) {
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>()) {
const int X<0>::Y::Z;
template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}}
}
+
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
+}
--- /dev/null
+// 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<>')}}