PATCH for overload resolution

Mark Mitchell mmitchell@usa.net
Tue May 5 00:50:00 GMT 1998


Jason --

  Here's a patch that consists of a substantial reworking of
compare_ics.  I started out to fix a particular bug, but it looked
like the whole thing could use some work, and I suspect I fixed a few
other bugs in the process.  Here's the test-case:

  template <class T>
  class ConstArray {
  };

  template <class T1, class T2>
  void operator+(const ConstArray<T1>&, const ConstArray<T2>&);

  template <class T1, class T2>
  void operator+(const ConstArray<T1>&, T2);

  template <class T1, class T2>
  void operator+(T1, const ConstArray<T2>&);

  const ConstArray<int> cai();
  const ConstArray<double> cad();

  void f()
  {
    cai () + cad ();
  }

This used to cause a bogus error message.

-- 
Mark Mitchell <mmitchell@usa.net>
http://home.earthlink.net/~mbmitchell
Consulting Services Available

Mon May  4 09:41:00 1998  Mark Mitchell  <mmitchell@usa.net>

	* call.c (compare_qual): Remove.
	(ICS_THIS_FLAG): Likewise.
	(add_function_candidate): Handle `this' parameters in conformance
	with the standard; i.e., build implicit conversion sequences for
	them as if they were reference, rather than pointer, parameters.
	(is_subseq): Tweak.
	(compare_ics): Modify substantially to bring into conformance with
	the standard.
	* cp-tree.h (is_derived_from): Declare
	(comp_cv_qualification): Likewise.
	* search.c (is_derived_from): Define.
	* typeck.c (comp_cv_qualification): Likewise.
	
Index: cp/call.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/call.c,v
retrieving revision 1.67
diff -c -p -r1.67 call.c
*** call.c	1998/05/03 02:30:57	1.67
--- call.c	1998/05/04 15:56:22
*************** static tree build_field_call PROTO((tree
*** 44,50 ****
  static tree find_scoped_type PROTO((tree, tree, tree));
  static struct z_candidate * tourney PROTO((struct z_candidate *));
  static int joust PROTO((struct z_candidate *, struct z_candidate *, int));
- static int compare_qual PROTO((tree, tree));
  static int compare_ics PROTO((tree, tree));
  static tree build_over_call PROTO((struct z_candidate *, tree, int));
  static tree convert_default_arg PROTO((tree, tree));
--- 44,49 ----
*************** struct z_candidate {
*** 687,693 ****
  
  #define ICS_USER_FLAG(NODE) TREE_LANG_FLAG_0 (NODE)
  #define ICS_ELLIPSIS_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
- #define ICS_THIS_FLAG(NODE) TREE_LANG_FLAG_2 (NODE)
  #define ICS_BAD_FLAG(NODE) TREE_LANG_FLAG_3 (NODE)
  
  #define USER_CONV_CAND(NODE) \
--- 688,693 ----
*************** add_function_candidate (candidates, fn, 
*** 1122,1138 ****
        if (parmnode == void_list_node)
  	break;
        else if (parmnode)
! 	t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg, flags);
        else
  	{
  	  t = build1 (IDENTITY_CONV, argtype, arg);
  	  ICS_ELLIPSIS_FLAG (t) = 1;
  	}
  
-       if (i == 0 && t && TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
- 	  && ! DECL_CONSTRUCTOR_P (fn))
- 	ICS_THIS_FLAG (t) = 1;
- 
        TREE_VEC_ELT (convs, i) = t;
        if (! t)
  	break;
--- 1122,1156 ----
        if (parmnode == void_list_node)
  	break;
        else if (parmnode)
! 	{
! 	  tree parmtype = TREE_VALUE (parmnode);
! 
! 	  if (i == 0 && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
! 	      && !DECL_CONSTRUCTOR_P (fn)
! 	      /* This last condition avoids problems with signatures.  */
! 	      && TYPE_PTR_P (parmtype))
! 	    {
! 	      /* [over.match.funcs]
! 		 
! 		 For non-static member functions, the type of the
! 		 implicit object parameter is "reference to cv X"
! 		 where X is the class of which the function is a
! 		 member and cv is the cv-qualification on the member
! 		 function declaration.  */
! 	      parmtype = build_reference_type (TREE_TYPE (parmtype));
! 	      
! 	      if (TYPE_PTR_P (argtype))
! 		argtype = build_reference_type (TREE_TYPE (argtype));
! 	    }
! 
! 	  t = implicit_conversion (parmtype, argtype, arg, flags);
! 	}
        else
  	{
  	  t = build1 (IDENTITY_CONV, argtype, arg);
  	  ICS_ELLIPSIS_FLAG (t) = 1;
  	}
  
        TREE_VEC_ELT (convs, i) = t;
        if (! t)
  	break;
*************** build_new_method_call (instance, name, a
*** 3624,3693 ****
       flags);
  }
  
! /* Compare two implicit conversion sequences that differ only in their
!    qualification conversion.  Subroutine of compare_ics.  */
  
  static int
! compare_qual (ics1, ics2)
       tree ics1, ics2;
  {
!   tree to1 = TREE_TYPE (ics1);
!   tree to2 = TREE_TYPE (ics2);
! 
!   if (TYPE_PTRMEMFUNC_P (to1))
!     to1 = TYPE_PTRMEMFUNC_FN_TYPE (to1);
!   if (TYPE_PTRMEMFUNC_P (to2))
!     to2 = TYPE_PTRMEMFUNC_FN_TYPE (to2);
  
!   to1 = TREE_TYPE (to1);
!   to2 = TREE_TYPE (to2);
! 
!   if (TREE_CODE (to1) == OFFSET_TYPE)
!     {
!       to1 = TREE_TYPE (to1);
!       to2 = TREE_TYPE (to2);
!     }
! 
!   if (TYPE_READONLY (to1) >= TYPE_READONLY (to2)
!       && TYPE_VOLATILE (to1) > TYPE_VOLATILE (to2))
!     return -1;
!   else if (TYPE_READONLY (to1) > TYPE_READONLY (to2)
! 	   && TYPE_VOLATILE (to1) == TYPE_VOLATILE (to2))
!     return -1;
!   else if (TYPE_READONLY (to1) <= TYPE_READONLY (to2)
! 	   && TYPE_VOLATILE (to1) < TYPE_VOLATILE (to2))
!     return 1;
!   else if (TYPE_READONLY (to1) < TYPE_READONLY (to2)
! 	   && TYPE_VOLATILE (to1) == TYPE_VOLATILE (to2))
!     return 1;
!   return 0;
! }
! 
! /* Determine whether standard conversion sequence ICS1 is a proper
!    subsequence of ICS2.  We assume that a conversion of the same code
!    between the same types indicates a subsequence.  */
  
! static int
! is_subseq (ics1, ics2)
!      tree ics1, ics2;
! {
!   /* Do not consider lvalue transformations here.  */
!   if (TREE_CODE (ics2) == RVALUE_CONV
!       || TREE_CODE (ics2) == LVALUE_CONV)
!     return 0;
  
-   for (;; ics2 = TREE_OPERAND (ics2, 0))
-     {
        if (TREE_CODE (ics2) == TREE_CODE (ics1)
  	  && comptypes (TREE_TYPE (ics2), TREE_TYPE (ics1), 1)
  	  && comptypes (TREE_TYPE (TREE_OPERAND (ics2, 0)),
  			TREE_TYPE (TREE_OPERAND (ics1, 0)), 1))
  	return 1;
- 
-       if (TREE_CODE (ics2) == USER_CONV
- 	  || TREE_CODE (ics2) == AMBIG_CONV
- 	  || TREE_CODE (ics2) == IDENTITY_CONV)
- 	return 0;
      }
  }
  
--- 3647,3689 ----
       flags);
  }
  
! /* Returns non-zero iff standard conversion sequence ICS1 is a proper
!    subsequence of ICS2.  */
  
  static int
! is_subseq (ics1, ics2)
       tree ics1, ics2;
  {
!   /* We can assume that a conversion of the same code
!      between the same types indicates a subsequence since we only get
!      here if the types we are converting from are the same.  */
! 
!   while (TREE_CODE (ics1) == RVALUE_CONV
! 	 || TREE_CODE (ics1) == LVALUE_CONV)
!     ics1 = TREE_OPERAND (ics1, 0);
! 
!   while (1)
!     {
!       while (TREE_CODE (ics2) == RVALUE_CONV
! 	  || TREE_CODE (ics2) == LVALUE_CONV)
! 	ics2 = TREE_OPERAND (ics2, 0);
  
!       if (TREE_CODE (ics2) == USER_CONV
! 	  || TREE_CODE (ics2) == AMBIG_CONV
! 	  || TREE_CODE (ics2) == IDENTITY_CONV)
! 	/* At this point, ICS1 cannot be a proper subsequence of
! 	   ICS2.  We can get a USER_CONV when we are comparing the
! 	   second standard conversion sequence of two user conversion
! 	   sequences.  */
! 	return 0;
  
!       ics2 = TREE_OPERAND (ics2, 0);
  
        if (TREE_CODE (ics2) == TREE_CODE (ics1)
  	  && comptypes (TREE_TYPE (ics2), TREE_TYPE (ics1), 1)
  	  && comptypes (TREE_TYPE (TREE_OPERAND (ics2, 0)),
  			TREE_TYPE (TREE_OPERAND (ics1, 0)), 1))
  	return 1;
      }
  }
  
*************** static int
*** 3702,3749 ****
  compare_ics (ics1, ics2)
       tree ics1, ics2;
  {
!   tree main1, main2;
! 
!   if (TREE_CODE (ics1) == QUAL_CONV)
!     main1 = TREE_OPERAND (ics1, 0);
!   else
!     main1 = ics1;
! 
!   if (TREE_CODE (ics2) == QUAL_CONV)
!     main2 = TREE_OPERAND (ics2, 0);
!   else
!     main2 = ics2;
! 
!   /* Conversions for `this' are PTR_CONVs, but we compare them as though
!      they were REF_BINDs.  */
!   if (ICS_THIS_FLAG (ics1))
!     {
!       tree t = main1;
!       if (TREE_CODE (t) == PTR_CONV)
! 	t = TREE_OPERAND (t, 0);
!       t = build1 (IDENTITY_CONV, TREE_TYPE (TREE_TYPE (t)), NULL_TREE);
!       t = build_conv (REF_BIND, TREE_TYPE (ics1), t);
!       ICS_STD_RANK (t) = ICS_STD_RANK (main1);
!       main1 = ics1 = t;
!     }
!   if (ICS_THIS_FLAG (ics2))
!     {
!       tree t = main2;
!       if (TREE_CODE (t) == PTR_CONV)
! 	t = TREE_OPERAND (t, 0);
!       t = build1 (IDENTITY_CONV, TREE_TYPE (TREE_TYPE (t)), NULL_TREE);
!       t = build_conv (REF_BIND, TREE_TYPE (ics2), t);
!       ICS_STD_RANK (t) = ICS_STD_RANK (main2);
!       main2 = ics2 = t;
!     }
! 
!   if (ICS_RANK (ics1) > ICS_RANK (ics2))
!     return -1;
!   else if (ICS_RANK (ics1) < ICS_RANK (ics2))
      return 1;
  
