]> gcc.gnu.org Git - gcc.git/commitdiff
87th Cygnus<->FSF quick merge
authorMike Stump <mrs@gcc.gnu.org>
Thu, 8 Aug 1996 22:54:56 +0000 (22:54 +0000)
committerMike Stump <mrs@gcc.gnu.org>
Thu, 8 Aug 1996 22:54:56 +0000 (22:54 +0000)
From-SVN: r12606

18 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/except.c
gcc/cp/gxx.gperf
gcc/cp/hash.h
gcc/cp/init.c
gcc/cp/lex.c
gcc/cp/lex.h
gcc/cp/method.c
gcc/cp/pt.c
gcc/cp/search.c
gcc/cp/typeck.c

index 089537308e758ab50a944e97a54afa6661c2a389..f65965add97c51ff3d420ff081c9e3a5479d3207 100644 (file)
@@ -3,8 +3,173 @@ Thu Aug  8 17:48:16 1996  Michael Meissner  <meissner@tiktok.cygnus.com>
        * decl2.c (import_export_vtable): Delete code that disabled vtable
        heuristic on systems with ASM_OUTPUT_EXTERNAL.
 
+Wed Aug  7 12:44:11 1996  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * typeck.c (build_x_function_call): Handle static call context
+       better.
+
+       * decl.c (finish_function): Set the DECL_CONTEXT of the result to
+       the function, not its outer block.
+
+       * call.c (build_field_call): Pass fields on to build_opfncall
+       regardless of TYPE_OVERLOADS_CALL_EXPR.
+       (build_method_call): Pass on to build_new_method_call sooner.
+
+       * typeck.c (build_ptrmemfunc): Just return what instantiate_type
+       gives us.
+       * class.c (instantiate_type): Don't put a POINTER_TYPE to
+       METHOD_TYPE on an expression.  Also make a copy of rhs instead of
+       modifying it.
+
+Tue Aug  6 12:58:46 1996  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * call.c (compare_ics): Handle qual_conv after lvalue_conv.
+       (add_builtin_candidate): Don't take enums for ++.
+       (build_new_method_call): Handle non-aggregates and field calls.
+       Move new overloading code from...
+       * cvt.c: Here.
+
+       * decl.c (grokparms): Don't check default args in templates.
+
+Mon Aug  5 17:17:06 1996  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * cvt.c (build_new_op): Fix args to build_unary_op.
+       (add_builtin_candidates): Don't call type_promotes_to on float.
+
+       * decl.c (grokparms): Check the type of the default arg.
+
+       * cvt.c (build_new_op): Pass non-overloaded cases on rather than
+       returning NULL_TREE.
+
+       * typeck.c (build_x_binary_op): Avoid doing extra work.
+       (build_x_unary_op): Ditto.
+       (build_x_conditional_expr): Ditto.
+       * cvt.c (build_over_call): Return.
+       (add_builtin_candidate): Fix MEMBER_REF.
+       (build_new_op): Ditto.
+
+Mon Aug  5 17:07:47 1996  Mike Stump  <mrs@cygnus.com>
+
+       * method.c (build_overload_name): Put bug fix into code but leave
+       disabled for now so we can be bug compatible with older releases
+       that do repeats incorrectly.  In the future, we can enable it.
+
+Mon Aug  5 13:46:28 1996  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * cvt.c (convert_like): Don't call build_cplus_new twice.
+
+       * call.c, cp-tree.h, cvt.c, decl2.c, init.c, method.c, pt.c, typeck.c:
+       Control new overloading code with -fansi-overloading.
+
+Sun Aug  4 15:29:11 1996  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * cvt.c (build_over_call): Call build_cplus_new.
+       * call.c (build_method_call): Ditto.
+       * typeck.c (build_function_call_real): Ditto.
+       (build_conditional_expr): If both operands are TARGET_EXPRs, wrap
+       the COND_EXPR in a TARGET_EXPR so they use the same slot.
+
+       * cvt.c (build_up_reference): Propagate INDIRECT_BIND to 
+       recursive calls.
+       * typeck.c (complete_type): Propagate
+       TYPE_NEEDS_{CONSTRUCTING,DESTRUCTOR}.
+
+Sat Aug  3 14:05:07 1996  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * cvt.c (joust): More ?: kludging.  Sigh.
+       (build_over_call): Don't try to synthesize global fns.
+
+       * search.c (lookup_conversions): Use binfo marking.
+
+Sat Aug  3 12:33:42 1996  Bob Manson  <manson@charmed.cygnus.com>
+
+       * search.c (build_mi_matrix): Use the correct value of cid
+       when determining the new mi_size.
+
+Sat Aug  3 01:27:41 1996  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * cvt.c (add_builtin_candidates): Do consider type conversion ops
+       for the first parms of += et al.
+       (strip_top_quals): New fn.
+       (reference_binding): Use it instead of TYPE_MAIN_VARIANT.
+       (implicit_conversion): Ditto.
+       (add_builtin_candidates): Be careful about arrays.
+       (build_new_method_call): Handle vtable optimization.
+
+Fri Aug  2 01:26:59 1996  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * cp-tree.h (LOOKUP_NO_TEMP_BIND): New flag.
+       * cvt.c (reference_binding): Use it.
+       (implicit_conversion): Use it.
+       (add_builtin_candidate, COND_EXPR): Use it.
+
+       * cvt.c (build_new_function_call): Check for error args.
+
+       * typeck.c (comptypes): Just check DERIVED_FROM_P, not UNIQUELY.
+
+       * gxx.gperf: Add __null.
+       * hash.h: Regenerate.
+       * lex.h: Add RID_NULL.
+       * lex.c (init_lex): Create null_pointer_node here, stick it in
+       RID_NULL.
+       * decl.c (init_decl_processing): Still set its type here.
+       * cvt.c (cp_convert_to_pointer): Don't produce null_pointer_node.
+       (convert_to_pointer_force): Ditto.
+       (null_ptr_cst_p): Check for null_pointer_node; only accept (void*)0
+       if (! pedantic).
+       * call.c (convert_harshness): Use null_ptr_cst_p.
+       * typeck.c (convert_for_assignment): Ditto.  Don't produce
+       null_pointer_node.
+
+       * error.c (args_as_string): Handle lists of actual args, too.
+       * cvt.c (null_ptr_cst): Support (void*)0 for now.
+       (build_user_type_conversion_1): Improve diagnostics.
+       (build_new_function_call): Likewise.
+       (build_object_call): Likewise.
+       (build_new_method_call): Likewise.  Move call before def diagnostic...
+       (build_over_call): Here.
+
+       * cvt.c (build_new_method_call): Don't complain about no match if
+       LOOKUP_SPECULATIVELY.
+       (build_over_call): Fix 'this' for virtual fn.
+       (build_new_method_call): Add diagnostic.
+
+Thu Aug  1 16:45:09 1996  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * cvt.c (add_function_candidate): Expect 'this' and 'in_chrg' for
+       constructors to be passed in.
+       (build_over_call): Likewise.
+       (build_user_type_conversion_1): Pass them in.
+       (convert_like): Likewise.
+       (build_object_call): Handle overloaded conversions.
+       (build_over_call): Pass the right args to build_vfn_ref.
+       (standard_conversion): Fix pmf convs.
+       (joust): Handle comparing statics and non-statics.
+       (build_new_method_call): New fn.
+       * call.c (build_method_call): Call it if NEW_OVER.
+
+Thu Aug  1 16:06:14 1996  Mike Stump  <mrs@cygnus.com>
+
+       * lex.c (do_identifier): Don't use %O on IDENTIFIER_OPNAME_Ps, use
+       %D instead.
+
+Thu Aug  1 15:24:02 1996  Mike Stump  <mrs@cygnus.com>
+
+       * except.c (expand_throw): Use maybe_build_cleanup_and_delete
+       instead of just maybe_build_cleanup so that we deallocate the
+       thrown object.
+
+Thu Aug  1 15:18:00 1996  Brendan Kehoe  <brendan@lisa.cygnus.com>
+
+       * decl2.c (finish_prevtable_vardecl): Make non-static for pt.c's use.
+       * cp-tree.h (finish_prevtable_vardecl): Add decl.
+
 Thu Aug  1 11:53:51 1996  Bob Manson  <manson@charmed.cygnus.com>
 
+       * pt.c (instantiate_class_template): Call complete_type. Also, if
+       we're at the end of the file and we just instantiated a template
+       class with a vtable, call finish_prevtable_vardecl.
+
        * error.c (dump_decl): Don't explode (or explode more gracefully
        as appropriate) if the object being dumped has a null type.
        (dump_expr): Ditto.
index 741e703c1bb524dd18d7eafd0d92de4287bb8605..b81f35f21b3ffc333989a75ec3929060c49cd997 100644 (file)
@@ -508,7 +508,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);
@@ -1214,7 +1214,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)
@@ -1245,7 +1246,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);
@@ -1759,6 +1761,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;
     
@@ -2621,6 +2626,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;
 }
