OSDN Git Service

cp:
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 31 Mar 2005 17:36:17 +0000 (17:36 +0000)
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 31 Mar 2005 17:36:17 +0000 (17:36 +0000)
PR c++/19203, implement DR 214
* call.c (joust): Use more_specialized_fn.
* cp-tree.h (DEDUCE_ORDER): Remove.
(more_specialized): Replace with ...
(more_specialized_fn): ... this.
* pt.c (maybe_adjust_types_for_deduction): Remove DEDUCE_ORDER
case.
(type_unification_real): Remove DEDUCE_ORDER case.
(more_specialized): Replace with ...
(more_specialized_fn): ... this.  Implement DR 214.
(most_specialized_instantiation): Use get_bindings_real directly.
testsuite:
PR c++/19203, DR 214
* g++.dg/parse/ambig3.C: Not ambiguous.
* g++.dg/template/spec20.C: New.
* g++.dg/template/spec21.C: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@97336 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/parse/ambig3.C
gcc/testsuite/g++.dg/template/spec20.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/spec21.C [new file with mode: 0644]

index b63906c..93c7170 100644 (file)
@@ -1,3 +1,17 @@
+2005-03-31  Nathan Sidwell  <nathan@codesourcery.com>
+
+       PR c++/19203, implement DR 214
+       * call.c (joust): Use more_specialized_fn.
+       * cp-tree.h (DEDUCE_ORDER): Remove.
+       (more_specialized): Replace with ...
+       (more_specialized_fn): ... this.
+       * pt.c (maybe_adjust_types_for_deduction): Remove DEDUCE_ORDER
+       case.
+       (type_unification_real): Remove DEDUCE_ORDER case.
+       (more_specialized): Replace with ...
+       (more_specialized_fn): ... this.  Implement DR 214.
+       (most_specialized_instantiation): Use get_bindings_real directly.
+
 2005-03-31  Gabriel Dos Reis  <gdr@integrable-solutions.net>
 
        PR c++/18644
