diff options
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 14 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp | 1 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp | 11 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp | 34 |
4 files changed, 56 insertions, 4 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index d76ca76693..a9b8af28c7 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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>()) { diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp index 733aaee754..a34eccd3f2 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp @@ -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'}} } + diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp index a5ecf5fcd9..72f33df7ef 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp @@ -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 index 0000000000..f49190ef5a --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp @@ -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<>')}} |