Enabled linkonce support for Darwin.
[platform/upstream/gcc.git] / gcc / cp / method.c
index 30ede1b..10dfaca 100644 (file)
@@ -1,23 +1,23 @@
 /* Handle the hair of processing (but not expanding) inline functions.
    Also manage function and variable name overloading.
-   Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
-This file is part of GNU CC.
+This file is part of GCC.
    
-GNU CC is free software; you can redistribute it and/or modify
+GCC 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,
+GCC 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
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
@@ -25,16 +25,17 @@ Boston, MA 02111-1307, USA.  */
 /* Handle method declarations.  */
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "cp-tree.h"
-#include "obstack.h"
 #include "rtl.h"
 #include "expr.h"
 #include "output.h"
 #include "flags.h"
 #include "toplev.h"
-#include "ggc.h"
 #include "tm_p.h"
+#include "target.h"
 
 /* Various flags to control the mangling process.  */
 
@@ -49,2189 +50,306 @@ enum mangling_flags
   mf_maybe_uninstantiated = 1,
   /* When mangling a numeric value, use the form `_XX_' (instead of
      just `XX') if the value has more than one digit.  */
-  mf_use_underscores_around_value = 2,
+  mf_use_underscores_around_value = 2
 };
 
 typedef enum mangling_flags mangling_flags;
 
-/* TREE_LIST of the current inline functions that need to be
-   processed.  */
-struct pending_inline *pending_inlines;
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
-/* Obstack where we build text strings for overloading, etc.  */
-static struct obstack scratch_obstack;
-static char *scratch_firstobj;
-
-static void icat PARAMS ((HOST_WIDE_INT));
-static void dicat PARAMS ((HOST_WIDE_INT, HOST_WIDE_INT));
-static int old_backref_index PARAMS ((tree));
-static int flush_repeats PARAMS ((int, tree));
-static void build_overload_identifier PARAMS ((tree));
-static void build_overload_nested_name PARAMS ((tree));
-static void mangle_expression PARAMS ((tree));
-static void build_overload_int PARAMS ((tree, mangling_flags));
-static void build_overload_identifier PARAMS ((tree));
-static void build_qualified_name PARAMS ((tree));
-static void build_overload_value PARAMS ((tree, tree, mangling_flags));
-static void issue_nrepeats PARAMS ((int, tree));
-static char *build_mangled_name PARAMS ((tree,int,int));
-static void process_modifiers PARAMS ((tree));
-static void process_overload_item PARAMS ((tree,int));
-static void do_build_assign_ref PARAMS ((tree));
-static void do_build_copy_constructor PARAMS ((tree));
-static void build_template_template_parm_names PARAMS ((tree));
-static void build_template_parm_names PARAMS ((tree, tree));
-static void build_underscore_int PARAMS ((int));
-static void start_squangling PARAMS ((void));
-static void end_squangling PARAMS ((void));
-static int check_ktype PARAMS ((tree, int));
-static int issue_ktype PARAMS ((tree));
-static void build_overload_scope_ref PARAMS ((tree));
-static void build_mangled_template_parm_index PARAMS ((const char *, tree));
-#if HOST_BITS_PER_WIDE_INT >= 64
-static void build_mangled_C99_name PARAMS ((int));
+static tree thunk_adjust (tree, bool, HOST_WIDE_INT, tree);
+static void do_build_assign_ref (tree);
+static void do_build_copy_constructor (tree);
+static tree synthesize_exception_spec (tree, tree (*) (tree, void *), void *);
+static tree locate_dtor (tree, void *);
+static tree locate_ctor (tree, void *);
+static tree locate_copy (tree, void *);
+#ifdef ASM_OUTPUT_DEF
+static tree make_alias_for_thunk (tree);
 #endif
-static int is_back_referenceable_type PARAMS ((tree));
-static int check_btype PARAMS ((tree));
-static void build_mangled_name_for_type PARAMS ((tree));
-static void build_mangled_name_for_type_with_Gcode PARAMS ((tree, int));
-static tree synthesize_exception_spec PARAMS ((tree, tree (*) (tree, void *), void *));
-static tree locate_dtor PARAMS ((tree, void *));
-static tree locate_ctor PARAMS ((tree, void *));
-static tree locate_copy PARAMS ((tree, void *));
-
-# define OB_INIT() (scratch_firstobj ? (obstack_free (&scratch_obstack, scratch_firstobj), 0) : 0)
-# define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C)))
-# define OB_PUTC2(C1,C2)       \
-  (obstack_1grow (&scratch_obstack, (C1)), obstack_1grow (&scratch_obstack, (C2)))
-# define OB_PUTS(S) (obstack_grow (&scratch_obstack, (S), sizeof (S) - 1))
-# define OB_PUTID(ID)  \
-  (obstack_grow (&scratch_obstack, IDENTIFIER_POINTER (ID),    \
-                IDENTIFIER_LENGTH (ID)))
-# define OB_PUTCP(S) (obstack_grow (&scratch_obstack, (S), strlen (S)))
-# define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0'))
-# define OB_LAST() (obstack_next_free (&scratch_obstack)[-1])
-
-/* type tables for K and B type compression */
-static varray_type btypelist;
-static varray_type ktypelist;
-
-/* number of each type seen */
-static size_t maxbtype;
-static size_t maxktype;
-
-/* Array of types seen so far in top-level call to `build_mangled_name'.
-   Allocated and deallocated by caller.  */
-static varray_type typevec;
-
-/* Number of types interned by `build_mangled_name' so far.  */
-static size_t maxtype;
 
 /* Called once to initialize method.c.  */
 
 void
