init.c (build_new_1): Split out from build_new.
[gcc.git] / gcc / cp / call.c
index c0cdf8b96aec9942945c044bb3a6018c586bf15b..848a821ee953511b26c24f9ab56c29ca25a0abb0 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions related to invoking methods and overloaded functions.
-   Copyright (C) 1987, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com) and
    hacked by Brendan Kehoe (brendan@cygnus.com).
 
@@ -31,12 +31,14 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "flags.h"
 
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
 #include "obstack.h"
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
-extern void sorry ();
-
 extern int inhibit_warnings;
 extern tree ctor_label, dtor_label;
 
@@ -44,6 +46,63 @@ extern tree ctor_label, dtor_label;
    between an expected and the given type.  */
 
 static struct harshness_code convert_harshness PROTO((register tree, register tree, tree));
+static tree build_new_method_call              PROTO((tree, tree, tree, tree, int));
+
+static int rank_for_ideal PROTO((struct candidate *,
+                                struct candidate *));
+static int user_harshness PROTO((tree, tree));
+static int strictly_better PROTO((unsigned int, unsigned int));
+static struct candidate * ideal_candidate PROTO((struct candidate *,
+                                                int, int));
+static int may_be_remote PROTO((tree));
+static tree build_field_call PROTO((tree, tree, tree, tree));
+static tree find_scoped_type PROTO((tree, tree, tree));
+static void print_candidates PROTO((tree));
+static struct z_candidate * tourney PROTO((struct z_candidate *));
+static int joust PROTO((struct z_candidate *, struct z_candidate *));
+static int compare_qual PROTO((tree, tree));
+static int compare_ics PROTO((tree, tree));
+static tree build_over_call PROTO((tree, tree, tree, int));
+static tree convert_default_arg PROTO((tree, tree));
+static void enforce_access PROTO((tree, tree));
+static tree convert_like PROTO((tree, tree));
+static void op_error PROTO((enum tree_code, enum tree_code, tree, tree,
+                           tree, char *));
+static tree build_object_call PROTO((tree, tree));
+static tree resolve_args PROTO((tree));
+static struct z_candidate * build_user_type_conversion_1
+       PROTO ((tree, tree, int));
+static void print_z_candidates PROTO((struct z_candidate *));
+static tree build_this PROTO((tree));
+static struct z_candidate * splice_viable PROTO((struct z_candidate *));
+static int any_viable PROTO((struct z_candidate *));
+static struct z_candidate * add_template_candidate
+       PROTO((struct z_candidate *, tree, tree, tree, tree, int));
+static struct z_candidate * add_template_conv_candidate 
+        PROTO((struct z_candidate *, tree, tree, tree, tree));
+static struct z_candidate * add_builtin_candidates
+       PROTO((struct z_candidate *, enum tree_code, enum tree_code,
+              tree, tree *, int));
+static struct z_candidate * add_builtin_candidate
+       PROTO((struct z_candidate *, enum tree_code, enum tree_code,
+              tree, tree, tree, tree *, tree *, int));
+static int is_complete PROTO((tree));
+static struct z_candidate * build_builtin_candidate 
+       PROTO((struct z_candidate *, tree, tree, tree, tree *, tree *,
+              int));
+static struct z_candidate * add_conv_candidate 
+       PROTO((struct z_candidate *, tree, tree, tree));
+static struct z_candidate * add_function_candidate 
+       PROTO((struct z_candidate *, tree, tree, int));
+static tree implicit_conversion PROTO((tree, tree, tree, int));
+static tree standard_conversion PROTO((tree, tree, tree));
+static tree reference_binding PROTO((tree, tree, tree, int));
+static tree strip_top_quals PROTO((tree));
+static tree non_reference PROTO((tree));
+static tree build_conv PROTO((enum tree_code, tree, tree));
+static void print_n_candidates PROTO((struct candidate *, int));
+static tree default_parm_conversions PROTO((tree, tree *));
+static int is_subseq PROTO((tree, tree));
 
 #define EVIL_RETURN(ARG)       ((ARG).code = EVIL_CODE, (ARG))
 #define STD_RETURN(ARG)                ((ARG).code = STD_CODE, (ARG))
@@ -82,7 +141,7 @@ rank_for_overload (x, y)
 
 /* Compare two candidates, argument by argument.  */
 
-int
+static int
 rank_for_ideal (x, y)
      struct candidate *x, *y;
 {
@@ -508,7 +567,7 @@ convert_harshness (type, parmtype, parm)
 
 #if 1
       if (TREE_CODE (ttl) != VOID_TYPE
-         && (TREE_CODE (ttr) != VOID_TYPE || !parm || !integer_zerop (parm)))
+         && (TREE_CODE (ttr) != VOID_TYPE || !parm || !null_ptr_cst_p (parm)))
        {
          if (comp_target_types (type, parmtype, 1) <= 0)
            return EVIL_RETURN (h);
@@ -627,7 +686,7 @@ convert_harshness (type, parmtype, parm)
 /* A clone of build_type_conversion for checking user-defined conversions in
    overload resolution.  */
 
-int
+static int
 user_harshness (type, parmtype)
      register tree type, parmtype;
 {
@@ -668,24 +727,6 @@ user_harshness (type, parmtype)
   return -1;
 }
 
-int
-can_convert (to, from)
-     tree to, from;
-{
-  struct harshness_code h;
-  h = convert_harshness (to, from, NULL_TREE);
-  return (h.code < USER_CODE) && (h.distance >= 0);
-}
-
-int
-can_convert_arg (to, from, arg)
-     tree to, from, arg;
-{
-  struct harshness_code h;
-  h = convert_harshness (to, from, arg);
-  return (h.code < USER_CODE) && (h.distance >= 0);
-}
-
 #ifdef DEBUG_MATCHING
 static char *
 print_harshness (h)
@@ -1048,7 +1089,7 @@ compute_conversion_costs (function, tta_in, cp, arglen)
 
 static int
 strictly_better (x, y)
-     unsigned short x, y;
+     unsigned int x, y;
 {
   unsigned short xor;
 
@@ -1089,7 +1130,7 @@ ideal_candidate (candidates, n_candidates, len)
      functions.  */
 
   qsort (candidates, n_candidates, sizeof (struct candidate),
-        rank_for_overload);
+        (int (*) PROTO((const void *, const void *))) 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.  */
@@ -1103,7 +1144,7 @@ ideal_candidate (candidates, n_candidates, len)
          break;
 
       qsort (candidates+j, n_candidates-j, sizeof (struct candidate),
-            rank_for_ideal);
+            (int (*) PROTO((const void *, const void *))) rank_for_ideal);
       for (i = 0; i < len; i++)
        {
          if (cp[-1].harshness[i].code < cp[-2].harshness[i].code)
@@ -1193,6 +1234,9 @@ build_field_call (basetype_path, instance_ptr, name, parms)
 {
   tree field, instance;
 
+  if (name == ctor_identifier || name == dtor_identifier)
+    return NULL_TREE;
+
   if (instance_ptr == current_class_ptr)
     {
       /* Check to see if we really have a reference to an instance variable
@@ -1214,7 +1258,8 @@ build_field_call (basetype_path, instance_ptr, name, parms)
            return error_mark_node;
 
          if (TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
-             && TYPE_OVERLOADS_CALL_EXPR (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)
@@ -1222,7 +1267,7 @@ build_field_call (basetype_path, instance_ptr, name, parms)
              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 build_function_call (instance, expr_tree_cons (NULL_TREE, current_class_ptr, parms));
            }
        }
       return NULL_TREE;
@@ -1245,7 +1290,8 @@ build_field_call (basetype_path, instance_ptr, name, parms)
       if (TREE_CODE (ftype) == REFERENCE_TYPE)
        ftype = TREE_TYPE (ftype);
 
-      if (TYPE_LANG_SPECIFIC (ftype) && TYPE_OVERLOADS_CALL_EXPR (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);
@@ -1282,7 +1328,7 @@ build_field_call (basetype_path, instance_ptr, name, parms)
   return NULL_TREE;
 }
 
-tree
+static tree
 find_scoped_type (type, inner_name, inner_types)
      tree type, inner_name, inner_types;
 {
@@ -1297,7 +1343,7 @@ find_scoped_type (type, inner_name, inner_types)
       if (TREE_PURPOSE (tags) == inner_name)
        {
          if (inner_types == NULL_TREE)
-           return TYPE_NAME (TREE_VALUE (tags));
+           return TYPE_MAIN_DECL (TREE_VALUE (tags));
          return resolve_scope_to_name (TREE_VALUE (tags), inner_types);
        }
       tags = TREE_CHAIN (tags);
@@ -1342,7 +1388,7 @@ resolve_scope_to_name (outer_type, inner_stuff)
 
          if (rval != NULL_TREE)
            return rval;
-         type = DECL_CONTEXT (TYPE_NAME (type));
+         type = DECL_CONTEXT (TYPE_MAIN_DECL (type));
        }
     }
 
@@ -1426,7 +1472,7 @@ build_scoped_method_call (exp, basetype, name, parms)
       || basetype == error_mark_node)
     return error_mark_node;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       if (TREE_CODE (name) == BIT_NOT_EXPR)
        {
@@ -1440,6 +1486,14 @@ build_scoped_method_call (exp, basetype, name, parms)
   if (TREE_CODE (type) == REFERENCE_TYPE)
     type = TREE_TYPE (type);
 
+  if (TREE_CODE (basetype) == TREE_VEC)
+    {
+      binfo = basetype;
+      basetype = BINFO_TYPE (binfo);
+    }
+  else
+    binfo = NULL_TREE;
+
   /* Destructors can be "called" for simple types; see 5.2.4 and 12.4 Note
      that explicit ~int is caught in the parser; this deals with typedefs
      and template parms.  */
@@ -1452,7 +1506,7 @@ build_scoped_method_call (exp, basetype, name, parms)
       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);
+      return cp_convert (void_type_node, exp);
     }
 
   if (! is_aggr_type (basetype, 1))
@@ -1465,13 +1519,21 @@ build_scoped_method_call (exp, basetype, name, parms)
       return error_mark_node;
     }
 
-  if ((binfo = binfo_or_else (basetype, type)))
+  if (! binfo)
     {
+      binfo = get_binfo (basetype, type, 1);
       if (binfo == error_mark_node)
        return error_mark_node;
+      if (! binfo)
+       error_not_base_type (basetype, type);
+    }
+
+  if (binfo)
+    {
       if (TREE_CODE (exp) == INDIRECT_REF)
-       decl = build_indirect_ref (convert_pointer_to (binfo,
-                                                      build_unary_op (ADDR_EXPR, exp, 0)), NULL_PTR);
+       decl = build_indirect_ref
+         (convert_pointer_to_real
+          (binfo, build_unary_op (ADDR_EXPR, exp, 0)), NULL_PTR);
       else
        decl = build_scoped_ref (exp, basetype);
 
@@ -1490,7 +1552,7 @@ build_scoped_method_call (exp, basetype, name, parms)
              return error_mark_node;
            }
          if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
-           return convert (void_type_node, exp);
+           return cp_convert (void_type_node, exp);
          
          return build_delete (TREE_TYPE (decl), decl, integer_two_node,
                               LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR,
@@ -1666,7 +1728,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
 {
   register tree function, fntype, value_type;
   register tree basetype, save_basetype;
-  register tree baselink, result, parmtypes, parm;
+  register tree baselink, result, parmtypes;
   tree last;
   int pass;
   tree access = access_public_node;
@@ -1697,7 +1759,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
       || (instance != NULL_TREE && TREE_TYPE (instance) == error_mark_node))
     return error_mark_node;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       if (TREE_CODE (name) == BIT_NOT_EXPR)
        {
@@ -1747,11 +1809,11 @@ build_method_call (instance, name, parms, basetype_path, flags)
        {
          cp_error ("destructor name `~%D' does not match type `%T' of expression",
                    name, basetype);
-         return convert (void_type_node, instance);
+         return cp_convert (void_type_node, instance);
        }
 
-      if (! TYPE_HAS_DESTRUCTOR (basetype))
-       return convert (void_type_node, instance);
+      if (! TYPE_HAS_DESTRUCTOR (complete_type (basetype)))
+       return cp_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),
@@ -1759,6 +1821,9 @@ build_method_call (instance, name, parms, basetype_path, flags)
                           LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
     }
 
+  if (flag_ansi_overloading)
+    return build_new_method_call (instance, name, parms, basetype_path, flags);
+
   {
     char *xref_name;
     
@@ -1833,7 +1898,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
       if (! IS_AGGR_TYPE (basetype))
        {
        non_aggr_error:
-         if ((flags & LOOKUP_COMPLAIN) && TREE_CODE (basetype) != ERROR_MARK)
+         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);
 
@@ -1860,8 +1925,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
          && TYPE_IDENTIFIER (basetype) != name)
        {
          basetype = SIGNATURE_TYPE (basetype);
-         instance_ptr = build_optr_ref (instance);
-         instance_ptr = convert (build_pointer_type (basetype), instance_ptr);
+         instance_ptr = instance;
          basetype_path = TYPE_BINFO (basetype);
        }
       else
@@ -1890,10 +1954,10 @@ build_method_call (instance, name, parms, basetype_path, flags)
       /* 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);
+      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);
@@ -1928,6 +1992,8 @@ build_method_call (instance, name, parms, basetype_path, flags)
              && TYPE_IDENTIFIER (basetype) != name)
            basetype = SIGNATURE_TYPE (basetype);
 
+         basetype = complete_type (basetype);
+
          if ((IS_SIGNATURE (basetype)
               && (instance_ptr = instance))
              || (lvalue_p (instance)
@@ -1978,7 +2044,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
            basetype = inst_ptr_basetype;
          else
            {
-             instance_ptr = convert (build_pointer_type (basetype), instance_ptr);
+             instance_ptr = cp_convert (build_pointer_type (basetype), instance_ptr);
              if (instance_ptr == error_mark_node)
                return error_mark_node;
            }
@@ -1989,8 +2055,9 @@ build_method_call (instance, name, parms, basetype_path, flags)
       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))
+      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);
@@ -2043,14 +2110,14 @@ build_method_call (instance, name, parms, basetype_path, flags)
         of the signature pointer?  */
       constp = TYPE_READONLY (basetype);
       volatilep = TYPE_VOLATILE (basetype);
-      parms = tree_cons (NULL_TREE, instance_ptr, parms);
+      parms = expr_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);
+      parms = expr_tree_cons (NULL_TREE, instance_ptr, parms);
     }
   else
     {
@@ -2059,18 +2126,18 @@ build_method_call (instance, name, parms, basetype_path, flags)
          && ! (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);
+         parms = expr_tree_cons (NULL_TREE, integer_one_node, parms);
+         parmtypes = scratch_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);
+      parms = expr_tree_cons (NULL_TREE, instance_ptr, parms);
     }
 
