Diagnose the condition in C++ [temp.expl.spec]p16 that prohibits

specializing a member of an unspecialized template, and recover from
such errors without crashing. Fixes PR10024 / <rdar://problem/9509761>.

llvm-svn: 132677
This commit is contained in:
Douglas Gregor 2011-06-06 15:22:55 +00:00
parent bd375f1a3f
commit 522d5eb7c3
4 changed files with 58 additions and 4 deletions

View File

@ -1893,6 +1893,9 @@ def note_explicit_template_spec_does_not_need_header : Note<
def err_template_qualified_declarator_no_match : Error<
"nested name specifier '%0' for declaration does not refer into a class, "
"class template or class template partial specialization">;
def err_specialize_member_of_template : Error<
"cannot specialize (with 'template<>') a member of an unspecialized "
"template">;
// C++ Class Template Partial Specialization
def err_default_arg_in_partial_spec : Error<

View File

@ -4516,8 +4516,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (!getLangOptions().CPlusPlus) {
// Perform semantic checking on the function declaration.
bool isExplctSpecialization=false;
CheckFunctionDeclaration(S, NewFD, Previous, isExplctSpecialization,
bool isExplicitSpecialization=false;
CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
Redeclaration);
assert((NewFD->isInvalidDecl() || !Redeclaration ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
@ -4540,7 +4540,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
HasExplicitTemplateArgs = true;
if (FunctionTemplate) {
if (NewFD->isInvalidDecl()) {
HasExplicitTemplateArgs = false;
} else if (FunctionTemplate) {
// Function template with explicit template arguments.
Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec)
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);

View File

@ -1610,6 +1610,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// such a member, the member declaration shall be preceded by a
// template<> for each enclosing class template that is
// explicitly specialized.
bool SawNonEmptyTemplateParameterList = false;
unsigned ParamIdx = 0;
for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes;
++TypeIdx) {
@ -1671,6 +1672,26 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
NeedNonemptyTemplateHeader = false;
}
// C++ [temp.expl.spec]p16:
// In an explicit specialization declaration for a member of a class
// template or a member template that ap- pears in namespace scope, the
// member template and some of its enclosing class templates may remain
// unspecialized, except that the declaration shall not explicitly
// specialize a class member template if its en- closing class templates
// are not explicitly specialized as well.
if (ParamIdx < NumParamLists) {
if (ParamLists[ParamIdx]->size() == 0) {
if (SawNonEmptyTemplateParameterList) {
Diag(DeclLoc, diag::err_specialize_member_of_template)
<< ParamLists[ParamIdx]->getSourceRange();
Invalid = true;
IsExplicitSpecialization = false;
return 0;
}
} else
SawNonEmptyTemplateParameterList = true;
}
if (NeedEmptyTemplateHeader) {
// If we're on the last of the types, and we need a 'template<>' header
// here, then it's an explicit specialization.
@ -1787,6 +1808,22 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
Invalid = true;
}
// C++ [temp.expl.spec]p16:
// In an explicit specialization declaration for a member of a class
// template or a member template that ap- pears in namespace scope, the
// member template and some of its enclosing class templates may remain
// unspecialized, except that the declaration shall not explicitly
// specialize a class member template if its en- closing class templates
// are not explicitly specialized as well.
if (ParamLists[NumParamLists - 1]->size() == 0 &&
SawNonEmptyTemplateParameterList) {
Diag(DeclLoc, diag::err_specialize_member_of_template)
<< ParamLists[ParamIdx]->getSourceRange();
Invalid = true;
IsExplicitSpecialization = false;
return 0;
}
// Return the last template parameter list, which corresponds to the
// entity being declared.
return ParamLists[NumParamLists - 1];

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only %s
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<class T> struct A {
void f(T);
template<class X1> void g1(T, X1);
@ -24,3 +24,15 @@ template<> template<>
// member specialization even if defined in class definition
template<> void A<int>::h(int) { }
namespace PR10024 {
template <typename T>
struct Test{
template <typename U>
void get(U i) {}
};
template <typename T>
template <>
void Test<T>::get<double>(double i) {} // expected-error{{cannot specialize (with 'template<>') a member of an unspecialized template}}
}