-init_method ()
+init_method (void)
 {
-  gcc_obstack_init (&scratch_obstack);
-  scratch_firstobj = (char *)obstack_alloc (&scratch_obstack, 0);
-  ggc_add_tree_varray_root (&btypelist, 1);
-  ggc_add_tree_varray_root (&ktypelist, 1);
-  ggc_add_tree_varray_root (&typevec, 1);
-  if (flag_new_abi)
-    init_mangle ();
-}
-
-/* This must be large enough to hold any printed integer or floating-point
-   value.  */
-static char digit_buffer[128];
-
-\f
-/* Here is where overload code starts.  */
-
-/* Nonzero if we should not try folding parameter types.  */
-static int nofold;
-
-/* Nonzero if an underscore is required before adding a digit to the
-   mangled name currently being built.  */
-static int numeric_output_need_bar;
-
-static inline void
-start_squangling ()
-{
-  /* This function is obsoleted by the new ABI.  */
-  my_friendly_assert (!flag_new_abi, 200005222);
-
-  if (flag_do_squangling)
-    {
-      nofold = 0;
-      maxbtype = 0;
-      maxktype = 0;
-      VARRAY_TREE_INIT (btypelist, 50, "btypelist");
-      VARRAY_TREE_INIT (ktypelist, 50, "ktypelist");
-    }
-}
-
-static inline void
-end_squangling ()
-{
-  if (flag_do_squangling)
-    {
-      VARRAY_FREE (ktypelist);
-      VARRAY_FREE (btypelist);
-      maxbtype = 0;
-      maxktype = 0;
-    }
-}
-
-/* Code to concatenate an asciified integer to a string.  */
-
-static inline void
-icat (i)
-     HOST_WIDE_INT i;
-{
-  unsigned HOST_WIDE_INT ui;
-
-  /* Handle this case first, to go really quickly.  For many common values,
-     the result of ui/10 below is 1.  */
-  if (i == 1)
-    {
-      OB_PUTC ('1');
-      return;
-    }
-
-  if (i >= 0)
-    ui = i;
-  else
-    {
-      OB_PUTC ('m');
-      ui = -i;
-    }
-
-  if (ui >= 10)
-    icat (ui / 10);
-
-  OB_PUTC ('0' + (ui % 10));
-}
-
-static void
-dicat (lo, hi)
-     HOST_WIDE_INT lo, hi;
-{
-  unsigned HOST_WIDE_INT ulo, uhi, qlo, qhi;
-
-  if (hi >= 0)
-    {
-      uhi = hi;
-      ulo = lo;
-    }
-  else
-    {
-      uhi = (lo == 0 ? -hi : -hi-1);
-      ulo = -lo;
-    }
-  if (uhi == 0
-      && ulo < ((unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT - 1)))
-    {
-      icat (ulo);
-      return;
-    }
-  /* Divide 2^HOST_WIDE_INT*uhi+ulo by 10. */
-  qhi = uhi / 10;
-  uhi = uhi % 10;
-  qlo = uhi * (((unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT - 1)) / 5);
-  qlo += ulo / 10;
-  ulo = ulo % 10;
-  ulo += uhi * (((unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT - 1)) % 5)
-        * 2;
-  qlo += ulo / 10;
-  ulo = ulo % 10;
-  /* Quotient is 2^HOST_WIDE_INT*qhi+qlo, remainder is ulo. */
-  dicat (qlo, qhi);
-  OB_PUTC ('0' + ulo);
-}
-
-/* Returns the index of TYPE in the typevec, or -1 if it's not there.  */
-
-static inline int
-old_backref_index (type)
-     tree type;
-{
-  size_t tindex;
-
-  if (! is_back_referenceable_type (type))
-    return -1;
-
-  /* The entry for this parm is at maxtype-1, so don't look there for
-     something to repeat.  */
-  for (tindex = 0; tindex < maxtype - 1; ++tindex)
-    if (same_type_p (VARRAY_TREE (typevec, tindex), type))
-      break;
-
-  if (tindex == maxtype - 1)
-    return -1;
-
-  return tindex;
-}
-
-/* Old mangling style:  If TYPE has already been used in the parameter list,
-   emit a backward reference and return non-zero; otherwise, return 0.
-
-   NREPEATS is the number of repeats we've recorded of this type, or 0 if
-   this is the first time we've seen it and we're just looking to see if
-   it had been used before.  */
-
-static inline int
-flush_repeats (nrepeats, type)
-     int nrepeats;
-     tree type;
-{
-  int tindex = old_backref_index (type);
-
-  if (tindex == -1)
-    {
-      my_friendly_assert (nrepeats == 0, 990316);
-      return 0;
-    }
-
-  if (nrepeats > 1)
-    {
-      OB_PUTC ('N');
-      icat (nrepeats);
-      if (nrepeats > 9)
-       OB_PUTC ('_');
-    }
-  else
-    OB_PUTC ('T');
-  icat (tindex);
-  if (tindex > 9)
-    OB_PUTC ('_');
-
-  return 1;
-}
-
-/* Returns nonzero iff this is a type to which we will want to make
-   back-references (using the `B' code).  */
-
-static int
-is_back_referenceable_type (type)
-     tree type;
-{
-  /* For some reason, the Java folks don't want back refs on these.  */
-  if (TYPE_FOR_JAVA (type))
-    return 0;
-
-  switch (TREE_CODE (type)) 
-    {
-    case BOOLEAN_TYPE:
-      if (!flag_do_squangling)
-       /* Even though the mangling of this is just `b', we did
-          historically generate back-references for it.  */
-       return 1;
-      /* Fall through.  */
-      
-    case INTEGER_TYPE:
-    case REAL_TYPE:
-    case VOID_TYPE:
-      /* These types have single-character manglings, so there's no
-        point in generating back-references.  */
-      return 0;         
-
-    case TEMPLATE_TYPE_PARM:
-      /* It would be a bit complex to demangle signatures correctly if
-        we generated back-references to these, and the manglings of
-        type parameters are short.  */
-      return 0;
-
-    default:
-      return 1;
-    }
-}
-
-/* Issue the squangling code indicating NREPEATS repetitions of TYPE,
-   which was the last parameter type output.  */
-
-static void
-issue_nrepeats (nrepeats, type)
-     int nrepeats;
-     tree type;
-{
-  if (nrepeats == 1 && !is_back_referenceable_type (type))
-    /* For types whose manglings are short, don't bother using the
-       repetition code if there's only one repetition, since the
-       repetition code will be about as long as the ordinary mangling.  */ 
-    build_mangled_name_for_type (type);
-  else
-    {
-      OB_PUTC ('n');
-      icat (nrepeats);
-      if (nrepeats > 9)
-       OB_PUTC ('_');
-    }
-}
-
-/* Check to see if a tree node has been entered into the Kcode typelist.
-   If not, add it.  Returns -1 if it isn't found, otherwise returns the
-   index.  */
-
-static int
-check_ktype (node, add)
-     tree node;
-     int add;
-{
-  size_t x;
-  tree localnode = node;
-
-  if (ktypelist == NULL)
-    return -1;
-
-  if (TREE_CODE (node) == TYPE_DECL)
-    localnode = TREE_TYPE (node);
-
-  for (x = 0; x < maxktype; x++)
-    {
-      if (same_type_p (localnode, VARRAY_TREE (ktypelist, x)))
-        return x;
-    }
-  /* Didn't find it, so add it here.  */
-  if (add)
-    {
-      if (VARRAY_SIZE (ktypelist) <= maxktype)
-       VARRAY_GROW (ktypelist, 
-                    VARRAY_SIZE (ktypelist) * 3 / 2);
-      VARRAY_TREE (ktypelist, maxktype) = localnode;
-      maxktype++;
-    }
-  return -1;
-}
-
-
-static inline int
-issue_ktype (decl)
-     tree decl;
-{
-  int kindex;
-  kindex = check_ktype (decl, FALSE);
-  if (kindex != -1)
-    {
-      OB_PUTC ('K');
-      icat (kindex);
-      if (kindex > 9)
-        OB_PUTC ('_');
-      return TRUE;
-    }
-  return FALSE;
-}
-  
-/* Build a representation for DECL, which may be an entity not at
-   global scope.  If so, a marker indicating that the name is
-   qualified has already been output, but the qualifying context has
-   not.  */
-
-static void
-build_overload_nested_name (decl)
-     tree decl;
-{
-  tree context;
-
-  if (ktypelist && issue_ktype (decl))
-      return;
-
-  if (decl == global_namespace)
-    return;
-
-  context = CP_DECL_CONTEXT (decl);
-
-  /* try to issue a K type, and if we can't continue the normal path */
-  if (!(ktypelist && issue_ktype (context)))
-  {
-    /* For a template type parameter, we want to output an 'Xn'
-       rather than 'T' or some such. */
-    if (TREE_CODE (context) == TEMPLATE_TYPE_PARM
-        || TREE_CODE (context) == TEMPLATE_TEMPLATE_PARM
-        || TREE_CODE (context) == BOUND_TEMPLATE_TEMPLATE_PARM)
-      build_mangled_name_for_type (context);
-    else
-    {
-      if (TYPE_P (context))
-        context = TYPE_NAME (context);
-      build_overload_nested_name (context);
-    }
-  }
-
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      static int static_labelno;
-
-      tree name = DECL_ASSEMBLER_NAME (decl);
-      char *label;
-
-      ASM_FORMAT_PRIVATE_NAME (label, IDENTIFIER_POINTER (name), static_labelno);
-      static_labelno++;
-
-      if (numeric_output_need_bar)
-       OB_PUTC ('_');
-      icat (strlen (label));
-      OB_PUTCP (label);
-      numeric_output_need_bar = 1;
-    }
-  else if (TREE_CODE (decl) == NAMESPACE_DECL)
-    build_overload_identifier (DECL_NAME (decl));
-  else                         /* TYPE_DECL */
-    build_overload_identifier (decl);
-}
-
-/* Output the decimal representation of I.  If I > 9, the decimal
-   representation is preceeded and followed by an underscore.  */
-
-static void
-build_underscore_int (i)
-     int i;
-{
-  if (i > 9)
-    OB_PUTC ('_');
-  icat (i);
-  if (i > 9)
-    OB_PUTC ('_');
-}
-
-static void
-build_overload_scope_ref (value)
-     tree value;
-{
-  OB_PUTC2 ('Q', '2');
-  numeric_output_need_bar = 0;
-  build_mangled_name_for_type (TREE_OPERAND (value, 0));
-  build_overload_identifier (TREE_OPERAND (value, 1));
-}
-
-/* VALUE is a complex expression.  Produce an appropriate mangling.
-   (We are forced to mangle complex expressions when dealing with
-   templates, and an expression involving template parameters appears
-   in the type of a function parameter.)  */
-
-static void
-mangle_expression (value)
-     tree value;
-{
-  if (TREE_CODE (value) == SCOPE_REF)
-    {
-      build_overload_scope_ref (value);
-      return;
-    }
-
-  OB_PUTC ('E');
-  numeric_output_need_bar = 0;
-
-  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (value))))
-    {
-      int i;
-      int operands = TREE_CODE_LENGTH (TREE_CODE (value));
-      const char *name;
-
-      name = operator_name_info[TREE_CODE (value)].mangled_name;
-      if (name == NULL)
-       /* On some erroneous inputs, we can get here with VALUE a
-          LOOKUP_EXPR. We must survive this routine in order to issue
-          a sensible error message, so we fall through to the case
-          below.  */
-       goto bad_value;
-
-      for (i = 0; i < operands; ++i)
-       {
-         tree operand;
-         enum tree_code tc;
-
-         /* We just outputted either the `E' or the name of the
-            operator.  */
-         numeric_output_need_bar = 0;
-
-         if (i != 0)
-           /* Skip the leading underscores.  */
-           OB_PUTCP (name + 2);
-
-         operand = TREE_OPERAND (value, i);
-         tc = TREE_CODE (operand);
-
-         if (TREE_CODE_CLASS (tc) == 't')
-           /* We can get here with sizeof, e.g.:
-                    
-              template <class T> void f(A<sizeof(T)>);  */
-           build_mangled_name_for_type (operand);
-         else
-           build_overload_value (TREE_TYPE (operand),
-                                 operand,
-                                 mf_maybe_uninstantiated);
-       }
-    }
-  else
-    {
-      /* We don't ever want this output, but it's
-        inconvenient not to be able to build the string.
-        This should cause assembler errors we'll notice.  */
-           
-      static int n;
-    bad_value:
-      sprintf (digit_buffer, " *%d", n++);
-      OB_PUTCP (digit_buffer);
-    }
-
-  OB_PUTC ('W');
-  numeric_output_need_bar = 0;
-}
-
-/* Encoding for an INTEGER_CST value.  */
-
-static void
-build_overload_int (value, flags)
-     tree value;
-     mangling_flags flags;
-{
-  int multiple_words_p = 0;
-  int multiple_digits_p = 0;
-
-  if ((flags & mf_maybe_uninstantiated) && TREE_CODE (value) != INTEGER_CST)
-    {
-      mangle_expression (value);
-      return;
-    }
-
-  /* Unless we were looking at an uninstantiated template, integers
-     should always be represented by constants.  */
-  my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243);
-
-  /* If value doesn't fit in a single HOST_WIDE_INT, we must use a
-     special output routine that can deal with this.  */
-  if (! host_integerp (value, 0))
-    {
-      multiple_words_p = 1;
-      /* And there is certainly going to be more than one digit.  */
-      multiple_digits_p = 1;
-    }
-  else 
-    multiple_digits_p = ((HOST_WIDE_INT) TREE_INT_CST_LOW (value) > 9
-                        || (HOST_WIDE_INT) TREE_INT_CST_LOW (value) < -9);
-
-  /* If necessary, add a leading underscore.  */
-  if (multiple_digits_p && (flags & mf_use_underscores_around_value))
-    OB_PUTC ('_');
-
-  /* Output the number itself.  */
-  if (multiple_words_p)
-    dicat (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value));
-  else
-    icat (TREE_INT_CST_LOW (value));
-
-  if (flags & mf_use_underscores_around_value)
-    {
-      if (multiple_digits_p)
-       OB_PUTC ('_');
-      /* Whether or not there were multiple digits, we don't need an
-        underscore.  We've either terminated the number with an
-        underscore, or else it only had one digit.  */
-      numeric_output_need_bar = 0;
-    }
-  else
-    /* We just output a numeric value.  */
-    numeric_output_need_bar = 1;
-}
-
-
-/* Output S followed by a representation of the TEMPLATE_PARM_INDEX
-   supplied in INDEX.  */
-
-static void 
-build_mangled_template_parm_index (s, index)
-     const char *s;
-     tree index;
-{
-  OB_PUTCP (s);
-  build_underscore_int (TEMPLATE_PARM_IDX (index));
-  /* We use the LEVEL, not the ORIG_LEVEL, because the mangling is a
-     representation of the function from the point of view of its
-     type.  */
-  build_underscore_int (TEMPLATE_PARM_LEVEL (index));
-}
-
-
-/* Mangling for C99 integer types (and Cygnus extensions for 128-bit
-   and other types) is based on the letter "I" followed by the hex
-   representations of the bitsize for the type in question. For
-   encodings that result in larger than two digits, a leading and
-   trailing underscore is added.
-
-   Thus:
-   int1_t   = 001 = I01
-   int8_t   = 008 = I08 
-   int16_t  = 010 = I10
-   int24_t  = 018 = I18
-   int32_t  = 020 = I20
-   int64_t  = 040 = I40
-   int80_t  = 050 = I50
-   int128_t = 080 = I80
-   int256_t = 100 = I_100_
-   int512_t = 200 = I_200_
-
-   Given an integer in decimal format, mangle according to this scheme. */
-
-#if HOST_BITS_PER_WIDE_INT >= 64
-static void
-build_mangled_C99_name (bits)
-     int bits;
-{
-  char mangled[10] = "";
-
-  if (bits > 255)
-    sprintf (mangled, "I_%x_", bits);
-  else
-    sprintf (mangled, "I%.2x", bits);
-
-  OB_PUTCP (mangled);
-}
-#endif
-
-static void
-build_overload_value (type, value, flags)
-     tree type, value;
-     mangling_flags flags;
-{
-  my_friendly_assert (TYPE_P (type), 0);
-
-  while (TREE_CODE (value) == NON_LVALUE_EXPR
-        || TREE_CODE (value) == NOP_EXPR)
-    value = TREE_OPERAND (value, 0);
-
-  if (numeric_output_need_bar)
-    {
-      OB_PUTC ('_');
-      numeric_output_need_bar = 0;
-    }
-
-  if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
-    {
-      build_mangled_template_parm_index ("Y", value);
-      return;
-    }
-
-  if (TYPE_PTRMEM_P (type))
-    {
-      if (TREE_CODE (value) != PTRMEM_CST)
-       /* We should have already rejected this pointer to member,
-          since it is not a constant.  */
-       my_friendly_abort (0);
-
-      /* Get the actual FIELD_DECL.  */
-      value = PTRMEM_CST_MEMBER (value);
-      my_friendly_assert (TREE_CODE (value) == FIELD_DECL, 0);
-
-      /* Output the name of the field.  */
-      build_overload_identifier (DECL_NAME (value));
-      return;
-    }
-  else if (INTEGRAL_TYPE_P (type))
-    {
-      build_overload_int (value, flags);
-      return;
-    }
-
-  /* The only case where we use the extra underscores here is when
-     forming the mangling for an integral non-type template argument.
-     If that didn't happen, stop now.  */
-  flags &= ~mf_use_underscores_around_value;
-
-  switch (TREE_CODE (type))
-    {
-    case REAL_TYPE:
-      {
-       REAL_VALUE_TYPE val;
-       char *bufp = digit_buffer;
-
-       /* We must handle non-constants in templates.  */
-       if (TREE_CODE (value) != REAL_CST)
-         {
-           mangle_expression (value);
-           break;
-         }
-
-       val = TREE_REAL_CST (value);
-       if (REAL_VALUE_ISNAN (val))
-         {
-           sprintf (bufp, "NaN");
-         }
-       else
-         {
-           if (REAL_VALUE_NEGATIVE (val))
-             {
-               val = REAL_VALUE_NEGATE (val);
-               *bufp++ = 'm';
-             }
-           if (REAL_VALUE_ISINF (val))
-             {
-               sprintf (bufp, "Infinity");
-             }
-           else
-             {
-               REAL_VALUE_TO_DECIMAL (val, "%.20e", bufp);
-               bufp = (char *) strchr (bufp, 'e');
-               if (!bufp)
-                 strcat (digit_buffer, "e0");
-               else
-                 {
-                   char *p;
-                   bufp++;
-                   if (*bufp == '-')
-                     {
-                       *bufp++ = 'm';
-                     }
-                   p = bufp;
-                   if (*p == '+')
-                     p++;
-                   while (*p == '0')
-                     p++;
-                   if (*p == 0)
-                     {
-                       *bufp++ = '0';
-                       *bufp = 0;
-                     }
-                   else if (p != bufp)
-                     {
-                       while (*p)
-                         *bufp++ = *p++;
-                       *bufp = 0;
-                     }
-                 }
-#ifdef NO_DOT_IN_LABEL
-               bufp = (char *) strchr (bufp, '.');
-               if (bufp)
-                 *bufp = '_';
-#endif
-             }
-         }
-       OB_PUTCP (digit_buffer);
-       numeric_output_need_bar = 1;
-       return;
-      }
-    case POINTER_TYPE:
-      if (TREE_CODE (value) == INTEGER_CST)
-       {
-         build_overload_int (value, flags);
-         return;
-       }
-      else if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
-       {
-         build_mangled_template_parm_index ("", value);
-         numeric_output_need_bar = 1;
-         return;
-       }
-
-      value = TREE_OPERAND (value, 0);
-
-      /* Fall through.  */
-
-    case REFERENCE_TYPE:
-      if (TREE_CODE (value) == ADDR_EXPR)
-       value = TREE_OPERAND (value, 0);
-
-      if (TREE_CODE (value) == VAR_DECL)
-       {
-         my_friendly_assert (DECL_NAME (value) != 0, 245);
-         build_overload_identifier (DECL_ASSEMBLER_NAME (value));
-         return;
-       }
-      else if (TREE_CODE (value) == FUNCTION_DECL)
-       {
-         my_friendly_assert (DECL_NAME (value) != 0, 246);
-         build_overload_identifier (DECL_ASSEMBLER_NAME (value));
-         return;
-       }
-      else if (TREE_CODE (value) == SCOPE_REF)
-       build_overload_scope_ref (value);
-      else
-       my_friendly_abort (71);
-      break; /* not really needed */
-
-    case RECORD_TYPE:
-      {
-       tree delta;
-       tree idx;
-       tree pfn;
-       tree delta2;
-       tree fn;
-
-       my_friendly_assert (TYPE_PTRMEMFUNC_P (type), 0);
-
-       /* We'll get a ADDR_EXPR of a SCOPE_REF here if we're
-          mangling, an instantiation of something like:
-
-            template <class T, void (T::*fp)()> class C {};
-            template <class T> C<T, &T::f> x();  
-       
-          We mangle the return type of the function, and that
-          contains template parameters.  */
-       if (TREE_CODE (value) == ADDR_EXPR
-           && TREE_CODE (TREE_OPERAND (value, 0)) == SCOPE_REF)
-         {
-           build_overload_scope_ref (TREE_OPERAND (value, 0));
-           break;
-         }
-
-       my_friendly_assert (TREE_CODE (value) == PTRMEM_CST, 0);
-
-       expand_ptrmemfunc_cst (value, &delta, &idx, &pfn, &delta2);
-       fn = PTRMEM_CST_MEMBER (value);
-       build_overload_int (delta, flags);
-       OB_PUTC ('_');
-       if (!flag_new_abi)
-         {
-           build_overload_int (idx, flags);
-           OB_PUTC ('_');
-         }
-       else if (DECL_VIRTUAL_P (fn))
-         {
-           build_overload_int (DECL_VINDEX (fn), flags);
-           OB_PUTC ('_');
-         }
-
-       if (!DECL_VIRTUAL_P (fn))
-         {
-           numeric_output_need_bar = 0;
-           build_overload_identifier (DECL_ASSEMBLER_NAME (fn));
-         }
-       else if (!flag_new_abi)
-         {
-           OB_PUTC ('i');
-           build_overload_int (delta2, flags);
-         }
-      }
-      break;
-      
-    default:
-      sorry ("conversion of %s as template parameter",
-            tree_code_name [(int) TREE_CODE (type)]);
-      my_friendly_abort (72);
-    }
-}
-
-
-/* Add encodings for the declaration of template template parameters.
-   PARMLIST must be a TREE_VEC.  */
-
-static void
-build_template_template_parm_names (parmlist)
-     tree parmlist;
-{
-  int i, nparms;
-
-  my_friendly_assert (TREE_CODE (parmlist) == TREE_VEC, 990228);
-  nparms = TREE_VEC_LENGTH (parmlist);
-  icat (nparms);
-  for (i = 0; i < nparms; i++)
-    {
-      tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
-      if (TREE_CODE (parm) == TYPE_DECL)
-       {
-         /* This parameter is a type.  */
-         OB_PUTC ('Z');
-       }
-      else if (TREE_CODE (parm) == TEMPLATE_DECL)
-       {
-         /* This parameter is a template. */
-         OB_PUTC ('z');
-         build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm));
-       }
-      else
-       /* It's a PARM_DECL.  */
-       build_mangled_name_for_type (TREE_TYPE (parm));
-    }
-}
-
-
-/* Add encodings for the vector of template parameters in PARMLIST,
-   given the vector of arguments to be substituted in ARGLIST.  */
-
-static void
-build_template_parm_names (parmlist, arglist)
-     tree parmlist;
-     tree arglist;
-{
-  int i, nparms;
-  tree inner_args = INNERMOST_TEMPLATE_ARGS (arglist);
-
-  nparms = TREE_VEC_LENGTH (parmlist);
-  icat (nparms);
-  for (i = 0; i < nparms; i++)
-    {
-      tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
-      tree arg = TREE_VEC_ELT (inner_args, i);
-      if (TREE_CODE (parm) == TYPE_DECL)
-       {
-         /* This parameter is a type.  */
-         OB_PUTC ('Z');
-         build_mangled_name_for_type (arg);
-       }
-      else if (TREE_CODE (parm) == TEMPLATE_DECL)
-       {
-         /* This parameter is a template.  */
-         if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
-           /* Output parameter declaration, argument index and level.  */
-           build_mangled_name_for_type (arg);
-         else
-           {
-             /* A TEMPLATE_DECL node, output the parameter declaration 
-                and template name */
-
-             OB_PUTC ('z');
-             build_template_template_parm_names
-               (DECL_INNERMOST_TEMPLATE_PARMS (parm));
-             icat (IDENTIFIER_LENGTH (DECL_NAME (arg)));
-             OB_PUTID (DECL_NAME (arg));
-           }
-       }
-      else
-       {
-         parm = tsubst (parm, inner_args, /*complain=*/1, NULL_TREE);
-         /* It's a PARM_DECL.  */
-         build_mangled_name_for_type (TREE_TYPE (parm));
-         build_overload_value (TREE_TYPE (parm), arg, 
-                               ((mf_maybe_uninstantiated 
-                                 * uses_template_parms (arglist))
-                                | mf_use_underscores_around_value));
-       }
-    }
- }
-
-/* Output the representation for NAME, which is either a TYPE_DECL or
-   an IDENTIFIER.  */
-
-static void
-build_overload_identifier (name)
-     tree name;
-{
-  if (TREE_CODE (name) == TYPE_DECL
-      && CLASS_TYPE_P (TREE_TYPE (name))
-      && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name))
-      && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name)))
-         || (TREE_CODE (CP_DECL_CONTEXT (CLASSTYPE_TI_TEMPLATE 
-                                         (TREE_TYPE (name))))
-             == FUNCTION_DECL)))
-    {
-      /* NAME is the TYPE_DECL for a template specialization.  */
-      tree template, parmlist, arglist, tname;
-      template = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name));
-      arglist = CLASSTYPE_TI_ARGS (TREE_TYPE (name));
-      tname = DECL_NAME (template);
-      parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
-      OB_PUTC ('t');
-      icat (IDENTIFIER_LENGTH (tname));
-      OB_PUTID (tname);
-      build_template_parm_names (parmlist, arglist);
-    }
-  else
-    {
-      if (TREE_CODE (name) == TYPE_DECL)
-       name = DECL_NAME (name);
-      if (numeric_output_need_bar)
-       {
-         OB_PUTC ('_');
-         numeric_output_need_bar = 0;
-       }
-      icat (IDENTIFIER_LENGTH (name));
-      OB_PUTID (name);
-    }
-}
-
-/* Given DECL, either a class TYPE, TYPE_DECL or FUNCTION_DECL, produce
-   the mangling for it.  Used by build_mangled_name and build_static_name.  */
-
-static void
-build_qualified_name (decl)
-     tree decl;
-{
-  tree context;
-  int i = 1;
-
-  if (TYPE_P (decl))
-    decl = TYPE_NAME (decl);
-
-  /* If DECL_ASSEMBLER_NAME has been set properly, use it.  */
-  if (TREE_CODE (decl) == TYPE_DECL
-      && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !flag_do_squangling)
-    {
-      tree id = DECL_ASSEMBLER_NAME (decl);
-      OB_PUTID (id);
-      if (ISDIGIT (IDENTIFIER_POINTER (id) [IDENTIFIER_LENGTH (id) - 1]))
-       numeric_output_need_bar = 1;
-      return;
-    }
-
-  context = decl;
-  /* If we can't find a Ktype, do it the hard way.  */
-  if (check_ktype (context, FALSE) == -1)
-    {
-      /* Count type and namespace scopes.  */
-      while (1)
-       {
-         context = CP_DECL_CONTEXT (context);
-         if (context == global_namespace)
-           break;
-         i += 1;
-         if (check_ktype (context, FALSE) != -1)
-           /* Found one!  */
-           break;
-         if (TYPE_P (context))
-           context = TYPE_NAME (context);
-       }
-    }
-
-  if (i > 1)
-    {
-      OB_PUTC ('Q');
-      build_underscore_int (i);
-      numeric_output_need_bar = 0;
-    }
-  build_overload_nested_name (decl);
-}
-
-/* Output the mangled representation for TYPE.  If EXTRA_GCODE is
-   non-zero, mangled names for structure/union types are intentionally
-   mangled differently from the method described in the ARM.  */
-
-static void 
-build_mangled_name_for_type_with_Gcode (type, extra_Gcode)
-     tree type;
-     int extra_Gcode;
-{
-  if (TYPE_PTRMEMFUNC_P (type))
-    type = TYPE_PTRMEMFUNC_FN_TYPE (type);
-  process_modifiers (type);
-  process_overload_item (type, extra_Gcode);
-}
-
-/* Like build_mangled_name_for_type_with_Gcode, but never outputs the
-   `G'.  */
-
-static void
-build_mangled_name_for_type (type)
-     tree type;
-{
-  build_mangled_name_for_type_with_Gcode (type, 0);
-}
-
-/* Given a list of parameters in PARMTYPES, create an unambiguous
-   overload string. Should distinguish any type that C (or C++) can
-   distinguish. I.e., pointers to functions are treated correctly.
-
-   Caller must deal with whether a final `e' goes on the end or not.
-
-   Any default conversions must take place before this function
-   is called.
-
-   BEGIN and END control initialization and finalization of the
-   obstack where we build the string.  */
-
-char *
-build_overload_name (parmtypes, begin, end)
-     tree parmtypes;
-     int begin, end;
-{
-  char *ret;
-
-  /* This function is obsoleted by the new ABI.  */
-  my_friendly_assert (!flag_new_abi, 200005221);
-
-  start_squangling ();
-  ret = build_mangled_name (parmtypes, begin, end);
-  end_squangling ();
-  return ret ;
-}
-
-/* Output the mangled representation for PARMTYPES.  If PARMTYPES is a
-   TREE_LIST, then it is a list of parameter types.  Otherwise,
-   PARMTYPES must be a single type.  */
-
-static char *
-build_mangled_name (parmtypes, begin, end)
-     tree parmtypes;
-     int begin, end;
-{
-  /* This function is obsoleted by the new ABI.  */
-  my_friendly_assert (!flag_new_abi, 200004105);
-
-  if (begin) 
-    OB_INIT ();
-
-  if (TREE_CODE (parmtypes) != TREE_LIST)  
-    /* There is only one type.  */
-    build_mangled_name_for_type (parmtypes);
-  else  
-    {
-      /* There are several types in a parameter list.  */
-      int nrepeats = 0;
-      int old_style_repeats = !flag_do_squangling && !nofold && typevec;
-      tree last_type = NULL_TREE;
-
-      for (; parmtypes && parmtypes != void_list_node;
-          parmtypes = TREE_CHAIN (parmtypes))
-       {
-         /* We used to call canonical_type_variant here, but that isn't
-            good enough; it doesn't handle pointers to typedef types.  So
-            we can't just set TREE_USED to say we've seen a type already;
-            we have to check each of the earlier types with same_type_p.  */
-         tree parmtype = TREE_VALUE (parmtypes);
-
-         if (old_style_repeats)
-           {
-             /* Every argument gets counted.  */
-             my_friendly_assert (maxtype < VARRAY_SIZE (typevec), 387);
-             VARRAY_TREE (typevec, maxtype) = parmtype;
-             maxtype++;
-           }
-
-         if (last_type && same_type_p (parmtype, last_type))
-           {
-             if (flag_do_squangling 
-                 || (old_style_repeats
-                     && is_back_referenceable_type (parmtype)))
-               {
-                 /* The next type is the same as this one.  Keep
-                    track of the repetition, and output the repeat
-                    count later.  */
-                 nrepeats++;
-                 continue;
-               }
-           }
-         else if (nrepeats != 0)
-           {
-             /* Indicate how many times the previous parameter was
-                repeated.  */
-             if (old_style_repeats)
-               flush_repeats (nrepeats, last_type);
-             else
-               issue_nrepeats (nrepeats, last_type);
-             nrepeats = 0;
-           }
-         
-         /* Insead of protecting flush_repeats() against
-            error_mark_node, we can do it here.  Since we wouldn't
-            add anything for an ERROR_MARK anyway, it's ok to skip
-            the mangling for this type.  */
-         if (old_style_repeats && parmtype == error_mark_node)
-           {
-             last_type = NULL_TREE;
-             continue;
-           }
-
-         last_type = parmtype;
-
-         /* Note that for bug-compatibility with 2.7.2, we can't build up
-            repeats of types other than the most recent one.  So we call
-            flush_repeats every round, if we get this far.  */
-         if (old_style_repeats && flush_repeats (0, parmtype))
-           continue;
-
-         /* Output the PARMTYPE.  */
-         build_mangled_name_for_type_with_Gcode (parmtype, 1);
-       }
-
-      /* Output the repeat count for the last parameter, if
-        necessary.  */
-      if (nrepeats != 0)
-       {
-         if (old_style_repeats)
-           flush_repeats (nrepeats, last_type);
-         else
-           issue_nrepeats (nrepeats, last_type);
-         nrepeats = 0;
-       }
-
-      if (!parmtypes)
-       /* The parameter list ends in an ellipsis.  */
-       OB_PUTC ('e');
-    }
-
-  if (end) 
-    OB_FINISH ();
-  return (char *) obstack_base (&scratch_obstack);
-}
-
-/* Emit modifiers such as constant, read-only, and volatile.  */
-
-static void 
-process_modifiers (parmtype) 
-     tree parmtype;
-{
-  /* Note that here we do not use CP_TYPE_CONST_P and friends because
-     we describe types recursively; we will get the `const' in 
-     `const int ()[10]' when processing the `const int' part.  */
-  if (TYPE_READONLY (parmtype))
-    OB_PUTC ('C');
-  if (TREE_CODE (parmtype) == INTEGER_TYPE
-      && ! same_type_p (parmtype, char_type_node)
-      && ! same_type_p (parmtype, wchar_type_node)
-      && (TYPE_MAIN_VARIANT (parmtype)
-         == unsigned_type (TYPE_MAIN_VARIANT (parmtype)))
-      && ! TYPE_FOR_JAVA (parmtype))
-    OB_PUTC ('U');
-  if (TYPE_VOLATILE (parmtype))
-    OB_PUTC ('V');
-  /* It would be better to use `R' for `restrict', but that's already
-     used for reference types.  And `r' is used for `long double'.  */
-  if (TYPE_RESTRICT (parmtype))
-    OB_PUTC ('u');
-}
-
-/* Check to see if TYPE has been entered into the Bcode typelist.  If
-   so, return 1 and emit a backreference to TYPE.  Otherwise, add TYPE
-   to the list of back-referenceable types and return 0.  */
-
-static int 
-check_btype (type) 
-     tree type;
-{
-  size_t x;
-
-  if (btypelist == NULL)
-    return 0;
-
-  if (!is_back_referenceable_type (type))
-    return 0;
-
-  for (x = 0; x < maxbtype; x++) 
-    if (same_type_p (type, VARRAY_TREE (btypelist, x)))
-      {
-       OB_PUTC ('B');
-       icat (x);
-       if (x > 9)
-         OB_PUTC ('_');
-       return 1 ;
-      }
-
-  if (VARRAY_SIZE (btypelist) <= maxbtype) 
-    /* Enlarge the table.  */
-    VARRAY_GROW (btypelist,
-                VARRAY_SIZE (btypelist) * 3 / 2);
-
-  /* Register the TYPE.  */
-  VARRAY_TREE (btypelist, maxbtype) = type;
-  maxbtype++;
-
-  return 0;
-}
-
-/* Emit the correct code for various node types.  */
-
-static void 
-process_overload_item (parmtype, extra_Gcode) 
-  tree parmtype;
-  int extra_Gcode;
-{
-  tree tmp;
-
-  numeric_output_need_bar = 0;
-
-  /* Our caller should have already handed any qualifiers, so pull out the
-     TYPE_MAIN_VARIANT to avoid typedef confusion.  Except we can't do that
-     for arrays, because they are transparent to qualifiers.  Sigh.  */
-  if (TREE_CODE (parmtype) == ARRAY_TYPE)
-    parmtype = canonical_type_variant (parmtype);
-  else
-    parmtype = TYPE_MAIN_VARIANT (parmtype);
-
-  /* These tree types are considered modifiers for B code squangling,
-     and therefore should not get entries in the Btypelist.  They are,
-     however, repeatable types.  */
-
-  switch (TREE_CODE (parmtype))
-    {
-    case REFERENCE_TYPE:
-      OB_PUTC ('R');
-      goto more;
-
-    case ARRAY_TYPE:
-      {
-        OB_PUTC ('A');
-        if (TYPE_DOMAIN (parmtype) == NULL_TREE)
-         OB_PUTC ('_');
-        else
-         {
-           tree length = array_type_nelts (parmtype);
-           if (TREE_CODE (length) != INTEGER_CST || flag_do_squangling)
-             {
-               length = fold (build (PLUS_EXPR, TREE_TYPE (length),
-                                     length, integer_one_node));
-               STRIP_NOPS (length);
-             }
-           build_overload_value (sizetype, length, 1);
-         }
-       if (numeric_output_need_bar && ! flag_do_squangling)
-         OB_PUTC ('_');
-        goto more;
-      }
-
-    case POINTER_TYPE:
-      OB_PUTC ('P');
-    more:
-      build_mangled_name_for_type (TREE_TYPE (parmtype));
-      return;
-      break;
-
-    default:
-      break;
-    }
-  
-  if (flag_do_squangling && check_btype (parmtype)) 
-    /* If PARMTYPE is already in the list of back-referenceable types,
-       then check_btype will output the appropriate reference, and
-       there's nothing more to do.  */
-    return;
-
-  switch (TREE_CODE (parmtype))
-    {
-    case OFFSET_TYPE:
-      OB_PUTC ('O');
-      build_mangled_name_for_type (TYPE_OFFSET_BASETYPE (parmtype));
-      OB_PUTC ('_');
-      build_mangled_name_for_type (TREE_TYPE (parmtype));
-      break;
-
-    case FUNCTION_TYPE:
-    case METHOD_TYPE:
-      {
-        tree parms = TYPE_ARG_TYPES (parmtype);
-
-       /* Rather than implementing a reentrant TYPEVEC, we turn off
-          repeat codes here, unless we're squangling.  Squangling
-          doesn't make use of the TYPEVEC, so there's no reentrancy
-          problem.  */
-       int old_nofold = nofold;
-       if (!flag_do_squangling)
-         nofold = 1;
-
-       if (TREE_CODE (parmtype) == METHOD_TYPE)
-         {
-           /* Mark this as a method.  */
-            OB_PUTC ('M');
-           /* Output the class of which this method is a member.  */
-            build_mangled_name_for_type (TYPE_METHOD_BASETYPE (parmtype));
-           /* Output any qualifiers for the `this' parameter.  */
-           process_modifiers (TREE_TYPE (TREE_VALUE (parms)));
-         }
-
-       /* Output the parameter types.  */
-       OB_PUTC ('F');
-       if (parms == NULL_TREE)
-         OB_PUTC ('e');
-       else if (parms == void_list_node)
-         OB_PUTC ('v');
-       else
-         build_mangled_name (parms, 0, 0);
-
-        /* Output the return type.  */
-        OB_PUTC ('_');
-        build_mangled_name_for_type (TREE_TYPE (parmtype));
-
-        nofold = old_nofold;
-        break;
-      }
-
-    case INTEGER_TYPE:
-    iagain:
-      if (parmtype == integer_type_node
-          || parmtype == unsigned_type_node
-         || parmtype == java_int_type_node)
-        OB_PUTC ('i');
-      else if (parmtype == long_integer_type_node
-               || parmtype == long_unsigned_type_node)
-        OB_PUTC ('l');
-      else if (parmtype == short_integer_type_node
-               || parmtype == short_unsigned_type_node
-              || parmtype == java_short_type_node)
-        OB_PUTC ('s');
-      else if (parmtype == signed_char_type_node)
-        {
-          OB_PUTC ('S');
-          OB_PUTC ('c');
-        }
-      else if (parmtype == char_type_node
-               || parmtype == unsigned_char_type_node
-              || parmtype == java_byte_type_node)
-        OB_PUTC ('c');
-      else if (parmtype == wchar_type_node
-              || parmtype == java_char_type_node)
-        OB_PUTC ('w');
-      else if (parmtype == long_long_integer_type_node
-              || parmtype == long_long_unsigned_type_node
-              || parmtype == java_long_type_node)
-        OB_PUTC ('x');
-      else if (parmtype == java_boolean_type_node)
-       OB_PUTC ('b');
-      /* Handle intSI_type_node and such like their C++ equivalents.  */
-      else if (tmp = type_for_mode (TYPE_MODE (parmtype),
-                                   TREE_UNSIGNED (parmtype)),
-              parmtype != tmp)
-       {
-         parmtype = tmp;
-         goto iagain;
-       }
-#if HOST_BITS_PER_WIDE_INT >= 64
-      else
-       {
-         int bits = TREE_INT_CST_LOW (TYPE_SIZE (parmtype));
-         build_mangled_C99_name (bits);
-       }
-#else
-      else
-       my_friendly_abort (73);
-#endif
-      break;
-
-    case BOOLEAN_TYPE:
-      OB_PUTC ('b');
-      break;
-
-    case REAL_TYPE:
-      if (parmtype == long_double_type_node)
-        OB_PUTC ('r');
-      else if (parmtype == double_type_node
-              || parmtype == java_double_type_node)
-        OB_PUTC ('d');
-      else if (parmtype == float_type_node
-              || parmtype == java_float_type_node)
-        OB_PUTC ('f');
-      else my_friendly_abort (74);
-      break;
-
-    case COMPLEX_TYPE:
-      OB_PUTC ('J');
-      build_mangled_name_for_type (TREE_TYPE (parmtype));
-      break;
-
-    case VECTOR_TYPE:
-      OB_PUTC ('o');
-      build_mangled_name_for_type (TREE_TYPE (parmtype));
-      break;
-
-    case VOID_TYPE:
-      OB_PUTC ('v');
-      break;
-
-    case ERROR_MARK:   /* not right, but nothing is anyway */
-      break;
-
-      /* have to do these */
-    case UNION_TYPE:
-    case RECORD_TYPE:
-      {   
-        if (extra_Gcode)
-          OB_PUTC ('G');       /* make it look incompatible with AT&T */
-        /* drop through into next case */
-      }
-    case ENUMERAL_TYPE:
-      {
-        tree name = TYPE_NAME (parmtype);
-
-        my_friendly_assert (TREE_CODE (name) == TYPE_DECL, 248);
-
-        build_qualified_name (name);
-        break;
-      }
-
-    case UNKNOWN_TYPE:
-      /* This will take some work.  */
-      OB_PUTC ('?');
-      break;
-
-    case BOUND_TEMPLATE_TEMPLATE_PARM:
-      /* Find and output the original template parameter 
-         declaration. */
-      build_mangled_template_parm_index ("tzX",
-                                        TEMPLATE_TYPE_PARM_INDEX 
-                                        (parmtype));
-      build_template_parm_names
-       (DECL_INNERMOST_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (parmtype)),
-        TYPE_TI_ARGS (parmtype));
-      break;
-
-    case TEMPLATE_TEMPLATE_PARM:
-      build_mangled_template_parm_index ("ZzX",
-                                        TEMPLATE_TYPE_PARM_INDEX 
-                                        (parmtype));
-      build_template_template_parm_names
-       (DECL_INNERMOST_TEMPLATE_PARMS (TYPE_STUB_DECL (parmtype)));
-      break;
-
-    case TEMPLATE_TYPE_PARM:
-      build_mangled_template_parm_index ("X", 
-                                        TEMPLATE_TYPE_PARM_INDEX
-                                        (parmtype));
-      break;
-        
-    case TYPENAME_TYPE:
-      /* When mangling the type of a function template whose
-         declaration looks like:
-
-         template <class T> void foo(typename T::U)
-         
-         we have to mangle these.  */
-      build_qualified_name (parmtype);
-      break;
-
-    default:
-      my_friendly_abort (75);
-    }
-
-}
-
-/* Produce the mangling for a variable named NAME in CONTEXT, which can
-   be either a class TYPE or a FUNCTION_DECL.  */
-
-tree
-build_static_name (context, name)
-     tree context, name;
-{
-  /* This function is obsoleted by the new ABI.  */
-  my_friendly_assert (!flag_new_abi, 200004106);
-
-  OB_INIT ();
-  numeric_output_need_bar = 0;
-  start_squangling ();
-#ifdef JOINER
-  OB_PUTC ('_');
-  build_qualified_name (context);
-  OB_PUTC (JOINER);
-#else
-  OB_PUTS ("__static_");
-  build_qualified_name (context);
-  OB_PUTC ('_');
-#endif
-  OB_PUTID (name);
-  OB_FINISH ();
-  end_squangling ();
-
-  return get_identifier ((char *)obstack_base (&scratch_obstack));
-}
-\f
-/* FOR_METHOD should be 1 if the declaration in question is for a member
-   of a class (including a static member) and 2 if the declaration is
-   for a constructor.  */
-tree 
-build_decl_overload_real (decl, parms, ret_type, tparms, targs,
-                         for_method) 
-     tree decl;
-     tree parms;
-     tree ret_type;
-     tree tparms;
-     tree targs;
-     int for_method;
-{
-  const char *name;
-  enum tree_code operator_code;
-
-  /* This function is obsoleted by the new ABI.  */
-  my_friendly_assert (!flag_new_abi, 20000410);
-
-  operator_code = DECL_OVERLOADED_OPERATOR_P (decl);
-  if (!DECL_CONV_FN_P (decl) && operator_code)
-    {
-      /* member operators new and delete look like methods at this
-         point.  */
-      if (! for_method && CP_DECL_CONTEXT (decl) == global_namespace
-         && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST
-         && TREE_CHAIN (parms) == void_list_node)
-       switch (operator_code)
-         {
-         case DELETE_EXPR:
-           return get_identifier ("__builtin_delete");
-         case VEC_DELETE_EXPR:
-           return get_identifier ("__builtin_vec_delete");
-         case NEW_EXPR:
-           return get_identifier ("__builtin_new");
-         case VEC_NEW_EXPR:
-           return get_identifier ("__builtin_vec_new");
-         default:
-           break;
-         }
-
-      if (DECL_ASSIGNMENT_OPERATOR_P (decl))
-       name = assignment_operator_name_info[(int) operator_code].mangled_name;
-      else
-       name = operator_name_info[(int) operator_code].mangled_name;
-    }
-  else
-    name = IDENTIFIER_POINTER (DECL_NAME (decl));
-
-  start_squangling ();
-  OB_INIT ();
-  if (for_method != 2)
-    OB_PUTCP (name);
-  /* Otherwise, we can divine that this is a constructor,
-     and figure out its name without any extra encoding.  */
-
-  OB_PUTC2 ('_', '_');
-  numeric_output_need_bar = 0;
-
-  if (tparms)
-    {
-      OB_PUTC ('H');
-      build_template_parm_names (tparms, targs);
-      OB_PUTC ('_');
-    }
-  else if (!for_method && CP_DECL_CONTEXT (decl) == global_namespace)
-    OB_PUTC ('F');
-
-  if (!for_method && CP_DECL_CONTEXT (decl) != global_namespace)
-    /* qualify with namespace */
-    build_qualified_name (CP_DECL_CONTEXT (decl));
-
-  if (parms == NULL_TREE)
-    OB_PUTC ('e');
-  else if (parms == void_list_node)
-    OB_PUTC ('v');
-  else
-    {
-      if (!flag_do_squangling)
-        {
-         /* Allocate typevec array.  */
-         size_t typevec_size = list_length (parms);
-          maxtype = 0;
-         if (!for_method && CP_DECL_CONTEXT (decl) != global_namespace)
-           /* The namespace of a global function needs one slot.  */
-           typevec_size++;
-         VARRAY_TREE_INIT (typevec, typevec_size, "typevec");
-        }
-      nofold = 0;
-
-      if (for_method)
-       {
-         tree this_type = TREE_TYPE (TREE_VALUE (parms));
-
-         build_mangled_name_for_type (this_type);
-
-          if (!flag_do_squangling) 
-           {
-             my_friendly_assert (maxtype < VARRAY_SIZE (typevec), 387);
-             VARRAY_TREE (typevec, maxtype) = this_type;
-             maxtype++;
-           }
-
-         if (TREE_CHAIN (parms))
-           build_mangled_name (TREE_CHAIN (parms), 0, 0);
-         else
-           OB_PUTC ('e');
-       }
-      else
-       {
-         /* the namespace qualifier for a global function 
-            will count as type */
-         if (CP_DECL_CONTEXT (decl) != global_namespace
-             && !flag_do_squangling)
-           {
-             my_friendly_assert (maxtype < VARRAY_SIZE (typevec), 387);
-             VARRAY_TREE (typevec, maxtype) = CP_DECL_CONTEXT (decl);
-             maxtype++;
-           }
-         build_mangled_name (parms, 0, 0);
-       }
-
-      if (!flag_do_squangling)
-       /* Deallocate typevec array.  */
-       VARRAY_FREE (typevec);
-    }
-
-  if (ret_type != NULL_TREE && for_method != 2)
-    {
-      /* Add the return type. */
-      OB_PUTC ('_');
-      build_mangled_name_for_type (ret_type);
-    }
-
-  OB_FINISH ();
-  end_squangling ();
-  {
-    tree n = get_identifier (obstack_base (&scratch_obstack));
-    return n;
-  }
+  init_mangle ();
 }
 