!   if (ICS_RANK (ics1) == BAD_RANK)
      {
        if (ICS_USER_FLAG (ics1) > ICS_USER_FLAG (ics2)
  	  || ICS_STD_RANK (ics1) > ICS_STD_RANK (ics2))
  	return -1;
--- 3698,3783 ----
  compare_ics (ics1, ics2)
       tree ics1, ics2;
  {
!   tree from_type1 = NULL_TREE;
!   tree from_type2;
!   tree orig_to_type1;
!   tree orig_to_type2;
!   tree to_type1;
!   tree to_type2;
!   int ref_binding_1;
!   int ref_binding_2;
! 
!   /* [over.ics.rank] 
! 
!      When a parameter of reference type binds directly
!      (_dcl.init.ref_) to an argument expression, the implicit
!      conversion sequence is the identity conversion, unless the
!      argument expression has a type that is a derived class of the
!      parameter type, in which case the implicit conversion sequence
!      is a derived-to-base Conversion.
! 
!      If the parameter binds directly to the result of applying a
!      conversion function to the argument expression, the implicit
!      conversion sequence is a user-defined conversion sequence
!      (_over.ics.user_), with the second standard conversion sequence
!      either an identity conversion or, if the conversion function
!      returns an entity of a type that is a derived class of the
!      parameter type, a derived-to-base Conversion.
! 
!      When a parameter of reference type is not bound directly to an
!      argument expression, the conversion sequence is the one required
!      to convert the argument expression to the underlying type of the
!      reference according to _over.best.ics_.  Conceptually, this
!      conversion sequence corresponds to copy-initializing a temporary
!      of the underlying type with the argument expression.  Any
!      difference in top-level cv-qualification is subsumed by the
!      initialization itself and does not constitute a conversion.  */
! 
!   if (TREE_CODE (ics1) == REF_BIND)
!     {
!       ref_binding_1 = 1;
!       orig_to_type1 = TREE_TYPE (TREE_TYPE (ics1));
!       ics1 = TREE_OPERAND (ics1, 0);
!       if (TREE_CODE (ics1) == IDENTITY_CONV
! 	  && is_derived_from (TREE_TYPE (ics1), orig_to_type1))
! 	ics1 = build_conv (BASE_CONV, orig_to_type1, ics1);
!     }
!   else
!     ref_binding_1 = 0;
! 
!   if (TREE_CODE (ics2) == REF_BIND)
!     {
!       ref_binding_2 = 1;
!       orig_to_type2 = TREE_TYPE (TREE_TYPE (ics2));
!       ics2 = TREE_OPERAND (ics2, 0);
!       if (TREE_CODE (ics2) == IDENTITY_CONV
! 	  && is_derived_from (TREE_TYPE (ics2), orig_to_type2))
! 	ics2 = build_conv (BASE_CONV, orig_to_type2, ics2);
!     }
!   else
!     ref_binding_2 = 0;
! 
!   /* [over.ics.rank]
! 
!      When  comparing  the  basic forms of implicit conversion sequences (as
!      defined in _over.best.ics_)
! 
!      --a standard conversion sequence (_over.ics.scs_) is a better
!        conversion sequence than a user-defined conversion sequence
!        or an ellipsis conversion sequence, and
!      
!      --a user-defined conversion sequence (_over.ics.user_) is a
!        better conversion sequence than an ellipsis conversion sequence
!        (_over.ics.ellipsis_).  */
!   if (ICS_RANK (ics1) < ICS_RANK (ics2))
      return 1;
+   else if (ICS_RANK (ics2) < ICS_RANK (ics1))
+     return -1;
  
!   if (ICS_BAD_FLAG (ics1))
      {
+       /* Both ICS are bad.  We try to make a decision based on what
+ 	 would have happenned if they'd been good.  */
        if (ICS_USER_FLAG (ics1) > ICS_USER_FLAG (ics2)
  	  || ICS_STD_RANK (ics1) > ICS_STD_RANK (ics2))
  	return -1;
*************** compare_ics (ics1, ics2)
*** 3751,3768 ****
  	       || ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2))
  	return 1;
  
!       /* else fall through */
      }
  
