call.c (compare_qual): Remove.
authorMark Mitchell <mmitchell@usa.net>
Tue, 19 May 1998 14:51:38 +0000 (14:51 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Tue, 19 May 1998 14:51:38 +0000 (14:51 +0000)
* call.c (compare_qual): Remove.
(is_subseq): Tweak.
(is_properly_derived_from): New function.
(maybe_handle_ref_bind): Likewise.
(maybe_handle_implicit_object): Likewise.
(compare_ics): Modify substantially to bring into conformance with
the standard.
* cp-tree.h (TYPE_PTRMEMFUNC_OBJECT_TYPE): New macro.
(comp_cv_qualification): Declare.
(comp_cv_qual_signature): Likewise.
* typeck.c (comp_cv_qualification): Likewise.
(comp_cv_qual_signature): Likewise.

From-SVN: r19880

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/typeck.c
gcc/testsuite/g++.old-deja/g++.other/overload3.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.other/overload4.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.other/overload5.C [new file with mode: 0644]

index e02f940322e54866815a5599ce95270910d36f1f..4050467066685e47b74f84a816d9f6c3eb80f513 100644 (file)
@@ -1,3 +1,18 @@
+Tue May 19 14:50:27 1998  Mark Mitchell  <mmitchell@usa.net>
+
+       * call.c (compare_qual): Remove.
+       (is_subseq): Tweak.
+       (is_properly_derived_from): New function.
+       (maybe_handle_ref_bind): Likewise.
+       (maybe_handle_implicit_object): Likewise.
+       (compare_ics): Modify substantially to bring into conformance with
+       the standard.
+       * cp-tree.h (TYPE_PTRMEMFUNC_OBJECT_TYPE): New macro.
+       (comp_cv_qualification): Declare.
+       (comp_cv_qual_signature): Likewise.
+       * typeck.c (comp_cv_qualification): Likewise.
+       (comp_cv_qual_signature): Likewise.
+
 Tue May 19 10:05:02 1998  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * Makefile.in (parse.o): Depend on toplev.h.
index 82397a607b7c0d772fd57d5d89d854edf3b59d6c..67795ab9bb2f5b20c0a250175614b518a3779e6f 100644 (file)
@@ -45,7 +45,6 @@ static tree build_field_call PROTO((tree, tree, tree, tree));
 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));
@@ -89,6 +88,9 @@ static tree strip_top_quals PROTO((tree));
 static tree non_reference PROTO((tree));
 static tree build_conv PROTO((enum tree_code, tree, tree));
 static int is_subseq PROTO((tree, tree));
+static int is_properly_derived_from PROTO((tree, tree));
+static int maybe_handle_ref_bind PROTO((tree*, tree*));
+static void maybe_handle_implicit_object PROTO((tree*));
 
 tree
 build_vfield_ref (datum, type)
@@ -3658,119 +3660,191 @@ build_new_method_call (instance, name, args, basetype_path, flags)
      flags);
 }
 
-/* Compare two implicit conversion sequences that differ only in their
-   qualification conversion.  Subroutine of compare_ics.  */
+/* Returns non-zero iff standard conversion sequence ICS1 is a proper
+   subsequence of ICS2.  */
 
 static int
-compare_qual (ics1, ics2)
+is_subseq (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);
+  /* 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.  */
 
-  to1 = TREE_TYPE (to1);
-  to2 = TREE_TYPE (to2);
+  while (TREE_CODE (ics1) == RVALUE_CONV
+        || TREE_CODE (ics1) == LVALUE_CONV)
+    ics1 = TREE_OPERAND (ics1, 0);
 
-  if (TREE_CODE (to1) == OFFSET_TYPE)
+  while (1)
     {
-      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;
-}
+      while (TREE_CODE (ics2) == RVALUE_CONV
+         || TREE_CODE (ics2) == LVALUE_CONV)
+       ics2 = TREE_OPERAND (ics2, 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.  */
+      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;
 
-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;
+      ics2 = TREE_OPERAND (ics2, 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;
     }
 }
 