index 131e175..9d76276 100644 (file)
@@ -6084,10 +6084,9 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn)
   
   if (cand1->template_decl && cand2->template_decl)
     {
-      winner = more_specialized
+      winner = more_specialized_fn
         (TI_TEMPLATE (cand1->template_decl),
          TI_TEMPLATE (cand2->template_decl),
-         DEDUCE_ORDER,
          /* Tell the deduction code how many real function arguments
            we saw, not counting the implicit 'this' argument.  But,
            add_function_candidate() suppresses the "this" argument
index ac025d6..7f4efc3 100644 (file)
@@ -3112,8 +3112,7 @@ extern int function_depth;
 typedef enum unification_kind_t {
   DEDUCE_CALL,
   DEDUCE_CONV,
-  DEDUCE_EXACT,
-  DEDUCE_ORDER
+  DEDUCE_EXACT
 } unification_kind_t;
 
 /* Macros for operating on a template instantiation level node.  */
@@ -3998,7 +3997,7 @@ extern tree instantiate_class_template            (tree);
 extern tree instantiate_template               (tree, tree, tsubst_flags_t);
 extern int fn_type_unification                  (tree, tree, tree, tree, tree, unification_kind_t, int);
 extern void mark_decl_instantiated             (tree, int);
-extern int more_specialized                    (tree, tree, int, int);
+extern int more_specialized_fn                 (tree, tree, int);
 extern void mark_class_instantiated            (tree, int);
 extern void do_decl_instantiation              (tree, tree);
 extern void do_type_instantiation              (tree, tree, tsubst_flags_t);
index d5514f3..b80faae 100644 (file)
@@ -9064,11 +9064,6 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain)
      as in [temp.expl.spec], or when taking the address of a function
      template, as in [temp.deduct.funcaddr]. 
 
-   DEDUCE_ORDER:
-     We are deducing arguments when calculating the partial
-     ordering between specializations of function or class
-     templates, as in [temp.func.order] and [temp.class.order].
-
    LEN is the number of parms to consider before returning success, or -1
    for all.  This is used in partial ordering to avoid comparing parms for
    which no actual argument was passed, since they are not considered in
@@ -9216,28 +9211,6 @@ maybe_adjust_types_for_deduction (unification_kind_t strict,
       /* There is nothing to do in this case.  */
       return 0;
 
-    case DEDUCE_ORDER:
-      /* DR 214. [temp.func.order] is underspecified, and leads to no
-         ordering between things like `T *' and `T const &' for `U *'.
-         The former has T=U and the latter T=U*. The former looks more
-         specialized and John Spicer considers it well-formed (the EDG
-         compiler accepts it).
-
-         John also confirms that deduction should proceed as in a function
-         call. Which implies the usual ARG and PARM conversions as DEDUCE_CALL.
-         However, in ordering, ARG can have REFERENCE_TYPE, but no argument
-         to an actual call can have such a type.
-         
-         If both ARG and PARM are REFERENCE_TYPE, we change neither.
-         If only ARG is a REFERENCE_TYPE, we look through that and then
-         proceed as with DEDUCE_CALL (which could further convert it).  */
-      if (TREE_CODE (*arg) == REFERENCE_TYPE)
-        {
-          if (TREE_CODE (*parm) == REFERENCE_TYPE)
-            return 0;
-          *arg = TREE_TYPE (*arg);
-        }
-      break;
     default:
       gcc_unreachable ();
     }
@@ -9333,10 +9306,6 @@ type_unification_real (tree tparms,
       sub_strict = UNIFY_ALLOW_NONE;
       break;
     
-    case DEDUCE_ORDER:
-      sub_strict = UNIFY_ALLOW_NONE;
-      break;
-      
     default:
       gcc_unreachable ();
     }
@@ -9379,7 +9348,7 @@ type_unification_real (tree tparms,
          else
            type = arg;
 
-         if (strict == DEDUCE_EXACT || strict == DEDUCE_ORDER)
+         if (strict == DEDUCE_EXACT)
            {
              if (same_type_p (parm, type))
                continue;
@@ -10426,36 +10395,158 @@ mark_decl_instantiated (tree result, int extern_p)
 
 /* Given two function templates PAT1 and PAT2, return:
 
-   DEDUCE should be DEDUCE_EXACT or DEDUCE_ORDER.
-   
    1 if PAT1 is more specialized than PAT2 as described in [temp.func.order].
    -1 if PAT2 is more specialized than PAT1.
    0 if neither is more specialized.
 
-   LEN is passed through to fn_type_unification.  */
+   LEN indicates the number of parameters we should consider
+   (defaulted parameters should not be considered).
+
+   The 1998 std underspecified function template partial ordering, and
+   DR214 addresses the issue.  We take pairs of arguments, one from
+   each of the templates, and deduce them against eachother.  One of
+   the templates will be more specialized if all the *other*
+   template's arguments deduce against its arguments and at least one
+   of its arguments *does* *not* deduce against the other template's
+   corresponding argument.  Deduction is done as for class templates.
+   The arguments used in deduction have reference and top level cv
+   qualifiers removed.  Iff both arguments were originally reference
+   types *and* deduction succeeds in both directions, the template
+   with the more cv-qualified argument wins for that pairing (if
+   neither is more cv-qualified, they both are equal).  Unlike regular
+   deduction, after all the arguments have been deduced in this way,
+   we do *not* verify the deduced template argument values can be
+   substituted into non-deduced contexts, nor do we have to verify
+   that all template arguments have been deduced.  */
    
 int
-more_specialized (tree pat1, tree pat2, int deduce, int len)
-{
-  tree targs;
-  int winner = 0;
+more_specialized_fn (tree pat1, tree pat2, int len)
+{
+  tree decl1 = DECL_TEMPLATE_RESULT (pat1);
+  tree decl2 = DECL_TEMPLATE_RESULT (pat2);
+  tree targs1 = make_tree_vec (DECL_NTPARMS (pat1));
+  tree targs2 = make_tree_vec (DECL_NTPARMS (pat2));
+  tree tparms1 = DECL_INNERMOST_TEMPLATE_PARMS (pat1);
+  tree tparms2 = DECL_INNERMOST_TEMPLATE_PARMS (pat2);
+  tree args1 = TYPE_ARG_TYPES (TREE_TYPE (decl1));
+  tree args2 = TYPE_ARG_TYPES (TREE_TYPE (decl2));
+  int better1 = 0;
+  int better2 = 0;
+
+  /* Don't consider 'this' parameter.  */
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1))
+    args1 = TREE_CHAIN (args1);
+  
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2))
+    args2 = TREE_CHAIN (args2);
 
-  /* If template argument deduction succeeds, we substitute the
-     resulting arguments into non-deduced contexts.  While doing that,
-     we must be aware that we may encounter dependent types.  */
-  ++processing_template_decl;
-  targs = get_bindings_real (pat1, DECL_TEMPLATE_RESULT (pat2),
-                             NULL_TREE, 0, deduce, len);
-  if (targs)
-    --winner;
+  /* Consider the return type for a conversion function */
+  if (DECL_CONV_FN_P (decl1))
+    {
+      gcc_assert (DECL_CONV_FN_P (decl2));
+      args1 = tree_cons (NULL_TREE, TREE_TYPE (TREE_TYPE (decl1)), args1);
+      args2 = tree_cons (NULL_TREE, TREE_TYPE (TREE_TYPE (decl2)), args2);
+      len++;
+    }
+  
+  processing_template_decl++;
+  
+  while (len--)
+    {
+      tree arg1 = TREE_VALUE (args1);
+      tree arg2 = TREE_VALUE (args2);
+      int deduce1, deduce2;
+      int quals1 = -1;
+      int quals2 = -1;
 
-  targs = get_bindings_real (pat2, DECL_TEMPLATE_RESULT (pat1),
-                             NULL_TREE, 0, deduce, len);
-  if (targs)
-    ++winner;
-  --processing_template_decl;
+      if (TREE_CODE (arg1) == REFERENCE_TYPE)
+       {
+         arg1 = TREE_TYPE (arg1);
+         quals1 = cp_type_quals (arg1);
+       }
+      
+      if (TREE_CODE (arg2) == REFERENCE_TYPE)
+       {
+         arg2 = TREE_TYPE (arg2);
+         quals2 = cp_type_quals (arg2);
+       }
 
-  return winner;
+      if ((quals1 < 0) != (quals2 < 0))
+       {
+         /* Only of the args is a reference, see if we should apply
+            array/function pointer decay to it.  This is not part of
+            DR214, but is, IMHO, consistent with the deduction rules
+            for the function call itself, and with our earlier
+            implementation of the underspecified partial ordering
+            rules.  (nathan).  */
+         if (quals1 >= 0)
+           {
+             switch (TREE_CODE (arg1))
+               {
+               case ARRAY_TYPE:
+                 arg1 = TREE_TYPE (arg1);
+                 /* FALLTHROUGH. */
+               case FUNCTION_TYPE:
+                 arg1 = build_pointer_type (arg1);
+                 break;
+                 
+               default:
+                 break;
+               }
+           }
+         else
+           {
+             switch (TREE_CODE (arg2))
+               {
+               case ARRAY_TYPE:
+                 arg2 = TREE_TYPE (arg2);
+                 /* FALLTHROUGH. */
+               case FUNCTION_TYPE:
+                 arg2 = build_pointer_type (arg2);
+                 break;
+                 
+               default:
+                 break;
+               }
+           }
+       }
+      
+      arg1 = TYPE_MAIN_VARIANT (arg1);
+      arg2 = TYPE_MAIN_VARIANT (arg2);
+      
+      deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
+      deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+
+      if (!deduce1)
+       better2 = -1;
+      if (!deduce2)
+       better1 = -1;
+      if (better1 < 0 && better2 < 0)
+       /* We've failed to deduce something in either direction.
+          These must be unordered.  */
+       break;
+      
+      if (deduce1 && deduce2 && quals1 >= 0 && quals2 >= 0)
+       {
+         /* Deduces in both directions, see if quals can
+            disambiguate.  Pretend the worse one failed to deduce. */
+         if ((quals1 & quals2) == quals2)
+           deduce1 = 0;
+         if ((quals1 & quals2) == quals1)
+           deduce2 = 0;
+       }
+      if (deduce1 && !deduce2 && !better2)
+       better2 = 1;
+      if (deduce2 && !deduce1 && !better1)
+       better1 = 1;
+      
+      args1 = TREE_CHAIN (args1);
+      args2 = TREE_CHAIN (args2);
+    }
+
+  processing_template_decl--;
+
+  return (better1 > 0) - (better2 > 0);
 }
 
 /* Given two class template specialization list nodes PAT1 and PAT2, return:
@@ -10619,37 +10710,56 @@ tree
 most_specialized_instantiation (tree instantiations)
 {
   tree fn, champ;
-  int fate;
 
   if (!instantiations)
     return NULL_TREE;
-
+  
+  ++processing_template_decl;
+  
   champ = instantiations;
   for (fn = TREE_CHAIN (instantiations); fn; fn = TREE_CHAIN (fn))
     {
-      fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn),
-                               DEDUCE_EXACT, -1);
-      if (fate == 1)
-       ;
-      else
+      int fate = 0;
+      
+      if (get_bindings_real (TREE_VALUE (champ),
+                            DECL_TEMPLATE_RESULT (TREE_VALUE (fn)),
+                            NULL_TREE, 0, DEDUCE_EXACT, -1))
+       fate--;
+
+      if (get_bindings_real (TREE_VALUE (fn),
+                            DECL_TEMPLATE_RESULT (TREE_VALUE (champ)),
+                            NULL_TREE, 0, DEDUCE_EXACT, -1))
+       fate++;
+      
+      if (fate != 1)
        {
-         if (fate == 0)
-           {
-             fn = TREE_CHAIN (fn);
-             if (! fn)
-               return error_mark_node;
-           }
+         if (!fate)
+           /* Equally specialized, move to next function.  If there
+              is no next function, nothing's most specialized.  */
+           fn = TREE_CHAIN (fn);
          champ = fn;
        }
     }