!   /* User-defined  conversion sequence U1 is a better conversion sequence
!      than another user-defined conversion sequence U2 if they contain the
!      same user-defined conversion operator or constructor and if the sec-
!      ond standard conversion sequence of U1 is  better  than  the  second
!      standard conversion sequence of U2.  */
  
    if (ICS_USER_FLAG (ics1))
      {
        tree t1, t2;
  
        for (t1 = ics1; TREE_CODE (t1) != USER_CONV; t1 = TREE_OPERAND (t1, 0))
  	if (TREE_CODE (t1) == AMBIG_CONV)
--- 3785,3810 ----
  	       || ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2))
  	return 1;
  
!       /* We couldn't make up our minds; try to figure it out below.  */
      }
  
!   if (ICS_ELLIPSIS_FLAG (ics1))
!     /* Both conversions are ellipsis conversions.  */
!     return 0;
  
    if (ICS_USER_FLAG (ics1))
      {
+       /* [over.ics.rank]
+ 
+ 	 User-defined conversion sequence U1 is a better conversion
+ 	 sequence than another user-defined conversion sequence U2 if
+ 	 they contain the same user-defined conversion function or
+ 	 constructor and if the second standard conversion sequence
+ 	 of U1 is better than the second standard conversion sequence
+ 	 of U2.  */
+       
        tree t1, t2;
+       int result;
  
        for (t1 = ics1; TREE_CODE (t1) != USER_CONV; t1 = TREE_OPERAND (t1, 0))
  	if (TREE_CODE (t1) == AMBIG_CONV)
*************** compare_ics (ics1, ics2)
*** 3773,3947 ****
  
        if (USER_CONV_FN (t1) != USER_CONV_FN (t2))
  	return 0;
-       else if (ICS_STD_RANK (ics1) > ICS_STD_RANK (ics2))
- 	return -1;
-       else if (ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2))
- 	return 1;
  
