OSDN Git Service

89th Cygnus<->FSF quick merge
[pf3gnuchains/gcc-fork.git] / gcc / cp / call.c
index 02fc964..9ae201c 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions related to invoking methods and overloaded functions.
-   Copyright (C) 1987, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com) and
    hacked by Brendan Kehoe (brendan@cygnus.com).
 
@@ -17,16 +17,18 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
-/* High-level class interface. */
+/* High-level class interface.  */
 
 #include "config.h"
 #include "tree.h"
 #include <stdio.h>
 #include "cp-tree.h"
 #include "class.h"
+#include "output.h"
 #include "flags.h"
 
 #include "obstack.h"
@@ -36,46 +38,24 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern void sorry ();
 
 extern int inhibit_warnings;
-extern int flag_assume_nonnull_objects;
 extern tree ctor_label, dtor_label;
 
-/* From cp-typeck.c:  */
-extern tree unary_complex_lvalue ();
-
 /* Compute the ease with which a conversion can be performed
    between an expected and the given type.  */
-static int convert_harshness_old ();
-static struct harshness_code convert_harshness_ansi ();
-
-/* OLD METHOD */
-/* Note the old method also uses USER_HARSHNESS, BASE_DERIVED_HARSHNESS,
-   CONST_HARSHNESS.  */
-#define EVIL 1
-#define TRIVIAL 0
-#define EVIL_HARSHNESS(ARG) ((ARG) & 1)
-#define ELLIPSIS_HARSHNESS(ARG) ((ARG) & 2)
-#define CONTRAVARIANT_HARSHNESS(ARG) ((ARG) & 8)
-#define INT_TO_BD_HARSHNESS(ARG) (((ARG) << 5) | 16)
-#define INT_FROM_BD_HARSHNESS(ARG) ((ARG) >> 5)
-#define INT_TO_EASY_HARSHNESS(ARG) ((ARG) << 5)
-#define INT_FROM_EASY_HARSHNESS(ARG) ((ARG) >> 5)
-#define ONLY_EASY_HARSHNESS(ARG) (((ARG) & 31) == 0)
-
-
-/* NEW METHOD */
+
+static struct harshness_code convert_harshness PROTO((register tree, register tree, tree));
+
 #define EVIL_RETURN(ARG)       ((ARG).code = EVIL_CODE, (ARG))
+#define STD_RETURN(ARG)                ((ARG).code = STD_CODE, (ARG))
 #define QUAL_RETURN(ARG)       ((ARG).code = QUAL_CODE, (ARG))
 #define TRIVIAL_RETURN(ARG)    ((ARG).code = TRIVIAL_CODE, (ARG))
 #define ZERO_RETURN(ARG)       ((ARG).code = 0, (ARG))
 
-#define USER_HARSHNESS(ARG) ((ARG) & 4)
-#define BASE_DERIVED_HARSHNESS(ARG) ((ARG) & 16)
-#define CONST_HARSHNESS(ARG) ((ARG) & 2048)
-
 /* Ordering function for overload resolution.  Compare two candidates
    by gross quality.  */
+
 int
-rank_for_overload_ansi (x, y)
+rank_for_overload (x, y)
      struct candidate *x, *y;
 {
   if (y->h.code & (EVIL_CODE|ELLIPSIS_CODE|USER_CODE))
@@ -85,8 +65,8 @@ rank_for_overload_ansi (x, y)
 
   /* This is set by compute_conversion_costs, for calling a non-const
      member function from a const member function.  */
-  if ((y->v.ansi_harshness[0].code & CONST_CODE) ^ (x->v.ansi_harshness[0].code & CONST_CODE))
-    return y->v.ansi_harshness[0].code - x->v.ansi_harshness[0].code;
+  if ((y->harshness[0].code & CONST_CODE) ^ (x->harshness[0].code & CONST_CODE))
+    return y->harshness[0].code - x->harshness[0].code;
 
   if (y->h.code & STD_CODE)
     {
@@ -100,34 +80,8 @@ rank_for_overload_ansi (x, y)
   return y->h.code - x->h.code;
 }
 
-int
-rank_for_overload_old (x, y)
-     struct candidate *x, *y;
-{
-  if (y->evil - x->evil)
-    return y->evil - x->evil;
-  if (CONST_HARSHNESS (y->v.old_harshness[0]) ^ CONST_HARSHNESS (x->v.old_harshness[0]))
-    return y->v.old_harshness[0] - x->v.old_harshness[0];
-  if (y->ellipsis - x->ellipsis)
-    return y->ellipsis - x->ellipsis;
-  if (y->user - x->user)
-    return y->user - x->user;
-  if (y->b_or_d - x->b_or_d)
-    return y->b_or_d - x->b_or_d;
-  return y->easy - x->easy;
-}
-
-int
-rank_for_overload (x, y)
-     struct candidate *x, *y;
-{
-  if (flag_ansi_overloading)
-    return rank_for_overload_ansi (x, y);
-  else
-    return rank_for_overload_old (x, y);
-}
-
 /* Compare two candidates, argument by argument.  */
+
 int
 rank_for_ideal (x, y)
      struct candidate *x, *y;
@@ -139,17 +93,17 @@ rank_for_ideal (x, y)
 
   for (i = 0; i < x->h_len; i++)
     {
-      if (y->v.ansi_harshness[i].code - x->v.ansi_harshness[i].code)
-       return y->v.ansi_harshness[i].code - x->v.ansi_harshness[i].code;
-      if ((y->v.ansi_harshness[i].code & STD_CODE)
-         && (y->v.ansi_harshness[i].distance - x->v.ansi_harshness[i].distance))
-       return y->v.ansi_harshness[i].distance - x->v.ansi_harshness[i].distance;
+      if (y->harshness[i].code - x->harshness[i].code)
+       return y->harshness[i].code - x->harshness[i].code;
+      if ((y->harshness[i].code & STD_CODE)
+         && (y->harshness[i].distance - x->harshness[i].distance))
+       return y->harshness[i].distance - x->harshness[i].distance;
 
       /* They're both the same code.  Now see if we're dealing with an
         integral promotion that needs a finer grain of accuracy.  */
-      if (y->v.ansi_harshness[0].code & PROMO_CODE
-         && (y->v.ansi_harshness[i].int_penalty ^ x->v.ansi_harshness[i].int_penalty))
-       return y->v.ansi_harshness[i].int_penalty - x->v.ansi_harshness[i].int_penalty;
+      if (y->harshness[0].code & PROMO_CODE
+         && (y->harshness[i].int_penalty ^ x->harshness[i].int_penalty))
+       return y->harshness[i].int_penalty - x->harshness[i].int_penalty;
     }
   return 0;
 }
@@ -157,14 +111,16 @@ rank_for_ideal (x, y)
 /* TYPE is the type we wish to convert to.  PARM is the parameter
    we have to work with.  We use a somewhat arbitrary cost function
    to measure this conversion.  */
+
 static struct harshness_code
-convert_harshness_ansi (type, parmtype, parm)
+convert_harshness (type, parmtype, parm)
      register tree type, parmtype;
      tree parm;
 {
   struct harshness_code h;
   register enum tree_code codel;
   register enum tree_code coder;
+  int lvalue;
 
   h.code = 0;
   h.distance = 0;
@@ -174,6 +130,18 @@ convert_harshness_ansi (type, parmtype, parm)
   n_convert_harshness++;
 #endif
 
+  if (TREE_CODE (parmtype) == REFERENCE_TYPE)
+    {
+      if (parm)
+       parm = convert_from_reference (parm);
+      parmtype = TREE_TYPE (parmtype);
+      lvalue = 1;
+    }
+  else if (parm)
+    lvalue = lvalue_p (parm);
+  else
+    lvalue = 0;
+
   if (TYPE_PTRMEMFUNC_P (type))
     type = TYPE_PTRMEMFUNC_FN_TYPE (type);
   if (TYPE_PTRMEMFUNC_P (parmtype))
@@ -188,6 +156,60 @@ convert_harshness_ansi (type, parmtype, parm)
   if (coder == ERROR_MARK)
     return EVIL_RETURN (h);
 
+  if (codel == REFERENCE_TYPE)
+    {
+      tree ttl, ttr;
+      int constp = parm ? TREE_READONLY (parm) : TYPE_READONLY (parmtype);
+      int volatilep = (parm ? TREE_THIS_VOLATILE (parm)
+                      : TYPE_VOLATILE (parmtype));
+      register tree intype = TYPE_MAIN_VARIANT (parmtype);
+      register enum tree_code form = TREE_CODE (intype);
+      int penalty = 0;
+
+      ttl = TREE_TYPE (type);
+
+      /* Only allow const reference binding if we were given a parm to deal
+         with, since it isn't really a conversion.  This is a hack to
+         prevent build_type_conversion from finding this conversion, but
+         still allow overloading to find it.  */
+      if (! lvalue && ! (parm && TYPE_READONLY (ttl)))
+       return EVIL_RETURN (h);
+
+      if ((TYPE_READONLY (ttl) < constp)
+         || (TYPE_VOLATILE (ttl) < volatilep))
+       return EVIL_RETURN (h);
+
+      /* When passing a non-const argument into a const reference, dig it a
+        little, so a non-const reference is preferred over this one.  */
+      penalty = ((TYPE_READONLY (ttl) > constp)
+                + (TYPE_VOLATILE (ttl) > volatilep));
+
+      ttl = TYPE_MAIN_VARIANT (ttl);
+
+      if (form == OFFSET_TYPE)
+       {
+         intype = TREE_TYPE (intype);
+         form = TREE_CODE (intype);
+       }
+
+      ttr = intype;
+
+      if (TREE_CODE (ttl) == ARRAY_TYPE && TREE_CODE (ttr) == ARRAY_TYPE)
+       {
+         if (comptypes (ttl, ttr, 1))
+           return ZERO_RETURN (h);
+         return EVIL_RETURN (h);
+       }
+
+      h = convert_harshness (ttl, ttr, NULL_TREE);
+      if (penalty && h.code == 0)
+       {
+         h.code = QUAL_CODE;
+         h.int_penalty = penalty;
+       }
+      return h;
+    }
+
   if (codel == POINTER_TYPE && fntype_p (parmtype))
     {
       tree p1, p2;
@@ -205,15 +227,41 @@ convert_harshness_ansi (type, parmtype, parm)
       if (coder != TREE_CODE (type))
        return EVIL_RETURN (h);
 
+      if (type != parmtype && coder == METHOD_TYPE)
+       {
+         tree ttl = TYPE_METHOD_BASETYPE (type);
+         tree ttr = TYPE_METHOD_BASETYPE (parmtype);
+
+         int b_or_d = get_base_distance (ttr, ttl, 0, (tree*)0);
+         if (b_or_d < 0)
+           {
+             b_or_d = get_base_distance (ttl, ttr, 0, (tree*)0);
+             if (b_or_d < 0)
+               return EVIL_RETURN (h);
+             h.distance = -b_or_d;
+           }
+         else
+           h.distance = b_or_d;
+         h.code = STD_CODE;
+
+         type = build_function_type
+           (TREE_TYPE (type), TREE_CHAIN (TYPE_ARG_TYPES (type)));
+         parmtype = build_function_type
+           (TREE_TYPE (parmtype), TREE_CHAIN (TYPE_ARG_TYPES (parmtype)));
+       }
+
       /* We allow the default conversion between function type
         and pointer-to-function type for free.  */
-      if (type == parmtype)
-       return ZERO_RETURN (h);
+      if (comptypes (type, parmtype, 1))
+       return h;
+
+      if (pedantic)
+       return EVIL_RETURN (h);
 
       /* Compare return types.  */
       p1 = TREE_TYPE (type);
       p2 = TREE_TYPE (parmtype);
-      h2 = convert_harshness_ansi (p1, p2, NULL_TREE);
+      h2 = convert_harshness (p1, p2, NULL_TREE);
       if (h2.code & EVIL_CODE)
        return h2;
 
@@ -241,14 +289,16 @@ convert_harshness_ansi (type, parmtype, parm)
 
          if (! BINFO_OFFSET_ZEROP (binfo))
            {
+#if 0
              static int explained = 0;
              if (h2.distance < 0)
-               message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p2, p1);
+               message_2_types (sorry, "cannot cast `%s' to `%s' at function call site", p2, p1);
              else
-               message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p1, p2);
+               message_2_types (sorry, "cannot cast `%s' to `%s' at function call site", p1, p2);
 
              if (! explained++)
                sorry ("(because pointer values change during conversion)");
+#endif
              return EVIL_RETURN (h);
            }
        }
@@ -262,14 +312,14 @@ convert_harshness_ansi (type, parmtype, parm)
       while (p1 && TREE_VALUE (p1) != void_type_node
             && p2 && TREE_VALUE (p2) != void_type_node)
        {
-         h2 = convert_harshness_ansi (TREE_VALUE (p1), TREE_VALUE (p2),
+         h2 = convert_harshness (TREE_VALUE (p1), TREE_VALUE (p2),
                                       NULL_TREE);
          if (h2.code & EVIL_CODE)
            return h2;
 
          if (h2.distance)
            {
-             /* This only works for pointers and references. */
+             /* This only works for pointers and references.  */
              if (TREE_CODE (TREE_VALUE (p1)) != POINTER_TYPE
                  && TREE_CODE (TREE_VALUE (p1)) != REFERENCE_TYPE)
                return EVIL_RETURN (h);
@@ -300,28 +350,34 @@ convert_harshness_ansi (type, parmtype, parm)
     }
   else if (codel == POINTER_TYPE && coder == OFFSET_TYPE)
     {
+      tree ttl, ttr;
+
       /* Get to the OFFSET_TYPE that this might be.  */
       type = TREE_TYPE (type);
 
       if (coder != TREE_CODE (type))
        return EVIL_RETURN (h);
 
-      if (TYPE_OFFSET_BASETYPE (type) == TYPE_OFFSET_BASETYPE (parmtype))
+      ttl = TYPE_OFFSET_BASETYPE (type);
+      ttr = TYPE_OFFSET_BASETYPE (parmtype);
+
+      if (ttl == ttr)
        h.code = 0;
-      else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (type),
-                              TYPE_OFFSET_BASETYPE (parmtype)))
-       {
-         h.code = STD_CODE;
-         h.distance = 1;
-       }
-      else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (parmtype),
-                              TYPE_OFFSET_BASETYPE (type)))
+      else
        {
+         int b_or_d = get_base_distance (ttr, ttl, 0, (tree*)0);
+         if (b_or_d < 0)
+           {
+             b_or_d = get_base_distance (ttl, ttr, 0, (tree*)0);
+             if (b_or_d < 0)
+               return EVIL_RETURN (h);
+             h.distance = -b_or_d;
+           }
+         else
+           h.distance = b_or_d;
          h.code = STD_CODE;
-         h.distance = -1;
        }
-      else
-       return EVIL_RETURN (h);
+
       /* Now test the OFFSET_TYPE's target compatibility.  */
       type = TREE_TYPE (type);
       parmtype = TREE_TYPE (parmtype);
@@ -341,7 +397,22 @@ convert_harshness_ansi (type, parmtype, parm)
   if (coder == VOID_TYPE)
     return EVIL_RETURN (h);
 
-  if (codel == ENUMERAL_TYPE || codel == INTEGER_TYPE)
+  if (codel == BOOLEAN_TYPE)
+    {
+      if (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE)
+       return STD_RETURN (h);
+      else if (coder == POINTER_TYPE || coder == OFFSET_TYPE)
+       {
+         /* Make this worse than any conversion to another pointer.
+            FIXME this is how I think the language should work, but it may not
+            end up being how the language is standardized (jason 1/30/95).  */
+         h.distance = 32767;
+         return STD_RETURN (h);
+       }
+      return EVIL_RETURN (h);
+    }
+
+  if (INTEGRAL_CODE_P (codel))
     {
       /* Control equivalence of ints an enums.  */
 
@@ -356,47 +427,15 @@ convert_harshness_ansi (type, parmtype, parm)
 
       /* else enums and ints (almost) freely interconvert.  */
 
-      if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE)
+      if (INTEGRAL_CODE_P (coder))
        {
-         if ((TREE_UNSIGNED (type) ^ TREE_UNSIGNED (parmtype))
-             || codel != coder
-             || TYPE_MODE (type) != TYPE_MODE (parmtype))
-           {
-             /* Make sure a value-preserving condition [from a smaller type to
-                a larger type] is preferred to a possibly value-destroying
-                standard conversion [from a larger type to a smaller type].  */
-             if (TYPE_PRECISION (type) >= TYPE_PRECISION (parmtype))
-               {
-                 h.code = PROMO_CODE;
-                 /* A char, short, wchar_t, etc., should promote to an int if
-                    it can handle it, otherwise to an unsigned.  So we'll make
-                    an unsigned.  */
-                 if (type != integer_type_node)
-                   h.int_penalty = 1;
-               }
-             else
-               h.code = STD_CODE;
-           }
-
-         /* If the three above conditions didn't trigger, we have found two
-            very similar types.  On systems where they're the same size, we
-            can end up here with TYPE as `long' and PARMTYPE as `int'.  Make
-            sure we realize that, even though they're the same mode, we will
-            have to do some sort of integral promotion on the type, since
-            they're not the same.  */
-         if (! comptypes (type, parmtype, 1) && h.code == 0)
+         if (TYPE_MAIN_VARIANT (type)
+             == TYPE_MAIN_VARIANT (type_promotes_to (parmtype)))
            {
-             /* This call to common_type will return the best type for the
-                combination.  If it matches TYPE, that means we'll be converting
-                from a so-called smaller type (in PARMTYPE) to the larger in TYPE,
-                thus an integral promotion.  Otherwise, it must be going from a
-                larger type in PARMTYPE to a smaller expected type in TYPE, so we
-                make it a standard conversion instead.  */
-             if (common_type (type, parmtype) == type)
-               h.code = PROMO_CODE;
-             else
-               h.code = STD_CODE;
+             h.code = PROMO_CODE;
            }
+         else
+           h.code = STD_CODE;
            
          return h;
        }
@@ -412,12 +451,15 @@ convert_harshness_ansi (type, parmtype, parm)
     {
       if (coder == REAL_TYPE)
        {
-         /* Shun converting among float, double, and long double if a
-            choice exists.  */
-         h.code = PROMO_CODE;
+         if (TYPE_MAIN_VARIANT (type)
+             == TYPE_MAIN_VARIANT (type_promotes_to (parmtype)))
+           h.code = PROMO_CODE;
+         else
+           h.code = STD_CODE;
+           
          return h;
        }
-      else if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE)
+      else if (INTEGRAL_CODE_P (coder))
        {
          h.code = STD_CODE;
          h.distance = 0;
@@ -426,10 +468,17 @@ convert_harshness_ansi (type, parmtype, parm)
     }
 
   /* Convert arrays which have not previously been converted.  */
-  if (codel == ARRAY_TYPE)
-    codel = POINTER_TYPE;
   if (coder == ARRAY_TYPE)
-    coder = POINTER_TYPE;
+    {
+      coder = POINTER_TYPE;
+      if (parm)
+       {
+         parm = decay_conversion (parm);
+         parmtype = TREE_TYPE (parm);
+       }
+      else
+       parmtype = build_pointer_type (TREE_TYPE (parmtype));
+    }
 
   /* Conversions among pointers */
   if (codel == POINTER_TYPE && coder == POINTER_TYPE)
@@ -438,11 +487,10 @@ convert_harshness_ansi (type, parmtype, parm)
       register tree ttr = TYPE_MAIN_VARIANT (TREE_TYPE (parmtype));
       int penalty = 4 * (ttl != ttr);
 
-      /* Anything converts to void *.  void * converts to anything.
-        Since these may be `const void *' (etc.) use VOID_TYPE
-        instead of void_type_node.  Otherwise, the targets must be the same,
-        except that we do allow (at some cost) conversion between signed and
-        unsigned pointer types.  */
+      /* Anything converts to void *.  Since this may be `const void *'
+        (etc.) use VOID_TYPE instead of void_type_node.  Otherwise, the
+        targets must be the same, except that we do allow (at some cost)
+        conversion between signed and unsigned pointer types.  */
 
       if ((TREE_CODE (ttl) == METHOD_TYPE
           || TREE_CODE (ttl) == FUNCTION_TYPE)
@@ -459,15 +507,10 @@ convert_harshness_ansi (type, parmtype, parm)
        }
 
 #if 1
-      if (TREE_CODE (ttl) != VOID_TYPE && TREE_CODE (ttr) != VOID_TYPE)
+      if (TREE_CODE (ttl) != VOID_TYPE
+         && (TREE_CODE (ttr) != VOID_TYPE || !parm || !null_ptr_cst_p (parm)))
        {
-         if (TREE_UNSIGNED (ttl) != TREE_UNSIGNED (ttr))
-           {
-             ttl = unsigned_type (ttl);
-             ttr = unsigned_type (ttr);
-             penalty = 10;
-           }
-         if (! comp_target_types (ttl, ttr, 0))
+         if (comp_target_types (type, parmtype, 1) <= 0)
            return EVIL_RETURN (h);
        }
 #else
@@ -477,26 +520,22 @@ convert_harshness_ansi (type, parmtype, parm)
                && (ttl = unsigned_type (ttl),
                    ttr = unsigned_type (ttr),
                    penalty = 10, 0))
-           || (comp_target_types (ttl, ttr, 0))))
+           || (comp_target_types (ttl, ttr, 0) > 0)))
        return EVIL_RETURN (h);
 #endif
 
-      if (penalty == 10 || ttr == ttl)
+      if (ttr == ttl)
        {
          tree tmp1 = TREE_TYPE (type), tmp2 = TREE_TYPE (parmtype);
 
-         /* If one was unsigned but the other wasn't, then we need to
-            do a standard conversion from T to unsigned T.  */
-         if (penalty == 10)
-           h.code = PROMO_CODE; /* was STD_CODE */
-         else
-           h.code = 0;
-
+         h.code = 0;
          /* Note conversion from `T*' to `const T*',
                               or `T*' to `volatile T*'.  */
-         if (ttl == ttr
-             && ((TYPE_READONLY (tmp1) != TREE_READONLY (tmp2))
-                 || (TYPE_VOLATILE (tmp1) != TYPE_VOLATILE (tmp2))))
+         if ((TYPE_READONLY (tmp1) < TREE_READONLY (tmp2))
+             || (TYPE_VOLATILE (tmp1) < TYPE_VOLATILE (tmp2)))
+           h.code = EVIL_CODE;
+         else if ((TYPE_READONLY (tmp1) != TREE_READONLY (tmp2))
+                  || (TYPE_VOLATILE (tmp1) != TYPE_VOLATILE (tmp2)))
            h.code |= QUAL_CODE;
 
          h.distance = 0;
@@ -506,10 +545,10 @@ convert_harshness_ansi (type, parmtype, parm)
 
       if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
        {
-         int b_or_d = get_base_distance (ttl, ttr, 0, 0);
+         int b_or_d = get_base_distance (ttl, ttr, 0, (tree*)0);
          if (b_or_d < 0)
            {
-             b_or_d = get_base_distance (ttr, ttl, 0, 0);
+             b_or_d = get_base_distance (ttr, ttl, 0, (tree*)0);
              if (b_or_d < 0)
                return EVIL_RETURN (h);
              h.distance = -b_or_d;
@@ -528,7 +567,20 @@ convert_harshness_ansi (type, parmtype, parm)
          h.distance = CLASSTYPE_MAX_DEPTH (ttr)+1;
          return h;
        }
+
       h.code = penalty ? STD_CODE : PROMO_CODE;
+      /* Catch things like `const char *' -> `const void *'
+        vs `const char *' -> `void *'.  */
+      if (ttl != ttr)
+       {
+         tree tmp1 = TREE_TYPE (type), tmp2 = TREE_TYPE (parmtype);
+         if ((TYPE_READONLY (tmp1) < TREE_READONLY (tmp2))
+             || (TYPE_VOLATILE (tmp1) < TYPE_VOLATILE (tmp2)))
+           h.code = EVIL_CODE;
+         else if ((TYPE_READONLY (tmp1) > TREE_READONLY (tmp2))
+                  || (TYPE_VOLATILE (tmp1) > TYPE_VOLATILE (tmp2)))
+           h.code |= QUAL_CODE;
+       }
       return h;
     }
 
@@ -544,201 +596,22 @@ convert_harshness_ansi (type, parmtype, parm)
        }
     }
 
-  /* C++: one of the types must be a reference type.  */
-  {
-    tree ttl, ttr;
-    register tree intype = TYPE_MAIN_VARIANT (parmtype);
-    register enum tree_code form = TREE_CODE (intype);
-    int penalty;
-
-    if (codel == REFERENCE_TYPE || coder == REFERENCE_TYPE)
-      {
-       ttl = TYPE_MAIN_VARIANT (type);
-
-       if (codel == REFERENCE_TYPE)
-         {
-           ttl = TREE_TYPE (ttl);
-
-           /* When passing a non-const argument into a const reference,
-              dig it a little, so a non-const reference is preferred over
-              this one. (mrs) */
-           if (parm && TREE_READONLY (ttl) && ! TREE_READONLY (parm))
-             penalty = 2;
-           else
-             penalty = 0;
-
-           ttl = TYPE_MAIN_VARIANT (ttl);
-
-           if (form == OFFSET_TYPE)
-             {
-               intype = TREE_TYPE (intype);
-               form = TREE_CODE (intype);
-             }
-
-           if (form == REFERENCE_TYPE)
-             {
-               intype = TYPE_MAIN_VARIANT (TREE_TYPE (intype));
-
-               if (ttl == intype)
-                 return ZERO_RETURN (h);
-               penalty = 2;
-             }
-           else
-             {
-               /* Can reference be built up?  */
-               if (ttl == intype && penalty == 0) {
-                 /* Because the READONLY and VIRTUAL bits are not always in
-                    the type, this extra check is necessary.  The problem
-                    should be fixed someplace else, and this extra code
-                    removed.
-
-                    Also, if type if a reference, the readonly bits could
-                    either be in the outer type (with reference) or on the
-                    inner type (the thing being referenced).  (mrs)  */
-                 if (parm
-                     && ((TREE_READONLY (parm)
-                          && ! (TYPE_READONLY (type)
-                                || (TREE_CODE (type) == REFERENCE_TYPE
-                                    && TYPE_READONLY (TREE_TYPE (type)))))
-                         || (TREE_SIDE_EFFECTS (parm)
-                             && ! (TYPE_VOLATILE (type)
-                                   || (TREE_CODE (type) == REFERENCE_TYPE
-                                       && TYPE_VOLATILE (TREE_TYPE (type)))))))
-                   penalty = 2;
-                 else
-                   return ZERO_RETURN (h);
-               }
-               else
-                 penalty = 2;
-             }
-         }
-       else if (form == REFERENCE_TYPE)
-         {
-           if (parm)
-             {
-               tree tmp = convert_from_reference (parm);
-               intype = TYPE_MAIN_VARIANT (TREE_TYPE (tmp));
-             }
-           else
-             {
-               intype = parmtype;
-               do
-                 intype = TREE_TYPE (intype);
-               while (TREE_CODE (intype) == REFERENCE_TYPE);
-               intype = TYPE_MAIN_VARIANT (intype);
-             }
-
-           if (ttl == intype)
-             return ZERO_RETURN (h);
-           else
-             penalty = 2;
-         }
-
-       if (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (intype))
-         {
-           ttl = unsigned_type (ttl);
-           intype = unsigned_type (intype);
-           penalty += 2;
-         }
-
-       ttr = intype;
-
-       /* If the initializer is not an lvalue, then it does not
-          matter if we make life easier for the programmer
-          by creating a temporary variable with which to
-          hold the result.  */
-       if (parm && (coder == INTEGER_TYPE
-                    || coder == ENUMERAL_TYPE
-                    || coder == REAL_TYPE)
-           && ! lvalue_p (parm))
-         {
-           h = convert_harshness_ansi (ttl, ttr, NULL_TREE);
-           if (penalty > 2 || h.code != 0)
-             h.code |= STD_CODE;
-           else
-             h.code |= TRIVIAL_CODE;
-           h.distance = 0;
-           return h;
-         }
-
-       if (ttl == ttr)
-         {
-           if (penalty > 2)
-             {
-               h.code = STD_CODE;
-               h.distance = 0;
-             }
-           else
-             {
-               h.code = TRIVIAL_CODE;
-               /* We set this here so that build_overload_call_real will be
-                  able to see the penalty we found, rather than just looking
-                  at a TRIVIAL_CODE with no other information.  */
-               h.int_penalty = penalty;
-             }
-           return h;
-         }
-
-       /* Pointers to voids always convert for pointers.  But
-          make them less natural than more specific matches.  */
-       if (TREE_CODE (ttl) == POINTER_TYPE && TREE_CODE (ttr) == POINTER_TYPE)
-         {
-           if (TREE_TYPE (ttl) == void_type_node
-               || TREE_TYPE (ttr) == void_type_node)
-             {
-               h.code = STD_CODE;
-               h.distance = 0;
-               return h;
-             }
-         }
-
-       if (parm && codel != REFERENCE_TYPE)
-         {
-           h = convert_harshness_ansi (ttl, ttr, NULL_TREE);
-           if (penalty)
-             h.code |= STD_CODE;
-           h.distance = 0;
-           return h;
-         }
+  /* C++: Since the `this' parameter of a signature member function
+     is represented as a signature pointer to handle default implementations
+     correctly, we can have the case that `type' is a signature pointer
+     while `parmtype' is a pointer to a signature table.  We don't really
+     do any conversions in this case, so just return 0.  */
 
-       /* Here it does matter.  If this conversion is from derived to base,
-          allow it.  Otherwise, types must be compatible in the strong sense.  */
-       if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
-         {
-           int b_or_d = get_base_distance (ttl, ttr, 0, 0);
-           if (b_or_d < 0)
-             {
-               b_or_d = get_base_distance (ttr, ttl, 0, 0);
-               if (b_or_d < 0)
-                 return EVIL_RETURN (h);
-               h.distance = -b_or_d;
-             }
-           /* Say that this conversion is relatively painless.
-              If it turns out that there is a user-defined X(X&)
-              constructor, then that will be invoked, but that's
-              preferable to dealing with other user-defined conversions
-              that may produce surprising results.  */
-           else
-             h.distance = b_or_d;
-           h.code = STD_CODE;
-           return h;
-         }
+  if (codel == RECORD_TYPE && coder == POINTER_TYPE
+      && IS_SIGNATURE_POINTER (type) && IS_SIGNATURE (TREE_TYPE (parmtype)))
+    return ZERO_RETURN (h);
 
-       if (comp_target_types (ttl, intype, 1))
-         {
-           if (penalty)
-             h.code = STD_CODE;
-           h.distance = 0;
-           return h;
-         }
-      }
-  }
   if (codel == RECORD_TYPE && coder == RECORD_TYPE)
     {
-      int b_or_d = get_base_distance (type, parmtype, 0, 0);
+      int b_or_d = get_base_distance (type, parmtype, 0, (tree*)0);
       if (b_or_d < 0)
        {
-         b_or_d = get_base_distance (parmtype, type, 0, 0);
+         b_or_d = get_base_distance (parmtype, type, 0, (tree*)0);
          if (b_or_d < 0)
            return EVIL_RETURN (h);
          h.distance = -b_or_d;
@@ -751,500 +624,82 @@ convert_harshness_ansi (type, parmtype, parm)
   return EVIL_RETURN (h);
 }
 
-/* TYPE is the type we wish to convert to.  PARM is the parameter
-   we have to work with.  We use a somewhat arbitrary cost function
-   to measure this conversion.  */
-static int
-convert_harshness_old (type, parmtype, parm)
+/* A clone of build_type_conversion for checking user-defined conversions in
+   overload resolution.  */
+
+int
+user_harshness (type, parmtype)
      register tree type, parmtype;
-     tree parm;
 {
-  register enum tree_code codel;
-  register enum tree_code coder;
-
-#ifdef GATHER_STATISTICS
-  n_convert_harshness++;
-#endif
-
-  if (TYPE_PTRMEMFUNC_P (type))
-    type = TYPE_PTRMEMFUNC_FN_TYPE (type);
-  if (TYPE_PTRMEMFUNC_P (parmtype))
-    parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype);
-
-  codel = TREE_CODE (type);
-  coder = TREE_CODE (parmtype);
-
-  if (TYPE_MAIN_VARIANT (parmtype) == TYPE_MAIN_VARIANT (type))
-    return TRIVIAL;
-
-  if (coder == ERROR_MARK)
-    return EVIL;
+  tree conv;
+  tree winner = NULL_TREE;
+  int code;
 
-  if (codel == POINTER_TYPE && fntype_p (parmtype))
+  {
+    tree typename = build_typename_overload (type);
+    if (lookup_fnfields (TYPE_BINFO (parmtype), typename, 0))
+      return 0;
+  }
+                       
+  for (conv = lookup_conversions (parmtype); conv; conv = TREE_CHAIN (conv))
     {
-      tree p1, p2;
-      int harshness, new_harshness;
+      struct harshness_code tmp;
+      tree cand = TREE_VALUE (conv);
 
-      /* Get to the METHOD_TYPE or FUNCTION_TYPE that this might be.  */
-      type = TREE_TYPE (type);
+      if (winner && winner == cand)
+       continue;
 
-      if (coder == POINTER_TYPE)
+      tmp = convert_harshness (type, TREE_TYPE (TREE_TYPE (cand)), NULL_TREE);
+      if ((tmp.code < USER_CODE) && (tmp.distance >= 0))
        {
-         parmtype = TREE_TYPE (parmtype);
-         coder = TREE_CODE (parmtype);
+         if (winner)
+           return EVIL_CODE;
+         else
+           {
+             winner = cand;
+             code = tmp.code;
+           }
        }
+    }
 
-      if (coder != TREE_CODE (type))
-       return EVIL;
-
-      harshness = 0;
+  if (winner)
+    return code;
 
-      /* We allow the default conversion between function type
-        and pointer-to-function type for free.  */
-      if (type == parmtype)
-       return TRIVIAL;
+  return -1;
+}
 
