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 <rdar://problem/9422013>.

llvm-svn: 131207
This commit is contained in:
Douglas Gregor 2011-05-11 23:26:17 +00:00
parent 851e18a1d4
commit 373af9bc5d
4 changed files with 56 additions and 4 deletions

View 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>()) {

View 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'}}
}

View 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
}

View File

@ -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<>')}}