OSDN Git Service

* lex.c (handle_cp_pragma): Remove #pragma vtable.
[pf3gnuchains/gcc-fork.git] / gcc / cp / call.c
index 67795ab..bb0b71a 100644 (file)
@@ -47,7 +47,6 @@ static struct z_candidate * tourney PROTO((struct z_candidate *));
 static int joust PROTO((struct z_candidate *, struct z_candidate *, int));
 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));
 static tree convert_like PROTO((tree, tree));
 static void op_error PROTO((enum tree_code, enum tree_code, tree, tree,
                            tree, char *));
@@ -341,6 +340,37 @@ resolve_scope_to_name (outer_type, inner_stuff)
   return tmp;
 }
 
+/* Returns nonzero iff the destructor name specified in NAME
+   (a BIT_NOT_EXPR) matches BASETYPE.  The operand of NAME can take many
+   forms...  */
+
+int
+check_dtor_name (basetype, name)
+     tree basetype, name;
+{
+  name = TREE_OPERAND (name, 0);
+
+  if (TREE_CODE (name) == TYPE_DECL)
+    name = TREE_TYPE (name);
+  else if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
+    /* OK */;
+  else if (TREE_CODE (name) == IDENTIFIER_NODE)
+    {
+      if ((IS_AGGR_TYPE (basetype) && name == constructor_name (basetype))
+         || (TREE_CODE (basetype) == ENUMERAL_TYPE
+             && name == TYPE_IDENTIFIER (basetype)))
+       name = basetype;
+      else
+       name = get_type_value (name);
+    }
+  else
+    my_friendly_abort (980605);
+
+  if (name && TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (name))
+    return 1;
+  return 0;
+}
+
 /* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'.
    This is how virtual function calls are avoided.  */
 
