From b1cc95ce4c15c335589c5e0077c29c06c739e730 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Mon, 2 Aug 2004 06:25:36 +0000 Subject: [PATCH] re PR c++/16224 (internal compiler error: in write_unscoped_name (template/namespace)) PR c++/16224 * name-lookup.c (decl_namespace): Remove. (current_decl_namespace): Use decl_namespace_context instead of decl_namespace. (push_decl_namespace): Likewise. (arg_assoc_class): Likewise. (arg_assoc_type): Likewise. * pt.c (check_specialization_namespace): New function. (maybe_process_partial_specialization): Use it. (register_specialization): Likewise. PR c++/16224 * g++.dg/template/spec17.C: New test. * g++.old-deja/g++.ns/template13.C: Remove XFAIL. * g++.old-deja/g++.pt/lookup10.C: Add dg-error marker. From-SVN: r85431 --- gcc/cp/ChangeLog | 11 ++ gcc/cp/name-lookup.c | 31 +--- gcc/cp/pt.c | 140 +++++++++++------- gcc/testsuite/ChangeLog | 7 + gcc/testsuite/g++.dg/template/spec17.C | 11 ++ .../g++.old-deja/g++.ns/template13.C | 5 +- gcc/testsuite/g++.old-deja/g++.pt/lookup10.C | 4 +- 7 files changed, 122 insertions(+), 87 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/spec17.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fffa892d494d..81a819a79316 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,16 @@ 2004-08-01 Mark Mitchell + PR c++/16224 + * name-lookup.c (decl_namespace): Remove. + (current_decl_namespace): Use decl_namespace_context instead of + decl_namespace. + (push_decl_namespace): Likewise. + (arg_assoc_class): Likewise. + (arg_assoc_type): Likewise. + * pt.c (check_specialization_namespace): New function. + (maybe_process_partial_specialization): Use it. + (register_specialization): Likewise. + PR c++/16489 * cp-tree.h (DECL_INTEGRAL_CONSTANT_VAR_P): New macro. * call.c (null_ptr_cst_p): Handle variables with constant diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 8c36fe8bd0ec..c44541285fb7 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2991,27 +2991,6 @@ set_namespace_binding (tree name, tree scope, tree val) timevar_pop (TV_NAME_LOOKUP); } -/* Compute the namespace where a declaration is defined. */ - -static tree -decl_namespace (tree decl) -{ - timevar_push (TV_NAME_LOOKUP); - if (TYPE_P (decl)) - decl = TYPE_STUB_DECL (decl); - while (DECL_CONTEXT (decl)) - { - decl = DECL_CONTEXT (decl); - if (TREE_CODE (decl) == NAMESPACE_DECL) - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl); - if (TYPE_P (decl)) - decl = TYPE_STUB_DECL (decl); - my_friendly_assert (DECL_P (decl), 390); - } - - POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, global_namespace); -} - /* Set the context of a declaration to scope. Complain if we are not outside scope. */ @@ -3080,9 +3059,9 @@ current_decl_namespace (void) return TREE_PURPOSE (decl_namespace_list); if (current_class_type) - result = decl_namespace (TYPE_STUB_DECL (current_class_type)); + result = decl_namespace_context (current_class_type); else if (current_function_decl) - result = decl_namespace (current_function_decl); + result = decl_namespace_context (current_function_decl); else result = current_namespace; return result; @@ -3210,7 +3189,7 @@ void push_decl_namespace (tree decl) { if (TREE_CODE (decl) != NAMESPACE_DECL) - decl = decl_namespace (decl); + decl = decl_namespace_context (decl); decl_namespace_list = tree_cons (ORIGINAL_NAMESPACE (decl), NULL_TREE, decl_namespace_list); } @@ -4394,7 +4373,7 @@ arg_assoc_class (struct arg_lookup *k, tree type) return false; k->classes = tree_cons (type, NULL_TREE, k->classes); - context = decl_namespace (TYPE_MAIN_DECL (type)); + context = decl_namespace_context (type); if (arg_assoc_namespace (k, context)) return true; @@ -4483,7 +4462,7 @@ arg_assoc_type (struct arg_lookup *k, tree type) return arg_assoc_type (k, TREE_TYPE (type)); case UNION_TYPE: case ENUMERAL_TYPE: - return arg_assoc_namespace (k, decl_namespace (TYPE_MAIN_DECL (type))); + return arg_assoc_namespace (k, decl_namespace_context (type)); case METHOD_TYPE: /* The basetype is referenced in the first arg type, so just fall through. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ad4891049748..1e9bbb131227 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -708,6 +708,36 @@ end_explicit_instantiation (void) processing_explicit_instantiation = false; } +/* A explicit specialization or partial specialization 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. */ + +static bool +check_specialization_namespace (tree tmpl) +{ + 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 (is_associated_namespace (current_namespace, tpl_ns)) + /* Same or super-using namespace. */ + return true; + else + { + pedwarn ("specialization of `%D' in different namespace", tmpl); + cp_pedwarn_at (" from definition of `%#D'", tmpl); + return false; + } +} + /* The TYPE is being declared. If it is a template type, that means it is a partial specialization. Do appropriate error-checking. */ @@ -733,15 +763,7 @@ maybe_process_partial_specialization (tree type) if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type)) { - tree tpl_ns = decl_namespace_context (CLASSTYPE_TI_TEMPLATE (type)); - if (is_associated_namespace (current_namespace, tpl_ns)) - /* Same or super-using namespace. */; - else - { - pedwarn ("specializing `%#T' in different namespace", type); - cp_pedwarn_at (" from definition of `%#D'", - CLASSTYPE_TI_TEMPLATE (type)); - } + check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type)); SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type); if (processing_template_decl) push_template_decl (TYPE_MAIN_DECL (type)); @@ -1057,64 +1079,68 @@ register_specialization (tree spec, tree tmpl, tree args) more convenient to simply allow this than to try to prevent it. */ if (fn == spec) return spec; - else if (comp_template_args (TREE_PURPOSE (s), args)) + else if (comp_template_args (TREE_PURPOSE (s), args) + && DECL_TEMPLATE_SPECIALIZATION (spec)) { - if (DECL_TEMPLATE_SPECIALIZATION (spec)) + if (DECL_TEMPLATE_INSTANTIATION (fn)) { - if (DECL_TEMPLATE_INSTANTIATION (fn)) + if (TREE_USED (fn) + || DECL_EXPLICIT_INSTANTIATION (fn)) { - if (TREE_USED (fn) - || DECL_EXPLICIT_INSTANTIATION (fn)) - { - error ("specialization of %D after instantiation", - fn); - return spec; - } - else - { - /* This situation should occur only if the first - specialization is an implicit instantiation, - the second is an explicit specialization, and - the implicit instantiation has not yet been - used. That situation can occur if we have - implicitly instantiated a member function and - then specialized it later. - - We can also wind up here if a friend - declaration that looked like an instantiation - turns out to be a specialization: - - template void foo(T); - class S { friend void foo<>(int) }; - template <> void foo(int); - - We transform the existing DECL in place so that - any pointers to it become pointers to the - updated declaration. - - If there was a definition for the template, but - not for the specialization, we want this to - look as if there were no definition, and vice - versa. */ - DECL_INITIAL (fn) = NULL_TREE; - duplicate_decls (spec, fn); - - return fn; - } + error ("specialization of %D after instantiation", + fn); + return spec; } - else if (DECL_TEMPLATE_SPECIALIZATION (fn)) + else { - if (!duplicate_decls (spec, fn) && DECL_INITIAL (spec)) - /* Dup decl failed, but this is a new - definition. Set the line number so any errors - match this new definition. */ - DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (spec); + /* This situation should occur only if the first + specialization is an implicit instantiation, the + second is an explicit specialization, and the + implicit instantiation has not yet been used. + That situation can occur if we have implicitly + instantiated a member function and then + specialized it later. + + We can also wind up here if a friend declaration + that looked like an instantiation turns out to be + a specialization: + + template void foo(T); + class S { friend void foo<>(int) }; + template <> void foo(int); + + We transform the existing DECL in place so that + any pointers to it become pointers to the updated + declaration. + + If there was a definition for the template, but + not for the specialization, we want this to look + as if there were no definition, and vice + versa. */ + DECL_INITIAL (fn) = NULL_TREE; + duplicate_decls (spec, fn); return fn; } } + else if (DECL_TEMPLATE_SPECIALIZATION (fn)) + { + if (!duplicate_decls (spec, fn) && DECL_INITIAL (spec)) + /* Dup decl failed, but this is a new definition. Set + the line number so any errors match this new + definition. */ + DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (spec); + + return fn; + } } - } + } + + /* A specialization must be declared in the same namespace as the + template it is specializing. */ + if (DECL_TEMPLATE_SPECIALIZATION (spec) + && !check_specialization_namespace (tmpl)) + DECL_CONTEXT (spec) = decl_namespace_context (tmpl); DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e394b1fe28c3..eb04ff1fd019 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2004-08-01 Mark Mitchell + + PR c++/16224 + * g++.dg/template/spec17.C: New test. + * g++.old-deja/g++.ns/template13.C: Remove XFAIL. + * g++.old-deja/g++.pt/lookup10.C: Add dg-error marker. + 2004-08-02 David Billinghurst PR fortran/16292 diff --git a/gcc/testsuite/g++.dg/template/spec17.C b/gcc/testsuite/g++.dg/template/spec17.C new file mode 100644 index 000000000000..237557684238 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/spec17.C @@ -0,0 +1,11 @@ +// PR c++/16224 + +namespace io { + template int foo(); // { dg-error "" } +} + +using namespace io; + +template<> int foo(); // { dg-error "" } + +int a = foo(); diff --git a/gcc/testsuite/g++.old-deja/g++.ns/template13.C b/gcc/testsuite/g++.old-deja/g++.ns/template13.C index d7e4b7970941..058d7b9ec88e 100644 --- a/gcc/testsuite/g++.old-deja/g++.ns/template13.C +++ b/gcc/testsuite/g++.old-deja/g++.ns/template13.C @@ -2,8 +2,9 @@ // Templates defined outside must be declared inside namespace bar { + // trick it to provide some prior declaration template - void foo(); // trick it to provide some prior declaration + void foo(); // { dg-error "definition" } templateclass X; // { dg-error "" } previous declaration } @@ -15,7 +16,7 @@ bar::foo(T const &a) } template<> void bar::foo() -{ // { dg-error "" "" { xfail *-*-* } } not declared in bar - +{ // { dg-error "" } } template diff --git a/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C b/gcc/testsuite/g++.old-deja/g++.pt/lookup10.C index c0b4389162c8..1c04250fc3c0 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 void Foo (T *) {} + template void Foo (T *) {} // { dg-error "definition" } } - template<> void Core::Foo<> (Render_Real::Type *) {} + template<> void Core::Foo<> (Render_Real::Type *) {} // { dg-error "" } } -- 2.43.5