+\f
 /* Set the mangled name (DECL_ASSEMBLER_NAME) for DECL.  */
 
 void
-set_mangled_name_for_decl (decl)
-     tree decl;
+set_mangled_name_for_decl (tree decl)
 {
-  tree parm_types;
-
   if (processing_template_decl)
     /* There's no need to mangle the name of a template function.  */
     return;
 
-  if (flag_new_abi)
-    {
-      DECL_ASSEMBLER_NAME (decl) = mangle_decl (decl);
-      return;
-    }
-
-  if (DECL_EXTERN_C_P (decl))
-    {
-      /* In extern "C" we have to mangle at least overloaded operators,
-        because they contain characters invalid in assembler.  */
-      enum tree_code code = DECL_OVERLOADED_OPERATOR_P (decl);
-      const char *name;
-
-      if (code)
-       {
-         if (DECL_ASSIGNMENT_OPERATOR_P (decl))
-           name = assignment_operator_name_info[(int) code].mangled_name;
-         else
-           name = operator_name_info[(int) code].mangled_name;
-         DECL_ASSEMBLER_NAME (decl) = get_identifier (name);
-         return;
-       }
-    }
-
-  parm_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
-
-  if (DECL_STATIC_FUNCTION_P (decl))
-    parm_types = 
-      hash_tree_chain (build_pointer_type (DECL_CONTEXT (decl)),
-                                          parm_types);
-  else
-    /* The only member functions whose type is a FUNCTION_TYPE, rather
-       than a METHOD_TYPE, should be static members.  */
-    my_friendly_assert (!DECL_CONTEXT (decl)
-                       || !IS_AGGR_TYPE_CODE (TREE_CODE (DECL_CONTEXT (decl)))
-                       || TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE,
-                       0);
-
-  DECL_ASSEMBLER_NAME (decl)
-    = build_decl_overload_real (decl, parm_types, NULL_TREE,
-                               NULL_TREE, NULL_TREE,
-                               DECL_FUNCTION_MEMBER_P (decl)
-                               + DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl));
+  mangle_decl (decl);
 }
 