@@ -363,7 +393,8 @@ build_scoped_method_call (exp, basetype, name, parms)
 
   if (processing_template_decl)
     {
-      if (TREE_CODE (name) == BIT_NOT_EXPR)
+      if (TREE_CODE (name) == BIT_NOT_EXPR
+         && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
        {
          tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 0);
          if (type)
@@ -384,21 +415,30 @@ build_scoped_method_call (exp, basetype, name, parms)
   else
     binfo = NULL_TREE;
 
-  /* Destructors can be "called" for simple types; see 5.2.4 and 12.4 Note
-     that explicit ~int is caught in the parser; this deals with typedefs
-     and template parms.  */
-  if (TREE_CODE (name) == BIT_NOT_EXPR && ! IS_AGGR_TYPE (basetype))
+  /* Check the destructor call syntax.  */
+  if (TREE_CODE (name) == BIT_NOT_EXPR)
     {
-      if (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (basetype))
-       cp_error ("type of `%E' does not match destructor type `%T' (type was `%T')",
-                 exp, basetype, type);
-      name = TREE_OPERAND (name, 0);
-      if (TYPE_MAIN_VARIANT (basetype) != name 
-         && (TYPE_MAIN_VARIANT (basetype)
-             != TYPE_MAIN_VARIANT (get_type_value (name))))
+      /* We can get here if someone writes their destructor call like
+        `obj.NS::~T()'; this isn't really a scoped method call, so hand
+        it off.  */
+      if (TREE_CODE (basetype) == NAMESPACE_DECL)
+       return build_method_call (exp, name, parms, NULL_TREE, LOOKUP_NORMAL);
+
+      if (! check_dtor_name (basetype, name))
        cp_error ("qualified type `%T' does not match destructor name `~%T'",
-                 basetype, name);
-      return cp_convert (void_type_node, exp);
+                 basetype, TREE_OPERAND (name, 0));
+
+      /* Destructors can be "called" for simple types; see 5.2.4 and 12.4 Note
+        that explicit ~int is caught in the parser; this deals with typedefs
+        and template parms.  */
+      if (! IS_AGGR_TYPE (basetype))
+       {
+         if (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (basetype))
+           cp_error ("type of `%E' does not match destructor type `%T' (type was `%T')",
+                     exp, basetype, type);
+
+         return cp_convert (void_type_node, exp);
+       }
     }
 
   if (! is_aggr_type (basetype, 1))
@@ -432,17 +472,6 @@ build_scoped_method_call (exp, basetype, name, parms)
       /* Call to a destructor.  */
       if (TREE_CODE (name) == BIT_NOT_EXPR)
        {
-         /* Explicit call to destructor.  */
-         name = TREE_OPERAND (name, 0);
-         if (! (name == TYPE_MAIN_VARIANT (TREE_TYPE (decl))
-                || name == constructor_name (TREE_TYPE (decl))
-                || TREE_TYPE (decl) == get_type_value (name)))
-           {
-             cp_error
-               ("qualified type `%T' does not match destructor name `~%T'",
-                TREE_TYPE (decl), name);
-             return error_mark_node;
-           }
          if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
            return cp_convert (void_type_node, exp);
          
@@ -597,10 +626,13 @@ build_method_call (instance, name, parms, basetype_path, flags)
 
   if (processing_template_decl)
     {
-      if (TREE_CODE (name) == BIT_NOT_EXPR)
+      /* We need to process template parm names here so that tsubst catches
+        them properly.  Other type names can wait.  */
+      if (TREE_CODE (name) == BIT_NOT_EXPR
+         && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
        {
          tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 0);
-         if (type)
+         if (type && TREE_CODE (type) == TEMPLATE_TYPE_PARM)
            name = build_min_nt (BIT_NOT_EXPR, type);
        }
 
@@ -632,23 +664,16 @@ build_method_call (instance, name, parms, basetype_path, flags)
 
   if (TREE_CODE (name) == BIT_NOT_EXPR)
     {
-      flags |= LOOKUP_DESTRUCTOR;
-      name = TREE_OPERAND (name, 0);
       if (parms)
        error ("destructors take no parameters");
       basetype = TREE_TYPE (instance);
       if (TREE_CODE (basetype) == REFERENCE_TYPE)
        basetype = TREE_TYPE (basetype);
-      if (! (name == TYPE_MAIN_VARIANT (basetype)
-            || (IS_AGGR_TYPE (basetype)
-                && name == constructor_name (basetype))
-            || (TYPE_MAIN_VARIANT (basetype)
-                == TYPE_MAIN_VARIANT (get_type_value (name)))))
-       {
-         cp_error ("destructor name `~%D' does not match type `%T' of expression",
-                   name, basetype);
-         return cp_convert (void_type_node, instance);
-       }
+
+      if (! check_dtor_name (basetype, name))
+       cp_error
+         ("destructor name `~%T' does not match type `%T' of expression",
+          TREE_OPERAND (name, 0), basetype);
 
       if (! TYPE_HAS_DESTRUCTOR (complete_type (basetype)))
        return cp_convert (void_type_node, instance);
@@ -858,6 +883,9 @@ standard_conversion (to, from, expr)
        /* OK */;
       else if (comp_ptr_ttypes (TREE_TYPE (to), TREE_TYPE (from)))
        conv = build_conv (QUAL_CONV, to, conv);
+      else if (expr && string_conv_p (to, expr, 0))
+       /* converting from string constant to char *.  */
+       conv = build_conv (QUAL_CONV, to, conv);
       else if (ptr_reasonably_similar (TREE_TYPE (to), TREE_TYPE (from)))
        {
          conv = build_conv (PTR_CONV, to, conv);
@@ -1119,15 +1147,9 @@ add_function_candidate (candidates, fn, arglist, flags)
   for (i = 0; i < len; ++i)
     {
       tree arg = TREE_VALUE (argnode);
-      tree argtype = TREE_TYPE (arg);
+      tree argtype = lvalue_type (arg);
       tree t;
 
-      /* An overloaded function does not have an argument type */
-      if (TREE_CODE (arg) == OVERLOAD)
-       argtype = unknown_type_node;
-      argtype = cp_build_type_variant
-       (argtype, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
-
       if (parmnode == void_list_node)
        break;
       else if (parmnode)
@@ -1780,6 +1802,11 @@ add_builtin_candidates (candidates, code, code2, fnname, args, flags)
        {
          tree convs = lookup_conversions (argtypes[i]);
 
+         if (i == 0 && code == MODIFY_EXPR && code2 == NOP_EXPR)
+           return candidates;
+
+         convs = lookup_conversions (argtypes[i]);
+
          if (code == COND_EXPR)
            {
              if (real_lvalue_p (args[i]))
@@ -1789,9 +1816,8 @@ add_builtin_candidates (candidates, code, code2, fnname, args, flags)
              types[i] = scratch_tree_cons
                (NULL_TREE, TYPE_MAIN_VARIANT (argtypes[i]), types[i]);
            }
-               
-         else if (! convs || (i == 0 && code == MODIFY_EXPR
-                              && code2 == NOP_EXPR))
+
+         else if (! convs)
            return candidates;
 
          for (; convs; convs = TREE_CHAIN (convs))
@@ -2897,16 +2923,16 @@ build_op_new_call (code, type, args, flags)
    ADDR is the pointer to be deleted.  For placement delete, it is also
      used to determine what the corresponding new looked like.
    SIZE is the size of the memory block to be deleted.
-   FLAGS are the usual overloading flags.  */
+   FLAGS are the usual overloading flags.
+   PLACEMENT is the corresponding placement new call, or 0.  */
 
 tree
-build_op_delete_call (code, addr, size, flags)
+build_op_delete_call (code, addr, size, flags, placement)
      enum tree_code code;
-     tree addr, size;
+     tree addr, size, placement;
      int flags;
 {
   tree fn, fns, fnname, fntype, argtypes, args, type;
-  int placement;
 
   if (addr == error_mark_node)
     return error_mark_node;
@@ -2930,42 +2956,20 @@ build_op_delete_call (code, addr, size, flags)
   else
     fns = NULL_TREE;
 
-  if (fns)
-    {
-#if 0
-      /* It is unnecessary to wrap another TREE_LIST around it. (MvL) */
-      /* Build this up like build_offset_ref does.  */
-      fns = build_tree_list (error_mark_node, fns);
-      TREE_TYPE (fns) = build_offset_type (type, unknown_type_node);
-#endif
-    }
-  else
+  if (fns == NULL_TREE)
     fns = lookup_name_nonclass (fnname);
 
-  /* We can recognize a placement delete because of LOOKUP_SPECULATIVELY;
-     if we are doing placement delete we do nothing if we don't find a
-     matching op delete.  */
-  placement = !!(flags & LOOKUP_SPECULATIVELY);
   if (placement)
     {
-      /* If placement, we are coming from build_new, and we know that addr
-        is the allocation expression, so extract the info we need from it.
-        Obviously, if the build_new process changes this may have to
-        change as well.  */
-
-      /* The NOP_EXPR.  */
-      tree t = TREE_OPERAND (addr, 1);
-      /* The CALL_EXPR.  */
-      t = TREE_OPERAND (t, 0);
-      /* The function.  */
-      argtypes = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
-      /* The second parm type.  */
+      /* placement is a CALL_EXPR around an ADDR_EXPR around a function.  */
+
+      /* Extract the function.  */
+      argtypes = TREE_OPERAND (TREE_OPERAND (placement, 0), 0);
+      /* Then the second parm type.  */
       argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (argtypes)));
-      /* The second argument.  */
-      args = TREE_CHAIN (TREE_OPERAND (t, 1));
 
-      /* Pull the dummy var out of the TARGET_EXPR for use in our call.  */
-      addr = TREE_OPERAND (addr, 0);
+      /* Also the second argument.  */
+      args = TREE_CHAIN (TREE_OPERAND (placement, 1));
     }
   else
     {
@@ -2996,6 +3000,8 @@ build_op_delete_call (code, addr, size, flags)
       return build_function_call (fn, expr_tree_cons (NULL_TREE, addr, args));
     }
 
+  /* If we are doing placement delete we do nothing if we don't find a
+     matching op delete.  */
   if (placement)
     return NULL_TREE;
 
@@ -3007,9 +3013,20 @@ build_op_delete_call (code, addr, size, flags)
   fn = instantiate_type (fntype, fns, 0);
 
   if (fn != error_mark_node)
-    return build_function_call
-      (fn, expr_tree_cons (NULL_TREE, addr,
-                          build_expr_list (NULL_TREE, size)));
+    {
+      if (TREE_CODE (fns) == TREE_LIST)
+       /* Member functions.  */
+       enforce_access (TREE_PURPOSE (fns), fn);
+      return build_function_call
+       (fn, expr_tree_cons (NULL_TREE, addr,
+                            build_expr_list (NULL_TREE, size)));
+    }
+
+  /* finish_function passes LOOKUP_SPECULATIVELY if we're in a
+     destructor, in which case the error should be deferred
+     until someone actually tries to delete one of these.  */
+  if (flags & LOOKUP_SPECULATIVELY)
+    return NULL_TREE;
 
   cp_error ("no suitable operator delete for `%T'", type);
   return error_mark_node;
@@ -3124,8 +3141,32 @@ convert_like (convs, expr)
        return expr;
       /* else fall through */
     case BASE_CONV:
-      return build_user_type_conversion
-       (TREE_TYPE (convs), expr, LOOKUP_NORMAL);
+      {
+       tree cvt_expr = build_user_type_conversion
+         (TREE_TYPE (convs), expr, LOOKUP_NORMAL);
+       if (!cvt_expr) 
+         {
+           /* This can occur if, for example, the EXPR has incomplete
+              type.  We can't check for that before attempting the
+              conversion because the type might be an incomplete
+              array type, which is OK if some constructor for the
+              destination type takes a pointer argument.  */
+           if (TYPE_SIZE (TREE_TYPE (expr)) == 0)
+             {
+               if (comptypes (TREE_TYPE (expr), TREE_TYPE (convs), 1))
+                 incomplete_type_error (expr, TREE_TYPE (expr));
+               else
+                 cp_error ("could not convert `%E' (with incomplete type `%T') to `%T'",
+                           expr, TREE_TYPE (expr), TREE_TYPE (convs));
+             }
+           else
+             cp_error ("could not convert `%E' to `%T'",
+                       expr, TREE_TYPE (convs));
+           return error_mark_node;
+         }
+       return cvt_expr;
+      }
+
     case REF_BIND:
       return convert_to_reference
        (TREE_TYPE (convs), expr,
@@ -3134,6 +3175,11 @@ convert_like (convs, expr)
     case LVALUE_CONV:
       return decay_conversion (expr);
 
+    case QUAL_CONV:
+      /* Warn about deprecated conversion if appropriate.  */
+      string_conv_p (TREE_TYPE (convs), expr, 1);
+      break;
+      
     default:
       break;
     }
@@ -3141,7 +3187,34 @@ convert_like (convs, expr)
                      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
 }
 
-static tree
+/* ARG is being passed to a varargs function.  Perform any conversions
+   required.  Return the converted value.  */
+
+tree
+convert_arg_to_ellipsis (arg)
+     tree arg;
+{
+  if (TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE
+      && (TYPE_PRECISION (TREE_TYPE (arg))
+         < TYPE_PRECISION (double_type_node)))
+    /* Convert `float' to `double'.  */
+    arg = cp_convert (double_type_node, arg);
+  else if (IS_AGGR_TYPE (TREE_TYPE (arg))
+          && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (arg)))
+    cp_warning ("cannot pass objects of type `%T' through `...'",
+               TREE_TYPE (arg));
+  else
+    /* Convert `short' and `char' to full-size `int'.  */
+    arg = default_conversion (arg);
+
+  return arg;
+}
+
+/* ARG is a default argument expression being passed to a parameter of
+   the indicated TYPE.  Do any required conversions.  Return the
+   converted value.  */
+
+tree
 convert_default_arg (type, arg)
      tree type, arg;
 {
@@ -3218,6 +3291,7 @@ build_over_call (cand, args, flags)
     {
       tree parmtype = TREE_VALUE (parm);
       tree argtype = TREE_TYPE (TREE_VALUE (arg));
+      tree t;
       if (ICS_BAD_FLAG (TREE_VEC_ELT (convs, i)))
        {
          int dv = (TYPE_VOLATILE (TREE_TYPE (parmtype))
@@ -3230,9 +3304,18 @@ build_over_call (cand, args, flags)
          cp_pedwarn ("passing `%T' as `this' argument of `%#D' discards %s",
                      TREE_TYPE (argtype), fn, p);
        }
-      converted_args = expr_tree_cons
-       (NULL_TREE, convert_force (TREE_VALUE (parm), TREE_VALUE (arg), CONV_C_CAST),
-        converted_args);
+      /* [class.mfct.nonstatic]: If a nonstatic member function of a class
+        X is called for an object that is not of type X, or of a type
+        derived from X, the behavior is undefined.
+
+         So we can assume that anything passed as 'this' is non-null, and
+        optimize accordingly.  */
+      if (TREE_CODE (parmtype) == POINTER_TYPE)
+       t = convert_pointer_to_real (TREE_TYPE (parmtype), TREE_VALUE (arg));
+      else
+       /* This happens with signatures.  */
+       t = convert_force (parmtype, TREE_VALUE (arg), CONV_C_CAST);
+      converted_args = expr_tree_cons (NULL_TREE, t, converted_args);
       parm = TREE_CHAIN (parm);
       arg = TREE_CHAIN (arg);
       ++i;
@@ -3266,7 +3349,14 @@ build_over_call (cand, args, flags)
             "argument passing", fn, i - is_method);
        }
       else
-       val = convert_like (conv, TREE_VALUE (arg));
+       {
+         /* Issue warnings about peculiar, but legal, uses of NULL.  */
+         if (ARITHMETIC_TYPE_P (TREE_VALUE (parm))
+             && TREE_VALUE (arg) == null_node)
+           cp_warning ("converting NULL to non-pointer type");
+           
+         val = convert_like (conv, TREE_VALUE (arg));
+       }
 
 #ifdef PROMOTE_PROTOTYPES
       if ((TREE_CODE (type) == INTEGER_TYPE
@@ -3301,7 +3391,7 @@ build_over_call (cand, args, flags)
          arg = tsubst_expr (arg, DECL_TI_ARGS (fn), NULL_TREE);
 
          if (DECL_CLASS_SCOPE_P (fn))
-           popclass (0);
+           popclass (1);
        }
       converted_args = expr_tree_cons
        (NULL_TREE, convert_default_arg (TREE_VALUE (parm), arg),
@@ -3310,31 +3400,20 @@ build_over_call (cand, args, flags)
 
   /* Ellipsis */
   for (; arg; arg = TREE_CHAIN (arg))
-    {
-      val = TREE_VALUE (arg);
-
-      if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (val))
-             < TYPE_PRECISION (double_type_node)))
-       /* Convert `float' to `double'.  */
-       val = cp_convert (double_type_node, val);
-      else if (IS_AGGR_TYPE (TREE_TYPE (val))
-              && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (val)))
-       cp_warning ("cannot pass objects of type `%T' through `...'",
-                   TREE_TYPE (val));
-      else
-       /* Convert `short' and `char' to full-size `int'.  */
-       val = default_conversion (val);
-
-      converted_args = expr_tree_cons (NULL_TREE, val, converted_args);
-    }
+    converted_args 
+      = expr_tree_cons (NULL_TREE,
+                       convert_arg_to_ellipsis (TREE_VALUE (arg)),
+                       converted_args);
 
   converted_args = nreverse (converted_args);
 
   /* Avoid actually calling copy constructors and copy assignment operators,
      if possible.  */
-  if (DECL_CONSTRUCTOR_P (fn)
-      && TREE_VEC_LENGTH (convs) == 1
+
+  if (! flag_elide_constructors)
+    /* Do things the hard way.  */;
+  else if (DECL_CONSTRUCTOR_P (fn)
+          && TREE_VEC_LENGTH (convs) == 1
       && copy_args_p (fn))
     {
       tree targ;
@@ -3739,23 +3818,27 @@ maybe_handle_implicit_object (ics)
         member and cv is the cv-qualification on the member
         function declaration.  */
       tree t = *ics;
+      if (TREE_CODE (t) == QUAL_CONV)
+       t = TREE_OPERAND (t, 0);
       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 (*ics), t);
+      t = build_conv (REF_BIND, 
+                     build_reference_type (TREE_TYPE (TREE_TYPE (*ics))), 
+                     t);
       ICS_STD_RANK (t) = ICS_STD_RANK (*ics);
       *ics = t;
     }
 }
 
-/* If ICS is a REF_BIND, modify it appropriately, set ORIG_TO_TYPE
+/* If ICS is a REF_BIND, modify it appropriately, set TARGET_TYPE
    to the type the reference originally referred to, and return 1.
    Otherwise, return 0.  */
 
 static int
-maybe_handle_ref_bind (ics, reference_type)
+maybe_handle_ref_bind (ics, target_type)
      tree* ics;
-     tree* reference_type;
+     tree* target_type;
 {
   if (TREE_CODE (*ics) == REF_BIND)
     {
@@ -3786,11 +3869,16 @@ maybe_handle_ref_bind (ics, reference_type)
         cv-qualification is subsumed by the initialization itself and
         does not constitute a conversion.  */
 
-      *reference_type = TREE_TYPE (TREE_TYPE (*ics));
+      tree old_ics = *ics;
+
+      *target_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);
+         && is_properly_derived_from (TREE_TYPE (*ics), *target_type))
+       *ics = build_conv (BASE_CONV, *target_type, *ics);
+      ICS_USER_FLAG (*ics) = ICS_USER_FLAG (old_ics);
+      ICS_BAD_FLAG (*ics) = ICS_BAD_FLAG (old_ics);
+      
       return 1;
     }
   
@@ -3818,20 +3906,20 @@ compare_ics (ics1, ics2)
   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.  */
+     is a reference type.   In that case TARGET_TYPE is the
+     type referred to by the reference.  */
   int ref_binding1;
   int ref_binding2;
-  tree reference_type1;
-  tree reference_type2;
+  tree target_type1;
+  tree target_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);
+  ref_binding1 = maybe_handle_ref_bind (&ics1, &target_type1);
+  ref_binding2 = maybe_handle_ref_bind (&ics2, &target_type2);
 
   /* [over.ics.rank]
 
@@ -3926,12 +4014,10 @@ compare_ics (ics1, ics2)
       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.  */
-    ;
+  /* Otherwise, 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]
 
@@ -4129,7 +4215,7 @@ compare_ics (ics1, ics2)
   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);
+    return comp_cv_qualification (target_type2, target_type1);
 
   /* Neither conversion sequence is better than the other.  */
   return 0;
@@ -4263,13 +4349,19 @@ joust (cand1, cand2, warn)
        }
     }
 