-      /* Compare return types.  */
-      p1 = TREE_TYPE (type);
-      p2 = TREE_TYPE (parmtype);
-      new_harshness = convert_harshness_old (p1, p2, NULL_TREE);
-      if (EVIL_HARSHNESS (new_harshness))
-       return EVIL;
+#ifdef DEBUG_MATCHING
+static char *
+print_harshness (h)
+     struct harshness_code *h;
+{
+  static char buf[1024];
+  char tmp[1024];
 
-      if (BASE_DERIVED_HARSHNESS (new_harshness))
-       {
-         tree binfo;
+  bzero (buf, 1024 * sizeof (char));
+  strcat (buf, "codes=[");
+  if (h->code & EVIL_CODE)
+    strcat (buf, "EVIL");
+  if (h->code & CONST_CODE)
+    strcat (buf, " CONST");
+  if (h->code & ELLIPSIS_CODE)
+    strcat (buf, " ELLIPSIS");
+  if (h->code & USER_CODE)
+    strcat (buf, " USER");
+  if (h->code & STD_CODE)
+    strcat (buf, " STD");
+  if (h->code & PROMO_CODE)
+    strcat (buf, " PROMO");
+  if (h->code & QUAL_CODE)
+    strcat (buf, " QUAL");
+  if (h->code & TRIVIAL_CODE)
+    strcat (buf, " TRIVIAL");
+  if (buf[0] == '\0')
+    strcat (buf, "0");
 
-         /* This only works for pointers.  */
-         if (TREE_CODE (p1) != POINTER_TYPE
-             && TREE_CODE (p1) != REFERENCE_TYPE)
-           return EVIL;
+  sprintf (tmp, "] distance=%d int_penalty=%d", h->distance, h->int_penalty);
 
-         p1 = TREE_TYPE (p1);
-         p2 = TREE_TYPE (p2);
-         /* Don't die if we happen to be dealing with void*.  */
-         if (!IS_AGGR_TYPE (p1) || !IS_AGGR_TYPE (p2))
-           return EVIL;
-         if (CONTRAVARIANT_HARSHNESS (new_harshness))
-           binfo = get_binfo (p2, p1, 0);
-         else
-           binfo = get_binfo (p1, p2, 0);
-
-         if (! BINFO_OFFSET_ZEROP (binfo))
-           {
-             static int explained = 0;
-             if (CONTRAVARIANT_HARSHNESS (new_harshness))
-               message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p2, p1);
-             else
-               message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p1, p2);
-
-             if (! explained++)
-               sorry ("(because pointer values change during conversion)");
-             return EVIL;
-           }
-       }
-
-      harshness |= new_harshness;
-
-      p1 = TYPE_ARG_TYPES (type);
-      p2 = TYPE_ARG_TYPES (parmtype);
-      while (p1 && TREE_VALUE (p1) != void_type_node
-            && p2 && TREE_VALUE (p2) != void_type_node)
-       {
-         new_harshness = convert_harshness_old (TREE_VALUE (p1),
-                                                TREE_VALUE (p2), NULL_TREE);
-         if (EVIL_HARSHNESS (new_harshness))
-           return EVIL;
-
-         if (BASE_DERIVED_HARSHNESS (new_harshness))
-           {
-             /* This only works for pointers and references. */
-             if (TREE_CODE (TREE_VALUE (p1)) != POINTER_TYPE
-                 && TREE_CODE (TREE_VALUE (p1)) != REFERENCE_TYPE)
-               return EVIL;
-             new_harshness ^= CONTRAVARIANT_HARSHNESS (new_harshness);
-             harshness |= new_harshness;
-           }
-         /* This trick allows use to accumulate easy type
-            conversions without messing up the bits that encode
-            info about more involved things.  */
-         else if (ONLY_EASY_HARSHNESS (new_harshness))
-           harshness += new_harshness;
-         else
-           harshness |= new_harshness;
-         p1 = TREE_CHAIN (p1);
-         p2 = TREE_CHAIN (p2);
-       }
-      if (p1 == p2)
-       return harshness;
-      if (p2)
-       return p1 ? EVIL : (harshness | ELLIPSIS_HARSHNESS (-1));
-      if (p1)
-       return harshness | (TREE_PURPOSE (p1) == NULL_TREE);
-    }
-  else if (codel == POINTER_TYPE && coder == OFFSET_TYPE)
-    {
-      /* XXX: Note this is set a few times, but it's never actually
-        used! (bpk) */
-      int harshness;
-
-      /* Get to the OFFSET_TYPE that this might be.  */
-      type = TREE_TYPE (type);
-
-      if (coder != TREE_CODE (type))
-       return EVIL;
-
-      harshness = 0;
-
-      if (TYPE_OFFSET_BASETYPE (type) == TYPE_OFFSET_BASETYPE (parmtype))
-       harshness = 0;
-      else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (type),
-                              TYPE_OFFSET_BASETYPE (parmtype)))
-       harshness = INT_TO_BD_HARSHNESS (1);
-      else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (parmtype),
-                              TYPE_OFFSET_BASETYPE (type)))
-       harshness = CONTRAVARIANT_HARSHNESS (-1);
-      else
-       return EVIL;
-      /* Now test the OFFSET_TYPE's target compatibility.  */
-      type = TREE_TYPE (type);
-      parmtype = TREE_TYPE (parmtype);
-    }
-
-  if (coder == UNKNOWN_TYPE)
-    {
-      if (codel == FUNCTION_TYPE
-         || codel == METHOD_TYPE
-         || (codel == POINTER_TYPE
-             && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
-                 || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)))
-       return TRIVIAL;
-      return EVIL;
-    }
-
-  if (coder == VOID_TYPE)
-    return EVIL;
-
-  if (codel == ENUMERAL_TYPE || codel == INTEGER_TYPE)
-    {
-      /* Control equivalence of ints an enums.  */
-
-      if (codel == ENUMERAL_TYPE
-         && flag_int_enum_equivalence == 0)
-       {
-         /* Enums can be converted to ints, but not vice-versa.  */
-         if (coder != ENUMERAL_TYPE
-             || TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (parmtype))
-           return EVIL;
-       }
-
-      /* else enums and ints (almost) freely interconvert.  */
-
-      if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE)
-       {
-         int easy = TREE_UNSIGNED (type) ^ TREE_UNSIGNED (parmtype);
-         if (codel != coder)
-           easy += 1;
-         if (TYPE_MODE (type) != TYPE_MODE (parmtype))
-           easy += 2;
-         return INT_TO_EASY_HARSHNESS (easy);
-       }
-      else if (coder == REAL_TYPE)
-       return INT_TO_EASY_HARSHNESS (4);
-    }
-
-  if (codel == REAL_TYPE)
-    if (coder == REAL_TYPE)
-      /* Shun converting between float and double if a choice exists.  */
-      {
-       if (TYPE_MODE (type) != TYPE_MODE (parmtype))
-         return INT_TO_EASY_HARSHNESS (2);
-       return TRIVIAL;
-      }
-    else if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE)
-      return INT_TO_EASY_HARSHNESS (4);
-
-  /* convert arrays which have not previously been converted.  */
-  if (codel == ARRAY_TYPE)
-    codel = POINTER_TYPE;
-  if (coder == ARRAY_TYPE)
-    coder = POINTER_TYPE;
-
-  /* Conversions among pointers */
-  if (codel == POINTER_TYPE && coder == POINTER_TYPE)
-    {
-      register tree ttl = TYPE_MAIN_VARIANT (TREE_TYPE (type));
-      register tree ttr = TYPE_MAIN_VARIANT (TREE_TYPE (parmtype));
-      int penalty = 4 * (ttl != ttr);
-      /* Anything converts to void *.  void * converts to anything.
-        Since these may be `const void *' (etc.) use VOID_TYPE
-        instead of void_type_node.
-        Otherwise, the targets must be the same,
-        except that we do allow (at some cost) conversion
-        between signed and unsinged pointer types.  */
-
-      if ((TREE_CODE (ttl) == METHOD_TYPE
-          || TREE_CODE (ttl) == FUNCTION_TYPE)
-         && TREE_CODE (ttl) == TREE_CODE (ttr))
-       {
-         if (comptypes (ttl, ttr, -1))
-           return INT_TO_EASY_HARSHNESS (penalty);
-         return EVIL;
-       }
-
-      if (!(TREE_CODE (ttl) == VOID_TYPE
-           || TREE_CODE (ttr) == VOID_TYPE
-           || (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (ttr)
-               && (ttl = unsigned_type (ttl),
-                   ttr = unsigned_type (ttr),
-                   penalty = 10, 0))
-           || (comp_target_types (ttl, ttr, 0))))
-       return EVIL;
-
-      if (penalty == 10)
-       return INT_TO_EASY_HARSHNESS (10);
-      if (ttr == ttl)
-       return INT_TO_BD_HARSHNESS (0);
-
-      if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
-       {
-         int b_or_d = get_base_distance (ttl, ttr, 0, 0);
-         if (b_or_d < 0)
-           {
-             b_or_d = get_base_distance (ttr, ttl, 0, 0);
-             if (b_or_d < 0)
-               return EVIL;
-             return CONTRAVARIANT_HARSHNESS (-1);
-           }
-         return INT_TO_BD_HARSHNESS (b_or_d);
-       }
-      /* If converting from a `class*' to a `void*', make it
-        less favorable than any inheritance relationship.  */
-      if (TREE_CODE (ttl) == VOID_TYPE && IS_AGGR_TYPE (ttr))
-       return INT_TO_BD_HARSHNESS (CLASSTYPE_MAX_DEPTH (ttr)+1);
-      return INT_TO_EASY_HARSHNESS (penalty);
-    }
-
-  if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
-    {
-      /* This is not a bad match, but don't let it beat
-        integer-enum combinations.  */
-      if (parm && integer_zerop (parm))
-       return INT_TO_EASY_HARSHNESS (4);
-    }
-
-  /* C++: Since the `this' parameter of a signature member function
-     is represented as a signature pointer to handle default implementations
-     correctly, we can have the case that `type' is a signature pointer
-     while `parmtype' is a pointer to a signature table.  We don't really
-     do any conversions in this case, so just return 0.  */
-
-  if (codel == RECORD_TYPE && coder == POINTER_TYPE
-      && IS_SIGNATURE_POINTER (type) && IS_SIGNATURE (TREE_TYPE (parmtype)))
-    return 0;
-
-  /* C++: one of the types must be a reference type.  */
-  {
-    tree ttl, ttr;
-    register tree intype = TYPE_MAIN_VARIANT (parmtype);
-    register enum tree_code form = TREE_CODE (intype);
-    int penalty;
-
-    if (codel == REFERENCE_TYPE || coder == REFERENCE_TYPE)
-      {
-       ttl = TYPE_MAIN_VARIANT (type);
-
-       if (codel == REFERENCE_TYPE)
-         {
-           ttl = TREE_TYPE (ttl);
-
-           /* When passing a non-const argument into a const reference,
-              dig it a little, so a non-const reference is preferred over
-              this one. (mrs) */
-           if (parm && TREE_READONLY (ttl) && ! TREE_READONLY (parm))
-             penalty = 2;
-           else
-             penalty = 0;
-
-           ttl = TYPE_MAIN_VARIANT (ttl);
-
-           if (form == OFFSET_TYPE)
-             {
-               intype = TREE_TYPE (intype);
-               form = TREE_CODE (intype);
-             }
-
-           if (form == REFERENCE_TYPE)
-             {
-               intype = TYPE_MAIN_VARIANT (TREE_TYPE (intype));
-
-               if (ttl == intype)
-                 return TRIVIAL;
-               penalty = 2;
-             }
-           else
-             {
-               /* Can reference be built up?  */
-               if (ttl == intype && penalty == 0) {
-                 /* Because the READONLY bits and VIRTUAL bits are not always
-                    in the type, this extra check is necessary.  The problem
-                    should be fixed someplace else, and this extra code
-                    removed.
-
-                    Also, if type if a reference, the readonly bits could
-                    either be in the outer type (with reference) or on the
-                    inner type (the thing being referenced).  (mrs)  */
-                 if (parm
-                     && ((TREE_READONLY (parm)
-                          && ! (TYPE_READONLY (type)
-                                || (TREE_CODE (type) == REFERENCE_TYPE
-                                    && TYPE_READONLY (TREE_TYPE (type)))))
-                         || (TREE_SIDE_EFFECTS (parm)
-                             && ! (TYPE_VOLATILE (type)
-                                   || (TREE_CODE (type) == REFERENCE_TYPE
-                                       && TYPE_VOLATILE (TREE_TYPE (type)))))))
-                   penalty = 2;
-                 else
-                   return TRIVIAL;
-               }
-               else
-                 penalty = 2;
-             }
-         }
-       else if (form == REFERENCE_TYPE)
-         {
-           if (parm)
-             {
-               tree tmp = convert_from_reference (parm);
-               intype = TYPE_MAIN_VARIANT (TREE_TYPE (tmp));
-             }
-           else
-             {
-               intype = parmtype;
-               do
-                 {
-                   intype = TREE_TYPE (intype);
-                 }
-               while (TREE_CODE (intype) == REFERENCE_TYPE);
-               intype = TYPE_MAIN_VARIANT (intype);
-             }
-
-           if (ttl == intype)
-             return TRIVIAL;
-           else
-             penalty = 2;
-         }
-
-       if (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (intype))
-         {
-           ttl = unsigned_type (ttl);
-           intype = unsigned_type (intype);
-           penalty += 2;
-         }
-
-       ttr = intype;
-
-       /* If the initializer is not an lvalue, then it does not
-          matter if we make life easier for the programmer
-          by creating a temporary variable with which to
-          hold the result.  */
-       if (parm && (coder == INTEGER_TYPE
-                    || coder == ENUMERAL_TYPE
-                    || coder == REAL_TYPE)
-           && ! lvalue_p (parm))
-         return (convert_harshness_old (ttl, ttr, NULL_TREE)
-                 | INT_TO_EASY_HARSHNESS (penalty));
-
-       if (ttl == ttr)
-         {
-           if (penalty)
-             return INT_TO_EASY_HARSHNESS (penalty);
-           return INT_TO_BD_HARSHNESS (0);
-         }
-
-       /* Pointers to voids always convert for pointers.  But
-          make them less natural than more specific matches.  */
-       if (TREE_CODE (ttl) == POINTER_TYPE && TREE_CODE (ttr) == POINTER_TYPE)
-         if (TREE_TYPE (ttl) == void_type_node
-             || TREE_TYPE (ttr) == void_type_node)
-           return INT_TO_EASY_HARSHNESS (penalty+1);
-
-       if (parm && codel != REFERENCE_TYPE)
-         return (convert_harshness_old (ttl, ttr, NULL_TREE)
-                 | INT_TO_EASY_HARSHNESS (penalty));
-
-       /* Here it does matter.  If this conversion is from
-          derived to base, allow it.  Otherwise, types must
-          be compatible in the strong sense.  */
-       if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
-         {
-           int b_or_d = get_base_distance (ttl, ttr, 0, 0);
-           if (b_or_d < 0)
-             {
-               b_or_d = get_base_distance (ttr, ttl, 0, 0);
-               if (b_or_d < 0)
-                 return EVIL;
-               return CONTRAVARIANT_HARSHNESS (-1);
-             }
-           /* Say that this conversion is relatively painless.
-              If it turns out that there is a user-defined X(X&)
-              constructor, then that will be invoked, but that's
-              preferable to dealing with other user-defined conversions
-              that may produce surprising results.  */
-           return INT_TO_BD_HARSHNESS (b_or_d);
-         }
-
-       if (comp_target_types (ttl, intype, 1))
-         return INT_TO_EASY_HARSHNESS (penalty);
-      }
-  }
-  if (codel == RECORD_TYPE && coder == RECORD_TYPE)
-    {
-      int b_or_d = get_base_distance (type, parmtype, 0, 0);
-      if (b_or_d < 0)
-       {
-         b_or_d = get_base_distance (parmtype, type, 0, 0);
-         if (b_or_d < 0)
-           return EVIL;
-         return CONTRAVARIANT_HARSHNESS (-1);
-       }
-      return INT_TO_BD_HARSHNESS (b_or_d);
-    }
-  return EVIL;
-}
-
-#ifdef DEBUG_MATCHING
-static char *
-print_harshness (h)
-     struct harshness_code *h;
-{
-  static char buf[1024];
-  char tmp[1024];
-
-  bzero (buf, 1024 * sizeof (char));
-  strcat (buf, "codes=[");
-  if (h->code & EVIL_CODE)
-    strcat (buf, "EVIL");
-  if (h->code & CONST_CODE)
-    strcat (buf, " CONST");
-  if (h->code & ELLIPSIS_CODE)
-    strcat (buf, " ELLIPSIS");
-  if (h->code & USER_CODE)
-    strcat (buf, " USER");
-  if (h->code & STD_CODE)
-    strcat (buf, " STD");
-  if (h->code & PROMO_CODE)
-    strcat (buf, " PROMO");
-  if (h->code & QUAL_CODE)
-    strcat (buf, " QUAL");
-  if (h->code & TRIVIAL_CODE)
-    strcat (buf, " TRIVIAL");
-  if (buf[0] == '\0')
-    strcat (buf, "0");
-
-  sprintf (tmp, "] distance=%d int_penalty=%d", h->distance, h->int_penalty);
-
-  strcat (buf, tmp);
+  strcat (buf, tmp);
 
   return buf;
 }
@@ -1263,7 +718,7 @@ print_harshness (h)
    must be unique.  */
 
 void
-compute_conversion_costs_ansi (function, tta_in, cp, arglen)
+compute_conversion_costs (function, tta_in, cp, arglen)
      tree function;
      tree tta_in;
      struct candidate *cp;
@@ -1282,11 +737,17 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
 
   int strike_index = 0, win;
   struct harshness_code lose;
+  extern int cp_silent;
 
 #ifdef GATHER_STATISTICS
   n_compute_conversion_costs++;
 #endif
 
+#ifndef DEBUG_MATCHING
+  /* We don't emit any warnings or errors while trying out each candidate.  */
+  cp_silent = 1;
+#endif
+
   cp->function = function;
   cp->arg = tta ? TREE_VALUE (tta) : NULL_TREE;
   cp->u.bad_arg = 0;           /* optimistic!  */
@@ -1294,7 +755,7 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
   cp->h.code = 0;
   cp->h.distance = 0;
   cp->h.int_penalty = 0;
-  bzero (cp->v.ansi_harshness,
+  bzero ((char *) cp->harshness,
         (cp->h_len + 1) * sizeof (struct harshness_code));
 
   while (ttf && tta)
@@ -1325,7 +786,7 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
          if (TREE_CODE (rhs) == ERROR_MARK)
            h.code = EVIL_CODE;
          else
-           h = convert_harshness_ansi (lhstype, TREE_TYPE (rhs), rhs);
+           h = convert_harshness (lhstype, TREE_TYPE (rhs), rhs);
        }
       else
        {
@@ -1343,16 +804,16 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
                    TREE_VALUE (ttf));
 #endif
 
-         h = convert_harshness_ansi (TREE_VALUE (ttf),
-                                     TREE_TYPE (TREE_VALUE (tta)),
-                                     TREE_VALUE (tta));
+         h = convert_harshness (TREE_VALUE (ttf),
+                                TREE_TYPE (TREE_VALUE (tta)),
+                                TREE_VALUE (tta));
 
 #ifdef DEBUG_MATCHING
          cp_error ("     evaluated %s", print_harshness (&h));
 #endif
        }
 
-      cp->v.ansi_harshness[strike_index] = h;
+      cp->harshness[strike_index] = h;
       if ((h.code & EVIL_CODE)
          || ((h.code & STD_CODE) && h.distance < 0))
        {
@@ -1362,7 +823,7 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
      else if (h.code & ELLIPSIS_CODE)
        ellipsis_strikes += 1;
 #if 0
-      /* This is never set by `convert_harshness_ansi'.  */
+      /* This is never set by `convert_harshness'.  */
       else if (h.code & USER_CODE)
        {
          user_strikes += 1;
@@ -1394,6 +855,7 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
        {
          cp->h.code = EVIL_CODE;
          cp->u.bad_arg = -1;
+         cp_silent = 0;
          return;
        }
       else
@@ -1405,7 +867,7 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
          h.distance = 0;
          h.int_penalty = 0;
          for (; l; --l)
-           cp->v.ansi_harshness[strike_index++] = h;
+           cp->harshness[strike_index++] = h;
        }
     }
   else if (ttf && ttf != void_list_node)
@@ -1415,13 +877,14 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
        {
          cp->h.code = EVIL_CODE;
          cp->u.bad_arg = -2;
+         cp_silent = 0;
          return;
        }
       /* Store index of first default.  */
-      cp->v.ansi_harshness[arglen].distance = strike_index+1;
+      cp->harshness[arglen].distance = strike_index+1;
     }
   else
-    cp->v.ansi_harshness[arglen].distance = 0;
+    cp->harshness[arglen].distance = 0;
 
   /* Argument list lengths work out, so don't need to check them again.  */
   if (evil_strikes)
@@ -1437,6 +900,7 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
       if (dont_convert_types)
        {
          cp->h.code = EVIL_CODE;
+         cp_silent = 0;
          return;
        }
 
@@ -1451,12 +915,13 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
          if (ttf == void_list_node)
            break;
 
-         lose = cp->v.ansi_harshness[strike_index];
+         lose = cp->harshness[strike_index];
          if ((lose.code & EVIL_CODE)
              || ((lose.code & STD_CODE) && lose.distance < 0))
            {
              tree actual_type = TREE_TYPE (TREE_VALUE (tta));
              tree formal_type = TREE_VALUE (ttf);
+             int extra_conversions = 0;
 
              dont_convert_types = 1;
 
@@ -1468,8 +933,8 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
              if (formal_type != error_mark_node
                  && actual_type != error_mark_node)
                {
-                 formal_type = TYPE_MAIN_VARIANT (formal_type);
-                 actual_type = TYPE_MAIN_VARIANT (actual_type);
+                 formal_type = complete_type (TYPE_MAIN_VARIANT (formal_type));
+                 actual_type = complete_type (TYPE_MAIN_VARIANT (actual_type));
 
                  if (TYPE_HAS_CONSTRUCTOR (formal_type))
                    {
@@ -1484,42 +949,14 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
                  if (TYPE_LANG_SPECIFIC (actual_type)
                      && TYPE_HAS_CONVERSION (actual_type))
                    {
-                     if (TREE_CODE (formal_type) == INTEGER_TYPE
-                         && TYPE_HAS_INT_CONVERSION (actual_type))
-                       win++;
-                     else if (TREE_CODE (formal_type) == REAL_TYPE
-                              && TYPE_HAS_REAL_CONVERSION (actual_type))
-                       win++;
-                     else
+                     int extra = user_harshness (formal_type, actual_type);
+
+                     if (extra == EVIL_CODE)
+                       win += 2;
+                     else if (extra >= 0)
                        {
-                         tree conv;
-                         /* Don't issue warnings since we're only groping
-                            around for the right answer, we haven't yet
-                            committed to going with this solution.  */
-                         int old_inhibit_warnings = inhibit_warnings;
-
-                         inhibit_warnings = 1;
-                         conv = build_type_conversion (CALL_EXPR, TREE_VALUE (ttf), TREE_VALUE (tta), 0);
-                         inhibit_warnings = old_inhibit_warnings;
-
-                         if (conv)
-                           {
-                             if (conv == error_mark_node)
-                               win += 2;
-                             else
-                               win++;
-                           }
-                         else if (TREE_CODE (TREE_VALUE (ttf)) == REFERENCE_TYPE)
-                           {
-                             conv = build_type_conversion (CALL_EXPR, formal_type, TREE_VALUE (tta), 0);
-                             if (conv)
-                               {
-                                 if (conv == error_mark_node)
-                                   win += 2;
-                                 else
-                                   win++;
-                               }
-                           }
+                         win++;
+                         extra_conversions = extra;
                        }
                    }
                }
@@ -1528,7 +965,8 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
              if (win == 1)
                {
                  user_strikes += 1;
-                 cp->v.ansi_harshness[strike_index].code = USER_CODE;
+                 cp->harshness[strike_index].code
+                   = USER_CODE | (extra_conversions ? STD_CODE : 0);
                  win = 0;
                }
              else
@@ -1548,7 +986,7 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
     }
 
   /* Const member functions get a small penalty because defaulting
-     to const is less useful than defaulting to non-const. */
+     to const is less useful than defaulting to non-const.  */
   /* This is bogus, it does not correspond to anything in the ARM.
      This code will be fixed when this entire section is rewritten
      to conform to the ARM.  (mrs)  */
@@ -1560,7 +998,7 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
            ? TYPE_READONLY (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (this_parm))))
            : TYPE_READONLY (TREE_TYPE (this_parm)))
        {
-         cp->v.ansi_harshness[0].code |= TRIVIAL_CODE;
+         cp->harshness[0].code |= TRIVIAL_CODE;
          ++easy_strikes;
        }
       else
@@ -1571,7 +1009,7 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
             harshness to a maximum value.  */
          if (TREE_CODE (TREE_TYPE (TREE_VALUE (tta_in))) == POINTER_TYPE
              && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (TREE_VALUE (tta_in))))))
-           cp->v.ansi_harshness[0].code |= CONST_CODE;
+           cp->harshness[0].code |= CONST_CODE;
        }
     }
 
@@ -1581,2625 +1019,4776 @@ compute_conversion_costs_ansi (function, tta_in, cp, arglen)
     cp->h.code |= ELLIPSIS_CODE;
   if (user_strikes)
     cp->h.code |= USER_CODE;
+  cp_silent = 0;
 #ifdef DEBUG_MATCHING
   cp_error ("final eval %s", print_harshness (&cp->h));
 #endif
 }
 