-/* Compare two implicit conversion sequences according to the rules set out in
-   [over.ics.rank].  Return values:
-
-      1: ics1 is better than ics2
-     -1: ics2 is better than ics1
-      0: ics1 and ics2 are indistinguishable */
+/* Returns non-zero iff DERIVED is derived from BASE.  The inputs may
+   be any _TYPE nodes.  */
 
 static int
-compare_ics (ics1, ics2)
-     tree ics1, ics2;
+is_properly_derived_from (derived, base)
+     tree derived;
+     tree base;
 {
-  tree main1, main2;
+  if (!IS_AGGR_TYPE_CODE (TREE_CODE (derived))
+      || !IS_AGGR_TYPE_CODE (TREE_CODE (base)))
+    return 0;
 
-  if (TREE_CODE (ics1) == QUAL_CONV)
-    main1 = TREE_OPERAND (ics1, 0);
-  else
-    main1 = ics1;
+  /* We only allow proper derivation here.  The DERIVED_FROM_P macro
+     considers every class derived from itself.  */
+  return (!comptypes (TYPE_MAIN_VARIANT (derived),
+                     TYPE_MAIN_VARIANT (base), 1)
+         && DERIVED_FROM_P (base, derived));
+}
 
-  if (TREE_CODE (ics2) == QUAL_CONV)
-    main2 = TREE_OPERAND (ics2, 0);
-  else
-    main2 = ics2;
+/* We build the ICS for an implicit object parameter as a pointer
+   conversion sequence.  However, such a sequence should be compared
+   as if it were a reference conversion sequence.  If ICS is the
+   implicit conversion sequence for an implicit object parameter,
+   modify it accordingly.  */
 
-  /* Conversions for `this' are PTR_CONVs, but we compare them as though
-     they were REF_BINDs.  */
-  if (ICS_THIS_FLAG (ics1))
+static void
+maybe_handle_implicit_object (ics)
+     tree* ics;
+{
+  if (ICS_THIS_FLAG (*ics))
     {
-      tree t = main1;
+      /* [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.  */
+      tree t = *ics;
       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;
+      t = build_conv (REF_BIND, TREE_TYPE (*ics), t);
+      ICS_STD_RANK (t) = ICS_STD_RANK (*ics);
+      *ics = t;
     }
-  if (ICS_THIS_FLAG (ics2))
+}
+
+/* If ICS is a REF_BIND, modify it appropriately, set ORIG_TO_TYPE
+   to the type the reference originally referred to, and return 1.
+   Otherwise, return 0.  */
+
+static int
+maybe_handle_ref_bind (ics, reference_type)
+     tree* ics;
+     tree* reference_type;
+{
+  if (TREE_CODE (*ics) == REF_BIND)
     {
-      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;
+      /* [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.  */
+
+      *reference_type = TREE_TYPE (TREE_TYPE (*ics));
+      *ics = TREE_OPERAND (*ics, 0);
+      if (TREE_CODE (*ics) == IDENTITY_CONV
+         && is_properly_derived_from (TREE_TYPE (*ics), *reference_type))
+       *ics = build_conv (BASE_CONV, *reference_type, *ics);
+      return 1;
     }
+  
+  return 0;
+}
 