!       /* else fall through */
      }
  
! #if 0 /* Handled by ranking */
!   /* A conversion that is not a conversion of a pointer,  or  pointer  to
!      member,  to  bool  is  better than another conversion that is such a
!      conversion.  */
! #endif
  
!   if (TREE_CODE (main1) != TREE_CODE (main2))
      {
!       /* ...if S1  is  a  proper  subsequence  of  S2  */
!       if (is_subseq (main1, main2))
  	return 1;
!       if (is_subseq (main2, main1))
  	return -1;
-       return 0;
      }
  
!   if (TREE_CODE (main1) == PTR_CONV || TREE_CODE (main1) == PMEM_CONV
!       || TREE_CODE (main1) == REF_BIND || TREE_CODE (main1) == BASE_CONV)
!     {
!       tree to1 = TREE_TYPE (main1);
!       tree from1 = TREE_TYPE (TREE_OPERAND (main1, 0));
!       tree to2 = TREE_TYPE (main2);
!       tree from2 = TREE_TYPE (TREE_OPERAND (main2, 0));
!       int distf, distt;
  
!       /* Standard conversion sequence S1 is a better conversion sequence than
! 	 standard conversion sequence S2 if...
  
! 	 S1 and S2 differ only in their qualification conversion  and  they
! 	 yield types identical except for cv-qualifiers and S2 adds all the
! 	 qualifiers that S1 adds (and in the same places) and S2  adds  yet
! 	 more  cv-qualifiers  than  S1,  or the similar case with reference
! 	 binding15).  */
!       if (TREE_CODE (main1) == REF_BIND)
! 	{
! 	  if (TYPE_MAIN_VARIANT (TREE_TYPE (to1))
! 	      == TYPE_MAIN_VARIANT (TREE_TYPE (to2)))
! 	    return compare_qual (ics1, ics2);
! 	}
!       else if (TREE_CODE (main1) != BASE_CONV && from1 == from2 && to1 == to2)
! 	return compare_qual (ics1, ics2);
! 	
!       if (TYPE_PTRMEMFUNC_P (to1))
! 	{
! 	  to1 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to1)));
! 	  from1 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from1)));
! 	}
!       else if (TREE_CODE (main1) != BASE_CONV)
! 	{
! 	  to1 = TREE_TYPE (to1);
! 	  if (TREE_CODE (main1) != REF_BIND)
! 	    from1 = TREE_TYPE (from1);
  
! 	  if (TREE_CODE (to1) == OFFSET_TYPE)
! 	    {
! 	      to1 = TYPE_OFFSET_BASETYPE (to1);
! 	      from1 = TYPE_OFFSET_BASETYPE (from1);
! 	    }
! 	}
  
