From 5fe7b6549e1d588e3b0ae4015d61080bac3dbf37 Mon Sep 17 00:00:00 2001 From: Giovanni Bajo Date: Wed, 21 Jul 2004 00:06:45 +0000 Subject: [PATCH] re PR c++/509 (G++ forbids template specialization as ambiguous) PR c++/509 * pt.c (determine_specialization): New parameter template_count. Disambiguate between member templates and member functions counting the template headers. (check_explicit_specialization): Update caller. (tsubst_friend_function): Likewise. PR c++/509 * g++.dg/template/spec15.C: New test. From-SVN: r84982 --- gcc/cp/ChangeLog | 9 +++++ gcc/cp/pt.c | 54 ++++++++++++++++++++++++-- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/g++.dg/template/spec15.C | 34 ++++++++++++++++ 4 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/spec15.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3038907545c..5883b7e26de 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2004-07-21 Giovanni Bajo + + PR c++/509 + * pt.c (determine_specialization): New parameter template_count. + Disambiguate between member templates and member functions counting + the template headers. + (check_explicit_specialization): Update caller. + (tsubst_friend_function): Likewise. + 2004-07-20 Steven Bosscher * cp-tree.def (TINST_LEVEL): Make it an 'x' node. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 86f945e7f8f..3971b6d37d2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -155,7 +155,7 @@ static int verify_class_unification (tree, tree, tree); static tree try_class_unification (tree, tree, tree, tree); static int coerce_template_template_parms (tree, tree, tsubst_flags_t, tree, tree); -static tree determine_specialization (tree, tree, tree *, int); +static tree determine_specialization (tree, tree, tree *, int, int); static int template_args_equal (tree, tree); static void tsubst_default_arguments (tree); static tree for_each_template_parm_r (tree *, int *, void *); @@ -1205,6 +1205,10 @@ print_candidates (tree fns) If NEED_MEMBER_TEMPLATE is nonzero the function is known to be a specialization of a member template. + The TEMPLATE_COUNT is the number of references to qualifying + template classes that appeared in the name of the function. See + check_explicit_specialization for a more accurate description. + The template args (those explicitly specified and those deduced) are output in a newly created vector *TARGS_OUT. @@ -1215,13 +1219,16 @@ static tree determine_specialization (tree template_id, tree decl, tree* targs_out, - int need_member_template) + int need_member_template, + int template_count) { tree fns; tree targs; tree explicit_targs; tree candidates = NULL_TREE; tree templates = NULL_TREE; + int header_count; + struct cp_binding_level *b; *targs_out = NULL_TREE; @@ -1244,6 +1251,14 @@ determine_specialization (tree template_id, return error_mark_node; } + /* Count the number of template headers specified for this + specialization. */ + header_count = 0; + for (b = current_binding_level; + b->kind == sk_template_parms || b->kind == sk_template_spec; + b = b->level_chain) + ++header_count; + for (; fns; fns = OVL_NEXT (fns)) { tree fn = OVL_CURRENT (fns); @@ -1280,6 +1295,35 @@ determine_specialization (tree template_id, TREE_VALUE (decl_arg_types))) continue; + /* In case of explicit specialization, we need to check if + the number of template headers appearing in the specialization + is correct. This is usually done in check_explicit_specialization, + but the check done there cannot be exhaustive when specializing + member functions. Consider the following code: + + template <> void A::f(int); + template <> template <> void A::f(int); + + Assuming that A is not itself an explicit specialization + already, the first line specializes "f" which is a non-template + member function, whilst the second line specializes "f" which + is a template member function. So both lines are syntactically + correct, and check_explicit_specialization does not reject + them. + + Here, we can do better, as we are matching the specialization + against the declarations. We count the number of template + headers, and we check if they match TEMPLATE_COUNT + 1 + (TEMPLATE_COUNT is the number of qualifying template classes, + plus there must be another header for the member template + itself). + + Notice that if header_count is zero, this is not a + specialization but rather a template instantiation, so there + is no check we can perform here. */ + if (header_count && header_count != template_count + 1) + continue; + /* See whether this function might be a specialization of this template. */ targs = get_bindings (fn, decl, explicit_targs); @@ -1872,7 +1916,8 @@ check_explicit_specialization (tree declarator, declaration. */ tmpl = determine_specialization (declarator, decl, &targs, - member_specialization); + member_specialization, + template_count); if (!tmpl || tmpl == error_mark_node) /* We couldn't figure out what this declaration was @@ -4980,7 +5025,8 @@ tsubst_friend_function (tree decl, tree args) new_friend = tsubst (decl, args, tf_error | tf_warning, NULL_TREE); tmpl = determine_specialization (template_id, new_friend, &new_args, - /*need_member_template=*/0); + /*need_member_template=*/0, + TREE_VEC_LENGTH (args)); new_friend = instantiate_template (tmpl, new_args, tf_error); goto done; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 39601decd15..b939e330a34 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2004-07-21 Giovanni Bajo + + PR c++/509 + * g++.dg/template/spec15.C: New test. + 2004-07-21 David Billinghurst (David.Billinghurst@riotinto.com) Copy cases from g77.f-torture/execute and add dg-run diff --git a/gcc/testsuite/g++.dg/template/spec15.C b/gcc/testsuite/g++.dg/template/spec15.C new file mode 100644 index 00000000000..fcf4ecb904d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/spec15.C @@ -0,0 +1,34 @@ +// { dg-do compile } +// Contributed by Wolfgang Bangerth +// PR c++/509: Make sure specializations of member templates match correctly +// between template and non-template overloads. + +template +struct A { + template void f (U); + void f2 (int); + + template void h (U); + void h (long); +}; + +template <> +struct A { + template void g (U); + void g2 (float); +}; + +template <> void A::f (int); // { dg-error "" } +template <> template <> void A::f (int); + +template <> void A::f2 (int); +template <> template <> void A::f2 (int); // { dg-error "" } + +template <> void A::g (float); +template <> template <> void A::g(float); // { dg-error "" } + +template <> void A::g2 (float); // { dg-error "" } +template <> template <> void A::g2(float); // { dg-error "" } + +template <> void A::h (long); +template <> template <> void A::h(long); -- 2.30.2