-void
-compute_conversion_costs_old (function, tta_in, cp, arglen)
-     tree function;
-     tree tta_in;
-     struct candidate *cp;
-     int arglen;
-{
-  tree ttf_in = TYPE_ARG_TYPES (TREE_TYPE (function));
-  tree ttf = ttf_in;
-  tree tta = tta_in;
+/* Subroutine of ideal_candidate.  See if X or Y is a better match
+   than the other.  */
 
-  /* Start out with no strikes against.  */
-  int evil_strikes = 0;
-  int ellipsis_strikes = 0;
-  int user_strikes = 0;
-  int b_or_d_strikes = 0;
-  int easy_strikes = 0;
+static int
+strictly_better (x, y)
+     unsigned short x, y;
+{
+  unsigned short xor;
 
-  int strike_index = 0, win, lose;
+  if (x == y)
+    return 0;
 
-#ifdef GATHER_STATISTICS
-  n_compute_conversion_costs++;
-#endif
+  xor = x ^ y;
+  if (xor >= x || xor >= y)
+    return 1;
+  return 0;
+}
 
-  cp->function = function;
-  cp->arg = tta ? TREE_VALUE (tta) : NULL_TREE;
-  cp->u.bad_arg = 0;           /* optimistic!  */
+/* When one of several possible overloaded functions and/or methods
+   can be called, choose the best candidate for overloading.
 
-  bzero (cp->v.old_harshness, (cp->h_len + 1) * sizeof (unsigned short));
+   BASETYPE is the context from which we start method resolution
+   or NULL if we are comparing overloaded functions.
+   CANDIDATES is the array of candidates we have to choose from.
+   N_CANDIDATES is the length of CANDIDATES.
+   PARMS is a TREE_LIST of parameters to the function we'll ultimately
+   choose.  It is modified in place when resolving methods.  It is not
+   modified in place when resolving overloaded functions.
+   LEN is the length of the parameter list.  */
 
-  while (ttf && tta)
+static struct candidate *
+ideal_candidate (candidates, n_candidates, len)
+     struct candidate *candidates;
+     int n_candidates;
+     int len;
+{
+  struct candidate *cp = candidates+n_candidates;
+  int i, j = -1, best_code;
+
+  /* For each argument, sort the functions from best to worst for the arg.
+     For each function that's not best for this arg, set its overall
+     harshness to EVIL so that other args won't like it.  The candidate
+     list for the last argument is the intersection of all the best-liked
+     functions.  */
+
+  qsort (candidates, n_candidates, sizeof (struct candidate),
+        rank_for_overload);
+  best_code = cp[-1].h.code;
+
+  /* If they're at least as good as each other, do an arg-by-arg check.  */
+  if (! strictly_better (cp[-1].h.code, cp[-2].h.code))
+    {
+      int better = 0;
+      int worse = 0;
+
+      for (j = 0; j < n_candidates; j++)
+       if (! strictly_better (candidates[j].h.code, best_code))
+         break;
+
+      qsort (candidates+j, n_candidates-j, sizeof (struct candidate),
+            rank_for_ideal);
+      for (i = 0; i < len; i++)
+       {
+         if (cp[-1].harshness[i].code < cp[-2].harshness[i].code)
+           better = 1;
+         else if (cp[-1].harshness[i].code > cp[-2].harshness[i].code)
+           worse = 1;
+         else if (cp[-1].harshness[i].code & STD_CODE)
+           {
+             /* If it involves a standard conversion, let the
+                inheritance lattice be the final arbiter.  */
+             if (cp[-1].harshness[i].distance > cp[-2].harshness[i].distance)
+               worse = 1;
+             else if (cp[-1].harshness[i].distance < cp[-2].harshness[i].distance)
+               better = 1;
+           }
+         else if (cp[-1].harshness[i].code & PROMO_CODE)
+           {
+             /* For integral promotions, take into account a finer
+                granularity for determining which types should be favored
+                over others in such promotions.  */
+             if (cp[-1].harshness[i].int_penalty > cp[-2].harshness[i].int_penalty)
+               worse = 1;
+             else if (cp[-1].harshness[i].int_penalty < cp[-2].harshness[i].int_penalty)
+               better = 1;
+           }
+       }
+
+      if (! better || worse)
+       return NULL;
+    }
+  return cp-1;
+}
+
+/* Assume that if the class referred to is not in the
+   current class hierarchy, that it may be remote.
+   PARENT is assumed to be of aggregate type here.  */
+
+static int
+may_be_remote (parent)
+     tree parent;
+{
+  if (TYPE_OVERLOADS_METHOD_CALL_EXPR (parent) == 0)
+    return 0;
+
+  if (current_class_type == NULL_TREE)
+    return 0;
+
+  if (parent == current_class_type)
+    return 0;
+
+  if (UNIQUELY_DERIVED_FROM_P (parent, current_class_type))
+    return 0;
+  return 1;
+}
+
+tree
+build_vfield_ref (datum, type)
+     tree datum, type;
+{
+  tree rval;
+  int old_assume_nonnull_objects = flag_assume_nonnull_objects;
+
+  if (datum == error_mark_node)
+    return error_mark_node;
+
+  /* Vtable references are always made from non-null objects.  */
+  flag_assume_nonnull_objects = 1;
+  if (TREE_CODE (TREE_TYPE (datum)) == REFERENCE_TYPE)
+    datum = convert_from_reference (datum);
+
+  if (! TYPE_USES_COMPLEX_INHERITANCE (type))
+    rval = build (COMPONENT_REF, TREE_TYPE (CLASSTYPE_VFIELD (type)),
+                 datum, CLASSTYPE_VFIELD (type));
+  else
+    rval = build_component_ref (datum, DECL_NAME (CLASSTYPE_VFIELD (type)), NULL_TREE, 0);
+  flag_assume_nonnull_objects = old_assume_nonnull_objects;
+
+  return rval;
+}
+
+/* Build a call to a member of an object.  I.e., one that overloads
+   operator ()(), or is a pointer-to-function or pointer-to-method.  */
+
+static tree
+build_field_call (basetype_path, instance_ptr, name, parms)
+     tree basetype_path, instance_ptr, name, parms;
+{
+  tree field, instance;
+
+  if (instance_ptr == current_class_ptr)
+    {
+      /* Check to see if we really have a reference to an instance variable
+        with `operator()()' overloaded.  */
+      field = IDENTIFIER_CLASS_VALUE (name);
+
+      if (field == NULL_TREE)
+       {
+         cp_error ("`this' has no member named `%D'", name);
+         return error_mark_node;
+       }
+
+      if (TREE_CODE (field) == FIELD_DECL)
+       {
+         /* If it's a field, try overloading operator (),
+            or calling if the field is a pointer-to-function.  */
+         instance = build_component_ref_1 (current_class_ref, field, 0);
+         if (instance == error_mark_node)
+           return error_mark_node;
+
+         if (TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
+             && (TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (instance))
+                 || flag_ansi_overloading))
+           return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, instance, parms, NULL_TREE);
+
+         if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
+           {
+             if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == FUNCTION_TYPE)
+               return build_function_call (instance, parms);
+             else if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == METHOD_TYPE)
+               return build_function_call (instance, tree_cons (NULL_TREE, current_class_ptr, parms));
+           }
+       }
+      return NULL_TREE;
+    }
+
+  /* Check to see if this is not really a reference to an instance variable
+     with `operator()()' overloaded.  */
+  field = lookup_field (basetype_path, name, 1, 0);
+
+  /* This can happen if the reference was ambiguous or for access
+     violations.  */
+  if (field == error_mark_node)
+    return error_mark_node;
+
+  if (field)
+    {
+      tree basetype;
+      tree ftype = TREE_TYPE (field);
+
+      if (TREE_CODE (ftype) == REFERENCE_TYPE)
+       ftype = TREE_TYPE (ftype);
+
+      if (TYPE_LANG_SPECIFIC (ftype)
+         && (TYPE_OVERLOADS_CALL_EXPR (ftype) || flag_ansi_overloading))
+       {
+         /* Make the next search for this field very short.  */
+         basetype = DECL_FIELD_CONTEXT (field);
+         instance_ptr = convert_pointer_to (basetype, instance_ptr);
+
+         instance = build_indirect_ref (instance_ptr, NULL_PTR);
+         return build_opfncall (CALL_EXPR, LOOKUP_NORMAL,
+                                build_component_ref_1 (instance, field, 0),
+                                parms, NULL_TREE);
+       }
+      if (TREE_CODE (ftype) == POINTER_TYPE)
+       {
+         if (TREE_CODE (TREE_TYPE (ftype)) == FUNCTION_TYPE
+             || TREE_CODE (TREE_TYPE (ftype)) == METHOD_TYPE)
+           {
+             /* This is a member which is a pointer to function.  */
+             tree ref
+               = build_component_ref_1 (build_indirect_ref (instance_ptr,
+                                                            NULL_PTR),
+                                        field, LOOKUP_COMPLAIN);
+             if (ref == error_mark_node)
+               return error_mark_node;
+             return build_function_call (ref, parms);
+           }
+       }
+      else if (TREE_CODE (ftype) == METHOD_TYPE)
+       {
+         error ("invalid call via pointer-to-member function");
+         return error_mark_node;
+       }
+      else
+       return NULL_TREE;
+    }
+  return NULL_TREE;
+}
+
+tree
+find_scoped_type (type, inner_name, inner_types)
+     tree type, inner_name, inner_types;
+{
+  tree tags = CLASSTYPE_TAGS (type);
+
+  while (tags)
+    {
+      /* The TREE_PURPOSE of an enum tag (which becomes a member of the
+        enclosing class) is set to the name for the enum type.  So, if
+        inner_name is `bar', and we strike `baz' for `enum bar { baz }',
+        then this test will be true.  */
+      if (TREE_PURPOSE (tags) == inner_name)
+       {
+         if (inner_types == NULL_TREE)
+           return TYPE_NAME (TREE_VALUE (tags));
+         return resolve_scope_to_name (TREE_VALUE (tags), inner_types);
+       }
+      tags = TREE_CHAIN (tags);
+    }
+
+  /* Look for a TYPE_DECL.  */
+  for (tags = TYPE_FIELDS (type); tags; tags = TREE_CHAIN (tags))
+    if (TREE_CODE (tags) == TYPE_DECL && DECL_NAME (tags) == inner_name)
+      {
+       /* Code by raeburn.  */
+       if (inner_types == NULL_TREE)
+         return tags;
+       return resolve_scope_to_name (TREE_TYPE (tags), inner_types);
+      }
+
+  return NULL_TREE;
+}
+
+/* Resolve an expression NAME1::NAME2::...::NAMEn to
+   the name that names the above nested type.  INNER_TYPES
+   is a chain of nested type names (held together by SCOPE_REFs);
+   OUTER_TYPE is the type we know to enclose INNER_TYPES.
+   Returns NULL_TREE if there is an error.  */
+
+tree
+resolve_scope_to_name (outer_type, inner_stuff)
+     tree outer_type, inner_stuff;
+{
+  register tree tmp;
+  tree inner_name, inner_type;
+
+  if (outer_type == NULL_TREE && current_class_type != NULL_TREE)
+    {
+      /* We first try to look for a nesting in our current class context,
+         then try any enclosing classes.  */
+      tree type = current_class_type;
+      
+      while (type && (TREE_CODE (type) == RECORD_TYPE
+                     || TREE_CODE (type) == UNION_TYPE))
+        {
+          tree rval = resolve_scope_to_name (type, inner_stuff);
+
+         if (rval != NULL_TREE)
+           return rval;
+         type = DECL_CONTEXT (TYPE_NAME (type));
+       }
+    }
+
+  if (TREE_CODE (inner_stuff) == SCOPE_REF)
+    {
+      inner_name = TREE_OPERAND (inner_stuff, 0);
+      inner_type = TREE_OPERAND (inner_stuff, 1);
+    }
+  else
+    {
+      inner_name = inner_stuff;
+      inner_type = NULL_TREE;
+    }
+
+  if (outer_type == NULL_TREE)
+    {
+      tree x;
+      /* If we have something that's already a type by itself,
+        use that.  */
+      if (IDENTIFIER_HAS_TYPE_VALUE (inner_name))
+       {
+         if (inner_type)
+           return resolve_scope_to_name (IDENTIFIER_TYPE_VALUE (inner_name),
+                                         inner_type);
+         return inner_name;
+       }
+      
+      x = lookup_name (inner_name, 0);
+
+      if (x && TREE_CODE (x) == NAMESPACE_DECL)
+       {
+         x = lookup_namespace_name (x, inner_type);
+         return x;
+       }
+      return NULL_TREE;
+    }
+
+  if (! IS_AGGR_TYPE (outer_type))
+    return NULL_TREE;
+
+  /* Look for member classes or enums.  */
+  tmp = find_scoped_type (outer_type, inner_name, inner_type);
+
+  /* If it's not a type in this class, then go down into the
+     base classes and search there.  */
+  if (! tmp && TYPE_BINFO (outer_type))
+    {
+      tree binfos = TYPE_BINFO_BASETYPES (outer_type);
+      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+      for (i = 0; i < n_baselinks; i++)
+       {
+         tree base_binfo = TREE_VEC_ELT (binfos, i);
+         tmp = resolve_scope_to_name (BINFO_TYPE (base_binfo), inner_stuff);
+         if (tmp)
+           return tmp;
+       }
+      tmp = NULL_TREE;
+    }
+
+  return tmp;
+}
+
+/* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'.
+   This is how virtual function calls are avoided.  */
+
+tree
+build_scoped_method_call (exp, basetype, name, parms)
+     tree exp, basetype, name, parms;
+{
+  /* Because this syntactic form does not allow
+     a pointer to a base class to be `stolen',
+     we need not protect the derived->base conversion
+     that happens here.
+     
+     @@ But we do have to check access privileges later.  */
+  tree binfo, decl;
+  tree type = TREE_TYPE (exp);
+
+  if (type == error_mark_node
+      || basetype == error_mark_node)
+    return error_mark_node;
+
+  if (processing_template_decl)
+    {
+      if (TREE_CODE (name) == BIT_NOT_EXPR)
+       {
+         tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 1);
+         name = build_min_nt (BIT_NOT_EXPR, type);
+       }
+      name = build_min_nt (SCOPE_REF, basetype, name);
+      return build_min_nt (METHOD_CALL_EXPR, name, exp, parms, NULL_TREE);
+    }
+
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    type = TREE_TYPE (type);
+
+  /* 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))
+    {
+      if (type != basetype)
+       cp_error ("type of `%E' does not match destructor type `%T' (type was `%T')",
+                 exp, basetype, type);
+      name = TREE_OPERAND (name, 0);
+      if (basetype != name && basetype != get_type_value (name))
+       cp_error ("qualified type `%T' does not match destructor name `~%T'",
+                 basetype, name);
+      return convert (void_type_node, exp);
+    }
+
+  if (! is_aggr_type (basetype, 1))
+    return error_mark_node;
+
+  if (! IS_AGGR_TYPE (type))
+    {
+      cp_error ("base object `%E' of scoped method call is of non-aggregate type `%T'",
+               exp, type);
+      return error_mark_node;
+    }
+
+  if ((binfo = binfo_or_else (basetype, type)))
+    {
+      if (binfo == error_mark_node)
+       return error_mark_node;
+      if (TREE_CODE (exp) == INDIRECT_REF)
+       decl = build_indirect_ref (convert_pointer_to (binfo,
+                                                      build_unary_op (ADDR_EXPR, exp, 0)), NULL_PTR);
+      else
+       decl = build_scoped_ref (exp, basetype);
+
+      /* 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 convert (void_type_node, exp);
+         
+         return build_delete (TREE_TYPE (decl), decl, integer_two_node,
+                              LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR,
+                              0);
+       }
+
+      /* Call to a method.  */
+      return build_method_call (decl, name, parms, binfo,
+                               LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
+    }
+  return error_mark_node;
+}
+
+static void
+print_candidates (candidates)
+     tree candidates;
+{
+  cp_error_at ("candidates are: %D", TREE_VALUE (candidates));
+  candidates = TREE_CHAIN (candidates);
+
+  while (candidates)
+    {
+      cp_error_at ("                %D", TREE_VALUE (candidates));
+      candidates = TREE_CHAIN (candidates);
+    }
+}
+
+static void
+print_n_candidates (candidates, n)
+     struct candidate *candidates;
+     int n;
+{
+  int i;
+
+  cp_error_at ("candidates are: %D", candidates[0].function);
+  for (i = 1; i < n; i++)
+    cp_error_at ("                %D", candidates[i].function);
+}
+
+/* We want the address of a function or method.  We avoid creating a
+   pointer-to-member function.  */
+
+tree
+build_addr_func (function)
+     tree function;
+{
+  tree type = TREE_TYPE (function);
+
+  /* We have to do these by hand to avoid real pointer to member
+     functions.  */
+  if (TREE_CODE (type) == METHOD_TYPE)
+    {
+      tree addr;
+
+      type = build_pointer_type (type);
+
+      if (mark_addressable (function) == 0)
+       return error_mark_node;
+
+      addr = build1 (ADDR_EXPR, type, function);
+
+      /* Address of a static or external variable or function counts
+        as a constant */
+      if (staticp (function))
+       TREE_CONSTANT (addr) = 1;
+
+      function = addr;
+    }
+  else
+    function = default_conversion (function);
+
+  return function;
+}
+
+/* Build a CALL_EXPR, we can handle FUNCTION_TYPEs, METHOD_TYPEs, or
+   POINTER_TYPE to those.  Note, pointer to member function types
+   (TYPE_PTRMEMFUNC_P) must be handled by our callers.  */
+
+tree
+build_call (function, result_type, parms)
+     tree function, result_type, parms;
+{
+  int is_constructor = 0;
+
+  function = build_addr_func (function);
+
+  if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
+    {
+      sorry ("unable to call pointer to member function here");
+      return error_mark_node;
+    }
+
+  if (TREE_CODE (function) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
+      && DECL_CONSTRUCTOR_P (TREE_OPERAND (function, 0)))
+    is_constructor = 1;
+
+  function = build_nt (CALL_EXPR, function, parms, NULL_TREE);
+  TREE_HAS_CONSTRUCTOR (function) = is_constructor;
+  TREE_TYPE (function) = result_type;
+  TREE_SIDE_EFFECTS (function) = 1;
+  
+  return function;
+}
+
+static tree
+default_parm_conversions (parms, last)
+     tree parms, *last;
+{
+  tree parm, parmtypes = NULL_TREE;
+
+  *last = NULL_TREE;
+
+  for (parm = parms; parm; parm = TREE_CHAIN (parm))
+    {
+      tree t = TREE_TYPE (TREE_VALUE (parm));
+
+      if (TREE_CODE (t) == OFFSET_TYPE
+         || TREE_CODE (t) == METHOD_TYPE
+         || TREE_CODE (t) == FUNCTION_TYPE)
+       {
+         TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
+         t = TREE_TYPE (TREE_VALUE (parm));
+       }
+
+      if (t == error_mark_node)
+         return error_mark_node;
+
+      *last = build_tree_list (NULL_TREE, t);
+      parmtypes = chainon (parmtypes, *last);
+    }
+
+  return parmtypes;
+}
+
+
+/* Build something of the form ptr->method (args)
+   or object.method (args).  This can also build
+   calls to constructors, and find friends.
+
+   Member functions always take their class variable
+   as a pointer.
+
+   INSTANCE is a class instance.
+
+   NAME is the name of the method desired, usually an IDENTIFIER_NODE.
+
+   PARMS help to figure out what that NAME really refers to.
+
+   BASETYPE_PATH, if non-NULL, contains a chain from the type of INSTANCE
+   down to the real instance type to use for access checking.  We need this
+   information to get protected accesses correct.  This parameter is used
+   by build_member_call.
+
+   FLAGS is the logical disjunction of zero or more LOOKUP_
+   flags.  See cp-tree.h for more info.
+
+   If this is all OK, calls build_function_call with the resolved
+   member function.
+
+   This function must also handle being called to perform
+   initialization, promotion/coercion of arguments, and
+   instantiation of default parameters.
+
+   Note that NAME may refer to an instance variable name.  If
+   `operator()()' is defined for the type of that field, then we return
+   that result.  */
+
+tree
+build_method_call (instance, name, parms, basetype_path, flags)
+     tree instance, name, parms, basetype_path;
+     int flags;
+{
+  register tree function, fntype, value_type;
+  register tree basetype, save_basetype;
+  register tree baselink, result, parmtypes, parm;
+  tree last;
+  int pass;
+  tree access = access_public_node;
+  tree orig_basetype = basetype_path ? BINFO_TYPE (basetype_path) : NULL_TREE;
+
+  /* Range of cases for vtable optimization.  */
+  enum vtable_needs { not_needed, maybe_needed, unneeded, needed };
+  enum vtable_needs need_vtbl = not_needed;
+
+  char *name_kind;
+  tree save_name = name;
+  int ever_seen = 0;
+  tree instance_ptr = NULL_TREE;
+  int all_virtual = flag_all_virtual;
+  int static_call_context = 0;
+  tree found_fns = NULL_TREE;
+
+  /* Keep track of `const' and `volatile' objects.  */
+  int constp, volatilep;
+
+#ifdef GATHER_STATISTICS
+  n_build_method_call++;
+#endif
+
+  if (instance == error_mark_node
+      || name == error_mark_node
+      || parms == error_mark_node
+      || (instance != NULL_TREE && TREE_TYPE (instance) == error_mark_node))
+    return error_mark_node;
+
+  if (processing_template_decl)
+    {
+      if (TREE_CODE (name) == BIT_NOT_EXPR)
+       {
+         tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 1);
+         name = build_min_nt (BIT_NOT_EXPR, type);
+       }
+
+      return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE);
+    }
+
+  /* This is the logic that magically deletes the second argument to
+     operator delete, if it is not needed.  */
+  if (name == ansi_opname[(int) DELETE_EXPR] && list_length (parms)==2)
+    {
+      tree save_last = TREE_CHAIN (parms);
+      tree result;
+      /* get rid of unneeded argument */
+      TREE_CHAIN (parms) = NULL_TREE;
+      result = build_method_call (instance, name, parms, basetype_path,
+                                 (LOOKUP_SPECULATIVELY|flags)
+                                 &~LOOKUP_COMPLAIN);
+      /* If it finds a match, return it.  */
+      if (result)
+       return build_method_call (instance, name, parms, basetype_path, flags);
+      /* If it doesn't work, two argument delete must work */
+      TREE_CHAIN (parms) = save_last;
+    }
+  /* We already know whether it's needed or not for vec delete.  */
+  else if (name == ansi_opname[(int) VEC_DELETE_EXPR]
+          && TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
+          && ! TYPE_VEC_DELETE_TAKES_SIZE (TREE_TYPE (instance)))
+    TREE_CHAIN (parms) = NULL_TREE;
+
+  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 == basetype
+            || (IS_AGGR_TYPE (basetype)
+                && name == constructor_name (basetype))
+            || basetype == get_type_value (name)))
+       {
+         cp_error ("destructor name `~%D' does not match type `%T' of expression",
+                   name, basetype);
+         return convert (void_type_node, instance);
+       }
+
+      if (! TYPE_HAS_DESTRUCTOR (basetype))
+       return convert (void_type_node, instance);
+      instance = default_conversion (instance);
+      instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
+      return build_delete (build_pointer_type (basetype),
+                          instance_ptr, integer_two_node,
+                          LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
+    }
+
+  if (flag_ansi_overloading)
+    return build_new_method_call (instance, name, parms, basetype_path, flags);
+
+  {
+    char *xref_name;
+    
+    /* Initialize name for error reporting.  */
+    if (IDENTIFIER_OPNAME_P (name) && ! IDENTIFIER_TYPENAME_P (name))
+      {
+       char *p = operator_name_string (name);
+       xref_name = (char *)alloca (strlen (p) + 10);
+       sprintf (xref_name, "operator %s", p);
+      }
+    else if (TREE_CODE (name) == SCOPE_REF)
+      xref_name = IDENTIFIER_POINTER (TREE_OPERAND (name, 1));
+    else
+      xref_name = IDENTIFIER_POINTER (name);
+
+    GNU_xref_call (current_function_decl, xref_name);
+  }
+
+  if (instance == NULL_TREE)
+    {
+      basetype = NULL_TREE;
+      /* Check cases where this is really a call to raise
+        an exception.  */
+      if (current_class_type && TREE_CODE (name) == IDENTIFIER_NODE)
+       {
+         basetype = purpose_member (name, CLASSTYPE_TAGS (current_class_type));
+         if (basetype)
+           basetype = TREE_VALUE (basetype);
+       }
+      else if (TREE_CODE (name) == SCOPE_REF
+              && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
+       {
+         if (! is_aggr_typedef (TREE_OPERAND (name, 0), 1))
+           return error_mark_node;
+         basetype = purpose_member (TREE_OPERAND (name, 1),
+                                    CLASSTYPE_TAGS (IDENTIFIER_TYPE_VALUE (TREE_OPERAND (name, 0))));
+         if (basetype)
+           basetype = TREE_VALUE (basetype);
+       }
+
+      if (basetype != NULL_TREE)
+       ;
+      /* call to a constructor...  */
+      else if (basetype_path)
+       {
+         basetype = BINFO_TYPE (basetype_path);
+         if (name == TYPE_IDENTIFIER (basetype))
+           name = ctor_identifier;
+       }
+      else if (IDENTIFIER_HAS_TYPE_VALUE (name))
+       {
+         basetype = IDENTIFIER_TYPE_VALUE (name);
+         name = ctor_identifier;
+       }
+      else
+       {
+         tree typedef_name = lookup_name (name, 1);
+         if (typedef_name && TREE_CODE (typedef_name) == TYPE_DECL)
+           {
+             /* Canonicalize the typedef name.  */
+             basetype = TREE_TYPE (typedef_name);
+             name = ctor_identifier;
+           }
+         else
+           {
+             cp_error ("no constructor named `%T' in scope",
+                       name);
+             return error_mark_node;
+           }
+       }
+
+      if (! IS_AGGR_TYPE (basetype))
+       {
+       non_aggr_error:
+         if ((flags & LOOKUP_COMPLAIN) && TREE_CODE (basetype) != ERROR_MARK)
+           cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
+                     name, instance, basetype);
+
+         return error_mark_node;
+       }
+    }
+  else if (instance == current_class_ref || instance == current_class_ptr)
+    {
+      /* When doing initialization, we side-effect the TREE_TYPE of
+        current_class_ref, hence we cannot set up BASETYPE from CURRENT_CLASS_TYPE.  */
+      basetype = TREE_TYPE (current_class_ref);
+
+      /* Anything manifestly `this' in constructors and destructors
+        has a known type, so virtual function tables are not needed.  */
+      if (TYPE_VIRTUAL_P (basetype)
+         && !(flags & LOOKUP_NONVIRTUAL))
+       need_vtbl = (dtor_label || ctor_label)
+         ? unneeded : maybe_needed;
+
+      /* If `this' is a signature pointer and `name' is not a constructor,
+        we are calling a signature member function.  In that case, set the
+        `basetype' to the signature type and dereference the `optr' field.  */
+      if (IS_SIGNATURE_POINTER (basetype)
+         && TYPE_IDENTIFIER (basetype) != name)
+       {
+         basetype = SIGNATURE_TYPE (basetype);
+         instance_ptr = instance;
+         basetype_path = TYPE_BINFO (basetype);
+       }
+      else
+       {
+         instance = current_class_ref;
+         instance_ptr = current_class_ptr;
+         basetype_path = TYPE_BINFO (current_class_type);
+       }
+      result = build_field_call (basetype_path, instance_ptr, name, parms);
+
+      if (result)
+       return result;
+    }
+  else if (TREE_CODE (instance) == RESULT_DECL)
+    {
+      basetype = TREE_TYPE (instance);
+      /* Should we ever have to make a virtual function reference
+        from a RESULT_DECL, know that it must be of fixed type
+        within the scope of this function.  */
+      if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
+       need_vtbl = maybe_needed;
+      instance_ptr = build1 (ADDR_EXPR, build_pointer_type (basetype), instance);
+    }
+  else
+    {
+      /* The MAIN_VARIANT of the type that `instance_ptr' winds up being.  */
+      tree inst_ptr_basetype;
+
+      static_call_context =
+       (TREE_CODE (instance) == INDIRECT_REF
+        && TREE_CODE (TREE_OPERAND (instance, 0)) == NOP_EXPR
+        && TREE_OPERAND (TREE_OPERAND (instance, 0), 0) == error_mark_node);
+
+      if (TREE_CODE (instance) == OFFSET_REF)
+       instance = resolve_offset_ref (instance);
+
+      /* the base type of an instance variable is pointer to class */
+      basetype = TREE_TYPE (instance);
+
+      if (TREE_CODE (basetype) == REFERENCE_TYPE)
+       {
+         basetype = TREE_TYPE (basetype);
+         if (! IS_AGGR_TYPE (basetype))
+           goto non_aggr_error;
+         /* Call to convert not needed because we are remaining
+            within the same type.  */
+         instance_ptr = build1 (NOP_EXPR, build_pointer_type (basetype),
+                                instance);
+         inst_ptr_basetype = TYPE_MAIN_VARIANT (basetype);
+       }
+      else
+       {
+         if (! IS_AGGR_TYPE (basetype)
+             && ! (TYPE_LANG_SPECIFIC (basetype)
+                   && (IS_SIGNATURE_POINTER (basetype)
+                       || IS_SIGNATURE_REFERENCE (basetype))))
+           goto non_aggr_error;
+
+         /* If `instance' is a signature pointer/reference and `name' is
+            not a constructor, we are calling a signature member function.
+            In that case set the `basetype' to the signature type.  */
+         if ((IS_SIGNATURE_POINTER (basetype)
+              || IS_SIGNATURE_REFERENCE (basetype))
+             && TYPE_IDENTIFIER (basetype) != name)
+           basetype = SIGNATURE_TYPE (basetype);
+
+         basetype = complete_type (basetype);
+
+         if ((IS_SIGNATURE (basetype)
+              && (instance_ptr = instance))
+             || (lvalue_p (instance)
+                 && (instance_ptr = build_unary_op (ADDR_EXPR, instance, 0)))
+             || (instance_ptr = unary_complex_lvalue (ADDR_EXPR, instance)))
+           {
+             if (instance_ptr == error_mark_node)
+               return error_mark_node;
+           }
+         else if (TREE_CODE (instance) == NOP_EXPR
+                  || TREE_CODE (instance) == CONSTRUCTOR)
+           {
+             /* A cast is not an lvalue.  Initialize a fresh temp
+                with the value we are casting from, and proceed with
+                that temporary.  We can't cast to a reference type,
+                so that simplifies the initialization to something
+                we can manage.  */
+             tree temp = get_temp_name (TREE_TYPE (instance), 0);
+             if (IS_AGGR_TYPE (TREE_TYPE (instance)))
+               expand_aggr_init (temp, instance, 0, flags);
+             else
+               {
+                 store_init_value (temp, instance);
+                 expand_decl_init (temp);
+               }
+             instance = temp;
+             instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
+           }
+         else
+           {
+             if (TREE_CODE (instance) != CALL_EXPR)
+               my_friendly_abort (125);
+             if (TYPE_NEEDS_CONSTRUCTING (basetype))
+               instance = build_cplus_new (basetype, instance);
+             else
+               {
+                 instance = get_temp_name (basetype, 0);
+                 TREE_ADDRESSABLE (instance) = 1;
+               }
+             instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
+           }
+         /* @@ Should we call comp_target_types here?  */
+         if (IS_SIGNATURE (basetype))
+           inst_ptr_basetype = basetype;
+         else
+           inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));
+         if (TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (inst_ptr_basetype))
+           basetype = inst_ptr_basetype;
+         else
+           {
+             instance_ptr = convert (build_pointer_type (basetype), instance_ptr);
+             if (instance_ptr == error_mark_node)
+               return error_mark_node;
+           }
+       }
+
+      /* After converting `instance_ptr' above, `inst_ptr_basetype' was
+        not updated, so we use `basetype' instead.  */
+      if (basetype_path == NULL_TREE
+         && IS_SIGNATURE (basetype))
+       basetype_path = TYPE_BINFO (basetype);
+      else if (basetype_path == NULL_TREE ||
+       BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (inst_ptr_basetype))
+       basetype_path = TYPE_BINFO (inst_ptr_basetype);
+
+      result = build_field_call (basetype_path, instance_ptr, name, parms);
+      if (result)
+       return result;
+
+      if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
+       {
+         if (TREE_SIDE_EFFECTS (instance_ptr))
+           {
+             /* This action is needed because the instance is needed
+                for providing the base of the virtual function table.
+                Without using a SAVE_EXPR, the function we are building
+                may be called twice, or side effects on the instance
+                variable (such as a post-increment), may happen twice.  */
+             instance_ptr = save_expr (instance_ptr);
+             instance = build_indirect_ref (instance_ptr, NULL_PTR);
+           }
+         else if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
+           {
+             /* This happens when called for operator new ().  */
+             instance = build_indirect_ref (instance, NULL_PTR);
+           }
+
+         need_vtbl = maybe_needed;
+       }
+    }
+
+  if (save_name == ctor_identifier)
+    save_name = TYPE_IDENTIFIER (basetype);
+
+  if (TYPE_SIZE (complete_type (basetype)) == 0)
     {
-      int harshness;
+      /* This is worth complaining about, I think.  */
+      cp_error ("cannot lookup method in incomplete type `%T'", basetype);
+      return error_mark_node;
+    }
 
-      if (ttf == void_list_node)
-       break;
+  save_basetype = TYPE_MAIN_VARIANT (basetype);
+
+  parmtypes = default_parm_conversions (parms, &last);
+  if (parmtypes == error_mark_node)
+    {
+      return error_mark_node;
+    }
+
+  if (instance && IS_SIGNATURE (basetype))
+    {
+      /* @@ Should this be the constp/volatilep flags for the optr field
+        of the signature pointer?  */
+      constp = TYPE_READONLY (basetype);
+      volatilep = TYPE_VOLATILE (basetype);
+      parms = tree_cons (NULL_TREE, instance_ptr, parms);
+    }
+  else if (instance)
+    {
+      /* TREE_READONLY (instance) fails for references.  */
+      constp = TYPE_READONLY (TREE_TYPE (TREE_TYPE (instance_ptr)));
+      volatilep = TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (instance_ptr)));
+      parms = tree_cons (NULL_TREE, instance_ptr, parms);
+    }
+  else
+    {
+      /* Raw constructors are always in charge.  */
+      if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
+         && ! (flags & LOOKUP_HAS_IN_CHARGE))
+       {
+         flags |= LOOKUP_HAS_IN_CHARGE;
+         parms = tree_cons (NULL_TREE, integer_one_node, parms);
+         parmtypes = tree_cons (NULL_TREE, integer_type_node, parmtypes);
+       }
+
+      constp = 0;
+      volatilep = 0;
+      instance_ptr = build_int_2 (0, 0);
+      TREE_TYPE (instance_ptr) = build_pointer_type (basetype);
+      parms = tree_cons (NULL_TREE, instance_ptr, parms);
+    }
+
+  parmtypes = tree_cons (NULL_TREE, TREE_TYPE (instance_ptr), parmtypes);
+
+  if (last == NULL_TREE)
+    last = parmtypes;
+
+  /* Look up function name in the structure type definition.  */
+
+  /* FIXME Axe most of this now?  */
+  if ((IDENTIFIER_HAS_TYPE_VALUE (name)
+       && ! IDENTIFIER_OPNAME_P (name)
+       && IS_AGGR_TYPE (IDENTIFIER_TYPE_VALUE (name)))
+      || name == constructor_name (basetype)
+      || name == ctor_identifier)
+    {
+      tree tmp = NULL_TREE;
+      if (IDENTIFIER_TYPE_VALUE (name) == basetype
+         || name == constructor_name (basetype)
+         || name == ctor_identifier)
+       tmp = TYPE_BINFO (basetype);
+      else
+       tmp = get_binfo (IDENTIFIER_TYPE_VALUE (name), basetype, 0);
+      
+      if (tmp != NULL_TREE)
+       {
+         name_kind = "constructor";
+         
+         if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
+             && ! (flags & LOOKUP_HAS_IN_CHARGE))
+           {
+             /* Constructors called for initialization
+                only are never in charge.  */
+             tree tmplist;
+             
+             flags |= LOOKUP_HAS_IN_CHARGE;
+             tmplist = tree_cons (NULL_TREE, integer_zero_node,
+                                  TREE_CHAIN (parms));
+             TREE_CHAIN (parms) = tmplist;
+             tmplist = tree_cons (NULL_TREE, integer_type_node, TREE_CHAIN (parmtypes));
+             TREE_CHAIN (parmtypes) = tmplist;
+           }
+         basetype = BINFO_TYPE (tmp);
+       }
+      else
+       name_kind = "method";
+    }
+  else
+    name_kind = "method";
+  
+  if (basetype_path == NULL_TREE
+      || BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (basetype))
+    basetype_path = TYPE_BINFO (basetype);
+  result = lookup_fnfields (basetype_path, name,
+                           (flags & LOOKUP_COMPLAIN));
+  if (result == error_mark_node)
+    return error_mark_node;
+
+  for (pass = 0; pass < 2; pass++)
+    {
+      struct candidate *candidates;
+      struct candidate *cp;
+      int len;
+      unsigned best = 1;
+
+      baselink = result;
+
+      if (pass > 0)
+       {
+         candidates
+           = (struct candidate *) alloca ((ever_seen+1)
+                                          * sizeof (struct candidate));
+         bzero ((char *) candidates, (ever_seen + 1) * sizeof (struct candidate));
+         cp = candidates;
+         len = list_length (parms);
+         ever_seen = 0;
+
+         /* First see if a global function has a shot at it.  */
+         if (flags & LOOKUP_GLOBAL)
+           {
+             tree friend_parms;
+             tree parm = instance_ptr;
+
+             if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE)
+               parm = convert_from_reference (parm);
+             else if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
+               parm = build_indirect_ref (parm, "friendifying parms (compiler error)");
+             else
+               my_friendly_abort (167);
+
+             friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
+
+             cp->h_len = len;
+             cp->harshness = (struct harshness_code *)
+               alloca ((len + 1) * sizeof (struct harshness_code));
+
+             result = build_overload_call_real (name, friend_parms, 0, cp, 1);
+
+             /* If it turns out to be the one we were actually looking for
+                (it was probably a friend function), the return the
+                good result.  */
+             if (TREE_CODE (result) == CALL_EXPR)
+               return result;
+
+             while ((cp->h.code & EVIL_CODE) == 0)
+               {
+                 /* non-standard uses: set the field to 0 to indicate
+                    we are using a non-member function.  */
+                 cp->u.field = 0;
+                 if (cp->harshness[len].distance == 0
+                     && cp->h.code < best)
+                   best = cp->h.code;
+                 cp += 1;
+               }
+           }
+       }
+
+      if (baselink)
+       {
+         /* We have a hit (of sorts). If the parameter list is
+            "error_mark_node", or some variant thereof, it won't
+            match any methods.  Since we have verified that the is
+            some method vaguely matching this one (in name at least),
+            silently return.
+            
+            Don't stop for friends, however.  */
+         basetype_path = TREE_PURPOSE (baselink);
+
+         function = TREE_VALUE (baselink);
+         if (TREE_CODE (basetype_path) == TREE_LIST)
+           basetype_path = TREE_VALUE (basetype_path);
+         basetype = BINFO_TYPE (basetype_path);
+
+         for (; function; function = DECL_CHAIN (function))
+           {
+#ifdef GATHER_STATISTICS
+             n_inner_fields_searched++;
+#endif
+             ever_seen++;
+             if (pass > 0)
+               found_fns = tree_cons (NULL_TREE, function, found_fns);
+
+             /* Not looking for friends here.  */
+             if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE
+                 && ! DECL_STATIC_FUNCTION_P (function))
+               continue;
+
+             if (pass > 0)
+               {
+                 tree these_parms = parms;
+
+#ifdef GATHER_STATISTICS
+                 n_inner_fields_searched++;
+#endif
+                 cp->h_len = len;
+                 cp->harshness = (struct harshness_code *)
+                   alloca ((len + 1) * sizeof (struct harshness_code));
+
+                 if (DECL_STATIC_FUNCTION_P (function))
+                   these_parms = TREE_CHAIN (these_parms);
+                 compute_conversion_costs (function, these_parms, cp, len);
+
+                 if ((cp->h.code & EVIL_CODE) == 0)
+                   {
+                     cp->u.field = function;
+                     cp->function = function;
+                     cp->basetypes = basetype_path;
+
+                     /* Don't allow non-converting constructors to convert.  */
+                     if (flags & LOOKUP_ONLYCONVERTING
+                         && DECL_LANG_SPECIFIC (function)
+                         && DECL_NONCONVERTING_P (function))
+                       continue;
+
+                     /* No "two-level" conversions.  */
+                     if (flags & LOOKUP_NO_CONVERSION
+                         && (cp->h.code & USER_CODE))
+                       continue;
+
+                     cp++;
+                   }
+               }
+           }
+       }
+
+      if (pass == 0)
+       {
+         tree igv = lookup_name_nonclass (name);
+
+         /* No exact match could be found.  Now try to find match
+            using default conversions.  */
+         if ((flags & LOOKUP_GLOBAL) && igv)
+           {
+             if (TREE_CODE (igv) == FUNCTION_DECL)
+               ever_seen += 1;
+             else if (TREE_CODE (igv) == TREE_LIST)
+               ever_seen += count_functions (igv);
+           }
+
+         if (ever_seen == 0)
+           {
+             if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
+                 == LOOKUP_SPECULATIVELY)
+               return NULL_TREE;
+             
+             TREE_CHAIN (last) = void_list_node;
+             if (flags & LOOKUP_GLOBAL)
+               cp_error ("no global or member function `%D(%A)' defined",
+                         save_name, parmtypes);
+             else
+               cp_error ("no member function `%T::%D(%A)' defined",
+                         save_basetype, save_name, TREE_CHAIN (parmtypes));
+             return error_mark_node;
+           }
+         continue;
+       }
+
+      if (cp - candidates != 0)
+       {
+         /* Rank from worst to best.  Then cp will point to best one.
+            Private fields have their bits flipped.  For unsigned
+            numbers, this should make them look very large.
+            If the best alternate has a (signed) negative value,
+            then all we ever saw were private members.  */
+         if (cp - candidates > 1)
+           {
+             int n_candidates = cp - candidates;
+             extern int warn_synth;
+             TREE_VALUE (parms) = instance_ptr;
+             cp = ideal_candidate (candidates, n_candidates, len);
+             if (cp == (struct candidate *)0)
+               {
+                 if (flags & LOOKUP_COMPLAIN)
+                   {
+                     TREE_CHAIN (last) = void_list_node;
+                     cp_error ("call of overloaded %s `%D(%A)' is ambiguous",
+                               name_kind, save_name, TREE_CHAIN (parmtypes));
+                     print_n_candidates (candidates, n_candidates);
+                   }
+                 return error_mark_node;
+               }
+             if (cp->h.code & EVIL_CODE)
+               return error_mark_node;
+             if (warn_synth
+                 && DECL_NAME (cp->function) == ansi_opname[MODIFY_EXPR]
+                 && DECL_ARTIFICIAL (cp->function)
+                 && n_candidates == 2)
+               {
+                 cp_warning ("using synthesized `%#D' for copy assignment",
+                             cp->function);
+                 cp_warning_at ("  where cfront would use `%#D'",
+                                candidates->function);
+               }
+           }
+         else if (cp[-1].h.code & EVIL_CODE)
+           {
+             if (flags & LOOKUP_COMPLAIN)
+               cp_error ("ambiguous type conversion requested for %s `%D'",
+                         name_kind, save_name);
+             return error_mark_node;
+           }
+         else
+           cp--;
 
-      if (type_unknown_p (TREE_VALUE (tta)))
-       {         
-         /* Must perform some instantiation here.  */
-         tree rhs = TREE_VALUE (tta);
-         tree lhstype = TREE_VALUE (ttf);
+         /* The global function was the best, so use it.  */
+         if (cp->u.field == 0)
+           {
+             /* We must convert the instance pointer into a reference type.
+                Global overloaded functions can only either take
+                aggregate objects (which come for free from references)
+                or reference data types anyway.  */
+             TREE_VALUE (parms) = copy_node (instance_ptr);
+             TREE_TYPE (TREE_VALUE (parms)) = build_reference_type (TREE_TYPE (TREE_TYPE (instance_ptr)));
+             return build_function_call (cp->function, parms);
+           }
 
-         /* Keep quiet about possible contravariance violations.  */
-         int old_inhibit_warnings = inhibit_warnings;
-         inhibit_warnings = 1;
+         function = cp->function;
+         basetype_path = cp->basetypes;
+         if (! DECL_STATIC_FUNCTION_P (function))
+           TREE_VALUE (parms) = cp->arg;
+         goto found_and_maybe_warn;
+       }
 
-         /* @@ This is to undo what `grokdeclarator' does to
-            parameter types.  It really should go through
-            something more general.  */
+      if (flags & (LOOKUP_COMPLAIN|LOOKUP_SPECULATIVELY))
+       {
+         if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
+             == LOOKUP_SPECULATIVELY)
+           return NULL_TREE;
 
-         TREE_TYPE (tta) = unknown_type_node;
-         rhs = instantiate_type (lhstype, rhs, 0);
-         inhibit_warnings = old_inhibit_warnings;
+         if (DECL_STATIC_FUNCTION_P (cp->function))
+           parms = TREE_CHAIN (parms);
+         if (ever_seen)
+           {
+             if (flags & LOOKUP_SPECULATIVELY)
+               return NULL_TREE;
+             if (static_call_context
+                 && TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
+               cp_error ("object missing in call to `%D'", cp->function);
+             else if (ever_seen > 1)
+               {
+                 TREE_CHAIN (last) = void_list_node;
+                 cp_error ("no matching function for call to `%T::%D (%A)%V'",
+                           TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (instance_ptr))),
+                           save_name, TREE_CHAIN (parmtypes),
+                           TREE_TYPE (TREE_TYPE (instance_ptr)));
+                 TREE_CHAIN (last) = NULL_TREE;
+                 print_candidates (found_fns);
+               }
+             else
+               report_type_mismatch (cp, parms, name_kind);
+             return error_mark_node;
+           }
 
-         if (TREE_CODE (rhs) == ERROR_MARK)
-           harshness = 1;
-         else
+         if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
+             == LOOKUP_COMPLAIN)
            {
-             harshness = convert_harshness_old (lhstype, TREE_TYPE (rhs),
-                                                rhs);
-             /* harshness |= 2; */
+             cp_error ("%T has no method named %D", save_basetype, save_name);
+             return error_mark_node;
            }
+         return NULL_TREE;
        }
-      else
-       harshness = convert_harshness_old (TREE_VALUE (ttf),
-                                          TREE_TYPE (TREE_VALUE (tta)),
-                                          TREE_VALUE (tta));
+      continue;
 
-      cp->v.old_harshness[strike_index] = harshness;
-      if (EVIL_HARSHNESS (harshness)
-         || CONTRAVARIANT_HARSHNESS (harshness))
+    found_and_maybe_warn:
+      if ((cp->harshness[0].code & CONST_CODE)
+         /* 12.1p2: Constructors can be called for const objects.  */
+         && ! DECL_CONSTRUCTOR_P (cp->function))
        {
-         cp->u.bad_arg = strike_index;
-         evil_strikes = 1;
+         if (flags & LOOKUP_COMPLAIN)
+           {
+             cp_error_at ("non-const member function `%D'", cp->function);
+             error ("called for const object at this point in file");
+           }
+         /* Not good enough for a match.  */
+         else
+           return error_mark_node;
        }
-     else if (ELLIPSIS_HARSHNESS (harshness))
+      goto found;
+    }
+  /* Silently return error_mark_node.  */
+  return error_mark_node;
+
+ found:
+  if (flags & LOOKUP_PROTECT)
+    access = compute_access (basetype_path, function);
+
+  if (access == access_private_node)
+    {
+      if (flags & LOOKUP_COMPLAIN)
        {
-         ellipsis_strikes += 1;
+         cp_error_at ("%s `%+#D' is %s", name_kind, function, 
+                      TREE_PRIVATE (function) ? "private"
+                      : "from private base class");
+         error ("within this context");
        }
-#if 0
-      /* This is never set by `convert_harshness_old'.  */
-      else if (USER_HARSHNESS (harshness))
+      return error_mark_node;
+    }
+  else if (access == access_protected_node)
+    {
+      if (flags & LOOKUP_COMPLAIN)
        {
-         user_strikes += 1;
+         cp_error_at ("%s `%+#D' %s", name_kind, function,
+                      TREE_PROTECTED (function) ? "is protected"
+                      : "has protected accessibility");
+         error ("within this context");
        }
-#endif
-      else if (BASE_DERIVED_HARSHNESS (harshness))
+      return error_mark_node;
+    }
+
+  /* From here on down, BASETYPE is the type that INSTANCE_PTR's
+     type (if it exists) is a pointer to.  */
+
+  if (DECL_ABSTRACT_VIRTUAL_P (function)
+      && instance == current_class_ref
+      && DECL_CONSTRUCTOR_P (current_function_decl)
+      && ! (flags & LOOKUP_NONVIRTUAL)
+      && value_member (function, get_abstract_virtuals (basetype)))
+    cp_error ("abstract virtual `%#D' called from constructor", function);
+
+  if (IS_SIGNATURE (basetype))
+    {
+      if (static_call_context)
        {
-         b_or_d_strikes += INT_FROM_BD_HARSHNESS (harshness);
+         cp_error ("cannot call signature member function `%T::%D' without signature pointer/reference",
+                   basetype, save_name);
+         return error_mark_node;
        }
+      return build_signature_method_call (function, parms);
+    }
+
+  function = DECL_MAIN_VARIANT (function);
+  mark_used (function);
+
+  fntype = TREE_TYPE (function);
+  if (TREE_CODE (fntype) == POINTER_TYPE)
+    fntype = TREE_TYPE (fntype);
+  basetype = DECL_CLASS_CONTEXT (function);
+
+  /* If we are referencing a virtual function from an object
+     of effectively static type, then there is no need
+     to go through the virtual function table.  */
+  if (need_vtbl == maybe_needed)
+    {
+      int fixed_type = resolves_to_fixed_type_p (instance, 0);
+
+      if (all_virtual == 1
+         && DECL_VINDEX (function)
+         && may_be_remote (basetype))
+       need_vtbl = needed;
+      else if (DECL_VINDEX (function))
+       need_vtbl = fixed_type ? unneeded : needed;
       else
-       easy_strikes += INT_FROM_EASY_HARSHNESS (harshness);
-      ttf = TREE_CHAIN (ttf);
-      tta = TREE_CHAIN (tta);
-      strike_index += 1;
+       need_vtbl = not_needed;
     }
 
-  if (tta)
+  if (TREE_CODE (fntype) == METHOD_TYPE && static_call_context
+      && !DECL_CONSTRUCTOR_P (function))
     {
-      /* ran out of formals, and parmlist is fixed size.  */
-      if (ttf /* == void_type_node */)
+      /* Let's be nasty to the user now, and give reasonable
+        error messages.  */
+      instance_ptr = current_class_ptr;
+      if (instance_ptr)
        {
-         cp->evil = 1;
-         cp->u.bad_arg = -1;
-         return;
+         if (basetype != current_class_type)
+           {
+             if (basetype == error_mark_node)
+               return error_mark_node;
+             else 
+                {
+                 if (orig_basetype != NULL_TREE)
+                   error_not_base_type (orig_basetype, current_class_type);
+                 else
+                   error_not_base_type (function, current_class_type);
+                  return error_mark_node;
+                }
+           }
+       }
+      /* Only allow a static member function to call another static member
+        function.  */
+      else if (DECL_LANG_SPECIFIC (function)
+              && !DECL_STATIC_FUNCTION_P (function))
+       {
+         cp_error ("cannot call member function `%D' without object",
+                   function);
+         return error_mark_node;
        }
-      else ellipsis_strikes += list_length (tta);
     }
-  else if (ttf && ttf != void_list_node)
+
+  value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
+
+  if (TYPE_SIZE (complete_type (value_type)) == 0)
     {
-      /* ran out of actuals, and no defaults.  */
-      if (TREE_PURPOSE (ttf) == NULL_TREE)
+      if (flags & LOOKUP_COMPLAIN)
+       incomplete_type_error (0, value_type);
+      return error_mark_node;
+    }
+
+  if (DECL_STATIC_FUNCTION_P (function))
+    parms = convert_arguments (NULL_TREE, TYPE_ARG_TYPES (fntype),
+                              TREE_CHAIN (parms), function, LOOKUP_NORMAL);
+  else if (need_vtbl == unneeded)
+    {
+      int sub_flags = DECL_CONSTRUCTOR_P (function) ? flags : LOOKUP_NORMAL;
+      basetype = TREE_TYPE (instance);
+      if (TYPE_METHOD_BASETYPE (TREE_TYPE (function))
+         != TYPE_MAIN_VARIANT (basetype))
        {
-         cp->evil = 1;
-         cp->u.bad_arg = -2;
-         return;
+         basetype = DECL_CLASS_CONTEXT (function);
+         instance_ptr = convert_pointer_to (basetype, instance_ptr);
+         instance = build_indirect_ref (instance_ptr, NULL_PTR);
        }
-      /* Store index of first default.  */
-      cp->v.old_harshness[arglen] = strike_index+1;
+      parms = tree_cons (NULL_TREE, instance_ptr,
+                        convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), function, sub_flags));
     }
   else
