This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix 19203 on 4.0


this patch backports 19203 (and its followon 20723) to the 4.0 branch.

booted & tested on i686-pc-linux-gnu.

nathan
--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

2005-05-10  Nathan Sidwell  <nathan@codesourcery.com>

	PR c++/20723
	* pt.c (more_specialized_fn): Member functions are unordered wrt
	non-members.  Conversion operators are unordered wrt other
	functions.

	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-05-10  Nathan Sidwell  <nathan@codesourcery.com>

	PR c++/20723
	* g++.dg/template/spec22.C: New.
	* g++.dg/template/spec23.C: New.

	PR c++/19203, DR 214
	* g++.dg/parse/ambig3.C: Not ambiguous.
	* g++.dg/template/spec20.C: New.
	* g++.dg/template/spec21.C: New.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.531.2.1
diff -c -3 -p -r1.531.2.1 call.c
*** cp/call.c	3 Apr 2005 12:07:22 -0000	1.531.2.1
--- cp/call.c	10 May 2005 13:10:37 -0000
*************** joust (struct z_candidate *cand1, struct
*** 6084,6093 ****
    
    if (cand1->template_decl && cand2->template_decl)
      {
!       winner = more_specialized
          (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
--- 6084,6092 ----
    
    if (cand1->template_decl && cand2->template_decl)
      {
!       winner = more_specialized_fn
          (TI_TEMPLATE (cand1->template_decl),
           TI_TEMPLATE (cand2->template_decl),
           /* 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: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1106.2.4
diff -c -3 -p -r1.1106.2.4 cp-tree.h
*** cp/cp-tree.h	1 May 2005 01:12:48 -0000	1.1106.2.4
--- cp/cp-tree.h	10 May 2005 13:10:48 -0000
*************** extern int function_depth;
*** 3109,3116 ****
  typedef enum unification_kind_t {
    DEDUCE_CALL,
    DEDUCE_CONV,
!   DEDUCE_EXACT,
!   DEDUCE_ORDER
  } unification_kind_t;
  
  /* Macros for operating on a template instantiation level node.  */
--- 3109,3115 ----
  typedef enum unification_kind_t {
    DEDUCE_CALL,
    DEDUCE_CONV,
!   DEDUCE_EXACT
  } unification_kind_t;
  
  /* Macros for operating on a template instantiation level node.  */
*************** extern tree instantiate_class_template		
*** 3996,4002 ****
  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 void mark_class_instantiated		(tree, int);
  extern void do_decl_instantiation		(tree, tree);
  extern void do_type_instantiation		(tree, tree, tsubst_flags_t);
--- 3995,4001 ----
  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_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: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.978.2.8
diff -c -3 -p -r1.978.2.8 pt.c
*** cp/pt.c	5 May 2005 23:30:13 -0000	1.978.2.8
--- cp/pt.c	10 May 2005 13:11:26 -0000
*************** instantiate_template (tree tmpl, tree ta
*** 9039,9049 ****
       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
--- 9039,9044 ----
*************** maybe_adjust_types_for_deduction (unific
*** 9191,9218 ****
        /* 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 ();
      }
--- 9186,9191 ----
*************** type_unification_real (tree tparms, 
*** 9308,9317 ****
        sub_strict = UNIFY_ALLOW_NONE;
        break;
      
-     case DEDUCE_ORDER:
-       sub_strict = UNIFY_ALLOW_NONE;
-       break;
-       
      default:
        gcc_unreachable ();
      }
--- 9281,9286 ----
*************** type_unification_real (tree tparms, 
*** 9354,9360 ****
  	  else
  	    type = arg;
  
! 	  if (strict == DEDUCE_EXACT || strict == DEDUCE_ORDER)
  	    {
  	      if (same_type_p (parm, type))
  		continue;
--- 9323,9329 ----
  	  else
  	    type = arg;
  
! 	  if (strict == DEDUCE_EXACT)
  	    {
  	      if (same_type_p (parm, type))
  		continue;
*************** mark_decl_instantiated (tree result, int
*** 10401,10436 ****
  
  /* 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.  */
     
  int
! more_specialized (tree pat1, tree pat2, int deduce, int len)
  {
!   tree targs;
!   int winner = 0;
  
!   /* 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;
  
!   targs = get_bindings_real (pat2, DECL_TEMPLATE_RESULT (pat1),
!                              NULL_TREE, 0, deduce, len);
!   if (targs)
!     ++winner;
!   --processing_template_decl;
  
!   return winner;
  }
  
  /* Given two class template specialization list nodes PAT1 and PAT2, return:
--- 10370,10533 ----
  
  /* Given two function templates PAT1 and PAT2, return:
  
     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 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_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;
  
!   /* If only one is a member function, they are unordered.  */
!   if (DECL_FUNCTION_MEMBER_P (decl1) != DECL_FUNCTION_MEMBER_P (decl2))
!     return 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 only one is a conversion operator, they are unordered.  */
!   if (DECL_CONV_FN_P (decl1) != DECL_CONV_FN_P (decl2))
!     return 0;
!   
!   /* Consider the return type for a conversion function */
!   if (DECL_CONV_FN_P (decl1))
!     {
!       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;
  
!       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);
! 	}
! 
!       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:
*************** tree
*** 10594,10630 ****
  most_specialized_instantiation (tree instantiations)
  {
    tree fn, champ;
-   int fate;
  
    if (!instantiations)
      return NULL_TREE;
! 
    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
  	{
! 	  if (fate == 0)
! 	    {
! 	      fn = TREE_CHAIN (fn);
! 	      if (! fn)
! 		return error_mark_node;
! 	    }
  	  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;
!     }
  
    return TREE_PURPOSE (champ) ? TREE_PURPOSE (champ) : TREE_VALUE (champ);
  }
--- 10691,10746 ----
  most_specialized_instantiation (tree instantiations)
  {
    tree fn, champ;
  
    if (!instantiations)
      return NULL_TREE;
!   
!   ++processing_template_decl;
!   
    champ = instantiations;
    for (fn = TREE_CHAIN (instantiations); fn; fn = TREE_CHAIN (fn))
      {
!       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)
! 	    /* Equally specialized, move to next function.  If there
! 	       is no next function, nothing's most specialized.  */
! 	    fn = TREE_CHAIN (fn);
  	  champ = fn;
  	}
      }
!   
!   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);
  }
Index: testsuite/g++.dg/parse/ambig3.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/parse/ambig3.C,v
retrieving revision 1.1
diff -c -3 -p -r1.1 ambig3.C
*** testsuite/g++.dg/parse/ambig3.C	22 Jul 2003 10:54:14 -0000	1.1
--- testsuite/g++.dg/parse/ambig3.C	10 May 2005 13:11:30 -0000
***************
*** 5,12 ****
  template <int> struct A { static const int i = 1; };
  template <int> struct B {};
  
! template <typename> void foo(B<0>) {} // { dg-error "" }
  
! template <typename, int j> B<A<j>::i-1> foo(B<j>) { return B<0>(); } // { dg-error "" }
  
! void bar() { foo<int>(B<0>()); } // { dg-error "ambiguous" }
--- 5,21 ----
  template <int> struct A { static const int i = 1; };
  template <int> struct B {};
  
! template <typename> int foo(B<0>)
! {
!   return 0;
! } 
  
! template <typename, int j> B<A<j>::i-1> foo(B<j>)
! {
!   return B<0>();
! } 
  
! int main()
! {
!   return foo<int>(B<0>());
! } 
Index: testsuite/g++.dg/template/spec20.C
===================================================================
RCS file: testsuite/g++.dg/template/spec20.C
diff -N testsuite/g++.dg/template/spec20.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/spec20.C	10 May 2005 13:11:33 -0000
***************
*** 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);
+ }
Index: testsuite/g++.dg/template/spec21.C
===================================================================
RCS file: testsuite/g++.dg/template/spec21.C
diff -N testsuite/g++.dg/template/spec21.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/spec21.C	10 May 2005 13:11:33 -0000
***************
*** 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;
+ }
Index: testsuite/g++.dg/template/spec22.C
===================================================================
RCS file: testsuite/g++.dg/template/spec22.C
diff -N testsuite/g++.dg/template/spec22.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/spec22.C	10 May 2005 13:11:33 -0000
***************
*** 0 ****
--- 1,22 ----
+ // Copyright (C) 2005 Free Software Foundation, Inc.
+ // Contributed by Nathan Sidwell 2 Apr 2005 <nathan@codesourcery.com>
+ 
+ // PR 20723
+ // Origin: Andrew Pinski <pinskia@gcc.gnu.org>
+ //         Nathan Sidwell <nathan@gcc.gnu.org>
+ 
+ template <typename T>
+ int operator+ (T const &, int); // { dg-error "T = Foo" "" }
+ 
+ struct Foo 
+ {
+   template <typename T>
+   int operator+ (T) const; // { dg-error "T = int" "" }
+ };
+ 
+ int main ()
+ {
+   Foo f;
+ 
+   return f + 0; // { dg-error "ambiguous overload" "" }
+ }
Index: testsuite/g++.dg/template/spec23.C
===================================================================
RCS file: testsuite/g++.dg/template/spec23.C
diff -N testsuite/g++.dg/template/spec23.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/spec23.C	10 May 2005 13:11:33 -0000
***************
*** 0 ****
--- 1,25 ----
+ // Copyright (C) 2005 Free Software Foundation, Inc.
+ // Contributed by Nathan Sidwell 2 Apr 2005 <nathan@codesourcery.com>
+ 
+ // PR 20723
+ // Origin: Andrew Pinski <pinskia@gcc.gnu.org>
+ //         Nathan Sidwell <nathan@gcc.gnu.org>
+ 
+ struct Foo
+ {
+   template <typename T>
+   Foo (const T &); // { dg-error "T = Bar" "" }
+ };
+ 
+ struct Bar
+ {
+   template <typename T>
+   operator T () const;   // { dg-error "T = Foo" "" }
+ };
+ 
+ Foo Quux (Bar const &b)
+ {
+   return b; // { dg-error "ambiguous overload" "" }
+ }
+ 
+ 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]