!       if (TYPE_PTRMEMFUNC_P (to2))
  	{
! 	  to2 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to2)));
! 	  from2 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from2)));
  	}
!       else if (TREE_CODE (main1) != BASE_CONV)
  	{
! 	  to2 = TREE_TYPE (to2);
! 	  if (TREE_CODE (main1) != REF_BIND)
! 	    from2 = TREE_TYPE (from2);
! 
! 	  if (TREE_CODE (to2) == OFFSET_TYPE)
  	    {
! 	      to2 = TYPE_OFFSET_BASETYPE (to2);
! 	      from2 = TYPE_OFFSET_BASETYPE (from2);
  	    }
  	}
! 
!       if (! (IS_AGGR_TYPE (from1) && IS_AGGR_TYPE (from2)))
! 	return 0;
! 
!       /* The sense of pmem conversions is reversed from that of the other
! 	 conversions.  */
!       if (TREE_CODE (main1) == PMEM_CONV)
  	{
! 	  tree t = from1; from1 = from2; from2 = t;
! 	  t = to1; to1 = to2; to2 = t;
! 	}
  
!       distf = get_base_distance (from1, from2, 0, 0);
!       if (distf == -1)
! 	{
! 	  distf = -get_base_distance (from2, from1, 0, 0);
! 	  if (distf == 1)
! 	    return 0;
  	}
! 
!       /* If class B is derived directly or indirectly from class A,
! 	 conver- sion of B* to A* is better than conversion of B* to
! 	 void*, and conversion of A* to void* is better than
! 	 conversion of B* to void*.  */
! 
!       if (TREE_CODE (to1) == VOID_TYPE && TREE_CODE (to2) == VOID_TYPE)
  	{
! 	  if (distf > 0)
  	    return 1;
! 	  else if (distf < 0)
  	    return -1;
  	}
!       else if (TREE_CODE (to2) == VOID_TYPE && IS_AGGR_TYPE (to1)
! 	       && get_base_distance (to1, from1, 0, 0) != -1)
! 	return 1;
!       else if (TREE_CODE (to1) == VOID_TYPE && IS_AGGR_TYPE (to2)
! 	       && get_base_distance (to2, from2, 0, 0) != -1)
! 	return -1;
! 
!       if (! (IS_AGGR_TYPE (to1) && IS_AGGR_TYPE (to2)))
! 	return 0;
  
!       /* If  class B is derived directly or indirectly from class A and class
! 	 C is derived directly or indirectly from B */
  
!       distt = get_base_distance (to1, to2, 0, 0);
!       if (distt == -1)
! 	{
! 	  distt = -get_base_distance (to2, to1, 0, 0);
! 	  if (distt == 1)
! 	    return 0;
! 	}
! 
!       /* --conversion of C* to B* is better than conversion of C* to A*, */
!       if (distf == 0)
! 	{
! 	  if (distt > 0)
! 	    return -1;
! 	  else if (distt < 0)
! 	    return 1;
! 	}
!       /* --conversion of B* to A* is better than conversion of C* to A*, */
!       else if (distt == 0)
  	{
! 	  if (distf > 0)
  	    return 1;
! 	  else if (distf < 0)
  	    return -1;
  	}
      }