+/* Compare two implicit conversion sequences according to the rules set out in
+   [over.ics.rank].  Return values:
+
+      1: ics1 is better than ics2
+     -1: ics2 is better than ics1
+      0: ics1 and ics2 are indistinguishable */
+
+static int
+compare_ics (ics1, ics2)
+     tree ics1, ics2;
+{
+  tree from_type1;
+  tree from_type2;
+  tree to_type1;
+  tree to_type2;
+  tree deref_from_type1 = NULL_TREE;
+  tree deref_from_type2;
+  tree deref_to_type1;
+  tree deref_to_type2;
+
+  /* REF_BINDING is non-zero if the result of the conversion sequence
+     is a reference type.   In that case REFERENCE_TYPE is the
+     reference type.  */
+  int ref_binding1;
+  int ref_binding2;
+  tree reference_type1;
+  tree reference_type2;
+
+  /* Handle implicit object parameters.  */
+  maybe_handle_implicit_object (&ics1);
+  maybe_handle_implicit_object (&ics2);
+
+  /* Handle reference parameters.  */
+  ref_binding1 = maybe_handle_ref_bind (&ics1, &reference_type1);
+  ref_binding2 = maybe_handle_ref_bind (&ics2, &reference_type2);
+
+  /* [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 (ics1) < ICS_RANK (ics2))
@@ -3778,6 +3852,8 @@ compare_ics (ics1, ics2)
 
   if (ICS_RANK (ics1) == BAD_RANK)
     {
+      /* 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;
@@ -3785,9 +3861,13 @@ compare_ics (ics1, ics2)
               || ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2))
        return 1;
 
-      /* else fall through */
+      /* 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;
+
   /* 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-
@@ -3807,175 +3887,251 @@ compare_ics (ics1, ics2)
 
       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 */
+      /* We can just fall through here, after setting up
+        FROM_TYPE1 and FROM_TYPE2.  */
+      from_type1 = TREE_TYPE (t1);
+      from_type2 = TREE_TYPE (t2);
     }
+  else
+    {
+      /* We're dealing with two standard conversion sequences. 
 
-#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
+        [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 */
+      
+      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 (TREE_CODE (main1) != TREE_CODE (main2))
+  if (comptypes (from_type1, from_type2, 1))
     {
-      /* ...if S1  is  a  proper  subsequence  of  S2  */
-      if (is_subseq (main1, main2))
+      if (is_subseq (ics1, ics2))
        return 1;
-      if (is_subseq (main2, main1))
+      if (is_subseq (ics2, ics1))
        return -1;
-      return 0;
     }
+  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.  */
+    ;
 
-  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);
+  /* [over.ics.rank]
 
-         if (TREE_CODE (to1) == OFFSET_TYPE)
-           {
-             to1 = TYPE_OFFSET_BASETYPE (to1);
-             from1 = TYPE_OFFSET_BASETYPE (from1);
-           }
-       }
+     Or, if not that,
 
-      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);
+     --the rank of S1 is better than the rank of S2 (by the rules
+       defined below):
 
-         if (TREE_CODE (to2) == OFFSET_TYPE)
-           {
-             to2 = TYPE_OFFSET_BASETYPE (to2);
-             from2 = TYPE_OFFSET_BASETYPE (from2);
-           }
-       }
+    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.
 
-      if (! (IS_AGGR_TYPE (from1) && IS_AGGR_TYPE (from2)))
-       return 0;
+    Two conversion sequences with the same rank are indistinguishable
+    unless one of the following rules applies:
 
-      /* 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;
-       }
+    --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.  
 
-      distf = get_base_distance (from1, from2, 0, 0);
-      if (distf == -1)
-       {
-         distf = -get_base_distance (from2, from1, 0, 0);
-         if (distf == 1)
-           return 0;
-       }
+    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);
 
-      /* 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 (TYPE_PTR_P (from_type1)
+      && TYPE_PTR_P (from_type2)
+      && TYPE_PTR_P (to_type1)
+      && TYPE_PTR_P (to_type2))
+    {
+      deref_from_type1 = TREE_TYPE (from_type1);
+      deref_from_type2 = TREE_TYPE (from_type2);
+      deref_to_type1 = TREE_TYPE (to_type1);
+      deref_to_type2 = TREE_TYPE (to_type2);
+    }
+  /* The rules for pointers to members A::* are just like the rules
+     for pointers A*, except opposite: if B is derived from A then
+     A::* converts to B::*, not vice versa.  For that reason, we
+     switch the from_ and to_ variables here.  */
+  else if (TYPE_PTRMEM_P (from_type1)
+          && TYPE_PTRMEM_P (from_type2)
+          && TYPE_PTRMEM_P (to_type1)
+          && TYPE_PTRMEM_P (to_type2))
+    {
+      deref_to_type1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (from_type1));
+      deref_to_type2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (from_type2));
+      deref_from_type1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (to_type1));
+      deref_from_type2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (to_type2));
+    }
+  else if (TYPE_PTRMEMFUNC_P (from_type1)
+          && TYPE_PTRMEMFUNC_P (from_type2)
+          && TYPE_PTRMEMFUNC_P (to_type1)
+          && TYPE_PTRMEMFUNC_P (to_type2))
+    {
+      deref_to_type1 = TYPE_PTRMEMFUNC_OBJECT_TYPE (from_type1);
+      deref_to_type2 = TYPE_PTRMEMFUNC_OBJECT_TYPE (from_type2);
+      deref_from_type1 = TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type1);
+      deref_from_type2 = TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type2);
+    }
 