@@ -2903,3 +2910,2661 @@ 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 ICS_RANK(NODE)                         \
+  (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 USER_CONV_FN(NODE) TREE_OPERAND (NODE, 1)
+
+static struct z_candidate * build_user_type_conversion_1 ();
+static tree convert_like ();
+static tree build_over_call ();
+static struct z_candidate * tourney ();
+static void enforce_access ();
+
+int
+null_ptr_cst_p (t)
+     tree t;
+{
+  if (t == null_pointer_node
+      || integer_zerop (t) && INTEGRAL_TYPE_P (TREE_TYPE (t)))
+    return 1;
+  /* Remove this eventually.  */
+  if (! pedantic && TREE_TYPE (t) == ptr_type_node && integer_zerop (t))
+    return 1;
+  return 0;
+}
+
+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 LVALUE_CONV:
+    case QUAL_CONV:
+    case RVALUE_CONV:
+      if (rank < EXACT_RANK)
+       rank = EXACT_RANK;
+
+    default:
+      break;
+    }
+  ICS_STD_RANK (t) = rank;
+  ICS_USER_FLAG (t) = ICS_USER_FLAG (from);
+  return t;
+}
+
+tree
+non_reference (t)
+     tree t;
+{
+  if (TREE_CODE (t) == REFERENCE_TYPE)
+    t = TREE_TYPE (t);
+  return 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.  */
+
+tree
+standard_conversion (to, from, expr)
+     tree to, from, expr;
+{
+  enum tree_code fcode, tcode;
+  tree conv;
+
+  fcode = TREE_CODE (from);
+  tcode = TREE_CODE (to);
+
+  conv = build1 (IDENTITY_CONV, from, expr);
+
+  if (from == to)
+    return conv;
+
+  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);
+    }
+
+  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));
+
+      if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (from)),
+                    TYPE_MAIN_VARIANT (TREE_TYPE (to)), 1))
+       /* OK for now */;
+      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))));
+         conv = 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);
+             conv = build_conv (PMEM_CONV, from, conv);
+           }
+         else
+           return 0;
+       }
+      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);
+             conv = build_conv (PTR_CONV, from, conv);
+           }
+         else
+           return 0;
+       }
+      else
+       return 0;
+
+      if (! comptypes (from, to, 1))
+       {
+         if (! comp_ptr_ttypes (TREE_TYPE (to), TREE_TYPE (from)))
+           return 0;
+
+         from = to;
+         conv = build_conv (QUAL_CONV, from, conv);
+       }
+    }
+  else if (TYPE_PTRMEMFUNC_P (to) && TYPE_PTRMEMFUNC_P (from))
+    {
+      tree fromfn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from));
+      tree tofn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to));
+      tree fbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fromfn)));
+      tree tbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (tofn)));
+
+      if (! DERIVED_FROM_P (fbase, tbase)
+         || ! comptypes (TREE_TYPE (fromfn), TREE_TYPE (tofn), 1)
+         || ! compparms (TREE_CHAIN (TYPE_ARG_TYPES (fromfn)),
+                         TREE_CHAIN (TYPE_ARG_TYPES (tofn)), 1)
+         || TYPE_READONLY (fbase) != TYPE_READONLY (tbase)
+         || TYPE_VOLATILE (fbase) != TYPE_VOLATILE (tbase))
+       return 0;
+
+      from = cp_build_type_variant (tbase, TYPE_READONLY (fbase),
+                                   TYPE_VOLATILE (fbase));
+      from = build_cplus_method_type (from, TREE_TYPE (fromfn),
+                                     TREE_CHAIN (TYPE_ARG_TYPES (fromfn)));
+      from = build_ptrmemfunc_type (build_pointer_type (from));
+      conv = build_conv (PMEM_CONV, from, conv);
+    }
+  else if (tcode == BOOLEAN_TYPE)
+    {
+      if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE
+            || fcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (from)))
+       return 0;
+
+      conv = build_conv (STD_CONV, to, conv);
+      if (fcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (from)
+         && ICS_STD_RANK (conv) < PBOOL_RANK)
+       ICS_STD_RANK (conv) = PBOOL_RANK;
+    }
+  /* We don't check for ENUMERAL_TYPE here because there are no standard
+     conversions to enum type.  */
+  else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
+          || tcode == REAL_TYPE)
+    {
+      if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE))
+       return 0;
+      conv = build_conv (STD_CONV, to, conv);
+
+      /* Give this a better rank if it's a promotion.  */
+      if (to == type_promotes_to (from)
+         && ICS_STD_RANK (TREE_OPERAND (conv, 0)) <= PROMO_RANK)
+       ICS_STD_RANK (conv) = PROMO_RANK;
+    }
+  else if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
+          && DERIVED_FROM_P (to, from))
+    conv = build_conv (BASE_CONV, to, conv);
+  else
+    return 0;
+
+  return conv;
+}
+
+tree
+strip_top_quals (t)
+     tree t;
+{
+  if (TREE_CODE (t) == ARRAY_TYPE)
+    return t;
+  return TYPE_MAIN_VARIANT (t);
+}
+
+/* Returns the conversion path from type FROM to reference type TO for
+   purposes of reference binding.  For lvalue binding, either pass a
+   reference type to FROM or an lvalue expression to EXPR.
+
+   Currently does not distinguish in the generated trees between binding to
+   an lvalue and a temporary.  Should it?  */
+
+tree
+reference_binding (rto, from, expr, flags)
+     tree rto, from, expr;
+     int flags;
+{
+  tree conv;
+  int lvalue = 1;
+  tree to = TREE_TYPE (rto);
+
+  if (TREE_CODE (from) == REFERENCE_TYPE)
+    from = TREE_TYPE (from);
+  else if (! expr || ! real_lvalue_p (expr))
+    lvalue = 0;
+
+  if (lvalue
+      && TYPE_READONLY (to) >= TYPE_READONLY (from)
+      && TYPE_VOLATILE (to) >= TYPE_VOLATILE (from))
+    {
+      conv = build1 (IDENTITY_CONV, from, expr);
+
+      if (TYPE_MAIN_VARIANT (to) == TYPE_MAIN_VARIANT (from))
+       conv = build_conv (REF_BIND, rto, conv);
+      else if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
+              && DERIVED_FROM_P (to, from))
+       {
+         conv = build_conv (REF_BIND, rto, conv);
+         ICS_STD_RANK (conv) = STD_RANK;
+       }
+      else
+       conv = NULL_TREE;
+    }
+  else
+    conv = NULL_TREE;
+
+  if (! conv && TYPE_READONLY (to) && ! TYPE_VOLATILE (to)
+      && (flags & LOOKUP_NO_TEMP_BIND) == 0)
+    {
+      conv = standard_conversion
+       (TYPE_MAIN_VARIANT (to), strip_top_quals (from), expr);
+      if (conv)
+       {
+         conv = build_conv (REF_BIND, rto, conv);
+
+         /* Bind directly to a base subobject of a class rvalue.  */
+         if (TREE_CODE (TREE_OPERAND (conv, 0)) == BASE_CONV)
+           TREE_OPERAND (conv, 0) = TREE_OPERAND (TREE_OPERAND (conv, 0), 0);
+       }
+    }
+
+  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.  */
+
+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
+      (TYPE_MAIN_VARIANT (non_reference (to)),
+       strip_top_quals (non_reference (from)), expr);
+
+  if (conv)
+    {
+      if (TREE_CODE (conv) == IDENTITY_CONV && IS_AGGR_TYPE (to)
+         && (TREE_CODE (from) == REFERENCE_TYPE || (expr && real_lvalue_p (expr))))
+       conv = build_conv (RVALUE_CONV, to, conv);
+    }
+  else if ((IS_AGGR_TYPE (non_reference (from))
+           || IS_AGGR_TYPE (non_reference (to)))
+          && (flags & LOOKUP_NO_CONVERSION) == 0)
+    {
+      if (TREE_CODE (to) == REFERENCE_TYPE
+         && TYPE_READONLY (TREE_TYPE (to))
+         && ! TYPE_VOLATILE (TREE_TYPE (to))
+         && (flags & LOOKUP_NO_TEMP_BIND) == 0)
+       {
+         cand = build_user_type_conversion_1
+           (TYPE_MAIN_VARIANT (TREE_TYPE (to)), expr, LOOKUP_ONLYCONVERTING);
+         if (cand)
+           conv = build_conv (REF_BIND, to, cand->second_conv);
+       }
+      else
+       {
+         cand = build_user_type_conversion_1
+           (to, expr, LOOKUP_ONLYCONVERTING);
+         if (cand)
+           conv = 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_tree_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;
+       }
+
+      TREE_VEC_ELT (convs, i) = t;
+      if (! t)
+       break;
+
+      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 *) oballoc (sizeof (struct z_candidate));
+
+  cand->fn = fn;
+  cand->convs = convs;
+  cand->second_conv = NULL_TREE;
+  cand->viable = viable;
+  cand->basetype_path = NULL_TREE;
+  cand->template = NULL_TREE;
+  cand->next = candidates;
+
+  return cand;
+}
+
+/* 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_tree_vec (len);
+  tree parmnode = parmlist;
+  tree argnode = arglist;
+  int viable = 1;
+  struct z_candidate *cand;
+  int flags = LOOKUP_NORMAL;
+
+  for (i = 0; i < len; ++i)
+    {
+      tree arg = i == 0 ? obj : TREE_VALUE (argnode);
+      tree argtype = TREE_TYPE (arg);
+      tree t;
+
+      argtype = cp_build_type_variant
+       (argtype, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
+
+      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 (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 *) oballoc (sizeof (struct z_candidate));
+
+  cand->fn = fn;
+  cand->convs = convs;
+  cand->second_conv = NULL_TREE;
+  cand->viable = viable;
+  cand->basetype_path = NULL_TREE;
+  cand->template = NULL_TREE;
+  cand->next = candidates;
+
+  return cand;
+}
+
+int
+ptr_complete_ob (t)
+     tree t;
+{
+  return (TREE_CODE (t) == POINTER_TYPE
+         && TREE_CODE (TREE_TYPE (t)) != OFFSET_TYPE
+         && TREE_CODE (TREE_TYPE (t)) != FUNCTION_TYPE
+         && TREE_CODE (TREE_TYPE (t)) != VOID_TYPE
+         && TYPE_SIZE (complete_type (TREE_TYPE (t))) != NULL_TREE);
+}
+
+#define TYPE_PTRMEM_P(NODE)                                    \
+  (TREE_CODE (NODE) == POINTER_TYPE                            \
+   && TREE_CODE (TREE_TYPE (NODE)) == OFFSET_TYPE)
+#define TYPE_PTR_P(NODE)                               \
+  (TREE_CODE (NODE) == POINTER_TYPE                    \
+   && TREE_CODE (TREE_TYPE (NODE)) != OFFSET_TYPE)
+#define TYPE_PTROB_P(NODE)                                             \
+  (TYPE_PTR_P (NODE) && TREE_CODE (TREE_TYPE (NODE)) != FUNCTION_TYPE  \
+   && TREE_CODE (TREE_TYPE (NODE)) != VOID_TYPE)
+
+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_tree_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);
+       }
+      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 *) oballoc (sizeof (struct z_candidate));
+
+  cand->fn = fnname;
+  cand->convs = convs;
+  cand->second_conv = NULL_TREE;
+  cand->viable = viable;
+  cand->basetype_path = NULL_TREE;
+  cand->template = NULL_TREE;
+  cand->next = candidates;
+
+  return cand;
+}
+
+int
+is_complete (t)
+     tree t;
+{
+  return TYPE_SIZE (complete_type (t)) != NULL_TREE;
+}
+
+/* Create any builtin operator overload candidates for the operator in
+   question given the converted operand types TYPE1 and TYPE2.  The other
+   args are passed through from add_builtin_candidates to
+   build_builtin_candidate.  */
+
+static struct z_candidate *
+add_builtin_candidate (candidates, code, code2, fnname, type1, type2,
+                      args, argtypes, flags)
+     struct z_candidate *candidates;
+     enum tree_code code, code2;
+     tree fnname, type1, type2, *args, *argtypes;
+     int flags;
+{
+  switch (code)
+    {
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      args[1] = integer_zero_node;
+      type2 = integer_type_node;
+    }
+
+  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)
+         || ptr_complete_ob (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
+         && (ptr_complete_ob (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 (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 (ptr_complete_ob (type1) && ptr_complete_ob (type2))
+       break;
+      if (ptr_complete_ob (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) && ptr_complete_ob (type2))
+       {
+         type1 = ptrdiff_type_node;
+         break;
+       }
+      if (ptr_complete_ob (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 (ptr_complete_ob (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.  */
+      flags |= LOOKUP_NO_TEMP_BIND;
+      if (TREE_CODE (type1) == ENUMERAL_TYPE && type1 == type2)
+       break;
+      else if (TREE_CODE (type1) == ENUMERAL_TYPE
+              || TREE_CODE (type2) == ENUMERAL_TYPE)
+       return candidates;
+      if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+       break;
+      if (TREE_CODE (type1) == TREE_CODE (type2)
+         && (TREE_CODE (type1) == REFERENCE_TYPE
+             || TREE_CODE (type1) == POINTER_TYPE
+             || TYPE_PTRMEMFUNC_P (type1)
+             || IS_AGGR_TYPE (type1)))
+       break;
+      if (TREE_CODE (type1) == REFERENCE_TYPE
+         || TREE_CODE (type2) == REFERENCE_TYPE)
+       return candidates;
+      if (((TYPE_PTRMEMFUNC_P (type1) || TREE_CODE (type1) == POINTER_TYPE)
+          && null_ptr_cst_p (args[1]))
+         || IS_AGGR_TYPE (type1))
+       {
+         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]  = cp_build_type_variant
+         (TREE_TYPE (args[i]), TREE_READONLY (args[i]),
+          TREE_THIS_VOLATILE (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] = tree_cons
+                 (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+
+             types[i] = tree_cons
+               (NULL_TREE, TYPE_MAIN_VARIANT (argtypes[i]), types[i]);
+           }
+               
+         else 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] = 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] = 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] = tree_cons (NULL_TREE, type, types[i]);
+           }
+       }
+      else
+       {
+         if (code == COND_EXPR && real_lvalue_p (args[i]))
+           types[i] = tree_cons
+             (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+         type = non_reference (argtypes[i]);
+         if (i != 0 || ! ref1)
+           {
+             type = TYPE_MAIN_VARIANT (type_decays_to (type));
+             if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
+               types[i] = tree_cons (NULL_TREE, type, types[i]);
+             if (INTEGRAL_TYPE_P (type))
+               type = type_promotes_to (type);
+           }
+         types[i] = tree_cons (NULL_TREE, type, types[i]);
+       }
+    }
+
+  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;
+}
+
+static struct z_candidate *
+add_template_candidate (candidates, tmpl, arglist, flags)
+     struct z_candidate *candidates;
+     tree tmpl, arglist;
+     int flags;
+{
+  int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl));
+  tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
+  struct z_candidate *cand;
+  int i, dummy; 
+  tree fn;
+
+  i = type_unification (DECL_TEMPLATE_PARMS (tmpl), targs,
+                       TYPE_ARG_TYPES (TREE_TYPE (tmpl)),
+                       arglist, &dummy, 0, 0);
+  if (i != 0)
+    return candidates;
+
+  fn = instantiate_template (tmpl, targs);
+  if (fn == error_mark_node)
+    return candidates;
+
+  cand = add_function_candidate (candidates, fn, arglist, flags);
+  cand->template = DECL_TEMPLATE_INFO (fn);
+  return cand;
+}
+
+static int
+any_viable (cands)
+     struct z_candidate *cands;
+{
+  for (; cands; cands = cands->next)
+    if (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 ((*p)->viable)
+       p = &((*p)->next);
+      else
+       *p = (*p)->next;
+    }
+
+  return cands;
+}
+
+tree
+build_this (obj)
+     tree obj;
+{
+  /* Fix this to work on non-lvalues.  */
+  return build_unary_op (ADDR_EXPR, obj, 0);
+}
+
+static void
+print_z_candidates (candidates)
+     struct z_candidate *candidates;
+{
+  if (! candidates)
+    return;
+
+  if (TREE_CODE (candidates->fn) == IDENTIFIER_NODE)
+    {
+      if (candidates->fn == ansi_opname [COND_EXPR])
+       cp_error ("candidates are: %D(%T, %T, %T) <builtin>", 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 ("candidates are: %D(%T, %T) <builtin>", candidates->fn,
+                 TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+                 TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)));
+      else
+       cp_error ("candidates are: %D(%T) <builtin>", candidates->fn,
+                 TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)));
+    }
+  else
+    cp_error_at ("candidates are: %D", candidates->fn);
+  candidates = candidates->next;
+
+  for (; candidates; candidates = candidates->next)
+    {
+      if (TREE_CODE (candidates->fn) == IDENTIFIER_NODE)
+       {
+         if (candidates->fn == ansi_opname [COND_EXPR])
+           cp_error ("                %D(%T, %T, %T) <builtin>",
+                     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 ("                %D(%T, %T) <builtin>", candidates->fn,
+                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)));
+         else
+           cp_error ("                %D(%T) <builtin>", candidates->fn,
+                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)));
+       }
+      else
+       cp_error_at ("                %D", candidates->fn);
+    }
+}
+
+/* Returns the best overload candidate to perform the requested
+   conversion.  */
+
+static struct z_candidate *
+build_user_type_conversion_1 (totype, expr, flags)
+     tree totype, expr;
+     int flags;
+{
+  struct z_candidate *candidates, *cand;
+  tree fromtype = TREE_TYPE (expr);
+  tree ctors = NULL_TREE, convs = NULL_TREE, *p;
+  tree args;
+
+  if (IS_AGGR_TYPE (totype))
+    ctors = lookup_fnfields (TYPE_BINFO (totype), ctor_identifier, 0);
+  if (IS_AGGR_TYPE (fromtype)
+      && (! IS_AGGR_TYPE (totype) || ! DERIVED_FROM_P (totype, fromtype)))
+    convs = lookup_conversions (fromtype);
+
+  candidates = 0;
+  flags |= LOOKUP_NO_CONVERSION;
+
+  if (ctors)
+    {
+      tree t = build_int_2 (0, 0);
+      TREE_TYPE (t) = build_pointer_type (totype);
+      args = build_tree_list (NULL_TREE, expr);
+      if (TYPE_USES_VIRTUAL_BASECLASSES (totype))
+       args = tree_cons (NULL_TREE, integer_one_node, args);
+      args = tree_cons (NULL_TREE, t, args);
+
+      ctors = TREE_VALUE (ctors);
+    }
+  for (; ctors; ctors = DECL_CHAIN (ctors))
+    {
+      if ((flags & LOOKUP_ONLYCONVERTING) && DECL_NONCONVERTING_P (ctors))
+       continue;
+
+      candidates = add_function_candidate (candidates, ctors, args, flags);
+      candidates->second_conv = build1 (IDENTITY_CONV, totype, NULL_TREE);
+      candidates->basetype_path = TYPE_BINFO (totype);
+    }
+
+  if (convs)
+    args = build_tree_list (NULL_TREE, build_this (expr));
+
+  for (; convs; convs = TREE_CHAIN (convs))
+    {
+      tree fn = TREE_VALUE (convs);
+      tree ics = implicit_conversion
+       (totype, TREE_TYPE (TREE_TYPE (fn)), 0, LOOKUP_NO_CONVERSION);
+      if (ics)
+       for (; fn; fn = DECL_CHAIN (fn))
+         {
+           candidates = add_function_candidate (candidates, fn, args, flags);
+           candidates->second_conv = ics;
+           candidates->basetype_path = TREE_PURPOSE (convs);
+         }
+    }
+
+  if (! 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, totype);
+
+  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;
+
+      return cand;
+    }
+
+  for (p = &(cand->second_conv); TREE_CODE (*p) != IDENTITY_CONV; )
+    p = &(TREE_OPERAND (*p, 0));
+
+  *p = build
+    (USER_CONV,
+     (DECL_CONSTRUCTOR_P (cand->fn)
+      ? totype : non_reference (TREE_TYPE (TREE_TYPE (cand->fn)))),
+     NULL_TREE, cand->fn, cand->convs, cand->basetype_path);
+  ICS_USER_FLAG (cand->second_conv) = 1;
+
+  return cand;
+}
+
+tree
+build_user_type_conversion (totype, expr, flags)
+     tree totype, expr, flags;
+{
+  struct z_candidate *cand
+    = build_user_type_conversion_1 (totype, expr, flags);
+
+  if (cand)
+    {
+      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;
+}
+
+tree
+build_new_function_call (fn, args, obj)
+     tree fn, args, obj;
+{
+  struct z_candidate *candidates = 0, *cand;
+  if (obj == NULL_TREE && TREE_CODE (fn) == TREE_LIST)
+    {
+      tree t;
+
+      for (t = args; t; t = TREE_CHAIN (t))
+       if (TREE_VALUE (t) == error_mark_node)
+         return error_mark_node;
+       
+      for (t = TREE_VALUE (fn); t; t = DECL_CHAIN (t))
+       {
+         if (TREE_CODE (t) == TEMPLATE_DECL)
+           candidates = add_template_candidate
+             (candidates, t, args, LOOKUP_NORMAL);
+         else
+           candidates = add_function_candidate
+             (candidates, t, args, LOOKUP_NORMAL);
+       }
+
+      if (! any_viable (candidates))
+       {
+         if (candidates && ! candidates->next)
+           return build_function_call (candidates->fn, args);
+         else
+           cp_error ("no matching function for call to `%D (%A)'",
+                     TREE_PURPOSE (fn), args);
+         return error_mark_node;
+       }
+      candidates = splice_viable (candidates);
+      cand = tourney (candidates, NULL_TREE);
+
+      if (cand == 0)
+       {
+         cp_error ("call of overloaded `%D (%A)' is ambiguous",
+                   TREE_PURPOSE (fn), args);
+         print_z_candidates (candidates);
+         return error_mark_node;
+       }
+
+      return build_over_call (cand->fn, cand->convs, args, LOOKUP_NORMAL);
+    }
+
+  return build_function_call (fn, args);
+}
+
+tree
+build_object_call (obj, args)
+     tree obj, args;
+{
+  struct z_candidate *candidates = 0, *cand;
+  tree fns, convs, mem_args, *p;
+  enum tree_code code2 = NOP_EXPR;
+  tree type = TREE_TYPE (obj);
+
+  fns = lookup_fnfields (TYPE_BINFO (type), ansi_opname [CALL_EXPR], 0);
+
+  if (fns)
+    {
+      tree fn = TREE_VALUE (fns);
+      mem_args = tree_cons (NULL_TREE, build_this (obj), args);
+
+      for (; fn; fn = DECL_CHAIN (fn))
+       {
+         candidates = add_function_candidate
+           (candidates, fn, mem_args, LOOKUP_NORMAL);
+         candidates->basetype_path = TREE_PURPOSE (fns);
+       }
+    }
+
+  convs = lookup_conversions (type);
+
+  for (; convs; convs = TREE_CHAIN (convs))
+    {
+      tree fn = TREE_VALUE (convs);
+      tree totype = TREE_TYPE (TREE_TYPE (fn));
+
+      if (TREE_CODE (totype) == POINTER_TYPE
+         && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
+       for (; fn; fn = DECL_CHAIN (fn))
+         {
+           candidates = add_conv_candidate (candidates, fn, obj, args);
+           candidates->basetype_path = TREE_PURPOSE (convs);
+         }
+    }
+
+  if (! any_viable (candidates))
+    {
+      cp_error ("no match for call to `(%T) (%A)", TREE_TYPE (obj), args);
+      print_z_candidates (candidates);
+      return error_mark_node;
+    }
+
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates, NULL_TREE);
+
+  if (cand == 0)
+    {
+      cp_error ("call of `(%T) (%A)' is ambiguous", TREE_TYPE (obj), args);
+      print_z_candidates (candidates);
+      return error_mark_node;
+    }
+
+  if (DECL_NAME (cand->fn) == ansi_opname [CALL_EXPR])
+    return build_over_call (cand->fn, cand->convs, mem_args, LOOKUP_NORMAL);
+
+  obj = convert_like (TREE_VEC_ELT (cand->convs, 0), obj);
+
+  /* FIXME */
+  return build_function_call (obj, args);
+}
+
+static void
+op_error (code, code2, arg1, arg2, arg3, problem)
+     enum tree_code code, code2;
+     tree arg1, arg2, arg3;
+     char *problem;
+{
+  char * opname
+    = (code == MODIFY_EXPR ? assignop_tab [code2] : opname_tab [code]);
+
+  switch (code)
+    {
+    case COND_EXPR:
+      cp_error ("%s for `%T ? %T : %T'", problem,
+               TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3));
+      break;
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      cp_error ("%s for `%T%s'", problem, TREE_TYPE (arg1), opname);
+      break;
+    case ARRAY_REF:
+      cp_error ("%s for `%T[%T]'", problem,
+               TREE_TYPE (arg1), TREE_TYPE (arg2));
+      break;
+    default:
+      if (arg2)
+       cp_error ("%s for `%T %s %T'", problem,
+                 TREE_TYPE (arg1), opname, TREE_TYPE (arg2));
+      else
+       cp_error ("%s for `%s%T'", problem, opname, TREE_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, *p;
+  enum tree_code code2 = NOP_EXPR;
+
+  if (arg1 == error_mark_node)
+    return error_mark_node;
+
+  if (code == MODIFY_EXPR)
+    {
+      code2 = TREE_CODE (arg3);
+      arg3 = NULL_TREE;
+      fnname = ansi_assopname[code2];
+    }
+  else
+    fnname = ansi_opname[code];
+
+  switch (code)
+    {
+    case NEW_EXPR:
+    case VEC_NEW_EXPR:
+      {
+       tree rval;
+
+       arglist = tree_cons (NULL_TREE, arg2, arg3);
+       if (flags & LOOKUP_GLOBAL)
+         return build_new_function_call
+           (lookup_name_nonclass (fnname), arglist, NULL_TREE);
+
+       /* FIXME */
+       rval = build_method_call
+         (build_indirect_ref (build1 (NOP_EXPR, arg1, error_mark_node),
+                              "new"),
+          fnname, arglist, NULL_TREE, flags);
+       if (rval == error_mark_node)
+         /* User might declare fancy operator new, but invoke it
+            like standard one.  */
+         return rval;
+
+       TREE_TYPE (rval) = arg1;
+       TREE_CALLS_NEW (rval) = 1;
+       return rval;
+      }
+
+    case VEC_DELETE_EXPR:
+    case DELETE_EXPR:
+      {
+       tree rval;
+
+       if (flags & LOOKUP_GLOBAL)
+         return build_new_function_call
+           (lookup_name_nonclass (fnname),
+            build_tree_list (NULL_TREE, arg1), NULL_TREE);
+
+       arglist = tree_cons (NULL_TREE, arg1, build_tree_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);
+    }
+
+  /* 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 (! IS_OVERLOAD_TYPE (TREE_TYPE (arg1))
+      && (! arg2 || ! IS_OVERLOAD_TYPE (TREE_TYPE (arg2)))
+      && (! arg3 || ! IS_OVERLOAD_TYPE (TREE_TYPE (arg3))))
+    goto builtin;
+
+  if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
+    arg2 = integer_zero_node;
+
+  fns = lookup_name_nonclass (fnname);
+  /* + Koenig lookup */
+
+  if (arg2 && arg3)
+    arglist = tree_cons (NULL_TREE, arg1, tree_cons
+                     (NULL_TREE, arg2, build_tree_list (NULL_TREE, arg3)));
+  else if (arg2)
+    arglist = tree_cons (NULL_TREE, arg1, build_tree_list (NULL_TREE, arg2));
+  else
+    arglist = build_tree_list (NULL_TREE, arg1);
+
+  if (fns && TREE_CODE (fns) == TREE_LIST)
+    fns = TREE_VALUE (fns);
+  for (; fns; fns = DECL_CHAIN (fns))
+    {
+      if (TREE_CODE (fns) == TEMPLATE_DECL)
+       candidates = add_template_candidate (candidates, fns, arglist, flags);
+      else
+       candidates = add_function_candidate (candidates, fns, arglist, flags);
+    }
+
+  if (IS_AGGR_TYPE (TREE_TYPE (arg1)))
+    fns = lookup_fnfields (TYPE_BINFO (TREE_TYPE (arg1)), fnname, 0);
+  else
+    fns = NULL_TREE;
+
+  if (fns)
+    {
+      tree fn = TREE_VALUE (fns);
+      mem_arglist = tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
+      for (; fn; fn = DECL_CHAIN (fn))
+       {
+         if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+           candidates = add_function_candidate
+             (candidates, fn, mem_arglist, flags);
+         else
+           candidates = add_function_candidate (candidates, fn, arglist, flags);
+         
+         candidates->basetype_path = TREE_PURPOSE (fns);
+       }
+    }
+
+  {
+    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;
+       }
+      if (flags & LOOKUP_COMPLAIN)
+       {
+         op_error (code, code2, arg1, arg2, arg3, "no match");
+         print_z_candidates (candidates);
+       }
+      return error_mark_node;
+    }
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates, NULL_TREE);
+
+  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);
+
+      return build_over_call
+       (cand->fn, cand->convs,
+        TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
+        ? mem_arglist : arglist,
+        LOOKUP_NORMAL);
+    }
+
+  arg1 = convert_from_reference
+    (convert_like (TREE_VEC_ELT (cand->convs, 0), arg1));
+  if (arg2)
+    arg2 = convert_like (TREE_VEC_ELT (cand->convs, 1), arg2);
+  if (arg3)
+    arg3 = convert_like (TREE_VEC_ELT (cand->convs, 2), arg3);
+
+builtin:
+  switch (code)
+    {
+    case MODIFY_EXPR:
+      return build_modify_expr (arg1, code2, arg2);
+
+    case INDIRECT_REF:
+      return build_indirect_ref (arg1, "unary *");
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case GT_EXPR:
+    case LT_EXPR:
+    case GE_EXPR:
+    case LE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case MAX_EXPR:
+    case MIN_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case TRUNC_MOD_EXPR:
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+      return build_binary_op_nodefault (code, arg1, arg2, code);
+
+    case CONVERT_EXPR:
+    case NEGATE_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      return build_unary_op (code, arg1, candidates != 0);
+
+    case ARRAY_REF:
+      return build_array_ref (arg1, arg2);
+
+    case COND_EXPR:
+      return build_conditional_expr (arg1, arg2, arg3);
+
+    case MEMBER_REF:
+      return build_m_component_ref
+       (build_indirect_ref (arg1, NULL_PTR), arg2);
+
+      /* The caller will deal with these.  */
+    case ADDR_EXPR:
+    case COMPONENT_REF:
+    case COMPOUND_EXPR:
+      return NULL_TREE;
+
+    default:
+      my_friendly_abort (367);
+    }
+}
+
+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;
+{
+  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_tree_list (NULL_TREE, expr);
+           if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+             args = tree_cons (NULL_TREE, integer_one_node, args);
+           args = tree_cons (NULL_TREE, t, args);
+         }
+       else
+         args = build_this (expr);
+       expr = build_over_call
+         (TREE_OPERAND (convs, 1), TREE_OPERAND (convs, 2),
+          args, LOOKUP_NORMAL);
+
+       /* If 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);
+      return expr;
+    case AMBIG_CONV:
+      /* Call build_user_type_conversion again for the error.  */
+      return build_user_type_conversion
+       (TREE_TYPE (convs), TREE_OPERAND (convs, 0), LOOKUP_NORMAL);
+    };
+
+  expr = convert_like (TREE_OPERAND (convs, 0), expr);
+  if (expr == error_mark_node)
+    return error_mark_node;
+
+  switch (TREE_CODE (convs))
+    {
+    case BASE_CONV:
+    case RVALUE_CONV:
+      return build_user_type_conversion
+       (TREE_TYPE (convs), expr, LOOKUP_NORMAL);
+    case REF_BIND:
+      return convert_to_reference
+       (TREE_TYPE (convs), expr,
+        CONV_IMPLICIT, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION|INDIRECT_BIND,
+        error_mark_node);
+    case LVALUE_CONV:
+      return decay_conversion (expr);
+    }
+  return cp_convert (TREE_TYPE (convs), expr, CONV_IMPLICIT,
+                    LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
+}
+
+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;
+
+  if (args && TREE_CODE (args) != TREE_LIST)
+    args = build_tree_list (NULL_TREE, args);
+  arg = args;
+
+  /* The implicit parameters to a constructor are not considered by overload
+     resolution, and must be of the proper type.  */
+  if (DECL_CONSTRUCTOR_P (fn))
+    {
+      converted_args = tree_cons (NULL_TREE, TREE_VALUE (arg), converted_args);
+      arg = TREE_CHAIN (arg);
+      parm = TREE_CHAIN (parm);
+      if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+       {
+         converted_args = 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)
+    {
+      converted_args = tree_cons
+       (NULL_TREE, convert_force (TREE_VALUE (parm), TREE_VALUE (arg), CONV_C_CAST),
+        converted_args);
+      parm = TREE_CHAIN (parm);
+      arg = TREE_CHAIN (arg);
+      ++i;
+    }
+
+  for (; conv = TREE_VEC_ELT (convs, i), arg && parm;
+       parm = TREE_CHAIN (parm), arg = TREE_CHAIN (arg), ++i)
+    {
+      tree type = TREE_VALUE (parm);
+      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 = tree_cons (NULL_TREE, val, converted_args);
+    }
+
+  /* Default arguments */
+  for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm))
+    converted_args = tree_cons
+      (NULL_TREE,
+       convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm)),
+       converted_args);
+
+  /* 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 = 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 = tree_cons (NULL_TREE, val, converted_args);
+    }
+
+  converted_args = nreverse (converted_args);
+
+  mark_used (fn);
+  /* Is it a synthesized method that needs to be synthesized?  */
+  if (DECL_ARTIFICIAL (fn) && ! DECL_INITIAL (fn)
+      && DECL_CLASS_CONTEXT (fn)
+      /* Kludge: don't synthesize for default args.  */
+      && current_function_decl)
+    synthesize_method (fn);
+
+  if (pedantic && DECL_THIS_INLINE (fn) && ! DECL_ARTIFICIAL (fn)
+      && ! DECL_INITIAL (fn) && ! DECL_PENDING_INLINE_INFO (fn)
+      && ! (DECL_TEMPLATE_INFO (fn)
+           && TREE_LANG_FLAG_0 (DECL_TEMPLATE_INFO (fn))))
+    cp_warning ("inline function `%#D' called before definition", fn);
+
+  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;
+  if (IS_AGGR_TYPE (TREE_TYPE (fn)))
+    fn = build_cplus_new (TREE_TYPE (fn), fn);
+  return convert_from_reference (require_complete_type (fn));
+}
+
+tree
+build_new_method_call (instance, name, args, basetype_path, flags)
+     tree instance, name, args, basetype_path;
+     int flags;
+{
+  struct z_candidate *candidates = 0, *cand;
+  tree basetype, mem_args, fns, instance_ptr;
+  tree pretty_name;
+
+  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))
+       {
+         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 (basetype_path == NULL_TREE)
+    basetype_path = TYPE_BINFO (basetype);
+
+  if (instance)
+    {
+      instance_ptr = build_this (instance);
+
+      /* XXX this should be handled before we get here.  */
+      fns = build_field_call (basetype_path, instance_ptr, name, args);
+      if (fns)
+       return fns;
+    }
+  else
+    {
+      instance_ptr = build_int_2 (0, 0);
+      TREE_TYPE (instance_ptr) = build_pointer_type (basetype);
+    }
+
+  pretty_name =
+    (name == ctor_identifier ? constructor_name_full (basetype) : name);
+
+  fns = lookup_fnfields (basetype_path, name, 1);
+
+  if (fns == error_mark_node)
+    return error_mark_node;
+  if (fns)
+    {
+      tree t = TREE_VALUE (fns);
+      if (name == ctor_identifier && TYPE_USES_VIRTUAL_BASECLASSES (basetype)
+         && ! (flags & LOOKUP_HAS_IN_CHARGE))
+       {
+         flags |= LOOKUP_HAS_IN_CHARGE;
+         args = tree_cons (NULL_TREE, integer_one_node, args);
+       }
+      mem_args = tree_cons (NULL_TREE, instance_ptr, args);
+      for (; t; t = DECL_CHAIN (t))
+       {
+         /* XXX copy-init should go through build_user_type_conversion.  */
+         if (name == ctor_identifier
+             && (flags & LOOKUP_ONLYCONVERTING)
+             && DECL_NONCONVERTING_P (t))
+           continue;
+         if (TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)
+           candidates = add_function_candidate
+             (candidates, t, mem_args, flags);
+         else
+           candidates = add_function_candidate (candidates, t, args, flags);
+         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, args, TREE_TYPE (TREE_TYPE (instance_ptr)));
+      print_z_candidates (candidates);
+      return error_mark_node;
+    }
+  candidates = splice_viable (candidates);
+  cand = tourney (candidates, NULL_TREE);
+
+  if (cand == 0)
+    {
+      cp_error ("call of overloaded `%D(%A)' is ambiguous");
+      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;
+
+  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);
+
+  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;
+}
+
+/* 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 (ICS_RANK (ics1) > ICS_RANK (ics2))
+    return -1;
+  else if (ICS_RANK (ics1) < ICS_RANK (ics2))
+    return 1;
+
+  /* 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_RANK (ics1) == USER_RANK)
+    {
+      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 (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;
+
+  if (TREE_CODE (main1) != TREE_CODE (main2))
+    return 0;
+
+  if (TREE_CODE (main1) == PTR_CONV || TREE_CODE (main1) == PMEM_CONV
+      || TREE_CODE (main1) == REF_BIND || TREE_CODE (main1) == BASE_CONV)
+    {
+      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 (TYPE_PTRMEMFUNC_FN_TYPE (to1));
+         from1 = TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (from1));
+       }
+      else if (TREE_CODE (main1) != BASE_CONV)
+       {
+         to1 = TREE_TYPE (to1);
+         if (TREE_CODE (main1) != REF_BIND)
+           from1 = TREE_TYPE (from1);
+
+         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 (TYPE_PTRMEMFUNC_FN_TYPE (to2));
+         from2 = TYPE_METHOD_BASETYPE (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;
+}
+
+/* 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;
+
+  /* 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)
+    {
+      int comp = compare_ics (TREE_VEC_ELT (cand1->convs, i+off1),
+                             TREE_VEC_ELT (cand2->convs, i+off2));
+
+      if (comp != 0)
+       {
+         if (winner && comp != winner)
+           return 0;
+         winner = comp;
+       }
+    }
+
+  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 < TREE_VEC_LENGTH (cand1->convs); ++i)
+       if (! comptypes (TREE_TYPE (TREE_VEC_ELT (cand1->convs, i)),
+                        TREE_TYPE (TREE_VEC_ELT (cand2->convs, i)), 1))
+         break;
+      if (i == TREE_VEC_LENGTH (cand1->convs))
+       return 1;
+      /* Kludge around broken overloading rules whereby
+        bool ? void *const & : void *const & is ambiguous.  */
+      if (cand1->fn == ansi_opname[COND_EXPR])
+       {
+         tree c1 = TREE_VEC_ELT (cand1->convs, 1);
+         tree c2 = TREE_VEC_ELT (cand2->convs, 1);
+         tree t1 = strip_top_quals (non_reference (TREE_TYPE (c1)));
+         tree t2 = strip_top_quals (non_reference (TREE_TYPE (c2)));
+
+         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;
+           }
+       }
+    }
+
+  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;
+}
index 01d59247b8c3b9f11e8206e95bb30c5b8d07fa45..676b13633267f06bc0b7024ad275d4987c77497e 100644 (file)
@@ -4841,6 +4841,8 @@ instantiate_type (lhstype, rhs, complain)
   if (TREE_TYPE (rhs) != NULL_TREE && ! (type_unknown_p (rhs)))
     return rhs;
 