-  /* warn about confusing overload resolution */
+  /* warn about confusing overload resolution for user-defined conversions,
+     either between a constructor and a conversion op, or between two
+     conversion ops.  */
   if (winner && cand1->second_conv
-      && ! DECL_CONSTRUCTOR_P (cand1->fn)
-      && ! DECL_CONSTRUCTOR_P (cand2->fn))
+      && ((DECL_CONSTRUCTOR_P (cand1->fn)
+          != DECL_CONSTRUCTOR_P (cand2->fn))
+         /* Don't warn if the two conv ops convert to the same type...  */
+         || (! DECL_CONSTRUCTOR_P (cand1->fn)
+             && ! comptypes (TREE_TYPE (cand1->second_conv),
+                             TREE_TYPE (cand2->second_conv), 1))))
     {
       int comp = compare_ics (cand1->second_conv, cand2->second_conv);
-      if (comp && comp != winner)
+      if (comp != winner)
        {
          struct z_candidate *w, *l;
          if (winner == 1)
@@ -4278,11 +4370,13 @@ joust (cand1, cand2, warn)
            w = cand2, l = cand1;
          if (warn)
            {
+             tree source = source_type (TREE_VEC_ELT (w->convs, 0));
+             if (! DECL_CONSTRUCTOR_P (w->fn))
+               source = TREE_TYPE (source);
              cp_warning ("choosing `%D' over `%D'", w->fn, l->fn);
              cp_warning ("  for conversion from `%T' to `%T'",
-                         TREE_TYPE (source_type (TREE_VEC_ELT (w->convs, 0))),
-                         TREE_TYPE (w->second_conv));
-             cp_warning ("  because conversion sequence for `this' argument is better");
+                         source, TREE_TYPE (w->second_conv));
+             cp_warning ("  because conversion sequence for the argument is better");
            }
          else
            add_warning (w, l);
@@ -4382,6 +4476,7 @@ tourney (candidates)
 {
   struct z_candidate *champ = candidates, *challenger;
   int fate;
+  int champ_compared_to_predecessor = 0;
 
   /* Walk through the list once, comparing each current champ to the next
      candidate, knocking out a candidate or two with each comparison.  */
@@ -4398,19 +4493,24 @@ tourney (candidates)
              champ = challenger->next;
              if (champ == 0)
                return 0;
+             champ_compared_to_predecessor = 0;
            }
          else
-           champ = challenger;
+           {
+             champ = challenger;
+             champ_compared_to_predecessor = 1;
+           }
 
          challenger = champ->next;
        }
     }
 
   /* Make sure the champ is better than all the candidates it hasn't yet
-     been compared to.  This may do one more comparison than necessary.  Oh
-     well.  */
+     been compared to.  */
 
-  for (challenger = candidates; challenger != champ;
+  for (challenger = candidates; 
+       challenger != champ 
+        && !(champ_compared_to_predecessor && challenger->next == champ);
        challenger = challenger->next)
     {
       fate = joust (champ, challenger, 0);