From 175c5bb2b09217df71319cb3d58b3c511fd04138 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 11 May 2011 23:26:17 +0000 Subject: [PATCH] When checking for the necessary 'template<>' headers based on the 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 . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131207 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplate.cpp | 14 +++++--- .../temp.spec/temp.expl.spec/examples.cpp | 1 + .../CXX/temp/temp.spec/temp.expl.spec/p15.cpp | 11 ++++++ .../temp.spec/temp.expl.spec/p5-example.cpp | 34 +++++++++++++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp 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(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()) { 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::member // expected-note{{instantiation}} : X::member; } + +namespace rdar9422013 { + template + 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 struct A { + struct B { }; + template struct C { }; +}; + template<> struct A { + void f(int); +}; +void h() { + A a; + a.f(16); +} +// A::f must be defined somewhere +// template<> not used for a member of an // explicitly specialized class template +void A::f(int) { /* ... */ } + template<> struct A::B { + void f(); +}; +// template<> also not used when defining a member of // an explicitly specialized member class +void A::B::f() { /* ... */ } + template<> template struct A::C { + void f(); +}; + +template<> +template void A::C::f() { /* ... */ } + template<> struct A::B { + void f(); +}; +template<> void A::B::f() { /* ... */ } // expected-error{{no function template matches function template specialization 'f'}} + template<> template struct A::C { + void f(); +}; +template void A::C::f() { /* ... */ } // expected-error{{template parameter list matching the non-templated nested type 'A' should be empty ('template<>')}} -- 2.40.0