re PR c++/509 (G++ forbids template specialization as ambiguous)
authorGiovanni Bajo <giovannibajo@gcc.gnu.org>
Wed, 21 Jul 2004 00:06:45 +0000 (00:06 +0000)
committerGiovanni Bajo <giovannibajo@gcc.gnu.org>
Wed, 21 Jul 2004 00:06:45 +0000 (00:06 +0000)
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
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/spec15.C [new file with mode: 0644]

index 3038907545c525a00af7c27ed3f72af383023504..5883b7e26deed87065665e3e15f2b94838dde228 100644 (file)
@@ -1,3 +1,12 @@
+2004-07-21  Giovanni Bajo  <giovannibajo@gcc.gnu.org>
+
+       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  <stevenb@suse.de>
 
        * cp-tree.def (TINST_LEVEL): Make it an 'x' node.
index 86f945e7f8fa2ea0ee35b7dcdbebcc87866e0a60..3971b6d37d2b89c0d29d94055550ce5dbf9972da 100644 (file)
@@ -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<int>::f(int);
+            template <> template <> void A<int>::f(int);
+
+            Assuming that A<int> 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;
     }
index 39601decd154c7c81f20cc46822078ed6981b868..b939e330a34ac8d68d86947bae1ba324ab245f1e 100644 (file)
@@ -1,3 +1,8 @@
+2004-07-21  Giovanni Bajo  <giovannibajo@gcc.gnu.org>
+
+       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 (file)
index 0000000..fcf4ecb
--- /dev/null
@@ -0,0 +1,34 @@
+// { dg-do compile }
+// Contributed by Wolfgang Bangerth <bangerth at ticam dot utexas dot edu>
+// PR c++/509: Make sure specializations of member templates match correctly
+//  between template and non-template overloads.
+
+template <class T>
+struct A {
+  template <class U> void f (U);
+  void f2 (int);
+
+  template <class U> void h (U);
+  void h (long);
+};
+
+template <>
+struct A<float> {
+  template <class U> void g (U);
+  void g2 (float);
+};
+
+template <> void A<int>::f (int);                    // { dg-error "" }
+template <> template <> void A<int>::f (int);
+
+template <> void A<int>::f2 (int);
+template <> template <> void A<int>::f2 (int);       // { dg-error "" }
+
+template <> void A<float>::g (float);
+template <> template <> void A<float>::g(float);     // { dg-error "" }
+
+template <> void A<float>::g2 (float);               // { dg-error "" }
+template <> template <> void A<float>::g2(float);    // { dg-error "" }
+
+template <> void A<long>::h (long);
+template <> template <> void A<long>::h(long);