On 2014.11.03 at 08:47 -0600, Jason Merrill wrote: > On 11/03/2014 05:27 AM, Markus Trippelsdorf wrote: > > 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. > > We should reject it, too. We can only leave out the namespace > qualification with inline namespaces. > > > +// { dg-options "-pedantic -pedantic-errors" } > > You shouldn't need these dg-options lines; if a testcase has no > dg-options line, -pedantic-errors is the default.
The following patch passes testing and fixes both issues. Please let me know if you're OK with the general direction, before I write a full Changelog. Thanks. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 320c39f636a2..ddfa5ebfd968 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7855,7 +7855,8 @@ grokfndecl (tree ctype, decl = check_explicit_specialization (orig_declarator, decl, template_count, 2 * funcdef_flag + - 4 * (friendp != 0)); + 4 * (friendp != 0) + + 8 * (in_namespace != 0)); if (decl == error_mark_node) return NULL_TREE; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2cf10f442f68..5cc320ed2fcf 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 ()) - { - 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 + if (specialization) { - permerror (input_location, "specialization of %qD in different namespace", tmpl); - permerror (input_location, " from definition of %q+#D", tmpl); - return false; - } -} + /* [tmpl.expl.spec] -/* SPEC is an explicit instantiation. Check that it is valid to - perform this explicit instantiation in the current namespace. */ - -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 " + if (!is_ancestor (current_namespace, tpl_ns)) + permerror (input_location, + "explicit instantiation of %qD in namespace %qD " "(which does not enclose namespace %qD)", - spec, current_namespace, ns); + 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); @@ -1338,14 +1340,22 @@ is_specialization_of_friend (tree decl, tree friend_decl) is actually just a friend declaration. Returns SPEC, or an equivalent prior declaration, if available. + FLAGS is a bitmask consisting of the following flags: + + 2: The function has a definition. + 4: The function is a friend. + 8: The function has explicit namespace qualification. + We also store instantiations of field packs in the hash table, even though they are not themselves templates, to make lookup easier. */ static tree register_specialization (tree spec, tree tmpl, tree args, bool is_friend, - hashval_t hash) + hashval_t hash, int flags) { tree fn; + int have_def = flags & 2; + int in_namespace = flags & 8; spec_entry **slot = NULL; spec_entry elt; @@ -1454,7 +1464,15 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, DECL_DELETED_FN (clone) = DECL_DELETED_FN (fn); } - check_specialization_namespace (tmpl); + + + if (!is_associated_namespace (current_namespace, + decl_namespace_context (tmpl)) + && !have_def && !in_namespace) + error ("no function template matches function " + "template specialization"); + + check_instant_or_special_namespace (tmpl, true); return fn; } @@ -1476,7 +1494,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) */) @@ -2347,6 +2365,7 @@ check_template_variable (tree decl) 2: The function has a definition. 4: The function is a friend. + 8: The function has explicit namespace qualification. The TEMPLATE_COUNT is the number of references to qualifying template classes that appeared in the name of the function. For @@ -2741,7 +2760,7 @@ check_explicit_specialization (tree declarator, DECL_CONTEXT (parm) = result; } return register_specialization (tmpl, gen_tmpl, targs, - is_friend, 0); + is_friend, 0, 0); } /* Set up the DECL_TEMPLATE_INFO for DECL. */ @@ -2821,7 +2840,7 @@ check_explicit_specialization (tree declarator, /* Register this specialization so that we can find it again. */ - decl = register_specialization (decl, gen_tmpl, targs, is_friend, 0); + decl = register_specialization (decl, gen_tmpl, targs, is_friend, 0, flags); /* A 'structor should already have clones. */ gcc_assert (decl == error_mark_node @@ -4930,7 +4949,7 @@ push_template_decl_real (tree decl, bool is_friend) register_specialization (new_tmpl, most_general_template (tmpl), args, - is_friend, 0); + is_friend, 0, 0); return decl; } @@ -8661,7 +8680,7 @@ tsubst_friend_function (tree decl, tree args) DECL_TI_ARGS (spec)); register_specialization - (spec, new_template, DECL_TI_ARGS (spec), true, 0); + (spec, new_template, DECL_TI_ARGS (spec), true, 0, 0); } DECL_TEMPLATE_INSTANTIATIONS (old_decl) = NULL_TREE; @@ -10587,7 +10606,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* Record this non-type partial instantiation. */ register_specialization (r, t, DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)), - false, hash); + false, hash, 0); } break; @@ -10795,7 +10814,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) SET_DECL_IMPLICIT_INSTANTIATION (r); tree new_r - = register_specialization (r, gen_tmpl, argvec, false, hash); + = register_specialization (r, gen_tmpl, argvec, false, hash, 0); if (new_r != r) /* We instantiated this while substituting into the type earlier (template/friend54.C). */ @@ -11067,7 +11086,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) SET_ARGUMENT_PACK_ARGS (pack, vec); SET_ARGUMENT_PACK_ARGS (tpack, expanded_types); TREE_TYPE (pack) = tpack; - register_specialization (pack, t, args, false, 0); + register_specialization (pack, t, args, false, 0, 0); } } break; @@ -11293,7 +11312,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) processing here. */ DECL_EXTERNAL (r) = 1; - register_specialization (r, gen_tmpl, argvec, false, hash); + register_specialization (r, gen_tmpl, argvec, false, hash, 0); DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec); SET_DECL_IMPLICIT_INSTANTIATION (r); } @@ -19406,7 +19425,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 +19573,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..849178920012 100644 --- a/gcc/testsuite/g++.dg/template/spec17.C +++ b/gcc/testsuite/g++.dg/template/spec17.C @@ -1,7 +1,7 @@ // PR c++/16224 namespace io { - template <typename> int foo(); // { dg-error "" } + template <typename> int foo(); // { dg-error "" "" { target { ! c++11 } } } } using namespace io; diff --git a/gcc/testsuite/g++.dg/template/spec25.C b/gcc/testsuite/g++.dg/template/spec25.C index 385d19ada0c4..c3836261f6af 100644 --- a/gcc/testsuite/g++.dg/template/spec25.C +++ b/gcc/testsuite/g++.dg/template/spec25.C @@ -1,10 +1,10 @@ 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..d9c57824b7e5 100644 --- a/gcc/testsuite/g++.dg/template/spec36.C +++ b/gcc/testsuite/g++.dg/template/spec36.C @@ -8,9 +8,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..0c99e74dc466 100644 --- a/gcc/testsuite/g++.old-deja/g++.ns/template13.C +++ b/gcc/testsuite/g++.old-deja/g++.ns/template13.C @@ -4,7 +4,7 @@ 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 +15,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..bcf4fe7f21a5 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit73.C @@ -7,9 +7,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..0ed5dbe42c89 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C @@ -13,8 +13,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