Give a more appropriate diagnostic when a template specialization or

instantiation appears in a non-enclosing namespace (the previous diagnostic
talked about the C++98 rule even in C++11 mode).

llvm-svn: 196642
This commit is contained in:
Richard Smith 2013-12-07 05:09:50 +00:00
parent 567befd88f
commit a98f8fc8d8
5 changed files with 38 additions and 36 deletions

View File

@ -5596,13 +5596,37 @@ static bool CheckTemplateSpecializationScope(Sema &S,
// A class template partial specialization may be declared or redeclared
// in any namespace scope in which its definition may be defined (14.5.1
// and 14.5.2).
bool ComplainedAboutScope = false;
DeclContext *SpecializedContext
DeclContext *SpecializedContext
= Specialized->getDeclContext()->getEnclosingNamespaceContext();
DeclContext *DC = S.CurContext->getEnclosingNamespaceContext();
if ((!PrevDecl ||
getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
getTemplateSpecializationKind(PrevDecl) == TSK_ImplicitInstantiation)){
// Make sure that this redeclaration (or definition) occurs in an enclosing
// namespace.
// Note that HandleDeclarator() performs this check for explicit
// specializations of function templates, static data members, and member
// functions, so we skip the check here for those kinds of entities.
// FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
// Should we refactor that check, so that it occurs later?
if (!DC->Encloses(SpecializedContext) &&
!(isa<FunctionTemplateDecl>(Specialized) ||
isa<FunctionDecl>(Specialized) ||
isa<VarTemplateDecl>(Specialized) ||
isa<VarDecl>(Specialized))) {
if (isa<TranslationUnitDecl>(SpecializedContext))
S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
<< EntityKind << Specialized;
else if (isa<NamespaceDecl>(SpecializedContext))
S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
<< EntityKind << Specialized
<< cast<NamedDecl>(SpecializedContext);
else
llvm_unreachable("unexpected namespace context for specialization");
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
} else if ((!PrevDecl ||
getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
getTemplateSpecializationKind(PrevDecl) ==
TSK_ImplicitInstantiation)) {
// C++ [temp.exp.spec]p2:
// An explicit specialization shall be declared in the namespace of which
// the template is a member, or, for member templates, in the namespace
@ -5611,9 +5635,12 @@ static bool CheckTemplateSpecializationScope(Sema &S,
// static data member of a class template shall be declared in the
// namespace of which the class template is a member.
//
// C++0x [temp.expl.spec]p2:
// C++11 [temp.expl.spec]p2:
// An explicit specialization shall be declared in a namespace enclosing
// the specialized template.
// C++11 [temp.explicit]p3:
// An explicit instantiation shall appear in an enclosing namespace of its
// template.
if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) {
bool IsCPlusPlus11Extension = DC->Encloses(SpecializedContext);
if (isa<TranslationUnitDecl>(SpecializedContext)) {
@ -5634,34 +5661,9 @@ static bool CheckTemplateSpecializationScope(Sema &S,
}
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
ComplainedAboutScope =
!(IsCPlusPlus11Extension && S.getLangOpts().CPlusPlus11);
}
}
// Make sure that this redeclaration (or definition) occurs in an enclosing
// namespace.
// Note that HandleDeclarator() performs this check for explicit
// specializations of function templates, static data members, and member
// functions, so we skip the check here for those kinds of entities.
// FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
// Should we refactor that check, so that it occurs later?
if (!ComplainedAboutScope && !DC->Encloses(SpecializedContext) &&
!(isa<FunctionTemplateDecl>(Specialized) || isa<VarDecl>(Specialized) ||
isa<FunctionDecl>(Specialized))) {
if (isa<TranslationUnitDecl>(SpecializedContext))
S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
<< EntityKind << Specialized;
else if (isa<NamespaceDecl>(SpecializedContext))
S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
<< EntityKind << Specialized
<< cast<NamedDecl>(SpecializedContext);
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
}
// FIXME: check for specialization-after-instantiation errors and such.
return false;
}

View File

@ -37,7 +37,7 @@ namespace noargs_body {
namespace exp_spec {
#ifndef FIXING
template<> void f0<int>(int) { } // expected-error {{no function template matches function template specialization 'f0'}}
template<> struct x0<int> { }; // expected-error {{class template specialization of 'x0' must originally be declared in the global scope}}
template<> struct x0<int> { }; // expected-error {{class template specialization of 'x0' must occur at global scope}}
#endif
}
@ -51,7 +51,7 @@ namespace args_bad {
template void f1<int>(int) { } // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \
expected-error {{no function template matches function template specialization 'f1'}}
template struct x1<int> { }; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \
expected-error {{class template specialization of 'x1' must originally be declared in the global scope}}
expected-error {{class template specialization of 'x1' must occur at global scope}}
#endif
}

View File

@ -79,7 +79,7 @@ template<> struct N0::X0<void> { };
N0::X0<void> test_X0;
namespace N1 {
template<> struct N0::X0<const void> { }; // expected-error{{class template specialization of 'X0' must originally be declared in namespace 'N0'}}
template<> struct N0::X0<const void> { }; // expected-error{{class template specialization of 'X0' not in a namespace enclosing 'N0'}}
}
namespace N0 {

View File

@ -80,7 +80,7 @@ template<> struct N0::X0<void> { }; // expected-warning{{C++11 extension}}
N0::X0<void> test_X0;
namespace N1 {
template<> struct N0::X0<const void> { }; // expected-error{{originally}}
template<> struct N0::X0<const void> { }; // expected-error{{not in a namespace enclosing 'N0'}}
}
namespace N0 {

View File

@ -91,7 +91,7 @@ template<> struct N::B<float> { }; // expected-warning{{C++11 extension}}
namespace M {
template<> struct ::N::B<short> { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}}
template<> struct ::A<long double>; // expected-error{{originally}}
template<> struct ::A<long double>; // expected-error{{must occur at global scope}}
}
template<> struct N::B<char> {