-
-  for (fn = instantiations; fn && fn != champ; fn = TREE_CHAIN (fn))
-    {
-      fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn),
-                               DEDUCE_EXACT, -1);
-      if (fate != 1)
-       return error_mark_node;
-    }
+  
+  if (champ)
+    /* Now verify that champ is better than everything earlier in the
+       instantiation list.  */
+    for (fn = instantiations; fn != champ; fn = TREE_CHAIN (fn))
+      if (get_bindings_real (TREE_VALUE (champ),
+                            DECL_TEMPLATE_RESULT (TREE_VALUE (fn)),
+                            NULL_TREE, 0, DEDUCE_EXACT, -1)
+         || !get_bindings_real (TREE_VALUE (fn),
+                                DECL_TEMPLATE_RESULT (TREE_VALUE (champ)),
+                                NULL_TREE, 0, DEDUCE_EXACT, -1))
+       {
+         champ = NULL_TREE;
+         break;
+       }
+  
+  processing_template_decl--;
+  
+  if (!champ)
+    return error_mark_node;
 
   return TREE_PURPOSE (champ) ? TREE_PURPOSE (champ) : TREE_VALUE (champ);
 }
@@ -12333,7 +12443,8 @@ dependent_template_id_p (tree tmpl, tree args)
    TYPENAME_TYPE corresponds.  Returns ERROR_MARK_NODE if no such TYPE
    can be found.  Note that this function peers inside uninstantiated
    templates and therefore should be used only in extremely limited