-    cp->v.old_harshness[arglen] = 0;
+    {
+      if ((flags & LOOKUP_NONVIRTUAL) == 0)
+       basetype = DECL_CONTEXT (function);
 
-  /* Argument list lengths work out, so don't need to check them again.  */
-  if (evil_strikes)
+      /* First parm could be integer_zerop with casts like
+        ((Object*)0)->Object::IsA()  */
+      if (!integer_zerop (TREE_VALUE (parms)))
+       {
+         /* Since we can't have inheritance with a union, doing get_binfo
+            on it won't work.  We do all the convert_pointer_to_real
+            stuff to handle MI correctly...for unions, that's not
+            an issue, so we must short-circuit that extra work here.  */
+         tree tmp = TREE_TYPE (TREE_TYPE (TREE_VALUE (parms)));
+         if (tmp != NULL_TREE && TREE_CODE (tmp) == UNION_TYPE)
+           instance_ptr = TREE_VALUE (parms);
+         else
+           {
+             tree binfo = get_binfo (basetype,
+                                     TREE_TYPE (TREE_TYPE (TREE_VALUE (parms))),
+                                     0);
+             instance_ptr = convert_pointer_to_real (binfo, TREE_VALUE (parms));
+           }
+         instance_ptr
+           = convert_pointer_to (build_type_variant (basetype,
+                                                     constp, volatilep),
+                                 instance_ptr);
+
+         if (TREE_CODE (instance_ptr) == COND_EXPR)
+           {
+             instance_ptr = save_expr (instance_ptr);
+             instance = build_indirect_ref (instance_ptr, NULL_PTR);
+           }
+         else if (TREE_CODE (instance_ptr) == NOP_EXPR
+                  && TREE_CODE (TREE_OPERAND (instance_ptr, 0)) == ADDR_EXPR
+                  && TREE_OPERAND (TREE_OPERAND (instance_ptr, 0), 0) == instance)
+           ;
+         /* The call to `convert_pointer_to' may return error_mark_node.  */
+         else if (TREE_CODE (instance_ptr) == ERROR_MARK)
+           return instance_ptr;
+         else if (instance == NULL_TREE
+                  || TREE_CODE (instance) != INDIRECT_REF
+                  || TREE_OPERAND (instance, 0) != instance_ptr)
+           instance = build_indirect_ref (instance_ptr, NULL_PTR);
+       }
+      parms = tree_cons (NULL_TREE, instance_ptr,
+                        convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), function, LOOKUP_NORMAL));
+    }
+
+  if (parms == error_mark_node
+      || (parms && TREE_CHAIN (parms) == error_mark_node))
+    return error_mark_node;
+
+  if (need_vtbl == needed)
     {
-      /* We do not check for derived->base conversions here, since in
-        no case would they give evil strike counts, unless such conversions
-        are somehow ambiguous.  */
+      function = build_vfn_ref (&TREE_VALUE (parms), instance,
+                               DECL_VINDEX (function));
+      TREE_TYPE (function) = build_pointer_type (fntype);
+    }
 
-      /* See if any user-defined conversions apply.
-         But make sure that we do not loop.  */
-      static int dont_convert_types = 0;
+  if (TREE_CODE (function) == FUNCTION_DECL)
+    GNU_xref_call (current_function_decl,
+                  IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)));
+
+  result = build_call (function, value_type, parms);
+  if (IS_AGGR_TYPE (value_type))
+    result = build_cplus_new (value_type, result);
+  result = convert_from_reference (result);
+  return result;
+}
 
-      if (dont_convert_types)
-       {
-         cp->evil = 1;
-         return;
-       }
+/* Similar to `build_method_call', but for overloaded non-member functions.
+   The name of this function comes through NAME.  The name depends
+   on PARMS.
 
-      win = 0;                 /* Only get one chance to win.  */
-      ttf = TYPE_ARG_TYPES (TREE_TYPE (function));
-      tta = tta_in;
-      strike_index = 0;
-      evil_strikes = 0;
+   Note that this function must handle simple `C' promotions,
+   as well as variable numbers of arguments (...), and
+   default arguments to boot.
 
-      while (ttf && tta)
-       {
-         if (ttf == void_list_node)
-           break;
+   If the overloading is successful, we return a tree node which
+   contains the call to the function.
 
-         lose = cp->v.old_harshness[strike_index];
-         if (EVIL_HARSHNESS (lose)
-             || CONTRAVARIANT_HARSHNESS (lose))
-           {
-             tree actual_type = TREE_TYPE (TREE_VALUE (tta));
-             tree formal_type = TREE_VALUE (ttf);
+   If overloading produces candidates which are probable, but not definite,
+   we hold these candidates.  If FINAL_CP is non-zero, then we are free
+   to assume that final_cp points to enough storage for all candidates that
+   this function might generate.  The `harshness' array is preallocated for
+   the first candidate, but not for subsequent ones.
 
-             dont_convert_types = 1;
+   Note that the DECL_RTL of FUNCTION must be made to agree with this
+   function's new name.  */
 
-             if (TREE_CODE (formal_type) == REFERENCE_TYPE)
-               formal_type = TREE_TYPE (formal_type);
-             if (TREE_CODE (actual_type) == REFERENCE_TYPE)
-               actual_type = TREE_TYPE (actual_type);
+tree
+build_overload_call_real (fnname, parms, flags, final_cp, require_complete)
+     tree fnname, parms;
+     int flags;
+     struct candidate *final_cp;
+     int require_complete;
+{
+  /* must check for overloading here */
+  tree functions, function, parm;
+  tree parmtypes, last;
+  register tree outer;
+  int length;
+  int parmlength = list_length (parms);
 
-             if (formal_type != error_mark_node
-                 && actual_type != error_mark_node)
-               {
-                 formal_type = TYPE_MAIN_VARIANT (formal_type);
-                 actual_type = TYPE_MAIN_VARIANT (actual_type);
+  struct candidate *candidates, *cp;
 
-                 if (TYPE_HAS_CONSTRUCTOR (formal_type))
-                   {
-                     /* If it has a constructor for this type, try to use it.  */
-                     if (convert_to_aggr (formal_type, TREE_VALUE (tta), 0, 1)
-                         != error_mark_node)
-                       {
-                         /* @@ There is no way to save this result yet.
-                            @@ So success is NULL_TREE for now.  */
-                         win++;
-                       }
-                   }
-                 if (TYPE_LANG_SPECIFIC (actual_type) && TYPE_HAS_CONVERSION (actual_type))
-                   {
-                     if (TREE_CODE (formal_type) == INTEGER_TYPE
-                         && TYPE_HAS_INT_CONVERSION (actual_type))
-                       win++;
-                     else if (TREE_CODE (formal_type) == REAL_TYPE
-                              && TYPE_HAS_REAL_CONVERSION (actual_type))
-                       win++;
-                     else
-                       {
-                         tree conv = build_type_conversion (CALL_EXPR, TREE_VALUE (ttf), TREE_VALUE (tta), 0);
-                         if (conv)
-                           {
-                             if (conv == error_mark_node)
-                               win += 2;
-                             else
-                               win++;
-                           }
-                         else if (TREE_CODE (TREE_VALUE (ttf)) == REFERENCE_TYPE)
-                           {
-                             conv = build_type_conversion (CALL_EXPR, formal_type, TREE_VALUE (tta), 0);
-                             if (conv)
-                               {
-                                 if (conv == error_mark_node)
-                                   win += 2;
-                                 else
-                                   win++;
-                               }
-                           }
-                       }
-                   }
-               }
-             dont_convert_types = 0;
+  if (final_cp)
+    {
+      final_cp[0].h.code = 0;
+      final_cp[0].h.distance = 0;
+      final_cp[0].function = 0;
+      /* end marker.  */
+      final_cp[1].h.code = EVIL_CODE;
+    }
 
-             if (win == 1)
-               {
-                 user_strikes += 1;
-                 cp->v.old_harshness[strike_index] = USER_HARSHNESS (-1);
-                 win = 0;
-               }
-             else
-               {
-                 if (cp->u.bad_arg > strike_index)
-                   cp->u.bad_arg = strike_index;
+  parmtypes = default_parm_conversions (parms, &last);
+  if (parmtypes == error_mark_node)
+    {
+      if (final_cp)
+       final_cp->h.code = EVIL_CODE;
+      return error_mark_node;
+    }
 
-                 evil_strikes = win ? 2 : 1;
-                 break;
-               }
-           }
+  if (last)
+    TREE_CHAIN (last) = void_list_node;
+  else
+    parmtypes = void_list_node;
 
-         ttf = TREE_CHAIN (ttf);
-         tta = TREE_CHAIN (tta);
-         strike_index += 1;
-       }
+  if (is_overloaded_fn (fnname))
+    {
+      functions = fnname;
+      if (TREE_CODE (fnname) == TREE_LIST)
+       fnname = TREE_PURPOSE (functions);
+      else if (TREE_CODE (fnname) == FUNCTION_DECL)
+       fnname = DECL_NAME (functions);
     }
+  else 
+    functions = lookup_name_nonclass (fnname);
 
-  /* Const member functions get a small penalty because defaulting
-     to const is less useful than defaulting to non-const. */
-  /* This is bogus, it does not correspond to anything in the ARM.
-     This code will be fixed when this entire section is rewritten
-     to conform to the ARM.  (mrs)  */
-  if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
+  if (functions == NULL_TREE)
     {
-      tree this_parm = TREE_VALUE (ttf_in);
+      if (flags & LOOKUP_SPECULATIVELY)
+       return NULL_TREE;
+      if (flags & LOOKUP_COMPLAIN)
+       error ("only member functions apply");
+      if (final_cp)
+       final_cp->h.code = EVIL_CODE;
+      return error_mark_node;
+    }
 
-      if (TREE_CODE (this_parm) == RECORD_TYPE /* Is `this' a sig ptr?  */
-           ? TYPE_READONLY (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (this_parm))))
-           : TYPE_READONLY (TREE_TYPE (this_parm)))
+  if (TREE_CODE (functions) == FUNCTION_DECL && ! IDENTIFIER_OPNAME_P (fnname))
+    {
+      functions = DECL_MAIN_VARIANT (functions);
+      if (final_cp)
        {
-         cp->v.old_harshness[0] += INT_TO_EASY_HARSHNESS (1);
-         ++easy_strikes;
+         /* We are just curious whether this is a viable alternative or
+             not.  */
+         compute_conversion_costs (functions, parms, final_cp, parmlength);
+         return functions;
        }
       else
-       {
-         /* Calling a non-const member function from a const member function
-            is probably invalid, but for now we let it only draw a warning.
-            We indicate that such a mismatch has occurred by setting the
-            harshness to a maximum value.  */
-         if (TREE_CODE (TREE_TYPE (TREE_VALUE (tta_in))) == POINTER_TYPE
-             && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (TREE_VALUE (tta_in))))))
-           cp->v.old_harshness[0] |= CONST_HARSHNESS (-1);
-       }
+       return build_function_call_real (functions, parms, 1, flags);
     }
 
-  cp->evil = evil_strikes;
-  cp->ellipsis = ellipsis_strikes;
-  cp->user = user_strikes;
-  cp->b_or_d = b_or_d_strikes;
-  cp->easy = easy_strikes;
-}
+  if (TREE_CODE (functions) == TREE_LIST
+      && TREE_VALUE (functions) == NULL_TREE)
+    {
+      if (flags & LOOKUP_SPECULATIVELY)
+       return NULL_TREE;
+      
+      if (flags & LOOKUP_COMPLAIN)
+       cp_error ("function `%D' declared overloaded, but no instances of that function declared",
+                 TREE_PURPOSE (functions));
+      if (final_cp)
+       final_cp->h.code = EVIL_CODE;
+      return error_mark_node;
+    }
 
-void
-compute_conversion_costs (function, tta_in, cp, arglen)
-     tree function;
-     tree tta_in;
-     struct candidate *cp;
-     int arglen;
-{
-  if (flag_ansi_overloading)
-    compute_conversion_costs_ansi (function, tta_in, cp, arglen);
+  length = count_functions (functions);
+  
+  if (final_cp)
+    candidates = final_cp;
   else
-    compute_conversion_costs_old (function, tta_in, cp, arglen);
-}
+    {
+      candidates
+       = (struct candidate *)alloca ((length+1) * sizeof (struct candidate));
+      bzero ((char *) candidates, (length + 1) * sizeof (struct candidate));
+    }
 
-/* When one of several possible overloaded functions and/or methods
-   can be called, choose the best candidate for overloading.
+  cp = candidates;
 
-   BASETYPE is the context from which we start method resolution
-   or NULL if we are comparing overloaded functions.
-   CANDIDATES is the array of candidates we have to choose from.
-   N_CANDIDATES is the length of CANDIDATES.
-   PARMS is a TREE_LIST of parameters to the function we'll ultimately
-   choose.  It is modified in place when resolving methods.  It is not
-   modified in place when resolving overloaded functions.
-   LEN is the length of the parameter list.  */
+  my_friendly_assert (is_overloaded_fn (functions), 169);
 
-static struct candidate *
-ideal_candidate_old (basetype, candidates, n_candidates, parms, len)
-     tree basetype;
-     struct candidate *candidates;
-     int n_candidates;
-     tree parms;
-     int len;
-{
-  struct candidate *cp = candidates + n_candidates;
-  int index, i;
-  tree ttf;
-
-  qsort (candidates,           /* char *base */
-        n_candidates,          /* int nel */
-        sizeof (struct candidate), /* int width */
-        rank_for_overload);    /* int (*compar)() */
-
-  /* If the best candidate requires user-defined conversions,
-     and its user-defined conversions are a strict subset
-     of all other candidates requiring user-defined conversions,
-     then it is, in fact, the best.  */
-  for (i = -1; cp + i != candidates; i--)
-    if (cp[i].user == 0)
-      break;
+  functions = get_first_fn (functions);
 
-  if (i < -1)
+  /* OUTER is the list of FUNCTION_DECLS, in a TREE_LIST.  */
+  for (outer = functions; outer; outer = DECL_CHAIN (outer))
     {
-      tree ttf0;
-
-      /* Check that every other candidate requires those conversions
-        as a strict subset of their conversions.  */
-      if (cp[i].user == cp[-1].user)
-       goto non_subset;
-
-      /* Look at subset relationship more closely.  */
-      while (i != -1)
+      int template_cost = 0;
+      function = outer;
+      if (TREE_CODE (function) != FUNCTION_DECL
+         && ! (TREE_CODE (function) == TEMPLATE_DECL
+               && TREE_CODE (DECL_TEMPLATE_RESULT (function)) == FUNCTION_DECL))
        {
-         for (ttf = TYPE_ARG_TYPES (TREE_TYPE (cp[i].function)),
-              ttf0 = TYPE_ARG_TYPES (TREE_TYPE (cp[-1].function)),
-              index = 0; index < len; index++)
+         enum tree_code code = TREE_CODE (function);
+         if (code == TEMPLATE_DECL)
+           code = TREE_CODE (DECL_TEMPLATE_RESULT (function));
+         if (code == CONST_DECL)
+           cp_error_at
+             ("enumeral value `%D' conflicts with function of same name",
+              function);
+         else if (code == VAR_DECL)
            {
-             if (USER_HARSHNESS (cp[i].v.old_harshness[index]))
-               {
-                 /* If our "best" candidate also needs a conversion,
-                    it must be the same one.  */
-                 if (USER_HARSHNESS (cp[-1].v.old_harshness[index])
-                     && TREE_VALUE (ttf) != TREE_VALUE (ttf0))
-                   goto non_subset;
-               }
-             ttf = TREE_CHAIN (ttf);
-             ttf0 = TREE_CHAIN (ttf0);
-             /* Handle `...' gracefully.  */
-             if (ttf == NULL_TREE || ttf0 == NULL_TREE)
-               break;
+             if (TREE_STATIC (function))
+               cp_error_at
+                 ("variable `%D' conflicts with function of same name",
+                  function);
+             else
+               cp_error_at
+                 ("constant field `%D' conflicts with function of same name",
+                  function);
            }
-         i++;
-       }
-      /* The best was the best.  */
-      return cp - 1;
-    non_subset:
-      /* Use other rules for determining "bestness".  */
-      ;
-    }
-
-  /* If the best two candidates we find require user-defined
-     conversions, we may need to report and error message.  */
-  if (cp[-1].user && cp[-2].user
-      && (cp[-1].b_or_d || cp[-2].b_or_d == 0))
-    {
-      /* If the best two methods found involved user-defined
-        type conversions, then we must see whether one
-        of them is exactly what we wanted.  If not, then
-        we have an ambiguity.  */
-      int best = 0;
-      tree tta = parms;
-      tree f1;
-#if 0
-      /* for LUCID */
-      tree p1;
-#endif
-
-      /* Stash all of our parameters in safe places
-        so that we can perform type conversions in place.  */
-      while (tta)
-       {
-         TREE_PURPOSE (tta) = TREE_VALUE (tta);
-         tta = TREE_CHAIN (tta);
+         else if (code == TYPE_DECL)
+           continue;
+         else
+           my_friendly_abort (2);
+         error ("at this point in file");
+         continue;
        }
-
-      i = 0;
-      do
+      if (TREE_CODE (function) == TEMPLATE_DECL)
        {
-         int exact_conversions = 0;
+         int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (function));
+         tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
+         int i;
 
-         i -= 1;
-         tta = parms;
-         if (DECL_STATIC_FUNCTION_P (cp[i].function))
-           tta = TREE_CHAIN (tta);
-         /* special note, we don't go through len parameters, because we
-            may only need len-1 parameters because of a call to a static
-            member. */
-         for (ttf = TYPE_ARG_TYPES (TREE_TYPE (cp[i].function)), index = 0;
-              tta;
-              tta = TREE_CHAIN (tta), ttf = TREE_CHAIN (ttf), index++)
+         i = type_unification (DECL_TEMPLATE_PARMS (function), targs,
+                               TYPE_ARG_TYPES (TREE_TYPE (function)),
+                               parms, &template_cost, 0, 0);
+         if (i == 0)
            {
-             /* If this is a varargs function, there's no conversion to do,
-                but don't accept an arg that needs a copy ctor.  */
-             if (ttf == NULL_TREE)
-               {
-                 /* FIXME: verify that we cannot get here with an
-                    arg that needs a ctor.  */
-                 break;
-               }
-
-             if (USER_HARSHNESS (cp[i].v.old_harshness[index]))
-               {
-                 tree this_parm = build_type_conversion (CALL_EXPR, TREE_VALUE (ttf), TREE_PURPOSE (tta), 2);
-                 if (basetype != NULL_TREE)
-                   TREE_VALUE (tta) = this_parm;
-                 if (this_parm)
-                   {
-                     if (TREE_CODE (this_parm) != CONVERT_EXPR
-                         && (TREE_CODE (this_parm) != NOP_EXPR
-                             || comp_target_types (TREE_TYPE (this_parm),
-                                                   TREE_TYPE (TREE_OPERAND (this_parm, 0)), 1)))
-                       exact_conversions += 1;
-                   }
-                 else if (PROMOTES_TO_AGGR_TYPE (TREE_VALUE (ttf), REFERENCE_TYPE))
-                   {
-                     /* To get here we had to have succeeded via
-                        a constructor.  */
-                     TREE_VALUE (tta) = TREE_PURPOSE (tta);
-                     exact_conversions += 1;
-                   }
-               }
+             function = instantiate_template (function, targs);
+             if (function == error_mark_node)
+               return function;
            }
-         if (exact_conversions == cp[i].user)
-           {
-             if (best == 0)
-               {
-                 best = i;
-                 f1 = cp[best].function;
-#if 0
-                 /* For LUCID */
-                 p1 = TYPE_ARG_TYPES (TREE_TYPE (f1));
-#endif
-               }
-             else
-               {
-                 /* Don't complain if next best is from base class.  */
-                 tree f2 = cp[i].function;
+       }
+
+      if (TREE_CODE (function) == TEMPLATE_DECL)
+       {
+         /* Unconverted template -- failed match.  */
+         cp->function = function;
+         cp->u.bad_arg = -4;
+         cp->h.code = EVIL_CODE;
+       }
+      else
+       {
+         struct candidate *cp2;
+
+         /* Check that this decl is not the same as a function that's in
+            the list due to some template instantiation.  */
+         cp2 = candidates;
+         while (cp2 != cp)
+           if (cp2->function == function)
+             break;
+           else
+             cp2 += 1;
+         if (cp2->function == function)
+           continue;
 
-                 if (TREE_CODE (TREE_TYPE (f1)) == METHOD_TYPE
-                     && TREE_CODE (TREE_TYPE (f2)) == METHOD_TYPE
-                     && BASE_DERIVED_HARSHNESS (cp[i].v.old_harshness[0])
-                     && cp[best].v.old_harshness[0] < cp[i].v.old_harshness[0])
-                   {
-#if 0
-                     tree p2 = TYPE_ARG_TYPES (TREE_TYPE (f2));
-                     /* For LUCID.  */
-                     if (! compparms (TREE_CHAIN (p1), TREE_CHAIN (p2), 1))
-                       goto ret0;
-                     else
-#endif
-                       continue;
-                   }
-                 else
-                   {
-                     /* Ensure that there's nothing ambiguous about these
-                        two fns.  */
-                     int identical = 1;
-                     for (index = 0; index < len; index++)
-                       {
-                         /* Type conversions must be piecewise equivalent.  */
-                         if (USER_HARSHNESS (cp[best].v.old_harshness[index])
-                             != USER_HARSHNESS (cp[i].v.old_harshness[index]))
-                           goto ret0;
-                         /* If there's anything we like better about the
-                            other function, consider it ambiguous.  */
-                         if (cp[i].v.old_harshness[index] < cp[best].v.old_harshness[index])
-                           goto ret0;
-                         /* If any single one it diffent, then the whole is
-                            not identical.  */
-                         if (cp[i].v.old_harshness[index] != cp[best].v.old_harshness[index])
-                           identical = 0;
-                       }
+         function = DECL_MAIN_VARIANT (function);
 
-                     /* If we can't tell the difference between the two, it
-                        is ambiguous.  */
-                     if (identical)
-                       goto ret0;
+         /* Can't use alloca here, since result might be
+            passed to calling function.  */
+         cp->h_len = parmlength;
+         cp->harshness = (struct harshness_code *)
+           oballoc ((parmlength + 1) * sizeof (struct harshness_code));
 
-                     /* If we made it to here, it means we're satisfied that
-                        BEST is still best.  */
-                     continue;
-                   }
-               }
-           }
-       } while (cp + i != candidates);
+         compute_conversion_costs (function, parms, cp, parmlength);
 
-      if (best)
-       {
-         int exact_conversions = cp[best].user;
-         tta = parms;
-         if (DECL_STATIC_FUNCTION_P (cp[best].function))
-           tta = TREE_CHAIN (parms);
-         for (ttf = TYPE_ARG_TYPES (TREE_TYPE (cp[best].function)), index = 0;
-              exact_conversions > 0;
-              tta = TREE_CHAIN (tta), ttf = TREE_CHAIN (ttf), index++)
+         /* Make sure this is clear as well.  */
+         cp->h.int_penalty += template_cost;
+
+         if ((cp[0].h.code & EVIL_CODE) == 0)
            {
-             if (USER_HARSHNESS (cp[best].v.old_harshness[index]))
-               {
-                 /* We must now fill in the slot we left behind.
-                    @@ This could be optimized to use the value previously
-                    @@ computed by build_type_conversion in some cases.  */
-                 if (basetype != NULL_TREE)
-                   TREE_VALUE (tta) = convert (TREE_VALUE (ttf), TREE_PURPOSE (tta));
-                 exact_conversions -= 1;
-               }
-             else
-               TREE_VALUE (tta) = TREE_PURPOSE (tta);
+             cp[1].h.code = EVIL_CODE;
+             cp++;
            }
-         return cp + best;
-       }
-      goto ret0;
-    }
-  /* If the best two candidates we find both use default parameters,
-     we may need to report and error.  Don't need to worry if next-best
-     candidate is forced to use user-defined conversion when best is not.  */
-  if (cp[-2].user == 0
-      && cp[-1].v.old_harshness[len] != 0 && cp[-2].v.old_harshness[len] != 0)
-    {
-      tree tt1 = TYPE_ARG_TYPES (TREE_TYPE (cp[-1].function));
-      tree tt2 = TYPE_ARG_TYPES (TREE_TYPE (cp[-2].function));
-      unsigned i = cp[-1].v.old_harshness[len];
-
-      if (cp[-2].v.old_harshness[len] < i)
-       i = cp[-2].v.old_harshness[len];
-      while (--i > 0)
-       {
-         if (TYPE_MAIN_VARIANT (TREE_VALUE (tt1))
-             != TYPE_MAIN_VARIANT (TREE_VALUE (tt2)))
-           /* These lists are not identical, so we can choose our best candidate.  */
-           return cp - 1;
-         tt1 = TREE_CHAIN (tt1);
-         tt2 = TREE_CHAIN (tt2);
        }
-      /* To get here, both lists had the same parameters up to the defaults
-        which were used.  This is an ambiguous request.  */
-      goto ret0;
     }
 
-  /* Otherwise, return our best candidate.  Note that if we get candidates
-     from independent base classes, we have an ambiguity, even if one
-     argument list look a little better than another one.  */
-  if (cp[-1].b_or_d && basetype && TYPE_USES_MULTIPLE_INHERITANCE (basetype))
+  if (cp - candidates)
     {
-      int i = n_candidates - 1, best = i;
-      tree base1 = NULL_TREE;
-
-      if (TREE_CODE (TREE_TYPE (candidates[i].function)) == FUNCTION_TYPE)
-       return cp - 1;
+      tree rval = error_mark_node;
 
-      for (; i >= 0 && candidates[i].user == 0 && candidates[i].evil == 0; i--)
+      /* Leave marker.  */
+      cp[0].h.code = EVIL_CODE;
+      if (cp - candidates > 1)
        {
-         if (TREE_CODE (TREE_TYPE (candidates[i].function)) == METHOD_TYPE)
+         struct candidate *best_cp
+           = ideal_candidate (candidates, cp - candidates, parmlength);
+         if (best_cp == (struct candidate *)0)
            {
-             tree newbase = DECL_CLASS_CONTEXT (candidates[i].function);
-
-             if (base1 != NULL_TREE)
-               {
-                 /* newbase could be a base or a parent of base1 */
-                 if (newbase != base1 && ! UNIQUELY_DERIVED_FROM_P (newbase, base1)
-                     && ! UNIQUELY_DERIVED_FROM_P (base1, newbase))
-                   {
-                     cp_error ("ambiguous request for function from distinct base classes of type `%T'", basetype);
-                     cp_error_at ("  first candidate is `%#D'",
-                                    candidates[best].function);
-                     cp_error_at ("  second candidate is `%#D'",
-                                    candidates[i].function);
-                     cp[-1].evil = 1;
-                     return cp - 1;
-                   }
-               }
-             else
+             if (flags & LOOKUP_COMPLAIN)
                {
-                 best = i;
-                 base1 = newbase;
+                 cp_error ("call of overloaded `%D' is ambiguous", fnname);
+                 print_n_candidates (candidates, cp - candidates);
                }
+             return error_mark_node;
            }
          else
-           return cp - 1;
+           rval = best_cp->function;
        }
-    }
-
-  /* Don't accept a candidate as being ideal if it's indistinguishable
-     from another candidate.  */
-  if (rank_for_overload (cp-1, cp-2) == 0)
-    {
-      /* If the types are distinguishably different (like
-        `long' vs. `unsigned long'), that's ok.  But if they are arbitrarily
-        different, such as `int (*)(void)' vs. `void (*)(int)',
-        that's not ok.  */
-      tree p1 = TYPE_ARG_TYPES (TREE_TYPE (cp[-1].function));
-      tree p2 = TYPE_ARG_TYPES (TREE_TYPE (cp[-2].function));
-      while (p1 && p2)
+      else
        {
-         if (TREE_CODE (TREE_VALUE (p1)) == POINTER_TYPE
-             && TREE_CODE (TREE_TYPE (TREE_VALUE (p1))) == FUNCTION_TYPE
-             && TREE_VALUE (p1) != TREE_VALUE (p2))
-           return NULL;
-         p1 = TREE_CHAIN (p1);
-         p2 = TREE_CHAIN (p2);
+         cp -= 1;
+         if (cp->h.code & EVIL_CODE)
+           {
+             if (flags & LOOKUP_COMPLAIN)
+               error ("type conversion ambiguous");
+           }
+         else
+           rval = cp->function;
        }
-      if (p1 || p2)
-       return NULL;
-    }
 
-  return cp - 1;
+      if (final_cp)
+       return rval;
 
- ret0:
-  /* In the case where there is no ideal candidate, restore
-     TREE_VALUE slots of PARMS from TREE_PURPOSE slots.  */
-  while (parms)
-    {
-      TREE_VALUE (parms) = TREE_PURPOSE (parms);
-      parms = TREE_CHAIN (parms);
+      return build_function_call_real (rval, parms, require_complete, flags);
     }
-  return NULL;
+
+  if (flags & LOOKUP_SPECULATIVELY)
+    return NULL_TREE;
+  
+  if (flags & LOOKUP_COMPLAIN)
+    report_type_mismatch (cp, parms, "function",
+                         decl_as_string (cp->function, 1));
+
+  return error_mark_node;
 }
 
-/* Subroutine of ideal_candidate.  See if X or Y is a better match
-   than the other.  */
-static int
-strictly_better (x, y)
-     unsigned short x, y;
+/* This requires a complete type on the result of the call.  */
+
+tree
+build_overload_call (fnname, parms, flags)
+     tree fnname, parms;
+     int flags;
 {
-  unsigned short xor;
+  return build_overload_call_real (fnname, parms, flags, (struct candidate *)0, 1);
+}
 
-  if (x == y)
-    return 0;
+/* New overloading code.  */
+
+struct z_candidate {
+  tree fn;
+  tree convs;
+  tree second_conv;
+  int viable;
+  tree basetype_path;
+  tree template;
+  struct z_candidate *next;
+};
+
+#define IDENTITY_RANK 0
+#define EXACT_RANK 1
+#define PROMO_RANK 2
+#define STD_RANK 3
+#define PBOOL_RANK 4
+#define USER_RANK 5
+#define ELLIPSIS_RANK 6
+#define BAD_RANK 7
+
+#define ICS_RANK(NODE)                         \
+  (ICS_BAD_FLAG (NODE) ? BAD_RANK   \
+   : ICS_ELLIPSIS_FLAG (NODE) ? ELLIPSIS_RANK  \
+   : ICS_USER_FLAG (NODE) ? USER_RANK          \
+   : ICS_STD_RANK (NODE))
+
+#define ICS_STD_RANK(NODE) TREE_COMPLEXITY (NODE)
+
+#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_FN(NODE) TREE_OPERAND (NODE, 1)
+
+static struct z_candidate * build_user_type_conversion_1 ();
+static tree convert_like ();
+static tree build_over_call ();
+static struct z_candidate * tourney ();
+static void enforce_access ();
 
-  xor = x ^ y;
-  if (xor >= x || xor >= y)
+int
+null_ptr_cst_p (t)
+     tree t;
+{
+  if (t == null_node
+      || integer_zerop (t) && INTEGRAL_TYPE_P (TREE_TYPE (t)))
+    return 1;
+  /* Remove this eventually.  */
+  if (! pedantic && TREE_TYPE (t) == ptr_type_node && integer_zerop (t))
     return 1;
   return 0;
 }
 
-static struct candidate *
-ideal_candidate_ansi (basetype, candidates, n_candidates, parms, len)
-     tree basetype;
-     struct candidate *candidates;
-     int n_candidates;
-     tree parms;
-     int len;
+tree
+build_conv (code, type, from)
+     enum tree_code code;
+     tree type, from;
 {
-  struct candidate *cp = candidates+n_candidates;
-  int i, j = -1, best_code;
-
-  /* For each argument, sort the functions from best to worst for the arg.
-     For each function that's not best for this arg, set its overall
-     harshness to EVIL so that other args won't like it.  The candidate
-     list for the last argument is the intersection of all the best-liked
-     functions.  */
-
-#if 0
-  for (i = 0; i < len; i++)
-    {
-      qsort (candidates, n_candidates, sizeof (struct candidate),
-            rank_for_overload);
-      best_code = cp[-1].h.code;
-
-      /* To find out functions that are worse than that represented
-        by BEST_CODE, we can't just do a comparison like h.code>best_code.
-        The total harshness for the "best" fn may be 8|8 for two args, and
-        the harshness for the next-best may be 8|2.  If we just compared,
-        that would be checking 8>10, which would lead to the next-best
-        being disqualified.  What we actually want to do is get rid
-        of functions that are definitely worse than that represented
-        by best_code, i.e. those which have bits set higher than the
-        highest in best_code.  Sooooo, what we do is clear out everything
-        represented by best_code, and see if we still come up with something
-        higher.  If so (e.g., 8|8 vs 8|16), it'll disqualify it properly.  */
-      for (j = n_candidates-2; j >= 0; j--)
-       if ((candidates[j].h.code & ~best_code) > best_code)
-         candidates[j].h.code = EVIL_CODE;
-    }
-
-  if (cp[-1].h.code & EVIL_CODE)
-    return NULL;
-#else
-  qsort (candidates, n_candidates, sizeof (struct candidate),
-        rank_for_overload);
-  best_code = cp[-1].h.code;
-#endif
-
-  /* If they're at least as good as each other, do an arg-by-arg check.  */
-  if (! strictly_better (cp[-1].h.code, cp[-2].h.code))
+  tree t = build1 (code, type, from);
+  int rank = ICS_STD_RANK (from);
+  switch (code)
     {
-      int better = 0;
-      int worse = 0;
-
-      for (j = 0; j < n_candidates; j++)
-       if (! strictly_better (candidates[j].h.code, best_code))
-         break;
+    case PTR_CONV:
+    case PMEM_CONV:
+    case BASE_CONV:
+    case STD_CONV:
+      if (rank < STD_RANK)
+       rank = STD_RANK;
+      break;
 
-      qsort (candidates+j, n_candidates-j, sizeof (struct candidate),
-            rank_for_ideal);
-      for (i = 0; i < len; i++)
-       {
-         if (cp[-1].v.ansi_harshness[i].code < cp[-2].v.ansi_harshness[i].code)
-           better = 1;
-         else if (cp[-1].v.ansi_harshness[i].code > cp[-2].v.ansi_harshness[i].code)
-           worse = 1;
-         else if (cp[-1].v.ansi_harshness[i].code & STD_CODE)
-           {
-             /* If it involves a standard conversion, let the
-                inheritance lattice be the final arbiter.  */
-             if (cp[-1].v.ansi_harshness[i].distance > cp[-2].v.ansi_harshness[i].distance)
-               worse = 1;
-             else if (cp[-1].v.ansi_harshness[i].distance < cp[-2].v.ansi_harshness[i].distance)
-               better = 1;
-           }
-         else if (cp[-1].v.ansi_harshness[i].code & PROMO_CODE)
-           {
-             /* For integral promotions, take into account a finer
-                granularity for determining which types should be favored
-                over others in such promotions.  */
-             if (cp[-1].v.ansi_harshness[i].int_penalty > cp[-2].v.ansi_harshness[i].int_penalty)
-               worse = 1;
-             else if (cp[-1].v.ansi_harshness[i].int_penalty < cp[-2].v.ansi_harshness[i].int_penalty)
-               better = 1;
-           }
-       }
+    case LVALUE_CONV:
+    case QUAL_CONV:
+    case RVALUE_CONV:
+      if (rank < EXACT_RANK)
+       rank = EXACT_RANK;
 
-      if (! better || worse)
-       return NULL;
+    default:
+      break;
     }
-  return cp-1;
+  ICS_STD_RANK (t) = rank;
+  ICS_USER_FLAG (t) = ICS_USER_FLAG (from);
+  ICS_BAD_FLAG (t) = ICS_BAD_FLAG (from);
+  return t;
 }
 
-static struct candidate *
-ideal_candidate (basetype, candidates, n_candidates, parms, len)
-     tree basetype;
-     struct candidate *candidates;
-     int n_candidates;
-     tree parms;
-     int len;
+tree
+non_reference (t)
+     tree t;
 {
-  if (flag_ansi_overloading)
-    return ideal_candidate_ansi (basetype, candidates, n_candidates, parms,
-                                len);
-  else
-    return ideal_candidate_old (basetype, candidates, n_candidates, parms,
-                               len);
+  if (TREE_CODE (t) == REFERENCE_TYPE)
+    t = TREE_TYPE (t);
+  return t;
 }
 
-/* Assume that if the class referred to is not in the
-   current class hierarchy, that it may be remote.
-   PARENT is assumed to be of aggregate type here.  */
-static int
-may_be_remote (parent)
-     tree parent;
-{
-  if (TYPE_OVERLOADS_METHOD_CALL_EXPR (parent) == 0)
-    return 0;
-
-  if (current_class_type == NULL_TREE)
-    return 0;
-
-  if (parent == current_class_type)
-    return 0;
-
-  if (UNIQUELY_DERIVED_FROM_P (parent, current_class_type))
-    return 0;
-  return 1;
-}
+/* Returns the standard conversion path (see [conv]) from type FROM to type
+   TO, if any.  For proper handling of null pointer constants, you must
+   also pass the expression EXPR to convert from.  */
 
 tree