+  rhs = copy_node (rhs);
+
   /* This should really only be used when attempting to distinguish
      what sort of a pointer to function we have.  For now, any
      arithmetic operation which is not supported on pointers
@@ -5246,6 +5248,12 @@ instantiate_type (lhstype, rhs, complain)
        TREE_TYPE (rhs) = lhstype;
        TREE_OPERAND (rhs, 0) = fn;
        TREE_CONSTANT (rhs) = staticp (fn);
+       if (TREE_CODE (lhstype) == POINTER_TYPE &&
+           TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE)
+         {
+           build_ptrmemfunc_type (lhstype);
+           rhs = build_ptrmemfunc (lhstype, rhs, 0);
+         }
       }
       return rhs;
 
index 7f6fd80500629a3075d9a7c06870e1bf73432668..19d98689091839a1521a02db5d13d5fedfed9fad 100644 (file)
@@ -295,6 +295,11 @@ extern int flag_elide_constructors;
 
 extern int flag_ansi;
 
+/* Nonzero means do argument matching for overloading according to the
+   ANSI rules, rather than what g++ used to believe to be correct.  */
+
+extern int flag_ansi_overloading;
+
 /* Nonzero means recognize and handle signature language constructs.  */
 
 extern int flag_handle_signatures;
@@ -1841,7 +1846,8 @@ extern tree current_class_type;   /* _TYPE: the type of the current class */
      before LOOKUP_SPECULATIVELY is checked.
    LOOKUP_NO_CONVERSION means that user-defined conversions are not
      permitted.  Built-in conversions are permitted.