-   else if (TREE_CODE (TREE_TYPE (main1)) == POINTER_TYPE
- 	   || TYPE_PTRMEMFUNC_P (TREE_TYPE (main1)))
-     {
-       if (TREE_TYPE (main1) == TREE_TYPE (main2))
- 	return compare_qual (ics1, ics2);
  
! #if 0 /* This is now handled by making identity better than anything else.  */
!       /* existing practice, not WP-endorsed: const char * -> const char *
! 	 is better than char * -> const char *.  (jason 6/29/96) */
!       if (TREE_TYPE (ics1) == TREE_TYPE (ics2))
! 	return -compare_qual (main1, main2);
! #endif
!     }
  
    return 0;
  }
  
--- 3815,4041 ----
  
        if (USER_CONV_FN (t1) != USER_CONV_FN (t2))
  	return 0;
  
!       /* We can just fall through here, after setting up
! 	 FROM_TYPE1 and FROM_TYPE2.  */
!       from_type1 = TREE_TYPE (t1);
!       from_type2 = TREE_TYPE (t2);
      }
  
!   /* We're dealing with two standard conversion sequences. 
! 
!      [over.ics.rank]
  
!      Standard conversion sequence S1 is a better conversion sequence than
!      standard conversion sequence S2 if
!      
!      --S1 is a proper subsequence of S2 (comparing the conversion
!        sequences in the canonical form defined by _over.ics.scs_,
!        excluding any Lvalue Transformation; the identity conversion
!        sequence is considered to be a subsequence of any non-identity
!        conversion sequence */
! 
!   if (from_type1 == NULL_TREE)
!     {
!       from_type1 = ics1;
!       while (TREE_CODE (from_type1) != IDENTITY_CONV)
! 	from_type1 = TREE_OPERAND (from_type1, 0);
!       from_type1 = TREE_TYPE (from_type1);
!       
!       from_type2 = ics2;
!       while (TREE_CODE (from_type2) != IDENTITY_CONV)
! 	from_type2 = TREE_OPERAND (from_type2, 0);
!       from_type2 = TREE_TYPE (from_type2);
!     }
! 
!   if (comptypes (from_type1, from_type2, 1))
      {
!       if (is_subseq (ics1, ics2))
  	return 1;
!       if (is_subseq (ics2, ics1))
  	return -1;
      }
+   else
+     /* One sequence cannot be a subsequence of the other; they don't
+        start with the same type.  This can happen when comparing the
+        second standard conversion sequence in two user-defined
+        conversion sequences.  */
+     ;
  
!   /* [over.ics.rank]
  
!      Or, if not that,
  
!      --the rank of S1 is better than the rank of S2 (by the rules
!        defined below):
  
!     Standard conversion sequences are ordered by their ranks: an Exact
!     Match is a better conversion than a Promotion, which is a better
!     conversion than a Conversion.
! 
!     Two conversion sequences with the same rank are indistinguishable
!     unless one of the following rules applies:
! 
!     --A conversion that is not a conversion of a pointer, or pointer
!       to member, to bool is better than another conversion that is such
!       a conversion.  
! 
!     The ICS_STD_RANK automatically handles the pointer-to-bool rule,
!     so that we do not have to check it explicitly.  */
!   if (ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2))
!     return 1;
!   else if (ICS_STD_RANK (ics2) < ICS_STD_RANK (ics1))
!     return -1;
! 
!   to_type1 = TREE_TYPE (ics1);
!   to_type2 = TREE_TYPE (ics2);
  
