On 2014.11.02 at 21:12 -0500, Jason Merrill wrote: > On 11/02/2014 09:15 AM, Markus Trippelsdorf wrote: > > + if (cxx_dialect < cxx11) > > + { > > + permerror (input_location, "specialization of %qD in different " > > + "namespace", tmpl); > > + permerror (input_location, " from definition of %q+#D", tmpl); > > + } > > + else > > + check_explicit_instantiation_namespace (tmpl); > > In most cases I think DRs should apply to C++98 as well. In this case I > think a pedwarn only with -pedantic in C++98 is appropriate. Let's put > all the logic in check_.... And add a flag to distinguish between > instantiation and specialization.
Thanks for the suggestions. I've implemented them below. (If someone comes up with a better name than: check_instant_or_special_namespace I would change it) BTW both EDG and clang reject g++.dg/template/spec17.C: namespace io { template <typename> int foo(); } using namespace io; template<> int foo<int>(); But I think it is a reasonable extension to accept it. Patch tested on powerpc64-unknown-linux-gnu. 2014-11-03 Markus Trippelsdorf <mar...@trippelsdorf.de> DR 374 PR c++/56480 * pt.c (check_explicit_instantiation_namespace) (check_specialization_namespace): Consolidate into check_instant_or_special_namespace. (check_instant_or_special_namespace): pedwarn only with -pedantic in C++98. (maybe_process_partial_specialization): Call consolidated function. (register_specialization): Likewise. (do_decl_instantiation): Likewise. (do_type_instantiation): Likewise. DR 374 PR c++/56480 * g++.dg/template/spec17.C: Add -pedantic and -pedantic-errors to dg-options. Don't dg-error for C++11 and up. * g++.dg/template/spec25.C: Likewise. Adjust regex. * g++.dg/template/spec36.C: Likewise. * g++.old-deja/g++.ns/template13.C: Likewise. * g++.old-deja/g++.pt/explicit73.C: Likewise. * g++.old-deja/g++.pt/lookup10.C: Likewise. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2cf10f442f68..0eaa6a22f39d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -755,57 +755,58 @@ end_explicit_instantiation (void) processing_explicit_instantiation = false; } -/* An explicit specialization or partial specialization of TMPL is being - declared. Check that the namespace in which the specialization is - occurring is permissible. Returns false iff it is invalid to - specialize TMPL in the current namespace. */ +/* If specialization is true, an explicit specialization or partial + specialization of TMPL is being declared. Check that the namespace + in which the specialization is occurring is permissible. Returns + false iff it is invalid to specialize TMPL in the current namespace. + If specialization is false, TMPL is an explicit instantiation. + Check that it is valid to perform this explicit instantiation in + the current namespace. */ static bool -check_specialization_namespace (tree tmpl) +check_instant_or_special_namespace (tree tmpl, bool specialization) { tree tpl_ns = decl_namespace_context (tmpl); - /* [tmpl.expl.spec] - - An explicit specialization shall be declared in the namespace of - which the template is a member, or, for member templates, in the - namespace of which the enclosing class or enclosing class - template is a member. An explicit specialization of a member - function, member class or static data member of a class template - shall be declared in the namespace of which the class template is - a member. */ - if (current_scope() != DECL_CONTEXT (tmpl) - && !at_namespace_scope_p ()) + if (specialization) { - error ("specialization of %qD must appear at namespace scope", tmpl); - return false; - } - if (is_associated_namespace (current_namespace, tpl_ns)) - /* Same or super-using namespace. */ - return true; - else - { - permerror (input_location, "specialization of %qD in different namespace", tmpl); - permerror (input_location, " from definition of %q+#D", tmpl); - return false; - } -} - -/* SPEC is an explicit instantiation. Check that it is valid to - perform this explicit instantiation in the current namespace. */ + /* [tmpl.expl.spec] -static void -check_explicit_instantiation_namespace (tree spec) -{ - tree ns; + An explicit specialization shall be declared in the namespace of + which the template is a member, or, for member templates, in the + namespace of which the enclosing class or enclosing class + template is a member. An explicit specialization of a member + function, member class or static data member of a class template + shall be declared in the namespace of which the class template is + a member. */ + if (current_scope () != DECL_CONTEXT (tmpl) && !at_namespace_scope_p ()) + { + error ("specialization of %qD must appear at namespace scope", tmpl); + return false; + } + if (is_associated_namespace (current_namespace, tpl_ns)) + /* Same or super-using namespace. */ + return true; + /* DR374: explicit specializations of templates in an enclosing + namespace are allowed. */ + else if (cxx_dialect < cxx11) + { + pedwarn (input_location, OPT_Wpedantic, + "specialization of %qD in different namespace", tmpl); + pedwarn (input_location, OPT_Wpedantic, + " from definition of %q+#D", tmpl); + } + } /* DR 275: An explicit instantiation shall appear in an enclosing namespace of its template. */ - ns = decl_namespace_context (spec); - if (!is_ancestor (current_namespace, ns)) - permerror (input_location, "explicit instantiation of %qD in namespace %qD " - "(which does not enclose namespace %qD)", - spec, current_namespace, ns); + if (!is_ancestor (current_namespace, tpl_ns)) + permerror (input_location, + "explicit instantiation of %qD in namespace %qD " + "(which does not enclose namespace %qD)", + tmpl, current_namespace, tpl_ns); + + return false; } /* The TYPE is being declared. If it is a template type, that means it @@ -859,7 +860,8 @@ maybe_process_partial_specialization (tree type) if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type)) { - if (!check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type)) + if (!check_instant_or_special_namespace ( + CLASSTYPE_TI_TEMPLATE (type), true) && !at_namespace_scope_p ()) return error_mark_node; SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type); @@ -1454,7 +1456,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, DECL_DELETED_FN (clone) = DECL_DELETED_FN (fn); } - check_specialization_namespace (tmpl); + check_instant_or_special_namespace (tmpl, true); return fn; } @@ -1476,7 +1478,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, /* A specialization must be declared in the same namespace as the template it is specializing. */ if (DECL_P (spec) && DECL_TEMPLATE_SPECIALIZATION (spec) - && !check_specialization_namespace (tmpl)) + && !check_instant_or_special_namespace (tmpl, true)) DECL_CONTEXT (spec) = DECL_CONTEXT (tmpl); if (slot != NULL /* !optimize_specialization_lookup_p (tmpl) */) @@ -19406,7 +19408,7 @@ do_decl_instantiation (tree decl, tree storage) else error ("storage class %qD applied to template instantiation", storage); - check_explicit_instantiation_namespace (result); + check_instant_or_special_namespace (result, false); mark_decl_instantiated (result, extern_p); if (! extern_p) instantiate_decl (result, /*defer_ok=*/1, @@ -19554,7 +19556,7 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain) return; } - check_explicit_instantiation_namespace (TYPE_NAME (t)); + check_instant_or_special_namespace (TYPE_NAME (t), false); mark_class_instantiated (t, extern_p); if (nomem_p) diff --git a/gcc/testsuite/g++.dg/template/spec17.C b/gcc/testsuite/g++.dg/template/spec17.C index 237557684238..0b2e02bf450c 100644 --- a/gcc/testsuite/g++.dg/template/spec17.C +++ b/gcc/testsuite/g++.dg/template/spec17.C @@ -1,11 +1,12 @@ // PR c++/16224 +// { dg-options "-pedantic -pedantic-errors" } namespace io { - template <typename> int foo(); // { dg-error "" } + template <typename> int foo(); // { dg-error "" "" { target { ! c++11 } } } } using namespace io; -template<> int foo<int>(); // { dg-error "" } +template<> int foo<int>(); // { dg-error "" "" { target { ! c++11 } } } int a = foo<int>(); diff --git a/gcc/testsuite/g++.dg/template/spec25.C b/gcc/testsuite/g++.dg/template/spec25.C index 385d19ada0c4..c7b51a4beca7 100644 --- a/gcc/testsuite/g++.dg/template/spec25.C +++ b/gcc/testsuite/g++.dg/template/spec25.C @@ -1,10 +1,11 @@ +// { dg-options "-pedantic -pedantic-errors" } namespace N { template <typename T> struct S { - void f() {} // { dg-error "definition" } + void f() {} // { dg-error "definition" "" { target { ! c++11 } } } }; } namespace K { - template <> void N::S<char>::f() {} // { dg-error "different namespace" } + template <> void N::S<char>::f() {} // { dg-error "namespace" } } diff --git a/gcc/testsuite/g++.dg/template/spec36.C b/gcc/testsuite/g++.dg/template/spec36.C index 7e8dc5241d9f..277a7f6243d5 100644 --- a/gcc/testsuite/g++.dg/template/spec36.C +++ b/gcc/testsuite/g++.dg/template/spec36.C @@ -1,5 +1,6 @@ /* PR c++/38089 */ /* { dg-do compile } */ +/* { dg-options "-pedantic -pedantic-errors" } */ struct basic_string { @@ -8,9 +9,9 @@ struct basic_string namespace MyNS { class MyClass { template <typename T> - T test() { } /* { dg-error "from definition" } */ + T test() { } /* { dg-error "from definition" "" { target { ! c++11 } } } */ }; } template <> -basic_string MyNS::MyClass::test() /* { dg-error "specialization of" } */ +basic_string MyNS::MyClass::test() /* { dg-error "specialization of" "" { target { ! c++11 } } } */ { return 1; } diff --git a/gcc/testsuite/g++.old-deja/g++.ns/template13.C b/gcc/testsuite/g++.old-deja/g++.ns/template13.C index a9559c7153b6..805811fd8b54 100644 --- a/gcc/testsuite/g++.old-deja/g++.ns/template13.C +++ b/gcc/testsuite/g++.old-deja/g++.ns/template13.C @@ -1,10 +1,11 @@ // { dg-do compile } +// { dg-options "-pedantic -pedantic-errors" } // Templates defined outside must be declared inside namespace bar { // trick it to provide some prior declaration template<class T> - void foo(); // { dg-error "definition" } + void foo(); // { dg-error "definition" "" { target { ! c++11 } } } template<class T>class X; // { dg-message "note: previous declaration" } } @@ -15,7 +16,7 @@ bar::foo(T const &a) // { dg-error "" "" { xfail *-*-* } } not declared in b return a; } -template<> void bar::foo<int>() // { dg-error "different namespace" } +template<> void bar::foo<int>() // { dg-error "different namespace" "" { target { ! c++11 } } } { } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C index 1d83e3468289..1f5e1e9d8d7b 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C @@ -1,4 +1,5 @@ // { dg-do assemble } +// { dg-options "-pedantic -pedantic-errors" } // by Alexandre Oliva <ol...@dcc.unicamp.br> @@ -7,9 +8,9 @@ // the template namespace N { - template <class T> class foo; // { dg-error "" } referenced below + template <class T> class foo; // { dg-error "" "" { target { ! c++11 } } } referenced below } using namespace N; -template <> class foo<void>; // { dg-error "" } invalid specialization +template <> class foo<void>; // { dg-error "" "" { target { ! c++11 } } } invalid specialization diff --git a/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C b/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C index 1c04250fc3c0..02b21d94cc9b 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C @@ -1,4 +1,5 @@ // { dg-do assemble } +// { dg-options "-pedantic -pedantic-errors" } // Copyright (C) 2000 Free Software Foundation // Contributed by Nathan Sidwell 3 July 2000 <nat...@codesourcery.com> @@ -13,8 +14,8 @@ namespace Outer { namespace Core = Core_Real; namespace Core_Real { - template<class T> void Foo (T *) {} // { dg-error "definition" } + template<class T> void Foo (T *) {} // { dg-error "definition" "" { target { ! c++11 } } } } - template<> void Core::Foo<> (Render_Real::Type *) {} // { dg-error "" } + template<> void Core::Foo<> (Render_Real::Type *) {} // { dg-error "" "" { target { ! c++11 } } } } -- Markus