-build_vfield_ref (datum, type)
-     tree datum, type;
+standard_conversion (to, from, expr)
+     tree to, from, expr;
 {
-  tree rval;
-  int old_assume_nonnull_objects = flag_assume_nonnull_objects;
-
-  if (datum == error_mark_node)
-    return error_mark_node;
-
-  /* Vtable references are always made from non-null objects.  */
-  flag_assume_nonnull_objects = 1;
-  if (TREE_CODE (TREE_TYPE (datum)) == REFERENCE_TYPE)
-    datum = convert_from_reference (datum);
+  enum tree_code fcode, tcode;
+  tree conv;
 
-  if (! TYPE_USES_COMPLEX_INHERITANCE (type))
-    rval = build (COMPONENT_REF, TREE_TYPE (CLASSTYPE_VFIELD (type)),
-                 datum, CLASSTYPE_VFIELD (type));
-  else
-    rval = build_component_ref (datum, DECL_NAME (CLASSTYPE_VFIELD (type)), 0, 0);
-  flag_assume_nonnull_objects = old_assume_nonnull_objects;
+  fcode = TREE_CODE (from);
+  tcode = TREE_CODE (to);
 
-  return rval;
-}
+  conv = build1 (IDENTITY_CONV, from, expr);
 
-/* Build a call to a member of an object.  I.e., one that overloads
-   operator ()(), or is a pointer-to-function or pointer-to-method.  */
-static tree
-build_field_call (basetype_path, instance_ptr, name, parms)
-     tree basetype_path, instance_ptr, name, parms;
-{
-  tree field, instance;
+  if (from == to)
+    return conv;
 
-  if (instance_ptr == current_class_decl)
+  if (fcode == FUNCTION_TYPE)
     {
-      /* Check to see if we really have a reference to an instance variable
-        with `operator()()' overloaded.  */
-      field = IDENTIFIER_CLASS_VALUE (name);
+      from = build_pointer_type (from);
+      fcode = TREE_CODE (from);
+      conv = build_conv (LVALUE_CONV, from, conv);
+    }
+  else if (fcode == ARRAY_TYPE)
+    {
+      from = build_pointer_type (TREE_TYPE (from));
+      fcode = TREE_CODE (from);
+      conv = build_conv (LVALUE_CONV, from, conv);
+    }
 
-      if (field == NULL_TREE)
+  if ((tcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (to))
+      && expr && null_ptr_cst_p (expr))
+    {
+      conv = build_conv (STD_CONV, to, conv);
+    }
+  else if (tcode == POINTER_TYPE && fcode == POINTER_TYPE)
+    {
+      enum tree_code ufcode = TREE_CODE (TREE_TYPE (from));
+      enum tree_code utcode = TREE_CODE (TREE_TYPE (to));
+      tree nconv = NULL_TREE;
+
+      if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (from)),
+                    TYPE_MAIN_VARIANT (TREE_TYPE (to)), 1))
+       nconv = conv;
+      else if (utcode == VOID_TYPE && ufcode != OFFSET_TYPE
+              && ufcode != FUNCTION_TYPE)
        {
-         cp_error ("`this' has no member named `%D'", name);
-         return error_mark_node;
+         from = build_pointer_type
+           (cp_build_type_variant (void_type_node,
+                                   TYPE_READONLY (TREE_TYPE (from)),
+                                   TYPE_VOLATILE (TREE_TYPE (from))));
+         nconv = build_conv (PTR_CONV, from, conv);
        }
-
-      if (TREE_CODE (field) == FIELD_DECL)
+      else if (ufcode == OFFSET_TYPE && utcode == OFFSET_TYPE)
        {
-         /* If it's a field, try overloading operator (),
-            or calling if the field is a pointer-to-function.  */
-         instance = build_component_ref_1 (C_C_D, field, 0);
-         if (instance == error_mark_node)
-           return error_mark_node;
-
-         if (TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
-             && TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (instance)))
-           return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, instance, parms, NULL_TREE);
+         tree fbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (from));
+         tree tbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (to));
 
-         if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
+         if (DERIVED_FROM_P (fbase, tbase)
+             && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (from))),
+                            TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (to))),
+                            1)))
            {
-             if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == FUNCTION_TYPE)
-               return build_function_call (instance, parms);
-             else if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == METHOD_TYPE)
-               return build_function_call (instance, tree_cons (NULL_TREE, current_class_decl, parms));
+             from = build_offset_type (tbase, TREE_TYPE (TREE_TYPE (from)));
+             from = build_pointer_type (from);
+             nconv = build_conv (PMEM_CONV, from, conv);
            }
        }
-      return NULL_TREE;
-    }
-
-  /* Check to see if this is not really a reference to an instance variable
-     with `operator()()' overloaded.  */
-  field = lookup_field (basetype_path, name, 1, 0);
-
-  /* This can happen if the reference was ambiguous or for access
-     violations.  */
-  if (field == error_mark_node)
-    return error_mark_node;
-
-  if (field)
-    {
-      tree basetype;
-      tree ftype = TREE_TYPE (field);
-
-      if (TREE_CODE (ftype) == REFERENCE_TYPE)
-       ftype = TREE_TYPE (ftype);
-
-      if (TYPE_LANG_SPECIFIC (ftype) && TYPE_OVERLOADS_CALL_EXPR (ftype))
-       {
-         /* Make the next search for this field very short.  */
-         basetype = DECL_FIELD_CONTEXT (field);
-         instance_ptr = convert_pointer_to (basetype, instance_ptr);
-
-         instance = build_indirect_ref (instance_ptr, NULL_PTR);
-         return build_opfncall (CALL_EXPR, LOOKUP_NORMAL,
-                                build_component_ref_1 (instance, field, 0),
-                                parms, NULL_TREE);
-       }
-      if (TREE_CODE (ftype) == POINTER_TYPE)
-       {
-         if (TREE_CODE (TREE_TYPE (ftype)) == FUNCTION_TYPE
-             || TREE_CODE (TREE_TYPE (ftype)) == METHOD_TYPE)
+      else if (IS_AGGR_TYPE (TREE_TYPE (from))
+              && IS_AGGR_TYPE (TREE_TYPE (to)))
+       {
+         if (DERIVED_FROM_P (TREE_TYPE (to), TREE_TYPE (from)))
            {
-             /* This is a member which is a pointer to function.  */
-             tree ref
-               = build_component_ref_1 (build_indirect_ref (instance_ptr,
-                                                            NULL_PTR),
-                                        field, LOOKUP_COMPLAIN);
-             if (ref == error_mark_node)
-               return error_mark_node;
-             return build_function_call (ref, parms);
+             from = cp_build_type_variant (TREE_TYPE (to),
+                                           TYPE_READONLY (TREE_TYPE (from)),
+                                           TYPE_VOLATILE (TREE_TYPE (from)));
+             from = build_pointer_type (from);
+             nconv = build_conv (PTR_CONV, from, conv);
            }
        }
-      else if (TREE_CODE (ftype) == METHOD_TYPE)
+
+      if (nconv && comptypes (from, to, 1))
+       conv = nconv;
+      else if (nconv && comp_ptr_ttypes (TREE_TYPE (to), TREE_TYPE (from)))
+       conv = build_conv (QUAL_CONV, to, nconv);
+      else if (ptr_reasonably_similar (TREE_TYPE (to), TREE_TYPE (from)))
        {
-         error ("invalid call via pointer-to-member function");
-         return error_mark_node;
+         conv = build_conv (PTR_CONV, to, conv);
+         ICS_BAD_FLAG (conv) = 1;
        }
       else
-       return NULL_TREE;
+       return 0;
+
+      from = to;
     }
-  return NULL_TREE;
+  else if (TYPE_PTRMEMFUNC_P (to) && TYPE_PTRMEMFUNC_P (from))
+    {
+      tree fromfn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from));
+      tree tofn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to));
+      tree fbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fromfn)));
+      tree tbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (tofn)));
+
+      if (! DERIVED_FROM_P (fbase, tbase)
+         || ! comptypes (TREE_TYPE (fromfn), TREE_TYPE (tofn), 1)
+         || ! compparms (TREE_CHAIN (TYPE_ARG_TYPES (fromfn)),
+                         TREE_CHAIN (TYPE_ARG_TYPES (tofn)), 1)
+         || TYPE_READONLY (fbase) != TYPE_READONLY (tbase)
+         || TYPE_VOLATILE (fbase) != TYPE_VOLATILE (tbase))
+       return 0;
+
+      from = cp_build_type_variant (tbase, TYPE_READONLY (fbase),
+                                   TYPE_VOLATILE (fbase));
+      from = build_cplus_method_type (from, TREE_TYPE (fromfn),
+                                     TREE_CHAIN (TYPE_ARG_TYPES (fromfn)));
+      from = build_ptrmemfunc_type (build_pointer_type (from));
+      conv = build_conv (PMEM_CONV, from, conv);
+    }
+  else if (tcode == BOOLEAN_TYPE)
+    {
+      if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE
+            || fcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (from)))
+       return 0;
+
+      conv = build_conv (STD_CONV, to, conv);
+      if (fcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (from)
+         && ICS_STD_RANK (conv) < PBOOL_RANK)
+       ICS_STD_RANK (conv) = PBOOL_RANK;
+    }
+  /* We don't check for ENUMERAL_TYPE here because there are no standard
+     conversions to enum type.  */
+  else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
+          || tcode == REAL_TYPE)
+    {
+      if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE))
+       return 0;
+      conv = build_conv (STD_CONV, to, conv);
+
+      /* Give this a better rank if it's a promotion.  */
+      if (to == type_promotes_to (from)
+         && ICS_STD_RANK (TREE_OPERAND (conv, 0)) <= PROMO_RANK)
+       ICS_STD_RANK (conv) = PROMO_RANK;
+    }
+  else if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
+          && DERIVED_FROM_P (to, from))
+    conv = build_conv (BASE_CONV, to, conv);
+  else
+    return 0;
+
+  return conv;
 }
 
 tree
-find_scoped_type (type, inner_name, inner_types)
-     tree type, inner_name, inner_types;
+strip_top_quals (t)
+     tree t;
 {
-  tree tags = CLASSTYPE_TAGS (type);
+  if (TREE_CODE (t) == ARRAY_TYPE)
+    return t;
+  return TYPE_MAIN_VARIANT (t);
+}
 
-  while (tags)
+/* Returns the conversion path from type FROM to reference type TO for
+   purposes of reference binding.  For lvalue binding, either pass a
+   reference type to FROM or an lvalue expression to EXPR.
+
+   Currently does not distinguish in the generated trees between binding to
+   an lvalue and a temporary.  Should it?  */
+
+tree
+reference_binding (rto, from, expr, flags)
+     tree rto, from, expr;
+     int flags;
+{
+  tree conv;
+  int lvalue = 1;
+  tree to = TREE_TYPE (rto);
+
+  if (TREE_CODE (from) == REFERENCE_TYPE)
+    from = TREE_TYPE (from);
+  else if (! expr || ! real_lvalue_p (expr))
+    lvalue = 0;
+
+  if (lvalue
+      && TYPE_READONLY (to) >= TYPE_READONLY (from)
+      && TYPE_VOLATILE (to) >= TYPE_VOLATILE (from))
     {
-      /* The TREE_PURPOSE of an enum tag (which becomes a member of the
-        enclosing class) is set to the name for the enum type.  So, if
-        inner_name is `bar', and we strike `baz' for `enum bar { baz }',
-        then this test will be true.  */
-      if (TREE_PURPOSE (tags) == inner_name)
+      conv = build1 (IDENTITY_CONV, from, expr);
+
+      if (TYPE_MAIN_VARIANT (to) == TYPE_MAIN_VARIANT (from))
+       conv = build_conv (REF_BIND, rto, conv);
+      else if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
+              && DERIVED_FROM_P (to, from))
        {
-         if (inner_types == NULL_TREE)
-           return DECL_NESTED_TYPENAME (TYPE_NAME (TREE_VALUE (tags)));
-         return resolve_scope_to_name (TREE_VALUE (tags), inner_types);
+         conv = build_conv (REF_BIND, rto, conv);
+         ICS_STD_RANK (conv) = STD_RANK;
        }
-      tags = TREE_CHAIN (tags);
+      else
+       conv = NULL_TREE;
     }
+  else
+    conv = NULL_TREE;
 
-#if 0
-  /* XXX This needs to be fixed better.  */
-  if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
+  if (! conv && TYPE_READONLY (to) && ! TYPE_VOLATILE (to)
+      && (flags & LOOKUP_NO_TEMP_BIND) == 0)
     {
-      sorry ("nested class lookup in template type");
-      return NULL_TREE;
+      conv = standard_conversion
+       (TYPE_MAIN_VARIANT (to), strip_top_quals (from), expr);
+      if (conv)
+       {
+         conv = build_conv (REF_BIND, rto, conv);
+
+         /* Bind directly to a base subobject of a class rvalue.  */
+         if (TREE_CODE (TREE_OPERAND (conv, 0)) == BASE_CONV)
+           TREE_OPERAND (conv, 0) = TREE_OPERAND (TREE_OPERAND (conv, 0), 0);
+       }
     }
-#endif
 
-  /* Look for a TYPE_DECL.  */
-  for (tags = TYPE_FIELDS (type); tags; tags = TREE_CHAIN (tags))
-    if (TREE_CODE (tags) == TYPE_DECL && DECL_NAME (tags) == inner_name)
-      {
-       /* Code by raeburn.  */
-       if (inner_types == NULL_TREE)
-         return DECL_NESTED_TYPENAME (tags);
-       return resolve_scope_to_name (TREE_TYPE (tags), inner_types);
-      }
+  if (! conv)
+    {
+      conv = standard_conversion
+       (TYPE_MAIN_VARIANT (to), strip_top_quals (from), expr);
+      if (conv)
+       ICS_BAD_FLAG (conv) = 1;
+    }  
 
-  return NULL_TREE;
+  return conv;
 }
 
-/* Resolve an expression NAME1::NAME2::...::NAMEn to
-   the name that names the above nested type.  INNER_TYPES
-   is a chain of nested type names (held together by SCOPE_REFs);
-   OUTER_TYPE is the type we know to enclose INNER_TYPES.
-   Returns NULL_TREE if there is an error.  */
+/* Returns the implicit conversion sequence (see [over.ics]) from type FROM
+   to type TO.  The optional expression EXPR may affect the conversion.
+   FLAGS are the usual overloading flags.  Only LOOKUP_NO_CONVERSION is
+   significant.  */
+
 tree
-resolve_scope_to_name (outer_type, inner_stuff)
-     tree outer_type, inner_stuff;
+implicit_conversion (to, from, expr, flags)
+     tree to, from, expr;
+     int flags;
 {
-  register tree tmp;
-  tree inner_name, inner_type;
+  tree conv;
+  struct z_candidate *cand;
 
-  if (outer_type == NULL_TREE && current_class_type != NULL_TREE)
+  if (expr && type_unknown_p (expr))
     {
-      /* We first try to look for a nesting in our current class context,
-         then try any enclosing classes.  */
-      tree type = current_class_type;
-      
-      while (type && (TREE_CODE (type) == RECORD_TYPE
-                     || TREE_CODE (type) == UNION_TYPE))
-        {
-          tree rval = resolve_scope_to_name (type, inner_stuff);
-
-         if (rval != NULL_TREE)
-           return rval;
-         type = DECL_CONTEXT (TYPE_NAME (type));
-       }
+      expr = instantiate_type (to, expr, 0);
+      if (expr == error_mark_node)
+       return 0;
+      from = TREE_TYPE (expr);
     }
 
-  if (TREE_CODE (inner_stuff) == SCOPE_REF)
-    {
-      inner_name = TREE_OPERAND (inner_stuff, 0);
-      inner_type = TREE_OPERAND (inner_stuff, 1);
-    }
+  if (TREE_CODE (to) == REFERENCE_TYPE)
+    conv = reference_binding (to, from, expr, flags);
   else
+    conv = standard_conversion
+      (TYPE_MAIN_VARIANT (non_reference (to)),
+       strip_top_quals (non_reference (from)), expr);
+
+  if (conv)
     {
-      inner_name = inner_stuff;
-      inner_type = NULL_TREE;
+      if (TREE_CODE (conv) == IDENTITY_CONV && IS_AGGR_TYPE (to)
+         && (TREE_CODE (from) == REFERENCE_TYPE || (expr && real_lvalue_p (expr))))
+       conv = build_conv (RVALUE_CONV, to, conv);
     }
-
-  if (outer_type == NULL_TREE)
+  else if ((IS_AGGR_TYPE (non_reference (from))
+           || IS_AGGR_TYPE (non_reference (to)))
+          && (flags & LOOKUP_NO_CONVERSION) == 0)
     {
-      /* If we have something that's already a type by itself,
-        use that.  */
-      if (IDENTIFIER_HAS_TYPE_VALUE (inner_name))
+      if (TREE_CODE (to) == REFERENCE_TYPE
+         && TYPE_READONLY (TREE_TYPE (to))
+         && ! TYPE_VOLATILE (TREE_TYPE (to))
+         && (flags & LOOKUP_NO_TEMP_BIND) == 0)
        {
-         if (inner_type)
-           return resolve_scope_to_name (IDENTIFIER_TYPE_VALUE (inner_name),
-                                         inner_type);
-         return inner_name;
+         cand = build_user_type_conversion_1
+           (TYPE_MAIN_VARIANT (TREE_TYPE (to)), expr, LOOKUP_ONLYCONVERTING);
+         if (cand)
+           conv = build_conv (REF_BIND, to, cand->second_conv);
        }
-      return NULL_TREE;
-    }
-
-  if (! IS_AGGR_TYPE (outer_type))
-    return NULL_TREE;
-
-  /* Look for member classes or enums.  */
-  tmp = find_scoped_type (outer_type, inner_name, inner_type);
-
-  /* If it's not a type in this class, then go down into the
-     base classes and search there.  */
-  if (! tmp && TYPE_BINFO (outer_type))
-    {
-      tree binfos = TYPE_BINFO_BASETYPES (outer_type);
-      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-      for (i = 0; i < n_baselinks; i++)
+      else
        {
-         tree base_binfo = TREE_VEC_ELT (binfos, i);
-         tmp = resolve_scope_to_name (BINFO_TYPE (base_binfo), inner_stuff);
-         if (tmp)
-           return tmp;
+         cand = build_user_type_conversion_1
+           (to, expr, LOOKUP_ONLYCONVERTING);
+         if (cand)
+           conv = cand->second_conv;
        }
-      tmp = NULL_TREE;
     }
 
-  return tmp;
+  return conv;
 }
 
-/* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'.
-   This is how virtual function calls are avoided.  */
-tree
-build_scoped_method_call (exp, scopes, name, parms)
-     tree exp, scopes, name, parms;
-{
-  /* Because this syntactic form does not allow
-     a pointer to a base class to be `stolen',
-     we need not protect the derived->base conversion
-     that happens here.
-     
-     @@ But we do have to check access privileges later.  */
-  tree basename = resolve_scope_to_name (NULL_TREE, scopes);
-  tree basetype, binfo, decl;
-  tree type = TREE_TYPE (exp);
-
-  if (type == error_mark_node
-      || basename == NULL_TREE)
-    return error_mark_node;
-
-  basetype = IDENTIFIER_TYPE_VALUE (basename);
-
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+/* Create an overload candidate for the function or method FN called with
+   the argument list ARGLIST and add it to CANDIDATES.  FLAGS is passed on
+   to implicit_conversion.  */
 
-  /* 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_typedef (basename, 0))
+static struct z_candidate *
+add_function_candidate (candidates, fn, arglist, flags)
+     struct z_candidate *candidates;
+     tree fn, arglist;
+     int flags;
+{
+  tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (fn));
+  int i, len;
+  tree convs;
+  tree parmnode = parmlist;
+  tree argnode = arglist;
+  int viable = 1;
+  struct z_candidate *cand;
+
+  /* The `this' and `in_chrg' arguments to constructors are not considered
+     in overload resolution.  */
+  if (DECL_CONSTRUCTOR_P (fn))
     {
-      if (type != basetype)
-       cp_error ("type of `%E' does not match destructor type `%T' (type was `%T')",
-                 exp, basetype, type);
-      name = IDENTIFIER_TYPE_VALUE (TREE_OPERAND (name, 0));
-      if (basetype != name)
-       cp_error ("qualified type `%T' does not match destructor type `%T'",
-                 basetype, name);
-      return void_zero_node;
+      parmnode = TREE_CHAIN (parmnode);
+      argnode = TREE_CHAIN (argnode);
+      if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+       {
+         parmnode = TREE_CHAIN (parmnode);
+         argnode = TREE_CHAIN (argnode);
+       }
     }
 
-  if (! is_aggr_typedef (basename, 1))
-    return error_mark_node;
+  len = list_length (argnode);
+  convs = make_tree_vec (len);
 
-  if (! IS_AGGR_TYPE (type))
+  for (i = 0; i < len; ++i)
     {
-      cp_error ("base object `%E' of scoped method call is of non-aggregate type `%T'",
-               exp, type);
-      return error_mark_node;
-    }
+      tree arg = TREE_VALUE (argnode);
+      tree argtype = TREE_TYPE (arg);
+      tree t;
 
-  if (binfo = binfo_or_else (basetype, type))
-    {
-      if (binfo == error_mark_node)
-       return error_mark_node;
-      if (TREE_CODE (exp) == INDIRECT_REF)
-       decl = build_indirect_ref (convert_pointer_to (binfo,
-                                                      build_unary_op (ADDR_EXPR, exp, 0)), NULL_PTR);
-      else
-       decl = build_scoped_ref (exp, scopes);
+      argtype = cp_build_type_variant
+       (argtype, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
 
-      /* Call to a destructor.  */
-      if (TREE_CODE (name) == BIT_NOT_EXPR)
+      if (parmnode == void_list_node)
+       break;
+      else if (parmnode)
+       t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg, flags);
+      else
        {
-         /* Explicit call to destructor.  */
-         name = TREE_OPERAND (name, 0);
-         if (TREE_TYPE (decl) !=
-             (IDENTIFIER_CLASS_VALUE (name)
-              ? IDENTIFIER_CLASS_TYPE_VALUE (name)
-              : IDENTIFIER_TYPE_VALUE (name)))
-           {
-             cp_error
-               ("qualified type `%T' does not match destructor type `%T'",
-                TREE_TYPE (decl), name);
-             return error_mark_node;
-           }
-         if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
-           return void_zero_node;
-         
-         return build_delete (TREE_TYPE (decl), decl, integer_two_node,
-                              LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR,
-                              0);
+         t = build1 (IDENTITY_CONV, argtype, arg);
+         ICS_ELLIPSIS_FLAG (t) = 1;
        }
 
-      /* Call to a method.  */
-      return build_method_call (decl, name, parms, NULL_TREE,
-                               LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
-    }
-  return error_mark_node;
-}
+      if (i == 0 && t && TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
+         && ! DECL_CONSTRUCTOR_P (fn))
+       ICS_THIS_FLAG (t) = 1;
 
-static void
-print_candidates (candidates)
-     tree candidates;
-{
-  cp_error_at ("candidates are: %D", TREE_VALUE (candidates));
-  candidates = TREE_CHAIN (candidates);
+      TREE_VEC_ELT (convs, i) = t;
+      if (! t)
+       break;
 
-  while (candidates)
-    {
-      cp_error_at ("                %D", TREE_VALUE (candidates));
-      candidates = TREE_CHAIN (candidates);
+      if (ICS_BAD_FLAG (t))
+       viable = -1;
+
+      if (parmnode)
+       parmnode = TREE_CHAIN (parmnode);
+      argnode = TREE_CHAIN (argnode);
     }
-}
 
-static void
-print_n_candidates (candidates, n)
-     struct candidate *candidates;
-     int n;
-{
-  int i;
+  if (i < len)
+    viable = 0;
 
-  cp_error_at ("candidates are: %D", candidates[0].function);
-  for (i = 1; i < n; i++)
-    cp_error_at ("                %D", candidates[i].function);
-}
+  /* Make sure there are default args for the rest of the parms.  */
+  for (; parmnode && parmnode != void_list_node;
+       parmnode = TREE_CHAIN (parmnode))
+    if (! TREE_PURPOSE (parmnode))
+      {
+       viable = 0;
+       break;
+      }
 
-/* Build something of the form ptr->method (args)
-   or object.method (args).  This can also build
-   calls to constructors, and find friends.
+  cand = (struct z_candidate *) oballoc (sizeof (struct z_candidate));
 
-   Member functions always take their class variable
-   as a pointer.
+  cand->fn = fn;
+  cand->convs = convs;
+  cand->second_conv = NULL_TREE;
+  cand->viable = viable;
+  cand->basetype_path = NULL_TREE;
+  cand->template = NULL_TREE;
+  cand->next = candidates;
 
-   INSTANCE is a class instance.
+  return cand;
+}
 
-   NAME is the name of the method desired, usually an IDENTIFIER_NODE.
+/* Create an overload candidate for the conversion function FN which will
+   be invoked for expression OBJ, producing a pointer-to-function which
+   will in turn be called with the argument list ARGLIST, and add it to
+   CANDIDATES.  FLAGS is passed on to implicit_conversion.  */
 
-   PARMS help to figure out what that NAME really refers to.
+static struct z_candidate *
+add_conv_candidate (candidates, fn, obj, arglist)
+     struct z_candidate *candidates;
+     tree fn, obj, arglist;
+{
+  tree totype = TREE_TYPE (TREE_TYPE (fn));
+  tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (totype));
+  int i, len = list_length (arglist) + 1;
+  tree convs = make_tree_vec (len);
+  tree parmnode = parmlist;
+  tree argnode = arglist;
+  int viable = 1;
+  struct z_candidate *cand;
+  int flags = LOOKUP_NORMAL;
+
+  for (i = 0; i < len; ++i)
+    {
+      tree arg = i == 0 ? obj : TREE_VALUE (argnode);
+      tree argtype = lvalue_type (arg);
+      tree t;
 
-   BASETYPE_PATH, if non-NULL, contains a chain from the type of INSTANCE
-   down to the real instance type to use for access checking.  We need this
-   information to get protected accesses correct.  This parameter is used
-   by build_member_call.
+      if (i == 0)
+       t = implicit_conversion (totype, argtype, arg, flags);
+      else 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;
+       }
 
-   FLAGS is the logical disjunction of zero or more LOOKUP_
-   flags.  See cp-tree.h for more info.
+      TREE_VEC_ELT (convs, i) = t;
+      if (! t)
+       break;
 
-   If this is all OK, calls build_function_call with the resolved
-   member function.
+      if (ICS_BAD_FLAG (t))
+       viable = -1;
 
-   This function must also handle being called to perform
-   initialization, promotion/coercion of arguments, and
-   instantiation of default parameters.
+      if (i == 0)
+       continue;
 
-   Note that NAME may refer to an instance variable name.  If
-   `operator()()' is defined for the type of that field, then we return
-   that result.  */
-tree
-build_method_call (instance, name, parms, basetype_path, flags)
-     tree instance, name, parms, basetype_path;
+      if (parmnode)
+       parmnode = TREE_CHAIN (parmnode);
+      argnode = TREE_CHAIN (argnode);
+    }
+
+  if (i < len)
+    viable = 0;
+
+  for (; parmnode && parmnode != void_list_node;
+       parmnode = TREE_CHAIN (parmnode))
+    if (! TREE_PURPOSE (parmnode))
+      {
+       viable = 0;
+       break;
+      }
+
+  cand = (struct z_candidate *) oballoc (sizeof (struct z_candidate));
+
+  cand->fn = fn;
+  cand->convs = convs;
+  cand->second_conv = NULL_TREE;
+  cand->viable = viable;
+  cand->basetype_path = NULL_TREE;
+  cand->template = NULL_TREE;
+  cand->next = candidates;
+
+  return cand;
+}
+
+static struct z_candidate *
+build_builtin_candidate (candidates, fnname, type1, type2,
+                        args, argtypes, flags)
+     struct z_candidate *candidates;
+     tree fnname, type1, type2, *args, *argtypes;
      int flags;
+
 {
-  register tree function, fntype, value_type;
-  register tree basetype, save_basetype;
-  register tree baselink, result, method_name, parmtypes, parm;
-  tree last;
-  int pass;
-  enum access_type access = access_public;
+  tree t, convs;
+  int viable = 1, i;
+  struct z_candidate *cand;
+  tree types[2];
 
-  /* Range of cases for vtable optimization.  */
-  enum vtable_needs { not_needed, maybe_needed, unneeded, needed };
-  enum vtable_needs need_vtbl = not_needed;
+  types[0] = type1;
+  types[1] = type2;
 
-  char *name_kind;
-  int ever_seen = 0;
-  tree instance_ptr = NULL_TREE;
-  int all_virtual = flag_all_virtual;
-  int static_call_context = 0;
-  tree found_fns = NULL_TREE;
+  convs = make_tree_vec (args[2] ? 3 : (args[1] ? 2 : 1));
 
-  /* Keep track of `const' and `volatile' objects.  */
-  int constp, volatilep;
+  for (i = 0; i < 2; ++i)
+    {
+      if (! args[i])
+       break;
 
-#ifdef GATHER_STATISTICS
-  n_build_method_call++;
-#endif
+      t = implicit_conversion (types[i], argtypes[i], args[i], flags);
+      if (! t)
+       {
+         viable = 0;
+         /* We need something for printing the candidate.  */
+         t = build1 (IDENTITY_CONV, types[i], NULL_TREE);
+       }
+      else if (ICS_BAD_FLAG (t))
+       viable = 0;
+      TREE_VEC_ELT (convs, i) = t;
+    }
 
-  if (instance == error_mark_node
-      || name == error_mark_node
-      || parms == error_mark_node
-      || (instance != NULL_TREE && TREE_TYPE (instance) == error_mark_node))
-    return error_mark_node;
+  /* For COND_EXPR we rearranged the arguments; undo that now.  */
+  if (args[2])
+    {
+      TREE_VEC_ELT (convs, 2) = TREE_VEC_ELT (convs, 1);
+      TREE_VEC_ELT (convs, 1) = TREE_VEC_ELT (convs, 0);
+      t = implicit_conversion (boolean_type_node, argtypes[2], args[2], flags);
+      if (t)
+       TREE_VEC_ELT (convs, 0) = t;
+      else
+       viable = 0;
+    }      
 
-  /* This is the logic that magically deletes the second argument to
-     operator delete, if it is not needed. */
-  if (name == ansi_opname[(int) DELETE_EXPR] && list_length (parms)==2)
+  cand = (struct z_candidate *) oballoc (sizeof (struct z_candidate));
+
+  cand->fn = fnname;
+  cand->convs = convs;
+  cand->second_conv = NULL_TREE;
+  cand->viable = viable;
+  cand->basetype_path = NULL_TREE;
+  cand->template = NULL_TREE;
+  cand->next = candidates;
+
+  return cand;
+}
+
+int
+is_complete (t)
+     tree t;
+{
+  return TYPE_SIZE (complete_type (t)) != NULL_TREE;
+}
+
+/* Create any builtin operator overload candidates for the operator in
+   question given the converted operand types TYPE1 and TYPE2.  The other
+   args are passed through from add_builtin_candidates to
+   build_builtin_candidate.  */
+
+static struct z_candidate *
+add_builtin_candidate (candidates, code, code2, fnname, type1, type2,
+                      args, argtypes, flags)
+     struct z_candidate *candidates;
+     enum tree_code code, code2;
+     tree fnname, type1, type2, *args, *argtypes;
+     int flags;
+{
+  switch (code)
     {
-      tree save_last = TREE_CHAIN (parms);
-      tree result;
-      /* get rid of unneeded argument */
-      TREE_CHAIN (parms) = NULL_TREE;
-      result = build_method_call (instance, name, parms, basetype_path,
-                                 (LOOKUP_SPECULATIVELY|flags)
-                                 &~LOOKUP_COMPLAIN);
-      /* If it works, return it. */
-      if (result && result != error_mark_node)
-       return build_method_call (instance, name, parms, basetype_path, flags);
-      /* If it doesn't work, two argument delete must work */
-      TREE_CHAIN (parms) = save_last;
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      args[1] = integer_zero_node;
+      type2 = integer_type_node;
     }
 
-  if (TREE_CODE (name) == BIT_NOT_EXPR)
+  switch (code)
     {
-      flags |= LOOKUP_DESTRUCTOR;
-      name = TREE_OPERAND (name, 0);
-      if (parms)
-       error ("destructors take no parameters");
-      basetype = get_type_value (name);
-      if (basetype == NULL_TREE)
+
+/* 4 For every pair T, VQ), where T is an arithmetic or  enumeration  type,
+     and  VQ  is  either  volatile or empty, there exist candidate operator
+     functions of the form
+            VQ T&   operator++(VQ T&);
+            T       operator++(VQ T&, int);
+   5 For every pair T, VQ), where T is an enumeration type or an arithmetic
+     type  other than bool, and VQ is either volatile or empty, there exist
+     candidate operator functions of the form
+            VQ T&   operator--(VQ T&);
+            T       operator--(VQ T&, int);
+   6 For every pair T, VQ), where T is  a  cv-qualified  or  cv-unqualified
+     complete  object type, and VQ is either volatile or empty, there exist
+     candidate operator functions of the form
+            T*VQ&   operator++(T*VQ&);
+            T*VQ&   operator--(T*VQ&);
+            T*      operator++(T*VQ&, int);
+            T*      operator--(T*VQ&, int);  */
+
+    case POSTDECREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+      if (TREE_CODE (type1) == BOOLEAN_TYPE)
+       return candidates;
+    case POSTINCREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+      if ((ARITHMETIC_TYPE_P (type1) && TREE_CODE (type1) != ENUMERAL_TYPE)
+         || TYPE_PTROB_P (type1))
        {
-         cp_error ("call to destructor for non-type `%D'", name);
-         return void_zero_node;
+         type1 = build_reference_type (type1);
+         break;
        }
-      if (! TYPE_HAS_DESTRUCTOR (basetype))
-       return void_zero_node;
-      instance = default_conversion (instance);
-      instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
-      return build_delete (build_pointer_type (basetype),
-                          instance_ptr, integer_two_node,
-                          LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
-    }
+      return candidates;
 
-  {
-    char *xref_name;
-    
-    /* Initialize name for error reporting.  */
-    if (IDENTIFIER_OPNAME_P (name) && ! IDENTIFIER_TYPENAME_P (name))
-      {
-       char *p = operator_name_string (name);
-       xref_name = (char *)alloca (strlen (p) + 10);
-       sprintf (xref_name, "operator %s", p);
-      }
-    else if (TREE_CODE (name) == SCOPE_REF)
-      xref_name = IDENTIFIER_POINTER (TREE_OPERAND (name, 1));
-    else
-      xref_name = IDENTIFIER_POINTER (name);
+/* 7 For every cv-qualified or cv-unqualified complete object type T, there
+     exist candidate operator functions of the form
 
-    GNU_xref_call (current_function_decl, xref_name);
-  }
+            T&      operator*(T*);
 
-  if (instance == NULL_TREE)
-    {
-      basetype = NULL_TREE;
-      /* Check cases where this is really a call to raise
-        an exception.  */
-      if (current_class_type && TREE_CODE (name) == IDENTIFIER_NODE)
+   8 For every function type T, there exist candidate operator functions of
+     the form
+            T&      operator*(T*);  */
+
+    case INDIRECT_REF:
+      if (TREE_CODE (type1) == POINTER_TYPE
+         && (TYPE_PTROB_P (type1)
+             || TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE))
+       break;
+      return candidates;
+
+/* 9 For every type T, there exist candidate operator functions of the form
+            T*      operator+(T*);
+
+   10For  every  promoted arithmetic type T, there exist candidate operator
+     functions of the form
+            T       operator+(T);
+            T       operator-(T);  */
+
+    case CONVERT_EXPR: /* unary + */
+      if (TREE_CODE (type1) == POINTER_TYPE
+         && TREE_CODE (TREE_TYPE (type1)) != OFFSET_TYPE)
+       break;
+    case NEGATE_EXPR:
+      if (ARITHMETIC_TYPE_P (type1))
+       break;
+      return candidates;
+
+/* 11For every promoted integral type T,  there  exist  candidate  operator
+     functions of the form
+            T       operator~(T);  */
+
+    case BIT_NOT_EXPR:
+      if (INTEGRAL_TYPE_P (type1))
+       break;
+      return candidates;
+
+/* 12For every quintuple C1, C2, T, CV1, CV2), where C2 is a class type, C1
+     is the same type as C2 or is a derived class of C2, T  is  a  complete
+     object type or a function type, and CV1 and CV2 are cv-qualifier-seqs,
+     there exist candidate operator functions of the form
+            CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
+     where CV12 is the union of CV1 and CV2.  */
+
+    case MEMBER_REF:
+      if (TREE_CODE (type1) == POINTER_TYPE
+         && (TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2)))
        {
-         basetype = purpose_member (name, CLASSTYPE_TAGS (current_class_type));
-         if (basetype)
-           basetype = TREE_VALUE (basetype);
+         tree c1 = TREE_TYPE (type1);
+         tree c2 = (TYPE_PTRMEMFUNC_P (type2)
+                    ? TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (type2))
+                    : TYPE_OFFSET_BASETYPE (TREE_TYPE (type2)));
+
+         if (IS_AGGR_TYPE (c1) && DERIVED_FROM_P (c2, c1)
+             && (TYPE_PTRMEMFUNC_P (type2)
+                 || is_complete (TREE_TYPE (TREE_TYPE (type2)))))
+           break;
        }
-      else if (TREE_CODE (name) == SCOPE_REF
-              && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
+      return candidates;
+
+/* 13For every pair of promoted arithmetic types L and R, there exist  can-
+     didate operator functions of the form
+            LR      operator*(L, R);
+            LR      operator/(L, R);
+            LR      operator+(L, R);
+            LR      operator-(L, R);
+            bool    operator<(L, R);
+            bool    operator>(L, R);
+            bool    operator<=(L, R);
+            bool    operator>=(L, R);
+            bool    operator==(L, R);
+            bool    operator!=(L, R);
+     where  LR  is  the  result of the usual arithmetic conversions between
+     types L and R.
+
+   14For every pair of types T and I, where T  is  a  cv-qualified  or  cv-
+     unqualified  complete  object  type and I is a promoted integral type,
+     there exist candidate operator functions of the form
+            T*      operator+(T*, I);
+            T&      operator[](T*, I);
+            T*      operator-(T*, I);
+            T*      operator+(I, T*);
+            T&      operator[](I, T*);
+
+   15For every T, where T is a pointer to complete object type, there exist
+     candidate operator functions of the form112)
+            ptrdiff_t operator-(T, T);
+
+   16For  every pointer type T, there exist candidate operator functions of
+     the form
+            bool    operator<(T, T);
+            bool    operator>(T, T);
+            bool    operator<=(T, T);
+            bool    operator>=(T, T);
+            bool    operator==(T, T);
+            bool    operator!=(T, T);
+
+   17For every pointer to member type T,  there  exist  candidate  operator
+     functions of the form
+            bool    operator==(T, T);
+            bool    operator!=(T, T);  */
+
+    case MINUS_EXPR:
+      if (TYPE_PTROB_P (type1) && TYPE_PTROB_P (type2))
+       break;
+      if (TYPE_PTROB_P (type1) && INTEGRAL_TYPE_P (type2))
        {
-         if (! is_aggr_typedef (TREE_OPERAND (name, 0), 1))
-           return error_mark_node;
-         basetype = purpose_member (TREE_OPERAND (name, 1),
-                                    CLASSTYPE_TAGS (IDENTIFIER_TYPE_VALUE (TREE_OPERAND (name, 0))));
-         if (basetype)
-           basetype = TREE_VALUE (basetype);
+         type2 = ptrdiff_type_node;
+         break;
        }
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+      if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+       break;
+      return candidates;
 
-      if (basetype != NULL_TREE)
-       ;
-      /* call to a constructor... */
-      else if (IDENTIFIER_HAS_TYPE_VALUE (name))
+    case EQ_EXPR:
+    case NE_EXPR:
+      if (TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2)
+         || TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2))
+       break;
+      if ((TYPE_PTRMEMFUNC_P (type1) || TYPE_PTRMEM_P (type1))
+         && null_ptr_cst_p (args[1]))
        {
-         basetype = IDENTIFIER_TYPE_VALUE (name);
-         name = constructor_name_full (basetype);
+         type2 = type1;
+         break;
        }