-      if (TREE_CODE (to1) == VOID_TYPE && TREE_CODE (to2) == VOID_TYPE)
+  if (deref_from_type1 != NULL_TREE
+      && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type1))
+      && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type2)))
+    {
+      /* This was one of the pointer or pointer-like conversions.  
+
+        [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 (deref_to_type1) == VOID_TYPE
+         && TREE_CODE (deref_to_type2) == VOID_TYPE)
        {
-         if (distf > 0)
-           return 1;
-         else if (distf < 0)
+         if (is_properly_derived_from (deref_from_type1,
+                                       deref_from_type2))
            return -1;
+         else if (is_properly_derived_from (deref_from_type2,
+                                            deref_from_type1))
+           return 1;
        }
-      else if (TREE_CODE (to2) == VOID_TYPE && IS_AGGR_TYPE (to1)
-              && DERIVED_FROM_P (to1, from1))
-       return 1;
-      else if (TREE_CODE (to1) == VOID_TYPE && IS_AGGR_TYPE (to2)
-              && DERIVED_FROM_P (to2, from2))
-       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)
+      else if (TREE_CODE (deref_to_type1) == VOID_TYPE
+              || TREE_CODE (deref_to_type2) == VOID_TYPE)
        {
-         distt = -get_base_distance (to2, to1, 0, 0);
-         if (distt == 1)
-           return 0;
+         if (comptypes (deref_from_type1, deref_from_type2, 1))
+           {
+             if (TREE_CODE (deref_to_type2) == VOID_TYPE)
+               {
+                 if (is_properly_derived_from (deref_from_type1,
+                                               deref_to_type1))
+                   return 1;
+               }
+             /* We know that DEREF_TO_TYPE1 is `void' here.  */
+             else if (is_properly_derived_from (deref_from_type1,
+                                                deref_to_type2))
+               return -1;
+           }
        }
-
-      /* --conversion of C* to B* is better than conversion of C* to A*, */
-      if (distf == 0)
+      else if (IS_AGGR_TYPE_CODE (TREE_CODE (deref_to_type1))
+              && IS_AGGR_TYPE_CODE (TREE_CODE (deref_to_type2)))
        {
-         if (distt > 0)
-           return -1;
-         else if (distt < 0)
-           return 1;
+         /* [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 (deref_from_type1, deref_from_type2, 1))
+           {
+             if (is_properly_derived_from (deref_to_type1,
+                                           deref_to_type2))
+               return 1;
+             else if (is_properly_derived_from (deref_to_type2,
+                                                deref_to_type1))
+               return -1;
+           }
+         else if (comptypes (deref_to_type1, deref_to_type2, 1))
+           {
+             if (is_properly_derived_from (deref_from_type2,
+                                           deref_from_type1))
+               return 1;
+             else if (is_properly_derived_from (deref_from_type1,
+                                                deref_from_type2))
+               return -1;
+           }
        }
-      /* --conversion of B* to A* is better than conversion of C* to A*, */
-      else if (distt == 0)
+    }
+  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_properly_derived_from (from_type1, to_type1)
+         && is_properly_derived_from (from_type1, to_type2))
        {
-         if (distf > 0)
+         if (is_properly_derived_from (to_type1, to_type2))
            return 1;
-         else if (distf < 0)
+         else if (is_properly_derived_from (to_type2, to_type1))
            return -1;
        }
     }
