BSD 4_4_Lite2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Thu, 17 Dec 1992 22:28:21 +0000 (14:28 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Thu, 17 Dec 1992 22:28:21 +0000 (14:28 -0800)
Work on file usr/src/contrib/gcc-2.3.3/cp-call.c

Synthesized-from: CSRG/cd3/4.4BSD-Lite2

usr/src/contrib/gcc-2.3.3/cp-call.c [new file with mode: 0644]

diff --git a/usr/src/contrib/gcc-2.3.3/cp-call.c b/usr/src/contrib/gcc-2.3.3/cp-call.c
new file mode 100644 (file)
index 0000000..6274410
--- /dev/null
@@ -0,0 +1,2904 @@
+/* Functions related to invoking methods and overloaded functions.
+   Copyright (C) 1987, 1992 Free Software Foundation, Inc.
+   Contributed by Michael Tiemann (tiemann@cygnus.com)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+/* High-level class interface. */
+
+#include "config.h"
+#include "tree.h"
+#include <stdio.h>
+#include "cp-tree.h"
+#include "flags.h"
+#include "cp-class.h"
+
+#include "obstack.h"
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+extern void sorry ();
+
+extern tree build_function_call_maybe ();
+
+extern int inhibit_warnings;
+extern int flag_assume_nonnull_objects;
+extern tree ctor_label, dtor_label;
+
+/* From cp-typeck.c:  */
+extern tree unary_complex_lvalue ();
+
+/* Compute the ease with which a conversion can be performed
+   between an expected and the given type.  */
+static int convert_harshness ();
+
+#define EVIL_HARSHNESS(ARG) ((ARG) & 1)
+#define USER_HARSHNESS(ARG) ((ARG) & 2)
+#define CONTRAVARIANT_HARSHNESS(ARG) ((ARG) & 4)
+#define BASE_DERIVED_HARSHNESS(ARG) ((ARG) & 8)
+#define INT_TO_BD_HARSHNESS(ARG) (((ARG) << 4) | 8)
+#define INT_FROM_BD_HARSHNESS(ARG) ((ARG) >> 4)
+#define INT_TO_EASY_HARSHNESS(ARG) ((ARG) << 4)
+#define INT_FROM_EASY_HARSHNESS(ARG) ((ARG) >> 4)
+#define ONLY_EASY_HARSHNESS(ARG) (((ARG) & 15) == 0)
+#define CONST_HARSHNESS(ARG) ((ARG) & 1024)
+
+/* Ordering function for overload resolution.  */
+int
+rank_for_overload (x, y)
+     struct candidate *x, *y;
+{
+  if (y->evil - x->evil)
+    return y->evil - x->evil;
+  if (CONST_HARSHNESS (y->harshness[0]) ^ CONST_HARSHNESS (x->harshness[0]))
+    return y->harshness[0] - x->harshness[0];
+  if (y->user - x->user)
+    return y->user - x->user;
+  if (y->b_or_d - x->b_or_d)
+    return y->b_or_d - x->b_or_d;
+  return y->easy - x->easy;
+}
+
+/* TYPE is the type we wish to convert to.  PARM is the parameter
+   we have to work with.  We use a somewhat arbitrary cost function
+   to measure this conversion.  */
+static int
+convert_harshness (type, parmtype, parm)
+     register tree type, parmtype;
+     tree parm;
+{
+  register enum tree_code codel = TREE_CODE (type);
+  register enum tree_code coder = TREE_CODE (parmtype);
+
+#ifdef GATHER_STATISTICS
+  n_convert_harshness++;
+#endif
+
+  if (TYPE_MAIN_VARIANT (parmtype) == TYPE_MAIN_VARIANT (type))
+    return 0;
+
+  if (coder == ERROR_MARK)
+    return 1;
+
+  if (codel == POINTER_TYPE
+      && (coder == METHOD_TYPE || coder == FUNCTION_TYPE))
+    {
+      tree p1, p2;
+      int harshness, new_harshness;
+
+      /* Get to the METHOD_TYPE or FUNCTION_TYPE that this might be.  */
+      type = TREE_TYPE (type);
+
+      if (coder != TREE_CODE (type))
+       return 1;
+
+      harshness = 0;
+
+      /* We allow the default conversion between function type
+        and pointer-to-function type for free.  */
+      if (type == parmtype)
+       return 0;
+
+      /* Compare return types.  */
+      p1 = TREE_TYPE (type);
+      p2 = TREE_TYPE (parmtype);
+      new_harshness = convert_harshness (p1, p2, 0);
+      if (new_harshness & 1)
+       return 1;
+
+      if (BASE_DERIVED_HARSHNESS (new_harshness))
+       {
+         tree binfo;
+
+         /* This only works for pointers.  */
+         if (TREE_CODE (p1) != POINTER_TYPE
+             && TREE_CODE (p1) != REFERENCE_TYPE)
+           return 1;
+
+         p1 = TREE_TYPE (p1);
+         p2 = TREE_TYPE (p2);
+         if (CONTRAVARIANT_HARSHNESS (new_harshness))
+           binfo = get_binfo (p2, p1, 0);
+         else
+           binfo = get_binfo (p1, p2, 0);
+
+         if (! BINFO_OFFSET_ZEROP (binfo))
+           {
+             static int explained;
+             if (CONTRAVARIANT_HARSHNESS (new_harshness))
+               message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p2, p1);
+             else
+               message_2_types (sorry, "cannot cast `%d' to `%d' at function call site", p1, p2);
+
+             if (! explained++)
+               sorry ("(because pointer values change during conversion)");
+             return 1;
+           }
+       }
+
+      harshness |= new_harshness;
+
+      p1 = TYPE_ARG_TYPES (type);
+      p2 = TYPE_ARG_TYPES (parmtype);
+      while (p1 && p2)
+       {
+         new_harshness = convert_harshness (TREE_VALUE (p1), TREE_VALUE (p2), 0);
+         if (EVIL_HARSHNESS (new_harshness))
+           return 1;
+
+         if (BASE_DERIVED_HARSHNESS (new_harshness))
+           {
+             /* This only works for pointers and references. */
+             if (TREE_CODE (TREE_VALUE (p1)) != POINTER_TYPE
+                 && TREE_CODE (TREE_VALUE (p1)) != REFERENCE_TYPE)
+               return 1;
+             new_harshness ^= CONTRAVARIANT_HARSHNESS (new_harshness);
+             harshness |= new_harshness;
+           }
+         /* This trick allows use to accumulate easy type
+            conversions without messing up the bits that encode
+            info about more involved things.  */
+         else if (ONLY_EASY_HARSHNESS (new_harshness))
+           harshness += new_harshness;
+         else
+           harshness |= new_harshness;
+         p1 = TREE_CHAIN (p1);
+         p2 = TREE_CHAIN (p2);
+       }
+      if (p1 == p2)
+       return harshness;
+      if (p2)
+       return 1;
+      if (p1)
+       return harshness | (TREE_PURPOSE (p1) == NULL_TREE);
+    }
+  else if (codel == POINTER_TYPE && coder == OFFSET_TYPE)
+    {
+      int harshness;
+
+      /* Get to the OFFSET_TYPE that this might be.  */
+      type = TREE_TYPE (type);
+
+      if (coder != TREE_CODE (type))
+       return 1;
+
+      harshness = 0;
+
+      if (TYPE_OFFSET_BASETYPE (type) == TYPE_OFFSET_BASETYPE (parmtype))
+       harshness = 0;
+      else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (type),
+                              TYPE_OFFSET_BASETYPE (parmtype)))
+       harshness = INT_TO_BD_HARSHNESS (1);
+      else if (UNIQUELY_DERIVED_FROM_P (TYPE_OFFSET_BASETYPE (parmtype),
+                              TYPE_OFFSET_BASETYPE (type)))
+       harshness = CONTRAVARIANT_HARSHNESS (-1);
+      else
+       return 1;
+      /* Now test the OFFSET_TYPE's target compatibility.  */
+      type = TREE_TYPE (type);
+      parmtype = TREE_TYPE (parmtype);
+    }
+
+  if (coder == UNKNOWN_TYPE)
+    {
+      if (codel == FUNCTION_TYPE
+         || codel == METHOD_TYPE
+         || (codel == POINTER_TYPE
+             && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+                 || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)))
+       return 0;
+      return 1;
+    }
+
+  if (coder == VOID_TYPE)
+    return 1;
+
+  if (codel == ENUMERAL_TYPE || codel == INTEGER_TYPE)
+    {
+      /* Control equivalence of ints an enums.  */
+
+      if (codel == ENUMERAL_TYPE
+         && flag_int_enum_equivalence == 0)
+       {
+         /* Enums can be converted to ints, but not vice-versa.  */
+         if (coder != ENUMERAL_TYPE
+             || TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (parmtype))
+           return 1;
+       }
+
+      /* else enums and ints (almost) freely interconvert.  */
+
+      if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE)
+       {
+         int easy = TREE_UNSIGNED (type) ^ TREE_UNSIGNED (parmtype);
+         if (codel != coder)
+           easy += 1;
+         if (TYPE_MODE (type) != TYPE_MODE (parmtype))
+           easy += 2;
+         return INT_TO_EASY_HARSHNESS (easy);
+       }
+      else if (coder == REAL_TYPE)
+       return INT_TO_EASY_HARSHNESS (4);
+    }
+
+  if (codel == REAL_TYPE)
+    if (coder == REAL_TYPE)
+      /* Shun converting between float and double if a choice exists.  */
+      {
+       if (TYPE_MODE (type) != TYPE_MODE (parmtype))
+         return INT_TO_EASY_HARSHNESS (2);
+       return 0;
+      }
+    else if (coder == INTEGER_TYPE || coder == ENUMERAL_TYPE)
+      return INT_TO_EASY_HARSHNESS (4);
+
+  /* convert arrays which have not previously been converted.  */
+  if (codel == ARRAY_TYPE)
+    codel = POINTER_TYPE;
+  if (coder == ARRAY_TYPE)
+    coder = POINTER_TYPE;
+
+  /* Conversions among pointers */
+  if (codel == POINTER_TYPE && coder == POINTER_TYPE)
+    {
+      register tree ttl = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+      register tree ttr = TYPE_MAIN_VARIANT (TREE_TYPE (parmtype));
+      int penalty = 4 * (ttl != ttr);
+      /* Anything converts to void *.  void * converts to anything.
+        Since these may be `const void *' (etc.) use VOID_TYPE
+        instead of void_type_node.
+        Otherwise, the targets must be the same,
+        except that we do allow (at some cost) conversion
+        between signed and unsinged pointer types.  */
+
+      if ((TREE_CODE (ttl) == METHOD_TYPE
+          || TREE_CODE (ttl) == FUNCTION_TYPE)
+         && TREE_CODE (ttl) == TREE_CODE (ttr))
+       {
+         if (comptypes (ttl, ttr, -1))
+           return INT_TO_EASY_HARSHNESS (penalty);
+         return 1;
+       }
+
+      if (!(TREE_CODE (ttl) == VOID_TYPE
+           || TREE_CODE (ttr) == VOID_TYPE
+           || (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (ttr)
+               && (ttl = unsigned_type (ttl),
+                   ttr = unsigned_type (ttr),
+                   penalty = 10, 0))
+           || (comp_target_types (ttl, ttr, 0))))
+       return 1;
+
+      if (penalty == 10)
+       return INT_TO_EASY_HARSHNESS (10);
+      if (ttr == ttl)
+       return INT_TO_BD_HARSHNESS (0);
+
+      if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
+       {
+         int b_or_d = get_base_distance (ttl, ttr, 0, 0);
+         if (b_or_d < 0)
+           {
+             b_or_d = get_base_distance (ttr, ttl, 0, 0);
+             if (b_or_d < 0)
+               return 1;
+             return CONTRAVARIANT_HARSHNESS (-1);
+           }
+         return INT_TO_BD_HARSHNESS (b_or_d);
+       }
+      /* If converting from a `class*' to a `void*', make it
+        less favorable than any inheritance relationship.  */
+      if (TREE_CODE (ttl) == VOID_TYPE && IS_AGGR_TYPE (ttr))
+       return INT_TO_BD_HARSHNESS (CLASSTYPE_MAX_DEPTH (ttr)+1);
+      return INT_TO_EASY_HARSHNESS (penalty);
+    }
+
+  if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
+    {
+      /* This is not a bad match, but don't let it beat
+        integer-enum combinations.  */
+      if (parm && integer_zerop (parm))
+       return INT_TO_EASY_HARSHNESS (4);
+    }
+
+  /* C++: one of the types must be a reference type.  */
+  {
+    tree ttl, ttr;
+    register tree intype = TYPE_MAIN_VARIANT (parmtype);
+    register enum tree_code form = TREE_CODE (intype);
+    int penalty;
+
+    if (codel == REFERENCE_TYPE || coder == REFERENCE_TYPE)
+      {
+       ttl = TYPE_MAIN_VARIANT (type);
+
+       if (codel == REFERENCE_TYPE)
+         {
+           ttl = TREE_TYPE (ttl);
+
+           /* When passing a non-const argument into a const reference,
+              dig it a little, so a non-const reference is preferred over
+              this one. (mrs) */
+           if (TREE_READONLY (ttl) && ! TREE_READONLY (parm))
+             penalty = 2;
+           else
+             penalty = 0;
+
+           ttl = TYPE_MAIN_VARIANT (ttl);
+
+           if (form == OFFSET_TYPE)
+             {
+               intype = TREE_TYPE (intype);
+               form = TREE_CODE (intype);
+             }
+
+           if (form == REFERENCE_TYPE)
+             {
+               intype = TYPE_MAIN_VARIANT (TREE_TYPE (intype));
+
+               if (ttl == intype)
+                 return 0;
+               penalty = 2;
+             }
+           else
+             {
+               /* Can reference be built up?  */
+               if (ttl == intype && penalty == 0) {
+                 /* Becuase the READONLY bits are not always in the type,
+                    this extra check is necessary.  The problem should
+                    be fixed someplace else, and this extra code removed.
+
+                    Also, if type if a reference, the readonly bits could
+                    either be in the outer type (with reference) or on the
+                    inner type (the thing being referenced).  (mrs)  */
+                 if (TREE_READONLY (parm)
+                     && ! (TYPE_READONLY (type)
+                           || (TREE_CODE (type) == REFERENCE_TYPE
+                               && TYPE_READONLY (TREE_TYPE (type)))))
+                   penalty = 2;
+                 else
+                   return 0;
+               }
+               else
+                 penalty = 2;
+             }
+         }
+       else if (form == REFERENCE_TYPE)
+         {
+           if (parm)
+             {
+               tree tmp = convert_from_reference (parm);
+               intype = TYPE_MAIN_VARIANT (TREE_TYPE (tmp));
+             }
+           else
+             {
+               intype = parmtype;
+               do
+                 {
+                   intype = TREE_TYPE (intype);
+                 }
+               while (TREE_CODE (intype) == REFERENCE_TYPE);
+               intype = TYPE_MAIN_VARIANT (intype);
+             }
+
+           if (ttl == intype)
+             return 0;
+           else
+             penalty = 2;
+         }
+
+       if (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (intype))
+         {
+           ttl = unsigned_type (ttl);
+           intype = unsigned_type (intype);
+           penalty += 2;
+         }
+
+       ttr = intype;
+
+       /* If the initializer is not an lvalue, then it does not
+          matter if we make life easier for the programmer
+          by creating a temporary variable with which to
+          hold the result.  */
+       if (parm && (coder == INTEGER_TYPE
+                    || coder == ENUMERAL_TYPE
+                    || coder == REAL_TYPE)
+           && ! lvalue_p (parm))
+         return (convert_harshness (ttl, ttr, 0)
+                 | INT_TO_EASY_HARSHNESS (penalty));
+
+       if (ttl == ttr)
+         {
+           if (penalty)
+             return INT_TO_EASY_HARSHNESS (penalty);
+           return INT_TO_BD_HARSHNESS (0);
+         }
+
+       /* Pointers to voids always convert for pointers.  But
+          make them less natural than more specific matches.  */
+       if (TREE_CODE (ttl) == POINTER_TYPE && TREE_CODE (ttr) == POINTER_TYPE)
+         if (TREE_TYPE (ttl) == void_type_node
+             || TREE_TYPE (ttr) == void_type_node)
+           return INT_TO_EASY_HARSHNESS (penalty+1);
+
+       if (parm && codel != REFERENCE_TYPE)
+         return (convert_harshness (ttl, ttr, 0)
+                 | INT_TO_EASY_HARSHNESS (penalty));
+
+       /* Here it does matter.  If this conversion is from
+          derived to base, allow it.  Otherwise, types must
+          be compatible in the strong sense.  */
+       if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
+         {
+           int b_or_d = get_base_distance (ttl, ttr, 0, 0);
+           if (b_or_d < 0)
+             {
+               b_or_d = get_base_distance (ttr, ttl, 0, 0);
+               if (b_or_d < 0)
+                 return 1;
+               return CONTRAVARIANT_HARSHNESS (-1);
+             }
+           /* Say that this conversion is relatively painless.
+              If it turns out that there is a user-defined X(X&)
+              constructor, then that will be invoked, but that's
+              preferable to dealing with other user-defined conversions
+              that may produce surprising results.  */
+           return INT_TO_BD_HARSHNESS (b_or_d);
+         }
+
+       if (comp_target_types (ttl, intype, 1))
+         return INT_TO_EASY_HARSHNESS (penalty);
+      }
+  }
+  if (codel == RECORD_TYPE && coder == RECORD_TYPE)
+    {
+      int b_or_d = get_base_distance (type, parmtype, 0, 0);
+      if (b_or_d < 0)
+       {
+         b_or_d = get_base_distance (parmtype, type, 0, 0);
+         if (b_or_d < 0)
+           return 1;
+         return CONTRAVARIANT_HARSHNESS (-1);
+       }
+      return INT_TO_BD_HARSHNESS (b_or_d);
+    }
+  return 1;
+}
+
+/* Algorithm: Start out with no strikes against.  For each argument
+   which requires a (subjective) hard conversion (such as between
+   floating point and integer), issue a strike.  If there are the same
+   number of formal and actual parameters in the list, there will be at
+   least on strike, otherwise an exact match would have been found.  If
+   there are not the same number of arguments in the type lists, we are
+   not dead yet: a `...' means that we can have more parms then were
+   declared, and if we wind up in the default argument section of the
+   list those can be used as well.  If an exact match could be found for
+   one of those cases, return it immediately.  Otherwise, rank the fields
+   so that fields with fewer strikes are tried first.
+
+   Conversions between builtin and user-defined types are allowed, but
+   no function involving such a conversion is preferred to one which
+   does not require such a conversion.  Furthermore, such conversions
+   must be unique.  */
+
+void
+compute_conversion_costs (function, tta_in, cp, arglen)
+     tree function;
+     tree tta_in;
+     struct candidate *cp;
+     int arglen;
+{
+  tree ttf_in = TYPE_ARG_TYPES (TREE_TYPE (function));
+  tree ttf = ttf_in;
+  tree tta = tta_in;
+
+  /* Start out with no strikes against.  */
+  int evil_strikes = 0;
+  int user_strikes = 0;
+  int b_or_d_strikes = 0;
+  int easy_strikes = 0;
+
+  int strike_index = 0, win, lose;
+
+#ifdef GATHER_STATISTICS
+  n_compute_conversion_costs++;
+#endif
+
+  cp->function = function;
+  cp->arg = tta ? TREE_VALUE (tta) : NULL_TREE;
+  cp->u.bad_arg = 0;           /* optimistic!  */
+
+  bzero (cp->harshness, (arglen+1) * sizeof (short));
+
+  while (ttf && tta)
+    {
+      int harshness;
+
+      if (ttf == void_list_node)
+       break;
+
+      if (type_unknown_p (TREE_VALUE (tta)))
+       {         
+         /* Must perform some instantiation here.  */
+         tree rhs = TREE_VALUE (tta);
+         tree lhstype = TREE_VALUE (ttf);
+
+         /* Keep quiet about possible contravariance violations.  */
+         int old_inhibit_warnings = inhibit_warnings;
+         inhibit_warnings = 1;
+
+         /* @@ This is to undo what `grokdeclarator' does to
+            parameter types.  It really should go through
+            something more general.  */
+
+         TREE_TYPE (tta) = unknown_type_node;
+         rhs = instantiate_type (lhstype, rhs, 0);
+         inhibit_warnings = old_inhibit_warnings;
+
+         if (TREE_CODE (rhs) == ERROR_MARK)
+           harshness = 1;
+         else
+           {
+             harshness = convert_harshness (lhstype, TREE_TYPE (rhs), rhs);
+             /* harshness |= 2; */
+           }
+       }
+      else
+       harshness = convert_harshness (TREE_VALUE (ttf), TREE_TYPE (TREE_VALUE (tta)), TREE_VALUE (tta));
+
+      cp->harshness[strike_index] = harshness;
+      if (EVIL_HARSHNESS (harshness)
+         || CONTRAVARIANT_HARSHNESS (harshness))
+       {
+         cp->u.bad_arg = strike_index;
+         evil_strikes = 1;
+       }
+#if 0
+      /* This is never set by `convert_harshness'.  */
+      else if (USER_HARSHNESS (harshness))
+       {
+         user_strikes += 1;
+       }
+#endif
+      else if (BASE_DERIVED_HARSHNESS (harshness))
+       {
+         b_or_d_strikes += INT_FROM_BD_HARSHNESS (harshness);
+       }
+      else
+       easy_strikes += INT_FROM_EASY_HARSHNESS (harshness);
+      ttf = TREE_CHAIN (ttf);
+      tta = TREE_CHAIN (tta);
+      strike_index += 1;
+    }
+
+  if (tta)
+    {
+      /* ran out of formals, and parmlist is fixed size.  */
+      if (ttf /* == void_type_node */)
+       {
+         cp->evil = 1;
+         cp->u.bad_arg = -1;
+         return;
+       }
+    }
+  else if (ttf && ttf != void_list_node)
+    {
+      /* ran out of actuals, and no defaults.  */
+      if (TREE_PURPOSE (ttf) == NULL_TREE)
+       {
+         cp->evil = 1;
+         cp->u.bad_arg = -2;
+         return;
+       }
+      /* Store index of first default.  */
+      cp->harshness[arglen] = strike_index+1;
+    }
+  else cp->harshness[arglen] = 0;
+
+  /* Argument list lengths work out, so don't need to check them again.  */
+  if (evil_strikes)
+    {
+      /* We do not check for derived->base conversions here, since in
+        no case would they give evil strike counts, unless such conversions
+        are somehow ambiguous.  */
+
+      /* See if any user-defined conversions apply.
+         But make sure that we do not loop.  */
+      static int dont_convert_types = 0;
+
+      if (dont_convert_types)
+       {
+         cp->evil = 1;
+         return;
+       }
+
+      win = 0;                 /* Only get one chance to win.  */
+      ttf = TYPE_ARG_TYPES (TREE_TYPE (function));
+      tta = tta_in;
+      strike_index = 0;
+      evil_strikes = 0;
+
+      while (ttf && tta)
+       {
+         if (ttf == void_list_node)
+           break;
+
+         lose = cp->harshness[strike_index];
+         if (EVIL_HARSHNESS (lose)
+             || CONTRAVARIANT_HARSHNESS (lose))
+           {
+             tree actual_type = TREE_TYPE (TREE_VALUE (tta));
+             tree formal_type = TREE_VALUE (ttf);
+
+             dont_convert_types = 1;
+
+             if (TREE_CODE (formal_type) == REFERENCE_TYPE)
+               formal_type = TREE_TYPE (formal_type);
+             if (TREE_CODE (actual_type) == REFERENCE_TYPE)
+               actual_type = TREE_TYPE (actual_type);
+
+             if (formal_type != error_mark_node
+                 && actual_type != error_mark_node)
+               {
+                 formal_type = TYPE_MAIN_VARIANT (formal_type);
+                 actual_type = TYPE_MAIN_VARIANT (actual_type);
+
+                 if (TYPE_HAS_CONSTRUCTOR (formal_type))
+                   {
+                     /* If it has a constructor for this type, try to use it.  */
+                     if (convert_to_aggr (formal_type, TREE_VALUE (tta), 0, 1)
+                         != error_mark_node)
+                       {
+                         /* @@ There is no way to save this result yet.
+                            @@ So success is NULL_TREE for now.  */
+                         win++;
+                       }
+                   }
+                 if (TYPE_LANG_SPECIFIC (actual_type) && TYPE_HAS_CONVERSION (actual_type))
+                   {
+                     if (TREE_CODE (formal_type) == INTEGER_TYPE
+                         && TYPE_HAS_INT_CONVERSION (actual_type))
+                       win++;
+                     else if (TREE_CODE (formal_type) == REAL_TYPE
+                              && TYPE_HAS_REAL_CONVERSION (actual_type))
+                       win++;
+                     else
+                       {
+                         tree conv = build_type_conversion (CALL_EXPR, TREE_VALUE (ttf), TREE_VALUE (tta), 0);
+                         if (conv)
+                           {
+                             if (conv == error_mark_node)
+                               win += 2;
+                             else
+                               win++;
+                           }
+                         else if (TREE_CODE (TREE_VALUE (ttf)) == REFERENCE_TYPE)
+                           {
+                             conv = build_type_conversion (CALL_EXPR, formal_type, TREE_VALUE (tta), 0);
+                             if (conv)
+                               {
+                                 if (conv == error_mark_node)
+                                   win += 2;
+                                 else
+                                   win++;
+                               }
+                           }
+                       }
+                   }
+               }
+             dont_convert_types = 0;
+
+             if (win == 1)
+               {
+                 user_strikes += 1;
+                 cp->harshness[strike_index] = USER_HARSHNESS (-1);
+                 win = 0;
+               }
+             else
+               {
+                 if (cp->u.bad_arg > strike_index)
+                   cp->u.bad_arg = strike_index;
+
+                 evil_strikes = win ? 2 : 1;
+                 break;
+               }
+           }
+
+         ttf = TREE_CHAIN (ttf);
+         tta = TREE_CHAIN (tta);
+         strike_index += 1;
+       }
+    }
+
+  /* Const member functions get a small penalty because defaulting
+     to const is less useful than defaulting to non-const. */
+  /* This is bogus, it does not correspond to anything in the ARM.
+     This code will be fixed when this entire section is rewritten
+     to conform to the ARM.  (mrs)  */
+  if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
+    {
+      if (TYPE_READONLY (TREE_TYPE (TREE_VALUE (ttf_in))))
+       {
+         cp->harshness[0] += INT_TO_EASY_HARSHNESS (1);
+         ++easy_strikes;
+       }
+      else
+       {
+         /* Calling a non-const member function from a const member function
+            is probably invalid, but for now we let it only draw a warning.
+            We indicate that such a mismatch has occurred by setting the
+            harshness to a maximum value.  */
+         if (TREE_CODE (TREE_TYPE (TREE_VALUE (tta_in))) == POINTER_TYPE
+             && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (TREE_VALUE (tta_in))))))
+           cp->harshness[0] |= CONST_HARSHNESS (-1);
+       }
+    }
+
+  cp->evil = evil_strikes;
+  cp->user = user_strikes;
+  cp->b_or_d = b_or_d_strikes;
+  cp->easy = easy_strikes;
+}
+
+/* When one of several possible overloaded functions and/or methods
+   can be called, choose the best candidate for overloading.
+
+   BASETYPE is the context from which we start method resolution
+   or NULL if we are comparing overloaded functions.
+   CANDIDATES is the array of candidates we have to choose from.
+   N_CANDIDATES is the length of CANDIDATES.
+   PARMS is a TREE_LIST of parameters to the function we'll ultimately
+   choose.  It is modified in place when resolving methods.  It is not
+   modified in place when resolving overloaded functions.
+   LEN is the length of the parameter list.  */
+
+static struct candidate *
+ideal_candidate (basetype, candidates, n_candidates, parms, len)
+     tree basetype;
+     struct candidate *candidates;
+     int n_candidates;
+     tree parms;
+     int len;
+{
+  struct candidate *cp = candidates + n_candidates;
+  int index, i;
+  tree ttf;
+
+  qsort (candidates,           /* char *base */
+        n_candidates,          /* int nel */
+        sizeof (struct candidate), /* int width */
+        rank_for_overload);    /* int (*compar)() */
+
+  /* If the best candidate requires user-defined conversions,
+     and its user-defined conversions are a strict subset
+     of all other candidates requiring user-defined conversions,
+     then it is, in fact, the best.  */
+  for (i = -1; cp + i != candidates; i--)
+    if (cp[i].user == 0)
+      break;
+
+  if (i < -1)
+    {
+      tree ttf0;
+
+      /* Check that every other candidate requires those conversions
+        as a strict subset of their conversions.  */
+      if (cp[i].user == cp[-1].user)
+       goto non_subset;
+
+      /* Look at subset relationship more closely.  */
+      while (i != -1)
+       {
+         for (ttf = TYPE_ARG_TYPES (TREE_TYPE (cp[i].function)),
+              ttf0 = TYPE_ARG_TYPES (TREE_TYPE (cp[-1].function)),
+              index = 0;
+              index < len;
+              ttf = TREE_CHAIN (ttf), ttf0 = TREE_CHAIN (ttf0), index++)
+           if (USER_HARSHNESS (cp[i].harshness[index]))
+             {
+               /* If our "best" candidate also needs a conversion,
+                  it must be the same one.  */
+               if (USER_HARSHNESS (cp[-1].harshness[index])
+                   && TREE_VALUE (ttf) != TREE_VALUE (ttf0))
+                 goto non_subset;
+             }
+         i++;
+       }
+      /* The best was the best.  */
+      return cp - 1;
+    non_subset:
+      /* Use other rules for determining "bestness".  */
+      ;
+    }
+
+  /* If the best two candidates we find require user-defined
+     conversions, we may need to report and error message.  */
+  if (cp[-1].user && cp[-2].user
+      && (cp[-1].b_or_d || cp[-2].b_or_d == 0))
+    {
+      /* If the best two methods found involved user-defined
+        type conversions, then we must see whether one
+        of them is exactly what we wanted.  If not, then
+        we have an ambiguity.  */
+      int best = 0;
+      tree tta = parms;
+      tree f1, p1;
+
+      /* Stash all of our parameters in safe places
+        so that we can perform type conversions in place.  */
+      while (tta)
+       {
+         TREE_PURPOSE (tta) = TREE_VALUE (tta);
+         tta = TREE_CHAIN (tta);
+       }
+
+      i = 0;
+      do
+       {
+         int exact_conversions = 0;
+
+         i -= 1;
+         tta = parms;
+         if (DECL_STATIC_FUNCTION_P (cp[i].function))
+           tta = TREE_CHAIN (tta);
+         /* special note, we don't go through len parameters, because we
+            may only need len-1 parameters because of a call to a static
+            member. */
+         for (ttf = TYPE_ARG_TYPES (TREE_TYPE (cp[i].function)), index = 0;
+              tta;
+              tta = TREE_CHAIN (tta), ttf = TREE_CHAIN (ttf), index++)
+           {
+             if (USER_HARSHNESS (cp[i].harshness[index]))
+               {
+                 tree this_parm = build_type_conversion (CALL_EXPR, TREE_VALUE (ttf), TREE_PURPOSE (tta), 2);
+                 if (basetype != NULL_TREE)
+                   TREE_VALUE (tta) = this_parm;
+                 if (this_parm)
+                   {
+                     if (TREE_CODE (this_parm) != CONVERT_EXPR
+                         && (TREE_CODE (this_parm) != NOP_EXPR
+                             || comp_target_types (TREE_TYPE (this_parm),
+                                                   TREE_TYPE (TREE_OPERAND (this_parm, 0)), 1)))
+                       exact_conversions += 1;
+                   }
+                 else if (PROMOTES_TO_AGGR_TYPE (TREE_VALUE (ttf), REFERENCE_TYPE))
+                   {
+                     /* To get here we had to have succeeded via
+                        a constructor.  */
+                     TREE_VALUE (tta) = TREE_PURPOSE (tta);
+                     exact_conversions += 1;
+                   }
+               }
+           }
+         if (exact_conversions == cp[i].user)
+           {
+             if (best == 0)
+               {
+                 best = i;
+                 f1 = cp[best].function;
+                 p1 = TYPE_ARG_TYPES (TREE_TYPE (f1));
+               }
+             else
+               {
+                 /* Don't complain if next best is from base class.  */
+                 tree f2 = cp[i].function;
+
+                 if (TREE_CODE (TREE_TYPE (f1)) == METHOD_TYPE
+                     && TREE_CODE (TREE_TYPE (f2)) == METHOD_TYPE
+                     && BASE_DERIVED_HARSHNESS (cp[i].harshness[0])
+                     && cp[best].harshness[0] < cp[i].harshness[0])
+                   {
+#if 0
+                     tree p2 = TYPE_ARG_TYPES (TREE_TYPE (f2));
+                     /* For LUCID.  */
+                     if (! compparms (TREE_CHAIN (p1), TREE_CHAIN (p2), 1))
+                       goto ret0;
+                     else
+#endif
+                       continue;
+                   }
+                 else
+                   {
+                     /* Ensure that there's nothing ambiguous about these
+                        two fns.  */
+                     int identical = 1;
+                     for (index = 0; index < len; index++)
+                       {
+                         /* Type conversions must be piecewise equivalent.  */
+                         if (USER_HARSHNESS (cp[best].harshness[index])
+                             != USER_HARSHNESS (cp[i].harshness[index]))
+                           goto ret0;
+                         /* If there's anything we like better about the
+                            other function, consider it ambiguous.  */
+                         if (cp[i].harshness[index] < cp[best].harshness[index])
+                           goto ret0;
+                         /* If any single one it diffent, then the whole is
+                            not identical.  */
+                         if (cp[i].harshness[index] != cp[best].harshness[index])
+                           identical = 0;
+                       }
+
+                     /* If we can't tell the difference between the two, it
+                        is ambiguous.  */
+                     if (identical)
+                       goto ret0;
+
+                     /* If we made it to here, it means we're satisfied that
+                        BEST is still best.  */
+                     continue;
+                   }
+               }
+           }
+       } while (cp + i != candidates);
+
+      if (best)
+       {
+         int exact_conversions = cp[best].user;
+         tta = parms;
+         if (DECL_STATIC_FUNCTION_P (cp[best].function))
+           tta = TREE_CHAIN (parms);
+         for (ttf = TYPE_ARG_TYPES (TREE_TYPE (cp[best].function)), index = 0;
+              exact_conversions > 0;
+              tta = TREE_CHAIN (tta), ttf = TREE_CHAIN (ttf), index++)
+           {
+             if (USER_HARSHNESS (cp[best].harshness[index]))
+               {
+                 /* We must now fill in the slot we left behind.
+                    @@ This could be optimized to use the value previously
+                    @@ computed by build_type_conversion in some cases.  */
+                 if (basetype != NULL_TREE)
+                   TREE_VALUE (tta) = convert (TREE_VALUE (ttf), TREE_PURPOSE (tta));
+                 exact_conversions -= 1;
+               }
+             else TREE_VALUE (tta) = TREE_PURPOSE (tta);
+           }
+         return cp + best;
+       }
+      goto ret0;
+    }
+  /* If the best two candidates we find both use default parameters,
+     we may need to report and error.  Don't need to worry if next-best
+     candidate is forced to use user-defined conversion when best is not.  */
+  if (cp[-2].user == 0
+      && cp[-1].harshness[len] != 0 && cp[-2].harshness[len] != 0)
+    {
+      tree tt1 = TYPE_ARG_TYPES (TREE_TYPE (cp[-1].function));
+      tree tt2 = TYPE_ARG_TYPES (TREE_TYPE (cp[-2].function));
+      unsigned i = cp[-1].harshness[len];
+
+      if (cp[-2].harshness[len] < i)
+       i = cp[-2].harshness[len];
+      while (--i > 0)
+       {
+         if (TYPE_MAIN_VARIANT (TREE_VALUE (tt1))
+             != TYPE_MAIN_VARIANT (TREE_VALUE (tt2)))
+           /* These lists are not identical, so we can choose our best candidate.  */
+           return cp - 1;
+         tt1 = TREE_CHAIN (tt1);
+         tt2 = TREE_CHAIN (tt2);
+       }
+      /* To get here, both lists had the same parameters up to the defaults
+        which were used.  This is an ambiguous request.  */
+      goto ret0;
+    }
+
+  /* Otherwise, return our best candidate.  Note that if we get candidates
+     from independent base classes, we have an ambiguity, even if one
+     argument list look a little better than another one.  */
+  if (cp[-1].b_or_d && basetype && TYPE_USES_MULTIPLE_INHERITANCE (basetype))
+    {
+      int i = n_candidates - 1, best = i;
+      tree base1 = NULL_TREE;
+
+      if (TREE_CODE (TREE_TYPE (candidates[i].function)) == FUNCTION_TYPE)
+       return cp - 1;
+
+      for (; i >= 0 && candidates[i].user == 0 && candidates[i].evil == 0; i--)
+       {
+         if (TREE_CODE (TREE_TYPE (candidates[i].function)) == METHOD_TYPE)
+           {
+             tree newbase = DECL_CLASS_CONTEXT (candidates[i].function);
+
+             if (base1 != NULL_TREE)
+               {
+                 /* newbase could be a base or a parent of base1 */
+                 if (newbase != base1 && ! UNIQUELY_DERIVED_FROM_P (newbase, base1)
+                     && ! UNIQUELY_DERIVED_FROM_P (base1, newbase))
+                   {
+                     error_with_aggr_type (basetype, "ambiguous request for function from distinct base classes of type `%s'");
+                     error ("first candidate is `%s'",
+                            fndecl_as_string (0, candidates[best].function, 1));
+                     error ("second candidate is `%s'",
+                            fndecl_as_string (0, candidates[i].function, 1));
+                     cp[-1].evil = 1;
+                     return cp - 1;
+                   }
+               }
+             else
+               {
+                 best = i;
+                 base1 = newbase;
+               }
+           }
+         else return cp - 1;
+       }
+    }
+
+  /* Don't accept a candidate as being ideal if it's indistinguishable
+     from another candidate.  */
+  if (rank_for_overload (cp-1, cp-2) == 0)
+    {
+      /* If the types are distinguishably different (like
+        `long' vs. `unsigned long'), that's ok.  But if they are arbitrarily
+        different, such as `int (*)(void)' vs. `void (*)(int)',
+        that's not ok.  */
+      tree p1 = TYPE_ARG_TYPES (TREE_TYPE (cp[-1].function));
+      tree p2 = TYPE_ARG_TYPES (TREE_TYPE (cp[-2].function));
+      while (p1 && p2)
+       {
+         if (TREE_CODE (TREE_VALUE (p1)) == POINTER_TYPE
+             && TREE_CODE (TREE_TYPE (TREE_VALUE (p1))) == FUNCTION_TYPE
+             && TREE_VALUE (p1) != TREE_VALUE (p2))
+           return 0;
+         p1 = TREE_CHAIN (p1);
+         p2 = TREE_CHAIN (p2);
+       }
+      if (p1 || p2)
+       return 0;
+    }
+
+  return cp - 1;
+
+ ret0:
+  /* In the case where there is no ideal candidate, restore
+     TREE_VALUE slots of PARMS from TREE_PURPOSE slots.  */
+  while (parms)
+    {
+      TREE_VALUE (parms) = TREE_PURPOSE (parms);
+      parms = TREE_CHAIN (parms);
+    }
+  return 0;
+}
+
+/* Assume that if the class referred to is not in the
+   current class hierarchy, that it may be remote.
+   PARENT is assumed to be of aggregate type here.  */
+static int
+may_be_remote (parent)
+     tree parent;
+{
+  if (TYPE_OVERLOADS_METHOD_CALL_EXPR (parent) == 0)
+    return 0;
+
+  if (current_class_type == NULL_TREE)
+    return 0;
+  if (parent == current_class_type)
+    return 0;
+
+  if (UNIQUELY_DERIVED_FROM_P (parent, current_class_type))
+    return 0;
+  return 1;
+}
+
+#ifdef ESKIT
+/* Return the number of bytes that the arglist in PARMS would
+   occupy on the stack.  */
+int
+get_arglist_len_in_bytes (parms)
+     tree parms;
+{
+  register tree parm;
+  register int bytecount = 0;
+
+  for (parm = parms; parm; parm = TREE_CHAIN (parm))
+    {
+      register tree pval = TREE_VALUE (parm);
+      register int used, size;
+
+      if (TREE_CODE (pval) == ERROR_MARK)
+       continue;
+      else if (TYPE_MODE (TREE_TYPE (pval)) != BLKmode)
+       {
+         used = size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (pval)));
+#ifdef PUSH_ROUNDING
+         size = PUSH_ROUNDING (size);
+#endif
+         used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
+                  / (PARM_BOUNDARY / BITS_PER_UNIT))
+                 * (PARM_BOUNDARY / BITS_PER_UNIT));
+       }
+      else
+       {
+         register tree size = size_in_bytes (TREE_TYPE (pval));
+         register tree used_t
+           = round_up (size, PARM_BOUNDARY / BITS_PER_UNIT);
+         used = TREE_INT_CST_LOW (used_t);
+       }
+      bytecount += used;
+    }
+  return bytecount;
+}
+#endif
+
+tree
+build_vfield_ref (datum, type)
+     tree datum, type;
+{
+  tree rval;
+  int old_assume_nonnull_objects = flag_assume_nonnull_objects;
+
+  /* Vtable references are always made from non-null objects.  */
+  flag_assume_nonnull_objects = 1;
+  if (TREE_CODE (TREE_TYPE (datum)) == REFERENCE_TYPE)
+    datum = convert_from_reference (datum);
+
+  if (! TYPE_USES_COMPLEX_INHERITANCE (type))
+    rval = build (COMPONENT_REF, TREE_TYPE (CLASSTYPE_VFIELD (type)),
+                 datum, CLASSTYPE_VFIELD (type));
+  else
+    rval = build_component_ref (datum, DECL_NAME (CLASSTYPE_VFIELD (type)), 0, 0);
+  flag_assume_nonnull_objects = old_assume_nonnull_objects;
+
+  return rval;
+}
+
+/* Build a call to a member of an object.  I.e., one that overloads
+   operator ()(), or is a pointer-to-function or pointer-to-method.  */
+static tree
+build_field_call (basetype_path, instance_ptr, name, parms, err_name)
+     tree basetype_path;
+     tree instance_ptr, name, parms;
+     char *err_name;
+{
+  tree field, instance;
+
+  if (instance_ptr == current_class_decl)
+    {
+      /* Check to see if we really have a reference to an instance variable
+        with `operator()()' overloaded.  */
+      field = IDENTIFIER_CLASS_VALUE (name);
+
+      if (field == NULL_TREE)
+       {
+         error ("`this' has no member named `%s'", err_name);
+         return error_mark_node;
+       }
+
+      if (TREE_CODE (field) == FIELD_DECL)
+       {
+         /* If it's a field, try overloading operator (),
+            or calling if the field is a pointer-to-function.  */
+         instance = build_component_ref_1 (C_C_D, field, 0);
+         if (instance == error_mark_node)
+           return error_mark_node;
+
+         if (TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
+             && TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (instance)))
+           return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, instance, parms);
+
+         if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
+           if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == FUNCTION_TYPE)
+             return build_function_call (instance, parms);
+           else if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == METHOD_TYPE)
+             return build_function_call (instance, tree_cons (NULL_TREE, current_class_decl, parms));
+       }
+      return NULL_TREE;
+    }
+
+  /* Check to see if this is not really a reference to an instance variable
+     with `operator()()' overloaded.  */
+  field = lookup_field (basetype_path, name, 1, 0);
+
+  /* This can happen if the reference was ambiguous
+     or for visibility violations.  */
+  if (field == error_mark_node)
+    return error_mark_node;
+  if (field)
+    {
+      tree basetype;
+      tree ftype = TREE_TYPE (field);
+
+      if (TYPE_LANG_SPECIFIC (ftype) && TYPE_OVERLOADS_CALL_EXPR (ftype))
+       {
+         /* Make the next search for this field very short.  */
+         basetype = DECL_FIELD_CONTEXT (field);
+         instance_ptr = convert_pointer_to (basetype, instance_ptr);
+
+         instance = build_indirect_ref (instance_ptr, 0);
+         return build_opfncall (CALL_EXPR, LOOKUP_NORMAL,
+                                build_component_ref_1 (instance, field, 0),
+                                parms);
+       }
+      if (TREE_CODE (ftype) == POINTER_TYPE)
+       {
+         if (TREE_CODE (TREE_TYPE (ftype)) == FUNCTION_TYPE
+             || TREE_CODE (TREE_TYPE (ftype)) == METHOD_TYPE)
+           {
+             /* This is a member which is a pointer to function.  */
+             tree ref = build_component_ref_1 (build_indirect_ref (instance_ptr, 0),
+                                               field, LOOKUP_COMPLAIN);
+             if (ref == error_mark_node)
+               return error_mark_node;
+             return build_function_call (ref, parms);
+           }
+       }
+      else if (TREE_CODE (ftype) == METHOD_TYPE)
+       {
+         error ("invalid call via pointer-to-member function");
+         return error_mark_node;
+       }
+      else
+       return NULL_TREE;
+    }
+  return NULL_TREE;
+}
+
+tree
+find_scoped_type (type, inner_name, inner_types)
+     tree type, inner_name, inner_types;
+{
+  tree tags = CLASSTYPE_TAGS (type);
+
+  while (tags)
+    {
+      /* The TREE_PURPOSE of an enum tag (which becomes a member of the
+        enclosing class) is set to the name for the enum type.  So, if
+        inner_name is `bar', and we strike `baz' for `enum bar { baz }',
+        then this test will be true.  */
+      if (TREE_PURPOSE (tags) == inner_name)
+       {
+         if (inner_types == NULL_TREE)
+           return DECL_NESTED_TYPENAME (TYPE_NAME (TREE_VALUE (tags)));
+         return resolve_scope_to_name (TREE_VALUE (tags), inner_types);
+       }
+      tags = TREE_CHAIN (tags);
+    }
+
+  /* Look for a TYPE_DECL.  */
+  for (tags = TYPE_FIELDS (type); tags; tags = TREE_CHAIN (tags))
+    if (TREE_CODE (tags) == TYPE_DECL && DECL_NAME (tags) == inner_name)
+      {
+       /* Code by raeburn.  */
+       if (inner_types == NULL_TREE)
+         return DECL_NESTED_TYPENAME (tags);
+       return resolve_scope_to_name (TREE_TYPE (tags), inner_types);
+      }
+
+  return NULL_TREE;
+}
+
+/* Resolve an expression NAME1::NAME2::...::NAMEn to
+   the name that names the above nested type.  INNER_TYPES
+   is a chain of nested type names (held together by SCOPE_REFs);
+   OUTER_TYPE is the type we know to enclose INNER_TYPES.
+   Returns NULL_TREE if there is an error.  */
+tree
+resolve_scope_to_name (outer_type, inner_types)
+     tree outer_type, inner_types;
+{
+  register tree tmp;
+  tree tags, inner_name;
+
+  if (outer_type == NULL_TREE && current_class_type != NULL_TREE)
+    {
+      /* We first try to look for a nesting in our current class context.  */
+      tree rval = resolve_scope_to_name (current_class_type, inner_types);
+      if (rval != NULL_TREE)
+       return rval;
+    }
+
+  if (TREE_CODE (inner_types) == SCOPE_REF)
+    {
+      inner_name = TREE_OPERAND (inner_types, 0);
+      inner_types = TREE_OPERAND (inner_types, 1);
+    }
+  else
+    {
+      inner_name = inner_types;
+      inner_types = 0;
+    }
+
+  if (outer_type == NULL_TREE)
+    {
+      /* If we have something that's already a type by itself,
+        use that.  */
+      if (IDENTIFIER_HAS_TYPE_VALUE (inner_name))
+       {
+         if (inner_types)
+           return resolve_scope_to_name (IDENTIFIER_TYPE_VALUE (inner_name),
+                                         inner_types);
+         return inner_name;
+       }
+      return NULL_TREE;
+    }
+
+  if (! IS_AGGR_TYPE (outer_type))
+    return NULL_TREE;
+
+  /* Look for member classes or enums.  */
+  tmp = find_scoped_type (outer_type, inner_name, inner_types);
+
+  /* If it's not a type in this class, then go down into the
+     base classes and search there.  */
+  if (! tmp && TYPE_BINFO (outer_type))
+    {
+      tree binfos = TYPE_BINFO_BASETYPES (outer_type);
+      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+      for (i = 0; i < n_baselinks; i++)
+       {
+         tree base_binfo = TREE_VEC_ELT (binfos, i);
+         tmp = find_scoped_type (BINFO_TYPE (base_binfo),
+                                 inner_name, inner_types);
+         if (tmp)
+           return tmp;
+       }
+      tmp = NULL_TREE;
+    }
+
+  return tmp;
+}
+
+/* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'.
+   This is how virtual function calls are avoided.  */
+tree
+build_scoped_method_call (exp, scopes, name, parms)
+     tree exp;
+     tree scopes;
+     tree name;
+     tree parms;
+{
+  /* Because this syntactic form does not allow
+     a pointer to a base class to be `stolen',
+     we need not protect the derived->base conversion
+     that happens here.
+     
+     @@ But we do have to check visibility privileges later.  */
+  tree basename = resolve_scope_to_name (NULL_TREE, scopes);
+  tree basetype, binfo, decl;
+  tree type = TREE_TYPE (exp);
+
+  if (type == error_mark_node
+      || basename == NULL_TREE
+      || ! is_aggr_typedef (basename, 1))
+    return error_mark_node;
+
+  if (! IS_AGGR_TYPE (type))
+    {
+      error ("base object of scoped method call is not of aggregate type");
+      return error_mark_node;
+    }
+
+  basetype = IDENTIFIER_TYPE_VALUE (basename);
+
+  if (binfo = binfo_or_else (basetype, type))
+    {
+      if (binfo == error_mark_node)
+       return error_mark_node;
+      if (TREE_CODE (exp) == INDIRECT_REF)
+       decl = build_indirect_ref (convert_pointer_to (binfo,
+                                                      build_unary_op (ADDR_EXPR, exp, 0)), 0);
+      else
+       decl = build_scoped_ref (exp, scopes);
+
+      /* Call to a destructor.  */
+      if (TREE_CODE (name) == BIT_NOT_EXPR)
+       {
+         /* Explicit call to destructor.  */
+         name = TREE_OPERAND (name, 0);
+         if (! is_aggr_typedef (name, 1))
+           return error_mark_node;
+         if (TREE_TYPE (decl) != IDENTIFIER_TYPE_VALUE (name))
+           {
+             error_with_aggr_type (TREE_TYPE (decl),
+                                   "qualified type `%s' does not match destructor type `%s'",
+                                   IDENTIFIER_POINTER (name));
+             return error_mark_node;
+           }
+         if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
+           error_with_aggr_type (TREE_TYPE (decl), "type `%s' has no destructor");
+         return build_delete (TREE_TYPE (decl), decl, integer_two_node,
+                              LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR,
+                              0, 0);
+       }
+
+      /* Call to a method.  */
+      return build_method_call (decl, name, parms, NULL_TREE,
+                               LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
+    }
+  return error_mark_node;
+}
+
+/* Build something of the form ptr->method (args)
+   or object.method (args).  This can also build
+   calls to constructors, and find friends.
+
+   Member functions always take their class variable
+   as a pointer.
+
+   INSTANCE is a class instance.
+
+   NAME is the NAME field of the struct, union, or class
+   whose type is that of INSTANCE.
+
+   PARMS help to figure out what that NAME really refers to.
+
+   BASETYPE_PATH, if non-NULL, tells which basetypes of INSTANCE
+   we should be traversed before starting our search.  We need
+   this information to get protected accesses correct.
+
+   FLAGS is the logical disjunction of zero or more LOOKUP_
+   flags.  See cp-tree.h for more info.
+
+   If this is all OK, calls build_function_call with the resolved
+   member function.
+
+   This function must also handle being called to perform
+   initialization, promotion/coercion of arguments, and
+   instantiation of default parameters.
+
+   Note that NAME may refer to an instance variable name.  If
+   `operator()()' is defined for the type of that field, then we return
+   that result.  */
+tree
+build_method_call (instance, name, parms, basetype_path, flags)
+     tree instance, name, parms, basetype_path;
+     int flags;
+{
+  register tree function, fntype, value_type;
+  register tree basetype, save_basetype;
+  register tree baselink, result, method_name, parmtypes, parm;
+  tree last;
+  int pass;
+  enum visibility_type visibility;
+  int rank_for_overload ();
+
+  /* Range of cases for vtable optimization.  */
+  enum vtable_needs
+    {
+      not_needed, maybe_needed, unneeded, needed,
+    };
+  enum vtable_needs need_vtbl = not_needed;
+
+  char *err_name;
+  char *name_kind;
+  int ever_seen = 0;
+  tree instance_ptr = NULL_TREE;
+  int all_virtual = flag_all_virtual;
+  int static_call_context = 0;
+  tree saw_private = 0;
+  tree saw_protected = 0;
+#ifdef SOS
+  /* If call is a call to a constructor, then `dtbl'
+     will first be initialized with the function table pointer
+     of the appropriate type (calling "sosFindCode" as a last
+     resort), the the call to the constructor will go through there.  */
+  tree dtbl = (flags & LOOKUP_DYNAMIC) ? TREE_VALUE (parms) : NULL_TREE;
+
+  /* Flag saying whether or not `dtbl' has been inserted into the
+     parameter list.  This is needed because we cannot tell (until
+     we have a match) whether this parameter should go in or not.
+
+     If 1, then `dtbl' is living naturally.
+     If 0, then `dtbl' is not among the parms that we know about.
+     If -1, the `dtbl' was place into the parms unnaturally.
+
+     Note that we may side-effect the parameter list, but in such a way
+     that the caller of this function would never know.  */
+  int dtbl_inserted = (flags & LOOKUP_DYNAMIC);
+#endif
+
+  /* Keep track of `const' and `volatile' objects.  */
+  int constp, volatilep;
+
+#ifdef GATHER_STATISTICS
+  n_build_method_call++;
+#endif
+
+  if (instance == error_mark_node
+      || name == error_mark_node
+      || parms == error_mark_node
+      || (instance != 0 && TREE_TYPE (instance) == error_mark_node))
+    return error_mark_node;
+
+  /* This is the logic that magically deletes the second argument to
+     operator delete, if it is not needed. */
+  if (name == ansi_opname[(int) DELETE_EXPR] && list_length (parms)==2)
+    {
+      tree save_last = TREE_CHAIN (parms);
+      tree result;
+      /* get rid of unneeded argument */
+      TREE_CHAIN (parms) = NULL_TREE;
+      result = build_method_call (instance, name, parms, basetype_path,
+                                 (LOOKUP_SPECULATIVELY|flags)
+                                 &~LOOKUP_COMPLAIN);
+      /* If it works, return it. */
+      if (result && result != error_mark_node)
+       return build_method_call (instance, name, parms, basetype_path, flags);
+      /* If it doesn't work, two argument delete must work */
+      TREE_CHAIN (parms) = save_last;
+    }
+
+#if 0
+  /* C++ 2.1 does not allow this, but ANSI probably will.  */
+  if (TREE_CODE (name) == BIT_NOT_EXPR)
+    {
+      error ("invalid call to destructor, use qualified name `%s::~%s'",
+            IDENTIFIER_POINTER (name), IDENTIFIER_POINTER (name));
+      return error_mark_node;
+    }
+#else
+  if (TREE_CODE (name) == BIT_NOT_EXPR)
+    {
+      flags |= LOOKUP_DESTRUCTOR;
+      name = TREE_OPERAND (name, 0);
+      if (! is_aggr_typedef (name, 1))
+       return error_mark_node;
+      if (parms)
+       error ("destructors take no parameters");
+      basetype = IDENTIFIER_TYPE_VALUE (name);
+      if (! TYPE_HAS_DESTRUCTOR (basetype))
+       {
+#if 0 /* ARM says tp->~T() without T::~T() is valid.  */
+         error_with_aggr_type (basetype, "type `%s' has no destructor");
+#endif
+         /* A destructive destructor wouldn't be a bad idea, but let's
+            not bother for now.  */
+         return build_c_cast (void_type_node, instance);
+       }
+      instance = default_conversion (instance);
+      if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
+       instance_ptr = instance;
+      else
+       instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
+      return build_delete (basetype, instance_ptr, integer_two_node,
+                          LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0, 0);
+    }
+#endif
+
+  /* Initialize name for error reporting.  */
+  if (IDENTIFIER_TYPENAME_P (name))
+    err_name = "type conversion operator";
+  else if (IDENTIFIER_OPNAME_P (name))
+    {
+      char *p = operator_name_string (name);
+      err_name = (char *)alloca (strlen (p) + 10);
+      sprintf (err_name, "operator %s", p);
+    }
+  else if (TREE_CODE (name) == SCOPE_REF)
+    err_name = IDENTIFIER_POINTER (TREE_OPERAND (name, 1));
+  else
+    err_name = IDENTIFIER_POINTER (name);
+
+  if (IDENTIFIER_OPNAME_P (name))
+    GNU_xref_call (current_function_decl,  IDENTIFIER_POINTER (name));
+  else
+    GNU_xref_call (current_function_decl, err_name);
+
+  if (instance == NULL_TREE)
+    {
+      basetype = NULL_TREE;
+      /* Check cases where this is really a call to raise
+        an exception.  */
+      if (current_class_type && TREE_CODE (name) == IDENTIFIER_NODE)
+       {
+         basetype = purpose_member (name, CLASSTYPE_TAGS (current_class_type));
+         if (basetype)
+           basetype = TREE_VALUE (basetype);
+       }
+      else if (TREE_CODE (name) == SCOPE_REF
+              && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
+       {
+         if (! is_aggr_typedef (TREE_OPERAND (name, 0), 1))
+           return error_mark_node;
+         basetype = purpose_member (TREE_OPERAND (name, 1),
+                                    CLASSTYPE_TAGS (IDENTIFIER_TYPE_VALUE (TREE_OPERAND (name, 0))));
+         if (basetype)
+           basetype = TREE_VALUE (basetype);
+       }
+
+      if (basetype != NULL_TREE)
+       ;
+      /* call to a constructor... */
+      else if (IDENTIFIER_HAS_TYPE_VALUE (name))
+       {
+         basetype = IDENTIFIER_TYPE_VALUE (name);
+         name = constructor_name (basetype);
+       }
+      else
+       {
+         tree typedef_name = lookup_name (name, 1);
+         if (typedef_name && TREE_CODE (typedef_name) == TYPE_DECL)
+           {
+             /* Canonicalize the typedef name.  */
+             basetype = TREE_TYPE (typedef_name);
+             name = TYPE_IDENTIFIER (basetype);
+           }
+         else
+           {
+             error ("no constructor named `%s' in visible scope",
+                    IDENTIFIER_POINTER (name));
+             return error_mark_node;
+           }
+       }
+
+      if (! IS_AGGR_TYPE (basetype))
+       {
+       non_aggr_error:
+         if ((flags & LOOKUP_COMPLAIN) && TREE_CODE (basetype) != ERROR_MARK)
+           error ("request for member `%s' in something not a structure or union", err_name);
+
+         return error_mark_node;
+       }
+    }
+  else if (instance == C_C_D || instance == current_class_decl)
+    {
+      /* When doing initialization, we side-effect the TREE_TYPE of
+        C_C_D, hence we cannot set up BASETYPE from CURRENT_CLASS_TYPE.  */
+      basetype = TREE_TYPE (C_C_D);
+
+      /* Anything manifestly `this' in constructors and destructors
+        has a known type, so virtual function tables are not needed.  */
+      if (TYPE_VIRTUAL_P (basetype)
+         && !(flags & LOOKUP_NONVIRTUAL))
+       need_vtbl = (dtor_label || ctor_label)
+         ? unneeded : maybe_needed;
+
+      instance = C_C_D;
+      instance_ptr = current_class_decl;
+      result = build_field_call (TYPE_BINFO (current_class_type),
+                                instance_ptr, name, parms, err_name);
+
+      if (result)
+       return result;
+    }
+  else if (TREE_CODE (instance) == RESULT_DECL)
+    {
+      basetype = TREE_TYPE (instance);
+      /* Should we ever have to make a virtual function reference
+        from a RESULT_DECL, know that it must be of fixed type
+        within the scope of this function.  */
+      if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
+       need_vtbl = maybe_needed;
+      instance_ptr = build1 (ADDR_EXPR, TYPE_POINTER_TO (basetype), instance);
+    }
+  else if (instance == current_exception_object)
+    {
+      instance_ptr = build1 (ADDR_EXPR, TYPE_POINTER_TO (current_exception_type),
+                           TREE_OPERAND (current_exception_object, 0));
+      mark_addressable (TREE_OPERAND (current_exception_object, 0));
+      result = build_field_call (TYPE_BINFO (current_exception_type),
+                                instance_ptr, name, parms, err_name);
+      if (result)
+       return result;
+      error ("exception member `%s' cannot be invoked", err_name);
+      return error_mark_node;
+    }
+  else
+    {
+      /* The MAIN_VARIANT of the type that `instance_ptr' winds up being.  */
+      tree inst_ptr_basetype;
+
+      static_call_context = (TREE_CODE (instance) == NOP_EXPR
+                            && TREE_OPERAND (instance, 0) == error_mark_node);
+
+      /* the base type of an instance variable is pointer to class */
+      basetype = TREE_TYPE (instance);
+
+      if (TREE_CODE (basetype) == REFERENCE_TYPE)
+       {
+         basetype = TYPE_MAIN_VARIANT (TREE_TYPE (basetype));
+         if (! IS_AGGR_TYPE (basetype))
+           goto non_aggr_error;
+         /* Call to convert not needed because we are remaining
+            within the same type.  */
+         instance_ptr = build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), instance);
+         inst_ptr_basetype = basetype;
+       }
+      else
+       {
+         if (TREE_CODE (basetype) == POINTER_TYPE)
+           {
+             basetype = TREE_TYPE (basetype);
+             instance_ptr = instance;
+           }
+
+         if (! IS_AGGR_TYPE (basetype))
+           goto non_aggr_error;
+
+         if (! instance_ptr)
+           {
+             if ((lvalue_p (instance)
+                  && (instance_ptr = build_unary_op (ADDR_EXPR, instance, 0)))
+                 || (instance_ptr = unary_complex_lvalue (ADDR_EXPR, instance)))
+               {
+                 if (instance_ptr == error_mark_node)
+                   return error_mark_node;
+               }
+             else if (TREE_CODE (instance) == NOP_EXPR
+                      || TREE_CODE (instance) == CONSTRUCTOR)
+               {
+                 /* A cast is not an lvalue.  Initialize a fresh temp
+                    with the value we are casting from, and proceed with
+                    that temporary.  We can't cast to a reference type,
+                    so that simplifies the initialization to something
+                    we can manage.  */
+                 tree temp = get_temp_name (TREE_TYPE (instance), 0);
+                 if (IS_AGGR_TYPE (TREE_TYPE (instance)))
+                   expand_aggr_init (temp, instance, 0);
+                 else
+                   {
+                     store_init_value (temp, instance);
+                     expand_decl_init (temp);
+                   }
+                 instance = temp;
+                 instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
+               }
+             else
+               {
+                 if (TREE_CODE (instance) != CALL_EXPR)
+                   my_friendly_abort (125);
+                 if (TYPE_NEEDS_CONSTRUCTOR (basetype))
+                   instance = build_cplus_new (basetype, instance, 0);
+                 else
+                   {
+                     instance = get_temp_name (basetype, 0);
+                     TREE_ADDRESSABLE (instance) = 1;
+                   }
+                 instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
+               }
+             /* @@ Should we call comp_target_types here?  */
+             inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));
+             if (TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (inst_ptr_basetype))
+               basetype = inst_ptr_basetype;
+             else
+               {
+                 instance_ptr = convert (TYPE_POINTER_TO (basetype), instance_ptr);
+                 if (instance_ptr == error_mark_node)
+                   return error_mark_node;
+               }
+           }
+         else
+           inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));
+       }
+
+      if (basetype_path == NULL_TREE)
+       basetype_path = TYPE_BINFO (inst_ptr_basetype);
+
+      result = build_field_call (basetype_path, instance_ptr, name, parms, err_name);
+      if (result)
+       return result;
+
+      if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
+       {
+         if (TREE_SIDE_EFFECTS (instance_ptr))
+           {
+             /* This action is needed because the instance is needed
+                for providing the base of the virtual function table.
+                Without using a SAVE_EXPR, the function we are building
+                may be called twice, or side effects on the instance
+                variable (such as a post-increment), may happen twice.  */
+             instance_ptr = save_expr (instance_ptr);
+             instance = build_indirect_ref (instance_ptr, 0);
+           }
+         else if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
+           {
+             /* This happens when called for operator new ().  */
+             instance = build_indirect_ref (instance, 0);
+           }
+
+         need_vtbl = maybe_needed;
+       }
+    }
+
+  if (TYPE_SIZE (basetype) == 0)
+    {
+      /* This is worth complaining about, I think.  */
+      error_with_aggr_type (basetype, "cannot lookup method in incomplete type `%s'");
+      return error_mark_node;
+    }
+
+  save_basetype = basetype;
+
+#if 0
+  if (all_virtual == 1
+      && (! strncmp (IDENTIFIER_POINTER (name), OPERATOR_METHOD_FORMAT,
+                    OPERATOR_METHOD_LENGTH)
+         || instance_ptr == NULL_TREE
+         || (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype) == 0
+             /*&& TYPE_NEEDS_WRAPPER (basetype) == 0*/ )))
+    all_virtual = 0;
+#endif
+
+  last = NULL_TREE;
+  for (parmtypes = 0, parm = parms; parm; parm = TREE_CHAIN (parm))
+    {
+      tree t = TREE_TYPE (TREE_VALUE (parm));
+      if (TREE_CODE (t) == OFFSET_TYPE)
+       {
+         /* Convert OFFSET_TYPE entities to their normal selves.  */
+         TREE_VALUE (parm) = resolve_offset_ref (TREE_VALUE (parm));
+         t = TREE_TYPE (TREE_VALUE (parm));
+       }
+      if (TREE_CODE (t) == ARRAY_TYPE)
+       {
+         /* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
+            This eliminates needless calls to `compute_conversion_costs'.  */
+         TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
+         t = TREE_TYPE (TREE_VALUE (parm));
+       }
+      if (t == error_mark_node)
+       return error_mark_node;
+      last = build_tree_list (NULL_TREE, t);
+      parmtypes = chainon (parmtypes, last);
+    }
+
+  if (instance)
+    {
+      constp = TREE_READONLY (instance);
+      volatilep = TREE_THIS_VOLATILE (instance);
+      parms = tree_cons (NULL_TREE, instance_ptr, parms);
+    }
+  else
+    {
+      /* Raw constructors are always in charge.  */
+      if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
+         && ! (flags & LOOKUP_HAS_IN_CHARGE))
+       {
+         flags |= LOOKUP_HAS_IN_CHARGE;
+         parms = tree_cons (NULL_TREE, integer_one_node, parms);
+         parmtypes = tree_cons (NULL_TREE, integer_type_node, parmtypes);
+       }
+
+      if (flag_this_is_variable > 0)
+       {
+         constp = 0;
+         volatilep = 0;
+         parms = tree_cons (NULL_TREE, build1 (NOP_EXPR, TYPE_POINTER_TO (basetype), integer_zero_node), parms);
+       }
+      else
+       {
+         constp = 0;
+         volatilep = 0;
+         instance_ptr = build_new (NULL_TREE, basetype, void_type_node, 0);
+         if (instance_ptr == error_mark_node)
+           return error_mark_node;
+         instance_ptr = save_expr (instance_ptr);
+         TREE_CALLS_NEW (instance_ptr) = 1;
+         instance = build_indirect_ref (instance_ptr, 0);
+
+         /* If it's a default argument initialized from a ctor, what we get
+            from instance_ptr will match the arglist for the FUNCTION_DECL
+            of the constructor.  */
+         if (parms && TREE_CODE (TREE_VALUE (parms)) == CALL_EXPR
+             && TREE_OPERAND (TREE_VALUE (parms), 1)
+             && TREE_CALLS_NEW (TREE_VALUE (TREE_OPERAND (TREE_VALUE (parms), 1))))
+           parms = build_tree_list (NULL_TREE, instance_ptr);
+         else
+           parms = tree_cons (NULL_TREE, instance_ptr, parms);
+       }
+    }
+  parmtypes = tree_cons (NULL_TREE,
+                        build_pointer_type (build_type_variant (basetype, constp, volatilep)),
+                        parmtypes);
+  if (last == NULL_TREE)
+    last = parmtypes;
+
+  /* Look up function name in the structure type definition.  */
+
+  if ((IDENTIFIER_HAS_TYPE_VALUE (name)
+       && IS_AGGR_TYPE (IDENTIFIER_TYPE_VALUE (name)))
+      || name == constructor_name (basetype))
+    {
+      tree tmp = NULL_TREE;
+      if (IDENTIFIER_TYPE_VALUE (name) == basetype
+         || name == constructor_name (basetype))
+       tmp = TYPE_BINFO (basetype);
+      else
+       tmp = get_binfo (IDENTIFIER_TYPE_VALUE (name), basetype, 0);
+      
+      if (tmp != 0)
+       {
+         name_kind = "constructor";
+         
+         if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
+             && ! (flags & LOOKUP_HAS_IN_CHARGE))
+           {
+             /* Constructors called for initialization
+                only are never in charge.  */
+             tree tmplist;
+             
+             flags |= LOOKUP_HAS_IN_CHARGE;
+             tmplist = tree_cons (NULL_TREE, integer_zero_node,
+                                  TREE_CHAIN (parms));
+             TREE_CHAIN (parms) = tmplist;
+             tmplist = tree_cons (NULL_TREE, integer_type_node, TREE_CHAIN (parmtypes));
+             TREE_CHAIN (parmtypes) = tmplist;
+           }
+         
+#ifdef SOS
+         if (TYPE_DYNAMIC (basetype) && dtbl_inserted == 0)
+           {
+             tree parm, parmtype;
+             dtbl = get_sos_dtable (basetype);
+             parm = tree_cons (NULL_TREE, dtbl, TREE_CHAIN (parms));
+             parmtype = tree_cons (NULL_TREE, build_pointer_type (ptr_type_node), TREE_CHAIN (parmtypes));
+             TREE_CHAIN (parms) = parm;
+             TREE_CHAIN (parmtypes) = parmtype;
+             dtbl_inserted = -1;
+           }
+#endif
+         /* constructors are in very specific places.  */
+#ifdef SOS
+         if (dtbl_inserted == -1)
+           {
+             TREE_CHAIN (parmtypes) = TREE_CHAIN (TREE_CHAIN (parmtypes));
+             TREE_CHAIN (parms) = TREE_CHAIN (TREE_CHAIN (parms));
+             dtbl_inserted = 0;
+           }
+#endif
+         basetype = BINFO_TYPE (tmp);
+       }
+      else
+       name_kind = "method";
+    }
+  else name_kind = "method";
+  
+  if (basetype_path == NULL_TREE)
+    basetype_path = TYPE_BINFO (basetype);
+  result = lookup_fnfields (basetype_path, name,
+                           (flags & LOOKUP_COMPLAIN));
+  if (result == error_mark_node)
+    return error_mark_node;
+
+
+  /* Now, go look for this method name.  We do not find destructors here.
+
+     Putting `void_list_node' on the end of the parmtypes
+     fakes out `build_decl_overload' into doing the right thing.  */
+  TREE_CHAIN (last) = void_list_node;
+  method_name = build_decl_overload (name, parmtypes,
+                                    1 + (name == constructor_name (save_basetype)));
+  TREE_CHAIN (last) = NULL_TREE;
+
+  for (pass = 0; pass < 2; pass++)
+    {
+      struct candidate *candidates;
+      struct candidate *cp;
+      int len;
+      unsigned best = 2;
+
+      /* This increments every time we go up the type hierarchy.
+        The idea is to prefer a function of the derived class if possible. */
+      int b_or_d = 0;
+
+      baselink = result;
+
+      if (pass > 0)
+       {
+         candidates
+           = (struct candidate *) alloca ((ever_seen+1)
+                                          * sizeof (struct candidate));
+         cp = candidates;
+         len = list_length (parms);
+
+         /* First see if a global function has a shot at it.  */
+         if (flags & LOOKUP_GLOBAL)
+           {
+             tree friend_parms;
+             tree parm = TREE_VALUE (parms);
+
+             if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE)
+               friend_parms = parms;
+             else if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
+               {
+                 tree new_type;
+                 parm = build_indirect_ref (parm, "friendifying parms (compiler error)");
+                 new_type = build_reference_type (TREE_TYPE (parm));
+                 /* It is possible that this should go down a layer. */
+                 new_type = build_type_variant (new_type,
+                                                TREE_READONLY (parm),
+                                                TREE_THIS_VOLATILE (parm));
+                 parm = convert (new_type, parm);
+                 friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
+               }
+             else
+               my_friendly_assert (0, 167);
+
+             cp->harshness
+               = (unsigned short *)alloca ((len+1) * sizeof (short));
+             result = build_overload_call (name, friend_parms, 0, cp);
+             /* If it turns out to be the one we were actually looking for
+                (it was probably a friend function), the return the
+                good result.  */
+             if (TREE_CODE (result) == CALL_EXPR)
+               return result;
+
+             while (cp->evil == 0)
+               {
+                 /* non-standard uses: set the field to 0 to indicate
+                    we are using a non-member function.  */
+                 cp->u.field = 0;
+                 if (cp->harshness[len] == 0
+                     && cp->harshness[len] == 0
+                     && cp->user == 0 && cp->b_or_d == 0
+                     && cp->easy < best)
+                   best = cp->easy;
+                 cp += 1;
+               }
+           }
+       }
+
+      while (baselink)
+       {
+         /* We have a hit (of sorts). If the parameter list is
+            "error_mark_node", or some variant thereof, it won't
+            match any methods.  Since we have verified that the is
+            some method vaguely matching this one (in name at least),
+            silently return.
+            
+            Don't stop for friends, however.  */
+         tree basetypes = TREE_PURPOSE (baselink);
+
+         function = TREE_VALUE (baselink);
+         if (TREE_CODE (basetypes) == TREE_LIST)
+           basetypes = TREE_VALUE (basetypes);
+         basetype = BINFO_TYPE (basetypes);
+
+         /* Cast the instance variable to the appropriate type.  */
+         TREE_VALUE (parmtypes) = TYPE_POINTER_TO (basetype);
+
+         if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function)))
+           function = DECL_CHAIN (function);
+
+         for (; function; function = DECL_CHAIN (function))
+           {
+#ifdef GATHER_STATISTICS
+             n_inner_fields_searched++;
+#endif
+             ever_seen++;
+
+             /* Not looking for friends here.  */
+             if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE
+                 && ! DECL_STATIC_FUNCTION_P (function))
+               continue;
+
+             if (pass == 0
+                 && DECL_ASSEMBLER_NAME (function) == method_name)
+               {
+                 if (flags & LOOKUP_PROTECT)
+                   {
+                     visibility = compute_visibility (basetypes, function);
+                     if (visibility == visibility_protected
+                         && flags & LOOKUP_PROTECTED_OK)
+                       visibility = visibility_public;
+                   }
+
+                 if ((flags & LOOKUP_PROTECT) == 0
+                     || visibility == visibility_public)
+                   goto found_and_ok;
+                 else if (visibility == visibility_private)
+                   saw_private = function;
+                 else if (visibility == visibility_protected)
+                   saw_protected = function;
+                 /* If we fail on the exact match, we have
+                    an immediate failure.  */
+                 goto found;
+               }
+             if (pass > 0)
+               {
+                 tree these_parms = parms;
+
+#ifdef GATHER_STATISTICS
+                 n_inner_fields_searched++;
+#endif
+                 cp->harshness
+                   = (unsigned short *)alloca ((len+1) * sizeof (short));
+                 if (DECL_STATIC_FUNCTION_P (function))
+                   these_parms = TREE_CHAIN (these_parms);
+                 compute_conversion_costs (function, these_parms, cp, len);
+                 cp->b_or_d += b_or_d;
+                 if (cp->evil == 0)
+                   {
+                     cp->u.field = function;
+                     cp->function = function;
+                     if (flags & LOOKUP_PROTECT)
+                       {
+                         enum visibility_type this_v;
+                         this_v = compute_visibility (basetypes, function);
+                         if (this_v == visibility_protected
+                             && (flags & LOOKUP_PROTECTED_OK))
+                           this_v = visibility_public;
+                         if (this_v != visibility_public)
+                           {
+                             if (this_v == visibility_private)
+                               saw_private = function;
+                             else
+                               saw_protected = function;
+                             continue;
+                           }
+                       }
+
+                     /* No "two-level" conversions.  */
+                     if (flags & LOOKUP_NO_CONVERSION && cp->user != 0)
+                       continue;
+
+                     /* If we used default parameters, we must
+                        check to see whether anyone else might
+                        use them also, and report a possible
+                        ambiguity.  */
+                     if (! TYPE_USES_MULTIPLE_INHERITANCE (save_basetype)
+                         && cp->harshness[len] == 0
+                         && CONST_HARSHNESS (cp->harshness[0]) == 0
+                         && cp->user == 0 && cp->b_or_d == 0
+                         && cp->easy < best)
+                       {
+                         if (! DECL_STATIC_FUNCTION_P (function))
+                           TREE_VALUE (parms) = cp->arg;
+                         if (best == 2)
+                           goto found_and_maybe_warn;
+                       }
+                     cp++;
+                   }
+               }
+           }
+         /* Now we have run through one link's member functions.
+            arrange to head-insert this link's links.  */
+         baselink = next_baselink (baselink);
+         b_or_d += 1;
+       }
+      if (pass == 0)
+       {
+         /* No exact match could be found.  Now try to find match
+            using default conversions.  */
+         if ((flags & LOOKUP_GLOBAL) && IDENTIFIER_GLOBAL_VALUE (name))
+           if (TREE_CODE (IDENTIFIER_GLOBAL_VALUE (name)) == FUNCTION_DECL)
+             ever_seen += 1;
+           else if (TREE_CODE (IDENTIFIER_GLOBAL_VALUE (name)) == TREE_LIST)
+             ever_seen += list_length (IDENTIFIER_GLOBAL_VALUE (name));
+
+         if (ever_seen == 0)
+           {
+             if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
+                 == LOOKUP_SPECULATIVELY)
+               return NULL_TREE;
+             if (flags & LOOKUP_GLOBAL)
+               error ("no global or member function `%s' defined", err_name);
+             else
+               error_with_aggr_type (save_basetype, "no member function `%s::%s'", err_name);
+             return error_mark_node;
+           }
+         continue;
+       }
+
+      if (cp - candidates != 0)
+       {
+         /* Rank from worst to best.  Then cp will point to best one.
+            Private fields have their bits flipped.  For unsigned
+            numbers, this should make them look very large.
+            If the best alternate has a (signed) negative value,
+            then all we ever saw were private members.  */
+         if (cp - candidates > 1)
+           {
+             cp = ideal_candidate (save_basetype, candidates,
+                                   cp - candidates, parms, len);
+             if (cp == 0)
+               {
+                 error ("ambiguous type conversion requested for %s `%s'",
+                        name_kind, err_name);
+                 return error_mark_node;
+               }
+             if (cp->evil)
+               return error_mark_node;
+           }
+         else if (cp[-1].evil == 2)
+           {
+             error ("ambiguous type conversion requested for %s `%s'",
+                    name_kind, err_name);
+             return error_mark_node;
+           }
+         else cp--;
+
+         /* The global function was the best, so use it.  */
+         if (cp->u.field == 0)
+           {
+             /* We must convert the instance pointer into a reference type.
+                Global overloaded functions can only either take
+                aggregate objects (which come for free from references)
+                or reference data types anyway.  */
+             TREE_VALUE (parms) = copy_node (instance_ptr);
+             TREE_TYPE (TREE_VALUE (parms)) = build_reference_type (TREE_TYPE (TREE_TYPE (instance_ptr)));
+             return build_function_call (cp->function, parms);
+           }
+
+         function = cp->function;
+         if (! DECL_STATIC_FUNCTION_P (function))
+           TREE_VALUE (parms) = cp->arg;
+         goto found_and_maybe_warn;
+       }
+
+      if ((flags & ~LOOKUP_GLOBAL) & (LOOKUP_COMPLAIN|LOOKUP_SPECULATIVELY))
+       {
+         char *tag_name, *buf;
+
+         if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
+             == LOOKUP_SPECULATIVELY)
+           return NULL_TREE;
+
+         if (DECL_STATIC_FUNCTION_P (cp->function))
+           parms = TREE_CHAIN (parms);
+         if (ever_seen)
+           {
+             if (((HOST_WIDE_INT)saw_protected|(HOST_WIDE_INT)saw_private) == 0)
+               {
+                 if (flags & LOOKUP_SPECULATIVELY)
+                   return NULL_TREE;
+                 if (static_call_context && TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
+                   error_with_aggr_type (TREE_TYPE (TREE_TYPE (instance_ptr)),
+                                         "object missing in call to `%s::%s'",
+                                         err_name);
+                 else
+                   report_type_mismatch (cp, parms, name_kind, err_name);
+               }
+             else
+               {
+                 char buf[80];
+                 char *msg;
+                 tree seen = saw_private;
+
+                 if (saw_private)
+                   if (saw_protected)
+                     msg = "%s %%s (and the like) are private or protected";
+                   else
+                     msg = "the %s %%s is private";
+                 else
+                   {
+                     msg = "the %s %%s is protected";
+                     seen = saw_protected;
+                   }
+                 sprintf (buf, msg, name_kind);
+                 error_with_decl (seen, buf);
+                 error ("within this context");
+               }
+             return error_mark_node;
+           }
+
+         if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
+             == LOOKUP_COMPLAIN)
+           {
+             if (TREE_CODE (save_basetype) == RECORD_TYPE)
+               tag_name = "structure";
+             else
+               tag_name = "union";
+
+             buf = (char *)alloca (30 + strlen (err_name));
+             strcpy (buf, "%s has no method named `%s'");
+             error (buf, tag_name, err_name);
+             return error_mark_node;
+           }
+         return NULL_TREE;
+       }
+      continue;
+
+    found_and_maybe_warn:
+      if (CONST_HARSHNESS (cp->harshness[0]))
+       {
+         if (flags & LOOKUP_COMPLAIN)
+           {
+             error_with_decl (cp->function, "non-const member function `%s'");
+             error ("called for const object at this point in file");
+           }
+         /* Not good enough for a match.  */
+         else return error_mark_node;
+       }
+      goto found_and_ok;
+    }
+  /* Silently return error_mark_node.  */
+  return error_mark_node;
+
+ found:
+  if (visibility == visibility_private)
+    {
+      if (flags & LOOKUP_COMPLAIN)
+       error_with_file_and_line (DECL_SOURCE_FILE (function),
+                                 DECL_SOURCE_LINE (function),
+                                 TREE_PRIVATE (function)
+                                 ? "%s `%s' is private"
+                                 : "%s `%s' is from private base class",
+                                 name_kind,
+                                 lang_printable_name (function));
+      return error_mark_node;
+    }
+  else if (visibility == visibility_protected)
+    {
+      if (flags & LOOKUP_COMPLAIN)
+       error_with_file_and_line (DECL_SOURCE_FILE (function),
+                                 DECL_SOURCE_LINE (function),
+                                 TREE_PROTECTED (function)
+                                 ? "%s `%s' is protected"
+                                 : "%s `%s' has protected visibility from this point",
+                                 name_kind,
+                                 lang_printable_name (function));
+      return error_mark_node;
+    }
+  my_friendly_abort (1);
+
+ found_and_ok:
+
+  /* From here on down, BASETYPE is the type that INSTANCE_PTR's
+     type (if it exists) is a pointer to.  */
+  function = DECL_MAIN_VARIANT (function);
+  /* Declare external function if necessary. */
+  assemble_external (function);
+
+  fntype = TREE_TYPE (function);
+  if (TREE_CODE (fntype) == POINTER_TYPE)
+    fntype = TREE_TYPE (fntype);
+  basetype = DECL_CLASS_CONTEXT (function);
+
+  /* If we are referencing a virtual function from an object
+     of effectively static type, then there is no need
+     to go through the virtual function table.  */
+  if (need_vtbl == maybe_needed)
+    {
+      int fixed_type = resolves_to_fixed_type_p (instance, 0);
+
+      if (all_virtual == 1
+         && DECL_VINDEX (function)
+         && may_be_remote (basetype))
+       need_vtbl = needed;
+      else if (DECL_VINDEX (function))
+       need_vtbl = fixed_type ? unneeded : needed;
+      else
+       need_vtbl = not_needed;
+
+      if (fixed_type && DECL_ABSTRACT_VIRTUAL_P (function))
+       {
+         error_with_decl (function, "invalid call to abstract function `%s'");
+         return error_mark_node;
+       }
+    }
+
+  if (TREE_CODE (fntype) == METHOD_TYPE && static_call_context)
+    {
+      /* Let's be nice to the user for now, and give reasonable
+        default behavior.  */
+      instance_ptr = current_class_decl;
+      if (instance_ptr)
+       {
+         if (basetype != current_class_type)
+           {
+             tree binfo = get_binfo (basetype, current_class_type, 1);
+             if (binfo == 0)
+               {
+                 error_not_base_type (function, current_class_type);
+                 return error_mark_node;
+               }
+             else if (basetype == error_mark_node)
+               return error_mark_node;
+           }
+       }
+      else if (! TREE_STATIC (function))
+       {
+         error_with_aggr_type (basetype, "cannot call member function `%s::%s' without object",
+                               err_name);
+         return error_mark_node;
+       }
+    }
+
+  value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
+
+  if (TYPE_SIZE (value_type) == 0)
+    {
+      if (flags & LOOKUP_COMPLAIN)
+       incomplete_type_error (0, value_type);
+      return error_mark_node;
+    }
+
+  /* We do not pass FUNCTION into `convert_arguments', because by
+     now everything should be ok.  If not, then we have a serious error.  */
+  if (DECL_STATIC_FUNCTION_P (function))
+    parms = convert_arguments (NULL_TREE, TYPE_ARG_TYPES (fntype),
+                              TREE_CHAIN (parms), NULL_TREE, LOOKUP_NORMAL);
+  else if (need_vtbl == unneeded)
+    {
+      int sub_flags = DECL_CONSTRUCTOR_P (function) ? flags : LOOKUP_NORMAL;
+      basetype = TREE_TYPE (instance);
+      if (TYPE_METHOD_BASETYPE (TREE_TYPE (function)) != TYPE_MAIN_VARIANT (basetype)
+         && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+       {
+         basetype = DECL_CLASS_CONTEXT (function);
+         instance_ptr = convert_pointer_to (basetype, instance_ptr);
+         instance = build_indirect_ref (instance_ptr, 0);
+       }
+      parms = tree_cons (NULL_TREE, instance_ptr,
+                        convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), NULL_TREE, sub_flags));
+    }
+  else
+    {
+      if ((flags & LOOKUP_NONVIRTUAL) == 0)
+       basetype = DECL_CONTEXT (function);
+
+      /* First parm could be integer_zerop with casts like
+        ((Object*)0)->Object::IsA()  */
+      if (!integer_zerop (TREE_VALUE (parms)))
+       {
+         instance_ptr = convert_pointer_to (build_type_variant (basetype, constp, volatilep),
+                                            TREE_VALUE (parms));
+         if (TREE_CODE (instance_ptr) == COND_EXPR)
+           {
+             instance_ptr = save_expr (instance_ptr);
+             instance = build_indirect_ref (instance_ptr, 0);
+           }
+         else if (TREE_CODE (instance_ptr) == NOP_EXPR
+                  && TREE_CODE (TREE_OPERAND (instance_ptr, 0)) == ADDR_EXPR
+                  && TREE_OPERAND (TREE_OPERAND (instance_ptr, 0), 0) == instance)
+           ;
+         /* The call to `convert_pointer_to' may return error_mark_node.  */
+         else if (TREE_CODE (instance_ptr) == ERROR_MARK)
+           return instance_ptr;
+         else if (instance == NULL_TREE
+                  || TREE_CODE (instance) != INDIRECT_REF
+                  || TREE_OPERAND (instance, 0) != instance_ptr)
+           instance = build_indirect_ref (instance_ptr, 0);
+       }
+      parms = tree_cons (NULL_TREE, instance_ptr,
+                        convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), NULL_TREE, LOOKUP_NORMAL));
+    }
+
+#if 0
+  /* Constructors do not overload method calls.  */
+  else if (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype)
+          && name != TYPE_IDENTIFIER (basetype)
+          && (TREE_CODE (function) != FUNCTION_DECL
+              || strncmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)),
+                          OPERATOR_METHOD_FORMAT,
+                          OPERATOR_METHOD_LENGTH))
+#if 0
+          && (may_be_remote (basetype)
+              || (C_C_D ? TREE_TYPE (instance) != current_class_type : 1))
+#else
+          /* This change by Larry Ketcham.  */
+          && (may_be_remote (basetype) || instance != C_C_D)
+#endif
+          )
+    {
+      tree fn_as_int;
+#ifdef ESKIT
+      register int bytecount = 0;
+
+      parms = tree_cons (NULL_TREE, build_int_2 (bytecount, 0),
+                        TREE_CHAIN (parms));
+#else
+      parms = TREE_CHAIN (parms);
+#endif
+
+      if (!all_virtual && TREE_CODE (function) == FUNCTION_DECL)
+       fn_as_int = build_unary_op (ADDR_EXPR, function, 0);
+      else
+       fn_as_int = convert (TREE_TYPE (default_conversion (function)), DECL_VINDEX (function));
+      if (all_virtual == 1)
+       fn_as_int = convert (integer_type_node, fn_as_int);
+
+      result = build_opfncall (METHOD_CALL_EXPR, LOOKUP_NORMAL, instance, fn_as_int, parms);
+
+      if (result == NULL_TREE)
+       {
+         compiler_error ("could not overload `operator->()(...)'");
+         return error_mark_node;
+       }
+      else if (result == error_mark_node)
+       return error_mark_node;
+
+#if 0
+      /* Do this if we want the result of operator->() to inherit
+        the type of the function it is subbing for.  */
+      TREE_TYPE (result) = value_type;
+#endif
+
+#ifdef ESKIT
+      {
+       int used, size;
+
+       /* Count the number of bytes of arguments to operator->(),
+          not to the method itself.  In the tally, don't count bytes
+          for pointer to member function or for the bytecount.  */
+       parms = TREE_OPERAND (result, 1);
+       bytecount = get_arglist_len_in_bytes (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (parms))));
+       used = size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_VALUE (parms))));
+#ifdef PUSH_ROUNDING
+       size = PUSH_ROUNDING (size);
+#endif
+       used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
+                / (PARM_BOUNDARY / BITS_PER_UNIT))
+               * (PARM_BOUNDARY / BITS_PER_UNIT));
+       bytecount += used;
+       TREE_CHAIN (TREE_CHAIN (parms))
+         = tree_cons (NULL_TREE, build_int_2 (bytecount, 0),
+                      TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (parms))));
+      }
+#endif
+
+      return result;
+    }
+#endif
+
+  if (need_vtbl == needed)
+    {
+      function = build_vfn_ref (&TREE_VALUE (parms), instance, DECL_VINDEX (function));
+      TREE_TYPE (function) = build_pointer_type (fntype);
+    }
+#ifdef SOS
+  else if (basetype && TYPE_DYNAMIC (basetype))
+    {
+      function = build_array_ref (dtbl, DECL_DINDEX (function));
+      TREE_TYPE (function) = build_pointer_type (fntype);
+    }
+#endif
+
+   if (TREE_CODE (function) == FUNCTION_DECL)
+     GNU_xref_call (current_function_decl,
+                   IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)));
+
+  if (TREE_CODE (function) == FUNCTION_DECL)
+    {
+      if (DECL_INLINE (function))
+       function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
+      else
+       {
+         assemble_external (function);
+         TREE_USED (function) = 1;
+         function = default_conversion (function);
+       }
+    }
+  else
+    function = default_conversion (function);
+
+  result =
+    build_nt (CALL_EXPR, function, parms, NULL_TREE);
+
+  TREE_TYPE (result) = value_type;
+  TREE_SIDE_EFFECTS (result) = 1;
+  TREE_RAISES (result)
+    = TYPE_RAISES_EXCEPTIONS (fntype) || (parms && TREE_RAISES (parms));
+  return result;
+}
+
+/* Similar to `build_method_call', but for overloaded non-member functions.
+   The name of this function comes through NAME.  The name depends
+   on PARMS.
+
+   Note that this function must handle simple `C' promotions,
+   as well as variable numbers of arguments (...), and
+   default arguments to boot.
+
+   If the overloading is successful, we return a tree node which
+   contains the call to the function.
+
+   If overloading produces candidates which are probable, but not definite,
+   we hold these candidates.  If FINAL_CP is non-zero, then we are free
+   to assume that final_cp points to enough storage for all candidates that
+   this function might generate.  The `harshness' array is preallocated for
+   the first candidate, but not for subsequent ones.
+
+   Note that the DECL_RTL of FUNCTION must be made to agree with this
+   function's new name.  */
+
+tree
+build_overload_call_real (fnname, parms, complain, final_cp, buildxxx)
+     tree fnname, parms;
+     int complain;
+     struct candidate *final_cp;
+     int buildxxx;
+{
+  /* must check for overloading here */
+  tree overload_name, functions, function, parm;
+  tree parmtypes = NULL_TREE, last = NULL_TREE;
+  register tree outer;
+  int length;
+  int parmlength = list_length (parms);
+
+  struct candidate *candidates, *cp;
+  int rank_for_overload ();
+
+  if (final_cp)
+    {
+      final_cp[0].evil = 0;
+      final_cp[0].user = 0;
+      final_cp[0].b_or_d = 0;
+      final_cp[0].easy = 0;
+      final_cp[0].function = 0;
+      /* end marker.  */
+      final_cp[1].evil = 1;
+    }
+
+  for (parm = parms; parm; parm = TREE_CHAIN (parm))
+    {
+      register tree t = TREE_TYPE (TREE_VALUE (parm));
+
+      if (t == error_mark_node)
+       {
+         if (final_cp)
+           final_cp->evil = 1;
+         return error_mark_node;
+       }
+      if (TREE_CODE (t) == ARRAY_TYPE || TREE_CODE (t) == OFFSET_TYPE)
+       {
+         /* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
+            Also convert OFFSET_TYPE entities to their normal selves.
+            This eliminates needless calls to `compute_conversion_costs'.  */
+         TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
+         t = TREE_TYPE (TREE_VALUE (parm));
+       }
+      last = build_tree_list (NULL_TREE, t);
+      parmtypes = chainon (parmtypes, last);
+    }
+  if (last)
+    TREE_CHAIN (last) = void_list_node;
+  else
+    parmtypes = void_list_node;
+  overload_name = build_decl_overload (fnname, parmtypes, 0);
+
+  /* Now check to see whether or not we can win.
+     Note that if we are called from `build_method_call',
+     then we cannot have a mis-match, because we would have
+     already found such a winning case.  */
+
+  if (IDENTIFIER_GLOBAL_VALUE (overload_name))
+    if (TREE_CODE (IDENTIFIER_GLOBAL_VALUE (overload_name)) != TREE_LIST)
+      return build_function_call (DECL_MAIN_VARIANT (IDENTIFIER_GLOBAL_VALUE (overload_name)), parms);
+
+  functions = IDENTIFIER_GLOBAL_VALUE (fnname);
+
+  if (functions == NULL_TREE)
+    {
+      if (complain)
+       error ("only member functions apply");
+      if (final_cp)
+       final_cp->evil = 1;
+      return error_mark_node;
+    }
+
+  if (TREE_CODE (functions) == FUNCTION_DECL)
+    {
+      functions = DECL_MAIN_VARIANT (functions);
+      if (final_cp)
+       {
+         /* We are just curious whether this is a viable alternative or not.  */
+         compute_conversion_costs (functions, parms, final_cp, parmlength);
+         return functions;
+       }
+      else
+       return build_function_call (functions, parms);
+    }
+
+  if (TREE_VALUE (functions) == NULL_TREE)
+    {
+      if (complain)
+       error ("function `%s' declared overloaded, but no instances of that function declared",
+              IDENTIFIER_POINTER (TREE_PURPOSE (functions)));
+      if (final_cp)
+       final_cp->evil = 1;
+      return error_mark_node;
+    }
+
+  if (TREE_CODE (TREE_VALUE (functions)) == TREE_LIST)
+    {
+      register tree outer;
+      length = 0;
+
+      /* The list-of-lists should only occur for class things.  */
+      my_friendly_assert (functions == IDENTIFIER_CLASS_VALUE (fnname), 168);
+
+      for (outer = functions; outer; outer = TREE_CHAIN (outer))
+       {
+         /* member functions.  */
+         length += decl_list_length (TREE_VALUE (TREE_VALUE (outer)));
+         /* friend functions.  */
+         length += list_length (TREE_TYPE (TREE_VALUE (outer)));
+       }
+    }
+  else
+    {
+      length = list_length (functions);
+    }
+
+  if (final_cp)
+    candidates = final_cp;
+  else
+    candidates = (struct candidate *)alloca ((length+1) * sizeof (struct candidate));
+
+  cp = candidates;
+
+  my_friendly_assert (TREE_CODE (TREE_VALUE (functions)) != TREE_LIST, 169);
+  /* OUTER is the list of FUNCTION_DECLS, in a TREE_LIST.  */
+
+  for (outer = functions; outer; outer = TREE_CHAIN (outer))
+    {
+      int template_cost = 0;
+      function = TREE_VALUE (outer);
+      if (TREE_CODE (function) != FUNCTION_DECL
+         && ! (TREE_CODE (function) == TEMPLATE_DECL
+               && ! DECL_TEMPLATE_IS_CLASS (function)
+               && TREE_CODE (DECL_TEMPLATE_RESULT (function)) == FUNCTION_DECL))
+       {
+         enum tree_code code = TREE_CODE (function);
+         if (code == TEMPLATE_DECL)
+           code = TREE_CODE (DECL_TEMPLATE_RESULT (function));
+         if (code == CONST_DECL)
+           error_with_decl (function, "enumeral value `%s' conflicts with function of same name");
+         else if (code == VAR_DECL)
+           if (TREE_STATIC (function))
+             error_with_decl (function, "variable `%s' conflicts with function of same name");
+           else
+             error_with_decl (function, "constant field `%s' conflicts with function of same name");
+         else if (code == TYPE_DECL)
+           continue;
+         else my_friendly_abort (2);
+         error ("at this point in file");
+         continue;
+       }
+      if (TREE_CODE (function) == TEMPLATE_DECL)
+       {
+         int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (function));
+         tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
+         int i;
+
+         i = type_unification (DECL_TEMPLATE_PARMS (function), targs,
+                               TYPE_ARG_TYPES (TREE_TYPE (function)),
+                               parms, &template_cost);
+         if (i == 0)
+           function = instantiate_template (function, targs);
+       }
+      if (TREE_CODE (function) == TEMPLATE_DECL)
+       /* Unconverted template -- failed match.  */
+       cp->evil = 1, cp->function = function, cp->u.bad_arg = -4;
+      else
+       {
+         function = DECL_MAIN_VARIANT (function);
+
+         /* Can't use alloca here, since result might be
+            passed to calling function.  */
+         cp->harshness
+           = (unsigned short *)oballoc ((parmlength+1) * sizeof (short));
+         compute_conversion_costs (function, parms, cp, parmlength);
+         /* Should really add another field...  */
+         cp->easy = cp->easy * 128 + template_cost;
+         if (cp[0].evil == 0)
+           {
+             cp[1].evil = 1;
+             if (final_cp
+                 && cp[0].user == 0 && cp[0].b_or_d == 0
+                 && template_cost == 0
+                 && cp[0].easy <= 1)
+               {
+                 final_cp[0].easy = cp[0].easy;
+                 return function;
+               }
+             cp++;
+           }
+       }
+    }
+
+  if (cp - candidates)
+    {
+      tree rval = error_mark_node;
+
+      /* Leave marker.  */
+      cp[0].evil = 1;
+      if (cp - candidates > 1)
+       {
+         struct candidate *best_cp
+           = ideal_candidate (NULL_TREE, candidates,
+                              cp - candidates, parms, parmlength);
+         if (best_cp == 0)
+           {
+             if (complain)
+               error ("call of overloaded `%s' is ambiguous", IDENTIFIER_POINTER (fnname));
+             return error_mark_node;
+           }
+         else
+           rval = best_cp->function;
+       }
+      else
+       {
+         cp -= 1;
+         if (cp->evil > 1)
+           {
+             if (complain)
+               error ("type conversion ambiguous");
+           }
+         else
+           rval = cp->function;
+       }
+
+      if (final_cp)
+       return rval;
+
+      return buildxxx ? build_function_call_maybe (rval, parms)
+        : build_function_call (rval, parms);
+    }
+  else if (complain)
+    {
+      tree name;
+      char *err_name;
+
+      /* Initialize name for error reporting.  */
+      if (TREE_CODE (functions) == TREE_LIST)
+       name = TREE_PURPOSE (functions);
+      else if (TREE_CODE (functions) == ADDR_EXPR)
+      /* Since the implicit `operator new' and `operator delete' functions
+        are set up to have IDENTIFIER_GLOBAL_VALUEs that are unary ADDR_EXPRs
+        by default_conversion(), we must compensate for that here by
+        using the name of the ADDR_EXPR's operand.  */
+       name = DECL_NAME (TREE_OPERAND (functions, 0));
+      else
+       name = DECL_NAME (functions);
+
+      if (IDENTIFIER_OPNAME_P (name))
+       {
+         char *opname = operator_name_string (name);
+         err_name = (char *)alloca (strlen (opname) + 12);
+         sprintf (err_name, "operator %s", opname);
+       }
+      else
+       err_name = IDENTIFIER_POINTER (name);
+
+      report_type_mismatch (cp, parms, "function", err_name);
+    }
+  return error_mark_node;
+}
+
+tree
+build_overload_call (fnname, parms, complain, final_cp)
+     tree fnname, parms;
+     int complain;
+     struct candidate *final_cp;
+{
+  return build_overload_call_real (fnname, parms, complain, final_cp, 0);
+}
+
+tree
+build_overload_call_maybe (fnname, parms, complain, final_cp)
+     tree fnname, parms;
+     int complain;
+     struct candidate *final_cp;
+{
+  return build_overload_call_real (fnname, parms, complain, final_cp, 1);
+}