-/* Build an overload name for the type expression TYPE.  */
-
-tree
-build_typename_overload (type)
-     tree type;
-{
-  tree id;
-
-  /* This function is obsoleted by the new ABI.  */
-  my_friendly_assert (!flag_new_abi, 200004108);
-
-  OB_INIT ();
-  OB_PUTS (OPERATOR_TYPENAME_FORMAT);
-  nofold = 1;
-  start_squangling ();
-  build_mangled_name (type, 0, 1);
-  id = get_identifier (obstack_base (&scratch_obstack));
-  IDENTIFIER_OPNAME_P (id) = 1;
-  IDENTIFIER_TYPENAME_P (id) = 1;
-  TREE_TYPE (id) = type;
-  end_squangling ();
-  return id;
-}
+\f
+/* Return a this or result adjusting thunk to FUNCTION.  THIS_ADJUSTING
+   indicates whether it is a this or result adjusting thunk.
+   FIXED_OFFSET and VIRTUAL_OFFSET indicate how to do the adjustment
+   (see thunk_adjust).  VIRTUAL_OFFSET can be NULL, but FIXED_OFFSET
+   never is.  VIRTUAL_OFFSET is the /index/ into the vtable for this
+   adjusting thunks, we scale it to a byte offset. For covariant
+   thunks VIRTUAL_OFFSET is the virtual binfo.  You must post process
+   the returned thunk with finish_thunk.  */
 
 tree
