forked from OSchip/llvm-project
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:
parent
567befd88f
commit
a98f8fc8d8
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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> {
|
||||
|
|
Loading…
Reference in New Issue