-  else if (TREE_CODE (TREE_TYPE (main1)) == POINTER_TYPE
-          || TYPE_PTRMEMFUNC_P (TREE_TYPE (main1)))
+  else if (IS_AGGR_TYPE_CODE (TREE_CODE (to_type1))
+          && comptypes (to_type1, to_type2, 1))
     {
-      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
+      /* [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_properly_derived_from (from_type1, to_type1)
+         && is_properly_derived_from (from_type2, to_type1))
+       {
+         if (is_properly_derived_from (from_type2, from_type1))
+           return 1;
+         else if (is_properly_derived_from (from_type1, from_type2))
+           return -1;
+       }
     }
 
+  /* [over.ics.rank]
+
+     --S1 and S2 differ only in their qualification conversion and  yield
+       similar  types  T1 and T2 (_conv.qual_), respectively, and the cv-
+       qualification signature of type T1 is a proper subset of  the  cv-
+       qualification signature of type T2  */
+  if (TREE_CODE (ics1) == QUAL_CONV 
+      && TREE_CODE (ics2) == QUAL_CONV
+      && comptypes (from_type1, from_type2, 1))
+    return comp_cv_qual_signature (to_type1, to_type2);
+
+  /* [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_binding1 && ref_binding2
+      && comptypes (TYPE_MAIN_VARIANT (to_type1),
+                   TYPE_MAIN_VARIANT (to_type2), 1))
+    return comp_cv_qualification (reference_type2, reference_type1);
+
+  /* Neither conversion sequence is better than the other.  */
   return 0;
 }
 
index a42ac73b1c3dde2882f9b3e6aebec46b6702039a..8679f58052a21a7461d7e27684684eb734da44c3 100644 (file)
@@ -1362,6 +1362,11 @@ extern int flag_new_for_scope;
    pointer to member function.  TYPE_PTRMEMFUNC_P _must_ be true,
    before using this macro.  */
 #define TYPE_PTRMEMFUNC_FN_TYPE(NODE) (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (NODE)))))))
+
+/* Returns `A' for a type like `int (A::*)(double)' */
+#define TYPE_PTRMEMFUNC_OBJECT_TYPE(NODE) \
+  TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (NODE)))
+
 /* These are use to manipulate the canonical RECORD_TYPE from the
    hashed POINTER_TYPE, and can only be used on the POINTER_TYPE.  */
 #define TYPE_GET_PTRMEMFUNC_TYPE(NODE) ((tree)TYPE_LANG_SPECIFIC(NODE))
@@ -2770,6 +2775,8 @@ extern int comptypes                              PROTO((tree, tree, int));
 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 comp_cv_qual_signature               PROTO((tree, tree));
 extern int self_promoting_args_p               PROTO((tree));
 extern tree unsigned_type                      PROTO((tree));
 extern tree signed_type                                PROTO((tree));
index 9e721ddf8a60dae3071ede69548bffac7bc8b40f..de5c3b34f43931c202ae3658c5b5fbcaac0de207 100644 (file)
@@ -1048,6 +1048,46 @@ comp_target_types (ttl, ttr, nptrs)
   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;