-build_overload_with_type (name, type)
-     tree name, type;
+make_thunk (tree function, bool this_adjusting,
+           tree fixed_offset, tree virtual_offset)
 {
-  /* This function is obsoleted by the new ABI.  */
-  my_friendly_assert (!flag_new_abi, 200004109);
-
-  OB_INIT ();
-  OB_PUTID (name);
-  nofold = 1;
-
-  start_squangling ();
-  build_mangled_name (type, 0, 1);
-  end_squangling ();
-  return get_identifier (obstack_base (&scratch_obstack));
-}
+  HOST_WIDE_INT d;
+  tree thunk;
+  
+  my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 20021025);
+  /* We can have this thunks to covariant thunks, but not vice versa.  */
+  my_friendly_assert (!DECL_THIS_THUNK_P (function), 20021127);
+  my_friendly_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting,
+                     20031123);
+  
+  /* Scale the VIRTUAL_OFFSET to be in terms of bytes.  */
+  if (this_adjusting && virtual_offset)
+    virtual_offset 
+      = size_binop (MULT_EXPR,
+                   virtual_offset,
+                   convert (ssizetype,
+                            TYPE_SIZE_UNIT (vtable_entry_type)));
+  
+  d = tree_low_cst (fixed_offset, 0);
+  
+  /* See if we already have the thunk in question.  For this_adjusting
+     thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it
+     will be a BINFO.  */
+  for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
+    if (DECL_THIS_THUNK_P (thunk) == this_adjusting
+       && THUNK_FIXED_OFFSET (thunk) == d
+       && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk)
+       && (!virtual_offset
+           || (this_adjusting
+               ? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
+                                     virtual_offset)
+               : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)))
+      return thunk;
+  
+  /* All thunks must be created before FUNCTION is actually emitted;
+     the ABI requires that all thunks be emitted together with the
+     function to which they transfer control.  */
+  my_friendly_assert (!TREE_ASM_WRITTEN (function), 20021025);
+  /* Likewise, we can only be adding thunks to a function declared in
+     the class currently being laid out.  */
+  my_friendly_assert (TYPE_SIZE (DECL_CONTEXT (function))
+                     && TYPE_BEING_DEFINED (DECL_CONTEXT (function)),
+                     20031211);
+
+  thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
+  DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
+  cxx_dup_lang_specific_decl (thunk);
+  DECL_THUNKS (thunk) = NULL_TREE;
+  
+  DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
+  TREE_READONLY (thunk) = TREE_READONLY (function);
+  TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
+  TREE_PUBLIC (thunk) = TREE_PUBLIC (function);
+  if (flag_weak)
+    comdat_linkage (thunk);
+  SET_DECL_THUNK_P (thunk, this_adjusting);
+  THUNK_TARGET (thunk) = function;
+  THUNK_FIXED_OFFSET (thunk) = d;
+  THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
+  THUNK_ALIAS (thunk) = NULL_TREE;
+  
+  /* The thunk itself is not a constructor or destructor, even if
+     the thing it is thunking to is.  */
+  DECL_INTERFACE_KNOWN (thunk) = 1;
+  DECL_NOT_REALLY_EXTERN (thunk) = 1;
+  DECL_SAVED_FUNCTION_DATA (thunk) = NULL;
+  DECL_DESTRUCTOR_P (thunk) = 0;
+  DECL_CONSTRUCTOR_P (thunk) = 0;
+  /* And neither is it a clone.  */
+  DECL_CLONED_FUNCTION (thunk) = NULL_TREE;
+  DECL_EXTERNAL (thunk) = 1;
+  DECL_ARTIFICIAL (thunk) = 1;
+  /* Even if this thunk is a member of a local class, we don't
+     need a static chain.  */
+  DECL_NO_STATIC_CHAIN (thunk) = 1;
+  /* The THUNK is not a pending inline, even if the FUNCTION is.  */
+  DECL_PENDING_INLINE_P (thunk) = 0;
+  DECL_INLINE (thunk) = 0;
+  DECL_DECLARED_INLINE_P (thunk) = 0;
+  /* Nor has it been deferred.  */
+  DECL_DEFERRED_FN (thunk) = 0;
+  
+  /* Add it to the list of thunks associated with FUNCTION.  */
+  TREE_CHAIN (thunk) = DECL_THUNKS (function);
+  DECL_THUNKS (function) = thunk;
 
-tree
-get_id_2 (name, name2)
-     const char *name;
-     tree name2;
-{
-  /* This function is obsoleted by the new ABI.  */
-  my_friendly_assert (!flag_new_abi, 20000411);
-
-  OB_INIT ();
-  OB_PUTCP (name);
-  OB_PUTID (name2);
-  OB_FINISH ();
-  return get_identifier (obstack_base (&scratch_obstack));
+  return thunk;
 }
 
-/* Returns the name of a construction vtable group.  TYPE is the most
-   derived class in the hierarhcy.  BINFO is the most derived class in
-   the construction vtable group.  */
+/* Finish THUNK, a thunk decl.  */
 
-tree
-get_ctor_vtbl_name (type, binfo)
-     tree type;
-     tree binfo;
+void
+finish_thunk (tree thunk)
 {
-  /* This function is obsoleted by the new ABI.  */
-  my_friendly_assert (!flag_new_abi, 200005220);
-
-  start_squangling ();
-  OB_INIT ();
-  OB_PUTCP (CTOR_VTBL_NAME_PREFIX);
-  build_mangled_name (type, 0, 0);
-  OB_PUTC ('_');
-  build_mangled_name (BINFO_TYPE (binfo), 0, 0);
-  OB_PUTC ('_');
-  build_overload_int (BINFO_OFFSET (binfo), mf_none);
-  OB_FINISH ();
-  end_squangling ();
-  return get_identifier (obstack_base (&scratch_obstack));
+  tree function, name;
+  tree fixed_offset = ssize_int (THUNK_FIXED_OFFSET (thunk));
+  tree virtual_offset = THUNK_VIRTUAL_OFFSET (thunk);
+
+  my_friendly_assert (!DECL_NAME (thunk) && DECL_THUNK_P (thunk), 20021127);
+  if (virtual_offset && DECL_RESULT_THUNK_P (thunk))
+    virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
+  function = THUNK_TARGET (thunk);
+  name = mangle_thunk (function, DECL_THIS_THUNK_P (thunk),
+                      fixed_offset, virtual_offset);
+
+  /* We can end up with declarations of (logically) different
+     covariant thunks, that do identical adjustments.  The two thunks
+     will be adjusting between within different hierarchies, which
+     happen to have the same layout.  We must nullify one of them to
+     refer to the other.  */
+  if (DECL_RESULT_THUNK_P (thunk))
+    {
+      tree cov_probe;
+
+      for (cov_probe = DECL_THUNKS (function);
+          cov_probe; cov_probe = TREE_CHAIN (cov_probe))
+       if (DECL_NAME (cov_probe) == name)
+         {
+           my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
+           THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe)
+                                  ? THUNK_ALIAS (cov_probe) : cov_probe);
+           break;
+         }
+    }
+  
+  DECL_NAME (thunk) = name;
+  SET_DECL_ASSEMBLER_NAME (thunk, name);
 }
 
-/* Returns a DECL_ASSEMBLER_NAME for the destructor of type TYPE.  */
+/* Adjust PTR by the constant FIXED_OFFSET, and by the vtable
+   offset indicated by VIRTUAL_OFFSET, if that is
+   non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and
+   zero for a result adjusting thunk.  */
 
-tree
-build_destructor_name (type)
-     tree type;
+static tree
+thunk_adjust (tree ptr, bool this_adjusting,
+             HOST_WIDE_INT fixed_offset, tree virtual_offset)
 {
-  return build_overload_with_type (get_identifier (DESTRUCTOR_DECL_PREFIX),
-                                  type);
-}
-\f
-/* Given a tree_code CODE, and some arguments (at least one),
-   attempt to use an overloaded operator on the arguments.
-
-   For unary operators, only the first argument need be checked.
-   For binary operators, both arguments may need to be checked.
-
-   Member functions can convert class references to class pointers,
-   for one-level deep indirection.  More than that is not supported.
-   Operators [](), ()(), and ->() must be member functions.
-
-   We call function call building calls with LOOKUP_COMPLAIN if they
-   are our only hope.  This is true when we see a vanilla operator
-   applied to something of aggregate type.  If this fails, we are free
-   to return `error_mark_node', because we will have reported the
-   error.
-
-   Operators NEW and DELETE overload in funny ways: operator new takes
-   a single `size' parameter, and operator delete takes a pointer to the
-   storage being deleted.  When overloading these operators, success is
-   assumed.  If there is a failure, report an error message and return
-   `error_mark_node'.  */
+  if (this_adjusting)
+    /* Adjust the pointer by the constant.  */
+    ptr = fold (build (PLUS_EXPR, TREE_TYPE (ptr), ptr,
+                      ssize_int (fixed_offset)));
+
+  /* If there's a virtual offset, look up that value in the vtable and
+     adjust the pointer again.  */
+  if (virtual_offset)
+    {
+      tree vtable;
+
+      ptr = save_expr (ptr);
+      /* The vptr is always at offset zero in the object.  */
+      vtable = build1 (NOP_EXPR,
+                      build_pointer_type (build_pointer_type 
+                                          (vtable_entry_type)),
+                      ptr);
+      /* Form the vtable address.  */
+      vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable);
+      /* Find the entry with the vcall offset.  */
+      vtable = build (PLUS_EXPR, TREE_TYPE (vtable), vtable, virtual_offset);
+      /* Get the offset itself.  */
+      vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable);
+      /* Adjust the `this' pointer.  */
+      ptr = fold (build (PLUS_EXPR, TREE_TYPE (ptr), ptr, vtable));
+    }
+  
+  if (!this_adjusting)
+    /* Adjust the pointer by the constant.  */
+    ptr = fold (build (PLUS_EXPR, TREE_TYPE (ptr), ptr,
+                      ssize_int (fixed_offset)));
 