-   LOOKUP_DESTRUCTOR means explicit call to destructor.  */
+   LOOKUP_DESTRUCTOR means explicit call to destructor.
+   LOOKUP_NO_TEMP_BIND means temporaries will not be bound to references.  */
 
 #define LOOKUP_PROTECT (1)
 #define LOOKUP_COMPLAIN (2)
@@ -1855,6 +1861,7 @@ extern tree current_class_type;   /* _TYPE: the type of the current class */
 #define INDIRECT_BIND (256)
 #define LOOKUP_NO_CONVERSION (512)
 #define LOOKUP_DESTRUCTOR (512)
+#define LOOKUP_NO_TEMP_BIND (1024)
 
 /* These flags are used by the conversion code.
    CONV_IMPLICIT   :  Perform implicit conversions (standard and user-defined).
@@ -1935,6 +1942,9 @@ extern tree build_scoped_method_call              PROTO((tree, tree, tree, tree));
 extern tree build_method_call                  PROTO((tree, tree, tree, tree, int));
 extern tree build_overload_call_real           PROTO((tree, tree, int, struct candidate *, int));
 extern tree build_overload_call                        PROTO((tree, tree, int));
+extern tree build_new_method_call              PROTO((tree, tree, tree, tree, int));
+extern tree build_new_function_call            PROTO((tree, tree, tree));
+extern tree build_new_op                       PROTO((enum tree_code, int, tree, tree, tree));
 
 /* in class.c */
 extern tree build_vbase_pointer                        PROTO((tree, tree));
@@ -2057,6 +2067,7 @@ extern tree start_method                  PROTO((tree, tree, tree));
 extern tree finish_method                      PROTO((tree));
 extern void hack_incomplete_structures         PROTO((tree));
 extern tree maybe_build_cleanup                        PROTO((tree));
+extern tree maybe_build_cleanup_and_delete     PROTO((tree));
 extern void cplus_expand_expr_stmt             PROTO((tree));
 extern void finish_stmt                                PROTO((void));
 extern void pop_implicit_try_blocks            PROTO((tree));
@@ -2096,6 +2107,7 @@ extern void finish_builtin_type                   PROTO((tree, char *, tree *, int, tree));
 extern tree coerce_new_type                    PROTO((tree));
 extern tree coerce_delete_type                 PROTO((tree));
 extern void import_export_vtable               PROTO((tree, tree, int));
+extern int finish_prevtable_vardecl            PROTO((tree, tree));
 extern int walk_vtables                                PROTO((void (*)(), int (*)()));
 extern void walk_sigtables                     PROTO((void (*)(), void (*)()));
 extern void finish_file                                PROTO((void));
@@ -2330,6 +2342,7 @@ extern void init_search_processing                PROTO((void));
 extern void reinit_search_statistics           PROTO((void));
 extern tree current_scope                      PROTO((void));
 extern tree lookup_conversions                 PROTO((tree));
+extern tree get_template_base                  PROTO((tree, tree));
 
 /* in sig.c */
 extern tree build_signature_pointer_type       PROTO((tree, int, int));
index a4c68e2180b76db37d4bec9a77080f42748d6b56..f92eb1de9eb6298dc1da4a6b889f311df97985a0 100644 (file)
@@ -231,8 +231,6 @@ cp_convert_to_pointer (type, expr)
 
   if (integer_zerop (expr))
     {
-      if (type == TREE_TYPE (null_pointer_node))
-       return null_pointer_node;
       expr = build_int_2 (0, 0);
       TREE_TYPE (expr) = type;
       return expr;
@@ -270,8 +268,6 @@ convert_to_pointer_force (type, expr)
   
   if (integer_zerop (expr))
     {
-      if (type == TREE_TYPE (null_pointer_node))
-       return null_pointer_node;
       expr = build_int_2 (0, 0);
       TREE_TYPE (expr) = type;
       return expr;
@@ -549,7 +545,7 @@ build_up_reference (type, arg, flags, checkconst)
     case COMPOUND_EXPR:
       {
        tree real_reference = build_up_reference (type, TREE_OPERAND (targ, 1),
-                                                 LOOKUP_PROTECT, checkconst);
+                                                 flags, checkconst);
        rval = build (COMPOUND_EXPR, type, TREE_OPERAND (targ, 0), real_reference);
        TREE_CONSTANT (rval) = staticp (TREE_OPERAND (targ, 1));
        return rval;
@@ -561,7 +557,7 @@ build_up_reference (type, arg, flags, checkconst)
     case INIT_EXPR:
       {
        tree real_reference = build_up_reference (type, TREE_OPERAND (targ, 0),
-                                                 LOOKUP_PROTECT, checkconst);
+                                                 flags, checkconst);
        rval = build (COMPOUND_EXPR, type, arg, real_reference);
        TREE_CONSTANT (rval) = staticp (TREE_OPERAND (targ, 0));
        return rval;
@@ -571,9 +567,9 @@ build_up_reference (type, arg, flags, checkconst)
       return build (COND_EXPR, type,
                    TREE_OPERAND (targ, 0),
                    build_up_reference (type, TREE_OPERAND (targ, 1),
-                                       LOOKUP_PROTECT, checkconst),
+                                       flags, checkconst),
                    build_up_reference (type, TREE_OPERAND (targ, 2),
-                                       LOOKUP_PROTECT, checkconst));
+                                       flags, checkconst));
 
       /* Undo the folding...  */
     case MIN_EXPR:
@@ -583,9 +579,9 @@ build_up_reference (type, arg, flags, checkconst)
                           boolean_type_node, TREE_OPERAND (targ, 0),
                           TREE_OPERAND (targ, 1)),
                    build_up_reference (type, TREE_OPERAND (targ, 0),
-                                       LOOKUP_PROTECT, checkconst),
+                                       flags, checkconst),
                    build_up_reference (type, TREE_OPERAND (targ, 1),
-                                       LOOKUP_PROTECT, checkconst));
+                                       flags, checkconst));
 
     case BIND_EXPR:
       arg = TREE_OPERAND (targ, 1);
@@ -716,12 +712,11 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
     {
       /* Look for a user-defined conversion to lvalue that we can use.  */
 
-#ifdef NEW_OVER
-      rval_as_conversion
-       = build_type_conversion (CONVERT_EXPR, reftype, expr, 1);
-#else
-      rval_as_conversion = build_type_conversion (CONVERT_EXPR, type, expr, 1);
-#endif
+      if (flag_ansi_overloading)
+       rval_as_conversion
+         = build_type_conversion (CONVERT_EXPR, reftype, expr, 1);
+      else
+       rval_as_conversion = build_type_conversion (CONVERT_EXPR, type, expr, 1);
 
       if (rval_as_conversion && rval_as_conversion != error_mark_node
          && real_lvalue_p (rval_as_conversion))
@@ -1340,11 +1335,8 @@ cp_convert (type, expr, convtype, flags)
          return conversion;
        }
 