-      else
+      if ((TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2))
+         && null_ptr_cst_p (args[0]))
        {
-         tree typedef_name = lookup_name (name, 1);
-         if (typedef_name && TREE_CODE (typedef_name) == TYPE_DECL)
+         type1 = type2;
+         break;
+       }
+    case LT_EXPR:
+    case GT_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+    case MAX_EXPR:
+    case MIN_EXPR:
+      if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2)
+         || TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
+       break;
+      if (TYPE_PTR_P (type1) && null_ptr_cst_p (args[1]))
+       {
+         type2 = type1;
+         break;
+       }
+      if (null_ptr_cst_p (args[0]) && TYPE_PTR_P (type2))
+       {
+         type1 = type2;
+         break;
+       }
+      return candidates;
+
+    case PLUS_EXPR:
+      if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+       break;
+    case ARRAY_REF:
+      if (INTEGRAL_TYPE_P (type1) && TYPE_PTROB_P (type2))
+       {
+         type1 = ptrdiff_type_node;
+         break;
+       }
+      if (TYPE_PTROB_P (type1) && INTEGRAL_TYPE_P (type2))
+       {
+         type2 = ptrdiff_type_node;
+         break;
+       }
+      return candidates;
+
+/* 18For  every pair of promoted integral types L and R, there exist candi-
+     date operator functions of the form
+            LR      operator%(L, R);
+            LR      operator&(L, R);
+            LR      operator^(L, R);
+            LR      operator|(L, R);
+            L       operator<<(L, R);
+            L       operator>>(L, R);
+     where LR is the result of the  usual  arithmetic  conversions  between
+     types L and R.  */
+
+    case TRUNC_MOD_EXPR:
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+      if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2))
+       break;
+      return candidates;
+
+/* 19For  every  triple  L, VQ, R), where L is an arithmetic or enumeration
+     type, VQ is either volatile or empty, and R is a  promoted  arithmetic
+     type, there exist candidate operator functions of the form
+            VQ L&   operator=(VQ L&, R);
+            VQ L&   operator*=(VQ L&, R);
+            VQ L&   operator/=(VQ L&, R);
+            VQ L&   operator+=(VQ L&, R);
+            VQ L&   operator-=(VQ L&, R);
+
+   20For  every  pair T, VQ), where T is any type and VQ is either volatile
+     or empty, there exist candidate operator functions of the form
+            T*VQ&   operator=(T*VQ&, T*);
+
+   21For every pair T, VQ), where T is a pointer to member type and  VQ  is
+     either  volatile or empty, there exist candidate operator functions of
+     the form
+            VQ T&   operator=(VQ T&, T);
+
+   22For every triple  T,  VQ,  I),  where  T  is  a  cv-qualified  or  cv-
+     unqualified  complete object type, VQ is either volatile or empty, and
+     I is a promoted integral type, there exist  candidate  operator  func-
+     tions of the form
+            T*VQ&   operator+=(T*VQ&, I);
+            T*VQ&   operator-=(T*VQ&, I);
+
+   23For  every  triple  L,  VQ,  R), where L is an integral or enumeration
+     type, VQ is either volatile or empty, and R  is  a  promoted  integral
+     type, there exist candidate operator functions of the form
+
+            VQ L&   operator%=(VQ L&, R);
+            VQ L&   operator<<=(VQ L&, R);
+            VQ L&   operator>>=(VQ L&, R);
+            VQ L&   operator&=(VQ L&, R);
+            VQ L&   operator^=(VQ L&, R);
+            VQ L&   operator|=(VQ L&, R);  */
+
+    case MODIFY_EXPR:
+      switch (code2)
+       {
+       case PLUS_EXPR:
+       case MINUS_EXPR:
+         if (TYPE_PTROB_P (type1) && INTEGRAL_TYPE_P (type2))
            {
-             /* Canonicalize the typedef name.  */
-             basetype = TREE_TYPE (typedef_name);
-             name = TYPE_IDENTIFIER (basetype);
+             type2 = ptrdiff_type_node;
+             break;
            }
-         else
+       case MULT_EXPR:
+       case TRUNC_DIV_EXPR:
+         if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+           break;
+         return candidates;
+
+       case TRUNC_MOD_EXPR:
+       case BIT_AND_EXPR:
+       case BIT_IOR_EXPR:
+       case BIT_XOR_EXPR:
+       case LSHIFT_EXPR:
+       case RSHIFT_EXPR:
+         if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2))
+           break;
+         return candidates;
+
+       case NOP_EXPR:
+         if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+           break;
+         if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
+             || (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
+             || (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2))
+             || ((TYPE_PTRMEMFUNC_P (type1)
+                  || TREE_CODE (type1) == POINTER_TYPE)
+                 && null_ptr_cst_p (args[1])))
            {
-             cp_error ("no constructor named `%T' in scope",
-                       name);
-             return error_mark_node;
+             type2 = type1;
+             break;
            }
+         return candidates;
+
+       default:
+         my_friendly_abort (367);
        }
+      type1 = build_reference_type (type1);
+      break;
 
-      if (! IS_AGGR_TYPE (basetype))
+    case COND_EXPR:
+      /* Kludge around broken overloading rules whereby
+        bool ? const char& : enum is ambiguous.  */
+      flags |= LOOKUP_NO_TEMP_BIND;
+      if (TREE_CODE (type1) == ENUMERAL_TYPE && type1 == type2)
+       break;
+      else if (TREE_CODE (type1) == ENUMERAL_TYPE
+              || TREE_CODE (type2) == ENUMERAL_TYPE)
+       return candidates;
+      if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+       break;
+      if (TREE_CODE (type1) == TREE_CODE (type2)
+         && (TREE_CODE (type1) == REFERENCE_TYPE
+             || TREE_CODE (type1) == POINTER_TYPE
+             || TYPE_PTRMEMFUNC_P (type1)
+             || IS_AGGR_TYPE (type1)))
+       break;
+      if (TREE_CODE (type1) == REFERENCE_TYPE
+         || TREE_CODE (type2) == REFERENCE_TYPE)
+       return candidates;
+      if (((TYPE_PTRMEMFUNC_P (type1) || TREE_CODE (type1) == POINTER_TYPE)
+          && null_ptr_cst_p (args[1]))
+         || IS_AGGR_TYPE (type1))
        {
-       non_aggr_error:
-         if ((flags & LOOKUP_COMPLAIN) && TREE_CODE (basetype) != ERROR_MARK)
-           cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
-                     name, instance, basetype);
-
-         return error_mark_node;
+         type2 = type1;
+         break;
+       }
+      if (((TYPE_PTRMEMFUNC_P (type2) || TREE_CODE (type2) == POINTER_TYPE)
+          && null_ptr_cst_p (args[0]))
+         || IS_AGGR_TYPE (type2))
+       {
+         type1 = type2;
+         break;
        }
+      return candidates;
+
+    default:
+      my_friendly_abort (367);
     }
-  else if (instance == C_C_D || instance == current_class_decl)
+
+  /* If we're dealing with two pointer types, we need candidates
+     for both of them.  */
+  if (type2 && type1 != type2
+      && TREE_CODE (type1) == TREE_CODE (type2)
+      && (TREE_CODE (type1) == REFERENCE_TYPE
+         || (TREE_CODE (type1) == POINTER_TYPE
+             && TYPE_PTRMEM_P (type1) == TYPE_PTRMEM_P (type2))
+         || TYPE_PTRMEMFUNC_P (type1)
+         || IS_AGGR_TYPE (type1)))
     {
-      /* When doing initialization, we side-effect the TREE_TYPE of
-        C_C_D, hence we cannot set up BASETYPE from CURRENT_CLASS_TYPE.  */
-      basetype = TREE_TYPE (C_C_D);
+      candidates = build_builtin_candidate
+       (candidates, fnname, type1, type1, args, argtypes, flags);
+      return build_builtin_candidate
+       (candidates, fnname, type2, type2, args, argtypes, flags);
+    }
 
-      /* Anything manifestly `this' in constructors and destructors
-        has a known type, so virtual function tables are not needed.  */
-      if (TYPE_VIRTUAL_P (basetype)
-         && !(flags & LOOKUP_NONVIRTUAL))
-       need_vtbl = (dtor_label || ctor_label)
-         ? unneeded : maybe_needed;
+  return build_builtin_candidate
+    (candidates, fnname, type1, type2, args, argtypes, flags);
+}
 
-      instance = C_C_D;
-      instance_ptr = current_class_decl;
-      result = build_field_call (TYPE_BINFO (current_class_type),
-                                instance_ptr, name, parms);
+tree
+type_decays_to (type)
+     tree type;
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    return build_pointer_type (TREE_TYPE (type));
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    return build_pointer_type (type);
+  return type;
+}
 
-      if (result)
-       return result;
-    }
-  else if (TREE_CODE (instance) == RESULT_DECL)
-    {
-      basetype = TREE_TYPE (instance);
-      /* Should we ever have to make a virtual function reference
-        from a RESULT_DECL, know that it must be of fixed type
-        within the scope of this function.  */
-      if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
-       need_vtbl = maybe_needed;
-      instance_ptr = build1 (ADDR_EXPR, TYPE_POINTER_TO (basetype), instance);
-    }
-  else if (instance == current_exception_object)
-    {
-      instance_ptr = build1 (ADDR_EXPR, TYPE_POINTER_TO (current_exception_type),
-                           TREE_OPERAND (current_exception_object, 0));
-      mark_addressable (TREE_OPERAND (current_exception_object, 0));
-      result = build_field_call (TYPE_BINFO (current_exception_type),
-                                instance_ptr, name, parms);
-      if (result)
-       return result;
-      cp_error ("exception member `%D' cannot be invoked", name);
-      return error_mark_node;
-    }
-  else
-    {
-      /* The MAIN_VARIANT of the type that `instance_ptr' winds up being.  */
-      tree inst_ptr_basetype;
+/* There are three conditions of builtin candidates:
 
-      static_call_context =
-       (TREE_CODE (instance) == INDIRECT_REF
-        && TREE_CODE (TREE_OPERAND (instance, 0)) == NOP_EXPR
-        && TREE_OPERAND (TREE_OPERAND (instance, 0), 0) == error_mark_node);
+   1) bool-taking candidates.  These are the same regardless of the input.
+   2) pointer-pair taking candidates.  These are generated for each type
+      one of the input types converts to.
+   3) arithmetic candidates.  According to the WP, we should generate
+      all of these, but I'm trying not to... */
 
-      /* the base type of an instance variable is pointer to class */
-      basetype = TREE_TYPE (instance);
+static struct z_candidate *
+add_builtin_candidates (candidates, code, code2, fnname, args, flags)
+     struct z_candidate *candidates;
+     enum tree_code code, code2;
+     tree fnname, *args;
+     int flags;
+{
+  int ref1, i;
+  tree type, argtypes[3], types[2];
 
-      if (TREE_CODE (basetype) == REFERENCE_TYPE)
-       {
-         basetype = TYPE_MAIN_VARIANT (TREE_TYPE (basetype));
-         if (! IS_AGGR_TYPE (basetype))
-           goto non_aggr_error;
-         /* Call to convert not needed because we are remaining
-            within the same type.  */
-         instance_ptr = build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), instance);
-         inst_ptr_basetype = basetype;
-       }
+  for (i = 0; i < 3; ++i)
+    {
+      if (args[i])
+       argtypes[i]  = lvalue_type (args[i]);
       else
-       {
-         if (! IS_AGGR_TYPE (basetype))
-           goto non_aggr_error;
+       argtypes[i] = NULL_TREE;
+    }
 
-         if (IS_SIGNATURE_POINTER (basetype)
-             || IS_SIGNATURE_REFERENCE (basetype))
-           basetype = SIGNATURE_TYPE (basetype);
+  switch (code)
+    {
+/* 4 For every pair T, VQ), where T is an arithmetic or  enumeration  type,
+     and  VQ  is  either  volatile or empty, there exist candidate operator
+     functions of the form
+                VQ T&   operator++(VQ T&);  */
+
+    case POSTINCREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case MODIFY_EXPR:
+      ref1 = 1;
+      break;
 
-         if ((IS_SIGNATURE (basetype)
-              && (instance_ptr = build_optr_ref (instance)))
-             || (lvalue_p (instance)
-              && (instance_ptr = build_unary_op (ADDR_EXPR, instance, 0)))
-             || (instance_ptr = unary_complex_lvalue (ADDR_EXPR, instance)))
-           {
-             if (instance_ptr == error_mark_node)
-               return error_mark_node;
-           }
-         else if (TREE_CODE (instance) == NOP_EXPR
-                  || TREE_CODE (instance) == CONSTRUCTOR)
-           {
-             /* A cast is not an lvalue.  Initialize a fresh temp
-                with the value we are casting from, and proceed with
-                that temporary.  We can't cast to a reference type,
-                so that simplifies the initialization to something
-                we can manage.  */
-             tree temp = get_temp_name (TREE_TYPE (instance), 0);
-             if (IS_AGGR_TYPE (TREE_TYPE (instance)))
-               expand_aggr_init (temp, instance, 0);
-             else
-               {
-                 store_init_value (temp, instance);
-                 expand_decl_init (temp);
-               }
-             instance = temp;
-             instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
+/* 24There also exist candidate operator functions of the form
+            bool    operator!(bool);
+            bool    operator&&(bool, bool);
+            bool    operator||(bool, bool);  */
+
+    case TRUTH_NOT_EXPR:
+      return build_builtin_candidate
+       (candidates, fnname, boolean_type_node,
+        NULL_TREE, args, argtypes, flags);
+
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_ANDIF_EXPR:
+      return build_builtin_candidate
+       (candidates, fnname, boolean_type_node,
+        boolean_type_node, args, argtypes, flags);
+
+    case ADDR_EXPR:
+    case COMPOUND_EXPR:
+    case COMPONENT_REF:
+      return candidates;
+
+    default:
+      ref1 = 0;
+    }
+
+  types[0] = types[1] = NULL_TREE;
+
+  for (i = 0; i < 2; ++i)
+    {
+      if (! args[i])
+       ;
+      else if (IS_AGGR_TYPE (argtypes[i]))
+       {
+         tree convs = lookup_conversions (argtypes[i]);
+
+         if (code == COND_EXPR)
+           {
+             if (real_lvalue_p (args[i]))
+               types[i] = tree_cons
+                 (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+
+             types[i] = tree_cons
+               (NULL_TREE, TYPE_MAIN_VARIANT (argtypes[i]), types[i]);
            }
-         else
+               
+         else if (! convs || (i == 0 && code == MODIFY_EXPR
+                              && code2 == NOP_EXPR))
+           return candidates;
+
+         for (; convs; convs = TREE_CHAIN (convs))
            {
-             if (TREE_CODE (instance) != CALL_EXPR)
-               my_friendly_abort (125);
-             if (TYPE_NEEDS_CONSTRUCTING (basetype))
-               instance = build_cplus_new (basetype, instance, 0);
-             else
+             type = TREE_TYPE (TREE_TYPE (TREE_VALUE (convs)));
+
+             if (i == 0 && ref1
+                 && (TREE_CODE (type) != REFERENCE_TYPE
+                     || TYPE_READONLY (TREE_TYPE (type))))
+               continue;
+
+             if (code == COND_EXPR && TREE_CODE (type) == REFERENCE_TYPE)
+               types[i] = tree_cons (NULL_TREE, type, types[i]);
+
+             type = non_reference (type);
+             if (i != 0 || ! ref1)
                {
-                 instance = get_temp_name (basetype, 0);
-                 TREE_ADDRESSABLE (instance) = 1;
+                 type = TYPE_MAIN_VARIANT (type_decays_to (type));
+                 if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
+                   types[i] = tree_cons (NULL_TREE, type, types[i]);
+                 if (INTEGRAL_TYPE_P (type))
+                   type = type_promotes_to (type);
                }
-             instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
+
+             if (! value_member (type, types[i]))
+               types[i] = tree_cons (NULL_TREE, type, types[i]);
            }
-         /* @@ Should we call comp_target_types here?  */
-         inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));
-         if (TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (inst_ptr_basetype))
-           basetype = inst_ptr_basetype;
-         else
+       }
+      else
+       {
+         if (code == COND_EXPR && real_lvalue_p (args[i]))
+           types[i] = tree_cons
+             (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+         type = non_reference (argtypes[i]);
+         if (i != 0 || ! ref1)
            {
-             instance_ptr = convert (TYPE_POINTER_TO (basetype), instance_ptr);
-             if (instance_ptr == error_mark_node)
-               return error_mark_node;
+             type = TYPE_MAIN_VARIANT (type_decays_to (type));
+             if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
+               types[i] = tree_cons (NULL_TREE, type, types[i]);
+             if (INTEGRAL_TYPE_P (type))
+               type = type_promotes_to (type);
            }
+         types[i] = tree_cons (NULL_TREE, type, types[i]);
        }
+    }
 
-      /* After converting `instance_ptr' above, `inst_ptr_basetype' was
-        not updated, so we use `basetype' instead.  */
-      if (basetype_path == NULL_TREE
-         && IS_SIGNATURE (basetype))
-       basetype_path = TYPE_BINFO (basetype);
-      else if (basetype_path == NULL_TREE ||
-       BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (inst_ptr_basetype))
-       basetype_path = TYPE_BINFO (inst_ptr_basetype);
+  for (; types[0]; types[0] = TREE_CHAIN (types[0]))
+    {
+      if (types[1])
+       for (type = types[1]; type; type = TREE_CHAIN (type))
+         candidates = add_builtin_candidate
+           (candidates, code, code2, fnname, TREE_VALUE (types[0]),
+            TREE_VALUE (type), args, argtypes, flags);
+      else
+       candidates = add_builtin_candidate
+         (candidates, code, code2, fnname, TREE_VALUE (types[0]),
+          NULL_TREE, args, argtypes, flags);
+    }
 
-      result = build_field_call (basetype_path, instance_ptr, name, parms);
-      if (result)
-       return result;
+  return candidates;
+}
 
-      if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
-       {
-         if (TREE_SIDE_EFFECTS (instance_ptr))
-           {
-             /* This action is needed because the instance is needed
-                for providing the base of the virtual function table.
-                Without using a SAVE_EXPR, the function we are building
-                may be called twice, or side effects on the instance
-                variable (such as a post-increment), may happen twice.  */
-             instance_ptr = save_expr (instance_ptr);
-             instance = build_indirect_ref (instance_ptr, NULL_PTR);
-           }
-         else if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
-           {
-             /* This happens when called for operator new ().  */
-             instance = build_indirect_ref (instance, NULL_PTR);
-           }
+static struct z_candidate *
+add_template_candidate (candidates, tmpl, arglist, flags)
+     struct z_candidate *candidates;
+     tree tmpl, arglist;
+     int flags;
+{
+  int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl));
+  tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
+  struct z_candidate *cand;
+  int i, dummy; 
+  tree fn;
+
+  i = type_unification (DECL_TEMPLATE_PARMS (tmpl), targs,
+                       TYPE_ARG_TYPES (TREE_TYPE (tmpl)),
+                       arglist, &dummy, 0, 0);
+  if (i != 0)
+    return candidates;
+
+  fn = instantiate_template (tmpl, targs);
+  if (fn == error_mark_node)
+    return candidates;
+
+  cand = add_function_candidate (candidates, fn, arglist, flags);
+  cand->template = DECL_TEMPLATE_INFO (fn);
+  return cand;
+}
 
-         need_vtbl = maybe_needed;
+static int
+any_viable (cands)
+     struct z_candidate *cands;
+{
+  for (; cands; cands = cands->next)
+    if (pedantic ? cands->viable == 1 : cands->viable)
+      return 1;
+  return 0;
+}
+
+static struct z_candidate *
+splice_viable (cands)
+     struct z_candidate *cands;
+{
+  struct z_candidate **p = &cands;
+
+  for (; *p; )
+    {
+      if (pedantic ? (*p)->viable == 1 : (*p)->viable)
+       p = &((*p)->next);
+      else
+       *p = (*p)->next;
+    }
+
+  return cands;
+}
+
+tree
+build_this (obj)
+     tree obj;
+{
+  /* Fix this to work on non-lvalues.  */
+  if (IS_SIGNATURE_POINTER (TREE_TYPE (obj))
+      || IS_SIGNATURE_REFERENCE (TREE_TYPE (obj)))
+    return obj;
+  else
+    return build_unary_op (ADDR_EXPR, obj, 0);
+}
+
+static void
+print_z_candidates (candidates)
+     struct z_candidate *candidates;
+{
+  char *str = "candidates are:";
+  for (; candidates; candidates = candidates->next)
+    {
+      if (TREE_CODE (candidates->fn) == IDENTIFIER_NODE)
+       {
+         if (candidates->fn == ansi_opname [COND_EXPR])
+           cp_error ("%s %D(%T, %T, %T) <builtin>", str, candidates->fn,
+                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)),
+                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 2)));
+         else if (TREE_VEC_LENGTH (candidates->convs) == 2)
+           cp_error ("%s %D(%T, %T) <builtin>", str, candidates->fn,
+                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)));
+         else
+           cp_error ("%s %D(%T) <builtin>", str, candidates->fn,
+                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)));
        }
+      else
+       cp_error_at ("%s %+D%s", str, candidates->fn,
+                    candidates->viable == -1 ? " <bad>" : "");
+      str = "               "; 
     }
+}
+
+/* Returns the best overload candidate to perform the requested
+   conversion.  */
+
+static struct z_candidate *
+build_user_type_conversion_1 (totype, expr, flags)
+     tree totype, expr;
+     int flags;
+{
+  struct z_candidate *candidates, *cand;
+  tree fromtype = TREE_TYPE (expr);
+  tree ctors = NULL_TREE, convs = NULL_TREE, *p;
+  tree args;
+
+  if (IS_AGGR_TYPE (totype))
+    ctors = lookup_fnfields (TYPE_BINFO (totype), ctor_identifier, 0);
+  if (IS_AGGR_TYPE (fromtype)
+      && (! IS_AGGR_TYPE (totype) || ! DERIVED_FROM_P (totype, fromtype)))
+    convs = lookup_conversions (fromtype);
+
+  candidates = 0;
+  flags |= LOOKUP_NO_CONVERSION;
 
-  if (TYPE_SIZE (basetype) == 0)
+  if (ctors)
     {
-      /* This is worth complaining about, I think.  */
-      cp_error ("cannot lookup method in incomplete type `%T'", basetype);
-      return error_mark_node;
+      tree t = build_int_2 (0, 0);
+      TREE_TYPE (t) = build_pointer_type (totype);
+      args = build_tree_list (NULL_TREE, expr);
+      if (TYPE_USES_VIRTUAL_BASECLASSES (totype))
+       args = tree_cons (NULL_TREE, integer_one_node, args);
+      args = tree_cons (NULL_TREE, t, args);
+
+      ctors = TREE_VALUE (ctors);
     }
+  for (; ctors; ctors = DECL_CHAIN (ctors))
+    {
+      if ((flags & LOOKUP_ONLYCONVERTING) && DECL_NONCONVERTING_P (ctors))
+       continue;
 
-  save_basetype = basetype;
+      candidates = add_function_candidate (candidates, ctors, args, flags);
+      candidates->second_conv = build1 (IDENTITY_CONV, totype, NULL_TREE);
+      candidates->basetype_path = TYPE_BINFO (totype);
+    }
 
-#if 0
-  if (all_virtual == 1
-      && (! strncmp (IDENTIFIER_POINTER (name), OPERATOR_METHOD_FORMAT,
-                    OPERATOR_METHOD_LENGTH)
-         || instance_ptr == NULL_TREE
-         || (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype) == 0)))
-    all_virtual = 0;
-#endif
+  if (convs)
+    args = build_tree_list (NULL_TREE, build_this (expr));
 
-  last = NULL_TREE;
-  for (parmtypes = NULL_TREE, parm = parms; parm; parm = TREE_CHAIN (parm))
+  for (; convs; convs = TREE_CHAIN (convs))
     {
-      tree t = TREE_TYPE (TREE_VALUE (parm));
-      if (TREE_CODE (t) == OFFSET_TYPE)
+      tree fn = TREE_VALUE (convs);
+      tree ics = implicit_conversion
+       (totype, TREE_TYPE (TREE_TYPE (fn)), 0, LOOKUP_NO_CONVERSION);
+      if (ics)
+       for (; fn; fn = DECL_CHAIN (fn))
+         {
+           candidates = add_function_candidate (candidates, fn, args, flags);
+           candidates->second_conv = ics;
+           candidates->basetype_path = TREE_PURPOSE (convs);
+           if (candidates->viable == 1 && ICS_BAD_FLAG (ics))
+             candidates->viable = -1;
+         }
+    }
+
+  if (! any_viable (candidates))
+    {
+#if 0
+      if (flags & LOOKUP_COMPLAIN)
        {
-         /* Convert OFFSET_TYPE entities to their normal selves.  */
-         TREE_VALUE (parm) = resolve_offset_ref (TREE_VALUE (parm));
-         t = TREE_TYPE (TREE_VALUE (parm));
+         if (candidates && ! candidates->next)
+           /* say why this one won't work or try to be loose */;
+         else
+           cp_error ("no viable candidates");
        }
-      if (TREE_CODE (t) == ARRAY_TYPE)
+#endif
+
+      return 0;
+    }
+
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates, totype);
+
+  if (cand == 0)
+    {
+      if (flags & LOOKUP_COMPLAIN)
        {
-         /* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
-            This eliminates needless calls to `compute_conversion_costs'.  */
-         TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
-         t = TREE_TYPE (TREE_VALUE (parm));
+         cp_error ("conversion from `%T' to `%T' is ambiguous",
+                   fromtype, totype);
+         print_z_candidates (candidates);
        }
-      if (t == error_mark_node)
-       return error_mark_node;
-      last = build_tree_list (NULL_TREE, t);
-      parmtypes = chainon (parmtypes, last);
+
+      cand = candidates;       /* any one will do */
+      cand->second_conv = build1 (AMBIG_CONV, totype, expr);
+      ICS_USER_FLAG (cand->second_conv) = 1;
+
+      return cand;
     }
 
-  if (instance)
+  for (p = &(cand->second_conv); TREE_CODE (*p) != IDENTITY_CONV; )
+    p = &(TREE_OPERAND (*p, 0));
+
+  *p = build
+    (USER_CONV,
+     (DECL_CONSTRUCTOR_P (cand->fn)
+      ? totype : non_reference (TREE_TYPE (TREE_TYPE (cand->fn)))),
+     NULL_TREE, cand->fn, cand->convs, cand->basetype_path);
+  ICS_USER_FLAG (cand->second_conv) = 1;
+
+  return cand;
+}
+
+tree
+build_user_type_conversion (totype, expr, flags)
+     tree totype, expr, flags;
+{
+  struct z_candidate *cand
+    = build_user_type_conversion_1 (totype, expr, flags);
+
+  if (cand)
     {
-      constp = TREE_READONLY (instance);
-      volatilep = TREE_THIS_VOLATILE (instance);
-      parms = tree_cons (NULL_TREE, instance_ptr, parms);
+      if (TREE_CODE (cand->second_conv) == AMBIG_CONV)
+       return error_mark_node;
+      return convert_from_reference (convert_like (cand->second_conv, expr));
     }
-  else
+  return NULL_TREE;
+}
+
+tree
+build_new_function_call (fn, args, obj)
+     tree fn, args, obj;
+{
+  struct z_candidate *candidates = 0, *cand;
+  if (obj == NULL_TREE && TREE_CODE (fn) == TREE_LIST)
     {
-      /* Raw constructors are always in charge.  */
-      if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
-         && ! (flags & LOOKUP_HAS_IN_CHARGE))
+      tree t;
+      tree templates = NULL_TREE;
+
+      for (t = args; t; t = TREE_CHAIN (t))
+       if (TREE_VALUE (t) == error_mark_node)
+         return error_mark_node;
+       
+      for (t = TREE_VALUE (fn); t; t = DECL_CHAIN (t))
        {
-         flags |= LOOKUP_HAS_IN_CHARGE;
-         parms = tree_cons (NULL_TREE, integer_one_node, parms);
-         parmtypes = tree_cons (NULL_TREE, integer_type_node, parmtypes);
+         if (TREE_CODE (t) == TEMPLATE_DECL)
+           {
+             templates = decl_tree_cons (NULL_TREE, t, templates);
+             candidates = add_template_candidate
+               (candidates, t, args, LOOKUP_NORMAL);
+           }
+         else
+           candidates = add_function_candidate
+             (candidates, t, args, LOOKUP_NORMAL);
        }
 
-      if (flag_this_is_variable > 0)
+      if (! any_viable (candidates))
        {
-         constp = 0;
-         volatilep = 0;
-         parms = tree_cons (NULL_TREE, build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node), parms);
+         if (candidates && ! candidates->next)
+           return build_function_call (candidates->fn, args);
+         else
+           cp_error ("no matching function for call to `%D (%A)'",
+                     TREE_PURPOSE (fn), args);
+         return error_mark_node;
        }
-      else
-       {
-         constp = 0;
-         volatilep = 0;
-         instance_ptr = build_new (NULL_TREE, basetype, void_type_node, 0);
-         if (instance_ptr == error_mark_node)
-           return error_mark_node;
-         instance_ptr = save_expr (instance_ptr);
-         TREE_CALLS_NEW (instance_ptr) = 1;
-         instance = build_indirect_ref (instance_ptr, NULL_PTR);
+      candidates = splice_viable (candidates);
+      cand = tourney (candidates, NULL_TREE);
 
-         /* If it's a default argument initialized from a ctor, what we get
-            from instance_ptr will match the arglist for the FUNCTION_DECL
-            of the constructor.  */
-         if (parms && TREE_CODE (TREE_VALUE (parms)) == CALL_EXPR
-             && TREE_OPERAND (TREE_VALUE (parms), 1)
-             && TREE_CALLS_NEW (TREE_VALUE (TREE_OPERAND (TREE_VALUE (parms), 1))))
-           parms = build_tree_list (NULL_TREE, instance_ptr);
-         else
-           parms = tree_cons (NULL_TREE, instance_ptr, parms);
+      if (cand == 0)
+       {
+         cp_error ("call of overloaded `%D (%A)' is ambiguous",
+                   TREE_PURPOSE (fn), args);
+         print_z_candidates (candidates);
+         return error_mark_node;
        }
+
+      /* Pedantically, it is ill-formed to define a function that could
+        also be a template instantiation, but we won't implement that
+        until things settle down.  */
+      if (templates && ! cand->template && ! DECL_INITIAL (cand->fn))
+       add_maybe_template (cand->fn, templates);
+
+      return build_over_call (cand->fn, cand->convs, args, LOOKUP_NORMAL);
     }
-  parmtypes = tree_cons (NULL_TREE,
-                        build_pointer_type (build_type_variant (basetype, constp, volatilep)),
-                        parmtypes);
-  if (last == NULL_TREE)
-    last = parmtypes;
 
-  /* Look up function name in the structure type definition.  */
+  return build_function_call (fn, args);
+}
 