-/* NOSTRICT */
-tree
-build_opfncall (code, flags, xarg1, xarg2, arg3)
-     enum tree_code code;
-     int flags;
-     tree xarg1, xarg2, arg3;
-{
-  return build_new_op (code, flags, xarg1, xarg2, arg3);
+  return ptr;
 }
-\f
-/* This function takes an identifier, ID, and attempts to figure out what
-   it means. There are a number of possible scenarios, presented in increasing
-   order of hair:
 
-   1) not in a class's scope
-   2) in class's scope, member name of the class's method
-   3) in class's scope, but not a member name of the class
-   4) in class's scope, member name of a class's variable
+/* Garbage collector tables contains thunk_labelno even when places
+   inside ifdef block.  */
+static GTY (()) int thunk_labelno;
+#ifdef ASM_OUTPUT_DEF
 
-   NAME is $1 from the bison rule. It is an IDENTIFIER_NODE.
-   VALUE is $$ from the bison rule. It is the value returned by lookup_name ($1)
+/* Create a static alias to function.  */
 
-   As a last ditch, try to look up the name as a label and return that
-   address.
-
-   Values which are declared as being of REFERENCE_TYPE are
-   automatically dereferenced here (as a hack to make the
-   compiler faster).  */
-
-tree
-hack_identifier (value, name)
-     tree value, name;
+static tree
+make_alias_for_thunk (tree function)
 {
-  tree type;
-
-  if (value == error_mark_node)
-    {
-      if (current_class_name)
-       {
-         tree fields = lookup_fnfields (TYPE_BINFO (current_class_type), name, 1);
-         if (fields == error_mark_node)
-           return error_mark_node;
-         if (fields)
-           {
-             tree fndecl;
-
-             fndecl = TREE_VALUE (fields);
-             my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 251);
-             /* I could not trigger this code. MvL */
-             my_friendly_abort (980325);
-#ifdef DEAD
-             if (DECL_CHAIN (fndecl) == NULL_TREE)
-               {
-                 warning ("methods cannot be converted to function pointers");
-                 return fndecl;
-               }
-             else
-               {
-                 error ("ambiguous request for method pointer `%s'",
-                        IDENTIFIER_POINTER (name));
-                 return error_mark_node;
-               }
-#endif
-           }
-       }
-      if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name))
-       {
-         return IDENTIFIER_LABEL_VALUE (name);
-       }
-      return error_mark_node;
-    }
-
-  type = TREE_TYPE (value);
-  if (TREE_CODE (value) == FIELD_DECL)
-    {
-      if (current_class_ptr == NULL_TREE)
-       {
-         if (current_function_decl 
-             && DECL_STATIC_FUNCTION_P (current_function_decl))
-           cp_error ("invalid use of member `%D' in static member function",
-                     value);
-         else
-           /* We can get here when processing a bad default
-              argument, like:
-                struct S { int a; void f(int i = a); }  */
-           cp_error ("invalid use of member `%D'", value);
-
-         return error_mark_node;
-       }
-      TREE_USED (current_class_ptr) = 1;
-
-      /* Mark so that if we are in a constructor, and then find that
-        this field was initialized by a base initializer,
-        we can emit an error message.  */
-      TREE_USED (value) = 1;
-      value = build_component_ref (current_class_ref, name, NULL_TREE, 1);
-    }
-  else if ((TREE_CODE (value) == FUNCTION_DECL
-           && DECL_FUNCTION_MEMBER_P (value))
-          || (TREE_CODE (value) == OVERLOAD
-              && DECL_FUNCTION_MEMBER_P (OVL_CURRENT (value))))
-    {
-      tree decl;
-
-      if (TREE_CODE (value) == OVERLOAD)
-       value = OVL_CURRENT (value);
-
-      decl = maybe_dummy_object (DECL_CONTEXT (value), 0);
-      value = build_component_ref (decl, name, NULL_TREE, 1);
-    }
-  else if (really_overloaded_fn (value))
-    ;
-  else if (TREE_CODE (value) == OVERLOAD)
-    /* not really overloaded function */
-    mark_used (OVL_FUNCTION (value));
-  else if (TREE_CODE (value) == TREE_LIST)
-    {
-      /* Ambiguous reference to base members, possibly other cases?.  */
-      tree t = value;
-      while (t && TREE_CODE (t) == TREE_LIST)
-       {
-         mark_used (TREE_VALUE (t));
-         t = TREE_CHAIN (t);
-       }
-    }
-  else if (TREE_CODE (value) == NAMESPACE_DECL)
-    {
-      cp_error ("use of namespace `%D' as expression", value);
-      return error_mark_node;
-    }
-  else if (DECL_CLASS_TEMPLATE_P (value))
-    {
-      cp_error ("use of class template `%T' as expression", value);
-      return error_mark_node;
-    }
-  else
-    mark_used (value);
-
-  if (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL
-      || TREE_CODE (value) == RESULT_DECL)
-    {
-      tree context = decl_function_context (value);
-      if (context != NULL_TREE && context != current_function_decl
-         && ! TREE_STATIC (value))
-       {
-         cp_error ("use of %s from containing function",
-                     (TREE_CODE (value) == VAR_DECL
-                      ? "`auto' variable" : "parameter"));
-         cp_error_at ("  `%#D' declared here", value);
-         value = error_mark_node;
-       }
-    }
-
-  if (DECL_P (value) && DECL_NONLOCAL (value))
-    {
-      if (DECL_CLASS_SCOPE_P (value)
-         && DECL_CONTEXT (value) != current_class_type)
-       {
-         tree path;
-         path = currently_open_derived_class (DECL_CONTEXT (value));
-         enforce_access (path, value);
-       }
-    }
-  else if (TREE_CODE (value) == TREE_LIST 
-          && TREE_TYPE (value) == error_mark_node)
-    {
-      error ("request for member `%s' is ambiguous in multiple inheritance lattice",
-            IDENTIFIER_POINTER (name));
-      print_candidates (value);
-      return error_mark_node;
-    }
-
-  if (! processing_template_decl)
-    value = convert_from_reference (value);
-  return value;
+  tree alias;
+  char buf[256];
+
+  ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno);
+  thunk_labelno++;
+  alias = build_decl (FUNCTION_DECL, get_identifier (buf),
+                     TREE_TYPE (function));
+  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
+  cxx_dup_lang_specific_decl (alias);
+  DECL_CONTEXT (alias) = NULL;
+  TREE_READONLY (alias) = TREE_READONLY (function);
+  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
+  TREE_PUBLIC (alias) = 0;
+  DECL_INTERFACE_KNOWN (alias) = 1;
+  DECL_NOT_REALLY_EXTERN (alias) = 1;
+  DECL_THIS_STATIC (alias) = 1;
+  DECL_SAVED_FUNCTION_DATA (alias) = NULL;
+  DECL_DESTRUCTOR_P (alias) = 0;
+  DECL_CONSTRUCTOR_P (alias) = 0;
+  DECL_CLONED_FUNCTION (alias) = NULL_TREE;
+  DECL_EXTERNAL (alias) = 0;
+  DECL_ARTIFICIAL (alias) = 1;
+  DECL_NO_STATIC_CHAIN (alias) = 1;
+  DECL_PENDING_INLINE_P (alias) = 0;
+  DECL_INLINE (alias) = 0;
+  DECL_DECLARED_INLINE_P (alias) = 0;
+  DECL_DEFERRED_FN (alias) = 0;
+  DECL_USE_TEMPLATE (alias) = 0;
+  DECL_TEMPLATE_INSTANTIATED (alias) = 0;
+  DECL_TEMPLATE_INFO (alias) = NULL;
+  DECL_INITIAL (alias) = error_mark_node;
+  TREE_ADDRESSABLE (alias) = 1;
+  TREE_USED (alias) = 1;
+  SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
+  TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
+  if (!flag_syntax_only)
+    assemble_alias (alias, DECL_ASSEMBLER_NAME (function));
+  return alias;
 }
+#endif
 
-\f
-/* Return a thunk to FUNCTION.  For a virtual thunk, DELTA is the
-   offset to this used to locate the vptr, and VCALL_INDEX is used to
-   look up the eventual subobject location.  For a non-virtual thunk,
-   DELTA is the offset to this and VCALL_INDEX is zero.  */
+/* Emit the definition of a C++ multiple inheritance or covariant
+   return vtable thunk.  If EMIT_P is nonzero, the thunk is emitted
+   immediately.  */
 
-tree
-make_thunk (function, delta, vcall_index, generate_with_vtable_p)
-     tree function;
-     tree delta;
-     tree vcall_index;
-     int generate_with_vtable_p;
+void
+use_thunk (tree thunk_fndecl, bool emit_p)
 {
-  tree thunk_id;
-  tree thunk;
-  tree func_decl;
-  tree vcall_offset;
-  HOST_WIDE_INT d;
-
-  /* Scale the VCALL_INDEX to be in terms of bytes.  */
-  if (vcall_index)
-    vcall_offset 
-      = size_binop (MULT_EXPR,
-                   vcall_index,
-                   convert (ssizetype,
-                            TYPE_SIZE_UNIT (vtable_entry_type)));
-  else
-    vcall_offset = NULL_TREE;
-
-  d = tree_low_cst (delta, 0);
-
-  if (TREE_CODE (function) != ADDR_EXPR)
-    abort ();
-  func_decl = TREE_OPERAND (function, 0);
-  if (TREE_CODE (func_decl) != FUNCTION_DECL)
-    abort ();
-
-  if (flag_new_abi) 
-    thunk_id = mangle_thunk (TREE_OPERAND (function, 0), 
-                            delta, vcall_offset);
-  else
-    {
-      OB_INIT ();
-      OB_PUTS ("__thunk_");
-      if (d > 0)
-       {
-         OB_PUTC ('n');
-         icat (d);
-       }
-      else
-       icat (-d);
-      OB_PUTC ('_');
-      if (vcall_index)
-       {
-         icat (tree_low_cst (vcall_index, 0));
-         OB_PUTC ('_');
-       }
-      OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
-      OB_FINISH ();
-      thunk_id = get_identifier (obstack_base (&scratch_obstack));
-    }
+  tree a, t, function, alias;
+  tree virtual_offset;
+  HOST_WIDE_INT fixed_offset, virtual_value;
+  bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);
 
-  thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id);
-  if (thunk && !DECL_THUNK_P (thunk))
-    {
-      cp_error ("implementation-reserved name `%D' used", thunk_id);
-      thunk = NULL_TREE;
-      SET_IDENTIFIER_GLOBAL_VALUE (thunk_id, thunk);
-    }
-  if (thunk == NULL_TREE)
-    {
-      thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl));
-      DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (func_decl);
-      copy_lang_decl (func_decl);
-      DECL_CONTEXT (thunk) = DECL_CONTEXT (func_decl);
-      TREE_READONLY (thunk) = TREE_READONLY (func_decl);
-      TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (func_decl);
-      comdat_linkage (thunk);
-      SET_DECL_THUNK_P (thunk);
-      DECL_INITIAL (thunk) = function;
-      THUNK_DELTA (thunk) = d;
-      THUNK_VCALL_OFFSET (thunk) = vcall_offset;
-      THUNK_GENERATE_WITH_VTABLE_P (thunk) = generate_with_vtable_p;
-      /* The thunk itself is not a constructor or destructor, even if
-       the thing it is thunking to is.  */
-      DECL_INTERFACE_KNOWN (thunk) = 1;
-      DECL_NOT_REALLY_EXTERN (thunk) = 1;
-      DECL_SAVED_FUNCTION_DATA (thunk) = NULL;
-      DECL_DESTRUCTOR_P (thunk) = 0;
-      DECL_CONSTRUCTOR_P (thunk) = 0;
-      DECL_EXTERNAL (thunk) = 1;
-      DECL_ARTIFICIAL (thunk) = 1;
-      DECL_VTT_PARM (thunk) = NULL_TREE;
-      /* Even if this thunk is a member of a local class, we don't
-        need a static chain.  */
-      DECL_NO_STATIC_CHAIN (thunk) = 1;
-      /* The THUNK is not a pending inline, even if the FUNC_DECL is.  */
-      DECL_PENDING_INLINE_P (thunk) = 0;
-      /* Nor has it been deferred.  */
-      DECL_DEFERRED_FN (thunk) = 0;
-      /* So that finish_file can write out any thunks that need to be: */
-      pushdecl_top_level (thunk);
-      /* Create RTL for this thunk so that its address can be taken.  */
-      make_decl_rtl (thunk, NULL);
-    }
-  return thunk;
-}
+  /* We should have called finish_thunk to give it a name.  */
+  my_friendly_assert (DECL_NAME (thunk_fndecl), 20021127);
 
-/* Emit the definition of a C++ multiple inheritance vtable thunk.  */
-
-void
-use_thunk (thunk_fndecl, emit_p)
-     tree thunk_fndecl;
-     int emit_p;
-     
-{
-  tree fnaddr;
-  tree function;
-  tree vcall_offset;
-  HOST_WIDE_INT delta;
+  /* We should never be using an alias, always refer to the
+     aliased thunk.  */
+  my_friendly_assert (!THUNK_ALIAS (thunk_fndecl), 20031023);
 
   if (TREE_ASM_WRITTEN (thunk_fndecl))
     return;
   
-  fnaddr = DECL_INITIAL (thunk_fndecl);
-  if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR)
+  function = THUNK_TARGET (thunk_fndecl);
+  if (DECL_RESULT (thunk_fndecl))
     /* We already turned this thunk into an ordinary function.
-       There's no need to process this thunk again.  (We can't just
-       clear DECL_THUNK_P because that will confuse
-       FNADDR_FROM_VTABLE_ENTRY and friends.)  */
+       There's no need to process this thunk again.  */
     return;
 
   /* Thunks are always addressable; they only appear in vtables.  */
@@ -2239,20 +357,41 @@ use_thunk (thunk_fndecl, emit_p)
 
   /* Figure out what function is being thunked to.  It's referenced in
      this translation unit.  */
-  function = TREE_OPERAND (fnaddr, 0);
   TREE_ADDRESSABLE (function) = 1;
   mark_used (function);
-  TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1;
+  mark_referenced (DECL_ASSEMBLER_NAME (function));
   if (!emit_p)
     return;
 
-  delta = THUNK_DELTA (thunk_fndecl);
-  vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
+#ifdef ASM_OUTPUT_DEF
+  alias = make_alias_for_thunk (function);
+#else
+  alias = function;
+#endif
+
+  fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl);
+  virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl);
 
+  if (virtual_offset)
+    {
+      if (!this_adjusting)
+       virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
+      virtual_value = tree_low_cst (virtual_offset, /*pos=*/0);
+      my_friendly_assert (virtual_value, 20021026);
+    }
+  else
+    virtual_value = 0;
+  
   /* And, if we need to emit the thunk, it's used.  */
   mark_used (thunk_fndecl);
   /* This thunk is actually defined.  */
   DECL_EXTERNAL (thunk_fndecl) = 0;
+  /* The linkage of the function may have changed.  FIXME in linkage
+     rewrite.  */
+  TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
+  DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
+  if (flag_weak && TREE_PUBLIC (thunk_fndecl))
+    comdat_linkage (thunk_fndecl);
 
   if (flag_syntax_only)
     {
@@ -2262,98 +401,118 @@ use_thunk (thunk_fndecl, emit_p)
 
   push_to_top_level ();
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (!vcall_offset)
+#ifdef ASM_OUTPUT_DEF
+  if (targetm.have_named_sections)
+    {
+      resolve_unique_section (function, 0, flag_function_sections);
+
+      if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function))
+       {
+         resolve_unique_section (thunk_fndecl, 0, flag_function_sections);
+
+         /* Output the thunk into the same section as function.  */
+         DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function);
+       }
+    }
+#endif
+
+  /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
+     create one.  */
+  DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
+
+  /* Set up cloned argument trees for the thunk.  */
+  t = NULL_TREE;
+  for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
+    {
+      tree x = copy_node (a);
+      TREE_CHAIN (x) = t;
+      DECL_CONTEXT (x) = thunk_fndecl;
+      SET_DECL_RTL (x, NULL_RTX);
+      t = x;
+    }
+  a = nreverse (t);
+  DECL_ARGUMENTS (thunk_fndecl) = a;
+  BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = a;
+  
+  if (this_adjusting
+      && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
+                                             virtual_value, alias))
     {
       const char *fnname;
       current_function_decl = thunk_fndecl;
       DECL_RESULT (thunk_fndecl)
        = build_decl (RESULT_DECL, 0, integer_type_node);
       fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
-      init_function_start (thunk_fndecl, input_filename, lineno);
+      init_function_start (thunk_fndecl);
       current_function_is_thunk = 1;
       assemble_start_function (thunk_fndecl, fnname);
-      ASM_OUTPUT_MI_THUNK (asm_out_file, thunk_fndecl, delta, function);
+
+      targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
+                                      fixed_offset, virtual_value, alias);
+
       assemble_end_function (thunk_fndecl, fnname);
       current_function_decl = 0;
       cfun = 0;
+      /* Because init_function_start increments this, we must
+        decrement it.  */
+      immediate_size_expand--;
       TREE_ASM_WRITTEN (thunk_fndecl) = 1;
     }
   else
-#endif /* ASM_OUTPUT_MI_THUNK */
-  {
-  /* If we don't have the necessary macro for efficient thunks, generate a
-     thunk function that just makes a call to the real function.
-     Unfortunately, this doesn't work for varargs.  */
-
-    tree a, t;
-
-    if (varargs_function_p (function))
-      cp_error ("generic thunk code fails for method `%#D' which uses `...'",
-               function);
-
-    /* Set up clone argument trees for the thunk.  */
-    t = NULL_TREE;
-    for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
-      {
-       tree x = copy_node (a);
-       TREE_CHAIN (x) = t;
-       DECL_CONTEXT (x) = thunk_fndecl;
-       t = x;
-      }
-    a = nreverse (t);
-    DECL_ARGUMENTS (thunk_fndecl) = a;
-    DECL_RESULT (thunk_fndecl) = NULL_TREE;
-
-    start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
-
-    /* Adjust the this pointer by the constant.  */
-    t = ssize_int (delta);
-    t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
-    /* If there's a vcall offset, look up that value in the vtable and
-       adjust the `this' pointer again.  */
-    if (vcall_offset && !integer_zerop (vcall_offset))
-      {
-       tree orig_this;
-
-       t = save_expr (t);
-       orig_this = t;
-       /* The vptr is always at offset zero in the object.  */
-       t = build1 (NOP_EXPR,
-                   build_pointer_type (build_pointer_type 
-                                       (vtable_entry_type)),
-                   t);
-       /* Form the vtable address.  */
-       t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
-       /* Find the entry with the vcall offset.  */
-       t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
-       /* Calculate the offset itself.  */
-       t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
-       /* Adjust the `this' pointer.  */
-       t = fold (build (PLUS_EXPR,
-                        TREE_TYPE (orig_this),
-                        orig_this,
-                        t));
-      }
-
-    /* Build up the call to the real function.  */
-    t = tree_cons (NULL_TREE, t, NULL_TREE);
-    for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
-      t = tree_cons (NULL_TREE, a, t);
-    t = nreverse (t);
-    t = build_call (function, t);
-    if (VOID_TYPE_P (TREE_TYPE (t)))
-      finish_expr_stmt (t);
-    else
-      finish_return_stmt (t);
-
-    /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
-       create one.  */
-    DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
-    BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) 
-      = DECL_ARGUMENTS (thunk_fndecl);
-    expand_body (finish_function (0));
-  }
+    {
+      /* If this is a covariant thunk, or we don't have the necessary
+        code for efficient thunks, generate a thunk function that
+        just makes a call to the real function.  Unfortunately, this
+        doesn't work for varargs.  */
+
+      if (varargs_function_p (function))
+       error ("generic thunk code fails for method `%#D' which uses `...'",
+              function);
+
+      DECL_RESULT (thunk_fndecl) = NULL_TREE;
+
+      start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
+      /* We don't bother with a body block for thunks.  */
+
+      /* There's no need to check accessibility inside the thunk body.  */
+      push_deferring_access_checks (dk_no_check);
+
+      t = a;
+      if (this_adjusting)
+       t = thunk_adjust (t, /*this_adjusting=*/1,
+                         fixed_offset, virtual_offset);
+      
+      /* Build up the call to the real function.  */
+      t = tree_cons (NULL_TREE, t, NULL_TREE);
+      for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
+       t = tree_cons (NULL_TREE, a, t);
+      t = nreverse (t);
+      t = build_call (alias, t);
+      CALL_FROM_THUNK_P (t) = 1;
+      
+      if (VOID_TYPE_P (TREE_TYPE (t)))
+       finish_expr_stmt (t);
+      else
+       {
+         t = force_target_expr (TREE_TYPE (t), t);
+         if (!this_adjusting)
+           t = thunk_adjust (t, /*this_adjusting=*/0,
+                             fixed_offset, virtual_offset);
+         finish_return_stmt (t);
+       }
+
+      /* Since we want to emit the thunk, we explicitly mark its name as
+        referenced.  */
+      mark_referenced (DECL_ASSEMBLER_NAME (thunk_fndecl));
+
+      /* But we don't want debugging information about it.  */
+      DECL_IGNORED_P (thunk_fndecl) = 1;
+
+      /* Re-enable access control.  */
+      pop_deferring_access_checks ();
+
+      expand_body (finish_function (0));
+    }
 
   pop_from_top_level ();
 }
@@ -2363,14 +522,11 @@ use_thunk (thunk_fndecl, emit_p)
 /* Generate code for default X(X&) constructor.  */
 
 static void
-do_build_copy_constructor (fndecl)
-     tree fndecl;
+do_build_copy_constructor (tree fndecl)
 {
-  tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
+  tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
   tree t;
 
-  if (DECL_HAS_IN_CHARGE_PARM_P (fndecl))
-    parm = TREE_CHAIN (parm);
   parm = convert_from_reference (parm);
 
   if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)
@@ -2388,30 +544,46 @@ do_build_copy_constructor (fndecl)
       int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
       tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
       tree member_init_list = NULL_TREE;
-      tree base_init_list = NULL_TREE;
-      int cvquals = CP_TYPE_QUALS (TREE_TYPE (parm));
+      int cvquals = cp_type_quals (TREE_TYPE (parm));
       int i;
 
-      /* Initialize all the base-classes.  */
+      /* Initialize all the base-classes with the parameter converted
+        to their type so that we get their copy constructor and not
+        another constructor that takes current_class_type.  We must
+        deal with the binfo's directly as a direct base might be
+        inaccessible due to ambiguity.  */
       for (t = CLASSTYPE_VBASECLASSES (current_class_type); t;
           t = TREE_CHAIN (t))
-       base_init_list 
-         = tree_cons (BINFO_TYPE (TREE_VALUE (t)), parm, 
-                      base_init_list);
+       {
+         tree binfo = TREE_VALUE (t);
+         
+         member_init_list 
+           = tree_cons (binfo,
+                        build_tree_list (NULL_TREE,
+                                         build_base_path (PLUS_EXPR, parm,
+                                                          binfo, 1)),
+                        member_init_list);
+       }
+
       for (i = 0; i < n_bases; ++i)
        {
-         t = TREE_VEC_ELT (binfos, i);
-         if (TREE_VIA_VIRTUAL (t))
+         tree binfo = TREE_VEC_ELT (binfos, i);
+         if (TREE_VIA_VIRTUAL (binfo))
            continue; 
 
-         base_init_list 
-           = tree_cons (BINFO_TYPE (t), parm, base_init_list);
+         member_init_list 
+           = tree_cons (binfo,
+                        build_tree_list (NULL_TREE,
+                                         build_base_path (PLUS_EXPR, parm,
+                                                          binfo, 1)),
+                        member_init_list);
        }
 
       for (; fields; fields = TREE_CHAIN (fields))
        {
-         tree init, t;
+         tree init;
          tree field = fields;
+         tree expr_type;
 
          if (TREE_CODE (field) != FIELD_DECL)
            continue;
@@ -2421,8 +593,6 @@ do_build_copy_constructor (fndecl)
            {
              if (VFIELD_NAME_P (DECL_NAME (field)))
                continue;
-             if (VBASE_NAME_P (DECL_NAME (field)))
-               continue;
 
              /* True for duplicate members.  */
              if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field)
@@ -2436,28 +606,31 @@ do_build_copy_constructor (fndecl)
          else
            continue;
 
-         init = build (COMPONENT_REF,
-                       build_qualified_type (TREE_TYPE (field), cvquals),
-                       init, field);
+         /* Compute the type of "init->field".  If the copy-constructor
+            parameter is, for example, "const S&", and the type of
+            the field is "T", then the type will usually be "const
+            T".  (There are no cv-qualified variants of reference
+            types.)  */
+         expr_type = TREE_TYPE (field);
+         if (TREE_CODE (expr_type) != REFERENCE_TYPE)
+           expr_type = cp_build_qualified_type (expr_type, cvquals);
+         init = build (COMPONENT_REF, expr_type, init, field);
          init = build_tree_list (NULL_TREE, init);
 
          member_init_list
            = tree_cons (field, init, member_init_list);
        }
-      member_init_list = nreverse (member_init_list);
-      base_init_list = nreverse (base_init_list);
-      setup_vtbl_ptr (member_init_list, base_init_list);
+      finish_mem_initializers (member_init_list);
     }
 }
 
 static void
-do_build_assign_ref (fndecl)
-     tree fndecl;
+do_build_assign_ref (tree fndecl)
 {
   tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
   tree compound_stmt;
 
-  compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+  compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
   parm = convert_from_reference (parm);
 
   if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)
@@ -2471,41 +644,49 @@ do_build_assign_ref (fndecl)
     }
   else
     {
-      tree fields = TYPE_FIELDS (current_class_type);
-      int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
-      tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
-      int cvquals = CP_TYPE_QUALS (TREE_TYPE (parm));
+      tree fields;
+      int cvquals = cp_type_quals (TREE_TYPE (parm));
       int i;
 
-      for (i = 0; i < n_bases; ++i)
+      /* Assign to each of the direct base classes.  */
+      for (i = 0; i < CLASSTYPE_N_BASECLASSES (current_class_type); ++i)
        {
-         tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
-         tree p = build_qualified_type (basetype, cvquals);
-
-         p = convert_to_reference
-           (build_reference_type (p), parm,
-            CONV_IMPLICIT, LOOKUP_COMPLAIN, NULL_TREE);
-         p = convert_from_reference (p);
-         p = build_member_call (basetype, ansi_assopname (NOP_EXPR),
-                                build_tree_list (NULL_TREE, p));
-         finish_expr_stmt (p);
+         tree binfo;
+         tree converted_parm;
+
+         binfo = BINFO_BASETYPE (TYPE_BINFO (current_class_type), i);
+         /* We must convert PARM directly to the base class
+            explicitly since the base class may be ambiguous.  */
+         converted_parm = build_base_path (PLUS_EXPR, parm, binfo, 1);
+         /* Call the base class assignment operator.  */
+         finish_expr_stmt 
+           (build_special_member_call (current_class_ref, 
+                                       ansi_assopname (NOP_EXPR),
+                                       build_tree_list (NULL_TREE, 
+                                                        converted_parm),
+                                       binfo,
+                                       LOOKUP_NORMAL | LOOKUP_NONVIRTUAL));
        }
-      for (; fields; fields = TREE_CHAIN (fields))
+
+      /* Assign to each of the non-static data members.  */
+      for (fields = TYPE_FIELDS (current_class_type); 
+          fields; 
+          fields = TREE_CHAIN (fields))
        {
          tree comp, init, t;
          tree field = fields;
 
-         if (TREE_CODE (field) != FIELD_DECL)
+         if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
            continue;
 
          if (CP_TYPE_CONST_P (TREE_TYPE (field)))
            {
-              cp_error ("non-static const member `%#D', can't use default assignment operator", field);
+              error ("non-static const member `%#D', can't use default assignment operator", field);
              continue;
            }
          else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
            {
-             cp_error ("non-static reference member `%#D', can't use default assignment operator", field);
+             error ("non-static reference member `%#D', can't use default assignment operator", field);
              continue;
            }
 
@@ -2516,8 +697,6 @@ do_build_assign_ref (fndecl)
            {
              if (VFIELD_NAME_P (DECL_NAME (field)))
                continue;
-             if (VBASE_NAME_P (DECL_NAME (field)))
-               continue;
 
              /* True for duplicate members.  */
              if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field)
@@ -2533,23 +712,27 @@ do_build_assign_ref (fndecl)
 
          comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field);
          init = build (COMPONENT_REF,
-                       build_qualified_type (TREE_TYPE (field), cvquals),
+                       cp_build_qualified_type (TREE_TYPE (field), cvquals),
                        init, field);
 
-         finish_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
+         if (DECL_NAME (field))
+           finish_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
+         else
+           finish_expr_stmt (build (MODIFY_EXPR, TREE_TYPE (comp), comp,
+                                    init));
        }
     }
   finish_return_stmt (current_class_ref);
-  finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+  finish_compound_stmt (compound_stmt);
 }
 
 void
-synthesize_method (fndecl)
-     tree fndecl;
+synthesize_method (tree fndecl)
 {
-  int nested = (current_function_decl != NULL_TREE);
+  bool nested = (current_function_decl != NULL_TREE);
   tree context = decl_function_context (fndecl);
-  int need_body = 1;
+  bool need_body = true;
+  tree stmt;
 
   if (at_eof)
     import_export_decl (fndecl);
@@ -2563,6 +746,10 @@ synthesize_method (fndecl)
       return;
     }
 
+  /* We may be in the middle of deferred access check.  Disable
+     it now.  */
+  push_deferring_access_checks (dk_no_deferred);
+
   if (! context)
     push_to_top_level ();
   else if (nested)
@@ -2573,30 +760,26 @@ synthesize_method (fndecl)
      during the generation of the implicit body points at the place
      where the attempt to generate the function occurs, giving the
      user a hint as to why we are attempting to generate the
-     function. */
-  DECL_SOURCE_LINE (fndecl) = lineno;
-  DECL_SOURCE_FILE (fndecl) = input_filename;
+     function.  */
+  DECL_SOURCE_LOCATION (fndecl) = input_location;
 
   interface_unknown = 1;
   start_function (NULL_TREE, fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED);
   clear_last_expr ();
+  stmt = begin_function_body ();
 
   if (DECL_OVERLOADED_OPERATOR_P (fndecl) == NOP_EXPR)
     {
       do_build_assign_ref (fndecl);
-      need_body = 0;
+      need_body = false;
     }
-  else if (DECL_DESTRUCTOR_P (fndecl))
-    setup_vtbl_ptr (NULL_TREE, NULL_TREE);
-  else
+  else if (DECL_CONSTRUCTOR_P (fndecl))
     {
-      tree arg_chain = FUNCTION_ARG_CHAIN (fndecl);
-      if (DECL_HAS_IN_CHARGE_PARM_P (fndecl))
-       arg_chain = TREE_CHAIN (arg_chain);
+      tree arg_chain = FUNCTION_FIRST_USER_PARMTYPE (fndecl);
       if (arg_chain != void_list_node)
        do_build_copy_constructor (fndecl);
       else if (TYPE_NEEDS_CONSTRUCTING (current_class_type))
-       setup_vtbl_ptr (NULL_TREE, NULL_TREE);
+       finish_mem_initializers (NULL_TREE);
     }
 
   /* If we haven't yet generated the body of the function, just
@@ -2604,35 +787,37 @@ synthesize_method (fndecl)
   if (need_body)
     {
       tree compound_stmt;
-      compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-      finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+      compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
+      finish_compound_stmt (compound_stmt);
     }
 
-  expand_body (finish_function (0));
+  finish_function_body (stmt);
+  expand_or_defer_fn (finish_function (0));
 
   extract_interface_info ();
   if (! context)
     pop_from_top_level ();
   else if (nested)
     pop_function_context_from (context);
+
+  pop_deferring_access_checks ();
 }
 
 /* Use EXTRACTOR to locate the relevant function called for each base &
    class field of TYPE. CLIENT allows additional information to be passed
-   to EXTRACTOR.  Generates the union of all exceptions generated by
-   those functions.  */
+   to EXTRACTOR.  Generates the union of all exceptions generated by those
+   functions.  Note that we haven't updated TYPE_FIELDS and such of any
+   variants yet, so we need to look at the main one.  */
 
 static tree
-synthesize_exception_spec (type, extractor, client)
-     tree type;
-     tree (*extractor) (tree, void *);
-     void *client;
+synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
+                           void *client)
 {
   tree raises = empty_except_spec;
   tree fields = TYPE_FIELDS (type);
   int i, n_bases = CLASSTYPE_N_BASECLASSES (type);
   tree binfos = TYPE_BINFO_BASETYPES (type);
-  
+
   for (i = 0; i != n_bases; i++)
     {
       tree base = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
@@ -2649,7 +834,7 @@ synthesize_exception_spec (type, extractor, client)
       tree type = TREE_TYPE (fields);
       tree fn;
       
-      if (TREE_CODE (fields) != FIELD_DECL)
+      if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
         continue;
       while (TREE_CODE (type) == ARRAY_TYPE)
        type = TREE_TYPE (type);
@@ -2670,9 +855,7 @@ synthesize_exception_spec (type, extractor, client)
 /* Locate the dtor of TYPE.  */
 
 static tree
-locate_dtor (type, client)
-     tree type;
-     void *client ATTRIBUTE_UNUSED;
+locate_dtor (tree type, void *client ATTRIBUTE_UNUSED)
 {
   tree fns;
   
@@ -2686,9 +869,7 @@ locate_dtor (type, client)
 /* Locate the default ctor of TYPE.  */
 
 static tree
-locate_ctor (type, client)
-     tree type;
-     void *client ATTRIBUTE_UNUSED;
+locate_ctor (tree type, void *client ATTRIBUTE_UNUSED)
 {
   tree fns;
   
@@ -2719,15 +900,13 @@ struct copy_data
    and desired qualifiers of the source operand.  */
 
 static tree
-locate_copy (type, client_)
-     tree type;
-     void *client_;
+locate_copy (tree type, void *client_)
 {
   struct copy_data *client = (struct copy_data *)client_;
   tree fns;
   int ix = -1;
   tree best = NULL_TREE;
-  int excess_p = 0;
+  bool excess_p = false;
   
   if (client->name)
     {
@@ -2751,14 +930,12 @@ locate_copy (type, client_)
       parms = TREE_CHAIN (parms);
       if (!parms)
         continue;
-      src_type = TREE_VALUE (parms);
-      if (TREE_CODE (src_type) == REFERENCE_TYPE)
-        src_type = TREE_TYPE (src_type);
+      src_type = non_reference (TREE_VALUE (parms));
       if (!same_type_ignoring_top_level_qualifiers_p (src_type, type))
         continue;
       if (!sufficient_parms_p (TREE_CHAIN (parms)))
         continue;
-      quals = CP_TYPE_QUALS (src_type);
+      quals = cp_type_quals (src_type);
       if (client->quals & ~quals)
         continue;
       excess = quals & ~client->quals;
@@ -2780,17 +957,14 @@ locate_copy (type, client_)
    reference argument or a non-const reference.  */
 
 tree
-implicitly_declare_fn (kind, type, const_p)
-     special_function_kind kind;
-     tree type;
-     int const_p;
+implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
 {
   tree declspecs = NULL_TREE;
   tree fn, args = NULL_TREE;
   tree raises = empty_except_spec;
-  tree argtype;
-  int retref = 0;
-  tree name = constructor_name (TYPE_IDENTIFIER (type));
+  bool retref = false;
+  bool has_parm = false;
+  tree name = constructor_name (type);
 
   switch (kind)
     {
@@ -2808,66 +982,80 @@ implicitly_declare_fn (kind, type, const_p)
       break;
 
     case sfk_copy_constructor:
-    {
-      struct copy_data data;
-      
-      if (const_p)
-       type = build_qualified_type (type, TYPE_QUAL_CONST);
-      argtype = build_reference_type (type);
-      args = tree_cons (NULL_TREE,
-                       build_tree_list (hash_tree_chain (argtype, NULL_TREE),
-                                        get_identifier ("_ctor_arg")),
-                       void_list_node);
-      data.name = NULL;
-      data.quals = const_p ? TYPE_QUAL_CONST : 0;
-      raises = synthesize_exception_spec (type, &locate_copy, &data);
-      break;
-    }
     case sfk_assignment_operator:
     {
       struct copy_data data;
+      tree argtype = type;
       
-      retref = 1;
-      declspecs = build_tree_list (NULL_TREE, type);
+      has_parm = true;
+      data.name = NULL;
+      data.quals = 0;
+      if (kind == sfk_assignment_operator)
+        {
+          retref = true;
+          declspecs = build_tree_list (NULL_TREE, type);
 
+          name = ansi_assopname (NOP_EXPR);
+          data.name = name;
+        }
       if (const_p)
-       type = build_qualified_type (type, TYPE_QUAL_CONST);
-
-      name = ansi_assopname (NOP_EXPR);
-
-      argtype = build_reference_type (type);
-      args = tree_cons (NULL_TREE,
-                       build_tree_list (hash_tree_chain (argtype, NULL_TREE),
-                                        get_identifier ("_ctor_arg")),
-                       void_list_node);
-      data.name = name;
-      data.quals = const_p ? TYPE_QUAL_CONST : 0;
+        {
+          data.quals = TYPE_QUAL_CONST;
+          argtype = build_qualified_type (argtype, TYPE_QUAL_CONST);
+        }
+    
+      argtype = build_reference_type (argtype);
+      args = build_tree_list (hash_tree_chain (argtype, NULL_TREE),
+                             get_identifier ("_ctor_arg"));
+      args = tree_cons (NULL_TREE, args, void_list_node);
+      
       raises = synthesize_exception_spec (type, &locate_copy, &data);
       break;
     }
     default:
-      my_friendly_abort (59);
+      abort ();
     }
 
   TREE_PARMLIST (args) = 1;
 
   {
     tree declarator = make_call_declarator (name, args, NULL_TREE, raises);
+    
     if (retref)
       declarator = build_nt (ADDR_EXPR, declarator);
 
     fn = grokfield (declarator, declspecs, NULL_TREE, NULL_TREE, NULL_TREE);
+    if (has_parm)
+      TREE_USED (FUNCTION_FIRST_USER_PARM (fn)) = 1;
   }
 
   my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 20000408);
 
-  if (kind != sfk_constructor && kind != sfk_destructor)
-    DECL_ARTIFICIAL (TREE_CHAIN (DECL_ARGUMENTS (fn))) = 1;
   DECL_ARTIFICIAL (fn) = 1;
   DECL_NOT_REALLY_EXTERN (fn) = 1;
-  DECL_THIS_INLINE (fn) = 1;
+  DECL_DECLARED_INLINE_P (fn) = 1;
   DECL_INLINE (fn) = 1;
   defer_fn (fn);
   
   return fn;
 }
+
+/* Given a FUNCTION_DECL FN and a chain LIST, skip as many elements of LIST
+   as there are artificial parms in FN.  */
+
+tree
+skip_artificial_parms_for (tree fn, tree list)
+{
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+    list = TREE_CHAIN (list);
+  else
+    return list;
+
+  if (DECL_HAS_IN_CHARGE_PARM_P (fn))
+    list = TREE_CHAIN (list);
+  if (DECL_HAS_VTT_PARM_P (fn))
+    list = TREE_CHAIN (list);
+  return list;
+}
+
+#include "gt-cp-method.h"