From a98f8fc8d842651619bb67f98ec6f211d8b206a5 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 7 Dec 2013 05:09:50 +0000 Subject: [PATCH] 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 --- clang/lib/Sema/SemaTemplate.cpp | 64 ++++++++++--------- clang/test/CXX/temp/temp.spec/no-body.cpp | 4 +- .../temp/temp.spec/temp.expl.spec/p2-0x.cpp | 2 +- .../CXX/temp/temp.spec/temp.expl.spec/p2.cpp | 2 +- .../test/SemaTemplate/class-template-spec.cpp | 2 +- 5 files changed, 38 insertions(+), 36 deletions(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 0376d106eae0..d72c04c01213 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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(Specialized) || + isa(Specialized) || + isa(Specialized) || + isa(Specialized))) { + if (isa(SpecializedContext)) + S.Diag(Loc, diag::err_template_spec_redecl_global_scope) + << EntityKind << Specialized; + else if (isa(SpecializedContext)) + S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope) + << EntityKind << Specialized + << cast(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(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(Specialized) || isa(Specialized) || - isa(Specialized))) { - if (isa(SpecializedContext)) - S.Diag(Loc, diag::err_template_spec_redecl_global_scope) - << EntityKind << Specialized; - else if (isa(SpecializedContext)) - S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope) - << EntityKind << Specialized - << cast(SpecializedContext); - - S.Diag(Specialized->getLocation(), diag::note_specialized_entity); - } - - // FIXME: check for specialization-after-instantiation errors and such. - return false; } diff --git a/clang/test/CXX/temp/temp.spec/no-body.cpp b/clang/test/CXX/temp/temp.spec/no-body.cpp index a4d7914d9eb6..61d285b27ed2 100644 --- a/clang/test/CXX/temp/temp.spec/no-body.cpp +++ b/clang/test/CXX/temp/temp.spec/no-body.cpp @@ -37,7 +37,7 @@ namespace noargs_body { namespace exp_spec { #ifndef FIXING template<> void f0(int) { } // expected-error {{no function template matches function template specialization 'f0'}} - template<> struct x0 { }; // expected-error {{class template specialization of 'x0' must originally be declared in the global scope}} + template<> struct x0 { }; // expected-error {{class template specialization of 'x0' must occur at global scope}} #endif } @@ -51,7 +51,7 @@ namespace args_bad { template void f1(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 { }; // 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 } diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp index 75b198e47d13..1a7065e0022b 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp @@ -79,7 +79,7 @@ template<> struct N0::X0 { }; N0::X0 test_X0; namespace N1 { - template<> struct N0::X0 { }; // expected-error{{class template specialization of 'X0' must originally be declared in namespace 'N0'}} + template<> struct N0::X0 { }; // expected-error{{class template specialization of 'X0' not in a namespace enclosing 'N0'}} } namespace N0 { diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp index c972bf7c7d0a..4fbc45a7d7dd 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp @@ -80,7 +80,7 @@ template<> struct N0::X0 { }; // expected-warning{{C++11 extension}} N0::X0 test_X0; namespace N1 { - template<> struct N0::X0 { }; // expected-error{{originally}} + template<> struct N0::X0 { }; // expected-error{{not in a namespace enclosing 'N0'}} } namespace N0 { diff --git a/clang/test/SemaTemplate/class-template-spec.cpp b/clang/test/SemaTemplate/class-template-spec.cpp index f9015b37ea09..e82537abded2 100644 --- a/clang/test/SemaTemplate/class-template-spec.cpp +++ b/clang/test/SemaTemplate/class-template-spec.cpp @@ -91,7 +91,7 @@ template<> struct N::B { }; // expected-warning{{C++11 extension}} namespace M { template<> struct ::N::B { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}} - template<> struct ::A; // expected-error{{originally}} + template<> struct ::A; // expected-error{{must occur at global scope}} } template<> struct N::B {