-#ifndef NEW_OVER
-      if (TYPE_HAS_CONSTRUCTOR (complete_type (type)))
-#else
-      if (TYPE_HAS_CONSTRUCTOR (complete_type (type)) && ! conversion)
-#endif
+      if (TYPE_HAS_CONSTRUCTOR (complete_type (type))
+         && (! flag_ansi_overloading || ! conversion))
        ctor = build_method_call (NULL_TREE, ctor_identifier,
                                  build_tree_list (NULL_TREE, e),
                                  TYPE_BINFO (type),
@@ -1504,16 +1496,16 @@ build_type_conversion (code, xtype, expr, for_sure)
      tree xtype, expr;
      int for_sure;
 {
-#ifdef NEW_OVER
-  return build_user_type_conversion
-    (xtype, expr, for_sure ? LOOKUP_NORMAL : 0);
-#else
   /* C++: check to see if we can convert this aggregate type
      into the required type.  */
   tree basetype;
   tree conv;
   tree winner = NULL_TREE;
 
+  if (flag_ansi_overloading)
+    return build_user_type_conversion
+      (xtype, expr, for_sure ? LOOKUP_NORMAL : 0);
+
   if (expr == error_mark_node)
     return error_mark_node;
 
@@ -1564,7 +1556,6 @@ build_type_conversion (code, xtype, expr, for_sure)
                                    DECL_NAME (winner), for_sure);
 
   return NULL_TREE;
-#endif
 }
 
 /* Convert the given EXPR to one of a group of types suitable for use in an
@@ -1852,2425 +1843,3 @@ type_promotes_to (type)
 
   return cp_build_type_variant (type, constp, volatilep);
 }
-
-/* Work in progress.  Ask jason before removing.  */
-
-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 ICS_RANK(NODE)                         \
-  (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 USER_CONV_FN(NODE) TREE_OPERAND (NODE, 1)
-
-static struct z_candidate * build_user_type_conversion_1 ();
-static tree convert_like ();
-static tree build_over_call ();
-static struct z_candidate * tourney ();
-static void enforce_access ();
-
-int
-null_ptr_cst (t)
-     tree t;
-{
-  return (INTEGRAL_TYPE_P (TREE_TYPE (t)) && integer_zerop (t));
-}
-
-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 LVALUE_CONV:
-    case QUAL_CONV:
-    case RVALUE_CONV:
-      if (rank < EXACT_RANK)
-       rank = EXACT_RANK;
-
-    default:
-      break;
-    }
-  ICS_STD_RANK (t) = rank;
-  ICS_USER_FLAG (t) = ICS_USER_FLAG (from);
-  return t;
-}
-
-tree
-non_reference (t)
-     tree t;
-{
-  if (TREE_CODE (t) == REFERENCE_TYPE)
-    t = TREE_TYPE (t);
-  return 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.  */
-
-tree
-standard_conversion (to, from, expr)
-     tree to, from, expr;
-{
-  enum tree_code fcode, tcode;
-  tree conv;
-
-  fcode = TREE_CODE (from);
-  tcode = TREE_CODE (to);
-
-  conv = build1 (IDENTITY_CONV, from, expr);
-
-  if (from == to)
-    return conv;
-
-  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);
-    }
-
-  if ((tcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (to))
-      && expr && null_ptr_cst (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));
-
-      if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (from)),
-                    TYPE_MAIN_VARIANT (TREE_TYPE (to)), 1))
-       /* OK for now */;
-      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))));
-         conv = 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);
-             conv = build_conv (PMEM_CONV, from, conv);
-           }
-         else
-           return 0;
-       }
-      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);
-             conv = build_conv (PTR_CONV, from, conv);
-           }
-         else
-           return 0;
-       }
-      else
-       return 0;
-
-      if (! comptypes (from, to, 1))
-       {
-         if (! comp_ptr_ttypes (TREE_TYPE (to), TREE_TYPE (from)))
-           return 0;
-
-         from = to;
-         conv = build_conv (QUAL_CONV, from, conv);
-       }
-    }
-  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)));
-      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?  */
-
-tree
-reference_binding (rto, from, expr)
-     tree rto, from, expr;
-{
-  tree conv;
-  int lvalue = 1;
-  tree to = TREE_TYPE (rto);
-
-  if (TREE_CODE (from) == REFERENCE_TYPE)
-    from = TREE_TYPE (from);
-  else if (! expr || ! real_lvalue_p (expr))
-    lvalue = 0;
-
-  if (lvalue
-      && TYPE_READONLY (to) >= TYPE_READONLY (from)
-      && TYPE_VOLATILE (to) >= TYPE_VOLATILE (from))
-    {
-      conv = build1 (IDENTITY_CONV, from, expr);
-
-      if (TYPE_MAIN_VARIANT (to) == TYPE_MAIN_VARIANT (from))
-       conv = build_conv (REF_BIND, rto, conv);
-      else if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
-              && DERIVED_FROM_P (to, from))
-       {
-         conv = build_conv (REF_BIND, rto, conv);
-         ICS_STD_RANK (conv) = STD_RANK;
-       }
-      else
-       conv = NULL_TREE;
-    }
-  else
-    conv = NULL_TREE;
-
-  if (! conv && TYPE_READONLY (to) && ! TYPE_VOLATILE (to))
-    {
-      conv = standard_conversion
-       (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), expr);
-      if (conv)
-       {
-         conv = build_conv (REF_BIND, rto, conv);
-
-         /* Bind directly to a base subobject of a class rvalue.  */
-         if (TREE_CODE (TREE_OPERAND (conv, 0)) == BASE_CONV)
-           TREE_OPERAND (conv, 0) = TREE_OPERAND (TREE_OPERAND (conv, 0), 0);
-       }
-    }
-
-  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.  */
-
-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);
-  else
-    conv = standard_conversion
-      (TYPE_MAIN_VARIANT (non_reference (to)),
-       TYPE_MAIN_VARIANT (non_reference (from)), expr);
-
-  if (conv)
-    {
-      if (TREE_CODE (conv) == IDENTITY_CONV && IS_AGGR_TYPE (to)
-         && (TREE_CODE (from) == REFERENCE_TYPE || (expr && real_lvalue_p (expr))))
-       conv = build_conv (RVALUE_CONV, to, conv);
-    }
-  else if ((IS_AGGR_TYPE (non_reference (from))
-           || IS_AGGR_TYPE (non_reference (to)))
-          && (flags & LOOKUP_NO_CONVERSION) == 0)
-    {
-      if (TREE_CODE (to) == REFERENCE_TYPE
-         && TYPE_READONLY (TREE_TYPE (to))
-         && ! TYPE_VOLATILE (TREE_TYPE (to)))
-       {
-         cand = build_user_type_conversion_1
-           (TYPE_MAIN_VARIANT (TREE_TYPE (to)), expr, LOOKUP_ONLYCONVERTING);
-         if (cand)
-           conv = build_conv (REF_BIND, to, cand->second_conv);
-       }
-      else
-       {
-         cand = build_user_type_conversion_1
-           (to, expr, LOOKUP_ONLYCONVERTING);
-         if (cand)
-           conv = 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 = list_length (arglist);
-  tree convs = make_tree_vec (len);
-  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);
-      if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
-       parmnode = TREE_CHAIN (parmnode);
-    }
-
-  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;
-       }
-
-      TREE_VEC_ELT (convs, i) = t;
-      if (! t)
-       break;
-
-      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 *) oballoc (sizeof (struct z_candidate));
-
-  cand->fn = fn;
-  cand->convs = convs;
-  cand->second_conv = NULL_TREE;
-  cand->viable = viable;
-  cand->basetype_path = NULL_TREE;
-  cand->template = NULL_TREE;
-  cand->next = candidates;
-
-  return cand;
-}
-
-/* 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_tree_vec (len);
-  tree parmnode = parmlist;
-  tree argnode = arglist;
-  int viable = 1;
-  struct z_candidate *cand;
-  int flags = LOOKUP_NORMAL;
-
-  for (i = 0; i < len; ++i)
-    {
-      tree arg = i == 0 ? obj : TREE_VALUE (argnode);
-      tree argtype = TREE_TYPE (arg);
-      tree t;
-
-      argtype = cp_build_type_variant
-       (argtype, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
-
-      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 (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 *) oballoc (sizeof (struct z_candidate));
-
-  cand->fn = fn;
-  cand->convs = convs;
-  cand->second_conv = NULL_TREE;
-  cand->viable = viable;
-  cand->basetype_path = NULL_TREE;
-  cand->template = NULL_TREE;
-  cand->next = candidates;
-
-  return cand;
-}
-
-int
-ptr_complete_ob (t)
-     tree t;
-{
-  return (TREE_CODE (t) == POINTER_TYPE
-         && TREE_CODE (TREE_TYPE (t)) != OFFSET_TYPE
-         && TREE_CODE (TREE_TYPE (t)) != FUNCTION_TYPE
-         && TREE_CODE (TREE_TYPE (t)) != VOID_TYPE
-         && TYPE_SIZE (complete_type (TREE_TYPE (t))) != NULL_TREE);
-}
-
-#define TYPE_PTRMEM_P(NODE)                                    \
-  (TREE_CODE (NODE) == POINTER_TYPE                            \
-   && TREE_CODE (TREE_TYPE (NODE)) == OFFSET_TYPE)
-#define TYPE_PTR_P(NODE)                               \
-  (TREE_CODE (NODE) == POINTER_TYPE                    \
-   && TREE_CODE (TREE_TYPE (NODE)) != OFFSET_TYPE)
-#define TYPE_PTROB_P(NODE)                                             \
-  (TYPE_PTR_P (NODE) && TREE_CODE (TREE_TYPE (NODE)) != FUNCTION_TYPE  \
-   && TREE_CODE (TREE_TYPE (NODE)) != VOID_TYPE)
-
-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_tree_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);
-       }
-      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 *) oballoc (sizeof (struct z_candidate));
-
-  cand->fn = fnname;
-  cand->convs = convs;
-  cand->second_conv = NULL_TREE;
-  cand->viable = viable;
-  cand->basetype_path = NULL_TREE;
-  cand->template = NULL_TREE;
-  cand->next = candidates;
-
-  return cand;
-}
-
-int
-is_complete (t)
-     tree t;
-{
-  return TYPE_SIZE (complete_type (t)) != NULL_TREE;
-}
-
-/* Create any builtin operator overload candidates for the operator in
-   question given the converted operand types TYPE1 and TYPE2.  The other
-   args are passed through from add_builtin_candidates to
-   build_builtin_candidate.  */
-
-static struct z_candidate *
-add_builtin_candidate (candidates, code, code2, fnname, type1, type2,
-                      args, argtypes, flags)
-     struct z_candidate *candidates;
-     enum tree_code code, code2;
-     tree fnname, type1, type2, *args, *argtypes;
-     int flags;
-{
-  switch (code)
-    {
-    case POSTINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-      args[1] = integer_zero_node;
-      type2 = integer_type_node;
-    }
-
-  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) || ptr_complete_ob (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
-         && (ptr_complete_ob (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 (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 (ptr_complete_ob (type1) && ptr_complete_ob (type2))
-       break;
-      if (ptr_complete_ob (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 (args[1]))
-       {
-         type2 = type1;
-         break;
-       }
-      if ((TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2))
-         && null_ptr_cst (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 (args[1]))
-       {
-         type2 = type1;
-         break;
-       }
-      if (null_ptr_cst (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) && ptr_complete_ob (type2))
-       {
-         type1 = ptrdiff_type_node;
-         break;
-       }
-      if (ptr_complete_ob (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 (ptr_complete_ob (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 (args[1])))
-           {
-             type2 = type1;
-             break;
-           }
-         return candidates;
-
-       default:
-         my_friendly_abort (367);
-       }
-      type1 = build_reference_type (type1);
-      break;
-
-    case COND_EXPR:
-      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 (args[1]))
-         || IS_AGGR_TYPE (type1))
-       {
-         type2 = type1;
-         break;
-       }
-      if (((TYPE_PTRMEMFUNC_P (type2) || TREE_CODE (type2) == POINTER_TYPE)
-          && null_ptr_cst (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_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]  = cp_build_type_variant
-         (TREE_TYPE (args[i]), TREE_READONLY (args[i]),
-          TREE_THIS_VOLATILE (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] = tree_cons
-                 (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
-
-             types[i] = tree_cons
-               (NULL_TREE, TYPE_MAIN_VARIANT (argtypes[i]), types[i]);
-           }
-               
-         else if (! convs || (i == 0 && code == MODIFY_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] = tree_cons (NULL_TREE, type, types[i]);
-
-             type = non_reference (type);
-             if (i != 0 || ! ref1)
-               {
-                 type = type_decays_to (TYPE_MAIN_VARIANT (type));
-                 if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
-                   types[i] = tree_cons (NULL_TREE, type, types[i]);
-                 type = type_promotes_to (type);
-               }
-
-             if (! value_member (type, types[i]))
-               types[i] = tree_cons (NULL_TREE, type, types[i]);
-           }
-       }
-      else
-       {
-         if (code == COND_EXPR && real_lvalue_p (args[i]))
-           types[i] = tree_cons
-             (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
-         type = non_reference (argtypes[i]);
-         if (i != 0 || ! ref1)
-           {
-             type = type_decays_to (TYPE_MAIN_VARIANT (type));
-             if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
-               types[i] = tree_cons (NULL_TREE, type, types[i]);
-             type = type_promotes_to (type);
-           }
-         types[i] = 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;
-}
-
-static struct z_candidate *
-add_template_candidate (candidates, tmpl, arglist, flags)
-     struct z_candidate *candidates;
-     tree tmpl, arglist;
-     int flags;
-{
-  int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl));
-  tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
-  struct z_candidate *cand;
-  int i, dummy; 
-  tree fn;
-
-  i = type_unification (DECL_TEMPLATE_PARMS (tmpl), targs,
-                       TYPE_ARG_TYPES (TREE_TYPE (tmpl)),
-                       arglist, &dummy, 0, 0);
-  if (i != 0)
-    return candidates;
-
-  fn = instantiate_template (tmpl, targs);
-  if (fn == error_mark_node)
-    return candidates;
-
-  cand = add_function_candidate (candidates, fn, arglist, flags);
-  cand->template = DECL_TEMPLATE_INFO (fn);
-  return cand;
-}
-
-static int
-any_viable (cands)
-     struct z_candidate *cands;
-{
-  for (; cands; cands = cands->next)
-    if (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 ((*p)->viable)
-       p = &((*p)->next);
-      else
-       *p = (*p)->next;
-    }
-
-  return cands;
-}
-
-tree
-build_this (obj)
-     tree obj;
-{
-  /* Fix this to work on non-lvalues.  */
-  return build_unary_op (ADDR_EXPR, obj, 0);
-}
-
-static void
-print_z_candidates (candidates)
-     struct z_candidate *candidates;
-{
-  if (! candidates)
-    return;
-
-  if (TREE_CODE (candidates->fn) == IDENTIFIER_NODE)
-    {
-      if (candidates->fn == ansi_opname [COND_EXPR])
-       cp_error ("candidates are: %D(%T, %T, %T) <builtin>", 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 ("candidates are: %D(%T, %T) <builtin>", candidates->fn,
-                 TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
-                 TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)));
-      else
-       cp_error ("candidates are: %D(%T) <builtin>", candidates->fn,
-                 TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)));
-    }
-  else
-    cp_error_at ("candidates are: %D", candidates->fn);
-  candidates = candidates->next;
-
-  for (; candidates; candidates = candidates->next)
-    {
-      if (TREE_CODE (candidates->fn) == IDENTIFIER_NODE)
-       {
-         if (candidates->fn == ansi_opname [COND_EXPR])
-           cp_error ("                %D(%T, %T, %T) <builtin>",
-                     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 ("                %D(%T, %T) <builtin>", candidates->fn,
-                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
-                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)));
-         else
-           cp_error ("                %D(%T) <builtin>", candidates->fn,
-                     TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)));
-       }
-      else
-       cp_error_at ("                %D", candidates->fn);
-    }
-}
-
-/* Returns the best overload candidate to perform the requested
-   conversion.  */
-
-static struct z_candidate *
-build_user_type_conversion_1 (totype, expr, flags)
-     tree totype, expr;
-     int flags;
-{
-  struct z_candidate *candidates, *cand;
-  tree fromtype = TREE_TYPE (expr);
-  tree ctors = NULL_TREE, convs = NULL_TREE, *p;
-  tree args;
-
-  if (IS_AGGR_TYPE (totype))
-    ctors = lookup_fnfields (TYPE_BINFO (totype), ctor_identifier, 0);
-  if (IS_AGGR_TYPE (fromtype)
-      && (! IS_AGGR_TYPE (totype) || ! DERIVED_FROM_P (totype, fromtype)))
-    convs = lookup_conversions (fromtype);
-
-  candidates = 0;
-  flags |= LOOKUP_NO_CONVERSION;
-
-  if (ctors)
-    {
-      ctors = TREE_VALUE (ctors);
-      args = build_tree_list (NULL_TREE, expr);
-    }
-  for (; ctors; ctors = DECL_CHAIN (ctors))
-    {
-      if ((flags & LOOKUP_ONLYCONVERTING) && DECL_NONCONVERTING_P (ctors))
-       continue;
-
-      candidates = add_function_candidate (candidates, ctors, args, flags);
-      candidates->second_conv = build1 (IDENTITY_CONV, totype, NULL_TREE);
-      candidates->basetype_path = TYPE_BINFO (totype);
-    }
-
-  if (convs)
-    args = build_tree_list (NULL_TREE, build_this (expr));
-
-  for (; convs; convs = TREE_CHAIN (convs))
-    {
-      tree fn = TREE_VALUE (convs);
-      tree ics = implicit_conversion
-       (totype, TREE_TYPE (TREE_TYPE (fn)), 0, LOOKUP_NO_CONVERSION);
-      if (ics)
-       for (; fn; fn = DECL_CHAIN (fn))
-         {
-           candidates = add_function_candidate (candidates, fn, args, flags);
-           candidates->second_conv = ics;
-           candidates->basetype_path = TREE_PURPOSE (convs);
-         }
-    }
-
-  if (! 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, totype);
-
-  if (cand == 0)
-    {
-      if (flags & LOOKUP_COMPLAIN)
-       {
-         cp_error ("ambiguous user-defined type conversion");
-         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;
-
-      return cand;
-    }
-
-  for (p = &(cand->second_conv); TREE_CODE (*p) != IDENTITY_CONV; )
-    p = &(TREE_OPERAND (*p, 0));
-
-  *p = build
-    (USER_CONV,
-     (DECL_CONSTRUCTOR_P (cand->fn)
-      ? totype : non_reference (TREE_TYPE (TREE_TYPE (cand->fn)))),
-     NULL_TREE, cand->fn, cand->convs, cand->basetype_path);
-  ICS_USER_FLAG (cand->second_conv) = 1;
-
-  return cand;
-}
-
-tree
-build_user_type_conversion (totype, expr, flags)
-     tree totype, expr, flags;
-{
-  struct z_candidate *cand
-    = build_user_type_conversion_1 (totype, expr, flags);
-
-  if (cand)
-    {
-      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;
-}
-
-tree
-build_new_function_call (fn, args, obj)
-     tree fn, args, obj;
-{
-  struct z_candidate *candidates = 0, *cand;
-  if (obj == NULL_TREE && TREE_CODE (fn) == TREE_LIST)
-    {
-      tree t = TREE_VALUE (fn);
-
-      for (; t; t = DECL_CHAIN (t))
-       {
-         if (TREE_CODE (t) == TEMPLATE_DECL)
-           candidates = add_template_candidate
-             (candidates, t, args, LOOKUP_NORMAL);
-         else
-           candidates = add_function_candidate
-             (candidates, t, args, LOOKUP_NORMAL);
-       }
-
-      if (! any_viable (candidates))
-       {
-         if (candidates && ! candidates->next)
-           return build_function_call (candidates->fn, args);
-         else
-           cp_error ("no viable candidates");
-         return error_mark_node;
-       }
-      candidates = splice_viable (candidates);
-      cand = tourney (candidates, NULL_TREE);
-
-      if (cand == 0)
-       {
-         cp_error ("ambiguous function call");
-         print_z_candidates (candidates);
-         return error_mark_node;
-       }
-
-      return build_over_call (cand->fn, cand->convs, args, LOOKUP_NORMAL);
-    }
-
-  return build_function_call (fn, args);
-}
-
-tree
-build_object_call (obj, args)
-     tree obj, args;
-{
-  struct z_candidate *candidates = 0, *cand;
-  tree fns, convs, mem_args, *p;
-  enum tree_code code2 = NOP_EXPR;
-  tree type = TREE_TYPE (obj);
-
-  fns = lookup_fnfields (TYPE_BINFO (type), ansi_opname [CALL_EXPR], 0);
-
-  if (fns)
-    {
-      tree fn = TREE_VALUE (fns);
-      mem_args = tree_cons (NULL_TREE, build_this (obj), args);
-
-      for (; fn; fn = DECL_CHAIN (fn))
-       {
-         candidates = add_function_candidate
-           (candidates, fn, mem_args, LOOKUP_NORMAL);
-         candidates->basetype_path = TREE_PURPOSE (fns);
-       }
-    }
-
-  convs = lookup_conversions (type);
-
-  for (; convs; convs = TREE_CHAIN (convs))
-    {
-      tree fn = TREE_VALUE (convs);
-      tree totype = TREE_TYPE (TREE_TYPE (fn));
-
-      if (TREE_CODE (totype) == POINTER_TYPE
-         && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
-       {
-         candidates = add_conv_candidate (candidates, fn, obj, args);
-         candidates->basetype_path = TREE_PURPOSE (convs);
-       }
-    }
-
-  if (! any_viable (candidates))
-    {
-      cp_error ("no viable candidates");
-      print_z_candidates (candidates);
-      return error_mark_node;
-    }
-
-  candidates = splice_viable (candidates);
-  cand = tourney (candidates, NULL_TREE);
-
-  if (cand == 0)
-    {
-      cp_error ("ambiguous object call");
-      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,
-               TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3));
-      break;
-    case POSTINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-      cp_error ("%s for `%T%s'", problem, TREE_TYPE (arg1), opname);
-      break;
-    case ARRAY_REF:
-      cp_error ("%s for `%T[%T]'", problem,
-               TREE_TYPE (arg1), TREE_TYPE (arg2));
-      break;
-    default:
-      if (arg2)
-       cp_error ("%s for `%T %s %T'", problem,
-                 TREE_TYPE (arg1), opname, TREE_TYPE (arg2));
-      else
-       cp_error ("%s for `%s%T'", problem, opname, TREE_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, *p;
-  enum tree_code code2 = NOP_EXPR;
-
-  if (arg1 == error_mark_node)
-    return error_mark_node;
-
-  if (code == MODIFY_EXPR)
-    {
-      code2 = TREE_CODE (arg3);
-      arg3 = NULL_TREE;
-      fnname = ansi_assopname[code2];
-    }
-  else
-    fnname = ansi_opname[code];
-
-  switch (code)
-    {
-    case NEW_EXPR:
-    case VEC_NEW_EXPR:
-      {
-       tree rval;
-
-       arglist = tree_cons (NULL_TREE, arg2, arg3);
-       if (flags & LOOKUP_GLOBAL)
-         return build_new_function_call
-           (lookup_name_nonclass (fnname), arglist, NULL_TREE);
-
-       /* FIXME */
-       rval = build_method_call
-         (build_indirect_ref (build1 (NOP_EXPR, arg1, error_mark_node),
-                              "new"),
-          fnname, arglist, NULL_TREE, flags);
-       if (rval == error_mark_node)
-         /* User might declare fancy operator new, but invoke it
-            like standard one.  */
-         return rval;
-
-       TREE_TYPE (rval) = arg1;
-       TREE_CALLS_NEW (rval) = 1;
-       return rval;
-      }
-
-    case VEC_DELETE_EXPR:
-    case DELETE_EXPR:
-      {
-       tree rval;
-
-       if (flags & LOOKUP_GLOBAL)
-         return build_new_function_call
-           (lookup_name_nonclass (fnname),
-            build_tree_list (NULL_TREE, arg1), NULL_TREE);
-
-       arglist = tree_cons (NULL_TREE, arg1, build_tree_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);
-    }
-
-  /* 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 (! IS_OVERLOAD_TYPE (TREE_TYPE (arg1))
-      && (! arg2 || ! IS_OVERLOAD_TYPE (TREE_TYPE (arg2)))
-      && (! arg3 || ! IS_OVERLOAD_TYPE (TREE_TYPE (arg3))))
-    return NULL_TREE;
-
-  if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
-    arg2 = integer_zero_node;
-
-  fns = lookup_name_nonclass (fnname);
-  /* + Koenig lookup */
-
-  if (arg2 && arg3)
-    arglist = tree_cons (NULL_TREE, arg1, tree_cons
-                     (NULL_TREE, arg2, build_tree_list (NULL_TREE, arg3)));
-  else if (arg2)
-    arglist = tree_cons (NULL_TREE, arg1, build_tree_list (NULL_TREE, arg2));
-  else
-    arglist = build_tree_list (NULL_TREE, arg1);
-
-  if (fns && TREE_CODE (fns) == TREE_LIST)
-    fns = TREE_VALUE (fns);
-  for (; fns; fns = DECL_CHAIN (fns))
-    {
-      if (TREE_CODE (fns) == TEMPLATE_DECL)
-       candidates = add_template_candidate (candidates, fns, arglist, flags);
-      else
-       candidates = add_function_candidate (candidates, fns, arglist, flags);
-    }
-
-  if (IS_AGGR_TYPE (TREE_TYPE (arg1)))
-    fns = lookup_fnfields (TYPE_BINFO (TREE_TYPE (arg1)), fnname, 0);
-  else
-    fns = NULL_TREE;
-
-  if (fns)
-    {
-      tree fn = TREE_VALUE (fns);
-      mem_arglist = tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
-      for (; fn; fn = DECL_CHAIN (fn))
-       {
-         if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
-           candidates = add_function_candidate
-             (candidates, fn, mem_arglist, flags);
-         else
-           candidates = add_function_candidate (candidates, fn, arglist, flags);
-         
-         candidates->basetype_path = TREE_PURPOSE (fns);
-       }
-    }
-
-#if 0 /* Don't handle builtin COND_EXPR for now */
-  if (code != COND_EXPR)
-#endif
-    {
-      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);
-         
-         /* FIXME */
-       case ADDR_EXPR:
-         /*return build_unary_op (code, arg1, 1);*/
-       case COMPOUND_EXPR:
-         /*return build (COMPOUND_EXPR, TREE_TYPE (arg2),
-                       break_out_cleanups (arg1), arg2);*/
-       case COMPONENT_REF:
-         /*return build_x_arrow (arg1);*/
-#if 0 /* Don't handle builtin COND_EXPR for now */
-       case COND_EXPR:
-#endif
-         return NULL_TREE;
-       }
-      if (flags & LOOKUP_COMPLAIN)
-       {
-         op_error (code, code2, arg1, arg2, arg3, "no match");
-         print_z_candidates (candidates);
-       }
-      return error_mark_node;
-    }
-  candidates = splice_viable (candidates);
-  cand = tourney (candidates, NULL_TREE);
-
-  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);
-
-      return build_over_call
-       (cand->fn, cand->convs,
-        TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
-        ? mem_arglist : arglist,
-        LOOKUP_NORMAL);
-    }
-
-  arg1 = convert_from_reference
-    (convert_like (TREE_VEC_ELT (cand->convs, 0), arg1));
-  if (arg2)
-    arg2 = convert_like (TREE_VEC_ELT (cand->convs, 1), arg2);
-  if (arg3)
-    arg3 = convert_like (TREE_VEC_ELT (cand->convs, 2), arg3);
-
-  switch (code)
-    {
-    case MODIFY_EXPR:
-      return build_modify_expr (arg1, code2, arg2);
-
-    case INDIRECT_REF:
-      return build_indirect_ref (arg1, "unary *");
-
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-    case MULT_EXPR:
-    case TRUNC_DIV_EXPR:
-    case GT_EXPR:
-    case LT_EXPR:
-    case GE_EXPR:
-    case LE_EXPR:
-    case EQ_EXPR:
-    case NE_EXPR:
-    case MAX_EXPR:
-    case MIN_EXPR:
-    case LSHIFT_EXPR:
-    case RSHIFT_EXPR:
-    case TRUNC_MOD_EXPR:
-    case BIT_AND_EXPR:
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-      return build_binary_op_nodefault (code, arg1, arg2, code);
-
-    case CONVERT_EXPR:
-    case NEGATE_EXPR:
-    case BIT_NOT_EXPR:
-    case TRUTH_NOT_EXPR:
-    case PREINCREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-    case PREDECREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-      return build_unary_op (code, arg1, 1);
-
-    case ARRAY_REF:
-      return build_array_ref (arg1, arg2);
-
-    case COND_EXPR:
-      return build_conditional_expr (arg1, arg2, arg3);
-
-    default:
-      my_friendly_abort (367);
-    }
-}
-
-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;
-{
-  switch (TREE_CODE (convs))
-    {
-    case USER_CONV:
-      {
-       tree fn = TREE_OPERAND (convs, 1);
-       enforce_access (TREE_OPERAND (convs, 3), fn);
-       expr = build_over_call
-         (TREE_OPERAND (convs, 1), TREE_OPERAND (convs, 2),
-          DECL_CONSTRUCTOR_P (fn) ? expr : build_this (expr), 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)
-           || IS_AGGR_TYPE (TREE_TYPE (TREE_TYPE (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);
-      return expr;
-    case AMBIG_CONV:
-      /* Call build_user_type_conversion again for the error.  */
-      return build_user_type_conversion
-       (TREE_TYPE (convs), TREE_OPERAND (convs, 0), LOOKUP_NORMAL);
-    };
-
-  expr = convert_like (TREE_OPERAND (convs, 0), expr);
-  if (expr == error_mark_node)
-    return error_mark_node;
-
-  switch (TREE_CODE (convs))
-    {
-    case BASE_CONV:
-    case RVALUE_CONV:
-      return build_user_type_conversion
-       (TREE_TYPE (convs), expr, LOOKUP_NORMAL);
-    case REF_BIND:
-      return convert_to_reference
-       (TREE_TYPE (convs), expr,
-        CONV_IMPLICIT, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION|INDIRECT_BIND,
-        error_mark_node);
-    case LVALUE_CONV:
-      return decay_conversion (expr);
-    }
-  return cp_convert (TREE_TYPE (convs), expr, CONV_IMPLICIT,
-                    LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
-}
-
-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;
-
-  if (args && TREE_CODE (args) != TREE_LIST)
-    args = build_tree_list (NULL_TREE, args);
-  arg = args;
-
-  if (DECL_CONSTRUCTOR_P (fn))
-    {
-      tree t = build_int_2 (0, 0);
-      TREE_TYPE (t) = build_pointer_type (DECL_CONTEXT (fn));
-      converted_args = tree_cons (NULL_TREE, t, converted_args);
-      parm = TREE_CHAIN (parm);
-
-      if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
-       {
-         converted_args = tree_cons
-           (NULL_TREE, integer_one_node, converted_args);
-         parm = TREE_CHAIN (parm);
-       }
-    }
-  /* Bypass access control for 'this' parameter.  */
-  else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
-    {
-      converted_args = tree_cons
-       (NULL_TREE, convert_force (TREE_VALUE (parm), TREE_VALUE (arg), CONV_C_CAST),
-        converted_args);
-      parm = TREE_CHAIN (parm);
-      arg = TREE_CHAIN (arg);
-      ++i;
-    }
-
-  for (; conv = TREE_VEC_ELT (convs, i), arg && parm;
-       parm = TREE_CHAIN (parm), arg = TREE_CHAIN (arg), ++i)
-    {
-      tree type = TREE_VALUE (parm);
-      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 = tree_cons (NULL_TREE, val, converted_args);
-    }
-
-  /* Default arguments */
-  for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm))
-    converted_args = tree_cons
-      (NULL_TREE,
-       convert_default_arg (TREE_VALUE (parm), TREE_PURPOSE (parm)),
-       converted_args);
-
-  /* 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 = 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 = tree_cons (NULL_TREE, val, converted_args);
-    }
-
-  converted_args = nreverse (converted_args);
-
-  mark_used (fn);
-  /* Is it a synthesized method that needs to be synthesized?  */
-  if (DECL_ARTIFICIAL (fn) && ! DECL_INITIAL (fn)
-      /* Kludge: don't synthesize for default args.  */
-      && current_function_decl)
-    synthesize_method (fn);
-
-  if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
-    {
-      tree t = build_pointer_type (TREE_TYPE (fn));
-      fn = build_vfn_ref (&TREE_VALUE (converted_args),
-                         build_indirect_ref (TREE_VALUE (args), 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;
-  return convert_from_reference (require_complete_type (fn));
-}
-
-/* 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);
-
-  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;
-}
-
-/* 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 (ICS_RANK (ics1) > ICS_RANK (ics2))
-    return -1;
-  else if (ICS_RANK (ics1) < ICS_RANK (ics2))
-    return 1;
-
-  /* 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_RANK (ics1) == USER_RANK)
-    {
-      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 (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;
-
-  if (TREE_CODE (main1) != TREE_CODE (main2))
-    return 0;
-
-  if (TREE_CODE (main1) == IDENTITY_CONV
-      && (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
-    }
-
-  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 (TYPE_PTRMEMFUNC_FN_TYPE (to1));
-         from1 = TYPE_METHOD_BASETYPE (TYPE_PTRMEMFUNC_FN_TYPE (from1));
-       }
-      else if (TREE_CODE (main1) != BASE_CONV)
-       {
-         to1 = TREE_TYPE (to1);
-         if (TREE_CODE (main1) != REF_BIND)
-           from1 = TREE_TYPE (from1);
-
-         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 (TYPE_PTRMEMFUNC_FN_TYPE (to2));
-         from2 = TYPE_METHOD_BASETYPE (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;
-       }
-    }
-  return 0;
-}
-
-/* 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;
-
-  /* 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 (i = 0; i < TREE_VEC_LENGTH (cand1->convs); ++i)
-    {
-      int comp = compare_ics (TREE_VEC_ELT (cand1->convs, i),
-                             TREE_VEC_ELT (cand2->convs, i));
-
-      if (comp != 0)
-       {
-         if (winner && comp != winner)
-           return 0;
-         winner = comp;
-       }
-    }
-
-  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 < TREE_VEC_LENGTH (cand1->convs); ++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;
-    }
-
-  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;
-}
index 6aa922f3f86f9922ec29b751f157a803b5b763f9..98d3f14f8eca38f4c9e9dd4d920338b4a0f70877 100644 (file)
@@ -4912,9 +4912,7 @@ init_decl_processing ()
   void_list_node = build_tree_list (NULL_TREE, void_type_node);
   TREE_PARMLIST (void_list_node) = 1;
 
-  null_pointer_node = build_int_2 (0, 0);
   TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
-  layout_type (TREE_TYPE (null_pointer_node));
 
   /* Used for expressions that do nothing, but are not errors.  */
   void_zero_node = build_int_2 (0, 0);
@@ -9864,6 +9862,10 @@ grokparms (first_parm, funcdef_flag)
                        }
                      else
                        init = require_instantiated_type (type, init, integer_zero_node);
+                     if (! current_template_parms
+                         && ! implicit_conversion (type, TREE_TYPE (init), init, LOOKUP_NORMAL))
+                       cp_pedwarn ("invalid type `%T' for default argument to `%#D'",
+                                   TREE_TYPE (init), decl);
                    }
                }
              else
@@ -11962,7 +11964,7 @@ finish_function (lineno, call_poplevel, nested)
     pop_memoized_context (1);
 
   /* Must mark the RESULT_DECL as being in this function.  */
-  DECL_CONTEXT (DECL_RESULT (fndecl)) = DECL_INITIAL (fndecl);
+  DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
 
   /* Obey `register' declarations if `setjmp' is called in this fn.  */
   if (flag_traditional && current_function_calls_setjmp)
@@ -12303,15 +12305,14 @@ hack_incomplete_structures (type)
 }
 
 /* If DECL is of a type which needs a cleanup, build that cleanup here.
-   We don't build cleanups if just going for syntax checking, since
-   fixup_cleanups does not know how to not handle them.
+   See build_delete for information about AUTO_DELETE.
 
    Don't build these on the momentary obstack; they must live
    the life of the binding contour.  */
 