!   /* The rules for pointers to members A::* are just like the rules
!      for pointers A*.  */
!   if (TYPE_PTRMEM_P (from_type1)
!       && TYPE_PTRMEM_P (from_type2)
!       && TYPE_PTRMEM_P (to_type1)
!       && TYPE_PTRMEM_P (to_type2))
!     {
!       from_type1 = build_pointer_type (TYPE_OFFSET_BASETYPE (from_type1));
!       from_type2 = build_pointer_type (TYPE_OFFSET_BASETYPE (from_type2));
!       to_type1 = build_pointer_type (TYPE_OFFSET_BASETYPE (to_type1));
!       to_type2 = build_pointer_type (TYPE_OFFSET_BASETYPE (to_type2));
!     }
!   else if (TYPE_PTRMEMFUNC_P (from_type1)
! 	   && TYPE_PTRMEMFUNC_P (from_type2)
! 	   && TYPE_PTRMEMFUNC_P (to_type1)
! 	   && TYPE_PTRMEMFUNC_P (to_type2))
!     {
!       from_type1 = TYPE_PTRMEMFUNC_FN_TYPE (from_type1);
!       from_type2 = TYPE_PTRMEMFUNC_FN_TYPE (from_type2);
!       to_type1 = TYPE_PTRMEMFUNC_FN_TYPE (to_type1);
!       to_type2 = TYPE_PTRMEMFUNC_FN_TYPE (to_type2);
!     }
! 
!   if (TYPE_PTR_P (from_type1)
!       && TYPE_PTR_P (from_type2)
!       && TYPE_PTR_P (to_type1)
!       && TYPE_PTR_P (to_type2))
!     {
!       /* [over.ics.rank]
! 	 
! 	 --If class B is derived directly or indirectly from class A,
! 	   conversion of B* to A* is better than conversion of B* to
! 	   void*, and conversion of A* to void* is better than
! 	   conversion of B* to void*.  */
!       if (TREE_CODE (TREE_TYPE (to_type1)) == VOID_TYPE
! 	  && TREE_CODE (TREE_TYPE (to_type1)) == VOID_TYPE)
  	{
! 	  if (is_derived_from (TREE_TYPE (from_type1),
! 			       TREE_TYPE (from_type2)))
! 	    return -1;
! 	  else if (is_derived_from (TREE_TYPE (from_type2),
! 				    TREE_TYPE (from_type1)))
! 	    return 1;
  	}
!       else if (TREE_CODE (TREE_TYPE (to_type1)) == VOID_TYPE
! 	       || TREE_CODE (TREE_TYPE (to_type2)) == VOID_TYPE)
  	{
! 	  if (comptypes (from_type1, from_type2, 1))
  	    {
! 	      if (TREE_CODE (TREE_TYPE (to_type2)) == VOID_TYPE)
! 		{
! 		  if (is_derived_from (TREE_TYPE (from_type1),
! 				       TREE_TYPE (to_type1)))
! 		    return 1;
! 		}
! 	      /* We know that TO_TYPE1 is `void*' here.  */
! 	      else if (is_derived_from (TREE_TYPE (from_type2),
! 					TREE_TYPE (to_type2)))
! 		return -1;
  	    }
  	}
!       else
  	{
! 	  /* [over.ics.rank]
  
! 	     --If class B is derived directly or indirectly from class A
! 	       and class C is derived directly or indirectly from B,
! 	     
! 	     --conversion of C* to B* is better than conversion of C* to
! 	       A*, 
! 	     
! 	     --conversion of B* to A* is better than conversion of C* to
! 	       A*  */
! 	  if (comptypes (from_type1, from_type2, 1))
! 	    {
! 	      if (is_derived_from (TREE_TYPE (to_type1),
! 				   TREE_TYPE (to_type2)))
! 		return 1;
! 	      else if (is_derived_from (TREE_TYPE (to_type2),
! 					TREE_TYPE (to_type1)))
! 		return -1;
! 	    }
! 	  else if (comptypes (to_type1, to_type2, 1))
! 	    {
! 	      if (is_derived_from (TREE_TYPE (from_type2),
! 				   TREE_TYPE (from_type1)))
! 		return 1;
! 	      else if (is_derived_from (TREE_TYPE (from_type1),
! 					TREE_TYPE (from_type2)))
! 		return -1;
! 	    }
  	}
!     }
!   else if (IS_AGGR_TYPE_CODE (TREE_CODE (from_type1))
! 	   && comptypes (from_type1, from_type2, 1))
!     {
!       /* [over.ics.rank]
! 	 
! 	 --binding of an expression of type C to a reference of type
! 	   B& is better than binding an expression of type C to a
! 	   reference of type A&
! 
! 	 --conversion of C to B is better than conversion of C to A,  */
!       if (is_derived_from (from_type1, to_type1)
! 	  && is_derived_from (from_type1, to_type2))
  	{
! 	  if (is_derived_from (to_type1, to_type2))
  	    return 1;
! 	  else if (is_derived_from (to_type2, to_type1))
  	    return -1;
  	}
!     }
!   else if (IS_AGGR_TYPE_CODE (TREE_CODE (to_type1))
! 	   && comptypes (to_type1, to_type2, 1))
!     {
!       /* [over.ics.rank]
  
! 	 --binding of an expression of type B to a reference of type
! 	   A& is better than binding an expression of type C to a
! 	   reference of type A&, 
  
! 	 --onversion of B to A is better than conversion of C to A  */
!       if (is_derived_from (from_type1, to_type1)
! 	  && is_derived_from (from_type2, to_type1))
  	{
! 	  if (is_derived_from (from_type2, from_type1))
  	    return 1;
! 	  else if (is_derived_from (from_type1, from_type2))
  	    return -1;
  	}
      }
  
!   /* [over.ics.rank]
! 
!      --S1 and S2 are reference bindings (_dcl.init.ref_), and the
!        types to which the references refer are the same type except
!        for top-level cv-qualifiers, and the type to which the
!        reference initialized by S2 refers is more cv-qualified than
!        the type to which the reference initialized by S1 refers */
! 
!   if (ref_binding_1 && ref_binding_2
!       && comptypes (TYPE_MAIN_VARIANT (to_type1),
! 		    TYPE_MAIN_VARIANT (to_type2), 1))
!     return comp_cv_qualification (orig_to_type2, orig_to_type1);
  