-  parmtypes = tree_cons (NULL_TREE, TREE_TYPE (instance_ptr), parmtypes);
+  parmtypes = scratch_tree_cons (NULL_TREE, TREE_TYPE (instance_ptr), parmtypes);
 
   if (last == NULL_TREE)
     last = parmtypes;
@@ -2104,10 +2171,10 @@ build_method_call (instance, name, parms, basetype_path, flags)
              tree tmplist;
              
              flags |= LOOKUP_HAS_IN_CHARGE;
-             tmplist = tree_cons (NULL_TREE, integer_zero_node,
+             tmplist = expr_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));
+             tmplist = scratch_tree_cons (NULL_TREE, integer_type_node, TREE_CHAIN (parmtypes));
              TREE_CHAIN (parmtypes) = tmplist;
            }
          basetype = BINFO_TYPE (tmp);
@@ -2158,7 +2225,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
              else
                my_friendly_abort (167);
 
-             friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
+             friend_parms = expr_tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
 
              cp->h_len = len;
              cp->harshness = (struct harshness_code *)
@@ -2208,7 +2275,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
 #endif
              ever_seen++;
              if (pass > 0)
-               found_fns = tree_cons (NULL_TREE, function, found_fns);
+               found_fns = scratch_tree_cons (NULL_TREE, function, found_fns);
 
              /* Not looking for friends here.  */
              if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE
@@ -2455,24 +2522,12 @@ build_method_call (instance, name, parms, basetype_path, flags)
                    basetype, save_name);
          return error_mark_node;
        }
-      return build_signature_method_call (basetype, instance, function, parms);
+      return build_signature_method_call (function, parms);
     }
 
   function = DECL_MAIN_VARIANT (function);
   mark_used (function);
 
-  /* Is it a synthesized method that needs to be synthesized?  */
-  if (DECL_ARTIFICIAL (function) && ! DECL_INITIAL (function)
-      /* Kludge: don't synthesize for default args.  */
-      && current_function_decl)
-    synthesize_method (function);
-
-  if (pedantic && DECL_THIS_INLINE (function) && ! DECL_ARTIFICIAL (function)
-      && ! DECL_INITIAL (function) && ! DECL_PENDING_INLINE_INFO (function)
-      && ! (DECL_TEMPLATE_INFO (function)
-           && TREE_LANG_FLAG_0 (DECL_TEMPLATE_INFO (function))))
-    cp_warning ("inline function `%#D' called before definition", function);
-
   fntype = TREE_TYPE (function);
   if (TREE_CODE (fntype) == POINTER_TYPE)
     fntype = TREE_TYPE (fntype);
@@ -2551,7 +2606,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
          instance_ptr = convert_pointer_to (basetype, instance_ptr);
          instance = build_indirect_ref (instance_ptr, NULL_PTR);
        }
-      parms = tree_cons (NULL_TREE, instance_ptr,
+      parms = expr_tree_cons (NULL_TREE, instance_ptr,
                         convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), function, sub_flags));
     }
   else
@@ -2592,14 +2647,14 @@ build_method_call (instance, name, parms, basetype_path, flags)
                   && 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)
+         else if (instance_ptr == error_mark_node)
            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,
+      parms = expr_tree_cons (NULL_TREE, instance_ptr,
                         convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), function, LOOKUP_NORMAL));
     }
 
@@ -2619,6 +2674,8 @@ build_method_call (instance, name, parms, basetype_path, flags)
                   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;
 }
@@ -2651,7 +2708,7 @@ build_overload_call_real (fnname, parms, flags, final_cp, require_complete)
      int require_complete;
 {
   /* must check for overloading here */
-  tree functions, function, parm;
+  tree functions, function;
   tree parmtypes, last;
   register tree outer;
   int length;
@@ -2784,13 +2841,14 @@ build_overload_call_real (fnname, parms, flags, final_cp, require_complete)
        }
       if (TREE_CODE (function) == TEMPLATE_DECL)
        {
-         int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (function));
-         tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
+         int ntparms = DECL_NTPARMS (function);
+         tree targs = make_scratch_vec (ntparms);
          int i;
 
-         i = type_unification (DECL_TEMPLATE_PARMS (function), targs,
+         i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (function),
+                               &TREE_VEC_ELT (targs, 0),
                                TYPE_ARG_TYPES (TREE_TYPE (function)),
-                               parms, &template_cost, 0);
+                               parms, NULL_TREE, &template_cost, 0, 0);
          if (i == 0)
            {
              function = instantiate_template (function, targs);
@@ -2827,7 +2885,7 @@ build_overload_call_real (fnname, parms, flags, final_cp, require_complete)
             passed to calling function.  */
          cp->h_len = parmlength;
          cp->harshness = (struct harshness_code *)
-           oballoc ((parmlength + 1) * sizeof (struct harshness_code));
+           scratchalloc ((parmlength + 1) * sizeof (struct harshness_code));
 
          compute_conversion_costs (function, parms, cp, parmlength);
 
@@ -2886,8 +2944,7 @@ build_overload_call_real (fnname, parms, flags, final_cp, require_complete)
     return NULL_TREE;
   
   if (flags & LOOKUP_COMPLAIN)
-    report_type_mismatch (cp, parms, "function",
-                         decl_as_string (cp->function, 1));
+    report_type_mismatch (cp, parms, "function");
 
   return error_mark_node;
 }
@@ -2901,3 +2958,3467 @@ build_overload_call (fnname, parms, flags)
 {
   return build_overload_call_real (fnname, parms, flags, (struct candidate *)0, 1);
 }