-tree
-maybe_build_cleanup (decl)
-     tree decl;
+static tree
+maybe_build_cleanup_1 (decl, auto_delete)
+     tree decl, auto_delete;
 {
   tree type = TREE_TYPE (decl);
   if (TYPE_NEEDS_DESTRUCTOR (type))
@@ -12335,7 +12336,7 @@ maybe_build_cleanup (decl)
          || flag_expensive_optimizations)
        flags |= LOOKUP_NONVIRTUAL;
 
-      rval = build_delete (TREE_TYPE (rval), rval, integer_two_node, flags, 0);
+      rval = build_delete (TREE_TYPE (rval), rval, auto_delete, flags, 0);
 
       if (TYPE_USES_VIRTUAL_BASECLASSES (type)
          && ! TYPE_HAS_DESTRUCTOR (type))
@@ -12352,6 +12353,26 @@ maybe_build_cleanup (decl)
     }
   return 0;
 }
+
+/* If DECL is of a type which needs a cleanup, build that cleanup
+   here.  The cleanup does free the storage with a call to delete.  */
+
+tree
+maybe_build_cleanup_and_delete (decl)
+     tree decl;
+{
+  return maybe_build_cleanup_1 (decl, integer_three_node);
+}
+
+/* If DECL is of a type which needs a cleanup, build that cleanup
+   here.  The cleanup does not free the storage with a call a delete.  */
+
+tree
+maybe_build_cleanup (decl)
+     tree decl;
+{
+  return maybe_build_cleanup_1 (decl, integer_two_node);
+}
 \f
 /* Expand a C++ expression at the statement level.
    This is needed to ferret out nodes which have UNKNOWN_TYPE.
index 632ce767c03fff0ec94142c38121421c890e98cd..b4de01b9e3de6f0d11263002f9d099c4260b20ab 100644 (file)
@@ -125,6 +125,15 @@ int flag_no_ident;
 
 int flag_ansi;
 
+/* Nonzero means do argument matching for overloading according to the
+   ANSI rules, rather than what g++ used to believe to be correct.  */
+
+#ifdef NEW_OVER
+int flag_ansi_overloading = 1;
+#else
+int flag_ansi_overloading;
+#endif
+
 /* Nonzero means do emit exported implementations of functions even if
    they can be inlined.  */
 
@@ -157,7 +166,11 @@ int warn_ctor_dtor_privacy = 1;
 /* True if we want to implement vtables using "thunks".
    The default is off.  */
 