+   /* Neither conversion sequence is better than the other.  */
    return 0;
  }
  
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.58
diff -c -p -r1.58 cp-tree.h
*** cp-tree.h	1998/04/26 16:29:58	1.58
--- cp-tree.h	1998/05/04 15:56:47
*************** extern void pop_memoized_context		PROTO(
*** 2516,2521 ****
--- 2533,2539 ----
  extern tree get_vbase				PROTO((tree, tree));
  extern tree get_binfo				PROTO((tree, tree, int));
  extern int get_base_distance			PROTO((tree, tree, int, tree *));
+ extern int is_derived_from                      PROTO((tree, tree));
  extern tree compute_access			PROTO((tree, tree));
  extern tree lookup_field			PROTO((tree, tree, int, int));
  extern tree lookup_nested_field			PROTO((tree, int));
*************** extern int comptypes				PROTO((tree, tre
*** 2690,2695 ****
--- 2719,2725 ----
  extern int comp_target_types			PROTO((tree, tree, int));
  extern int compparms				PROTO((tree, tree, int));
  extern int comp_target_types			PROTO((tree, tree, int));
+ extern int comp_cv_qualification                PROTO((tree, tree));
  extern int self_promoting_args_p		PROTO((tree));
  extern tree unsigned_type			PROTO((tree));
  extern tree signed_type				PROTO((tree));
Index: cp/search.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/search.c,v
retrieving revision 1.22
diff -c -p -r1.22 search.c
*** search.c	1998/04/17 08:05:24	1.22
--- search.c	1998/05/04 15:58:58
*************** get_base_distance (parent, binfo, protec
*** 790,795 ****
--- 790,810 ----
    return rval;
  }
  
+ /* Returns non-zero iff DERIVED is derived from BASE.  The inputs may
+    be any _TYPE nodes.  */
+ 
+ int
+ is_derived_from (derived, base)
+      tree derived;
+      tree base;
+ {
+   if (!IS_AGGR_TYPE_CODE (TREE_CODE (derived))
+       || !IS_AGGR_TYPE_CODE (TREE_CODE (base)))
+     return 0;
+ 
+   return get_base_distance (derived, base, /*protect=*/0, /*path_ptr=*/0);
+ }
+ 
  /* Search for a member with name NAME in a multiple inheritance lattice
     specified by TYPE.  If it does not exist, return NULL_TREE.
     If the member is ambiguously referenced, return `error_mark_node'.
Index: cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.61
diff -c -p -r1.61 typeck.c
*** typeck.c	1998/04/26 16:30:11	1.61
--- typeck.c	1998/05/04 15:59:21
*************** comp_target_types (ttl, ttr, nptrs)
*** 1019,1024 ****
--- 1019,1047 ----
    return 0;
  }
  
+ /* Returns 1 if TYPE1 is more cv-qualified than TYPE2, -1 if TYPE2 is
+    more cv-qualified that TYPE1, and 0 otherwise.  */
+ 
+ int
+ comp_cv_qualification (type1, type2)
+      tree type1;
+      tree type2;
+ {
+   if (TYPE_READONLY (type1) == TYPE_READONLY (type2)
+       && TYPE_VOLATILE (type1) == TYPE_VOLATILE (type2))
+     return 0;
+ 
+   if (TYPE_READONLY (type1) >= TYPE_READONLY (type2)
+       && TYPE_VOLATILE (type1) >= TYPE_VOLATILE (type2))
+     return 1;
+ 
+   if (TYPE_READONLY (type2) >= TYPE_READONLY (type1)
+       && TYPE_VOLATILE (type2) >= TYPE_VOLATILE (type1))
+     return -1;
+ 
+   return 0;
+ }
+ 
  /* If two types share a common base type, return that basetype.
     If there is not a unique most-derived base type, this function
     returns ERROR_MARK_NODE.  */
Index: testsuite/g++.old-deja/g++.other/overload2.C
===================================================================
RCS file: overload2.C
diff -N overload2.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- overload2.C	Mon May  4 09:48:42 1998
***************
*** 0 ****
--- 1,22 ----
+ // Build don't link:
+ 
+ template <class T>
+ class ConstArray {
+ };
+ 
+ template <class T1, class T2>
+ void operator+(const ConstArray<T1>&, const ConstArray<T2>&);
+ 
+ template <class T1, class T2>
+ void operator+(const ConstArray<T1>&, T2);
+ 
+ template <class T1, class T2>
+ void operator+(T1, const ConstArray<T2>&);
+ 
+ const ConstArray<int> cai();
+ const ConstArray<double> cad();
+ 
+ void f()
+ {
+   cai () + cad ();
+ }



More information about the Gcc-bugs mailing list