+}
+
+/* Returns 1 if the cv-qualification signature of TYPE1 is a proper
+   subset of the cv-qualification signature of TYPE2, and the types
+   are similar.  Returns -1 if the other way 'round, and 0 otherwise.  */
+
+int
+comp_cv_qual_signature (type1, type2)
+     tree type1;
+     tree type2;
+{
+  if (comp_ptr_ttypes_real (type2, type1, -1))
+    return 1;
+  else if (comp_ptr_ttypes_real (type1, type2, -1))
+    return -1;
+  else
+    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.  */
@@ -7409,14 +7449,21 @@ c_expand_start_case (exp)
   return exp;
 }
 
-/* CONSTP remembers whether or not all the intervening pointers in the `to'
-   type have been const.  */
+/* Returns non-zero if the pointer-type FROM can be converted to the
+   pointer-type TO via a qualification conversion.  If CONSTP is -1,
+   then we return non-zero if the pointers are similar, and the
+   cv-qualification signature of FROM is a proper subset of that of TO.
+
+   If CONSTP is positive, then all outer pointers have been
+   const-qualified.  */
 
 static int
 comp_ptr_ttypes_real (to, from, constp)
      tree to, from;
      int constp;
 {
+  int to_more_cv_qualified = 0;
+
   for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
     {
       if (TREE_CODE (to) != TREE_CODE (from))
@@ -7431,19 +7478,32 @@ comp_ptr_ttypes_real (to, from, constp)
         so the usual checks are not appropriate.  */
       if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
        {
-         if (TYPE_READONLY (from) > TYPE_READONLY (to)
-             || TYPE_VOLATILE (from) > TYPE_VOLATILE (to))
-           return 0;
+         switch (comp_cv_qualification (from, to))
+           {
+           case 1:
+             /* FROM is more cv-qualified than TO.  */
+             return 0;
 
-         if (! constp
-             && (TYPE_READONLY (to) > TYPE_READONLY (from)
-                 || TYPE_VOLATILE (to) > TYPE_READONLY (from)))
-           return 0;
-         constp &= TYPE_READONLY (to);
+           case -1:
+             /* TO is more cv-qualified than FROM.  */
+             if (constp == 0)
+               return 0;
+             else 
+               ++to_more_cv_qualified;
+             break;
+
+           default:
+             break;
+           }
+
+         if (constp > 0)
+           constp &= TYPE_READONLY (to);
        }
 
       if (TREE_CODE (to) != POINTER_TYPE)
-       return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1);
+       return 
+         comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1)
+         && (constp >= 0 || to_more_cv_qualified);
     }
 }
 
diff --git a/gcc/testsuite/g++.old-deja/g++.other/overload3.C b/gcc/testsuite/g++.old-deja/g++.other/overload3.C
new file mode 100644 (file)
index 0000000..fc1d5c0
--- /dev/null
@@ -0,0 +1,16 @@
+// Build don't run:
+
+void f(const int *);
+void f(int *) {}
+
+void f2(const volatile int *);
+void f2(volatile int *) {}
+
+int i;
+
+int main()
+{
+  f(&i);
+  f2(&i);
+}
+          
diff --git a/gcc/testsuite/g++.old-deja/g++.other/overload4.C b/gcc/testsuite/g++.old-deja/g++.other/overload4.C
new file mode 100644 (file)
index 0000000..2247853
--- /dev/null
@@ -0,0 +1,10 @@
+// Build don't run:
+
+void f(int* const volatile * const * const*);
+void f(int* const * const * const*) {}
+
+int main()
+{
+  int*** ip;
+  f(&ip);
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/overload5.C b/gcc/testsuite/g++.old-deja/g++.other/overload5.C
new file mode 100644 (file)
index 0000000..5f5e11f
--- /dev/null
@@ -0,0 +1,22 @@
+// Build don't run:
+
+struct S {};
+
+struct T : public S {};
+
+struct U : public T {};
+
+void f(int T::*) {}
+void f(int U::*);
+
+void g(void (T::*)(int)) {}
+void g(void (U::*)(int));
+
+int main()
+{
+  int S::*ip;
+  void (S::*fp)(int);
+
+  f(ip);
+  g(fp);
+}