+#if defined(NEW_OVER) && defined (__i386__)
+int flag_vtable_thunks = 1;
+#else
 int flag_vtable_thunks;
+#endif
 
 /* True if we want to deal with repository information.  */
 
@@ -410,6 +423,7 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
   {"implement-inlines", &flag_implement_inlines, 1},
   {"external-templates", &flag_external_templates, 1},
   {"implicit-templates", &flag_implicit_templates, 1},
+  {"ansi-overloading", &flag_ansi_overloading, 1},
   {"huge-objects", &flag_huge_objects, 1},
   {"conserve-space", &flag_conserve_space, 1},
   {"vtable-thunks", &flag_vtable_thunks, 1},
@@ -2562,7 +2576,7 @@ import_export_template (type)
     }
 }
     
-static int
+int
 finish_prevtable_vardecl (prev, vars)
      tree prev, vars;
 {
index 4dd7e6096d3cf64176341bc1604f854195fa4a7c..964f8c05ce7dec0fa5c8dc693d4ed9ae5d29634d 100644 (file)
@@ -1539,9 +1539,20 @@ args_as_string (p, v)
      int v;
 {
   if (p == NULL_TREE)
-    return "...";
+    return "";
 
-  return type_as_string (p, v);
+  if (TREE_CODE_CLASS (TREE_CODE (TREE_VALUE (p))) == 't')
+    return type_as_string (p, v);
+
+  OB_INIT ();
+  for (; p; p = TREE_CHAIN (p))
+    {
+      dump_type (TREE_TYPE (TREE_VALUE (p)), v);
+      if (TREE_CHAIN (p))
+       OB_PUTS (", ");
+    }
+  OB_FINISH ();
+  return (char *)obstack_base (&scratch_obstack);
 }
 
 char *
index 1d207e54664b282d219d7d039b09b011a3199d04..257ec113a124d910286a11950a9d97d9308ff4d4 100644 (file)
@@ -1079,7 +1079,7 @@ expand_throw (exp)
          start_sequence ();
          object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
          object = build_indirect_ref (object, NULL_PTR);
-         cleanup = maybe_build_cleanup (object);
+         cleanup = maybe_build_cleanup_and_delete (object);
          if (cleanup)
            expand_expr (cleanup, const0_rtx, VOIDmode, 0);
          cleanup_insns = get_insns ();
@@ -1089,7 +1089,8 @@ expand_throw (exp)
            {
              cleanup = start_anon_func ();
 
-             expand_expr (maybe_build_cleanup (object), const0_rtx, VOIDmode, 0);
+             expand_expr (maybe_build_cleanup_and_delete (object),
+                          const0_rtx, VOIDmode, 0);
 
              end_anon_func ();
 
index e5465e89b487e012f7ee75676c8ae6c303af6cc8..f846f5ce508e9cb0f93e2df435008a4eed8353ba 100644 (file)
@@ -15,6 +15,7 @@ __extension__, EXTENSION, NORID
 __inline, SCSPEC, RID_INLINE
 __inline__, SCSPEC, RID_INLINE
 __label__, LABEL, NORID
+__null, CONSTANT, RID_NULL
 __signature__, AGGR, RID_SIGNATURE     /* Extension */,
 __signed, TYPESPEC, RID_SIGNED
 __signed__, TYPESPEC, RID_SIGNED
index 4848aba47754b714b46330edea48c86757662cd1..d8bdc06ee2b84e0ac187a432e4bde62f1dd57c48 100644 (file)
@@ -1,14 +1,14 @@
 /* C code produced by gperf version 2.5 (GNU C++ version) */
-/* Command-line: gperf -p -j1 -g -o -t -N is_reserved_word -k1,4,7,$ ../../../devo/gcc/cp/gxx.gperf  */
+/* Command-line: gperf -p -j1 -g -o -t -N is_reserved_word -k1,4,7,$ /yorick/splunge/jason/g++/small/devo/gcc/cp/gxx.gperf  */
 /* Command-line: gperf -p -j1 -g -o -t -N is_reserved_word -k1,4,$,7 gplus.gperf  */
 struct resword { char *name; short token; enum rid rid;};
 
-#define TOTAL_KEYWORDS 97
+#define TOTAL_KEYWORDS 98
 #define MIN_WORD_LENGTH 2
 #define MAX_WORD_LENGTH 16
 #define MIN_HASH_VALUE 4
-#define MAX_HASH_VALUE 219
-/* maximum key range = 216, duplicates = 0 */
+#define MAX_HASH_VALUE 258
+/* maximum key range = 255, duplicates = 0 */
 
 #ifdef __GNUC__
 inline
@@ -18,21 +18,21 @@ hash (str, len)
      register char *str;
      register int unsigned len;
 {
-  static unsigned char asso_values[] =
+  static unsigned short asso_values[] =
     {
-     220, 220, 220, 220, 220, 220, 220, 220, 220, 220,
-     220, 220, 220, 220, 220, 220, 220, 220, 220, 220,
-     220, 220, 220, 220, 220, 220, 220, 220, 220, 220,
-     220, 220, 220, 220, 220, 220, 220, 220, 220, 220,
-     220, 220, 220, 220, 220, 220, 220, 220, 220, 220,
-     220, 220, 220, 220, 220, 220, 220, 220, 220, 220,
-     220, 220, 220, 220, 220, 220, 220, 220, 220, 220,
-     220, 220, 220, 220, 220, 220, 220, 220, 220, 220,
-     220, 220, 220, 220, 220, 220, 220, 220, 220, 220,
-     220, 220, 220, 220, 220,   0, 220,  88,  16,  19,
-      52,   0,   9,  72,   1,  77, 220,   0,   0,  38,
-      13,  44,  38,  30,  27,  57,   1,  14,   0,   2,
-       2,   7, 220, 220, 220, 220, 220, 220,
+     259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+     259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+     259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+     259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+     259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+     259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+     259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+     259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+     259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+     259, 259, 259, 259, 259,   0, 259,  27,  17,  20,
+      40,   0,  64,   6,  10,  89, 259,   2, 110,  44,
+      13, 107,  40,  10,  18,  55,   1,   3,   5,  17,
+       2,   4, 259, 259, 259, 259, 259, 259,
     };
   register int hval = len;
 
@@ -49,6 +49,7 @@ hash (str, len)
       case 2:
       case 1:
         hval += asso_values[str[0]];
+        break;
     }
   return hval + asso_values[str[len - 1]];
 }
@@ -66,143 +67,150 @@ is_reserved_word (str, len)
       {"",}, {"",}, {"",}, {"",}, 
       {"else",  ELSE, NORID,},
       {"true",  CXX_TRUE, NORID,},
-      {"",}, 
-      {"while",  WHILE, NORID,},
-      {"virtual",  SCSPEC, RID_VIRTUAL,},
       {"",}, {"",}, 
       {"try",  TRY, NORID,},
-      {"",}, {"",}, {"",}, {"",}, 
-      {"typeof",  TYPEOF, NORID,},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
       {"not",  '!', NORID,},
-      {"new",  NEW, NORID,},
+      {"xor_eq",  ASSIGN, NORID,},
       {"extern",  SCSPEC, RID_EXTERN,},
-      {"bool",  TYPESPEC, RID_BOOL,},
-      {"",}, {"",}, 
+      {"",}, {"",}, {"",}, 
+      {"xor",  '^', NORID,},
       {"case",  CASE, NORID,},
-      {"__alignof__",  ALIGNOF, NORID},
-      {"",}, 
-      {"typedef",  SCSPEC, RID_TYPEDEF,},
-      {"",}, 
+      {"",}, {"",}, 
+      {"using",  USING, NORID,},
       {"__extension__",  EXTENSION, NORID},
+      {"not_eq",  EQCOMPARE, NORID,},
       {"",}, {"",}, 
-      {"__alignof",  ALIGNOF, NORID},
-      {"xor",  '^', NORID,},
-      {"",}, 
+      {"continue",  CONTINUE, NORID,},
+      {"new",  NEW, NORID,},
       {"__inline",  SCSPEC, RID_INLINE},
       {"",}, 
       {"__inline__",  SCSPEC, RID_INLINE},
-      {"",}, 
-      {"xor_eq",  ASSIGN, NORID,},
-      {"for",  FOR, NORID,},
+      {"",}, {"",}, {"",}, 
+      {"return",  RETURN, NORID,},
       {"",}, {"",}, 
-      {"continue",  CONTINUE, NORID,},
-      {"",}, 
-      {"catch",  CATCH, NORID,},
-      {"private",  VISSPEC, RID_PRIVATE,},
-      {"",}, 
-      {"typename",  TYPENAME_KEYWORD, NORID,},
-      {"template",  TEMPLATE, RID_TEMPLATE,},
-      {"not_eq",  EQCOMPARE, NORID,},
+      {"and_eq",  ASSIGN, NORID,},
       {"",}, {"",}, 
-      {"throw",  THROW, NORID,},
-      {"__const",  TYPE_QUAL, RID_CONST},
-      {"__const__",  TYPE_QUAL, RID_CONST},
-      {"__volatile",  TYPE_QUAL, RID_VOLATILE},
-      {"__wchar_t",  TYPESPEC, RID_WCHAR  /* Unique to ANSI C++ */,},
-      {"__volatile__",  TYPE_QUAL, RID_VOLATILE},
       {"delete",  DELETE, NORID,},
       {"typeid",  TYPEID, NORID,},
-      {"return",  RETURN, NORID,},
-      {"__typeof__",  TYPEOF, NORID},
-      {"compl",  '~', NORID,},
-      {"public",  VISSPEC, RID_PUBLIC,},
-      {"__asm__",  GCC_ASM_KEYWORD, NORID},
-      {"switch",  SWITCH, NORID,},
+      {"__wchar_t",  TYPESPEC, RID_WCHAR  /* Unique to ANSI C++ */,},
+      {"namespace",  NAMESPACE, NORID,},
+      {"template",  TEMPLATE, RID_TEMPLATE,},
+      {"break",  BREAK, NORID,},
+      {"private",  VISSPEC, RID_PRIVATE,},
+      {"typename",  TYPENAME_KEYWORD, NORID,},
       {"",}, 
-      {"friend",  SCSPEC, RID_FRIEND,},
-      {"__typeof",  TYPEOF, NORID},
+      {"catch",  CATCH, NORID,},
+      {"",}, {"",}, {"",}, {"",}, 
+      {"char",  TYPESPEC, RID_CHAR,},
       {"",}, 
-      {"static_cast",  STATIC_CAST, NORID,},
-      {"false",  CXX_FALSE, NORID,},
-      {"sizeof",  SIZEOF, NORID,},
-      {"or",  OROR, NORID,},
+      {"__asm__",  GCC_ASM_KEYWORD, NORID},
       {"double",  TYPESPEC, RID_DOUBLE,},
       {"",}, 
-      {"union",  AGGR, RID_UNION,},
-      {"char",  TYPESPEC, RID_CHAR,},
       {"struct",  AGGR, RID_RECORD,},
-      {"or_eq",  ASSIGN, NORID,},
-      {"enum",  ENUM, NORID,},
-      {"int",  TYPESPEC, RID_INT,},
-      {"const",  TYPE_QUAL, RID_CONST,},
-      {"static",  SCSPEC, RID_STATIC,},
       {"reinterpret_cast",  REINTERPRET_CAST, NORID,},
       {"",}, 
-      {"explicit",  SCSPEC, RID_EXPLICIT,},
-      {"__signed__",  TYPESPEC, RID_SIGNED},
-      {"if",  IF, NORID,},
-      {"__attribute",  ATTRIBUTE, NORID},
+      {"static_cast",  STATIC_CAST, NORID,},
+      {"",}, 
+      {"and",  ANDAND, NORID,},
+      {"typeof",  TYPEOF, NORID,},
+      {"switch",  SWITCH, NORID,},
+      {"",}, 
+      {"asm",  ASM_KEYWORD, NORID,},
+      {"",}, 
+      {"default",  DEFAULT, NORID,},
+      {"",}, 
+      {"mutable",  SCSPEC, RID_MUTABLE,},
       {"short",  TYPESPEC, RID_SHORT,},
-      {"__attribute__",  ATTRIBUTE, NORID},
-      {"bitor",  '|', NORID,},
       {"signature",  AGGR, RID_SIGNATURE       /* Extension */,},
+      {"const",  TYPE_QUAL, RID_CONST,},
+      {"static",  SCSPEC, RID_STATIC,},
+      {"",}, {"",}, 
+      {"for",  FOR, NORID,},
+      {"",}, {"",}, {"",}, 
+      {"void",  TYPESPEC, RID_VOID,},
+      {"bitand",  '&', NORID,},
+      {"protected",  VISSPEC, RID_PROTECTED,},
+      {"enum",  ENUM, NORID,},
+      {"int",  TYPESPEC, RID_INT,},
+      {"",}, {"",}, {"",}, 
+      {"float",  TYPESPEC, RID_FLOAT,},
       {"",}, 
-      {"__sigof__",  SIGOF, NORID              /* Extension */,},
-      {"volatile",  TYPE_QUAL, RID_VOLATILE,},
-      {"__label__",  LABEL, NORID},
-      {"do",  DO, NORID,},
+      {"__signed__",  TYPESPEC, RID_SIGNED},
+      {"dynamic_cast",  DYNAMIC_CAST, NORID,},
+      {"__attribute",  ATTRIBUTE, NORID},
       {"",}, 
+      {"__attribute__",  ATTRIBUTE, NORID},
       {"__asm",  GCC_ASM_KEYWORD, NORID},
-      {"protected",  VISSPEC, RID_PROTECTED,},
-      {"",}, 
-      {"float",  TYPESPEC, RID_FLOAT,},
-      {"using",  USING, NORID,},
       {"",}, 
       {"const_cast",  CONST_CAST, NORID,},
-      {"",}, 
-      {"void",  TYPESPEC, RID_VOID,},
-      {"break",  BREAK, NORID,},
-      {"namespace",  NAMESPACE, NORID,},
-      {"",}, {"",}, {"",}, {"",}, 
-      {"sigof",  SIGOF, NORID          /* Extension */,},
       {"",}, {"",}, {"",}, 
-      {"this",  THIS, NORID,},
-      {"",}, {"",}, {"",}, {"",}, 
-      {"and_eq",  ASSIGN, NORID,},
+      {"friend",  SCSPEC, RID_FRIEND,},
       {"",}, {"",}, {"",}, 
       {"signed",  TYPESPEC, RID_SIGNED,},
-      {"asm",  ASM_KEYWORD, NORID,},
-      {"",}, {"",}, {"",}, 
-      {"mutable",  SCSPEC, RID_MUTABLE,},
-      {"",}, {"",}, {"",}, 
-      {"__signed",  TYPESPEC, RID_SIGNED},
-      {"class",  AGGR, RID_CLASS,},
-      {"register",  SCSPEC, RID_REGISTER,},
-      {"",}, {"",}, {"",}, 
-      {"and",  ANDAND, NORID,},
-      {"",}, {"",}, {"",}, {"",}, 
-      {"long",  TYPESPEC, RID_LONG,},
-      {"default",  DEFAULT, NORID,},
-      {"operator",  OPERATOR, NORID,},
-      {"unsigned",  TYPESPEC, RID_UNSIGNED,},
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
-      {"inline",  SCSPEC, RID_INLINE,},
+      {"this",  THIS, NORID,},
+      {"__const",  TYPE_QUAL, RID_CONST},
+      {"__const__",  TYPE_QUAL, RID_CONST},
+      {"__volatile",  TYPE_QUAL, RID_VOLATILE},
+      {"__null",  CONSTANT, RID_NULL},
+      {"__volatile__",  TYPE_QUAL, RID_VOLATILE},
+      {"__typeof__",  TYPEOF, NORID},
+      {"or_eq",  ASSIGN, NORID,},
       {"",}, 
-      {"bitand",  '&', NORID,},
+      {"false",  CXX_FALSE, NORID,},
+      {"sizeof",  SIZEOF, NORID,},
+      {"long",  TYPESPEC, RID_LONG,},
+      {"or",  OROR, NORID,},
+      {"union",  AGGR, RID_UNION,},
+      {"__signature__",  AGGR, RID_SIGNATURE   /* Extension */,},
+      {"throw",  THROW, NORID,},
       {"",}, 
-      {"goto",  GOTO, NORID,},
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
-      {"dynamic_cast",  DYNAMIC_CAST, NORID,},
+      {"while",  WHILE, NORID,},
+      {"register",  SCSPEC, RID_REGISTER,},
+      {"__alignof__",  ALIGNOF, NORID},
+      {"class",  AGGR, RID_CLASS,},
+      {"typedef",  SCSPEC, RID_TYPEDEF,},
+      {"__signed",  TYPESPEC, RID_SIGNED},
+      {"",}, {"",}, 
+      {"unsigned",  TYPESPEC, RID_UNSIGNED,},
       {"",}, {"",}, {"",}, {"",}, {"",}, 
-      {"__signature__",  AGGR, RID_SIGNATURE   /* Extension */,},
+      {"__label__",  LABEL, NORID},
+      {"bitor",  '|', NORID,},
       {"",}, 
-      {"auto",  SCSPEC, RID_AUTO,},
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"do",  DO, NORID,},
+      {"volatile",  TYPE_QUAL, RID_VOLATILE,},
+      {"",}, {"",}, {"",}, {"",}, 
+      {"if",  IF, NORID,},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"__sigof__",  SIGOF, NORID              /* Extension */,},
       {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"",}, {"",}, {"",}, 