-   situations.  */
+   situations.  ONLY_CURRENT_P restricts this peering to the currently
+   open classes heirarchy (which is required when comparing types).  */
 
 tree
 resolve_typename_type (tree type, bool only_current_p)
index 66d1b01..afa03d5 100644 (file)
@@ -1,3 +1,10 @@
+2005-03-31  Nathan Sidwell  <nathan@codesourcery.com>
+
+       PR c++/19203, DR 214
+       * g++.dg/parse/ambig3.C: Not ambiguous.
+       * g++.dg/template/spec20.C: New.
+       * g++.dg/template/spec21.C: New.
+
 2005-03-31  Steve Ellcey  <sje@cup.hp.com>
 
        PR target/20045
index 72ee960..4139071 100644 (file)
@@ -5,8 +5,17 @@
 template <int> struct A { static const int i = 1; };
 template <int> struct B {};
 
-template <typename> void foo(B<0>) {} // { dg-error "" }
+template <typename> int foo(B<0>)
+{
+  return 0;
+} 
 
-template <typename, int j> B<A<j>::i-1> foo(B<j>) { return B<0>(); } // { dg-error "" }
+template <typename, int j> B<A<j>::i-1> foo(B<j>)
+{
+  return B<0>();
+} 
 
-void bar() { foo<int>(B<0>()); } // { dg-error "ambiguous" }
+int main()
+{
+  return foo<int>(B<0>());
+} 
diff --git a/gcc/testsuite/g++.dg/template/spec20.C b/gcc/testsuite/g++.dg/template/spec20.C
new file mode 100644 (file)
index 0000000..71548e4
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (C) 2005 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 31 Mar 2005 <nathan@codesourcery.com>
+
+// Origin: Giovanni Bajo <giovannibajo@libero.it>
+// Bug 19203: Failure to implement DR 214
+
+template <class A>
+void foo(const A& a);
+
+template <class RET, class ARG1>
+int foo(RET (&)(ARG1)); // this one
+
+
+float decl(int);
+
+int bar(void)
+{
+  return foo(decl);
+}
diff --git a/gcc/testsuite/g++.dg/template/spec21.C b/gcc/testsuite/g++.dg/template/spec21.C
new file mode 100644 (file)
index 0000000..e04ac5a
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright (C) 2005 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 31 Mar 2005 <nathan@codesourcery.com>
+
+// { dg-do run }
+// DR214
+
+template <class T> T f(int) {return 0;}
+template <class T, class U> T f(U){return 1;}
+
+template <typename T, typename R> T checked_cast (R const &) {return 0;}
+template <typename T, typename R> T checked_cast (R *) {return 1;}
+
+
+int main ()
+{
+  int i = 0;
+
+  if (f<int>(1))
+    return 1;
+  
+  if (checked_cast<int>(i) != 0)
+    return 2;
+
+  if (checked_cast<int>(&i) != 1)
+    return 3;
+
+  return 0;
+}