-  if ((IDENTIFIER_HAS_TYPE_VALUE (name)
-       && IS_AGGR_TYPE (IDENTIFIER_TYPE_VALUE (name))
-       && TREE_CODE(IDENTIFIER_TYPE_VALUE (name)) != UNINSTANTIATED_P_TYPE)
-      || name == constructor_name (basetype))
+tree
+build_object_call (obj, args)
+     tree obj, args;
+{
+  struct z_candidate *candidates = 0, *cand;
+  tree fns, convs, mem_args, *p;
+  enum tree_code code2 = NOP_EXPR;
+  tree type = TREE_TYPE (obj);
+
+  fns = lookup_fnfields (TYPE_BINFO (type), ansi_opname [CALL_EXPR], 0);
+
+  if (fns)
     {
-      tree tmp = NULL_TREE;
-      if (IDENTIFIER_TYPE_VALUE (name) == basetype
-         || name == constructor_name (basetype))
-       tmp = TYPE_BINFO (basetype);
-      else
-       tmp = get_binfo (IDENTIFIER_TYPE_VALUE (name), basetype, 0);
-      
-      if (tmp != NULL_TREE)
+      tree fn = TREE_VALUE (fns);
+      mem_args = tree_cons (NULL_TREE, build_this (obj), args);
+
+      for (; fn; fn = DECL_CHAIN (fn))
        {
-         name_kind = "constructor";
-         
-         if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
-             && ! (flags & LOOKUP_HAS_IN_CHARGE))
-           {
-             /* Constructors called for initialization
-                only are never in charge.  */
-             tree tmplist;
-             
-             flags |= LOOKUP_HAS_IN_CHARGE;
-             tmplist = tree_cons (NULL_TREE, integer_zero_node,
-                                  TREE_CHAIN (parms));
-             TREE_CHAIN (parms) = tmplist;
-             tmplist = tree_cons (NULL_TREE, integer_type_node, TREE_CHAIN (parmtypes));
-             TREE_CHAIN (parmtypes) = tmplist;
-           }
-         basetype = BINFO_TYPE (tmp);
+         candidates = add_function_candidate
+           (candidates, fn, mem_args, LOOKUP_NORMAL);
+         candidates->basetype_path = TREE_PURPOSE (fns);
        }
+    }
+
+  convs = lookup_conversions (type);
+
+  for (; convs; convs = TREE_CHAIN (convs))
+    {
+      tree fn = TREE_VALUE (convs);
+      tree totype = TREE_TYPE (TREE_TYPE (fn));
+
+      if (TREE_CODE (totype) == POINTER_TYPE
+         && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
+       for (; fn; fn = DECL_CHAIN (fn))
+         {
+           candidates = add_conv_candidate (candidates, fn, obj, args);
+           candidates->basetype_path = TREE_PURPOSE (convs);
+         }
+    }
+
+  if (! any_viable (candidates))
+    {
+      cp_error ("no match for call to `(%T) (%A)'", TREE_TYPE (obj), args);
+      print_z_candidates (candidates);
+      return error_mark_node;
+    }
+
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates, NULL_TREE);
+
+  if (cand == 0)
+    {
+      cp_error ("call of `(%T) (%A)' is ambiguous", TREE_TYPE (obj), args);
+      print_z_candidates (candidates);
+      return error_mark_node;
+    }
+
+  if (DECL_NAME (cand->fn) == ansi_opname [CALL_EXPR])
+    return build_over_call (cand->fn, cand->convs, mem_args, LOOKUP_NORMAL);
+
+  obj = convert_like (TREE_VEC_ELT (cand->convs, 0), obj);
+
+  /* FIXME */
+  return build_function_call (obj, args);
+}
+
+static void
+op_error (code, code2, arg1, arg2, arg3, problem)
+     enum tree_code code, code2;
+     tree arg1, arg2, arg3;
+     char *problem;
+{
+  char * opname
+    = (code == MODIFY_EXPR ? assignop_tab [code2] : opname_tab [code]);
+
+  switch (code)
+    {
+    case COND_EXPR:
+      cp_error ("%s for `%T ? %T : %T'", problem,
+               error_type (arg1), error_type (arg2), error_type (arg3));
+      break;
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      cp_error ("%s for `%T%s'", problem, error_type (arg1), opname);
+      break;
+    case ARRAY_REF:
+      cp_error ("%s for `%T[%T]'", problem,
+               error_type (arg1), error_type (arg2));
+      break;
+    default:
+      if (arg2)
+       cp_error ("%s for `%T %s %T'", problem,
+                 error_type (arg1), opname, error_type (arg2));
       else
-       name_kind = "method";
+       cp_error ("%s for `%s%T'", problem, opname, error_type (arg1));
     }
-  else
-    name_kind = "method";
-  
-  if (basetype_path == NULL_TREE
-      || BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (basetype))
-    basetype_path = TYPE_BINFO (basetype);
-  result = lookup_fnfields (basetype_path, name,
-                           (flags & LOOKUP_COMPLAIN));
-  if (result == error_mark_node)
+}
+
+tree
+build_new_op (code, flags, arg1, arg2, arg3)
+     enum tree_code code;
+     int flags;
+     tree arg1, arg2, arg3;
+{
+  struct z_candidate *candidates = 0, *cand;
+  tree fns, mem_arglist, arglist, fnname, *p;
+  enum tree_code code2 = NOP_EXPR;
+  tree templates = NULL_TREE;
+
+  if (arg1 == error_mark_node
+      || arg2 == error_mark_node
+      || arg3 == error_mark_node)
     return error_mark_node;
 
+  if (code == MODIFY_EXPR)
+    {
+      code2 = TREE_CODE (arg3);
+      arg3 = NULL_TREE;
+      fnname = ansi_assopname[code2];
+    }
+  else
+    fnname = ansi_opname[code];
+
+  switch (code)
+    {
+    case NEW_EXPR:
+    case VEC_NEW_EXPR:
+      {
+       tree rval;
+
+       arglist = tree_cons (NULL_TREE, arg2, arg3);
+       if (flags & LOOKUP_GLOBAL)
+         return build_new_function_call
+           (lookup_name_nonclass (fnname), arglist, NULL_TREE);
+
+       /* FIXME */
+       rval = build_method_call
+         (build_indirect_ref (build1 (NOP_EXPR, arg1, error_mark_node),
+                              "new"),
+          fnname, arglist, NULL_TREE, flags);
+       if (rval == error_mark_node)
+         /* User might declare fancy operator new, but invoke it
+            like standard one.  */
+         return rval;
+
+       TREE_TYPE (rval) = arg1;
+       TREE_CALLS_NEW (rval) = 1;
+       return rval;
+      }
+
+    case VEC_DELETE_EXPR:
+    case DELETE_EXPR:
+      {
+       tree rval;
+
+       if (flags & LOOKUP_GLOBAL)
+         return build_new_function_call
+           (lookup_name_nonclass (fnname),
+            build_tree_list (NULL_TREE, arg1), NULL_TREE);
 
-  /* Now, go look for this method name.  We do not find destructors here.
+       arglist = tree_cons (NULL_TREE, arg1, build_tree_list (NULL_TREE, arg2));
 
-     Putting `void_list_node' on the end of the parmtypes
-     fakes out `build_decl_overload' into doing the right thing.  */
-  TREE_CHAIN (last) = void_list_node;
-  method_name = build_decl_overload (name, parmtypes,
-                                    1 + (name == constructor_name (save_basetype)
-                                         || name == constructor_name_full (save_basetype)));
-  TREE_CHAIN (last) = NULL_TREE;
+       arg1 = TREE_TYPE (arg1);
 
-  for (pass = 0; pass < 2; pass++)
-    {
-      struct candidate *candidates;
-      struct candidate *cp;
-      int len;
-      unsigned best = 1;
+       /* This handles the case where we're trying to delete
+          X (*a)[10];
+          a=new X[5][10];
+          delete[] a; */
+          
+       if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE)
+         {
+           /* Strip off the pointer and the array.  */
+           arg1 = TREE_TYPE (TREE_TYPE (arg1));
 
-      /* This increments every time we go up the type hierarchy.
-        The idea is to prefer a function of the derived class if possible. */
-      int b_or_d = 0;
+           while (TREE_CODE (arg1) == ARRAY_TYPE)
+               arg1 = (TREE_TYPE (arg1));
 
-      baselink = result;
+           arg1 = build_pointer_type (arg1);
+         }
 
-      if (pass > 0)
-       {
-         candidates
-           = (struct candidate *) alloca ((ever_seen+1)
-                                          * sizeof (struct candidate));
-         bzero (candidates, (ever_seen + 1) * sizeof (struct candidate));
-         cp = candidates;
-         len = list_length (parms);
-         ever_seen = 0;
+       /* FIXME */
+       rval = build_method_call
+         (build_indirect_ref (build1 (NOP_EXPR, arg1,
+                                      error_mark_node),
+                              NULL_PTR),
+          fnname, arglist, NULL_TREE, flags);
+#if 0
+       /* This can happen when operator delete is protected.  */
+       my_friendly_assert (rval != error_mark_node, 250);
+       TREE_TYPE (rval) = void_type_node;
+#endif
+       return rval;
+      }
 
-         /* First see if a global function has a shot at it.  */
-         if (flags & LOOKUP_GLOBAL)
-           {
-             tree friend_parms;
-             tree parm = TREE_VALUE (parms);
+    case CALL_EXPR:
+      return build_object_call (arg1, arg2);
+    }
 
-             if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE)
-               friend_parms = parms;
-             else if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
-               {
-                 tree new_type;
-                 parm = build_indirect_ref (parm, "friendifying parms (compiler error)");
-                 new_type = build_reference_type (TREE_TYPE (parm));
-                 /* It is possible that this should go down a layer. */
-                 new_type = build_type_variant (new_type,
-                                                TREE_READONLY (parm),
-                                                TREE_THIS_VOLATILE (parm));
-                 parm = convert (new_type, parm);
-                 friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
-               }
-             else
-               my_friendly_abort (167);
+  /* The comma operator can have void args.  */
+  if (TREE_CODE (arg1) == OFFSET_REF)
+    arg1 = resolve_offset_ref (arg1);
+  if (arg2 && TREE_CODE (arg2) == OFFSET_REF)
+    arg2 = resolve_offset_ref (arg2);
+  if (arg3 && TREE_CODE (arg3) == OFFSET_REF)
+    arg3 = resolve_offset_ref (arg3);
 
-             cp->h_len = len;
-             if (flag_ansi_overloading)
-               cp->v.ansi_harshness = (struct harshness_code *)
-                 alloca ((len + 1) * sizeof (struct harshness_code));
-             else
-               cp->v.old_harshness = (unsigned short *)
-                 alloca ((len + 1) * sizeof (unsigned short));
+  if (code == COND_EXPR)
+    {
+      if (TREE_CODE (TREE_TYPE (arg2)) == VOID_TYPE
+         || TREE_CODE (TREE_TYPE (arg3)) == VOID_TYPE
+         || (! IS_OVERLOAD_TYPE (TREE_TYPE (arg2))
+             && ! IS_OVERLOAD_TYPE (TREE_TYPE (arg3))))
+       goto builtin;
+    }
+  else if (! IS_OVERLOAD_TYPE (TREE_TYPE (arg1))
+          && (! arg2 || ! IS_OVERLOAD_TYPE (TREE_TYPE (arg2))))
+    goto builtin;
 
-             result = build_overload_call (name, friend_parms, 0, cp);
-             /* If it turns out to be the one we were actually looking for
-                (it was probably a friend function), the return the
-                good result.  */
-             if (TREE_CODE (result) == CALL_EXPR)
-               return result;
+  if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
+    arg2 = integer_zero_node;
 
-             if (flag_ansi_overloading)
-               while ((cp->h.code & EVIL_CODE) == 0)
-                 {
-                   /* non-standard uses: set the field to 0 to indicate
-                      we are using a non-member function.  */
-                   cp->u.field = 0;
-                   if (cp->v.ansi_harshness[len].distance == 0
-                       && cp->h.code < best)
-                     best = cp->h.code;
-                   cp += 1;
-                 }
-             else
-               while (cp->evil == 0)
-                 {
-                   /* non-standard uses: set the field to 0 to indicate
-                      we are using a non-member function.  */
-                   cp->u.field = 0;
-                   if (cp->v.old_harshness[len] == 0
-                       && cp->v.old_harshness[len] == 0
-                       && cp->ellipsis == 0 && cp->user == 0 && cp->b_or_d == 0
-                       && cp->easy < best)
-                     best = cp->easy;
-                   cp += 1;
-                 }
-           }
+  fns = lookup_name_nonclass (fnname);
+  /* + Koenig lookup */
+
+  if (arg2 && arg3)
+    arglist = tree_cons (NULL_TREE, arg1, tree_cons
+                     (NULL_TREE, arg2, build_tree_list (NULL_TREE, arg3)));
+  else if (arg2)
+    arglist = tree_cons (NULL_TREE, arg1, build_tree_list (NULL_TREE, arg2));
+  else
+    arglist = build_tree_list (NULL_TREE, arg1);
+
+  if (fns && TREE_CODE (fns) == TREE_LIST)
+    fns = TREE_VALUE (fns);
+  for (; fns; fns = DECL_CHAIN (fns))
+    {
+      if (TREE_CODE (fns) == TEMPLATE_DECL)
+       {
+         templates = decl_tree_cons (NULL_TREE, fns, templates);
+         candidates = add_template_candidate
+           (candidates, fns, arglist, flags);
        }
+      else
+       candidates = add_function_candidate (candidates, fns, arglist, flags);
+    }
+
+  if (IS_AGGR_TYPE (TREE_TYPE (arg1)))
+    fns = lookup_fnfields (TYPE_BINFO (TREE_TYPE (arg1)), fnname, 0);
+  else
+    fns = NULL_TREE;
 
-      while (baselink)
+  if (fns)
+    {
+      tree fn = TREE_VALUE (fns);
+      mem_arglist = tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
+      for (; fn; fn = DECL_CHAIN (fn))
        {
-         /* We have a hit (of sorts). If the parameter list is
-            "error_mark_node", or some variant thereof, it won't
-            match any methods.  Since we have verified that the is
-            some method vaguely matching this one (in name at least),
-            silently return.
-            
-            Don't stop for friends, however.  */
-         basetype_path = TREE_PURPOSE (baselink);
+         if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+           candidates = add_function_candidate
+             (candidates, fn, mem_arglist, flags);
+         else
+           candidates = add_function_candidate (candidates, fn, arglist, flags);
+         
+         candidates->basetype_path = TREE_PURPOSE (fns);
+       }
+    }
 
-         function = TREE_VALUE (baselink);
-         if (TREE_CODE (basetype_path) == TREE_LIST)
-           basetype_path = TREE_VALUE (basetype_path);
-         basetype = BINFO_TYPE (basetype_path);
+  {
+    tree args[3];
 
-         /* Cast the instance variable to the appropriate type.  */
-         TREE_VALUE (parms) = convert_force (TYPE_POINTER_TO (basetype),
-                                             instance_ptr);
-         /* FIXME: this is the wrong place to get an error.  Hopefully
-            the access-control rewrite will make this change more cleanly.  */
-         if (TREE_VALUE (parms) == error_mark_node)
-           return error_mark_node;
+    /* Rearrange the arguments for ?: so that add_builtin_candidate only has
+       to know about two args; a builtin candidate will always have a first
+       parameter of type bool.  We'll handle that in
+       build_builtin_candidate.  */
+    if (code == COND_EXPR)
+      {
+       args[0] = arg2;
+       args[1] = arg3;
+       args[2] = arg1;
+      }
+    else
+      {
+       args[0] = arg1;
+       args[1] = arg2;
+       args[2] = NULL_TREE;
+      }
 
-         if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function)))
-           function = DECL_CHAIN (function);
+    candidates = add_builtin_candidates
+      (candidates, code, code2, fnname, args, flags);
+  }
 
-         for (; function; function = DECL_CHAIN (function))
-           {
-#ifdef GATHER_STATISTICS
-             n_inner_fields_searched++;
-#endif
-             ever_seen++;
-             if (pass > 0)
-               found_fns = tree_cons (NULL_TREE, function, found_fns);
+  if (! any_viable (candidates))
+    {
+      switch (code)
+       {
+       case POSTINCREMENT_EXPR:
+       case POSTDECREMENT_EXPR:
+         /* Look for an `operator++ (int)'.  If they didn't have
+            one, then we fall back to the old way of doing things.  */
+         if (flags & LOOKUP_COMPLAIN)
+           cp_pedwarn ("no `%D (int)' declared for postfix `%s', trying prefix operator instead",
+                       fnname, opname_tab [code]);
+         if (code == POSTINCREMENT_EXPR)
+           code = PREINCREMENT_EXPR;
+         else
+           code = PREDECREMENT_EXPR;   
+         return build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE);
+         
+         /* The caller will deal with these.  */
+       case ADDR_EXPR:
+       case COMPOUND_EXPR:
+       case COMPONENT_REF:
+         return NULL_TREE;
+       }
+      if (flags & LOOKUP_COMPLAIN)
+       {
+         op_error (code, code2, arg1, arg2, arg3, "no match");
+         print_z_candidates (candidates);
+       }
+      return error_mark_node;
+    }
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates, NULL_TREE);
 
-             /* Not looking for friends here.  */
-             if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE
-                 && ! DECL_STATIC_FUNCTION_P (function))
-               continue;
+  if (cand == 0)
+    {
+      if (flags & LOOKUP_COMPLAIN)
+       {
+         op_error (code, code2, arg1, arg2, arg3, "ambiguous overload");
+         print_z_candidates (candidates);
+       }
+      return error_mark_node;
+    }
 
-             if (pass == 0
-                 && DECL_ASSEMBLER_NAME (function) == method_name)
-               goto found;
+  if (TREE_CODE (cand->fn) == FUNCTION_DECL)
+    {
+      extern int warn_synth;
+      if (warn_synth
+         && fnname == ansi_opname[MODIFY_EXPR]
+         && DECL_ARTIFICIAL (cand->fn)
+         && candidates->next
+         && ! candidates->next->next)
+       {
+         cp_warning ("using synthesized `%#D' for copy assignment",
+                     cand->fn);
+         cp_warning_at ("  where cfront would use `%#D'",
+                        cand == candidates
+                        ? candidates->next->fn
+                        : candidates->fn);
+       }
 
-             if (pass > 0)
-               {
-                 tree these_parms = parms;
+      if (DECL_FUNCTION_MEMBER_P (cand->fn))
+       enforce_access (cand->basetype_path, cand->fn);
+
+      /* Pedantically, it is ill-formed to define a function that could
+        also be a template instantiation, but we won't implement that
+        until things settle down.  */
+      if (templates && ! cand->template && ! DECL_INITIAL (cand->fn)
+         && TREE_CODE (TREE_TYPE (cand->fn)) != METHOD_TYPE)
+       add_maybe_template (cand->fn, templates);
+
+      return build_over_call
+       (cand->fn, cand->convs,
+        TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
+        ? mem_arglist : arglist,
+        LOOKUP_NORMAL);
+    }
 
-#ifdef GATHER_STATISTICS
-                 n_inner_fields_searched++;
-#endif
-                 cp->h_len = len;
-                 if (flag_ansi_overloading)
-                   cp->v.ansi_harshness = (struct harshness_code *)
-                     alloca ((len + 1) * sizeof (struct harshness_code));
-                 else
-                   cp->v.old_harshness = (unsigned short *)
-                     alloca ((len + 1) * sizeof (unsigned short));
+  /* Check for comparison of different enum types.  */
+  switch (code)
+    {
+    case GT_EXPR:
+    case LT_EXPR:
+    case GE_EXPR:
+    case LE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+      if (flag_int_enum_equivalence == 0 
+         && TREE_CODE (TREE_TYPE (arg1)) == ENUMERAL_TYPE 
+         && TREE_CODE (TREE_TYPE (arg2)) == ENUMERAL_TYPE 
+         && (TYPE_MAIN_VARIANT (TREE_TYPE (arg1))
+             != TYPE_MAIN_VARIANT (TREE_TYPE (arg2))))
+       {
+         cp_warning ("comparison between `%#T' and `%#T'", 
+                     TREE_TYPE (arg1), TREE_TYPE (arg2));
+       }
+    }
 
-                 if (DECL_STATIC_FUNCTION_P (function))
-                   these_parms = TREE_CHAIN (these_parms);
-                 compute_conversion_costs (function, these_parms, cp, len);
+  arg1 = convert_from_reference
+    (convert_like (TREE_VEC_ELT (cand->convs, 0), arg1));
+  if (arg2)
+    arg2 = convert_like (TREE_VEC_ELT (cand->convs, 1), arg2);
+  if (arg3)
+    arg3 = convert_like (TREE_VEC_ELT (cand->convs, 2), arg3);
 
-                 if (!flag_ansi_overloading)
-                     cp->b_or_d += b_or_d;
+builtin:
+  switch (code)
+    {
+    case MODIFY_EXPR:
+      return build_modify_expr (arg1, code2, arg2);
+
+    case INDIRECT_REF:
+      return build_indirect_ref (arg1, "unary *");
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case GT_EXPR:
+    case LT_EXPR:
+    case GE_EXPR:
+    case LE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case MAX_EXPR:
+    case MIN_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case TRUNC_MOD_EXPR:
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+      return build_binary_op_nodefault (code, arg1, arg2, code);
+
+    case CONVERT_EXPR:
+    case NEGATE_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      return build_unary_op (code, arg1, candidates != 0);
+
+    case ARRAY_REF:
+      return build_array_ref (arg1, arg2);
+
+    case COND_EXPR:
+      return build_conditional_expr (arg1, arg2, arg3);
+
+    case MEMBER_REF:
+      return build_m_component_ref
+       (build_indirect_ref (arg1, NULL_PTR), arg2);
+
+      /* The caller will deal with these.  */
+    case ADDR_EXPR:
+    case COMPONENT_REF:
+    case COMPOUND_EXPR:
+      return NULL_TREE;
 
-                 if ((flag_ansi_overloading && (cp->h.code & EVIL_CODE) == 0)
-                     || (!flag_ansi_overloading && cp->evil == 0))
-                   {
-                     cp->u.field = function;
-                     cp->function = function;
-                     cp->basetypes = basetype_path;
+    default:
+      my_friendly_abort (367);
+    }
+}
 
-                     /* No "two-level" conversions.  */
-                     if (flags & LOOKUP_NO_CONVERSION
-                         && ((flag_ansi_overloading
-                              && (cp->h.code & USER_CODE))
-                             || (!flag_ansi_overloading
-                                 && cp->user != 0)))
-                       continue;
+static void
+enforce_access (basetype_path, function)
+     tree basetype_path, function;
+{
+  tree access = compute_access (basetype_path, function);
 
-                     /* If we used default parameters, we must
-                        check to see whether anyone else might
-                        use them also, and report a possible
-                        ambiguity.  */
-                     if (! TYPE_USES_MULTIPLE_INHERITANCE (save_basetype)
-                         && ((flag_ansi_overloading
-                              && cp->v.ansi_harshness[len].distance == 0
-                              && cp->h.code < best)
-                             || (!flag_ansi_overloading
-                                 && cp->v.old_harshness[len] == 0
-                                 && CONST_HARSHNESS (cp->v.old_harshness[0]) == 0
-                                 && cp->ellipsis == 0 && cp->user == 0 && cp->b_or_d == 0
-                                 && cp->easy < best)))
-                       {
-                         if (! DECL_STATIC_FUNCTION_P (function))
-                           TREE_VALUE (parms) = cp->arg;
-                         if (best == 1)
-                           goto found_and_maybe_warn;
-                       }
-                     cp++;
-                   }
-               }
-           }
-         /* Now we have run through one link's member functions.
-            arrange to head-insert this link's links.  */
-         baselink = next_baselink (baselink);
-         b_or_d += 1;
-         /* Don't grab functions from base classes.  lookup_fnfield will
-            do the work to get us down into the right place.  */
-         baselink = NULL_TREE;
-       }
-      if (pass == 0)
-       {
-         tree igv = IDENTIFIER_GLOBAL_VALUE (name);
+  if (access == access_private_node)
+    {
+      cp_error_at ("`%+#D' is %s", function, 
+                  TREE_PRIVATE (function) ? "private"
+                  : "from private base class");
+      error ("within this context");
+    }
+  else if (access == access_protected_node)
+    {
+      cp_error_at ("`%+#D' %s", function,
+                  TREE_PROTECTED (function) ? "is protected"
+                  : "has protected accessibility");
+      error ("within this context");
+    }
+}
 
-         /* No exact match could be found.  Now try to find match
-            using default conversions.  */
-         if ((flags & LOOKUP_GLOBAL) && igv)
-           {
-             if (TREE_CODE (igv) == FUNCTION_DECL)
-               ever_seen += 1;
-             else if (TREE_CODE (igv) == TREE_LIST)
-               ever_seen += count_functions (igv);
-           }
+/* Perform the conversions in CONVS on the expression EXPR.  */
 
-         if (ever_seen == 0)
+static tree
+convert_like (convs, expr)
+     tree convs, expr;
+{
+  if (ICS_BAD_FLAG (convs))
+    {
+      tree t = convs; 
+      for (; t; t = TREE_OPERAND (t, 0))
+       {
+         if (TREE_CODE (t) == USER_CONV)
            {
-             if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
-                 == LOOKUP_SPECULATIVELY)
-               return NULL_TREE;
-             
-             TREE_CHAIN (last) = void_list_node;
-             if (flags & LOOKUP_GLOBAL)
-               cp_error ("no global or member function `%D(%A)' defined",
-                         name, parmtypes);
-             else
-               cp_error ("no member function `%T::%D(%A)' defined",
-                         save_basetype, name, TREE_CHAIN (parmtypes));
-             return error_mark_node;
+             expr = convert_like (t, expr);
+             break;
            }
-         continue;
+         else if (TREE_CODE (t) == AMBIG_CONV)
+           return convert_like (t, expr);
+         else if (TREE_CODE (t) == IDENTITY_CONV)
+           break;
        }
+      return convert_for_initialization
+       (NULL_TREE, TREE_TYPE (convs), expr, LOOKUP_NORMAL,
+        "conversion", NULL_TREE, 0);
+    }
 
-      if (cp - candidates != 0)
-       {
-         /* Rank from worst to best.  Then cp will point to best one.
-            Private fields have their bits flipped.  For unsigned
-            numbers, this should make them look very large.
-            If the best alternate has a (signed) negative value,
-            then all we ever saw were private members.  */
-         if (cp - candidates > 1)
-           {
-             cp = ideal_candidate (save_basetype, candidates,
-                                   cp - candidates, parms, len);
-             if (cp == (struct candidate *)0)
-               {
-                 cp_error ("ambiguous type conversion requested for %s `%D'",
-                           name_kind, name);
-                 return error_mark_node;
-               }
-             if ((flag_ansi_overloading && (cp->h.code & EVIL_CODE))
-                 || (!flag_ansi_overloading && cp->evil))
-               return error_mark_node;
-           }
-         else if ((flag_ansi_overloading && (cp[-1].h.code & EVIL_CODE))
-                  || (!flag_ansi_overloading && cp[-1].evil == 2))
-           {
-             cp_error ("ambiguous type conversion requested for %s `%D'",
-                       name_kind, name);
-             return error_mark_node;
-           }
-         else
-           cp--;
+  switch (TREE_CODE (convs))
+    {
+    case USER_CONV:
+      {
+       tree fn = TREE_OPERAND (convs, 1);
+       tree args;
+       enforce_access (TREE_OPERAND (convs, 3), fn);
 
-         /* The global function was the best, so use it.  */
-         if (cp->u.field == 0)
-           {
-             /* We must convert the instance pointer into a reference type.
-                Global overloaded functions can only either take
-                aggregate objects (which come for free from references)
-                or reference data types anyway.  */
-             TREE_VALUE (parms) = copy_node (instance_ptr);
-             TREE_TYPE (TREE_VALUE (parms)) = build_reference_type (TREE_TYPE (TREE_TYPE (instance_ptr)));
-             return build_function_call (cp->function, parms);
-           }
+       if (DECL_CONSTRUCTOR_P (fn))
+         {
+           tree t = build_int_2 (0, 0);
+           TREE_TYPE (t) = build_pointer_type (DECL_CONTEXT (fn));
 
-         function = cp->function;
-         basetype_path = cp->basetypes;
-         if (! DECL_STATIC_FUNCTION_P (function))
-           TREE_VALUE (parms) = cp->arg;
-         goto found_and_maybe_warn;
-       }
+           args = build_tree_list (NULL_TREE, expr);
+           if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+             args = tree_cons (NULL_TREE, integer_one_node, args);
+           args = tree_cons (NULL_TREE, t, args);
+         }
+       else
+         args = build_this (expr);
+       expr = build_over_call
+         (TREE_OPERAND (convs, 1), TREE_OPERAND (convs, 2),
+          args, LOOKUP_NORMAL);
 
-      if ((flags & ~LOOKUP_GLOBAL) & (LOOKUP_COMPLAIN|LOOKUP_SPECULATIVELY))
-       {
-         if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
-             == LOOKUP_SPECULATIVELY)
-           return NULL_TREE;
+       /* If this is a constructor or a function returning an aggr type,
+          we need to build up a TARGET_EXPR.  */
+       if (DECL_CONSTRUCTOR_P (fn))
+         expr = build_cplus_new (TREE_TYPE (convs), expr);
 
-         if (DECL_STATIC_FUNCTION_P (cp->function))
-           parms = TREE_CHAIN (parms);
-         if (ever_seen)
-           {
-             if (flags & LOOKUP_SPECULATIVELY)
-               return NULL_TREE;
-             if (static_call_context
-                 && TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
-               cp_error ("object missing in call to `%D'", cp->function);
-             else if (ever_seen > 1)
-               {
-                 TREE_CHAIN (last) = void_list_node;
-                 cp_error ("no matching function for call to `%T::%D (%A)'",
-                           TREE_TYPE (TREE_TYPE (instance_ptr)),
-                           name, TREE_CHAIN (parmtypes));
-                 TREE_CHAIN (last) = NULL_TREE;
-                 print_candidates (found_fns);
-               }
-             else
-               report_type_mismatch (cp, parms, name_kind);
-             return error_mark_node;
-           }
+       return expr;
+      }
+    case IDENTITY_CONV:
+      if (type_unknown_p (expr))
+       expr = instantiate_type (TREE_TYPE (convs), expr, 1);
+      if (TREE_READONLY_DECL_P (expr))
+       expr = decl_constant_value (expr);
+      return expr;
+    case AMBIG_CONV:
+      /* Call build_user_type_conversion again for the error.  */
+      return build_user_type_conversion
+       (TREE_TYPE (convs), TREE_OPERAND (convs, 0), LOOKUP_NORMAL);
+    };
+
+  expr = convert_like (TREE_OPERAND (convs, 0), expr);
+  if (expr == error_mark_node)
+    return error_mark_node;
 
-         if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
-             == LOOKUP_COMPLAIN)
-           {
-             cp_error ("%T has no method named %D", save_basetype, name);
-             return error_mark_node;
-           }
-         return NULL_TREE;
-       }
-      continue;
+  switch (TREE_CODE (convs))
+    {
+    case BASE_CONV:
+    case RVALUE_CONV:
+      return build_user_type_conversion
+       (TREE_TYPE (convs), expr, LOOKUP_NORMAL);
+    case REF_BIND:
+      return convert_to_reference
+       (TREE_TYPE (convs), expr,
+        CONV_IMPLICIT, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION|INDIRECT_BIND,
+        error_mark_node);
+    case LVALUE_CONV:
+      return decay_conversion (expr);
+    }
+  return cp_convert (TREE_TYPE (convs), expr, CONV_IMPLICIT,
+                    LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
+}
 
-    found_and_maybe_warn:
-      if ((flag_ansi_overloading
-          && (cp->v.ansi_harshness[0].code & CONST_CODE))
-         || (!flag_ansi_overloading
-             && CONST_HARSHNESS (cp->v.old_harshness[0])))
-       {
-         if (flags & LOOKUP_COMPLAIN)
-           {
-             cp_error_at ("non-const member function `%D'", cp->function);
-             error ("called for const object at this point in file");
-           }
-         /* Not good enough for a match.  */
-         else
-           return error_mark_node;
-       }
-      goto found;
+static tree
+convert_default_arg (type, arg)
+     tree type, arg;
+{
+  arg = break_out_target_exprs (arg);
+
+  if (TREE_CODE (arg) == CONSTRUCTOR)
+    {
+      arg = digest_init (type, arg, 0);
+      arg = convert_for_initialization (0, type, arg, LOOKUP_NORMAL,
+                                       "default argument", 0, 0);
+    }
+  else
+    {
+      /* This could get clobbered by the following call.  */
+      if (TREE_HAS_CONSTRUCTOR (arg))
+       arg = copy_node (arg);
+
+      arg = convert_for_initialization (0, type, arg, LOOKUP_NORMAL,
+                                       "default argument", 0, 0);
+#ifdef PROMOTE_PROTOTYPES
+      if ((TREE_CODE (type) == INTEGER_TYPE
+          || TREE_CODE (type) == ENUMERAL_TYPE)
+         && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+       arg = default_conversion (arg);
+#endif
     }
-  /* Silently return error_mark_node.  */
-  return error_mark_node;
 
- found:
-  if (flags & LOOKUP_PROTECT)
-    access = compute_access (basetype_path, function);
+  return arg;
+}
 
-  if (access == access_private)
+static tree
+build_over_call (fn, convs, args, flags)
+     tree fn, convs, args;
+     int flags;
+{
+  tree converted_args = NULL_TREE;
+  tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
+  tree conv, arg, val;
+  int i = 0;
+  int is_method = 0;
+
+  if (args && TREE_CODE (args) != TREE_LIST)
+    args = build_tree_list (NULL_TREE, args);
+  arg = args;
+
+  /* The implicit parameters to a constructor are not considered by overload
+     resolution, and must be of the proper type.  */
+  if (DECL_CONSTRUCTOR_P (fn))
     {
-      if (flags & LOOKUP_COMPLAIN)
+      converted_args = tree_cons (NULL_TREE, TREE_VALUE (arg), converted_args);
+      arg = TREE_CHAIN (arg);
+      parm = TREE_CHAIN (parm);
+      if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
        {
-         cp_error_at ("%s `%+#D' is %s", name_kind, function, 
-                      TREE_PRIVATE (function) ? "private"
-                      : "from private base class");
-         error ("within this context");
+         converted_args = tree_cons
+           (NULL_TREE, TREE_VALUE (arg), converted_args);
+         arg = TREE_CHAIN (arg);
+         parm = TREE_CHAIN (parm);
        }
-      return error_mark_node;
-    }
-  else if (access == access_protected)
+    }      
+  /* Bypass access control for 'this' parameter.  */
+  else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
     {
-      if (flags & LOOKUP_COMPLAIN)
+      tree parmtype = TREE_VALUE (parm);
+      tree argtype = TREE_TYPE (TREE_VALUE (arg));
+      if (ICS_BAD_FLAG (TREE_VEC_ELT (convs, i)))
        {
-         cp_error_at ("%s `%+#D' %s", name_kind, function,
-                      TREE_PROTECTED (function) ? "is protected"
-                      : "has protected accessibility");
-         error ("within this context");
+         int dv = (TYPE_VOLATILE (TREE_TYPE (parmtype))
+                   < TYPE_VOLATILE (TREE_TYPE (argtype)));
+         int dc = (TYPE_READONLY (TREE_TYPE (parmtype))
+                   < TYPE_READONLY (TREE_TYPE (argtype)));
+         char *p = (dv && dc ? "const and volatile" :
+                    dc ? "const" : dv ? "volatile" : "");
+
+         cp_pedwarn ("passing `%T' as `this' argument of `%#D' discards %s",
+                     TREE_TYPE (argtype), fn, p);
        }
-      return error_mark_node;
+      converted_args = tree_cons
+       (NULL_TREE, convert_force (TREE_VALUE (parm), TREE_VALUE (arg), CONV_C_CAST),
+        converted_args);
+      parm = TREE_CHAIN (parm);
+      arg = TREE_CHAIN (arg);
+      ++i;
+      is_method = 1;
     }
 
-  /* From here on down, BASETYPE is the type that INSTANCE_PTR's
-     type (if it exists) is a pointer to.  */
-
-  if (IS_SIGNATURE (basetype) && static_call_context)
+  for (; conv = TREE_VEC_ELT (convs, i), arg && parm;
+       parm = TREE_CHAIN (parm), arg = TREE_CHAIN (arg), ++i)
     {
-      cp_error ("cannot call signature member function `%T::%D' without signature pointer/reference",
-               basetype, name);
-      return error_mark_node;
+      tree type = TREE_VALUE (parm);
+
+      if (ICS_BAD_FLAG (conv))
+       {
+         tree t = conv;
+         val = TREE_VALUE (arg);
+
+         for (; t; t = TREE_OPERAND (t, 0))
+           {
+             if (TREE_CODE (t) == USER_CONV
+                 || TREE_CODE (t) == AMBIG_CONV)
+               {
+                 val = convert_like (t, val);
+                 break;
+               }
+             else if (TREE_CODE (t) == IDENTITY_CONV)
+               break;
+           }
+         val = convert_for_initialization
+           (NULL_TREE, type, val, LOOKUP_NORMAL,
+            "argument passing", fn, i - is_method);
        }
-  else if (IS_SIGNATURE (basetype))
-    return build_signature_method_call (basetype, instance, function, parms);
+      else
+       val = convert_like (conv, TREE_VALUE (arg));
 
-  function = DECL_MAIN_VARIANT (function);
-  /* Declare external function if necessary. */
-  assemble_external (function);
+#ifdef PROMOTE_PROTOTYPES
+      if ((TREE_CODE (type) == INTEGER_TYPE
+          || TREE_CODE (type) == ENUMERAL_TYPE)
+         && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+       val = default_conversion (val);
+#endif
+      converted_args = tree_cons (NULL_TREE, val, converted_args);
+    }
 
-  fntype = TREE_TYPE (function);
-  if (TREE_CODE (fntype) == POINTER_TYPE)
-    fntype = TREE_TYPE (fntype);
-  basetype = DECL_CLASS_CONTEXT (function);
+  /* Default arguments */
+  for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm))
+    converted_args = tree_cons
+      (NULL_TREE,
+       convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm)),
+       converted_args);
 
-  /* If we are referencing a virtual function from an object
-     of effectively static type, then there is no need
-     to go through the virtual function table.  */
-  if (need_vtbl == maybe_needed)
+  /* Ellipsis */
+  for (; arg; arg = TREE_CHAIN (arg))
     {
-      int fixed_type = resolves_to_fixed_type_p (instance, 0);
-
-      if (all_virtual == 1
-         && DECL_VINDEX (function)
-         && may_be_remote (basetype))
-       need_vtbl = needed;
-      else if (DECL_VINDEX (function))
-       need_vtbl = fixed_type ? unneeded : needed;
+      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 = convert (double_type_node, val);
+      else if (TYPE_LANG_SPECIFIC (TREE_TYPE (val))
+              && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (val)))
+       cp_warning ("cannot pass objects of type `%T' through `...'",
+                   TREE_TYPE (val));
       else
-       need_vtbl = not_needed;
+       /* Convert `short' and `char' to full-size `int'.  */
+       val = default_conversion (val);
+
+      converted_args = tree_cons (NULL_TREE, val, converted_args);
     }
 
-  if (TREE_CODE (fntype) == METHOD_TYPE && static_call_context
-      && !DECL_CONSTRUCTOR_P (function))
+  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
+      && copy_args_p (fn))
     {
-      /* Let's be nice to the user for now, and give reasonable
-        default behavior.  */
-      instance_ptr = current_class_decl;
-      if (instance_ptr)
+      tree targ = NULL_TREE;
+      arg = TREE_VALUE (TREE_CHAIN (converted_args));
+
+      /* Pull out the real argument, disregarding const-correctness.  */
+      if (TREE_CODE (arg) == ADDR_EXPR)
        {
-         if (basetype != current_class_type)
+         targ = TREE_OPERAND (arg, 0);
+         if (! comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (arg))),
+                          TYPE_MAIN_VARIANT (TREE_TYPE (targ)), 1))
+           targ = NULL_TREE;
+       }
+
+      if (targ)
+       arg = targ;
+      else
+       arg = build_indirect_ref (arg, 0);
+
+      /* If we're creating a temp and we already have one, don't create a
+         new one.  If we're not creating a temp but we get one, use
+         INIT_EXPR to collapse the temp into our target.  Otherwise, if the
+         ctor is trivial, do a bitwise copy with a simple TARGET_EXPR for a
+         temp or an INIT_EXPR otherwise.  */
+      if (integer_zerop (TREE_VALUE (args)))
+       {
+         if (! real_lvalue_p (arg))
+           return arg;
+         else if (TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
            {
-             tree binfo = get_binfo (basetype, current_class_type, 1);
-             if (binfo == NULL_TREE)
-               {
-                 error_not_base_type (function, current_class_type);
-                 return error_mark_node;
-               }
-             else if (basetype == error_mark_node)
-               return error_mark_node;
+             val = build (VAR_DECL, DECL_CONTEXT (fn));
+             layout_decl (val, 0);
+             return build (TARGET_EXPR, DECL_CONTEXT (fn), val, arg, 0, 0);
            }
        }
-      /* Only allow a static member function to call another static member
-        function.  */
-      else if (DECL_LANG_SPECIFIC (function)
-              && !DECL_STATIC_FUNCTION_P (function))
+      else if (! real_lvalue_p (arg)
+              || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
        {
-         cp_error ("cannot call member function `%D' without object",
-                   function);
-         return error_mark_node;
+         tree to = stabilize_reference
+           (build_indirect_ref (TREE_VALUE (args), 0));
+         val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
+         TREE_SIDE_EFFECTS (val) = 1;
+         return build_unary_op (ADDR_EXPR, val, 0);
        }
     }
+  else if (DECL_NAME (fn) == ansi_opname[MODIFY_EXPR]
+          && copy_args_p (fn)
+          && TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CONTEXT (fn)))
+    {
+      tree to = stabilize_reference
+       (build_indirect_ref (TREE_VALUE (converted_args), 0));
+      arg = build_indirect_ref (TREE_VALUE (TREE_CHAIN (converted_args)), 0);
+      val = build (MODIFY_EXPR, TREE_TYPE (to), to, arg);
+      TREE_SIDE_EFFECTS (val) = 1;
+      return val;
+    }
 
-  value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
+  mark_used (fn);
 
-  if (TYPE_SIZE (value_type) == 0)
+  if (DECL_CONTEXT (fn) && IS_SIGNATURE (DECL_CONTEXT (fn)))
+    return build_signature_method_call (fn, converted_args);
+  else if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
     {
-      if (flags & LOOKUP_COMPLAIN)
-       incomplete_type_error (0, value_type);
-      return error_mark_node;
+      tree t, *p = &TREE_VALUE (converted_args);
+      tree binfo = get_binfo
+       (DECL_CONTEXT (fn), TREE_TYPE (TREE_TYPE (*p)), 0);
+      *p = convert_pointer_to_real (binfo, *p);
+      if (TREE_SIDE_EFFECTS (*p))
+       *p = save_expr (*p);
+      t = build_pointer_type (TREE_TYPE (fn));
+      fn = build_vfn_ref (p, build_indirect_ref (*p, 0), DECL_VINDEX (fn));
+      TREE_TYPE (fn) = t;
     }
+  else if (DECL_INLINE (fn))
+    fn = inline_conversion (fn);
+  else
+    fn = build_addr_func (fn);
+
+  fn = build_call (fn, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), converted_args);
+  if (TREE_TYPE (fn) == void_type_node)
+    return fn;
+  if (IS_AGGR_TYPE (TREE_TYPE (fn)))
+    fn = build_cplus_new (TREE_TYPE (fn), fn);
+  return convert_from_reference (require_complete_type (fn));
+}
 
-  /* We do not pass FUNCTION into `convert_arguments', because by
-     now everything should be ok.  If not, then we have a serious error.  */
-  if (DECL_STATIC_FUNCTION_P (function))
-    parms = convert_arguments (NULL_TREE, TYPE_ARG_TYPES (fntype),
-                              TREE_CHAIN (parms), NULL_TREE, LOOKUP_NORMAL);
-  else if (need_vtbl == unneeded)
+tree
+build_new_method_call (instance, name, args, basetype_path, flags)
+     tree instance, name, args, basetype_path;
+     int flags;
+{
+  struct z_candidate *candidates = 0, *cand;
+  tree basetype, mem_args, fns, instance_ptr;
+  tree pretty_name;
+
+  for (fns = args; fns; fns = TREE_CHAIN (fns))
+    if (TREE_VALUE (fns) == error_mark_node)
+      return error_mark_node;
+
+  if (instance == NULL_TREE)
+    basetype = BINFO_TYPE (basetype_path);
+  else
     {
-      int sub_flags = DECL_CONSTRUCTOR_P (function) ? flags : LOOKUP_NORMAL;
+      if (TREE_CODE (instance) == OFFSET_REF)
+       instance = resolve_offset_ref (instance);
+      if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE)
+       instance = convert_from_reference (instance);
       basetype = TREE_TYPE (instance);
-      if (TYPE_METHOD_BASETYPE (TREE_TYPE (function)) != TYPE_MAIN_VARIANT (basetype)
-         && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+
+      /* XXX this should be handled before we get here.  */
+      if (! IS_AGGR_TYPE (basetype)
+         && ! (TYPE_LANG_SPECIFIC (basetype)
+               && (IS_SIGNATURE_POINTER (basetype)
+                   || IS_SIGNATURE_REFERENCE (basetype))))
        {
-         basetype = DECL_CLASS_CONTEXT (function);
-         instance_ptr = convert_pointer_to (basetype, instance_ptr);
-         instance = build_indirect_ref (instance_ptr, NULL_PTR);
+         if ((flags & LOOKUP_COMPLAIN) && basetype != error_mark_node)
+           cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
+                     name, instance, basetype);
+
+         return error_mark_node;
        }
-      parms = tree_cons (NULL_TREE, instance_ptr,
-                        convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), NULL_TREE, sub_flags));
+
+      /* If `instance' is a signature pointer/reference and `name' is
+        not a constructor, we are calling a signature member function.
+        In that case set the `basetype' to the signature type.  */
+      if ((IS_SIGNATURE_POINTER (basetype)
+          || IS_SIGNATURE_REFERENCE (basetype))
+         && TYPE_IDENTIFIER (basetype) != name)
+       basetype = SIGNATURE_TYPE (basetype);
+    }
+
+  if (basetype_path == NULL_TREE)
+    basetype_path = TYPE_BINFO (basetype);
+
+  if (instance)
+    {
+      instance_ptr = build_this (instance);
+
+      /* XXX this should be handled before we get here.  */
+      fns = build_field_call (basetype_path, instance_ptr, name, args);
+      if (fns)
+       return fns;
     }
   else
     {
-      if ((flags & LOOKUP_NONVIRTUAL) == 0)
-       basetype = DECL_CONTEXT (function);
+      instance_ptr = build_int_2 (0, 0);
+      TREE_TYPE (instance_ptr) = build_pointer_type (basetype);
+    }
 
-      /* First parm could be integer_zerop with casts like
-        ((Object*)0)->Object::IsA()  */
-      if (!integer_zerop (TREE_VALUE (parms)))
+  pretty_name =
+    (name == ctor_identifier ? constructor_name_full (basetype) : name);
+
+  fns = lookup_fnfields (basetype_path, name, 1);
+
+  if (fns == error_mark_node)
+    return error_mark_node;
+  if (fns)
+    {
+      tree t = TREE_VALUE (fns);
+      if (name == ctor_identifier && TYPE_USES_VIRTUAL_BASECLASSES (basetype)
+         && ! (flags & LOOKUP_HAS_IN_CHARGE))
        {
-         /* Since we can't have inheritance with a union, doing get_binfo
-            on it won't work.  We do all the convert_pointer_to_real
-            stuff to handle MI correctly...for unions, that's not
-            an issue, so we must short-circuit that extra work here.  */
-         tree tmp = TREE_TYPE (TREE_TYPE (TREE_VALUE (parms)));
-         if (tmp != NULL_TREE && TREE_CODE (tmp) == UNION_TYPE)
-           instance_ptr = TREE_VALUE (parms);
+         flags |= LOOKUP_HAS_IN_CHARGE;
+         args = tree_cons (NULL_TREE, integer_one_node, args);
+       }
+      mem_args = tree_cons (NULL_TREE, instance_ptr, args);
+      for (; t; t = DECL_CHAIN (t))
+       {
+         /* XXX copy-init should go through build_user_type_conversion.  */
+         if (name == ctor_identifier
+             && (flags & LOOKUP_ONLYCONVERTING)
+             && DECL_NONCONVERTING_P (t))
+           continue;
+         if (TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)
+           candidates = add_function_candidate
+             (candidates, t, mem_args, flags);
          else
-           {
-             tree binfo = get_binfo (basetype,
-                                     TREE_TYPE (TREE_TYPE (TREE_VALUE (parms))),
-                                     0);
-             instance_ptr = convert_pointer_to_real (binfo, TREE_VALUE (parms));
-           }
-         instance_ptr
-           = convert_pointer_to (build_type_variant (basetype,
-                                                     constp, volatilep),
-                                 instance_ptr);
-
-         if (TREE_CODE (instance_ptr) == COND_EXPR)
-           {
-             instance_ptr = save_expr (instance_ptr);
-             instance = build_indirect_ref (instance_ptr, NULL_PTR);
-           }
-         else if (TREE_CODE (instance_ptr) == NOP_EXPR
-                  && TREE_CODE (TREE_OPERAND (instance_ptr, 0)) == ADDR_EXPR
-                  && TREE_OPERAND (TREE_OPERAND (instance_ptr, 0), 0) == instance)
-           ;
-         /* The call to `convert_pointer_to' may return error_mark_node.  */
-         else if (TREE_CODE (instance_ptr) == ERROR_MARK)
-           return instance_ptr;
-         else if (instance == NULL_TREE
-                  || TREE_CODE (instance) != INDIRECT_REF
-                  || TREE_OPERAND (instance, 0) != instance_ptr)
-           instance = build_indirect_ref (instance_ptr, NULL_PTR);
+           candidates = add_function_candidate (candidates, t, args, flags);
+         candidates->basetype_path = TREE_PURPOSE (fns);
        }
-      parms = tree_cons (NULL_TREE, instance_ptr,
-                        convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), NULL_TREE, LOOKUP_NORMAL));
     }
 
-#if 0
-  /* Constructors do not overload method calls.  */
-  else if (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype)
-          && name != TYPE_IDENTIFIER (basetype)
-          && (TREE_CODE (function) != FUNCTION_DECL
-              || strncmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)),
-                          OPERATOR_METHOD_FORMAT,
-                          OPERATOR_METHOD_LENGTH))
-          && (may_be_remote (basetype) || instance != C_C_D))
+  if (! any_viable (candidates))
     {
-      tree fn_as_int;
-
-      parms = TREE_CHAIN (parms);
+      /* XXX will LOOKUP_SPECULATIVELY be needed when this is done?  */
+      if (flags & LOOKUP_SPECULATIVELY)
+       return NULL_TREE;
+      cp_error ("no matching function for call to `%T::%D (%A)%V'", basetype,
+               pretty_name, args, TREE_TYPE (TREE_TYPE (instance_ptr)));
+      print_z_candidates (candidates);
+      return error_mark_node;
+    }
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates, NULL_TREE);
 
-      if (!all_virtual && TREE_CODE (function) == FUNCTION_DECL)
-       fn_as_int = build_unary_op (ADDR_EXPR, function, 0);
-      else
-       fn_as_int = convert (TREE_TYPE (default_conversion (function)), DECL_VINDEX (function));
-      if (all_virtual == 1)
-       fn_as_int = convert (integer_type_node, fn_as_int);
+  if (cand == 0)
+    {
+      cp_error ("call of overloaded `%D(%A)' is ambiguous", pretty_name, args);
+      print_z_candidates (candidates);
+      return error_mark_node;
+    }
 
-      result = build_opfncall (METHOD_CALL_EXPR, LOOKUP_NORMAL, instance, fn_as_int, parms);
+  enforce_access (cand->basetype_path, cand->fn);
+  if (DECL_ABSTRACT_VIRTUAL_P (cand->fn)
+      && instance == current_class_ref
+      && DECL_CONSTRUCTOR_P (current_function_decl)
+      && ! (flags & LOOKUP_NONVIRTUAL)
+      && value_member (cand->fn, get_abstract_virtuals (basetype)))
+    cp_error ("abstract virtual `%#D' called from constructor", cand->fn);
+  if (TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
+      && TREE_CODE (instance_ptr) == NOP_EXPR
+      && TREE_OPERAND (instance_ptr, 0) == error_mark_node)
+    cp_error ("cannot call member function `%D' without object", cand->fn);
+
+  if (DECL_VINDEX (cand->fn) && ! (flags & LOOKUP_NONVIRTUAL)
+      && ((instance == current_class_ref && (dtor_label || ctor_label))
+         || resolves_to_fixed_type_p (instance, 0)))
+    flags |= LOOKUP_NONVIRTUAL;
+
+  return build_over_call
+    (cand->fn, cand->convs,
+     TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE ? mem_args : args,
+     flags);
+}
 
-      if (result == NULL_TREE)
-       {
-         compiler_error ("could not overload `operator->()(...)'");
-         return error_mark_node;
-       }
-      else if (result == error_mark_node)
-       return error_mark_node;
+/* Compare two implicit conversion sequences that differ only in their
+   qualification conversion.  Subroutine of compare_ics.  */
 
-#if 0
-      /* Do this if we want the result of operator->() to inherit
-        the type of the function it is subbing for.  */
-      TREE_TYPE (result) = value_type;
-#endif
+static int
+compare_qual (ics1, ics2)
+     tree ics1, ics2;
+{
+  tree to1 = TREE_TYPE (ics1);
+  tree to2 = TREE_TYPE (ics2);
 
-      return result;
-    }
-#endif
+  to1 = TREE_TYPE (to1);
+  to2 = TREE_TYPE (to2);
 
-  if (need_vtbl == needed)
+  if (TREE_CODE (to1) == OFFSET_TYPE)
     {
-      function = build_vfn_ref (&TREE_VALUE (parms), instance, DECL_VINDEX (function));
-      TREE_TYPE (function) = build_pointer_type (fntype);
+      to1 = TREE_TYPE (to1);
+      to2 = TREE_TYPE (to2);
     }
 
-  if (TREE_CODE (function) == FUNCTION_DECL)
-    GNU_xref_call (current_function_decl,
-                  IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)));
+  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;
+}
 
-  {
-    int is_constructor;
-    
-    if (TREE_CODE (function) == FUNCTION_DECL)
-      {
-       is_constructor = DECL_CONSTRUCTOR_P (function);
-       if (DECL_INLINE (function))
-         function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
-       else
-         {
-           assemble_external (function);
-           TREE_USED (function) = 1;
-           function = default_conversion (function);
-         }
-      }
-    else
-      {
-       is_constructor = 0;
-       function = default_conversion (function);
-      }
+/* Compare two implicit conversion sequences according to the rules set out in
+   [over.ics.rank].  Return values:
 
-    result = build_nt (CALL_EXPR, function, parms, NULL_TREE);
+      1: ics1 is better than ics2
+     -1: ics2 is better than ics1
+      0: ics1 and ics2 are indistinguishable */
 
-    TREE_TYPE (result) = value_type;
-    TREE_SIDE_EFFECTS (result) = 1;
-    TREE_RAISES (result)
-      = TYPE_RAISES_EXCEPTIONS (fntype) || (parms && TREE_RAISES (parms));
-    TREE_HAS_CONSTRUCTOR (result) = is_constructor;
-    return result;
-  }
-}
+static int
+compare_ics (ics1, ics2)
+     tree ics1, ics2;
+{
+  tree main1, main2;
 
-/* Similar to `build_method_call', but for overloaded non-member functions.
-   The name of this function comes through NAME.  The name depends
-   on PARMS.
+  if (TREE_CODE (ics1) == QUAL_CONV)
+    main1 = TREE_OPERAND (ics1, 0);
+  else
+    main1 = ics1;
 
-   Note that this function must handle simple `C' promotions,
-   as well as variable numbers of arguments (...), and
-   default arguments to boot.
+  if (TREE_CODE (ics2) == QUAL_CONV)
+    main2 = TREE_OPERAND (ics2, 0);
+  else
+    main2 = ics2;
 
-   If the overloading is successful, we return a tree node which
-   contains the call to the function.
+  /* Conversions for `this' are PTR_CONVs, but we compare them as though
+     they were REF_BINDs.  */
+  if (ICS_THIS_FLAG (ics1))
+    {
+      ics1 = build_conv (REF_BIND, TREE_TYPE (ics1), main1);
+      TREE_OPERAND (ics1, 0) = TREE_OPERAND (main1, 0);
+      main1 = ics1;
+    }
+  if (ICS_THIS_FLAG (ics2))
+    {
+      ics2 = build_conv (REF_BIND, TREE_TYPE (ics2), main2);
+      TREE_OPERAND (ics2, 0) = TREE_OPERAND (main2, 0);
+      main2 = ics2;
+    }
 
-   If overloading produces candidates which are probable, but not definite,
-   we hold these candidates.  If FINAL_CP is non-zero, then we are free
-   to assume that final_cp points to enough storage for all candidates that
-   this function might generate.  The `harshness' array is preallocated for
-   the first candidate, but not for subsequent ones.
+  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;
+      else if (ICS_USER_FLAG (ics1) < ICS_USER_FLAG (ics2)
+              || ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2))
+       return 1;
+
+      /* else fall through */
+    }
 
-   Note that the DECL_RTL of FUNCTION must be made to agree with this
-   function's new name.  */
+  /* 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.  */
 
-tree
-build_overload_call_real (fnname, parms, flags, final_cp, buildxxx)
-     tree fnname, parms;
-     int flags;
-     struct candidate *final_cp;
-     int buildxxx;
-{
-  /* must check for overloading here */
-  tree overload_name, functions, function, parm;
-  tree parmtypes = NULL_TREE, last = NULL_TREE;
-  register tree outer;
-  int length;
-  int parmlength = list_length (parms);
+  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)
+         return 0;
+      for (t2 = ics2; TREE_CODE (t2) != USER_CONV; t2 = TREE_OPERAND (t2, 0))
+       if (TREE_CODE (t2) == AMBIG_CONV)
+         return 0;
+
+      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 */
+    }
 
-  struct candidate *candidates, *cp;
+#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 (final_cp)
+  if (TREE_CODE (main1) != TREE_CODE (main2))
+    return 0;
+
+  if (TREE_CODE (main1) == PTR_CONV || TREE_CODE (main1) == PMEM_CONV
+      || TREE_CODE (main1) == REF_BIND || TREE_CODE (main1) == BASE_CONV)
     {
-      if (flag_ansi_overloading)
+      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)
        {
-         final_cp[0].h.code = 0;
-         final_cp[0].h.distance = 0;
-         final_cp[0].function = 0;
-         /* end marker.  */
-         final_cp[1].h.code = EVIL_CODE;
+         if (TYPE_MAIN_VARIANT (TREE_TYPE (to1))
+             == TYPE_MAIN_VARIANT (TREE_TYPE (to2)))
+           return compare_qual (ics1, ics2);
        }
-      else
+      else if (TREE_CODE (main1) != BASE_CONV && from1 == from2 && to1 == to2)
+       return compare_qual (ics1, ics2);
+       
+      if (TYPE_PTRMEMFUNC_P (to1))
        {
-         final_cp[0].evil = 0;
-         final_cp[0].user = 0;
-         final_cp[0].b_or_d = 0;
-         final_cp[0].easy = 0;
-         final_cp[0].function = 0;
-         /* end marker.  */
-         final_cp[1].evil = 1;
+         to1 = TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (to1));
+         from1 = TYPE_METHOD_BASETYPE (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);
 
-  for (parm = parms; parm; parm = TREE_CHAIN (parm))
-    {
-      register tree t = TREE_TYPE (TREE_VALUE (parm));
+         if (TREE_CODE (to1) == OFFSET_TYPE)
+           {
+             to1 = TYPE_OFFSET_BASETYPE (to1);
+             from1 = TYPE_OFFSET_BASETYPE (from1);
+           }
+       }
 
-      if (t == error_mark_node)
+      if (TYPE_PTRMEMFUNC_P (to2))
+       {
+         to2 = TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (to2));
+         from2 = TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (from2));
+       }
+      else if (TREE_CODE (main1) != BASE_CONV)
        {
-         if (final_cp)
+         to2 = TREE_TYPE (to2);
+         if (TREE_CODE (main1) != REF_BIND)
+           from2 = TREE_TYPE (from2);
+
+         if (TREE_CODE (to2) == OFFSET_TYPE)
            {
-             if (flag_ansi_overloading)
-               final_cp->h.code = EVIL_CODE;
-             else
-               final_cp->evil = 1;
+             to2 = TYPE_OFFSET_BASETYPE (to2);
+             from2 = TYPE_OFFSET_BASETYPE (from2);
            }
-         return error_mark_node;
        }
-      if (TREE_CODE (t) == ARRAY_TYPE || TREE_CODE (t) == OFFSET_TYPE)
+
+      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)
        {
-         /* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
-            Also convert OFFSET_TYPE entities to their normal selves.
-            This eliminates needless calls to `compute_conversion_costs'.  */
-         TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
-         t = TREE_TYPE (TREE_VALUE (parm));
+         tree t = from1; from1 = from2; from2 = t;
+         t = to1; to1 = to2; to2 = t;
        }
-      last = build_tree_list (NULL_TREE, t);
-      parmtypes = chainon (parmtypes, last);
-    }
-  if (last)
-    TREE_CHAIN (last) = void_list_node;
-  else
-    parmtypes = void_list_node;
 
-  if (! flag_ansi_overloading)
-    {
-      /* This is a speed improvement that ends up not working properly in
-        the situation of fns with and without default parameters.  I turned
-        this off in the new method so it'll go through the argument matching
-        code to properly diagnose a match/failure. (bpk)  */
-      overload_name = build_decl_overload (fnname, parmtypes, 0);
+      distf = get_base_distance (from1, from2, 0, 0);
+      if (distf == -1)
+       {
+         distf = -get_base_distance (from2, from1, 0, 0);
+         if (distf == 1)
+           return 0;
+       }
 
-      /* Now check to see whether or not we can win.
-        Note that if we are called from `build_method_call',
-        then we cannot have a mis-match, because we would have
-        already found such a winning case.  */
+      /* 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 (IDENTIFIER_GLOBAL_VALUE (overload_name))
-       if (TREE_CODE (IDENTIFIER_GLOBAL_VALUE (overload_name)) != TREE_LIST)
-         return build_function_call (DECL_MAIN_VARIANT (IDENTIFIER_GLOBAL_VALUE (overload_name)), parms);
-    }
+      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;
 
-  functions = IDENTIFIER_GLOBAL_VALUE (fnname);
+      if (! (IS_AGGR_TYPE (to1) && IS_AGGR_TYPE (to2)))
+       return 0;
 
-  if (functions == NULL_TREE)
-    {
-      if (flags & LOOKUP_SPECULATIVELY)
-       return NULL_TREE;
-      if (flags & LOOKUP_COMPLAIN)
-       error ("only member functions apply");
-      if (final_cp)
+      /* 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)
        {
-         if (flag_ansi_overloading)
-           final_cp->h.code = EVIL_CODE;
-         else
-           final_cp->evil = 1;
+         distt = -get_base_distance (to2, to1, 0, 0);
+         if (distt == 1)
+           return 0;
        }
-      return error_mark_node;
-    }
 
-  if (! TREE_OVERLOADED (fnname))
-    {
-      functions = DECL_MAIN_VARIANT (functions);
-      if (final_cp)
+      /* --conversion of C* to B* is better than conversion of C* to A*, */
+      if (distf == 0)
        {
-         /* We are just curious whether this is a viable alternative or
-             not.  */
-         compute_conversion_costs (functions, parms, final_cp, parmlength);
-         return functions;
+         if (distt > 0)
+           return -1;
+         else if (distt < 0)
+           return 1;
        }
-      else
-       return build_function_call_real (functions, parms, 1, flags);
-    }
-
-  if (TREE_CODE (functions) == TREE_LIST
-      && TREE_VALUE (functions) == NULL_TREE)
-    {
-      if (flags & LOOKUP_SPECULATIVELY)
-       return NULL_TREE;
-      
-      if (flags & LOOKUP_COMPLAIN)
-       cp_error ("function `%D' declared overloaded, but no instances of that function declared",
-                 TREE_PURPOSE (functions));
-      if (final_cp)
+      /* --conversion of B* to A* is better than conversion of C* to A*, */
+      else if (distt == 0)
        {
-         if (flag_ansi_overloading)
-           final_cp->h.code = EVIL_CODE;
-         else
-           final_cp->evil = 1;
+         if (distf > 0)
+           return 1;
+         else if (distf < 0)
+           return -1;
        }
-      return error_mark_node;
     }
-
-  length = count_functions (functions);
-  
-  if (final_cp)
-    candidates = final_cp;
-  else
+  else if (TREE_CODE (TREE_TYPE (main1)) == POINTER_TYPE
+          || TYPE_PTRMEMFUNC_P (TREE_TYPE (main1)))
     {
-      candidates
-       = (struct candidate *)alloca ((length+1) * sizeof (struct candidate));
-      bzero (candidates, (length + 1) * sizeof (struct candidate));
+      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
     }
 
-  cp = candidates;
+  return 0;
+}
 
-  my_friendly_assert (is_overloaded_fn (functions), 169);
+/* Compare two candidates for overloading as described in
+   [over.match.best].  Return values:
 
-  functions = get_first_fn (functions);
+      1: cand1 is better than cand2
+     -1: cand2 is better than cand1
+      0: cand1 and cand2 are indistinguishable */
 
-  /* OUTER is the list of FUNCTION_DECLS, in a TREE_LIST.  */
-  for (outer = functions; outer; outer = DECL_CHAIN (outer))
-    {
-      int template_cost = 0;
-      function = outer;
-      if (TREE_CODE (function) != FUNCTION_DECL
-         && ! (TREE_CODE (function) == TEMPLATE_DECL
-               && ! DECL_TEMPLATE_IS_CLASS (function)
-               && TREE_CODE (DECL_TEMPLATE_RESULT (function)) == FUNCTION_DECL))
-       {
-         enum tree_code code = TREE_CODE (function);
-         if (code == TEMPLATE_DECL)
-           code = TREE_CODE (DECL_TEMPLATE_RESULT (function));
-         if (code == CONST_DECL)
-           cp_error_at
-             ("enumeral value `%D' conflicts with function of same name",
-              function);
-         else if (code == VAR_DECL)
-           {
-             if (TREE_STATIC (function))
-               cp_error_at
-                 ("variable `%D' conflicts with function of same name",
-                  function);
-             else
-               cp_error_at
-                 ("constant field `%D' conflicts with function of same name",
-                  function);
-           }
-         else if (code == TYPE_DECL)
-           continue;
-         else
-           my_friendly_abort (2);
-         error ("at this point in file");
-         continue;
-       }
-      if (TREE_CODE (function) == TEMPLATE_DECL)
-       {
-         int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (function));
-         tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
-         int i;
+static int
+joust (cand1, cand2)
+     struct z_candidate *cand1, *cand2;
+{
+  int winner = 0;
+  int i, off1 = 0, off2 = 0, len;
 
-         i = type_unification (DECL_TEMPLATE_PARMS (function), targs,
-                               TYPE_ARG_TYPES (TREE_TYPE (function)),
-                               parms, &template_cost, 0);
-         if (i == 0)
-           {
-             struct candidate *cp2;
+  /* Candidates that involve bad conversions are always worse than those
+     that don't.  */
+  if (cand1->viable > cand2->viable)
+    return 1;
+  if (cand1->viable < cand2->viable)
+    return -1;
 
-             function = instantiate_template (function, targs);
-             /* Now check that the template instantiated for this is not
-                the same as a function that's in the list due to some
-                previous instantiation.  */
-             cp2 = candidates;
-             while (cp2 != cp)
-               if (cp2->function == function)
-                 break;
-               else
-                 cp2 += 1;
-             if (cp2->function == function)
-               continue;
-           }
-       }
+  /* a viable function F1
+     is defined to be a better function than another viable function F2  if
+     for  all arguments i, ICSi(F1) is not a worse conversion sequence than
+     ICSi(F2), and then */
 
-      if (TREE_CODE (function) == TEMPLATE_DECL)
+  /* for some argument j, ICSj(F1) is a better conversion  sequence  than
+     ICSj(F2) */
+
+  /* For comparing static and non-static member functions, we ignore the
+     implicit object parameter of the non-static function.  The WP says to
+     pretend that the static function has an object parm, but that won't
+     work with operator overloading.  */
+  len = TREE_VEC_LENGTH (cand1->convs);
+  if (len != TREE_VEC_LENGTH (cand2->convs))
+    {
+      if (DECL_STATIC_FUNCTION_P (cand1->fn)
+         && ! DECL_STATIC_FUNCTION_P (cand2->fn))
+       off2 = 1;
+      else if (! DECL_STATIC_FUNCTION_P (cand1->fn)
+              && DECL_STATIC_FUNCTION_P (cand2->fn))
        {
-         /* Unconverted template -- failed match.  */
-         cp->function = function;
-         cp->u.bad_arg = -4;
-         if (flag_ansi_overloading)
-           cp->h.code = EVIL_CODE;
-         else
-           cp->evil = 1;
+         off1 = 1;
+         --len;
        }
       else
+       my_friendly_abort (42);
+    }
+
+  for (i = 0; i < len; ++i)
+    {
+      int comp = compare_ics (TREE_VEC_ELT (cand1->convs, i+off1),
+                             TREE_VEC_ELT (cand2->convs, i+off2));
+
+      if (comp != 0)
        {
-         function = DECL_MAIN_VARIANT (function);
+         if (winner && comp != winner)
+           {
+             winner = 0;
+             goto tweak;
+           }
+         winner = comp;
+       }
+    }
 
-         /* Can't use alloca here, since result might be
-            passed to calling function.  */
-         cp->h_len = parmlength;
-         if (flag_ansi_overloading)
-           cp->v.ansi_harshness = (struct harshness_code *)
-             oballoc ((parmlength + 1) * sizeof (struct harshness_code));
-         else
-           cp->v.old_harshness = (unsigned short *)
-             oballoc ((parmlength + 1) * sizeof (unsigned short));
+  if (winner)
+    return winner;
 
-         compute_conversion_costs (function, parms, cp, parmlength);
+  /* or, if not that,
+     F1 is a non-template function and F2 is a template function */
 
-         if (flag_ansi_overloading)
-           /* Make sure this is clear as well.  */
-           cp->h.int_penalty += template_cost;
-         else
-           /* Should really add another field...  */
-           cp->easy = cp->easy * 128 + template_cost;
+  if (! cand1->template && cand2->template)
+    return 1;
+  else if (cand1->template && ! cand2->template)
+    return -1;
+  else if (cand1->template && cand2->template)
+    winner = more_specialized
+      (TI_TEMPLATE (cand1->template), TI_TEMPLATE (cand2->template));
+
+  /* or, if not that,
+     the  context  is  an  initialization by user-defined conversion (see
+     _dcl.init_  and  _over.match.user_)  and  the  standard   conversion
+     sequence  from  the return type of F1 to the destination type (i.e.,
+     the type of the entity being initialized)  is  a  better  conversion
+     sequence  than the standard conversion sequence from the return type
+     of F2 to the destination type.  */
+
+  if (! winner && cand1->second_conv)
+    winner = compare_ics (cand1->second_conv, cand2->second_conv);
+
+  /* If the built-in candidates are the same, arbitrarily pick one.  */
+  if (! winner && cand1->fn == cand2->fn
+      && TREE_CODE (cand1->fn) == IDENTIFIER_NODE)
+    {
+      for (i = 0; i < len; ++i)
+       if (! comptypes (TREE_TYPE (TREE_VEC_ELT (cand1->convs, i)),
+                        TREE_TYPE (TREE_VEC_ELT (cand2->convs, i)), 1))
+         break;
+      if (i == TREE_VEC_LENGTH (cand1->convs))
+       return 1;
+      /* Kludge around broken overloading rules whereby
+        bool ? void *const & : void *const & is ambiguous.  */
+      if (cand1->fn == ansi_opname[COND_EXPR])
+       {
+         tree c1 = TREE_VEC_ELT (cand1->convs, 1);
+         tree c2 = TREE_VEC_ELT (cand2->convs, 1);
+         tree t1 = strip_top_quals (non_reference (TREE_TYPE (c1)));
+         tree t2 = strip_top_quals (non_reference (TREE_TYPE (c2)));
 
-         /* It seemed easier to have both if stmts in here, rather
-            than excluding the hell out of it with flag_ansi_overloading
-            everywhere. (bpk) */
-         if (flag_ansi_overloading)
+         if (comptypes (t1, t2, 1))
            {
-             if ((cp[0].h.code & EVIL_CODE) == 0)
-               {
-                 cp[1].h.code = EVIL_CODE;
-
-                 /* int_penalty is set by convert_harshness_ansi for cases
-                    where we need to know about any penalties that would
-                    otherwise make a TRIVIAL_CODE pass.  */
-                 if (final_cp
-                     && template_cost == 0
-                     && cp[0].h.code <= TRIVIAL_CODE
-                     && cp[0].h.int_penalty == 0)
-                   {
-                     final_cp[0].h = cp[0].h;
-                     return function;
-                   }
-                 cp++;
-               }
-           }
-         else
-           {
-             if (cp[0].evil == 0)
-               {
-                 cp[1].evil = 1;
-                 if (final_cp
-                     && cp[0].user == 0 && cp[0].b_or_d == 0
-                     && template_cost == 0
-                     && cp[0].easy <= 1)
-                   {
-                     final_cp[0].easy = cp[0].easy;
-                     return function;
-                   }
-                 cp++;
-               }
+             if (TREE_CODE (c1) == REF_BIND && TREE_CODE (c2) != REF_BIND)
+               return 1;
+             if (TREE_CODE (c1) != REF_BIND && TREE_CODE (c2) == REF_BIND)
+               return -1;
            }
        }
     }
 
-  if (cp - candidates)
+tweak:
+
+  /* Extension: If the worst conversion for one candidate is worse than the
+     worst conversion for the other, take the first.  */
+  if (! winner && ! pedantic)
     {
-      tree rval = error_mark_node;
+      int rank1 = IDENTITY_RANK, rank2 = IDENTITY_RANK;
 
-      /* Leave marker.  */
-      if (flag_ansi_overloading)
-       cp[0].h.code = EVIL_CODE;
-      else
-       cp[0].evil = 1;
-      if (cp - candidates > 1)
+      for (i = 0; i < len; ++i)
        {
-         struct candidate *best_cp
-           = ideal_candidate (NULL_TREE, candidates,
-                              cp - candidates, parms, parmlength);
-         if (best_cp == (struct candidate *)0)
-           {
-             if (flags & LOOKUP_COMPLAIN)
-               {
-                 cp_error ("call of overloaded `%D' is ambiguous", fnname);
-                 print_n_candidates (candidates, cp - candidates);
-               }
-             return error_mark_node;
-           }
-         else
-           rval = best_cp->function;
+         if (ICS_RANK (TREE_VEC_ELT (cand1->convs, i+off1)) > rank1)
+           rank1 = ICS_RANK (TREE_VEC_ELT (cand1->convs, i+off1));
+         if (ICS_RANK (TREE_VEC_ELT (cand2->convs, i+off2)) > rank2)
+           rank2 = ICS_RANK (TREE_VEC_ELT (cand2->convs, i+off2));
        }
+
+      if (rank1 < rank2)
+       return 1;
+      if (rank1 > rank2)
+       return -1;
+    }
+
+  return winner;
+}
+
+/* Given a list of candidates for overloading, find the best one, if any.
+   This algorithm has a worst case of O(2n) (winner is last), and a best
+   case of O(n/2) (totally ambiguous); much better than a sorting
+   algorithm.  */
+
+static struct z_candidate *
+tourney (candidates)
+     struct z_candidate *candidates;
+{
+  struct z_candidate *champ = candidates, *challenger;
+  int fate;
+
+  /* Walk through the list once, comparing each current champ to the next
+     candidate, knocking out a candidate or two with each comparison.  */
+
+  for (challenger = champ->next; challenger; )
+    {
+      fate = joust (champ, challenger);
+      if (fate == 1)
+       challenger = challenger->next;
       else
        {
-         cp -= 1;
-         if ((flag_ansi_overloading && (cp->h.code & EVIL_CODE))
-             || (!flag_ansi_overloading && cp->evil > 1))
+         if (fate == 0)
            {
-             if (flags & LOOKUP_COMPLAIN)
-               error ("type conversion ambiguous");
+             champ = challenger->next;
+             if (champ == 0)
+               return 0;
            }
          else
-           rval = cp->function;
+           champ = challenger;
+
+         challenger = champ->next;
        }
+    }
 
-      if (final_cp)
-       return rval;
+  /* 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.  */
 
-      return buildxxx ? build_function_call_real (rval, parms, 0, flags)
-        : build_function_call_real (rval, parms, 1, flags);
+  for (challenger = candidates; challenger != champ;
+       challenger = challenger->next)
+    {
+      fate = joust (champ, challenger);
+      if (fate != 1)
+       return 0;
     }
 
-  if (flags & LOOKUP_SPECULATIVELY)
-    return NULL_TREE;
-  
-  if (flags & LOOKUP_COMPLAIN)
-    report_type_mismatch (cp, parms, "function",
-                         decl_as_string (cp->function, 1));
-
-  return error_mark_node;
+  return champ;
 }
 
-tree
-build_overload_call (fnname, parms, flags, final_cp)
-     tree fnname, parms;
-     int flags;
-     struct candidate *final_cp;
+int
+can_convert (to, from)
+     tree to, from;
 {
-  return build_overload_call_real (fnname, parms, flags, final_cp, 0);
+  if (flag_ansi_overloading)
+    {
+      tree t = implicit_conversion (to, from, NULL_TREE, LOOKUP_NORMAL);
+      return (t && ! ICS_BAD_FLAG (t));
+    }
+  else
+    {
+      struct harshness_code h;
+      h = convert_harshness (to, from, NULL_TREE);
+      return (h.code < USER_CODE) && (h.distance >= 0);
+    }
 }
 
-tree
-build_overload_call_maybe (fnname, parms, flags, final_cp)
-     tree fnname, parms;
-     int flags;
-     struct candidate *final_cp;
+int
+can_convert_arg (to, from, arg)
+     tree to, from, arg;
 {
-  return build_overload_call_real (fnname, parms, flags, final_cp, 1);
+  if (flag_ansi_overloading)
+    {
+      tree t = implicit_conversion (to, from, arg, LOOKUP_NORMAL);
+      return (t && ! ICS_BAD_FLAG (t));
+    }
+  else
+    {
+      struct harshness_code h;
+      h = convert_harshness (to, from, arg);
+      return (h.code < USER_CODE) && (h.distance >= 0);
+    }
 }