+      {"compl",  '~', NORID,},
+      {"public",  VISSPEC, RID_PUBLIC,},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"__typeof",  TYPEOF, NORID},
+      {"inline",  SCSPEC, RID_INLINE,},
       {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
       {"",}, {"",}, 
+      {"__alignof",  ALIGNOF, NORID},
+      {"",}, {"",}, {"",}, 
       {"overload",  OVERLOAD, NORID,},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"explicit",  SCSPEC, RID_EXPLICIT,},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"goto",  GOTO, NORID,},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"sigof",  SIGOF, NORID          /* Extension */,},
+      {"",}, 
+      {"virtual",  SCSPEC, RID_VIRTUAL,},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"bool",  TYPESPEC, RID_BOOL,},
+      {"",}, {"",}, {"",}, 
+      {"auto",  SCSPEC, RID_AUTO,},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"",}, {"",}, {"",}, 
+      {"operator",  OPERATOR, NORID,},
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
index 62e3909c86b12108127c4f293ecfe9aa35207446..1d49c409beaf43e56560d276267288810a9ca508 100644 (file)
@@ -1541,9 +1541,14 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
            {
              tree rval = build_type_conversion (CONVERT_EXPR, type, init, 1);
 
-             if (rval)
+             if (flag_ansi_overloading && rval)
+               {
+                 if (rval != error_mark_node)
+                   expand_aggr_init_1 (binfo, true_exp, exp, rval, alias_this, flags);
+                 return;
+               }
+             else if (rval)
                {
-#ifndef NEW_OVER
                  /* See if there is a constructor for``type'' that takes a
                     ``ttype''-typed object.  */
                  tree parms = build_tree_list (NULL_TREE, init);
@@ -1557,9 +1562,8 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
                    cp_error ("ambiguity between conversion to `%T' and constructor",
                              type);
                  else
-#endif
-                 if (rval != error_mark_node)
-                   expand_aggr_init_1 (binfo, true_exp, exp, rval, alias_this, flags);
+                   if (rval != error_mark_node)
+                     expand_aggr_init_1 (binfo, true_exp, exp, rval, alias_this, flags);
                  return;
                }
            }
index 56cf159cdc9b62dbbf8c41e4024c9d17734a0dee..66e00463e320f5e4a640079c65f14f43ac26834c 100644 (file)
@@ -673,6 +673,9 @@ init_lex ()
   TREE_TYPE (signature_type_node) = signature_type_node;
   ridpointers[(int) RID_SIGNATURE] = signature_type_node;
 
+  null_pointer_node = build_int_2 (0, 0);
+  ridpointers[RID_NULL] = null_pointer_node;
+
   opname_tab[(int) COMPONENT_REF] = "->";
   opname_tab[(int) MEMBER_REF] = "->*";
   opname_tab[(int) METHOD_CALL_EXPR] = "->()";
@@ -2561,7 +2564,7 @@ do_identifier (token, parsing)
       else if (IDENTIFIER_OPNAME_P (token))
        {
          if (token != ansi_opname[ERROR_MARK])
-           cp_error ("operator %O not defined", token);
+           cp_error ("`%D' not defined", token);
          id = error_mark_node;
        }
       else if (parsing && (yychar == '(' || yychar == LEFT_RIGHT))
index 1c20f596f9abddd16197cb68486eee71efea09f1..4a2c7d133d244865d67205470c782ca04b0c586a 100644 (file)
@@ -72,6 +72,7 @@ enum rid
   RID_EXCEPTION,
   RID_TEMPLATE,
   RID_SIGNATURE,
+  RID_NULL,
   /* Before adding enough to get up to 64, the RIDBIT_* macros
      will have to be changed a little.  */
   RID_MAX
index bb8a2046688a9071ea85e533be1eae050bb5c933..64563438e7e772bac25f8261cac3814943cac4f0 100644 (file)
@@ -674,7 +674,14 @@ build_overload_name (parmtypes, begin, end)
 
          if (TREE_USED (parmtype))
            {
+#if 0
+             /* We can turn this on at some point when we want
+                improved symbol mangling.  */
+             nrepeats++;
+#else
+             /* This is bug compatible with 2.7.x  */
              flush_repeats (parmtype);
+#endif
              goto next;
            }
 
@@ -1193,9 +1200,8 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
   int try_second;
   int binary_is_unary;
 
-#ifdef NEW_OVER
-  return build_new_op (code, flags, xarg1, xarg2, arg3);
-#endif
+  if (flag_ansi_overloading)
+    return build_new_op (code, flags, xarg1, xarg2, arg3);
 
   if (xarg1 == error_mark_node)
     return error_mark_node;
index d86e852f4010aa5ca1f032ff2bf2950f028ffc83..40a4582332e49962c56507c02e2d5dbbde029623 100644 (file)
@@ -1189,10 +1189,15 @@ instantiate_class_template (type)
       tree tmp;
       for (tmp = TYPE_FIELDS (type); tmp; tmp = TREE_CHAIN (tmp))
        if (TREE_CODE (tmp) == FIELD_DECL)
-         require_complete_type (tmp);
+         {
+           TREE_TYPE (tmp) = complete_type (TREE_TYPE (tmp));
+           require_complete_type (tmp);
+         }
 
       type = finish_struct_1 (type, 0);
       CLASSTYPE_GOT_SEMICOLON (type) = 1;
+      if (at_eof && TYPE_BINFO_VTABLE (type) != NULL_TREE)
+       finish_prevtable_vardecl (NULL, TYPE_BINFO_VTABLE (type));
 
       repo_template_used (type);
     }
@@ -2707,13 +2712,11 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts, strict)
       if (CLASSTYPE_TEMPLATE_INFO (parm) && uses_template_parms (parm))
        {
          tree t = NULL_TREE;
-#ifdef NEW_OVER
-         if (! strict)
+         if (flag_ansi_overloading && ! strict)
            t = get_template_base (CLASSTYPE_TI_TEMPLATE (parm), arg);
-         else
-#endif
-         if (CLASSTYPE_TEMPLATE_INFO (arg)
-             && CLASSTYPE_TI_TEMPLATE (parm) == CLASSTYPE_TI_TEMPLATE (arg))
+         else if
+           (CLASSTYPE_TEMPLATE_INFO (arg)
+            && CLASSTYPE_TI_TEMPLATE (parm) == CLASSTYPE_TI_TEMPLATE (arg))
            t = arg;
          if (! t || t == error_mark_node)
            return 1;
index ed7843329ec76b53339344a578dfef5315aa59e8..ebb692ddef70267d43abc9f5eeb18952d48b5cec 100644 (file)
@@ -3087,8 +3087,8 @@ build_mi_matrix (type)
   dfs_walk (binfo, dfs_number, unnumberedp);
 
   mi_size = CLASSTYPE_N_SUPERCLASSES (type) + CLASSTYPE_N_VBASECLASSES (type);
-  if (mi_size < cid)
-    mi_size = cid;
+  if (mi_size < (cid-1))
+    mi_size = cid-1;
   mi_matrix = (char *)xmalloc ((mi_size + 1) * (mi_size + 1));
   mi_type = type;
   bzero (mi_matrix, (mi_size + 1) * (mi_size + 1));
@@ -3551,6 +3551,7 @@ add_conversions (binfo)
        break;
       conversions = tree_cons (binfo, tmp, conversions);
     }
+  SET_BINFO_MARKED (binfo);
 }
 
 tree
@@ -3559,7 +3560,10 @@ lookup_conversions (type)
 {
   conversions = NULL_TREE;
   if (TYPE_SIZE (type))
-    dfs_walk (TYPE_BINFO (type), add_conversions, 0);
+    {
+      dfs_walk (TYPE_BINFO (type), add_conversions, unmarkedp);
+      dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp);
+    }
   return conversions;
 }
 
index 775e2c813181808edc0f8af2fb54f69ad3d0b7ac..a43443bd7fe370f13ab17e12e2bc954aeb970e6a 100644 (file)
@@ -135,6 +135,10 @@ complete_type (type)
       if (TYPE_SIZE (t) != NULL_TREE
          && current_template_parms == NULL_TREE)
        layout_type (type);
+      TYPE_NEEDS_CONSTRUCTING (type)
+       = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
+      TYPE_NEEDS_DESTRUCTOR (type)
+       = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t));
     }
   else if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
     instantiate_class_template (TYPE_MAIN_VARIANT (type));
@@ -771,7 +775,7 @@ comptypes (type1, type2, strict)
            {
              int rval;
            look_hard:
-             rval = t1 == t2 || UNIQUELY_DERIVED_FROM_P (t1, t2);
+             rval = t1 == t2 || DERIVED_FROM_P (t1, t2);
 
              if (rval)
                {
@@ -780,7 +784,7 @@ comptypes (type1, type2, strict)
                }
              if (strict < 0)
                {
-                 val = UNIQUELY_DERIVED_FROM_P (t2, t1);
+                 val = DERIVED_FROM_P (t2, t1);
                  break;
                }
            }
@@ -2239,8 +2243,12 @@ build_x_function_call (function, params, decl)
   /* Handle methods, friends, and overloaded functions, respectively.  */
   if (is_method)
     {
+      tree basetype = NULL_TREE;
+
       if (TREE_CODE (function) == FUNCTION_DECL)
        {
+         basetype = DECL_CLASS_CONTEXT (function);
+
          if (DECL_NAME (function))
            function = DECL_NAME (function);
          else
@@ -2249,6 +2257,7 @@ build_x_function_call (function, params, decl)
       else if (TREE_CODE (function) == TREE_LIST)
        {
          my_friendly_assert (TREE_CODE (TREE_VALUE (function)) == FUNCTION_DECL, 312);
+         basetype = DECL_CLASS_CONTEXT (TREE_VALUE (function));
          function = TREE_PURPOSE (function);
        }
       else if (TREE_CODE (function) != IDENTIFIER_NODE)
@@ -2276,6 +2285,10 @@ build_x_function_call (function, params, decl)
          must go through here in case it is a virtual function.
         @@ Perhaps this could be optimized.  */
 
+      if (basetype && (! current_class_type
+                      || ! DERIVED_FROM_P (basetype, current_class_type)))
+       return build_member_call (basetype, function, params);
+
       if (decl == NULL_TREE)
        {
          if (current_class_type == NULL_TREE)
@@ -2315,11 +2328,11 @@ build_x_function_call (function, params, decl)
        }
       else
        {
-#ifdef NEW_OVER
-         return build_new_function_call (function, params, NULL_TREE);
-#else
          tree val = TREE_VALUE (function);
 
+         if (flag_ansi_overloading)
+           return build_new_function_call (function, params, NULL_TREE);
+
          if (TREE_CODE (val) == TEMPLATE_DECL)
            return build_overload_call_real
              (function, params, LOOKUP_COMPLAIN, (struct candidate *)0, 0);
@@ -2328,7 +2341,6 @@ build_x_function_call (function, params, decl)
              (function, params, LOOKUP_COMPLAIN);
          else
            my_friendly_abort (360);
-#endif
        }
     }
 
@@ -2628,6 +2640,8 @@ build_function_call_real (function, params, require_complete, flags)
          return result;
        result = require_complete_type (result);
       }
+    if (IS_AGGR_TYPE (value_type))
+      result = build_cplus_new (value_type, result);
     return convert_from_reference (result);
   }
 }
@@ -2899,6 +2913,9 @@ build_x_binary_op (code, arg1, arg2)
   if (current_template_parms)
     return build_min_nt (code, arg1, arg2);
 
+  if (flag_ansi_overloading)
+    return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
+
   rval = build_opfncall (code, LOOKUP_SPECULATIVELY,
                         arg1, arg2, NULL_TREE);
   if (rval)
@@ -3955,11 +3972,23 @@ build_x_unary_op (code, xarg)
     /* don't look for a function */;
   else
     {
-      tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
-                                 NULL_TREE, NULL_TREE);
-      if (rval)
-       return build_opfncall (code, LOOKUP_NORMAL, xarg,
+      tree rval;
+
+      if (flag_ansi_overloading)
+       {
+         rval = build_new_op (code, LOOKUP_NORMAL, xarg,
                               NULL_TREE, NULL_TREE);
+         if (rval || code != ADDR_EXPR)
+           return rval;
+       }
+      else
+       {
+         rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
+                                NULL_TREE, NULL_TREE);
+         if (rval)
+           return build_opfncall (code, LOOKUP_NORMAL, xarg,
+                                  NULL_TREE, NULL_TREE);
+       }
     }
 
   if (code == ADDR_EXPR)
@@ -4629,6 +4658,9 @@ build_x_conditional_expr (ifexp, op1, op2)
   if (current_template_parms)
     return build_min_nt (COND_EXPR, ifexp, op1, op2);
 
+  if (flag_ansi_overloading)
+    return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
+
   /* See comments in `build_x_binary_op'.  */
   if (op1 != 0)
     rval = build_opfncall (COND_EXPR, LOOKUP_SPECULATIVELY, ifexp, op1, op2);
@@ -4723,6 +4755,15 @@ build_conditional_expr (ifexp, op1, op2)
       result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
       if (TREE_TYPE (result) != type1)
        result = build1 (NOP_EXPR, type1, result);
+      /* Expand both sides into the same slot,
+        hopefully the target of the ?: expression.  */
+      if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
+       {
+         tree slot = build (VAR_DECL, TREE_TYPE (result));
+         layout_decl (slot, 0);
+         result = build (TARGET_EXPR, TREE_TYPE (result),
+                         slot, result, NULL_TREE, NULL_TREE);
+       }
       return result;
     }
 
@@ -6093,12 +6134,7 @@ build_ptrmemfunc (type, pfn, force)
   if (TREE_CODE (pfn) == TREE_LIST
       || (TREE_CODE (pfn) == ADDR_EXPR
          && TREE_CODE (TREE_OPERAND (pfn, 0)) == TREE_LIST))
-    {
-      pfn = instantiate_type (type, pfn, 1);
-      if (pfn == error_mark_node)
-       return error_mark_node;
-      pfn = build_addr_func (pfn);
-    }
+    return instantiate_type (type, pfn, 1);
 
   /* Allow pointer to member conversions here.  */
   delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
@@ -6354,7 +6390,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
 
          if (TYPE_MAIN_VARIANT (ttl) != void_type_node
              && TYPE_MAIN_VARIANT (ttr) == void_type_node
-             && rhs != null_pointer_node)
+             && ! null_ptr_cst_p (rhs))
            {
              if (coder == RECORD_TYPE)
                cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
@@ -6545,9 +6581,8 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
          else
            cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
                        errtype, type, rhstype);
-         return convert (type, rhs);
        }
-      return null_pointer_node;
+      return convert (type, rhs);
     }
   else if (codel == INTEGER_TYPE
           && (coder == POINTER_TYPE
This page took 0.314387 seconds and 5 git commands to generate.