+
+/* 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)
+
+int
+null_ptr_cst_p (t)
+     tree t;
+{
+  if (t == null_node
+      || integer_zerop (t) && TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE)
+    return 1;
+  return 0;
+}
+
+static tree
+build_conv (code, type, from)
+     enum tree_code code;
+     tree type, from;
+{
+  tree t = build1 (code, type, from);
+  int rank = ICS_STD_RANK (from);
+  switch (code)
+    {
+    case PTR_CONV:
+    case PMEM_CONV:
+    case BASE_CONV:
+    case STD_CONV:
+      if (rank < STD_RANK)
+       rank = STD_RANK;
+      break;
+
+    case QUAL_CONV:
+      if (rank < EXACT_RANK)
+       rank = EXACT_RANK;
+
+    default:
+      break;
+    }
+  ICS_STD_RANK (t) = rank;
+  ICS_USER_FLAG (t) = ICS_USER_FLAG (from);
+  ICS_BAD_FLAG (t) = ICS_BAD_FLAG (from);
+  return t;
+}
+
+static tree
+non_reference (t)
+     tree t;
+{
+  if (TREE_CODE (t) == REFERENCE_TYPE)
+    t = TREE_TYPE (t);
+  return t;
+}
+
+static tree
+strip_top_quals (t)
+     tree t;
+{
+  if (TREE_CODE (t) == ARRAY_TYPE)
+    return t;
+  return TYPE_MAIN_VARIANT (t);
+}
+
+/* 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.  */
+
+static tree
+standard_conversion (to, from, expr)
+     tree to, from, expr;
+{
+  enum tree_code fcode, tcode;
+  tree conv;
+  int fromref = 0;
+
+  if (TREE_CODE (to) == REFERENCE_TYPE)
+    to = TREE_TYPE (to);
+  if (TREE_CODE (from) == REFERENCE_TYPE)
+    {
+      fromref = 1;
+      from = TREE_TYPE (from);
+    }
+  to = strip_top_quals (to);
+  from = strip_top_quals (from);
+
+  fcode = TREE_CODE (from);
+  tcode = TREE_CODE (to);
+
+  conv = build1 (IDENTITY_CONV, from, expr);
+
+  if (fcode == FUNCTION_TYPE)
+    {
+      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);
+    }
+  else if (fromref || (expr && real_lvalue_p (expr)))
+    conv = build_conv (RVALUE_CONV, from, conv);
+
+  if (from == to)
+    return conv;
+
+  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)
+       {
+         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);
+       }
+      else if (ufcode == OFFSET_TYPE && utcode == OFFSET_TYPE)
+       {
+         tree fbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (from));
+         tree tbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (to));
+
+         if (DERIVED_FROM_P (fbase, tbase)
+             && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (from))),
+                            TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (to))),
+                            1)))
+           {
+             from = build_offset_type (tbase, TREE_TYPE (TREE_TYPE (from)));
+             from = build_pointer_type (from);
+             nconv = build_conv (PMEM_CONV, from, conv);
+           }
+       }
+      else if (IS_AGGR_TYPE (TREE_TYPE (from))
+              && IS_AGGR_TYPE (TREE_TYPE (to)))
+       {
+         if (DERIVED_FROM_P (TREE_TYPE (to), TREE_TYPE (from)))
+           {
+             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);
+           }
+       }
+
+      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)))
+       {
+         conv = build_conv (PTR_CONV, to, conv);
+         ICS_BAD_FLAG (conv) = 1;
+       }
+      else
+       return 0;
+
+      from = to;
+    }
+  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;
+}
+
+/* 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?  */
+
+static tree
+reference_binding (rto, rfrom, expr, flags)
+     tree rto, rfrom, expr;
+     int flags;
+{
+  tree conv;
+  int lvalue = 1;
+  tree to = TREE_TYPE (rto);
+  tree from = rfrom;
+  int related;
+
+  if (TREE_CODE (from) == REFERENCE_TYPE)
+    from = TREE_TYPE (from);
+  else if (! expr || ! real_lvalue_p (expr))
+    lvalue = 0;
+
+  related = (TYPE_MAIN_VARIANT (to) == TYPE_MAIN_VARIANT (from)
+            || (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
+                && DERIVED_FROM_P (to, from)));
+
+  if (lvalue && related
+      && TYPE_READONLY (to) >= TYPE_READONLY (from)
+      && TYPE_VOLATILE (to) >= TYPE_VOLATILE (from))
+    {
+      conv = build1 (IDENTITY_CONV, from, expr);
+
+      if (TYPE_MAIN_VARIANT (to) == TYPE_MAIN_VARIANT (from))
+       conv = build_conv (REF_BIND, rto, conv);
+      else
+       {
+         conv = build_conv (REF_BIND, rto, conv);
+         ICS_STD_RANK (conv) = STD_RANK;
+       }
+    }
+  else
+    conv = NULL_TREE;
+
+  if (! conv)
+    {
+      conv = standard_conversion (to, rfrom, expr);
+      if (conv)
+       {
+         conv = build_conv (REF_BIND, rto, conv);
+
+         /* Bind directly to a base subobject of a class rvalue.  Do it
+             after building the conversion for proper handling of ICS_RANK.  */
+         if (TREE_CODE (TREE_OPERAND (conv, 0)) == BASE_CONV)
+           TREE_OPERAND (conv, 0) = TREE_OPERAND (TREE_OPERAND (conv, 0), 0);
+       }
+      if (conv
+         && ((! (TYPE_READONLY (to) && ! TYPE_VOLATILE (to)
+                 && (flags & LOOKUP_NO_TEMP_BIND) == 0))
+             /* If T1 is reference-related to T2, cv1 must be the same
+                cv-qualification as, or greater cv-qualification than,
+                cv2; otherwise, the program is ill-formed.  */
+             || (related
+                 && (TYPE_READONLY (to) < TYPE_READONLY (from)
+                     || TYPE_VOLATILE (to) < TYPE_VOLATILE (from)))))
+       ICS_BAD_FLAG (conv) = 1;
+    }
+
+  return conv;
+}
+
+/* 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.  */
+
+static tree
+implicit_conversion (to, from, expr, flags)
+     tree to, from, expr;
+     int flags;
+{
+  tree conv;
+  struct z_candidate *cand;
+
+  if (expr && type_unknown_p (expr))
+    {
+      expr = instantiate_type (to, expr, 0);
+      if (expr == error_mark_node)
+       return 0;
+      from = TREE_TYPE (expr);
+    }
+
+  if (TREE_CODE (to) == REFERENCE_TYPE)
+    conv = reference_binding (to, from, expr, flags);
+  else
+    conv = standard_conversion (to, from, expr);
+
+  if (conv)
+    ;
+  else if (expr != NULL_TREE
+          && (IS_AGGR_TYPE (non_reference (from))
+           || IS_AGGR_TYPE (non_reference (to)))
+          && (flags & LOOKUP_NO_CONVERSION) == 0)
+    {
+      cand = build_user_type_conversion_1
+       (to, expr, LOOKUP_ONLYCONVERTING);
+      if (cand)
+       conv = cand->second_conv;
+      if ((! conv || ICS_BAD_FLAG (conv))
+         && TREE_CODE (to) == REFERENCE_TYPE
+         && (flags & LOOKUP_NO_TEMP_BIND) == 0)
+       {
+         cand = build_user_type_conversion_1
+           (TYPE_MAIN_VARIANT (TREE_TYPE (to)), expr, LOOKUP_ONLYCONVERTING);
+         if (cand)
+           {
+             if (! TYPE_READONLY (TREE_TYPE (to))
+                 || TYPE_VOLATILE (TREE_TYPE (to)))
+               ICS_BAD_FLAG (cand->second_conv) = 1;
+             if (!conv || (ICS_BAD_FLAG (conv)
+                           > ICS_BAD_FLAG (cand->second_conv)))
+               conv = build_conv (REF_BIND, to, cand->second_conv);
+           }
+       }
+    }
+
+  return conv;
+}
+
+/* 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.  */
+
+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))
+    {
+      parmnode = TREE_CHAIN (parmnode);
+      argnode = TREE_CHAIN (argnode);
+      if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+       {
+         parmnode = TREE_CHAIN (parmnode);
+         argnode = TREE_CHAIN (argnode);
+       }
+    }
+
+  len = list_length (argnode);
+  convs = make_scratch_vec (len);
+
+  for (i = 0; i < len; ++i)
+    {
+      tree arg = TREE_VALUE (argnode);
+      tree argtype = TREE_TYPE (arg);
+      tree t;
+
+      argtype = cp_build_type_variant
+       (argtype, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
+
+      if (parmnode == void_list_node)
+       break;
+      else if (parmnode)
+       t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg, flags);
+      else
+       {
+         t = build1 (IDENTITY_CONV, argtype, arg);
+         ICS_ELLIPSIS_FLAG (t) = 1;
+       }
+
+      if (i == 0 && t && TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
+         && ! DECL_CONSTRUCTOR_P (fn))
+       ICS_THIS_FLAG (t) = 1;
+
+      TREE_VEC_ELT (convs, i) = t;
+      if (! t)
+       break;
+
+      if (ICS_BAD_FLAG (t))
+       viable = -1;
+
+      if (parmnode)
+       parmnode = TREE_CHAIN (parmnode);
+      argnode = TREE_CHAIN (argnode);
+    }
+
+  if (i < len)
+    viable = 0;
+
+  /* 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;
+      }
+
+  cand = (struct z_candidate *) scratchalloc (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;
+}
+
+/* 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.  */
+
+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_scratch_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;
+
+      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;
+       }
+
+      TREE_VEC_ELT (convs, i) = t;
+      if (! t)
+       break;
+
+      if (ICS_BAD_FLAG (t))
+       viable = -1;
+
+      if (i == 0)
+       continue;
+
+      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 *) scratchalloc (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;
+
+{
+  tree t, convs;
+  int viable = 1, i;
+  struct z_candidate *cand;
+  tree types[2];
+
+  types[0] = type1;
+  types[1] = type2;
+
+  convs = make_scratch_vec (args[2] ? 3 : (args[1] ? 2 : 1));
+
+  for (i = 0; i < 2; ++i)
+    {
+      if (! args[i])
+       break;
+
+      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;
+    }
+
+  /* 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;
+    }      
+
+  cand = (struct z_candidate *) scratchalloc (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;
+}
+
+static 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)
+    {
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      args[1] = integer_zero_node;
+      type2 = integer_type_node;
+      break;
+    default:
+      break;
+    }
+
+  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&);
+            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))
+       {
+         type1 = build_reference_type (type1);
+         break;
+       }
+      return candidates;
+
+/* 7 For every cv-qualified or cv-unqualified complete object type T, there
+     exist candidate operator functions of the form
+
+            T&      operator*(T*);
+
+   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)))
+       {
+         tree c1 = TREE_TYPE (type1);
+         tree c2 = (TYPE_PTRMEMFUNC_P (type2)
+                    ? TYPE_METHOD_BASETYPE (TREE_TYPE (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;
+       }
+      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))
+       {
+         type2 = ptrdiff_type_node;
+         break;
+       }
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+      if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+       break;
+      return candidates;
+
+    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]))
+       {
+         type2 = type1;
+         break;
+       }
+      if ((TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2))
+         && null_ptr_cst_p (args[0]))
+       {
+         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))
+           {
+             type2 = ptrdiff_type_node;
+             break;
+           }
+       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])))
+           {
+             type2 = type1;
+             break;
+           }
+         return candidates;
+
+       default:
+         my_friendly_abort (367);
+       }
+      type1 = build_reference_type (type1);
+      break;
+
+    case COND_EXPR:
+      /* Kludge around broken overloading rules whereby
+        bool ? const char& : enum is ambiguous
+        (between int and const char&).  */
+      flags |= LOOKUP_NO_TEMP_BIND;
+
+      /* Extension: Support ?: of enumeral type.  Hopefully this will not
+         be an extension for long.  */
+      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))
+       {
+         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);
+    }
+
+  /* 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)))
+    {
+      candidates = build_builtin_candidate
+       (candidates, fnname, type1, type1, args, argtypes, flags);
+      return build_builtin_candidate
+       (candidates, fnname, type2, type2, args, argtypes, flags);
+    }
+
+  return build_builtin_candidate
+    (candidates, fnname, type1, type2, args, argtypes, flags);
+}
+
+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;
+}
+
+/* There are three conditions of builtin candidates:
+
+   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... */
+
+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];
+
+  for (i = 0; i < 3; ++i)
+    {
+      if (args[i])
+       argtypes[i]  = lvalue_type (args[i]);
+      else
+       argtypes[i] = NULL_TREE;
+    }
+
+  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;
+
+/* 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] = scratch_tree_cons
+                 (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+
+             types[i] = scratch_tree_cons
+               (NULL_TREE, TYPE_MAIN_VARIANT (argtypes[i]), types[i]);
+           }
+               
+         else if (! convs || (i == 0 && code == MODIFY_EXPR
+                              && code2 == NOP_EXPR))
+           return candidates;
+
+         for (; convs; convs = TREE_CHAIN (convs))
+           {
+             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] = scratch_tree_cons (NULL_TREE, type, types[i]);
+
+             type = non_reference (type);
+             if (i != 0 || ! ref1)
+               {
+                 type = TYPE_MAIN_VARIANT (type_decays_to (type));
+                 if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
+                   types[i] = scratch_tree_cons (NULL_TREE, type, types[i]);
+                 if (INTEGRAL_TYPE_P (type))
+                   type = type_promotes_to (type);
+               }
+
+             if (! value_member (type, types[i]))
+               types[i] = scratch_tree_cons (NULL_TREE, type, types[i]);
+           }
+       }
+      else
+       {
+         if (code == COND_EXPR && real_lvalue_p (args[i]))
+           types[i] = scratch_tree_cons
+             (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+         type = non_reference (argtypes[i]);
+         if (i != 0 || ! ref1)
+           {
+             type = TYPE_MAIN_VARIANT (type_decays_to (type));
+             if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
+               types[i] = scratch_tree_cons (NULL_TREE, type, types[i]);
+             if (INTEGRAL_TYPE_P (type))
+               type = type_promotes_to (type);
+           }
+         types[i] = scratch_tree_cons (NULL_TREE, type, types[i]);
+       }
+    }
+
+  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);
+    }
+
+  return candidates;
+}
+
+/* If TMPL can be successfully instantiated as indicated by
+   EXPLICIT_TARGS and ARGLIST, adds the instantiation to CANDIDATES.
+
+   TMPL is the template.  EXPLICIT_TARGS are any explicit template arguments.
+   ARGLIST is the arguments provided at the call-site.  The RETURN_TYPE
+   is the desired type for conversion operators.  FLAGS are as for
+   add_function_candidate.  */
+
+static struct z_candidate *
+add_template_candidate (candidates, tmpl, explicit_targs, 
+                       arglist, return_type, flags)
+     struct z_candidate *candidates;
+     tree tmpl, explicit_targs, arglist, return_type;
+     int flags;
+{
+  int ntparms = DECL_NTPARMS (tmpl);
+  tree targs = make_scratch_vec (ntparms);
+  struct z_candidate *cand;
+  int i;
+  tree fn;
+
+  i = fn_type_unification (tmpl, explicit_targs, targs, arglist,
+                          return_type, 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;
+}
+
+
+static struct z_candidate *
+add_template_conv_candidate (candidates, tmpl, obj, arglist, return_type)
+     struct z_candidate *candidates;
+     tree tmpl, obj, arglist, return_type;
+{
+  int ntparms = DECL_NTPARMS (tmpl);
+  tree targs = make_scratch_vec (ntparms);
+  struct z_candidate *cand;
+  int i;
+  tree fn;
+
+  i = fn_type_unification (tmpl, NULL_TREE, targs, arglist, return_type, 0);
+
+  if (i != 0)
+    return candidates;
+
+  fn = instantiate_template (tmpl, targs);
+  if (fn == error_mark_node)
+    return candidates;
+
+  cand = add_conv_candidate (candidates, fn, obj, arglist);
+  cand->template = DECL_TEMPLATE_INFO (fn);
+  return cand;
+}
+
+
+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;
+}
+
+static 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 ? " <near match>" : "");
+      str = "               "; 
+    }
+}
+
+/* Returns the best overload candidate to perform the requested
+   conversion.  This function is used for three the overloading situations
+   described in [over.match.copy], [over.match.conv], and [over.match.ref].
+   If TOTYPE is a REFERENCE_TYPE, we're trying to find an lvalue binding as
+   per [dcl.init.ref], so we ignore temporary bindings.  */
+
+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;
+  tree templates = NULL_TREE;
+
+  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 (ctors)
+    {
+      tree t = build_int_2 (0, 0);
+      TREE_TYPE (t) = build_pointer_type (totype);
+      args = build_scratch_list (NULL_TREE, expr);
+      if (TYPE_USES_VIRTUAL_BASECLASSES (totype))
+       args = scratch_tree_cons (NULL_TREE, integer_one_node, args);
+      args = scratch_tree_cons (NULL_TREE, t, args);
+
+      ctors = TREE_VALUE (ctors);
+    }
+  for (; ctors; ctors = DECL_CHAIN (ctors))
+    {
+      if (DECL_NONCONVERTING_P (ctors))
+       continue;
+
+      if (TREE_CODE (ctors) == TEMPLATE_DECL) 
+       {
+         templates = scratch_tree_cons (NULL_TREE, ctors, templates);
+         candidates = 
+           add_template_candidate (candidates, ctors,
+                                   NULL_TREE, args, NULL_TREE, flags);
+       } 
+      else 
+       candidates = add_function_candidate (candidates, ctors,
+                                            args, flags); 
+
+      if (candidates) 
+       {
+         candidates->second_conv = build1 (IDENTITY_CONV, totype, NULL_TREE);
+         candidates->basetype_path = TYPE_BINFO (totype);
+       } 
+    }
+
+  if (convs)
+    args = build_scratch_list (NULL_TREE, build_this (expr));
+
+  for (; convs; convs = TREE_CHAIN (convs))
+    {
+      tree fn = TREE_VALUE (convs);
+      int convflags = LOOKUP_NO_CONVERSION;
+      tree ics;
+
+      /* If we are called to convert to a reference type, we are trying to
+        find an lvalue binding, so don't even consider temporaries.  If
+        we don't find an lvalue binding, the caller will try again to
+        look for a temporary binding.  */
+      if (TREE_CODE (totype) == REFERENCE_TYPE)
+       convflags |= LOOKUP_NO_TEMP_BIND;
+
+      ics = implicit_conversion
+       (totype, TREE_TYPE (TREE_TYPE (fn)), 0, convflags);
+
+      if (TREE_CODE (totype) == REFERENCE_TYPE && ics && ICS_BAD_FLAG (ics))
+       /* ignore the near match.  */;
+      else if (ics)
+       for (; fn; fn = DECL_CHAIN (fn))
+         {
+           if (TREE_CODE (fn) == TEMPLATE_DECL)
+             {
+               templates = scratch_tree_cons (NULL_TREE, fn, templates);
+               candidates = 
+                 add_template_candidate (candidates, fn, NULL_TREE,
+                                         args, totype, flags);
+             } 
+           else 
+             candidates = add_function_candidate (candidates, fn,
+                                                  args, flags); 
+
+           if (candidates) 
+             {
+               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)
+       {
+         if (candidates && ! candidates->next)
+           /* say why this one won't work or try to be loose */;
+         else
+           cp_error ("no viable candidates");
+       }
+#endif
+
+      return 0;
+    }
+
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates);
+
+  if (cand == 0)
+    {
+      if (flags & LOOKUP_COMPLAIN)
+       {
+         cp_error ("conversion from `%T' to `%T' is ambiguous",
+                   fromtype, totype);
+         print_z_candidates (candidates);
+       }
+
+      cand = candidates;       /* any one will do */
+      cand->second_conv = build1 (AMBIG_CONV, totype, expr);
+      ICS_USER_FLAG (cand->second_conv) = 1;
+      ICS_BAD_FLAG (cand->second_conv) = 1;
+
+      return cand;
+    }
+
+  for (p = &(cand->second_conv); TREE_CODE (*p) != IDENTITY_CONV; )
+    p = &(TREE_OPERAND (*p, 0));
+
+  /* Pedantically, normal function declarations are never considered
+     to refer to template instantiations, so we only do this with
+     -fguiding-decls.  */ 
+  if (flag_guiding_decls && templates && ! cand->template 
+      && !DECL_INITIAL (cand->fn) 
+      && TREE_CODE (TREE_TYPE (cand->fn)) != METHOD_TYPE)
+    add_maybe_template (cand->fn, templates);
+
+  *p = build
+    (USER_CONV,
+     (DECL_CONSTRUCTOR_P (cand->fn)
+      ? totype : non_reference (TREE_TYPE (TREE_TYPE (cand->fn)))),
+     expr, cand->fn, cand->convs, cand->basetype_path);
+  ICS_USER_FLAG (cand->second_conv) = 1;
+  if (cand->viable == -1)
+    ICS_BAD_FLAG (cand->second_conv) = 1;
+
+  return cand;
+}
+
+tree
+build_user_type_conversion (totype, expr, flags)
+     tree totype, expr;
+     int flags;
+{
+  struct z_candidate *cand
+    = build_user_type_conversion_1 (totype, expr, flags);
+
+  if (cand)
+    {
+      if (TREE_CODE (cand->second_conv) == AMBIG_CONV)
+       return error_mark_node;
+      return convert_from_reference (convert_like (cand->second_conv, expr));
+    }
+  return NULL_TREE;
+}
+
+/* Do any initial processing on the arguments to a function call.  */
+
+static tree
+resolve_args (args)
+     tree args;
+{
+  tree t;
+  for (t = args; t; t = TREE_CHAIN (t))
+    {
+      if (TREE_VALUE (t) == error_mark_node)
+       return error_mark_node;
+      else if (TREE_CODE (TREE_TYPE (TREE_VALUE (t))) == VOID_TYPE)
+       {
+         error ("invalid use of void expression");
+         return error_mark_node;
+       }
+      else if (TREE_CODE (TREE_VALUE (t)) == OFFSET_REF)
+       TREE_VALUE (t) = resolve_offset_ref (TREE_VALUE (t));
+    }
+  return args;
+}
+      
+tree
+build_new_function_call (fn, args)
+     tree fn, args;
+{
+  struct z_candidate *candidates = 0, *cand;
+  tree explicit_targs = NULL_TREE;
+  int template_only = 0;
+
+  if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
+    {
+      explicit_targs = TREE_OPERAND (fn, 1);
+      fn = TREE_OPERAND (fn, 0);
+      template_only = 1;
+    }
+
+  if (really_overloaded_fn (fn))
+    {
+      tree t;
+      tree templates = NULL_TREE;
+
+      args = resolve_args (args);
+
+      if (args == error_mark_node)
+       return error_mark_node;
+
+      for (t = TREE_VALUE (fn); t; t = DECL_CHAIN (t))
+       {
+         if (TREE_CODE (t) == TEMPLATE_DECL)
+           {
+             templates = scratch_tree_cons (NULL_TREE, t, templates);
+             candidates = add_template_candidate
+               (candidates, t, explicit_targs, args, NULL_TREE,
+                LOOKUP_NORMAL);  
+           }
+         else if (! template_only)
+           candidates = add_function_candidate
+             (candidates, t, args, LOOKUP_NORMAL);
+       }
+
+      if (! any_viable (candidates))
+       {
+         if (candidates && ! candidates->next)
+           return build_function_call (candidates->fn, args);
+         cp_error ("no matching function for call to `%D (%A)'",
+                   TREE_PURPOSE (fn), args);
+         if (candidates)
+           print_z_candidates (candidates);
+         return error_mark_node;
+       }
+      candidates = splice_viable (candidates);
+      cand = tourney (candidates);
+
+      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, normal function declarations are never considered
+        to refer to template instantiations, so we only do this with
+        -fguiding-decls.  */
+      if (flag_guiding_decls && templates && ! cand->template 
+         && ! DECL_INITIAL (cand->fn))
+       add_maybe_template (cand->fn, templates);
+
+      return build_over_call (cand->fn, cand->convs, args, LOOKUP_NORMAL);
+    }
+
+  return build_function_call (fn, args);
+}
+
+static tree
+build_object_call (obj, args)
+     tree obj, args;
+{
+  struct z_candidate *candidates = 0, *cand;
+  tree fns, convs, mem_args;
+  tree type = TREE_TYPE (obj);
+  tree templates = NULL_TREE;
+
+  fns = lookup_fnfields (TYPE_BINFO (type), ansi_opname [CALL_EXPR], 0);
+
+  args = resolve_args (args);
+
+  if (args == error_mark_node)
+    return error_mark_node;
+
+  if (fns)
+    {
+      tree fn = TREE_VALUE (fns);
+      mem_args = scratch_tree_cons (NULL_TREE, build_this (obj), args);
+
+      for (; fn; fn = DECL_CHAIN (fn))
+       {
+         if (TREE_CODE (fn) == TEMPLATE_DECL)
+           {
+             templates = scratch_tree_cons (NULL_TREE, fn, templates);
+             candidates 
+               = add_template_candidate (candidates, fn, NULL_TREE,
+                                         mem_args, NULL_TREE, 
+                                         LOOKUP_NORMAL);
+           }
+         else
+           candidates = add_function_candidate
+             (candidates, fn, mem_args, LOOKUP_NORMAL);
+
+         if (candidates)
+           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))
+         {
+           if (TREE_CODE (fn) == TEMPLATE_DECL) 
+             {
+               templates = scratch_tree_cons (NULL_TREE, fn, templates);
+               candidates = add_template_conv_candidate (candidates,
+                                                         fn,
+                                                         obj,
+                                                         args,
+                                                         totype);
+             }
+           else
+             candidates = add_conv_candidate (candidates, fn, obj, args);
+
+           if (candidates)
+             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);
+
+  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
+       cp_error ("%s for `%s%T'", problem, opname, error_type (arg1));
+    }
+}
+
+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;
+  enum tree_code code2 = NOP_EXPR;
+  tree templates = NULL_TREE;
+  tree conv;
+
+  if (arg1 == error_mark_node
+      || arg2 == error_mark_node
+      || arg3 == error_mark_node)
+    return error_mark_node;
+
+  /* This can happen if a template takes all non-type parameters, e.g.
+     undeclared_template<1, 5, 72>a;  */
+  if (code == LT_EXPR && TREE_CODE (arg1) == TEMPLATE_DECL)
+    {
+      cp_error ("`%D' must be declared before use", arg1);
+      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 = scratch_tree_cons (NULL_TREE, arg2, arg3);
+       if (flags & LOOKUP_GLOBAL)
+         return build_new_function_call
+           (lookup_name_nonclass (fnname), arglist);
+
+       /* 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;
+       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_scratch_list (NULL_TREE, arg1));
+
+       arglist = scratch_tree_cons (NULL_TREE, arg1, build_scratch_list (NULL_TREE, arg2));
+
+       arg1 = TREE_TYPE (arg1);
+
+       /* 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));
+
+           while (TREE_CODE (arg1) == ARRAY_TYPE)
+               arg1 = (TREE_TYPE (arg1));
+
+           arg1 = build_pointer_type (arg1);
+         }
+
+       /* 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;
+      }
+
+    case CALL_EXPR:
+      return build_object_call (arg1, arg2);
+
+    default:
+      break;
+    }
+
+  /* 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);
+
+  if (code == COND_EXPR)
+    {
+      if (arg2 == NULL_TREE
+         || 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;
+
+  if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
+    arg2 = integer_zero_node;
+
+  if (arg2 && arg3)
+    arglist = scratch_tree_cons (NULL_TREE, arg1, scratch_tree_cons
+                     (NULL_TREE, arg2, build_scratch_list (NULL_TREE, arg3)));
+  else if (arg2)
+    arglist = scratch_tree_cons (NULL_TREE, arg1, build_scratch_list (NULL_TREE, arg2));
+  else
+    arglist = build_scratch_list (NULL_TREE, arg1);
+
+  fns = lookup_name_nonclass (fnname);
+  /* + Koenig lookup */
+
+  if (fns && TREE_CODE (fns) == TREE_LIST)
+    fns = TREE_VALUE (fns);
+  for (; fns; fns = DECL_CHAIN (fns))
+    {
+      if (TREE_CODE (fns) == TEMPLATE_DECL)
+       {
+         templates = scratch_tree_cons (NULL_TREE, fns, templates);
+         candidates 
+           = add_template_candidate (candidates, fns, NULL_TREE,
+                                     arglist, TREE_TYPE (fnname),
+                                     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;
+
+  if (fns)
+    {
+      tree fn = TREE_VALUE (fns);
+      mem_arglist = scratch_tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
+      for (; fn; fn = DECL_CHAIN (fn))
+       {
+         tree this_arglist;
+
+         if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+           this_arglist = mem_arglist;
+         else
+           this_arglist = arglist;
+
+         if (TREE_CODE (fn) == TEMPLATE_DECL)
+           {
+             /* A member template. */
+             templates = scratch_tree_cons (NULL_TREE, fn, templates);
+             candidates 
+               = add_template_candidate (candidates, fn, NULL_TREE,
+                                         this_arglist,  TREE_TYPE (fnname),
+                                         flags); 
+           }
+         else
+           candidates = add_function_candidate
+             (candidates, fn, this_arglist, flags);
+
+         if (candidates) 
+           candidates->basetype_path = TREE_PURPOSE (fns);
+       }
+    }
+
+  {
+    tree args[3];
+
+    /* 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;
+      }
+
+    candidates = add_builtin_candidates
+      (candidates, code, code2, fnname, args, flags);
+  }
+
+  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;
+
+       default:
+         break;
+       }
+      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);
+
+  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 (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 (DECL_FUNCTION_MEMBER_P (cand->fn))
+       enforce_access (cand->basetype_path, cand->fn);
+
+      /* Pedantically, normal function declarations are never considered
+        to refer to template instantiations, so we only do this with
+        -fguiding-decls.  */ 
+      if (flag_guiding_decls && 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);
+    }
+
+  /* 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));
+       }
+      break;
+    default:
+      break;
+    }
+
+  /* We need to strip any leading REF_BIND so that bitfields don't cause
+     errors.  This should not remove any important conversions, because
+     builtins don't apply to class objects directly.  */
+  conv = TREE_VEC_ELT (cand->convs, 0);
+  if (TREE_CODE (conv) == REF_BIND)
+    conv = TREE_OPERAND (conv, 0);
+  arg1 = convert_like (conv, 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);
+
+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:
+    case REALPART_EXPR:
+    case IMAGPART_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;
+
+    default:
+      my_friendly_abort (367);
+    }
+}
+
+/* Build up a call to operator new.  This has to be handled differently
+   from other operators in the way lookup is handled; first members are
+   considered, then globals.  CODE is either NEW_EXPR or VEC_NEW_EXPR.
+   TYPE is the type to be created.  ARGS are any new-placement args.
+   FLAGS are the usual overloading flags.  */
+
+tree
+build_op_new_call (code, type, args, flags)
+     enum tree_code code;
+     tree type, args;
+     int flags;
+{
+  tree fnname = ansi_opname[code];
+
+  if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL)
+      && (TYPE_GETS_NEW (type) & (1 << (code == VEC_NEW_EXPR))))
+    {
+      tree dummy = build1 (NOP_EXPR, build_pointer_type (type),
+                          error_mark_node);
+      dummy = build_indirect_ref (dummy, "new");
+      return build_method_call (dummy, fnname, args, NULL_TREE, flags);
+    }
+  else
+    return build_new_function_call (lookup_name_nonclass (fnname), args);
+}
+
+/* Build a call to operator delete.  This has to be handled very specially,
+   because the restrictions on what signatures match are different from all
+   other call instances.  For a normal delete, only a delete taking (void *)
+   or (void *, size_t) is accepted.  For a placement delete, only an exact
+   match with the placement new is accepted.
+
+   CODE is either DELETE_EXPR or VEC_DELETE_EXPR.
+   ADDR is the pointer to be deleted.  For placement delete, it is also
+     used to determine what the corresponding new looked like.
+   SIZE is the size of the memory block to be deleted.
+   FLAGS are the usual overloading flags.  */
+
+tree
+build_op_delete_call (code, addr, size, flags)
+     enum tree_code code;
+     tree addr, size;
+     int flags;
+{
+  tree fn, fns, fnname, fntype, argtypes, args, type;
+  int placement;
+
+  if (addr == error_mark_node)
+    return error_mark_node;
+
+  type = TREE_TYPE (TREE_TYPE (addr));
+  fnname = ansi_opname[code];
+
+  if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL))
+    fns = lookup_fnfields (TYPE_BINFO (type), fnname, 0);
+  else
+    fns = NULL_TREE;
+
+  if (fns)
+    {
+      /* Build this up like build_offset_ref does.  */
+      fns = build_tree_list (error_mark_node, fns);
+      TREE_TYPE (fns) = build_offset_type (type, unknown_type_node);
+    }
+  else
+    fns = lookup_name_nonclass (fnname);
+
+  /* We can recognize a placement delete because of LOOKUP_SPECULATIVELY;
+     if we are doing placement delete we do nothing if we don't find a
+     matching op delete.  */
+  placement = !!(flags & LOOKUP_SPECULATIVELY);
+  if (placement)
+    {
+      /* If placement, we are coming from build_new, and we know that addr
+        is the allocation expression, so extract the info we need from it.
+        Obviously, if the build_new process changes this may have to
+        change as well.  */
+
+      /* The NOP_EXPR.  */
+      tree t = TREE_OPERAND (addr, 1);
+      /* The CALL_EXPR.  */
+      t = TREE_OPERAND (t, 0);
+      /* The function.  */
+      argtypes = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+      /* The second parm type.  */
+      argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (argtypes)));
+      /* The second argument.  */
+      args = TREE_CHAIN (TREE_OPERAND (t, 1));
+
+      /* Pull the dummy var out of the TARGET_EXPR for use in our call.  */
+      addr = TREE_OPERAND (addr, 0);
+    }
+  else
+    {
+      /* First try it without the size argument.  */
+      argtypes = void_list_node;
+      args = NULL_TREE;
+    }
+
+  argtypes = tree_cons (NULL_TREE, ptr_type_node, argtypes);
+  fntype = build_function_type (void_type_node, argtypes);
+
+  /* Strip const and volatile from addr.  */
+  if (type != TYPE_MAIN_VARIANT (type))
+    addr = cp_convert (build_pointer_type (TYPE_MAIN_VARIANT (type)), addr);
+
+  /* instantiate_type will always return a plain function; pretend it's
+     overloaded.  */
+  if (TREE_CODE (fns) == FUNCTION_DECL)
+    fns = scratch_tree_cons (NULL_TREE, fns, NULL_TREE);
+
+  fn = instantiate_type (fntype, fns, 0);
+
+  if (fn != error_mark_node)
+    {
+      if (TREE_CODE (TREE_VALUE (fns)) == TREE_LIST)
+       /* Member functions.  */
+       enforce_access (TREE_PURPOSE (TREE_VALUE (fns)), fn);
+      return build_function_call (fn, expr_tree_cons (NULL_TREE, addr, args));
+    }
+
+  if (placement)
+    return NULL_TREE;
+
+  /* Normal delete; now try to find a match including the size argument.  */
+  argtypes = tree_cons (NULL_TREE, ptr_type_node,
+                       tree_cons (NULL_TREE, sizetype, void_list_node));
+  fntype = build_function_type (void_type_node, argtypes);
+
+  fn = instantiate_type (fntype, fns, 0);
+
+  if (fn != error_mark_node)
+    return build_function_call
+      (fn, expr_tree_cons (NULL_TREE, addr,
+                          build_expr_list (NULL_TREE, size)));
+
+  cp_error ("no suitable operator delete for `%T'", type);
+  return error_mark_node;
+}
+
+/* If the current scope isn't allowed to access FUNCTION along
+   BASETYPE_PATH, give an error.  */
+
+static void
+enforce_access (basetype_path, function)
+     tree basetype_path, function;
+{
+  tree access = compute_access (basetype_path, function);
+
+  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");
+    }
+}
+
+/* Perform the conversions in CONVS on the expression EXPR.  */
+
+static tree
+convert_like (convs, expr)
+     tree convs, expr;
+{
+  if (ICS_BAD_FLAG (convs)
+      && TREE_CODE (convs) != USER_CONV
+      && TREE_CODE (convs) != AMBIG_CONV)
+    {
+      tree t = convs; 
+      for (; t; t = TREE_OPERAND (t, 0))
+       {
+         if (TREE_CODE (t) == USER_CONV)
+           {
+             expr = convert_like (t, expr);
+             break;
+           }
+         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);
+    }
+
+  switch (TREE_CODE (convs))
+    {
+    case USER_CONV:
+      {
+       tree fn = TREE_OPERAND (convs, 1);
+       tree args;
+       enforce_access (TREE_OPERAND (convs, 3), fn);
+
+       if (DECL_CONSTRUCTOR_P (fn))
+         {
+           tree t = build_int_2 (0, 0);
+           TREE_TYPE (t) = build_pointer_type (DECL_CONTEXT (fn));
+
+           args = build_scratch_list (NULL_TREE, expr);
+           if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+             args = scratch_tree_cons (NULL_TREE, integer_one_node, args);
+           args = scratch_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 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);
+
+       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);
+
+    default:
+      break;
+    };
+
+  expr = convert_like (TREE_OPERAND (convs, 0), expr);
+  if (expr == error_mark_node)
+    return error_mark_node;
+
+  switch (TREE_CODE (convs))
+    {
+    case RVALUE_CONV:
+      if (! IS_AGGR_TYPE (TREE_TYPE (convs)))
+       return expr;
+      /* else fall through */
+    case BASE_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,
+        error_mark_node);
+    case LVALUE_CONV:
+      return decay_conversion (expr);
+
+    default:
+      break;
+    }
+  return ocp_convert (TREE_TYPE (convs), expr, CONV_IMPLICIT,
+                     LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
+}
+
+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
+    }
+
+  return arg;
+}
+
+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_scratch_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))
+    {
+      converted_args = expr_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)))
+       {
+         converted_args = expr_tree_cons
+           (NULL_TREE, TREE_VALUE (arg), converted_args);
+         arg = TREE_CHAIN (arg);
+         parm = TREE_CHAIN (parm);
+       }
+    }      
+  /* Bypass access control for 'this' parameter.  */
+  else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+    {
+      tree parmtype = TREE_VALUE (parm);
+      tree argtype = TREE_TYPE (TREE_VALUE (arg));
+      if (ICS_BAD_FLAG (TREE_VEC_ELT (convs, i)))
+       {
+         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);
+       }
+      converted_args = expr_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;
+    }
+
+  for (; arg && parm;
+       parm = TREE_CHAIN (parm), arg = TREE_CHAIN (arg), ++i)
+    {
+      tree type = TREE_VALUE (parm);
+
+      conv = TREE_VEC_ELT (convs, i);
+      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
+       val = convert_like (conv, TREE_VALUE (arg));
+
+#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 = expr_tree_cons (NULL_TREE, val, converted_args);
+    }
+
+  /* Default arguments */
+  for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm))
+    {
+      tree arg = TREE_PURPOSE (parm);
+
+      if (DECL_TEMPLATE_INFO (fn))
+       /* This came from a template.  Instantiate the default arg here,
+          not in tsubst.  */
+       arg = tsubst_expr (arg, DECL_TI_ARGS (fn),
+                          TREE_VEC_LENGTH (DECL_TI_ARGS (fn)), NULL_TREE);
+      converted_args = expr_tree_cons
+       (NULL_TREE, convert_default_arg (TREE_VALUE (parm), arg),
+        converted_args);
+    }
+
+  /* Ellipsis */
+  for (; arg; arg = TREE_CHAIN (arg))
+    {
+      val = TREE_VALUE (arg);
+
+      if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
+         && (TYPE_PRECISION (TREE_TYPE (val))
+             < TYPE_PRECISION (double_type_node)))
+       /* Convert `float' to `double'.  */
+       val = cp_convert (double_type_node, val);
+      else if (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
+       /* Convert `short' and `char' to full-size `int'.  */
+       val = default_conversion (val);
+
+      converted_args = expr_tree_cons (NULL_TREE, val, converted_args);
+    }
+
+  converted_args = nreverse (converted_args);
+
+  /* Avoid actually calling copy constructors and copy assignment operators,
+     if possible.  */
+  if (DECL_CONSTRUCTOR_P (fn)
+      && TREE_VEC_LENGTH (convs) == 1
+      && copy_args_p (fn))
+    {
+      tree targ;
+      arg = TREE_CHAIN (converted_args);
+      if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+       arg = TREE_CHAIN (arg);
+      arg = TREE_VALUE (arg);
+
+      /* Pull out the real argument, disregarding const-correctness.  */
+      targ = arg;
+      while (TREE_CODE (targ) == NOP_EXPR
+            || TREE_CODE (targ) == NON_LVALUE_EXPR
+            || TREE_CODE (targ) == CONVERT_EXPR)
+       targ = TREE_OPERAND (targ, 0);
+      if (TREE_CODE (targ) == ADDR_EXPR)
+       {
+         targ = TREE_OPERAND (targ, 0);
+         if (! comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (arg))),
+                          TYPE_MAIN_VARIANT (TREE_TYPE (targ)), 1))
+           targ = NULL_TREE;
+       }
+      else
+       targ = NULL_TREE;
+
+      if (targ)
+       arg = targ;
+      else
+       arg = build_indirect_ref (arg, 0);
+
+      /* [class.copy]: the copy constructor is implicitly defined even if
+        the implementation elided its use.  */
+      if (TYPE_HAS_COMPLEX_INIT_REF (DECL_CONTEXT (fn)))
+       mark_used (fn);
+
+      /* 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)))
+           {
+             val = build (VAR_DECL, DECL_CONTEXT (fn));
+             layout_decl (val, 0);
+             val = build (TARGET_EXPR, DECL_CONTEXT (fn), val, arg, 0, 0);
+             TREE_SIDE_EFFECTS (val) = 1;
+             return val;
+           }
+       }
+      else if (! real_lvalue_p (arg)
+              || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
+       {
+         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;
+    }
+
+  mark_used (fn);
+
+  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)
+    {
+      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;
+  fn = require_complete_type (fn);
+  if (IS_AGGR_TYPE (TREE_TYPE (fn)))
+    fn = build_cplus_new (TREE_TYPE (fn), fn);
+  return convert_from_reference (fn);
+}
+
+static 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 explicit_targs = NULL_TREE;
+  tree basetype, mem_args, fns, instance_ptr;
+  tree pretty_name;
+  tree user_args = args;
+  tree templates = NULL_TREE;
+  int template_only = 0;
+
+  if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+    {
+      explicit_targs = TREE_OPERAND (name, 1);
+      name = TREE_OPERAND (name, 0);
+      if (TREE_CODE (name) == TEMPLATE_DECL)
+       name = DECL_NAME (name);
+      template_only = 1;
+    }
+
+  /* If there is an extra argument for controlling virtual bases,
+     remove it for error reporting.  */
+  if (flags & LOOKUP_HAS_IN_CHARGE)
+    user_args = TREE_CHAIN (args);
+
+  args = resolve_args (args);
+
+  if (args == error_mark_node)
+    return error_mark_node;
+
+  if (instance == NULL_TREE)
+    basetype = BINFO_TYPE (basetype_path);
+  else
+    {
+      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);
+
+      /* 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))))
+       {
+         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;
+       }
+
+      /* 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);
+
+      if (! template_only)
+       {
+         /* XXX this should be handled before we get here.  */
+         fns = build_field_call (basetype_path, instance_ptr, name, args);
+         if (fns)
+           return fns;
+       }
+    }
+  else
+    {
+      instance_ptr = build_int_2 (0, 0);
+      TREE_TYPE (instance_ptr) = build_pointer_type (basetype);
+    }
+
+  pretty_name
+    = (name == ctor_identifier ? constructor_name (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))
+       {
+         flags |= LOOKUP_HAS_IN_CHARGE;
+         args = scratch_tree_cons (NULL_TREE, integer_one_node, args);
+       }
+      mem_args = scratch_tree_cons (NULL_TREE, instance_ptr, args);
+      for (; t; t = DECL_CHAIN (t))
+       {
+         tree this_arglist;
+
+         /* We can end up here for copy-init of same or base class.  */
+         if (name == ctor_identifier
+             && (flags & LOOKUP_ONLYCONVERTING)
+             && DECL_NONCONVERTING_P (t))
+           continue;
+         if (TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)
+           this_arglist = mem_args;
+         else
+           this_arglist = args;
+
+         if (TREE_CODE (t) == TEMPLATE_DECL)
+           {
+             /* A member template. */
+             templates = scratch_tree_cons (NULL_TREE, t, templates);
+             candidates = 
+               add_template_candidate (candidates, t, explicit_targs,
+                                       this_arglist,
+                                       TREE_TYPE (name), flags); 
+           }
+         else if (! template_only)
+           candidates = add_function_candidate (candidates, t,
+                                                this_arglist, flags);
+
+         if (candidates)
+           candidates->basetype_path = TREE_PURPOSE (fns);
+       }
+    }
+
+  if (! any_viable (candidates))
+    {
+      /* 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, user_args, TREE_TYPE (TREE_TYPE (instance_ptr)));
+      print_z_candidates (candidates);
+      return error_mark_node;
+    }
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates);
+
+  if (cand == 0)
+    {
+      cp_error ("call of overloaded `%D(%A)' is ambiguous", pretty_name,
+               user_args);
+      print_z_candidates (candidates);
+      return error_mark_node;
+    }
+
+  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;
+
+  /* Pedantically, normal function declarations are never considered
+     to refer to template instantiations, so we only do this with
+     -fguiding-decls.  */ 
+  if (flag_guiding_decls && templates && ! cand->template 
+      && ! DECL_INITIAL (cand->fn))
+    add_maybe_template (cand->fn, templates);
+
+  return build_over_call
+    (cand->fn, cand->convs,
+     TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE ? mem_args : args,
+     flags);
+}
+
+/* Compare two implicit conversion sequences that differ only in their
+   qualification conversion.  Subroutine of compare_ics.  */
+
+static int
+compare_qual (ics1, ics2)
+     tree ics1, ics2;
+{
+  tree to1 = TREE_TYPE (ics1);
+  tree to2 = TREE_TYPE (ics2);
+
+  if (TYPE_PTRMEMFUNC_P (to1))
+    to1 = TYPE_PTRMEMFUNC_FN_TYPE (to1);
+  if (TYPE_PTRMEMFUNC_P (to2))
+    to2 = TYPE_PTRMEMFUNC_FN_TYPE (to2);
+
+  to1 = TREE_TYPE (to1);
+  to2 = TREE_TYPE (to2);
+
+  if (TREE_CODE (to1) == OFFSET_TYPE)
+    {
+      to1 = TREE_TYPE (to1);
+      to2 = TREE_TYPE (to2);
+    }
+
+  if (TYPE_READONLY (to1) >= TYPE_READONLY (to2)
+      && TYPE_VOLATILE (to1) > TYPE_VOLATILE (to2))
+    return -1;
+  else if (TYPE_READONLY (to1) > TYPE_READONLY (to2)
+          && TYPE_VOLATILE (to1) == TYPE_VOLATILE (to2))
+    return -1;
+  else if (TYPE_READONLY (to1) <= TYPE_READONLY (to2)
+          && TYPE_VOLATILE (to1) < TYPE_VOLATILE (to2))
+    return 1;
+  else if (TYPE_READONLY (to1) < TYPE_READONLY (to2)
+          && TYPE_VOLATILE (to1) == TYPE_VOLATILE (to2))
+    return 1;
+  return 0;
+}
+
+/* Determine whether standard conversion sequence ICS1 is a proper
+   subsequence of ICS2.  We assume that a conversion of the same code
+   between the same types indicates a subsequence.  */
+
+static int
+is_subseq (ics1, ics2)
+     tree ics1, ics2;
+{
+  /* Do not consider lvalue transformations here.  */
+  if (TREE_CODE (ics2) == RVALUE_CONV
+      || TREE_CODE (ics2) == LVALUE_CONV)
+    return 0;
+
+  for (;; ics2 = TREE_OPERAND (ics2, 0))
+    {
+      if (TREE_CODE (ics2) == TREE_CODE (ics1)
+         && comptypes (TREE_TYPE (ics2), TREE_TYPE (ics1), 1)
+         && comptypes (TREE_TYPE (TREE_OPERAND (ics2, 0)),
+                       TREE_TYPE (TREE_OPERAND (ics1, 0)), 1))
+       return 1;
+
+      if (TREE_CODE (ics2) == USER_CONV
+         || TREE_CODE (ics2) == AMBIG_CONV
+         || TREE_CODE (ics2) == IDENTITY_CONV)
+       return 0;
+    }
+}
+
+/* Compare two implicit conversion sequences according to the rules set out in
+   [over.ics.rank].  Return values:
+
+      1: ics1 is better than ics2
+     -1: ics2 is better than ics1
+      0: ics1 and ics2 are indistinguishable */
+
+static int
+compare_ics (ics1, ics2)
+     tree ics1, ics2;
+{
+  tree main1, main2;
+
+  if (TREE_CODE (ics1) == QUAL_CONV)
+    main1 = TREE_OPERAND (ics1, 0);
+  else
+    main1 = ics1;
+
+  if (TREE_CODE (ics2) == QUAL_CONV)
+    main2 = TREE_OPERAND (ics2, 0);
+  else
+    main2 = ics2;
+
+  /* Conversions for `this' are PTR_CONVs, but we compare them as though
+     they were REF_BINDs.  */
+  if (ICS_THIS_FLAG (ics1))
+    {
+      tree t = main1;
+      if (TREE_CODE (t) == PTR_CONV)
+       t = TREE_OPERAND (t, 0);
+      t = build1 (IDENTITY_CONV, TREE_TYPE (TREE_TYPE (t)), NULL_TREE);
+      t = build_conv (REF_BIND, TREE_TYPE (ics1), t);
+      ICS_STD_RANK (t) = ICS_STD_RANK (main1);
+      main1 = ics1 = t;
+    }
+  if (ICS_THIS_FLAG (ics2))
+    {
+      tree t = main2;
+      if (TREE_CODE (t) == PTR_CONV)
+       t = TREE_OPERAND (t, 0);
+      t = build1 (IDENTITY_CONV, TREE_TYPE (TREE_TYPE (t)), NULL_TREE);
+      t = build_conv (REF_BIND, TREE_TYPE (ics2), t);
+      ICS_STD_RANK (t) = ICS_STD_RANK (main2);
+      main2 = ics2 = t;
+    }
+
+  if (ICS_RANK (ics1) > ICS_RANK (ics2))
+    return -1;
+  else if (ICS_RANK (ics1) < ICS_RANK (ics2))
+    return 1;
+
+  if (ICS_RANK (ics1) == BAD_RANK)
+    {
+      if (ICS_USER_FLAG (ics1) > ICS_USER_FLAG (ics2)
+         || ICS_STD_RANK (ics1) > ICS_STD_RANK (ics2))
+       return -1;
+      else if (ICS_USER_FLAG (ics1) < ICS_USER_FLAG (ics2)
+              || ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2))
+       return 1;
+
+      /* else fall through */
+    }
+
+  /* User-defined  conversion sequence U1 is a better conversion sequence
+     than another user-defined conversion sequence U2 if they contain the
+     same user-defined conversion operator or constructor and if the sec-
+     ond standard conversion sequence of U1 is  better  than  the  second
+     standard conversion sequence of U2.  */
+
+  if (ICS_USER_FLAG (ics1))
+    {
+      tree t1, t2;
+
+      for (t1 = ics1; TREE_CODE (t1) != USER_CONV; t1 = TREE_OPERAND (t1, 0))
+       if (TREE_CODE (t1) == AMBIG_CONV)
+         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 */
+    }
+
+#if 0 /* Handled by ranking */
+  /* A conversion that is not a conversion of a pointer,  or  pointer  to
+     member,  to  bool  is  better than another conversion that is such a
+     conversion.  */
+#endif
+
+  if (TREE_CODE (main1) != TREE_CODE (main2))
+    {
+      /* ...if S1  is  a  proper  subsequence  of  S2  */
+      if (is_subseq (main1, main2))
+       return 1;
+      if (is_subseq (main2, main1))
+       return -1;
+      return 0;
+    }
+
+  if (TREE_CODE (main1) == PTR_CONV || TREE_CODE (main1) == PMEM_CONV
+      || TREE_CODE (main1) == REF_BIND || TREE_CODE (main1) == BASE_CONV)
+    {
+      tree to1 = TREE_TYPE (main1);
+      tree from1 = TREE_TYPE (TREE_OPERAND (main1, 0));
+      tree to2 = TREE_TYPE (main2);
+      tree from2 = TREE_TYPE (TREE_OPERAND (main2, 0));
+      int distf, distt;
+
+      /* Standard conversion sequence S1 is a better conversion sequence than
+        standard conversion sequence S2 if...
+
+        S1 and S2 differ only in their qualification conversion  and  they
+        yield types identical except for cv-qualifiers and S2 adds all the
+        qualifiers that S1 adds (and in the same places) and S2  adds  yet
+        more  cv-qualifiers  than  S1,  or the similar case with reference
+        binding15).  */
+      if (TREE_CODE (main1) == REF_BIND)
+       {
+         if (TYPE_MAIN_VARIANT (TREE_TYPE (to1))
+             == TYPE_MAIN_VARIANT (TREE_TYPE (to2)))
+           return compare_qual (ics1, ics2);
+       }
+      else if (TREE_CODE (main1) != BASE_CONV && from1 == from2 && to1 == to2)
+       return compare_qual (ics1, ics2);
+       
+      if (TYPE_PTRMEMFUNC_P (to1))
+       {
+         to1 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to1)));
+         from1 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from1)));
+       }
+      else if (TREE_CODE (main1) != BASE_CONV)
+       {
+         to1 = TREE_TYPE (to1);
+         if (TREE_CODE (main1) != REF_BIND)
+           from1 = TREE_TYPE (from1);
+
+         if (TREE_CODE (to1) == OFFSET_TYPE)
+           {
+             to1 = TYPE_OFFSET_BASETYPE (to1);
+             from1 = TYPE_OFFSET_BASETYPE (from1);
+           }
+       }
+
+      if (TYPE_PTRMEMFUNC_P (to2))
+       {
+         to2 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to2)));
+         from2 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from2)));
+       }
+      else if (TREE_CODE (main1) != BASE_CONV)
+       {
+         to2 = TREE_TYPE (to2);
+         if (TREE_CODE (main1) != REF_BIND)
+           from2 = TREE_TYPE (from2);
+
+         if (TREE_CODE (to2) == OFFSET_TYPE)
+           {
+             to2 = TYPE_OFFSET_BASETYPE (to2);
+             from2 = TYPE_OFFSET_BASETYPE (from2);
+           }
+       }
+
+      if (! (IS_AGGR_TYPE (from1) && IS_AGGR_TYPE (from2)))
+       return 0;
+
+      /* The sense of pmem conversions is reversed from that of the other
+        conversions.  */
+      if (TREE_CODE (main1) == PMEM_CONV)
+       {
+         tree t = from1; from1 = from2; from2 = t;
+         t = to1; to1 = to2; to2 = t;
+       }
+
+      distf = get_base_distance (from1, from2, 0, 0);
+      if (distf == -1)
+       {
+         distf = -get_base_distance (from2, from1, 0, 0);
+         if (distf == 1)
+           return 0;
+       }
+
+      /* If class B is derived directly or indirectly from class A,
+        conver- sion of B* to A* is better than conversion of B* to
+        void*, and conversion of A* to void* is better than
+        conversion of B* to void*.  */
+
+      if (TREE_CODE (to1) == VOID_TYPE && TREE_CODE (to2) == VOID_TYPE)
+       {
+         if (distf > 0)
+           return 1;
+         else if (distf < 0)
+           return -1;
+       }
+      else if (TREE_CODE (to2) == VOID_TYPE && IS_AGGR_TYPE (to1)
+              && get_base_distance (to1, from1, 0, 0) != -1)
+       return 1;
+      else if (TREE_CODE (to1) == VOID_TYPE && IS_AGGR_TYPE (to2)
+              && get_base_distance (to2, from2, 0, 0) != -1)
+       return -1;
+
+      if (! (IS_AGGR_TYPE (to1) && IS_AGGR_TYPE (to2)))
+       return 0;
+
+      /* If  class B is derived directly or indirectly from class A and class
+        C is derived directly or indirectly from B */
+
+      distt = get_base_distance (to1, to2, 0, 0);
+      if (distt == -1)
+       {
+         distt = -get_base_distance (to2, to1, 0, 0);
+         if (distt == 1)
+           return 0;
+       }
+
+      /* --conversion of C* to B* is better than conversion of C* to A*, */
+      if (distf == 0)
+       {
+         if (distt > 0)
+           return -1;
+         else if (distt < 0)
+           return 1;
+       }
+      /* --conversion of B* to A* is better than conversion of C* to A*, */
+      else if (distt == 0)
+       {
+         if (distf > 0)
+           return 1;
+         else if (distf < 0)
+           return -1;
+       }
+    }
+  else if (TREE_CODE (TREE_TYPE (main1)) == POINTER_TYPE
+          || TYPE_PTRMEMFUNC_P (TREE_TYPE (main1)))
+    {
+      if (TREE_TYPE (main1) == TREE_TYPE (main2))
+       return compare_qual (ics1, ics2);
+
+#if 0 /* This is now handled by making identity better than anything else.  */
+      /* existing practice, not WP-endorsed: const char * -> const char *
+        is better than char * -> const char *.  (jason 6/29/96) */
+      if (TREE_TYPE (ics1) == TREE_TYPE (ics2))
+       return -compare_qual (main1, main2);
+#endif
+    }
+
+  return 0;
+}
+
+/* The source type for this standard conversion sequence.  */
+
+static tree
+source_type (t)
+     tree t;
+{
+  for (;; t = TREE_OPERAND (t, 0))
+    {
+      if (TREE_CODE (t) == USER_CONV
+         || TREE_CODE (t) == AMBIG_CONV
+         || TREE_CODE (t) == IDENTITY_CONV)
+       return TREE_TYPE (t);
+    }
+  my_friendly_abort (1823);
+}
+
+/* Compare two candidates for overloading as described in
+   [over.match.best].  Return values:
+
+      1: cand1 is better than cand2
+     -1: cand2 is better than cand1
+      0: cand1 and cand2 are indistinguishable */
+
+static int
+joust (cand1, cand2)
+     struct z_candidate *cand1, *cand2;
+{
+  int winner = 0;
+  int i, off1 = 0, off2 = 0, len;
+
+  /* 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;
+
+  /* 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 */
+
+  /* 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))
+       {
+         off1 = 1;
+         --len;
+       }
+      else
+       my_friendly_abort (42);
+    }
+
+  for (i = 0; i < len; ++i)
+    {
+      tree t1 = TREE_VEC_ELT (cand1->convs, i+off1);
+      tree t2 = TREE_VEC_ELT (cand2->convs, i+off2);
+      int comp = compare_ics (t1, t2);
+
+      if (comp != 0)
+       {
+#if 0 /* move this warning to tourney.  */
+         if (warn_sign_promo
+             && ICS_RANK (t1) + ICS_RANK (t2) == STD_RANK + PROMO_RANK
+             && TREE_CODE (t1) == STD_CONV
+             && TREE_CODE (t2) == STD_CONV
+             && TREE_CODE (TREE_TYPE (t1)) == INTEGER_TYPE
+             && TREE_CODE (TREE_TYPE (t2)) == INTEGER_TYPE
+             && (TYPE_PRECISION (TREE_TYPE (t1))
+                 == TYPE_PRECISION (TREE_TYPE (t2)))
+             && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (t1, 0)))
+                 || (TREE_CODE (TREE_TYPE (TREE_OPERAND (t1, 0)))
+                     == ENUMERAL_TYPE)))
+           {
+             tree type = TREE_TYPE (TREE_OPERAND (t1, 0));
+             tree type1, type2;
+             if (comp > 0)
+               type1 = TREE_TYPE (t1), type2 = TREE_TYPE (t2);
+             else
+               type1 = TREE_TYPE (t2), type2 = TREE_TYPE (t1);
+
+             cp_warning ("passing `%T' chooses `%T' over `%T'",
+                         type, type1, type2);
+             cp_warning ("  in call to `%D'", DECL_NAME (cand1->fn));
+           }
+#endif
+
+         if (winner && comp != winner)
+           {
+             winner = 0;
+             goto tweak;
+           }
+         winner = comp;
+       }
+    }
+
+#if 0 /* move this warning to tourney.  */
+  /* warn about confusing overload resolution */
+  if (winner && cand1->second_conv
+      && ! DECL_CONSTRUCTOR_P (cand1->fn)
+      && ! DECL_CONSTRUCTOR_P (cand2->fn))
+    {
+      int comp = compare_ics (cand1->second_conv, cand2->second_conv);
+      if (comp && comp != winner)
+       {
+         struct z_candidate *w, *l;
+         if (winner == 1)
+           w = cand1, l = cand2;
+         else
+           w = cand2, l = cand1;
+         cp_warning ("choosing `%D' over `%D'", w->fn, l->fn);
+         cp_warning ("  for conversion from `%T' to `%T'",
+                     TREE_TYPE (source_type (TREE_VEC_ELT (w->convs, 0))),
+                     TREE_TYPE (w->second_conv));
+         cp_warning ("  because conversion sequence for `this' argument is better");
+       }
+    }
+#endif
+
+  if (winner)
+    return winner;
+
+  /* or, if not that,
+     F1 is a non-template function and F2 is a template function */
+
+  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
+        Integer a, b; test ? a : b; is ambiguous, since there's a builtin
+        that takes references and another that takes values.  */
+      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)));
+
+         if (comptypes (t1, t2, 1))
+           {
+             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;
+           }
+       }
+    }
+
+tweak:
+
+  /* Extension: If the worst conversion for one candidate is worse than the
+     worst conversion for the other, take the first.  */
+  if (! winner && ! pedantic)
+    {
+      int rank1 = IDENTITY_RANK, rank2 = IDENTITY_RANK;
+
+      for (i = 0; i < len; ++i)
+       {
+         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
+       {
+         if (fate == 0)
+           {
+             champ = challenger->next;
+             if (champ == 0)
+               return 0;
+           }
+         else
+           champ = challenger;
+
+         challenger = champ->next;
+       }
+    }
+
+  /* Make sure the champ is better than all the candidates it hasn't yet
+     been compared to.  This may do one more comparison than necessary.  Oh
+     well.  */
+
+  for (challenger = candidates; challenger != champ;
+       challenger = challenger->next)
+    {
+      fate = joust (champ, challenger);
+      if (fate != 1)
+       return 0;
+    }
+
+  return champ;
+}
+
+int
+can_convert (to, from)
+     tree to, from;
+{
+  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);
+    }
+}
+
+int
+can_convert_arg (to, from, arg)
+     tree to, from, arg;
+{
+  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);
+    }
+}