forked from OSchip/llvm-project
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:
parent
bd375f1a3f
commit
522d5eb7c3
|
@ -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<
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue