diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 05a76a71a44e..9a2102b74316 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1459,10 +1459,18 @@ def err_template_spec_decl_out_of_scope_global : Error< "%select{class template|class template partial|function template|member " "function|static data member|member class}0 specialization of %1 must " "originally be declared in the global scope">; +def ext_template_spec_decl_out_of_scope_global : ExtWarn< + "%select{class template|class template partial|function template|member " + "function|static data member|member class}0 specialization of %1 must " + "originally be declared in the global scope; accepted as a C++0x extension">; def err_template_spec_decl_out_of_scope : Error< "%select{class template|class template partial|function template|member " "function|static data member|member class}0 specialization of %1 must " "originally be declared in namespace %2">; +def ext_template_spec_decl_out_of_scope : ExtWarn< + "%select{class template|class template partial|function template|member " + "function|static data member|member class}0 specialization of %1 must " + "originally be declared in namespace %2; accepted as a C++0x extension">; def err_template_spec_redecl_out_of_scope : Error< "%select{class template|class template partial|function template|member " "function|static data member|member class}0 specialization of %1 not in a " diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 851f7b960458..6fe8c75441fc 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3454,13 +3454,19 @@ static bool CheckTemplateSpecializationScope(Sema &S, // the specialized template. if (!DC->InEnclosingNamespaceSetOf(SpecializedContext) && !(S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext))) { + bool IsCPlusPlus0xExtension + = !S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext); if (isa(SpecializedContext)) - S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global) - << EntityKind << Specialized; + S.Diag(Loc, IsCPlusPlus0xExtension + ? diag::ext_template_spec_decl_out_of_scope_global + : diag::err_template_spec_decl_out_of_scope_global) + << EntityKind << Specialized; else if (isa(SpecializedContext)) - S.Diag(Loc, diag::err_template_spec_decl_out_of_scope) - << EntityKind << Specialized - << cast(SpecializedContext); + S.Diag(Loc, IsCPlusPlus0xExtension + ? diag::ext_template_spec_decl_out_of_scope + : diag::err_template_spec_decl_out_of_scope) + << EntityKind << Specialized + << cast(SpecializedContext); S.Diag(Specialized->getLocation(), diag::note_specialized_entity); ComplainedAboutScope = true; 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 new file mode 100644 index 000000000000..ed600e4ad999 --- /dev/null +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp @@ -0,0 +1,239 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s + +// This test creates cases where implicit instantiations of various entities +// would cause a diagnostic, but provides expliict specializations for those +// entities that avoid the diagnostic. The specializations are alternately +// declarations and definitions, and the intent of this test is to verify +// that we allow specializations only in the appropriate namespaces (and +// nowhere else). +struct NonDefaultConstructible { + NonDefaultConstructible(int); +}; + + +// C++ [temp.expl.spec]p1: +// An explicit specialization of any of the following: + +// -- function template +namespace N0 { + template void f0(T) { + T t; + } + + template<> void f0(NonDefaultConstructible) { } + + void test_f0(NonDefaultConstructible NDC) { + f0(NDC); + } + + template<> void f0(int); + template<> void f0(long); +} + +template<> void N0::f0(int) { } // okay + +namespace N1 { + template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}} +} + +template<> void N0::f0(double) { } + +struct X1 { + template void f(T); + + template<> void f(int); // expected-error{{in class scope}} +}; + +// -- class template +namespace N0 { + +template +struct X0 { // expected-note {{here}} + static T member; + + void f1(T t) { + t = 17; + } + + struct Inner : public T { }; // expected-note 2{{here}} + + template + struct InnerTemplate : public T { }; // expected-note 1{{explicitly specialized}} \ + // expected-error{{base specifier}} + + template + void ft1(T t, U u); +}; + +} + +template +template +void N0::X0::ft1(T t, U u) { + t = u; +} + +template T N0::X0::member; + +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'}} +} + +namespace N0 { + template<> struct X0; +} + +template<> struct N0::X0 { + void f1(void *); +}; + +// -- member function of a class template +template<> void N0::X0::f1(void *) { } + +void test_spec(N0::X0 xvp, void *vp) { + xvp.f1(vp); +} + +namespace N0 { + template<> void X0::f1(void *) { } // expected-error{{no function template matches}} + + template<> void X0::f1(const volatile void*); +} + +void test_x0_cvvoid(N0::X0 x0, const volatile void *cvp) { + x0.f1(cvp); // okay: we've explicitly specialized +} + +// -- static data member of a class template +namespace N0 { + // This actually tests p15; the following is a declaration, not a definition. + template<> + NonDefaultConstructible X0::member; + + template<> long X0::member = 17; + + template<> float X0::member; + + template<> double X0::member; +} + +NonDefaultConstructible &get_static_member() { + return N0::X0::member; +} + +template<> int N0::X0::member; + +template<> float N0::X0::member = 3.14f; + +namespace N1 { + template<> double N0::X0::member = 3.14; // expected-error{{not in a namespace enclosing}} +} + +// -- member class of a class template +namespace N0 { + + template<> + struct X0::Inner { }; + + template<> + struct X0::Inner { }; + + template<> + struct X0::Inner; + + template<> + struct X0::Inner; + + template<> + struct X0::Inner; // expected-note{{forward declaration}} +} + +template<> +struct N0::X0::Inner { }; + +template<> +struct N0::X0::Inner { }; + +namespace N1 { + template<> + struct N0::X0::Inner { }; // expected-error{{member class specialization}} + + template<> + struct N0::X0::Inner { }; // expected-error{{member class specialization}} +}; + +N0::X0::Inner inner0; +N0::X0::Inner inner1; +N0::X0::Inner inner2; +N0::X0::Inner inner3; +N0::X0::Inner inner4; // expected-error{{incomplete}} + +// -- member class template of a class template +namespace N0 { + template<> + template<> + struct X0::InnerTemplate { }; + + template<> template<> + struct X0::InnerTemplate; // expected-note{{forward declaration}} + + template<> template<> + struct X0::InnerTemplate; + + template<> template<> + struct X0::InnerTemplate; +} + +template<> template<> +struct N0::X0::InnerTemplate { }; // okay + +template<> template<> +struct N0::X0::InnerTemplate { }; + +namespace N1 { + template<> template<> + struct N0::X0::InnerTemplate { }; // expected-error{{enclosing}} +} + +N0::X0::InnerTemplate inner_template0; +N0::X0::InnerTemplate inner_template1; // expected-error{{incomplete}} +N0::X0::InnerTemplate inner_template2; +N0::X0::InnerTemplate inner_template3; // expected-note{{instantiation}} + +// -- member function template of a class template +namespace N0 { + template<> + template<> + void X0::ft1(void*, const void*) { } + + template<> template<> + void X0::ft1(void *, int); + + template<> template<> + void X0::ft1(void *, unsigned); + + template<> template<> + void X0::ft1(void *, long); +} + +template<> template<> +void N0::X0::ft1(void *, unsigned) { } // okay + +template<> template<> +void N0::X0::ft1(void *, float) { } + +namespace N1 { + template<> template<> + void N0::X0::ft1(void *, long) { } // expected-error{{enclosing}} +} + + +void test_func_template(N0::X0 xvp, void *vp, const void *cvp, + int i, unsigned u) { + xvp.ft1(vp, cvp); + xvp.ft1(vp, i); + xvp.ft1(vp, u); +} 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 654f5abb8a54..1032a87def13 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 @@ -36,7 +36,7 @@ namespace N1 { template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}} } -template<> void N0::f0(double) { } // expected-error{{originally be declared}} +template<> void N0::f0(double) { } // expected-warning{{originally be declared}} struct X1 { template void f(T); @@ -75,7 +75,7 @@ void N0::X0::ft1(T t, U u) { template T N0::X0::member; -template<> struct N0::X0 { }; // expected-error{{originally}} +template<> struct N0::X0 { }; // expected-warning{{originally}} N0::X0 test_X0; namespace N1 { @@ -91,7 +91,7 @@ template<> struct N0::X0 { }; // -- member function of a class template -template<> void N0::X0::f1(void *) { } // expected-error{{member function specialization}} +template<> void N0::X0::f1(void *) { } // expected-warning{{member function specialization}} void test_spec(N0::X0 xvp, void *vp) { xvp.f1(vp); @@ -124,7 +124,7 @@ NonDefaultConstructible &get_static_member() { return N0::X0::member; } -template<> int N0::X0::member; // expected-error{{originally}} +template<> int N0::X0::member; // expected-warning{{originally}} template<> float N0::X0::member = 3.14f; @@ -152,7 +152,7 @@ namespace N0 { } template<> -struct N0::X0::Inner { }; // expected-error{{originally}} +struct N0::X0::Inner { }; // expected-warning{{originally}} template<> struct N0::X0::Inner { }; @@ -191,7 +191,7 @@ template<> template<> struct N0::X0::InnerTemplate { }; // okay template<> template<> -struct N0::X0::InnerTemplate { }; // expected-error{{class template specialization}} +struct N0::X0::InnerTemplate { }; // expected-warning{{class template specialization}} namespace N1 { template<> template<> @@ -223,7 +223,7 @@ template<> template<> void N0::X0::ft1(void *, unsigned) { } // okay template<> template<> -void N0::X0::ft1(void *, float) { } // expected-error{{function template specialization}} +void N0::X0::ft1(void *, float) { } // expected-warning{{function template specialization}} namespace N1 { template<> template<> diff --git a/clang/test/SemaTemplate/class-template-spec.cpp b/clang/test/SemaTemplate/class-template-spec.cpp index c65802e5c869..07a5e2982c7f 100644 --- a/clang/test/SemaTemplate/class-template-spec.cpp +++ b/clang/test/SemaTemplate/class-template-spec.cpp @@ -86,7 +86,7 @@ namespace N { template<> struct N::B { }; // okay -template<> struct N::B { }; // expected-error{{originally}} +template<> struct N::B { }; // expected-warning{{originally}} namespace M { template<> struct ::N::B { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}} diff --git a/clang/test/SemaTemplate/temp_class_spec_neg.cpp b/clang/test/SemaTemplate/temp_class_spec_neg.cpp index c8e8a57f278b..6b129a5369fb 100644 --- a/clang/test/SemaTemplate/temp_class_spec_neg.cpp +++ b/clang/test/SemaTemplate/temp_class_spec_neg.cpp @@ -9,7 +9,7 @@ namespace N { } template -struct N::M::A { }; // expected-error{{originally}} +struct N::M::A { }; // expected-warning{{originally}} // C++ [temp.class.spec]p9 // bullet 1