OSDN Git Service

* call.c (joust): Don't warn about "confusing" conversions to the
[pf3gnuchains/gcc-fork.git] / gcc / cp / method.c
index c873207..a13082b 100644 (file)
@@ -1,9 +1,9 @@
 /* Handle the hair of processing (but not expanding) inline functions.
    Also manage function and variable name overloading.
-   Copyright (C) 1987, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
-   This file is part of GNU CC.
+This file is part of GNU CC.
    
 GNU CC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -21,28 +21,33 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
 
+#ifndef __GNUC__
+#define __inline
+#endif
+
 #ifndef PARM_CAN_BE_ARRAY_TYPE
 #define PARM_CAN_BE_ARRAY_TYPE 1
 #endif
 
 /* Handle method declarations.  */
-#include <stdio.h>
 #include "config.h"
+#include "system.h"
 #include "tree.h"
 #include "cp-tree.h"
-#include "class.h"
 #include "obstack.h"
-#include <ctype.h>
 #include "rtl.h"
 #include "expr.h"
 #include "output.h"
 #include "hard-reg-set.h"
 #include "flags.h"
+#include "toplev.h"
 
 /* TREE_LIST of the current inline functions that need to be
    processed.  */
 struct pending_inline *pending_inlines;
 
+int static_labelno;
+
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
@@ -50,6 +55,38 @@ struct pending_inline *pending_inlines;
 static struct obstack scratch_obstack;
 static char *scratch_firstobj;
 
+static void icat PROTO((HOST_WIDE_INT));
+static void dicat PROTO((HOST_WIDE_INT, HOST_WIDE_INT));
+static void flush_repeats PROTO((int, tree));
+static void build_overload_identifier PROTO((tree));
+static void build_overload_nested_name PROTO((tree));
+static void build_overload_int PROTO((tree, int));
+static void build_overload_identifier PROTO((tree));
+static void build_qualified_name PROTO((tree));
+static void build_overload_value PROTO((tree, tree, int));
+static void issue_nrepeats PROTO((int, tree));
+static char *build_mangled_name PROTO((tree,int,int));
+static void process_modifiers PROTO((tree));
+static void process_overload_item PROTO((tree,int));
+static void do_build_assign_ref PROTO((tree));
+static void do_build_copy_constructor PROTO((tree));
+static tree largest_union_member PROTO((tree));
+static tree build_decl_overload_real PROTO((tree, tree, tree, tree,
+                                           tree, int)); 
+static void build_template_template_parm_names PROTO((tree));
+static void build_template_parm_names PROTO((tree, tree));
+static void build_underscore_int PROTO((int));
+static void start_squangling PROTO((void));
+static void end_squangling PROTO((void));
+static int check_ktype PROTO((tree, int));
+static int issue_ktype PROTO((tree));
+static void build_overload_scope_ref PROTO((tree));
+static void build_mangled_template_parm_index PROTO((char *, tree));
+static int is_back_referenceable_type PROTO((tree));
+static int check_btype PROTO((tree));
+static void build_mangled_name_for_type PROTO((tree));
+static void build_mangled_name_for_type_with_Gcode PROTO((tree, int));
+
 # 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)       \
@@ -62,10 +99,6 @@ static char *scratch_firstobj;
 # define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0'))
 # define OB_LAST() (obstack_next_free (&scratch_obstack)[-1])
 
-#ifdef NO_AUTO_OVERLOAD
-int is_overloaded ();
-#endif
-
 void
 init_method ()
 {
@@ -114,11 +147,6 @@ do_inline_function_hair (type, friend_list)
              DECL_CONTEXT (args) = method;
              args = TREE_CHAIN (args);
            }
-
-         /* Allow this decl to be seen in global scope.  Don't do this for
-             local class methods, though.  */
-         if (! current_function_decl)
-           IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (method)) = method;
        }
       method = TREE_CHAIN (method);
     }
@@ -137,162 +165,142 @@ do_inline_function_hair (type, friend_list)
              DECL_CONTEXT (args) = fndecl;
              args = TREE_CHAIN (args);
            }
-
-         /* Allow this decl to be seen in global scope */
-         if (! current_function_decl)
-           IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (fndecl)) = fndecl;
        }
 
       friend_list = TREE_CHAIN (friend_list);
     }
 }
 \f
-/* Report an argument type mismatch between the best declared function
-   we could find and the current argument list that we have.  */
-void
-report_type_mismatch (cp, parmtypes, name_kind)
-     struct candidate *cp;
-     tree parmtypes;
-     char *name_kind;
-{
-  int i = cp->u.bad_arg;
-  tree ttf, tta;
-  char *tmp_firstobj;
-
-  switch (i)
-    {
-    case -4:
-      my_friendly_assert (TREE_CODE (cp->function) == TEMPLATE_DECL, 240);
-      cp_error ("type unification failed for function template `%#D'",
-               cp->function);
-      return;
-
-    case -2:
-      cp_error ("too few arguments for %s `%#D'", name_kind, cp->function);
-      return;
-    case -1:
-      cp_error ("too many arguments for %s `%#D'", name_kind, cp->function);
-      return;
-    case 0:
-      if (TREE_CODE (TREE_TYPE (cp->function)) != METHOD_TYPE)
-       break;
-    case -3:
-      /* Happens when the implicit object parameter is rejected.  */
-      my_friendly_assert (! TYPE_READONLY (TREE_TYPE (TREE_VALUE (parmtypes))),
-                         241);
-      if (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (TREE_VALUE (parmtypes))))
-         && ! TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (cp->function))))))
-       cp_error ("call to non-volatile %s `%#D' with volatile object",
-                 name_kind, cp->function);
-      else
-       cp_error ("call to non-const %s `%#D' with const object",
-                 name_kind, cp->function);
-      return;
-    }
-
-  ttf = TYPE_ARG_TYPES (TREE_TYPE (cp->function));
-  tta = parmtypes;
-
-  while (i-- > 0)
-    {
-      ttf = TREE_CHAIN (ttf);
-      tta = TREE_CHAIN (tta);
-    }
+/* Here is where overload code starts.  */
 
-  OB_INIT ();
-  OB_PUTS ("bad argument ");
-  sprintf (digit_buffer, "%d", cp->u.bad_arg
-          - (TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
-          + 1);
-  OB_PUTCP (digit_buffer);
-
-  OB_PUTS (" for function `");
-  OB_PUTCP (decl_as_string (cp->function, 1));
-  OB_PUTS ("' (type was ");
-
-  /* Reset `i' so that type printing routines do the right thing.  */
-  if (tta)
-    {
-      enum tree_code code = TREE_CODE (TREE_TYPE (TREE_VALUE (tta)));
-      if (code == ERROR_MARK)
-       OB_PUTS ("(failed type instantiation)");
-      else
-       {
-         i = (code == FUNCTION_TYPE || code == METHOD_TYPE);
-         OB_PUTCP (type_as_string (TREE_TYPE (TREE_VALUE (tta)), 1));
-       }
-    }
-  else OB_PUTS ("void");
-  OB_PUTC (')');
-  OB_FINISH ();
+/* type tables for K and B type compression */
+static tree *btypelist = NULL;
+static tree *ktypelist = NULL;
+static int maxbsize = 0;
+static int maxksize = 0;
 
-  tmp_firstobj = (char *)alloca (obstack_object_size (&scratch_obstack));
-  bcopy (obstack_base (&scratch_obstack), tmp_firstobj,
-        obstack_object_size (&scratch_obstack));
-  error (tmp_firstobj);
-}
-\f
-/* Here is where overload code starts.  */
+/* number of each type seen */
+static int maxbtype = 0;
+static int maxktype = 0;
 
-/* Array of types seen so far in top-level call to `build_overload_name'.
+/* Array of types seen so far in top-level call to `build_mangled_name'.
    Allocated and deallocated by caller.  */
-static tree *typevec;
-
-/* Number of types interned by `build_overload_name' so far.  */
-static int maxtype;
+static tree *typevec = NULL;
+static int  typevec_size;
 
-/* Number of occurrences of last type seen.  */
-static int nrepeats;
+/* Number of types interned by `build_mangled_name' so far.  */
+static int maxtype = 0;
 
 /* Nonzero if we should not try folding parameter types.  */
 static int nofold;
 
-#define ALLOCATE_TYPEVEC(PARMTYPES) \
-  do { maxtype = 0, nrepeats = 0; \
-       typevec = (tree *)alloca (list_length (PARMTYPES) * sizeof (tree)); } while (0)
+/* This appears to be set to true if an underscore is required to be
+   comcatenated before another number can be outputed. */
+static int numeric_output_need_bar;
+
+static __inline void
+start_squangling ()
+{
+  if (flag_do_squangling)
+    {
+      nofold = 0;
+      maxbtype = 0;
+      maxktype = 0;
+      maxbsize = 50;
+      maxksize = 50;
+      btypelist = (tree *)xmalloc (sizeof (tree) * maxbsize);
+      ktypelist = (tree *)xmalloc (sizeof (tree) * maxksize);
+    }
+}
 
-#define DEALLOCATE_TYPEVEC(PARMTYPES) \
-  do { tree t = (PARMTYPES); \
-       while (t) { TREE_USED (TREE_VALUE (t)) = 0; t = TREE_CHAIN (t); } \
-  } while (0)
+static __inline void
+end_squangling ()
+{
+  if (flag_do_squangling)
+    {
+      if (ktypelist)
+        free (ktypelist);
+      if (btypelist)
+        free (btypelist);
+      maxbsize = 0;
+      maxksize = 0;
+      maxbtype = 0;
+      maxktype = 0;
+      ktypelist = NULL;
+      btypelist = NULL;
+    }
+}
 
 /* Code to concatenate an asciified integer to a string.  */
-static
-#ifdef __GNUC__
-__inline
-#endif
-void
+
+static __inline void
 icat (i)
-     int 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 i/10 below is 1.  */
+     the result of ui/10 below is 1.  */
   if (i == 1)
     {
       OB_PUTC ('1');
       return;
     }
 
-  if (i < 0)
+  if (i >= 0)
+    ui = i;
+  else
     {
       OB_PUTC ('m');
-      i = -i;
+      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;
     }
-  if (i < 10)
-    OB_PUTC ('0' + i);
   else
     {
-      icat (i / 10);
-      OB_PUTC ('0' + (i % 10));
+      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);
 }
 
-static
-#ifdef __GNUC__
-__inline
-#endif
-void
-flush_repeats (type)
+static __inline void
+flush_repeats (nrepeats, type)
+     int nrepeats;
      tree type;
 {
   int tindex = 0;
@@ -309,105 +317,327 @@ flush_repeats (type)
     }
   else
     OB_PUTC ('T');
-  nrepeats = 0;
   icat (tindex);
   if (tindex > 9)
     OB_PUTC ('_');
 }
 
-static int numeric_output_need_bar;
-static void build_overload_identifier ();
+/* Returns nonzero iff this is a type to which we will want to make
+   back-references (using the `B' code).  */
+
+int
+is_back_referenceable_type (type)
+     tree type;
+{
+  if (btypelist == NULL)
+    /* We're not generating any back-references.  */
+    return 0;
+
+  switch (TREE_CODE (type)) 
+    {
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case VOID_TYPE:
+    case BOOLEAN_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. Return -1 if it isn't found, otherwise return the index */
+static int
+check_ktype (node, add)
+     tree node;
+     int add;
+{
+  int 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 (localnode == ktypelist[x])
+        return x ;
+    }
+  /* Didn't find it, so add it here */
+  if (add)
+    {
+      if (maxksize <= maxktype)
+        {
+          maxksize = maxksize* 3 / 2;
+          ktypelist = (tree *)xrealloc (ktypelist, sizeof (tree) * maxksize);
+        }
+      ktypelist[maxktype++] = localnode;
+    }
+  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;
 {
-  if (DECL_CONTEXT (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)
+      build_mangled_name_for_type (context);
+    else
     {
-      tree context = DECL_CONTEXT (decl);
       if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
-       context = TYPE_MAIN_DECL (context);
+        context = TYPE_NAME (context);
       build_overload_nested_name (context);
     }
+  }
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
     {
       tree name = DECL_ASSEMBLER_NAME (decl);
       char *label;
-      extern int var_labelno;
 
-      ASM_FORMAT_PRIVATE_NAME (label, IDENTIFIER_POINTER (name), var_labelno);
-      var_labelno++;
+      ASM_FORMAT_PRIVATE_NAME (label, IDENTIFIER_POINTER (name), static_labelno);
+      static_labelno++;
 
       if (numeric_output_need_bar)
-       {
-         OB_PUTC ('_');
-         numeric_output_need_bar = 0;
-       }
+       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);
 }
 
-/* Encoding for an INTEGER_CST value. */
+/* 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_int (value)
+build_overload_scope_ref (value)
      tree value;
 {
-  if (TREE_CODE (value) == TEMPLATE_CONST_PARM)
-    {
-      OB_PUTC ('Y');
-      if (TEMPLATE_CONST_IDX (value) > 9)
-       OB_PUTC ('_');
-      icat (TEMPLATE_CONST_IDX (value)); 
-      if (TEMPLATE_CONST_IDX (value) > 9)
-       OB_PUTC ('_');
-      return;
-    }
-  else if (current_template_parms
-          && TREE_CODE (value) != INTEGER_CST)
-    /* 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.  */
+  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));
+}
+
+/* Encoding for an INTEGER_CST value.  */
+
+static void
+build_overload_int (value, in_template)
+     tree value;
+     int in_template;
+{
+  if (in_template && TREE_CODE (value) != INTEGER_CST)
     {
-      static int n;
-      sprintf (digit_buffer, " *%d", n++);
-      OB_PUTCP (digit_buffer);
+      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[(int) TREE_CODE (value)];
+         tree id;
+         char* name;
+
+         id = ansi_opname [(int) TREE_CODE (value)];
+         my_friendly_assert (id != NULL_TREE, 0);
+         name = IDENTIFIER_POINTER (id);
+         if (name[0] != '_' || name[1] != '_')
+           /* On some erroneous inputs, we can get here with VALUE a
+              LOOKUP_EXPR.  In that case, the NAME will be the
+              identifier for "<invalid operator>".  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 if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (tc)))
+               build_overload_int (operand, in_template);
+             else
+               build_overload_value (TREE_TYPE (operand),
+                                     operand,
+                                     in_template);
+           }
+       }
+      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;
       return;
     }
 
   my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243);
-  if (TYPE_PRECISION (value) == 2 * HOST_BITS_PER_WIDE_INT)
+  if (TYPE_PRECISION (TREE_TYPE (value)) == 2 * HOST_BITS_PER_WIDE_INT)
     {
-      if (tree_int_cst_lt (value, integer_zero_node))
-       {
-         OB_PUTC ('m');
-         value = build_int_2 (~ TREE_INT_CST_LOW (value),
-                              - TREE_INT_CST_HIGH (value));
-       }
       if (TREE_INT_CST_HIGH (value)
          != (TREE_INT_CST_LOW (value) >> (HOST_BITS_PER_WIDE_INT - 1)))
        {
          /* need to print a DImode value in decimal */
-         sorry ("conversion of long long as PT parameter");
+         dicat (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value));
+         numeric_output_need_bar = 1;
+         return;
        }
       /* else fall through to print in smaller mode */
     }
   /* Wordsize or smaller */
   icat (TREE_INT_CST_LOW (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)
+     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));
 }
 
+
 static void
-build_overload_value (type, value)
+build_overload_value (type, value, in_template)
      tree type, value;
+     int in_template;
 {
   while (TREE_CODE (value) == NON_LVALUE_EXPR
         || TREE_CODE (value) == NOP_EXPR)
     value = TREE_OPERAND (value, 0);
-  my_friendly_assert (TREE_CODE (type) == PARM_DECL, 242);
-  type = TREE_TYPE (type);
+
+  if (TREE_CODE (type) == PARM_DECL)
+    type = TREE_TYPE (type);
+
+  my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (type)) == 't', 0);
 
   if (numeric_output_need_bar)
     {
@@ -415,6 +645,12 @@ build_overload_value (type, value)
       numeric_output_need_bar = 0;
     }
 
+  if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
+    {
+      build_mangled_template_parm_index ("Y", value);
+      return;
+    }
+
   if (TREE_CODE (type) == POINTER_TYPE
       && TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)
     {
@@ -437,65 +673,82 @@ build_overload_value (type, value)
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
       {
-       build_overload_int (value);
-       numeric_output_need_bar = 1;
+       build_overload_int (value, in_template);
        return;
       }
-#ifndef REAL_IS_NOT_DOUBLE
     case REAL_TYPE:
       {
        REAL_VALUE_TYPE val;
        char *bufp = digit_buffer;
-       extern char *index ();
+
+       pedwarn ("ANSI C++ forbids floating-point template arguments");
 
        my_friendly_assert (TREE_CODE (value) == REAL_CST, 244);
        val = TREE_REAL_CST (value);
-       if (val < 0)
+       if (REAL_VALUE_ISNAN (val))
          {
-           val = -val;
-           *bufp++ = 'm';
+           sprintf (bufp, "NaN");
          }
-       sprintf (bufp, "%e", val);
-       bufp = (char *) index (bufp, 'e');
-       if (!bufp)
-         strcat (digit_buffer, "e0");
        else
          {
-           char *p;
-           bufp++;
-           if (*bufp == '-')
+           if (REAL_VALUE_NEGATIVE (val))
              {
+               val = REAL_VALUE_NEGATE (val);
                *bufp++ = 'm';
              }
-           p = bufp;
-           if (*p == '+')
-             p++;
-           while (*p == '0')
-             p++;
-           if (*p == 0)
+           if (REAL_VALUE_ISINF (val))
              {
-               *bufp++ = '0';
-               *bufp = 0;
+               sprintf (bufp, "Infinity");
              }
-           else if (p != bufp)
+           else
              {
-               while (*p)
-                 *bufp++ = *p++;
-               *bufp = 0;
+               REAL_VALUE_TO_DECIMAL (val, "%.20e", bufp);
+               bufp = (char *) index (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 *) index (bufp, '.');
+               if (bufp)
+                 *bufp = '_';
+#endif
              }
          }
        OB_PUTCP (digit_buffer);
        numeric_output_need_bar = 1;
        return;
       }
-#endif
     case POINTER_TYPE:
       if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
          && TREE_CODE (value) != ADDR_EXPR)
        {
          if (TREE_CODE (value) == CONSTRUCTOR)
            {
-             /* This is dangerous code, crack built up pointer to members. */
+             /* This is dangerous code, crack built up pointer to members.  */
              tree args = CONSTRUCTOR_ELTS (value);
              tree a1 = TREE_VALUE (args);
              tree a2 = TREE_VALUE (TREE_CHAIN (args));
@@ -505,9 +758,9 @@ build_overload_value (type, value)
              if (TREE_CODE (a1) == INTEGER_CST
                  && TREE_CODE (a2) == INTEGER_CST)
                {
-                 build_overload_int (a1);
+                 build_overload_int (a1, in_template);
                  OB_PUTC ('_');
-                 build_overload_int (a2);
+                 build_overload_int (a2, in_template);
                  OB_PUTC ('_');
                  if (TREE_CODE (a3) == ADDR_EXPR)
                    {
@@ -522,8 +775,7 @@ build_overload_value (type, value)
                  else if (TREE_CODE (a3) == INTEGER_CST)
                    {
                      OB_PUTC ('i');
-                     build_overload_int (a3);
-                     numeric_output_need_bar = 1;
+                     build_overload_int (a3, in_template);
                      return;
                    }
                }
@@ -533,10 +785,16 @@ build_overload_value (type, value)
        }
       if (TREE_CODE (value) == INTEGER_CST)
        {
-         build_overload_int (value);
+         build_overload_int (value, in_template);
+         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);
       if (TREE_CODE (value) == VAR_DECL)
        {
@@ -550,6 +808,8 @@ build_overload_value (type, value)
          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 */
@@ -561,6 +821,92 @@ build_overload_value (type, value)
     }
 }
 
+
+/* 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, 246.5);
+  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;
+  
+  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 (arglist, 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, arglist, NULL_TREE);
+         /* It's a PARM_DECL.  */
+         build_mangled_name_for_type (TREE_TYPE (parm));
+         build_overload_value (parm, arg, uses_template_parms (arglist));
+       }
+    }
+ }
+
+/* Output the representation for NAME, which is either a TYPE_DECL or
+   an IDENTIFIER.  */
+
 static void
 build_overload_identifier (name)
      tree name;
@@ -568,39 +914,22 @@ build_overload_identifier (name)
   if (TREE_CODE (name) == TYPE_DECL
       && IS_AGGR_TYPE (TREE_TYPE (name))
       && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name))
-      && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name))))
+      && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name)))
+         || (TREE_CODE (DECL_CONTEXT (CLASSTYPE_TI_TEMPLATE 
+                                      (TREE_TYPE (name))))
+             == FUNCTION_DECL)))
     {
+      /* NAME is the TYPE_DECL for a template specialization.  */
       tree template, parmlist, arglist, tname;
-      int i, nparms;
       template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
-      arglist = TREE_VALUE (template);
+      arglist = innermost_args (TREE_VALUE (template), 0);
       template = TREE_PURPOSE (template);
       tname = DECL_NAME (template);
-      parmlist = DECL_ARGUMENTS (template);
-      nparms = TREE_VEC_LENGTH (parmlist);
+      parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
       OB_PUTC ('t');
       icat (IDENTIFIER_LENGTH (tname));
       OB_PUTID (tname);
-      icat (nparms);
-      for (i = 0; i < nparms; i++)
-       {
-         tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
-         tree arg = TREE_VEC_ELT (arglist, i);
-         if (TREE_CODE (parm) == TYPE_DECL)
-           {
-             /* This parameter is a type.  */
-             OB_PUTC ('Z');
-             build_overload_name (arg, 0, 0);
-           }
-         else
-           {
-             parm = tsubst (parm, &TREE_VEC_ELT (arglist, 0),
-                            TREE_VEC_LENGTH (arglist), NULL_TREE);
-             /* It's a PARM_DECL.  */
-             build_overload_name (TREE_TYPE (parm), 0, 0);
-             build_overload_value (parm, arg);
-           }
-       }
+      build_template_parm_names (parmlist, arglist);
     }
   else
     {
@@ -616,384 +945,581 @@ build_overload_identifier (name)
     }
 }
 
-/* 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.  */
+/* 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.  */
 
-char *
-build_overload_name (parmtypes, begin, end)
-     tree parmtypes;
-     int begin, end;
+static void
+build_qualified_name (decl)
+     tree decl;
 {
-  int just_one;
-  tree parmtype;
+  tree context;
+  int i = 1;
 
-  if (begin) OB_INIT ();
-  numeric_output_need_bar = 0;
+  if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't')
+    decl = TYPE_NAME (decl);
 
-  if ((just_one = (TREE_CODE (parmtypes) != TREE_LIST)))
+  /* 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)
     {
-      parmtype = parmtypes;
-      goto only_one;
+      tree id = DECL_ASSEMBLER_NAME (decl);
+      OB_PUTID (id);
+      if (ISDIGIT (IDENTIFIER_POINTER (id) [IDENTIFIER_LENGTH (id) - 1]))
+       numeric_output_need_bar = 1;
+      return;
     }
 
-  while (parmtypes)
+  context = decl;
+  /* if we can't find a Ktype, do it the hard way */
+  if (check_ktype (context, FALSE) == -1)
     {
-      parmtype = TREE_VALUE (parmtypes);
-
-    only_one:
-
-      if (! nofold && ! just_one)
+      /* count type and namespace scopes */
+      while (DECL_CONTEXT (context) && DECL_CONTEXT (context) != global_namespace)
        {
-         /* Every argument gets counted.  */
-         typevec[maxtype++] = parmtype;
-
-         if (TREE_USED (parmtype) && parmtype == typevec[maxtype-2])
-           {
-             nrepeats++;
-             goto next;
-           }
+         i += 1;
+         context = DECL_CONTEXT (context);
+         if (check_ktype (context, FALSE) != -1)  /* found it! */
+           break;
+         if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
+           context = TYPE_NAME (context);
+       }
+    }
 
-         if (nrepeats)
-           flush_repeats (typevec[maxtype-2]);
+  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.  */
+
+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);
+  type = CANONICAL_TYPE_VARIANT (type);
+  process_modifiers (type);
+  process_overload_item (type, extra_Gcode);
+}
+
+/* Like build_mangled_name_for_type_with_Gcode, but never outputs the
+   `G'.  */
+
+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;
+  start_squangling ();
+  ret = build_mangled_name (parmtypes, begin, end);
+  end_squangling ();
+  return ret ;
+}
 
-         if (TREE_USED (parmtype))
+/* 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;
+{
+  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))
+       {
+         tree parmtype = CANONICAL_TYPE_VARIANT (TREE_VALUE (parmtypes));
+
+         if (old_style_repeats)
            {
-             flush_repeats (parmtype);
-             goto next;
+             /* Every argument gets counted.  */
+             my_friendly_assert (maxtype < typevec_size, 387);
+             typevec[maxtype++] = parmtype;
            }
 
-         /* Only cache types which take more than one character.  */
-         if (parmtype != TYPE_MAIN_VARIANT (parmtype)
-             || (TREE_CODE (parmtype) != INTEGER_TYPE
-                 && TREE_CODE (parmtype) != REAL_TYPE))
-           TREE_USED (parmtype) = 1;
-       }
+         if (parmtype == last_type)
+           {
+             if (flag_do_squangling 
+                 || (old_style_repeats && TREE_USED (parmtype)
+                     && !TYPE_FOR_JAVA (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;
+           }
+         
+         last_type = parmtype;
+
+         if (old_style_repeats)
+           {
+             if (nrepeats)
+               {
+                 flush_repeats (nrepeats, last_type);
+                 nrepeats = 0;
+               }
 
-      if (TYPE_PTRMEMFUNC_P (parmtype))
-       parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype);
+             if (TREE_USED (parmtype))
+               {
+#if 0
+                 /* We can turn this on at some point when we want
+                    improved symbol mangling.  */
+                 nrepeats++;
+#else
+                 /* This is bug compatible with 2.7.x  */
+                 flush_repeats (nrepeats, parmtype);
+#endif
+                 nrepeats = 0;
+                 continue;
+               }
+             
+             /* Only cache types which take more than one character.  */
+             if ((parmtype != TYPE_MAIN_VARIANT (parmtype)
+                  || (TREE_CODE (parmtype) != INTEGER_TYPE
+                      && TREE_CODE (parmtype) != REAL_TYPE))
+                 && ! TYPE_FOR_JAVA (parmtype))
+               TREE_USED (parmtype) = 1;
+           }
 
-      if (TREE_READONLY (parmtype))
-       OB_PUTC ('C');
-      if (TREE_CODE (parmtype) == INTEGER_TYPE
-         && TYPE_MAIN_VARIANT (parmtype) == unsigned_type (TYPE_MAIN_VARIANT (parmtype)))
-       OB_PUTC ('U');
-      if (TYPE_VOLATILE (parmtype))
-       OB_PUTC ('V');
+         /* Output the PARMTYPE.  */
+         build_mangled_name_for_type_with_Gcode (parmtype, 1);
+       }
 
-      switch (TREE_CODE (parmtype))
+      /* Output the repeat count for the last parameter, if
+        necessary.  */
+      if (nrepeats != 0)
        {
-       case OFFSET_TYPE:
-         OB_PUTC ('O');
-         build_overload_name (TYPE_OFFSET_BASETYPE (parmtype), 0, 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);
+}
+
+/* handles emitting modifiers such as Constant, read-only, and volatile */
+void 
+process_modifiers (parmtype) 
+     tree parmtype;
+{
+  if (TREE_READONLY (parmtype))
+    OB_PUTC ('C');
+  if (TREE_CODE (parmtype) == INTEGER_TYPE
+      && (TYPE_MAIN_VARIANT (parmtype)
+         == unsigned_type (TYPE_MAIN_VARIANT (parmtype)))
+      && ! TYPE_FOR_JAVA (parmtype))
+    OB_PUTC ('U');
+  if (TYPE_VOLATILE (parmtype))
+    OB_PUTC ('V');
+}
+
+/* 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.  */
+
+int 
+check_btype (type) 
+     tree type;
+{
+  int x;
+
+  if (btypelist == NULL)
+    return 0;
+
+  if (!is_back_referenceable_type (type))
+    return 0;
+
+  /* We assume that our caller has put out any necessary
+     qualifiers.  */
+  type = TYPE_MAIN_VARIANT (type);
+
+  for (x = 0; x < maxbtype; x++) 
+    if (type == btypelist[x]) 
+      {
+       OB_PUTC ('B');
+       icat (x);
+       if (x > 9)
          OB_PUTC ('_');
-         build_overload_name (TREE_TYPE (parmtype), 0, 0);
-         break;
+       return 1 ;
+      }
 
-       case REFERENCE_TYPE:
-         OB_PUTC ('R');
-         goto more;
+  if (maxbsize <= maxbtype) 
+    {
+      /* Enlarge the table.  */
+      maxbsize = maxbsize * 3 / 2;
+      btypelist = (tree *)xrealloc (btypelist, sizeof (tree) * maxbsize); 
+    }
+  
+  /* Register the TYPE.  */
+  btypelist[maxbtype++] = type;
 
-       case ARRAY_TYPE:
-#if PARM_CAN_BE_ARRAY_TYPE
-         {
-           tree length;
+  return 0;
+}
 
-           OB_PUTC ('A');
-           if (TYPE_DOMAIN (parmtype) == NULL_TREE)
-             error ("pointer or reference to array of unknown bound in parm type");
-           else
-             {
-               length = array_type_nelts (parmtype);
-               if (TREE_CODE (length) == INTEGER_CST)
-                 icat (TREE_INT_CST_LOW (length) + 1);
-             }
-           OB_PUTC ('_');
-           goto more;
-         }
+/* handle emitting the correct code for various node types */
+static void 
+process_overload_item (parmtype, extra_Gcode) 
+  tree parmtype;
+  int extra_Gcode;
+{
+  numeric_output_need_bar = 0;
+
+  /* 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:
+#if PARM_CAN_BE_ARRAY_TYPE
+      {
+        tree length;
+
+        OB_PUTC ('A');
+        if (TYPE_DOMAIN (parmtype) == NULL_TREE)
+          error("pointer/reference to array of unknown bound in parm type");
+        else
+          {
+            length = array_type_nelts (parmtype);
+            if (TREE_CODE (length) == INTEGER_CST)
+              icat (TREE_INT_CST_LOW (length) + 1);
+          }
+        OB_PUTC ('_');
+        goto more;
+      }
 #else
-         OB_PUTC ('P');
-         goto more;
+      OB_PUTC ('P');
+      goto more;
 #endif
 
-       case POINTER_TYPE:
-         OB_PUTC ('P');
-       more:
-         build_overload_name (TREE_TYPE (parmtype), 0, 0);
-         break;
+    case POINTER_TYPE:
+      OB_PUTC ('P');
+    more:
+      build_mangled_name_for_type (TREE_TYPE (parmtype));
+      return;
+      break;
 
-       case FUNCTION_TYPE:
-       case METHOD_TYPE:
-         {
-           tree firstarg = TYPE_ARG_TYPES (parmtype);
-           /* Otherwise have to implement reentrant typevecs,
-              unmark and remark types, etc.  */
-           int old_nofold = nofold;
-           nofold = 1;
-
-           if (nrepeats)
-             flush_repeats (typevec[maxtype-1]);
-
-           /* @@ It may be possible to pass a function type in
-              which is not preceded by a 'P'.  */
-           if (TREE_CODE (parmtype) == FUNCTION_TYPE)
-             {
-               OB_PUTC ('F');
-               if (firstarg == NULL_TREE)
-                 OB_PUTC ('e');
-               else if (firstarg == void_list_node)
-                 OB_PUTC ('v');
-               else
-                 build_overload_name (firstarg, 0, 0);
-             }
-           else
-             {
-               int constp = TYPE_READONLY (TREE_TYPE (TREE_VALUE (firstarg)));
-               int volatilep = TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (firstarg)));
-               OB_PUTC ('M');
-               firstarg = TREE_CHAIN (firstarg);
-
-               build_overload_name (TYPE_METHOD_BASETYPE (parmtype), 0, 0);
-               if (constp)
-                 OB_PUTC ('C');
-               if (volatilep)
-                 OB_PUTC ('V');
-
-               /* For cfront 2.0 compatibility.  */
-               OB_PUTC ('F');
-
-               if (firstarg == NULL_TREE)
-                 OB_PUTC ('e');
-               else if (firstarg == void_list_node)
-                 OB_PUTC ('v');
-               else
-                 build_overload_name (firstarg, 0, 0);
-             }
+    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;
 
-           /* Separate args from return type.  */
-           OB_PUTC ('_');
-           build_overload_name (TREE_TYPE (parmtype), 0, 0);
-           nofold = old_nofold;
-           break;
+  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)));
          }
 
-       case INTEGER_TYPE:
-         parmtype = TYPE_MAIN_VARIANT (parmtype);
-         if (parmtype == integer_type_node
-             || parmtype == unsigned_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)
-           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)
-           OB_PUTC ('c');
-         else if (parmtype == wchar_type_node)
-           OB_PUTC ('w');
-         else if (parmtype == long_long_integer_type_node
-             || parmtype == long_long_unsigned_type_node)
-           OB_PUTC ('x');
+       /* 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:
+      parmtype = TYPE_MAIN_VARIANT (parmtype);
+      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');
 #if 0
-         /* it would seem there is no way to enter these in source code,
-            yet.  (mrs) */
-         else if (parmtype == long_long_long_integer_type_node
-             || parmtype == long_long_long_unsigned_type_node)
-           OB_PUTC ('q');
+      /* it would seem there is no way to enter these in source code,
+         yet.  (mrs) */
+      else if (parmtype == long_long_long_integer_type_node
+          || parmtype == long_long_long_unsigned_type_node)
+        OB_PUTC ('q');
 #endif
-         else
-           my_friendly_abort (73);
-         break;
-
-       case BOOLEAN_TYPE:
-         OB_PUTC ('b');
-         break;
-
-       case REAL_TYPE:
-         parmtype = TYPE_MAIN_VARIANT (parmtype);
-         if (parmtype == long_double_type_node)
-           OB_PUTC ('r');
-         else if (parmtype == double_type_node)
-           OB_PUTC ('d');
-         else if (parmtype == float_type_node)
-           OB_PUTC ('f');
-         else my_friendly_abort (74);
-         break;
-
-       case VOID_TYPE:
-         if (! just_one)
-           {
-#if 0
-             extern tree void_list_node;
+      else if (parmtype == java_boolean_type_node)
+       OB_PUTC ('b');
+      else
+        my_friendly_abort (73);
+      break;
 
-             /* See if anybody is wasting memory.  */
-             my_friendly_assert (parmtypes == void_list_node, 247);
-#endif
-             /* This is the end of a parameter list.  */
-             if (end) OB_FINISH ();
-             return (char *)obstack_base (&scratch_obstack);
-           }
-         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 (! just_one)
-           /* Make this type signature look incompatible
-              with AT&T.  */
-           OB_PUTC ('G');
-         goto common;
-       case ENUMERAL_TYPE:
-       common:
-         {
-           tree name = TYPE_NAME (parmtype);
-           int i = 1;
+    case BOOLEAN_TYPE:
+      OB_PUTC ('b');
+      break;
 
-           if (TREE_CODE (name) == TYPE_DECL)
-             {
-               tree context = name;
+    case REAL_TYPE:
+      parmtype = TYPE_MAIN_VARIANT (parmtype);
+      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;
 
-               /* If DECL_ASSEMBLER_NAME has been set properly, use it. */
-               if (DECL_ASSEMBLER_NAME (context) != DECL_NAME (context))
-                 {
-                   OB_PUTID (DECL_ASSEMBLER_NAME (context));
-                   break;
-                 }
-               while (DECL_CONTEXT (context))
-                 {
-                   i += 1;
-                   context = DECL_CONTEXT (context);
-                   if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
-                     context = TYPE_NAME (context);
-                 }
-               name = DECL_NAME (name);
-             }
-           my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 248);
-           if (i > 1)
-             {
-               OB_PUTC ('Q');
-               if (i > 9)
-                 OB_PUTC ('_');
-               icat (i);
-               if (i > 9)
-                 OB_PUTC ('_');
-               numeric_output_need_bar = 0;
-               build_overload_nested_name (TYPE_MAIN_DECL (parmtype));
-             }
-           else              
-             build_overload_identifier (TYPE_MAIN_DECL (parmtype));
-           break;
-         }
+    case COMPLEX_TYPE:
+      OB_PUTC ('J');
+      build_mangled_name_for_type (TREE_TYPE (parmtype));
+      break;
 
-       case UNKNOWN_TYPE:
-         /* This will take some work.  */
-         OB_PUTC ('?');
-         break;
-
-       case TEMPLATE_TYPE_PARM:
-         OB_PUTC ('X');
-         if (TEMPLATE_TYPE_IDX (parmtype) > 9)
-           OB_PUTC ('_');
-         icat (TEMPLATE_TYPE_IDX (parmtype)); 
-         if (TEMPLATE_TYPE_IDX (parmtype) > 9)
-           OB_PUTC ('_');
-         break;
-           
-       case TYPENAME_TYPE:
-         /* 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;
-           sprintf (digit_buffer, " *%d", n++);
-           OB_PUTCP (digit_buffer);
-         }
-         break;
+    case VOID_TYPE:
+      OB_PUTC ('v');
+      break;
 
-       default:
-         my_friendly_abort (75);
-       }
+    case ERROR_MARK:   /* not right, but nothing is anyway */
+      break;
 
-    next:
-      if (just_one) break;
-      parmtypes = TREE_CHAIN (parmtypes);
-    }
-  if (! just_one)
-    {
-      if (nrepeats)
-       flush_repeats (typevec[maxtype-1]);
+      /* 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);
+
+        if (TREE_CODE (name) == IDENTIFIER_NODE)
+          {
+            build_overload_identifier (TYPE_NAME (parmtype));
+            break;
+          }
+        my_friendly_assert (TREE_CODE (name) == TYPE_DECL, 248);
 
-      /* To get here, parms must end with `...'. */
-      OB_PUTC ('e');
+        build_qualified_name (name);
+        break;
+      }
+
+    case UNKNOWN_TYPE:
+      /* This will take some work.  */
+      OB_PUTC ('?');
+      break;
+
+    case TEMPLATE_TEMPLATE_PARM:
+      /* Find and output the original template parameter 
+         declaration. */
+      if (CLASSTYPE_TEMPLATE_INFO (parmtype))
+        {
+         build_mangled_template_parm_index ("tzX",
+                                            TEMPLATE_TYPE_PARM_INDEX 
+                                            (parmtype));
+          build_template_parm_names
+            (DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (parmtype)),
+            CLASSTYPE_TI_ARGS (parmtype));
+        }
+      else
+        {
+         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);
     }
 
-  if (end) OB_FINISH ();
-  return (char *)obstack_base (&scratch_obstack);
 }
 
+/* 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 (basetype, name)
-  tree basetype, name;
+build_static_name (context, name)
+     tree context, name;
 {
-  char *basename  = build_overload_name (basetype, 1, 1);
-  char *buf = (char *) alloca (IDENTIFIER_LENGTH (name)
-                              + sizeof (STATIC_NAME_FORMAT)
-                              + strlen (basename));
-  sprintf (buf, STATIC_NAME_FORMAT, basename, IDENTIFIER_POINTER (name));
-  return get_identifier (buf);
-}  
-\f
-/* Change the name of a function definition so that it may be
-   overloaded. NAME is the name of the function to overload,
-   PARMS is the parameter list (which determines what name the
-   final function obtains).
+  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 ();
 
-   FOR_METHOD is 1 if this overload is being performed
-   for a method, rather than a function type.  It is 2 if
-   this overload is being performed for a constructor.  */
-tree
-build_decl_overload (dname, parms, for_method)
+  return get_identifier ((char *)obstack_base (&scratch_obstack));
+}
+\f
+static tree 
+build_decl_overload_real (dname, parms, ret_type, tparms, targs,
+                         for_method) 
      tree dname;
      tree parms;
+     tree ret_type;
+     tree tparms;
+     tree targs;
      int for_method;
 {
   char *name = IDENTIFIER_POINTER (dname);
 
   /* member operators new and delete look like methods at this point.  */
-  if (! for_method && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST)
+  if (! for_method && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST
+      && TREE_CHAIN (parms) == void_list_node)
     {
       if (dname == ansi_opname[(int) DELETE_EXPR])
        return get_identifier ("__builtin_delete");
       else if (dname == ansi_opname[(int) VEC_DELETE_EXPR])
        return get_identifier ("__builtin_vec_delete");
-      else if (TREE_CHAIN (parms) == void_list_node)
-       {
-         if (dname == ansi_opname[(int) NEW_EXPR])
-           return get_identifier ("__builtin_new");
-         else if (dname == ansi_opname[(int) VEC_NEW_EXPR])
-           return get_identifier ("__builtin_vec_new");
-       }
+      if (dname == ansi_opname[(int) NEW_EXPR])
+       return get_identifier ("__builtin_new");
+      else if (dname == ansi_opname[(int) VEC_NEW_EXPR])
+       return get_identifier ("__builtin_vec_new");
     }
 
+  start_squangling ();
   OB_INIT ();
   if (for_method != 2)
     OB_PUTCP (name);
@@ -1001,50 +1527,105 @@ build_decl_overload (dname, parms, for_method)
      and figure out its name without any extra encoding.  */
 
   OB_PUTC2 ('_', '_');
-  if (for_method)
-    {
-#if 0
-      /* We can get away without doing this.  */
-      OB_PUTC ('M');
-#endif
-      {
-       tree this_type = TREE_VALUE (parms);
 
-       if (TREE_CODE (this_type) == RECORD_TYPE)  /* a signature pointer */
-         parms = temp_tree_cons (NULL_TREE, SIGNATURE_TYPE (this_type),
-                                 TREE_CHAIN (parms));
-       else
-         parms = temp_tree_cons (NULL_TREE, TREE_TYPE (this_type),
-                                 TREE_CHAIN (parms));
-      }
+  if (tparms)
+    {
+      OB_PUTC ('H');
+      build_template_parm_names (tparms, targs);
+      OB_PUTC ('_');
     }
-  else
+  else if (!for_method && current_namespace == global_namespace)
+    /* XXX this works only if we call this in the same namespace
+       as the declaration. Unfortunately, we don't have the _DECL,
+       only its name */
     OB_PUTC ('F');
+  else if (!for_method)
+    /* qualify with namespace */
+    build_qualified_name (current_namespace);
 
   if (parms == NULL_TREE)
-    OB_PUTC2 ('e', '\0');
+    OB_PUTC ('e');
   else if (parms == void_list_node)
-    OB_PUTC2 ('v', '\0');
+    OB_PUTC ('v');
   else
     {
-      ALLOCATE_TYPEVEC (parms);
+      if (!flag_do_squangling)    /* Allocate typevec array. */
+        {
+          maxtype = 0;
+         typevec_size = list_length (parms);
+         if (!for_method && current_namespace != global_namespace)
+           /* the namespace of a global function needs one slot */
+           typevec_size++;
+          typevec = (tree *)alloca (typevec_size * sizeof (tree));
+        }
       nofold = 0;
+
       if (for_method)
        {
-         build_overload_name (TREE_VALUE (parms), 0, 0);
+         tree this_type = TREE_VALUE (parms);
+
+         if (TREE_CODE (this_type) == RECORD_TYPE)  /* a signature pointer */
+           this_type = SIGNATURE_TYPE (this_type);
+         else
+           this_type = TREE_TYPE (this_type);
 
-         typevec[maxtype++] = TREE_VALUE (parms);
-         TREE_USED (TREE_VALUE (parms)) = 1;
+         build_mangled_name_for_type (this_type);
+
+          if (!flag_do_squangling) 
+           {
+             my_friendly_assert (maxtype < typevec_size, 387);
+             typevec[maxtype++] = this_type;
+             TREE_USED (this_type) = 1;
+
+             /* By setting up PARMS in this way, the loop below will
+                automatically clear TREE_USED on THIS_TYPE.  */
+             parms = temp_tree_cons (NULL_TREE, this_type,
+                                     TREE_CHAIN (parms));
+           }
 
          if (TREE_CHAIN (parms))
-           build_overload_name (TREE_CHAIN (parms), 0, 1);
+           build_mangled_name (TREE_CHAIN (parms), 0, 0);
          else
-           OB_PUTC2 ('e', '\0');
+           OB_PUTC ('e');
        }
       else
-       build_overload_name (parms, 0, 1);
-      DEALLOCATE_TYPEVEC (parms);
+       {
+         /* the namespace qualifier for a global function 
+            will count as type */
+         if (current_namespace != global_namespace
+             && !flag_do_squangling)
+           {
+             my_friendly_assert (maxtype < typevec_size, 387);
+             typevec[maxtype++] = current_namespace;
+           }
+         build_mangled_name (parms, 0, 0);
+       }
+
+      if (!flag_do_squangling)     /* Deallocate typevec array */
+        {
+          tree t = parms;
+          typevec = NULL;
+          while (t)
+            {
+              tree temp = TREE_VALUE (t);
+              TREE_USED (temp) = 0;
+              /* clear out the type variant in case we used it */
+              temp = CANONICAL_TYPE_VARIANT (temp);
+              TREE_USED (temp) = 0;
+              t = TREE_CHAIN (t);
+            }
+        }
+    }
+
+  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));
     if (IDENTIFIER_OPNAME_P (dname))
@@ -1053,458 +1634,146 @@ build_decl_overload (dname, parms, for_method)
   }
 }
 
-/* Build an overload name for the type expression TYPE.  */
-tree
-build_typename_overload (type)
-     tree type;
-{
-  tree id;
-
-  OB_INIT ();
-  OB_PUTID (ansi_opname[(int) TYPE_EXPR]);
-  nofold = 1;
-  build_overload_name (type, 0, 1);
-  id = get_identifier (obstack_base (&scratch_obstack));
-  IDENTIFIER_OPNAME_P (id) = 1;
-#if 0
-  IDENTIFIER_GLOBAL_VALUE (id) = TYPE_NAME (type);
-#endif
-  TREE_TYPE (id) = type;
-  return id;
-}
+/* Change the name of a function definition so that it may be
+   overloaded. NAME is the name of the function to overload,
+   PARMS is the parameter list (which determines what name the
+   final function obtains).
 
-#ifndef NO_DOLLAR_IN_LABEL
-#define T_DESC_FORMAT "TD$"
-#define I_DESC_FORMAT "ID$"
-#define M_DESC_FORMAT "MD$"
-#else
-#if !defined(NO_DOT_IN_LABEL)
-#define T_DESC_FORMAT "TD."
-#define I_DESC_FORMAT "ID."
-#define M_DESC_FORMAT "MD."
-#else
-#define T_DESC_FORMAT "__t_desc_"
-#define I_DESC_FORMAT "__i_desc_"
-#define M_DESC_FORMAT "__m_desc_"
-#endif
-#endif
+   FOR_METHOD is 1 if this overload is being performed
+   for a method, rather than a function type.  It is 2 if
+   this overload is being performed for a constructor.  */
 
-/* Build an overload name for the type expression TYPE.  */
 tree
-build_t_desc_overload (type)
-     tree type;
-{
-  OB_INIT ();
-  OB_PUTS (T_DESC_FORMAT);
-  nofold = 1;
-
-#if 0
-  /* Use a different format if the type isn't defined yet.  */
-  if (TYPE_SIZE (type) == NULL_TREE)
-    {
-      char *p;
-      int changed;
-
-      for (p = tname; *p; p++)
-       if (isupper (*p))
-         {
-           changed = 1;
-           *p = tolower (*p);
-         }
-      /* If there's no change, we have an inappropriate T_DESC_FORMAT.  */
-      my_friendly_assert (changed != 0, 249);
-    }
-#endif
-
-  build_overload_name (type, 0, 1);
-  return get_identifier (obstack_base (&scratch_obstack));
-}
-
-/* Top-level interface to explicit overload requests. Allow NAME
-   to be overloaded. Error if NAME is already declared for the current
-   scope. Warning if function is redundantly overloaded. */
-
-void
-declare_overloaded (name)
-     tree name;
-{
-#ifdef NO_AUTO_OVERLOAD
-  if (is_overloaded (name))
-    warning ("function `%s' already declared overloaded",
-            IDENTIFIER_POINTER (name));
-  else if (IDENTIFIER_GLOBAL_VALUE (name))
-    error ("overloading function `%s' that is already defined",
-          IDENTIFIER_POINTER (name));
-  else
-    {
-      TREE_OVERLOADED (name) = 1;
-      IDENTIFIER_GLOBAL_VALUE (name) = build_tree_list (name, NULL_TREE);
-      TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)) = unknown_type_node;
-    }
-#else
-  if (current_lang_name == lang_name_cplusplus)
-    {
-      if (0)
-       warning ("functions are implicitly overloaded in C++");
-    }
-  else if (current_lang_name == lang_name_c)
-    error ("overloading function `%s' cannot be done in C language context");
-  else
-    my_friendly_abort (76);
-#endif
-}
-
-#ifdef NO_AUTO_OVERLOAD
-/* Check to see if NAME is overloaded. For first approximation,
-   check to see if its TREE_OVERLOADED is set.  This is used on
-   IDENTIFIER nodes.  */
-int
-is_overloaded (name)
-     tree name;
+build_decl_overload (dname, parms, for_method)
+     tree dname;
+     tree parms;
+     int for_method;
 {
-  /* @@ */
-  return (TREE_OVERLOADED (name)
-         && (! IDENTIFIER_CLASS_VALUE (name) || current_class_type == 0)
-         && ! IDENTIFIER_LOCAL_VALUE (name));
+  return build_decl_overload_real (dname, parms, NULL_TREE, NULL_TREE,
+                                  NULL_TREE, for_method); 
 }
-#endif
-\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.
+/* Like build_decl_overload, but for template 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'.  */
-
-/* NOSTRICT */
 tree
-build_opfncall (code, flags, xarg1, xarg2, arg3)
-     enum tree_code code;
-     int flags;
-     tree xarg1, xarg2, arg3;
+build_template_decl_overload (decl, parms, ret_type, tparms, targs,
+                             for_method) 
+     tree decl;
+     tree parms;
+     tree ret_type;
+     tree tparms;
+     tree targs;
+     int for_method;
 {
-  tree rval = 0;
-  tree arg1, arg2;
-  tree type1, type2, fnname;
-  tree fields1 = 0, parms = 0;
-  tree global_fn;
-  int try_second;
-  int binary_is_unary;
-
-  if (xarg1 == error_mark_node)
-    return error_mark_node;
-
-  if (code == COND_EXPR)
-    {
-      if (TREE_CODE (xarg2) == ERROR_MARK
-         || TREE_CODE (arg3) == ERROR_MARK)
-       return error_mark_node;
-    }
-  if (code == COMPONENT_REF)
-    if (TREE_CODE (TREE_TYPE (xarg1)) == POINTER_TYPE)
-      return rval;
-
-  /* First, see if we can work with the first argument */
-  type1 = TREE_TYPE (xarg1);
-
-  /* Some tree codes have length > 1, but we really only want to
-     overload them if their first argument has a user defined type.  */
-  switch (code)
-    {
-    case PREINCREMENT_EXPR:
-    case PREDECREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-    case COMPONENT_REF:
-      binary_is_unary = 1;
-      try_second = 0;
-      break;
-
-      /* ARRAY_REFs and CALL_EXPRs must overload successfully.
-        If they do not, return error_mark_node instead of NULL_TREE.  */
-    case ARRAY_REF:
-      if (xarg2 == error_mark_node)
-       return error_mark_node;
-    case CALL_EXPR:
-      rval = error_mark_node;
-      binary_is_unary = 0;
-      try_second = 0;
-      break;
-
-    case VEC_NEW_EXPR:
-    case NEW_EXPR:
-      {
-       tree args = tree_cons (NULL_TREE, xarg2, arg3);
-       fnname = ansi_opname[(int) code];
-       if (flags & LOOKUP_GLOBAL)
-         return build_overload_call (fnname, args, flags & LOOKUP_COMPLAIN,
-                                     (struct candidate *)0);
-
-       rval = build_method_call
-         (build_indirect_ref (build1 (NOP_EXPR, xarg1, error_mark_node),
-                              "new"),
-          fnname, args, NULL_TREE, flags);
-       if (rval == error_mark_node)
-         /* User might declare fancy operator new, but invoke it
-            like standard one.  */
-         return rval;
-
-       TREE_TYPE (rval) = xarg1;
-       TREE_CALLS_NEW (rval) = 1;
-       return rval;
-      }
-      break;
-
-    case VEC_DELETE_EXPR:
-    case DELETE_EXPR:
-      {
-       fnname = ansi_opname[(int) code];
-       if (flags & LOOKUP_GLOBAL)
-         return build_overload_call (fnname,
-                                     build_tree_list (NULL_TREE, xarg1),
-                                     flags & LOOKUP_COMPLAIN,
-                                     (struct candidate *)0);
-       arg1 = TREE_TYPE (xarg1);
-
-       /* This handles the case where we're trying to delete
-          X (*a)[10];
-          a=new X[5][10];
-          delete[] a; */
-          
-       if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE)
-         {
-           /* Strip off the pointer and the array. */
-           arg1 = TREE_TYPE (TREE_TYPE (arg1));
-
-           while (TREE_CODE (arg1) == ARRAY_TYPE)
-               arg1 = (TREE_TYPE (arg1));
-
-           arg1 = build_pointer_type (arg1);
-         }
-
-       rval = build_method_call
-         (build_indirect_ref (build1 (NOP_EXPR, arg1,
-                                      error_mark_node),
-                              NULL_PTR),
-          fnname, tree_cons (NULL_TREE, xarg1,
-                              build_tree_list (NULL_TREE, xarg2)),
-          NULL_TREE, flags);
-#if 0
-       /* This can happen when operator delete is protected.  */
-       my_friendly_assert (rval != error_mark_node, 250);
-       TREE_TYPE (rval) = void_type_node;
-#endif
-       return rval;
-      }
-      break;
-
-    default:
-      binary_is_unary = 0;
-      try_second = tree_code_length [(int) code] == 2;
-      if (try_second && xarg2 == error_mark_node)
-       return error_mark_node;
-      break;
-    }
+  tree res, saved_ctx;
 
-  if (try_second && xarg2 == error_mark_node)
-    return error_mark_node;
+  /* If the template is in a namespace, we need to put that into the
+     mangled name. Unfortunately, build_decl_overload_real does not
+     get the decl to mangle, so it relies on the current
+     namespace. Therefore, we set that here temporarily. */
 
-  /* What ever it was, we do not know how to deal with it.  */
-  if (type1 == NULL_TREE)
-    return rval;
+  my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd', 980702);
+  saved_ctx = current_namespace;
+  current_namespace = CP_DECL_CONTEXT (decl);  
 
-  if (TREE_CODE (type1) == OFFSET_TYPE)
-    type1 = TREE_TYPE (type1);
+  res = build_decl_overload_real (DECL_NAME (decl), parms, ret_type,
+                                 tparms, targs, for_method); 
 
-  if (TREE_CODE (type1) == REFERENCE_TYPE)
-    {
-      arg1 = convert_from_reference (xarg1);
-      type1 = TREE_TYPE (arg1);
-    }
-  else
-    {
-      arg1 = xarg1;
-    }
-
-  if (!IS_AGGR_TYPE (type1) || TYPE_PTRMEMFUNC_P (type1))
-    {
-      /* Try to fail. First, fail if unary */
-      if (! try_second)
-       return rval;
-      /* Second, see if second argument is non-aggregate. */
-      type2 = TREE_TYPE (xarg2);
-      if (TREE_CODE (type2) == OFFSET_TYPE)
-       type2 = TREE_TYPE (type2);
-      if (TREE_CODE (type2) == REFERENCE_TYPE)
-       {
-         arg2 = convert_from_reference (xarg2);
-         type2 = TREE_TYPE (arg2);
-       }
-      else
-       {
-         arg2 = xarg2;
-       }
-
-      if (!IS_AGGR_TYPE (type2))
-       return rval;
-      try_second = 0;
-    }
-
-  if (try_second)
-    {
-      /* First arg may succeed; see whether second should.  */
-      type2 = TREE_TYPE (xarg2);
-      if (TREE_CODE (type2) == OFFSET_TYPE)
-       type2 = TREE_TYPE (type2);
-      if (TREE_CODE (type2) == REFERENCE_TYPE)
-       {
-         arg2 = convert_from_reference (xarg2);
-         type2 = TREE_TYPE (arg2);
-       }
-      else
-       {
-         arg2 = xarg2;
-       }
-
-      if (! IS_AGGR_TYPE (type2))
-       try_second = 0;
-    }
+  current_namespace = saved_ctx;
+  return res;
+}
 
-  if (type1 == unknown_type_node
-      || (try_second && TREE_TYPE (xarg2) == unknown_type_node))
-    {
-      /* This will not be implemented in the foreseeable future.  */
-      return rval;
-    }
 
-  if (code == MODIFY_EXPR)
-    fnname = ansi_assopname[(int) TREE_CODE (arg3)];
-  else
-    fnname = ansi_opname[(int) code];
+/* Build an overload name for the type expression TYPE.  */
 
-  global_fn = lookup_name_nonclass (fnname);
+tree
+build_typename_overload (type)
+     tree type;
+{
+  tree id;
 
-  /* This is the last point where we will accept failure.  This
-     may be too eager if we wish an overloaded operator not to match,
-     but would rather a normal operator be called on a type-converted
-     argument.  */
+  OB_INIT ();
+  OB_PUTID (ansi_opname[(int) TYPE_EXPR]);
+  nofold = 1;
+  start_squangling ();
+  build_mangled_name (type, 0, 1);
+  id = get_identifier (obstack_base (&scratch_obstack));
+  IDENTIFIER_OPNAME_P (id) = 1;
+#if 0
+  IDENTIFIER_GLOBAL_VALUE (id) = TYPE_MAIN_DECL (type);
+#endif
+  TREE_TYPE (id) = type;
+  end_squangling ();
+  return id;
+}
 
-  if (IS_AGGR_TYPE (type1))
-    {
-      fields1 = lookup_fnfields (TYPE_BINFO (type1), fnname, 0);
-      /* ARM $13.4.7, prefix/postfix ++/--.  */
-      if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
-       {
-         xarg2 = integer_zero_node;
-         binary_is_unary = 0;
+tree
+build_overload_with_type (name, type)
+     tree name, type;
+{
+  OB_INIT ();
+  OB_PUTID (name);
+  nofold = 1;
 
-         if (fields1)
-           {
-             tree t, t2;
-             int have_postfix = 0;
+  start_squangling ();
+  build_mangled_name (type, 0, 1);
+  end_squangling ();
+  return get_identifier (obstack_base (&scratch_obstack));
+}
 
-             /* Look for an `operator++ (int)'.  If they didn't have
-                one, then we fall back to the old way of doing things.  */
-             for (t = TREE_VALUE (fields1); t ; t = DECL_CHAIN (t))
-               {
-                 t2 = TYPE_ARG_TYPES (TREE_TYPE (t));
-                 if (TREE_CHAIN (t2) != NULL_TREE
-                     && TREE_VALUE (TREE_CHAIN (t2)) == integer_type_node)
-                   {
-                     have_postfix = 1;
-                     break;
-                   }
-               }
+tree
+get_id_2 (name, name2)
+     char *name;
+     tree name2;
+{
+  OB_INIT ();
+  OB_PUTCP (name);
+  OB_PUTID (name2);
+  OB_FINISH ();
+  return get_identifier (obstack_base (&scratch_obstack));
+}
 
-             if (! have_postfix)
-               {
-                 char *op = POSTINCREMENT_EXPR ? "++" : "--";
-
-                 /* There's probably a LOT of code in the world that
-                    relies upon this old behavior.  */
-                 if (! flag_traditional)
-                   pedwarn ("no `operator%s (int)' declared for postfix `%s', using prefix operator instead",
-                            op, op);
-                 xarg2 = NULL_TREE;
-                 binary_is_unary = 1;
-               }
-           }
-       }
-    }
+/* Returns a DECL_ASSEMBLER_NAME for the destructor of type TYPE.  */
 
-  if (fields1 == NULL_TREE && global_fn == NULL_TREE)
-    return rval;
+tree
+build_destructor_name (type)
+     tree type;
+{
+  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.
 
-  /* If RVAL winds up being `error_mark_node', we will return
-     that... There is no way that normal semantics of these
-     operators will succeed.  */
+   For unary operators, only the first argument need be checked.
+   For binary operators, both arguments may need to be checked.
 
-  /* This argument may be an uncommitted OFFSET_REF.  This is
-     the case for example when dealing with static class members
-     which are referenced from their class name rather than
-     from a class instance.  */
-  if (TREE_CODE (xarg1) == OFFSET_REF
-      && TREE_CODE (TREE_OPERAND (xarg1, 1)) == VAR_DECL)
-    xarg1 = TREE_OPERAND (xarg1, 1);
-  if (try_second && xarg2 && TREE_CODE (xarg2) == OFFSET_REF
-      && TREE_CODE (TREE_OPERAND (xarg2, 1)) == VAR_DECL)
-    xarg2 = TREE_OPERAND (xarg2, 1);
+   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.
 
-  if (global_fn)
-    flags |= LOOKUP_GLOBAL;
+   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.
 
-  if (code == CALL_EXPR)
-    {
-      /* This can only be a member function.  */
-      return build_method_call (xarg1, fnname, xarg2,
-                               NULL_TREE, LOOKUP_NORMAL);
-    }
-  else if (tree_code_length[(int) code] == 1 || binary_is_unary)
-    {
-      parms = NULL_TREE;
-      rval = build_method_call (xarg1, fnname, NULL_TREE, NULL_TREE, flags);
-    }
-  else if (code == COND_EXPR)
-    {
-      parms = tree_cons (0, xarg2, build_tree_list (NULL_TREE, arg3));
-      rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);
-    }
-  else if (code == METHOD_CALL_EXPR)
-    {
-      /* must be a member function.  */
-      parms = tree_cons (NULL_TREE, xarg2, arg3);
-      return build_method_call (xarg1, fnname, parms, NULL_TREE,
-                               LOOKUP_NORMAL);
-    }
-  else if (fields1)
-    {
-      parms = build_tree_list (NULL_TREE, xarg2);
-      rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);
-    }
-  else
-    {
-      parms = tree_cons (NULL_TREE, xarg1,
-                        build_tree_list (NULL_TREE, xarg2));
-      rval = build_overload_call (fnname, parms, flags,
-                                 (struct candidate *)0);
-    }
+   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'.  */
 
-  return rval;
+/* 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);
 }
 \f
 /* This function takes an identifier, ID, and attempts to figure out what
@@ -1530,9 +1799,9 @@ tree
 hack_identifier (value, name)
      tree value, name;
 {
-  tree type, context;
+  tree type;
 
-  if (TREE_CODE (value) == ERROR_MARK)
+  if (value == error_mark_node)
     {
       if (current_class_name)
        {
@@ -1545,6 +1814,9 @@ hack_identifier (value, name)
 
              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");
@@ -1556,6 +1828,7 @@ hack_identifier (value, name)
                         IDENTIFIER_POINTER (name));
                  return error_mark_node;
                }
+#endif
            }
        }
       if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name))
@@ -1568,22 +1841,21 @@ hack_identifier (value, name)
   type = TREE_TYPE (value);
   if (TREE_CODE (value) == FIELD_DECL)
     {
-      if (current_class_decl == NULL_TREE)
+      if (current_class_ptr == NULL_TREE)
        {
          error ("request for member `%s' in static member function",
                 IDENTIFIER_POINTER (DECL_NAME (value)));
          return error_mark_node;
        }
-      TREE_USED (current_class_decl) = 1;
+      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;
-      return build_component_ref (C_C_D, name, 0, 1);
+      value = build_component_ref (current_class_ref, name, NULL_TREE, 1);
     }
-
-  if (really_overloaded_fn (value))
+  else if (really_overloaded_fn (value))
     {
 #if 0
       tree t = get_first_fn (value);
@@ -1597,6 +1869,9 @@ hack_identifier (value, name)
        }
 #endif
     }
+  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?.  */
@@ -1607,6 +1882,16 @@ hack_identifier (value, name)
          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);
 
@@ -1644,8 +1929,8 @@ hack_identifier (value, name)
                  if (TREE_CODE (value) == VAR_DECL)
                    error ("static member `%s' is %s",
                           IDENTIFIER_POINTER (name),
-                          TREE_PRIVATE (value) ? "private" :
-                          "from a private base class");
+                          TREE_PRIVATE (value) ? "private"
+                                               : "from a private base class");
                  else
                    error ("enum `%s' is from private base class",
                           IDENTIFIER_POINTER (name));
@@ -1653,9 +1938,8 @@ hack_identifier (value, name)
                }
            }
        }
-      return value;
     }
-  if (TREE_CODE (value) == TREE_LIST && TREE_NONLOCAL_FLAG (value))
+  else if (TREE_CODE (value) == TREE_LIST && TREE_NONLOCAL_FLAG (value))
     {
       if (type == 0)
        {
@@ -1667,435 +1951,167 @@ hack_identifier (value, name)
       return value;
     }
 
-  if (TREE_CODE (type) == REFERENCE_TYPE && ! current_template_parms)
-    {
-      my_friendly_assert (TREE_CODE (value) == VAR_DECL
-                         || TREE_CODE (value) == PARM_DECL
-                         || TREE_CODE (value) == RESULT_DECL, 252);
-      return convert_from_reference (value);
-    }
+  if (TREE_CODE (type) == REFERENCE_TYPE && ! processing_template_decl)
+    value = convert_from_reference (value);
   return value;
 }
 
 \f
-#if 0
-/* Given an object OF, and a type conversion operator COMPONENT
-   build a call to the conversion operator, if a call is requested,
-   or return the address (as a pointer to member function) if one is not.
-
-   OF can be a TYPE_DECL or any kind of datum that would normally
-   be passed to `build_component_ref'.  It may also be NULL_TREE,
-   in which case `current_class_type' and `current_class_decl'
-   provide default values.
-
-   BASETYPE_PATH, if non-null, is the path of basetypes
-   to go through before we get the the instance of interest.
-
-   PROTECT says whether we apply C++ scoping rules or not.  */
-tree
-build_component_type_expr (of, component, basetype_path, protect)
-     tree of, component, basetype_path;
-     int protect;
-{
-  tree cname = NULL_TREE;
-  tree tmp, last;
-  tree name;
-  int flags = protect ? LOOKUP_NORMAL : LOOKUP_COMPLAIN;
-
-  if (of)
-    my_friendly_assert (IS_AGGR_TYPE (TREE_TYPE (of)), 253);
-  my_friendly_assert (TREE_CODE (component) == TYPE_EXPR, 254);
-
-  tmp = TREE_OPERAND (component, 0);
-  last = NULL_TREE;
-
-  while (tmp)
-    {
-      switch (TREE_CODE (tmp))
-       {
-       case CALL_EXPR:
-         if (last)
-           TREE_OPERAND (last, 0) = TREE_OPERAND (tmp, 0);
-         else
-           TREE_OPERAND (component, 0) = TREE_OPERAND (tmp, 0);
-
-         last = groktypename (build_tree_list (TREE_TYPE (component),
-                                               TREE_OPERAND (component, 0)));
-         name = build_typename_overload (last);
-         TREE_TYPE (name) = last;
-
-         if (TREE_OPERAND (tmp, 0)
-             && TREE_OPERAND (tmp, 0) != void_list_node)
-           {
-             cp_error ("`operator %T' requires empty parameter list", last);
-             TREE_OPERAND (tmp, 0) = NULL_TREE;
-           }
-
-         if (of && TREE_CODE (of) != TYPE_DECL)
-           return build_method_call (of, name, NULL_TREE, NULL_TREE, flags);
-         else if (of)
-           {
-             tree this_this;
-
-             if (current_class_decl == NULL_TREE)
-               {
-                 cp_error ("object required for `operator %T' call",
-                           TREE_TYPE (name));
-                 return error_mark_node;
-               }
-
-             this_this = convert_pointer_to (TREE_TYPE (of),
-                                             current_class_decl);
-             this_this = build_indirect_ref (this_this, NULL_PTR);
-             return build_method_call (this_this, name, NULL_TREE,
-                                       NULL_TREE, flags | LOOKUP_NONVIRTUAL);
-           }
-         else if (current_class_decl)
-           return build_method_call (tmp, name, NULL_TREE, NULL_TREE, flags);
-
-         cp_error ("object required for `operator %T' call",
-                   TREE_TYPE (name));
-         return error_mark_node;
-
-       case INDIRECT_REF:
-       case ADDR_EXPR:
-       case ARRAY_REF:
-         break;
-
-       case SCOPE_REF:
-         my_friendly_assert (cname == 0, 255);
-         cname = TREE_OPERAND (tmp, 0);
-         tmp = TREE_OPERAND (tmp, 1);
-         break;
-
-       default:
-         my_friendly_abort (77);
-       }
-      last = tmp;
-      tmp = TREE_OPERAND (tmp, 0);
-    }
-
-  last = groktypename (build_tree_list (TREE_TYPE (component), TREE_OPERAND (component, 0)));
-  name = build_typename_overload (last);
-  TREE_TYPE (name) = last;
-  if (of && TREE_CODE (of) == TYPE_DECL)
-    {
-      if (cname == NULL_TREE)
-       {
-         cname = DECL_NAME (of);
-         of = NULL_TREE;
-       }
-      else my_friendly_assert (cname == DECL_NAME (of), 256);
-    }
-
-  if (of)
-    {
-      tree this_this;
-
-      if (current_class_decl == NULL_TREE)
-       {
-         cp_error ("object required for `operator %T' call",
-                   TREE_TYPE (name));
-         return error_mark_node;
-       }
-
-      this_this = convert_pointer_to (TREE_TYPE (of), current_class_decl);
-      return build_component_ref (this_this, name, 0, protect);
-    }
-  else if (cname)
-    return build_offset_ref (cname, name);
-  else if (current_class_name)
-    return build_offset_ref (current_class_name, name);
-
-  cp_error ("object required for `operator %T' member reference",
-           TREE_TYPE (name));
-  return error_mark_node;
-}
-#endif
-\f
-static char *
-thunk_printable_name (decl)
-     tree decl;
-{
-  return "<thunk function>";
-}
-
 tree
 make_thunk (function, delta)
      tree function;
      int delta;
 {
-  char buffer[250];
-  tree thunk_fndecl, thunk_id;
+  tree thunk_id;
   tree thunk;
-  char *func_name;
-  static int thunk_number = 0;
   tree func_decl;
+
   if (TREE_CODE (function) != ADDR_EXPR)
     abort ();
   func_decl = TREE_OPERAND (function, 0);
   if (TREE_CODE (func_decl) != FUNCTION_DECL)
     abort ();
-  func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func_decl));
-  if (delta<=0)
-    sprintf (buffer, "__thunk_%d_%s", -delta, func_name);
+
+  OB_INIT ();
+  OB_PUTS ("__thunk_");
+  if (delta > 0)
+    {
+      OB_PUTC ('n');
+      icat (delta);
+    }
   else
-    sprintf (buffer, "__thunk_n%d_%s", delta, func_name);
-  thunk_id = get_identifier (buffer);
+    icat (-delta);
+  OB_PUTC ('_');
+  OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
+  OB_FINISH ();
+  thunk_id = get_identifier (obstack_base (&scratch_obstack));
+
   thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id);
   if (thunk && TREE_CODE (thunk) != THUNK_DECL)
     {
       cp_error ("implementation-reserved name `%D' used", thunk_id);
-      IDENTIFIER_GLOBAL_VALUE (thunk_id) = thunk = NULL_TREE;
+      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_RESULT (thunk)
-       = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (vtable_entry_type)));
-      TREE_READONLY (thunk) = TYPE_READONLY (TREE_TYPE (vtable_entry_type));
-      TREE_THIS_VOLATILE (thunk) = TYPE_VOLATILE (TREE_TYPE (vtable_entry_type));
-      make_function_rtl (thunk);
+      TREE_READONLY (thunk) = TREE_READONLY (func_decl);
+      TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (func_decl);
+      comdat_linkage (thunk);
       TREE_SET_CODE (thunk, THUNK_DECL);
       DECL_INITIAL (thunk) = function;
       THUNK_DELTA (thunk) = delta;
       DECL_EXTERNAL (thunk) = 1;
-      TREE_PUBLIC (thunk) = 1;
+      DECL_ARTIFICIAL (thunk) = 1;
       /* So that finish_file can write out any thunks that need to be: */
       pushdecl_top_level (thunk);
     }
   return thunk;
 }
 
+/* Emit the definition of a C++ multiple inheritance vtable thunk.  */
+
 void
 emit_thunk (thunk_fndecl)
-  tree thunk_fndecl;
+     tree thunk_fndecl;
 {
-  rtx insns;
-  char *fnname;
-  char buffer[250];
-  tree argp;
-  struct args_size stack_args_size;
   tree function = TREE_OPERAND (DECL_INITIAL (thunk_fndecl), 0);
   int delta = THUNK_DELTA (thunk_fndecl);
-  int tem;
-  int failure = 0;
-  int current_call_is_indirect = 0;    /* needed for HPPA FUNCTION_ARG */
-
-  /* Used to remember which regs we need to emit a USE rtx for. */
-  rtx need_use[FIRST_PSEUDO_REGISTER];
-  int need_use_count = 0;
-
-  /* rtx for the 'this' parameter. */
-  rtx this_rtx = 0, this_reg_rtx = 0, fixed_this_rtx;
-
-  char *(*save_decl_printable_name) () = decl_printable_name;
-  /* Data on reg parms scanned so far.  */
-  CUMULATIVE_ARGS args_so_far;
 
   if (TREE_ASM_WRITTEN (thunk_fndecl))
     return;
 
   TREE_ASM_WRITTEN (thunk_fndecl) = 1;
 
-  if (! TREE_PUBLIC (function))
-    TREE_PUBLIC (thunk_fndecl) = 0;
-  if (DECL_EXTERNAL (function))
-    return;
-  DECL_EXTERNAL (thunk_fndecl) = 0;
+  TREE_ADDRESSABLE (function) = 1;
+  mark_used (function);
 
-  decl_printable_name = thunk_printable_name;
   if (current_function_decl)
     abort ();
-  current_function_decl = thunk_fndecl;
-  init_function_start (thunk_fndecl, input_filename, lineno);
-  pushlevel (0);
-  expand_start_bindings (1);
-
-  /* Start updating where the next arg would go.  */
-  INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (function), NULL_RTX);
-  stack_args_size.constant = 0;
-  stack_args_size.var = 0;
-  /* SETUP for possible structure return address FIXME */
-
-  /* Now look through all the parameters, make sure that we
-     don't clobber any registers used for parameters.
-     Also, pick up an rtx for the first "this" parameter. */
-  for (argp = TYPE_ARG_TYPES (TREE_TYPE (function));
-       argp != NULL_TREE;
-       argp = TREE_CHAIN (argp))
-
-    {
-      tree passed_type = TREE_VALUE (argp);
-      register rtx entry_parm;
-      int named = 1; /* FIXME */
-      struct args_size stack_offset;
-      struct args_size arg_size;
-
-      if (passed_type == void_type_node)
-       break;
-
-      if ((TREE_CODE (TYPE_SIZE (passed_type)) != INTEGER_CST
-          && contains_placeholder_p (TYPE_SIZE (passed_type)))
-#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
-         || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far,
-                                            TYPE_MODE (passed_type),
-                                            passed_type, named)
-#endif
-         )
-       passed_type = build_pointer_type (passed_type);
-
-      entry_parm = FUNCTION_ARG (args_so_far,
-                                TYPE_MODE (passed_type),
-                                passed_type,
-                                named);
-      if (entry_parm != 0)
-       need_use[need_use_count++] = entry_parm;
-
-      locate_and_pad_parm (TYPE_MODE (passed_type), passed_type,
-#ifdef STACK_PARMS_IN_REG_PARM_AREA
-                          1,
-#else
-                          entry_parm != 0,
-#endif
-                          thunk_fndecl,
-                          &stack_args_size, &stack_offset, &arg_size);
-
-/*    REGNO (entry_parm);*/
-      if (this_rtx == 0)
-       {
-         this_reg_rtx = entry_parm;
-         if (!entry_parm)
-           {
-             rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
-
-             rtx internal_arg_pointer, stack_parm;
-
-             if ((ARG_POINTER_REGNUM == STACK_POINTER_REGNUM
-                  || ! (fixed_regs[ARG_POINTER_REGNUM]
-                        || ARG_POINTER_REGNUM == FRAME_POINTER_REGNUM)))
-               internal_arg_pointer = copy_to_reg (virtual_incoming_args_rtx);
-             else
-               internal_arg_pointer = virtual_incoming_args_rtx;
-
-             if (offset_rtx == const0_rtx)
-               entry_parm = gen_rtx (MEM, TYPE_MODE (passed_type),
-                                     internal_arg_pointer);
-             else
-               entry_parm = gen_rtx (MEM, TYPE_MODE (passed_type),
-                                     gen_rtx (PLUS, Pmode,
-                                              internal_arg_pointer, 
-                                              offset_rtx));
-           }
-         
-         this_rtx = entry_parm;
-       }
-
-      FUNCTION_ARG_ADVANCE (args_so_far,
-                           TYPE_MODE (passed_type),
-                           passed_type,
-                           named);
-    }
-
-  fixed_this_rtx = plus_constant (this_rtx, delta);
-  if (this_rtx != fixed_this_rtx)
-    emit_move_insn (this_rtx, fixed_this_rtx);
-
-  if (this_reg_rtx)
-    emit_insn (gen_rtx (USE, VOIDmode, this_reg_rtx));
-
-  emit_indirect_jump (XEXP (DECL_RTL (function), 0));
-
-  while (need_use_count > 0)
-    emit_insn (gen_rtx (USE, VOIDmode, need_use[--need_use_count]));
-
-  expand_end_bindings (NULL, 1, 0);
-  poplevel (0, 0, 1);
-
-  /* From now on, allocate rtl in current_obstack, not in saveable_obstack.
-     Note that that may have been done above, in save_for_inline_copying.
-     The call to resume_temporary_allocation near the end of this function
-     goes back to the usual state of affairs.  */
-
-  rtl_in_current_obstack ();
-
-  insns = get_insns ();
-
-  /* Copy any shared structure that should not be shared.  */
-
-  unshare_all_rtl (insns);
-
-  /* Instantiate all virtual registers.  */
-
-  instantiate_virtual_regs (current_function_decl, get_insns ());
-
-  /* We are no longer anticipating cse in this function, at least.  */
-
-  cse_not_expected = 1;
-
-  /* Now we choose between stupid (pcc-like) register allocation
-     (if we got the -noreg switch and not -opt)
-     and smart register allocation.  */
-
-  if (optimize > 0)                    /* Stupid allocation probably won't work */
-    obey_regdecls = 0;         /* if optimizations being done.  */
-
-  regclass_init ();
 
-  regclass (insns, max_reg_num ());
-  if (obey_regdecls)
-    {
-      stupid_life_analysis (insns, max_reg_num (), NULL);
-      failure = reload (insns, 0, NULL);
-    }
-  else
-    {
-      /* Do control and data flow analysis,
-        and write some of the results to dump file.  */
-
-      flow_analysis (insns, max_reg_num (), NULL);
-      local_alloc ();
-      failure = global_alloc (NULL);
-    }
-
-  reload_completed = 1;
-
-#ifdef LEAF_REGISTERS
-  leaf_function = 0;
-  if (optimize > 0 && only_leaf_regs_used () && leaf_function_p ())
-    leaf_function = 1;
-#endif
-
-  /* If a machine dependent reorganization is needed, call it.  */
-#ifdef MACHINE_DEPENDENT_REORG
-   MACHINE_DEPENDENT_REORG (insns);
-#endif
-
-  /* Now turn the rtl into assembler code.  */
-
-    {
-      char *fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
-      assemble_start_function (thunk_fndecl, fnname);
-      final (insns, asm_out_file, optimize, 0);
-      assemble_end_function (thunk_fndecl, fnname);
-    };
-
- exit_rest_of_compilation:
-
-  reload_completed = 0;
+  TREE_SET_CODE (thunk_fndecl, FUNCTION_DECL);
 
-  /* Cancel the effect of rtl_in_current_obstack.  */
-
-  resume_temporary_allocation ();
+  {
+#ifdef ASM_OUTPUT_MI_THUNK
+    char *fnname;
+    current_function_decl = thunk_fndecl;
+    /* Make sure we build up its RTL before we go onto the
+       temporary obstack.  */
+    make_function_rtl (thunk_fndecl);
+    temporary_allocation ();
+    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);
+    current_function_is_thunk = 1;
+    assemble_start_function (thunk_fndecl, fnname);
+    ASM_OUTPUT_MI_THUNK (asm_out_file, thunk_fndecl, delta, function);
+    assemble_end_function (thunk_fndecl, fnname);
+    permanent_allocation (1);
+    current_function_decl = 0;
+#else /* 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;
+    DECL_LANG_SPECIFIC (thunk_fndecl) = DECL_LANG_SPECIFIC (function);
+    copy_lang_decl (thunk_fndecl);
+    DECL_INTERFACE_KNOWN (thunk_fndecl) = 1;
+    DECL_NOT_REALLY_EXTERN (thunk_fndecl) = 1;
+
+    start_function (NULL_TREE, thunk_fndecl, NULL_TREE, 1);
+    store_parm_decls ();
+    current_function_is_thunk = 1;
+
+    /* Build up the call to the real function.  */
+    t = build_int_2 (delta, -1 * (delta < 0));
+    TREE_TYPE (t) = signed_type (sizetype);
+    t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
+    t = expr_tree_cons (NULL_TREE, t, NULL_TREE);
+    for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
+      t = expr_tree_cons (NULL_TREE, a, t);
+    t = nreverse (t);
+    t = build_call (function, TREE_TYPE (TREE_TYPE (function)), t);
+    c_expand_return (t);
+
+    finish_function (lineno, 0, 0);
+
+    /* Don't let the backend defer this function.  */
+    if (DECL_DEFER_OUTPUT (thunk_fndecl))
+      {
+       output_inline_function (thunk_fndecl);
+       permanent_allocation (1);
+      }
+#endif /* ASM_OUTPUT_MI_THUNK */
+  }
 
-  decl_printable_name = save_decl_printable_name;
-  current_function_decl = 0;
+  TREE_SET_CODE (thunk_fndecl, THUNK_DECL);
 }
 \f
 /* Code for synthesizing methods which have default semantics defined.  */
 
 /* For the anonymous union in TYPE, return the member that is at least as
    large as the rest of the members, so we can copy it.  */
+
 static tree
 largest_union_member (type)
      tree type;
@@ -2112,7 +2128,8 @@ largest_union_member (type)
 }
 
 /* Generate code for default X(X&) constructor.  */
-void
+
+static void
 do_build_copy_constructor (fndecl)
      tree fndecl;
 {
@@ -2126,9 +2143,13 @@ do_build_copy_constructor (fndecl)
     parm = TREE_CHAIN (parm);
   parm = convert_from_reference (parm);
 
-  if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type))
+  if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)
+      && is_empty_class (current_class_type))
+    /* Don't copy the padding byte; it might not have been allocated
+       if *this is a base subobject.  */;
+  else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type))
     {
-      t = build (INIT_EXPR, void_type_node, C_C_D, parm);
+      t = build (INIT_EXPR, void_type_node, current_class_ref, parm);
       TREE_SIDE_EFFECTS (t) = 1;
       cplus_expand_expr_stmt (t);
     }
@@ -2147,8 +2168,12 @@ do_build_copy_constructor (fndecl)
            (build_reference_type (basetype), parm,
             CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
          p = convert_from_reference (p);
-         current_base_init_list = tree_cons (basetype,
-                                             p, current_base_init_list);
+
+         if (p == error_mark_node)
+           cp_error ("in default copy constructor");
+         else 
+           current_base_init_list = tree_cons (basetype,
+                                               p, current_base_init_list);
        }
        
       for (i = 0; i < n_bases; ++i)
@@ -2161,17 +2186,25 @@ do_build_copy_constructor (fndecl)
          p = convert_to_reference
            (build_reference_type (basetype), parm,
             CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
-         p = convert_from_reference (p);
-         current_base_init_list = tree_cons (basetype,
-                                             p, current_base_init_list);
+
+         if (p == error_mark_node) 
+           cp_error ("in default copy constructor");
+         else 
+           {
+             p = convert_from_reference (p);
+             current_base_init_list = tree_cons (basetype,
+                                                 p, current_base_init_list);
+           }
        }
       for (; fields; fields = TREE_CHAIN (fields))
        {
-         tree name, init, t;
+         tree init, t;
          tree field = fields;
 
          if (TREE_CODE (field) != FIELD_DECL)
            continue;
+
+         init = parm;
          if (DECL_NAME (field))
            {
              if (VFIELD_NAME_P (DECL_NAME (field)))
@@ -2184,14 +2217,22 @@ do_build_copy_constructor (fndecl)
                continue;
            }
          else if ((t = TREE_TYPE (field)) != NULL_TREE
-                  && TREE_CODE (t) == UNION_TYPE
-                  && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+                  && ANON_UNION_TYPE_P (t)
                   && TYPE_FIELDS (t) != NULL_TREE)
-           field = largest_union_member (t);
+           {
+             do
+               {
+                 init = build (COMPONENT_REF, t, init, field);
+                 field = largest_union_member (t);
+               }
+             while ((t = TREE_TYPE (field)) != NULL_TREE
+                    && ANON_UNION_TYPE_P (t)
+                    && TYPE_FIELDS (t) != NULL_TREE);
+           }
          else
            continue;
 
-         init = build (COMPONENT_REF, TREE_TYPE (field), parm, field);
+         init = build (COMPONENT_REF, TREE_TYPE (field), init, field);
          init = build_tree_list (NULL_TREE, init);
 
          current_member_init_list
@@ -2205,7 +2246,7 @@ do_build_copy_constructor (fndecl)
   pop_momentary ();
 }
 
-void
+static void
 do_build_assign_ref (fndecl)
      tree fndecl;
 {
@@ -2216,9 +2257,13 @@ do_build_assign_ref (fndecl)
 
   parm = convert_from_reference (parm);
 
-  if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type))
+  if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)
+      && is_empty_class (current_class_type))
+    /* Don't copy the padding byte; it might not have been allocated
+       if *this is a base subobject.  */;
+  else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type))
     {
-      tree t = build (MODIFY_EXPR, void_type_node, C_C_D, parm);
+      tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm);
       TREE_SIDE_EFFECTS (t) = 1;
       cplus_expand_expr_stmt (t);
     }
@@ -2232,16 +2277,13 @@ do_build_assign_ref (fndecl)
       for (i = 0; i < n_bases; ++i)
        {
          tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
-         if (TYPE_HAS_ASSIGN_REF (basetype))
-           {
-             tree p = convert_to_reference
-               (build_reference_type (basetype), parm,
-                CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
-             p = convert_from_reference (p);
-             p = build_member_call (basetype, ansi_opname [MODIFY_EXPR],
-                                    build_tree_list (NULL_TREE, p));
-             expand_expr_stmt (p);
-           }
+         tree p = convert_to_reference
+           (build_reference_type (basetype), parm,
+            CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
+         p = convert_from_reference (p);
+         p = build_member_call (basetype, ansi_opname [MODIFY_EXPR],
+                                build_expr_list (NULL_TREE, p));
+         expand_expr_stmt (p);
        }
       for (; fields; fields = TREE_CHAIN (fields))
        {
@@ -2250,6 +2292,27 @@ do_build_assign_ref (fndecl)
 
          if (TREE_CODE (field) != FIELD_DECL)
            continue;
+
+         if (TREE_READONLY (field))
+           {
+             if (DECL_NAME (field))
+               cp_error ("non-static const member `%#D', can't use default assignment operator", field);
+             else
+               cp_error ("non-static const member in type `%T', can't use default assignment operator", current_class_type);
+             continue;
+           }
+         else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
+           {
+             if (DECL_NAME (field))
+               cp_error ("non-static reference member `%#D', can't use default assignment operator", field);
+             else
+               cp_error ("non-static reference member in type `%T', can't use default assignment operator", current_class_type);
+             continue;
+           }
+
+         comp = current_class_ref;
+         init = parm;
+
          if (DECL_NAME (field))
            {
              if (VFIELD_NAME_P (DECL_NAME (field)))
@@ -2262,20 +2325,29 @@ do_build_assign_ref (fndecl)
                continue;
            }
          else if ((t = TREE_TYPE (field)) != NULL_TREE
-                  && TREE_CODE (t) == UNION_TYPE
-                  && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+                  && ANON_UNION_TYPE_P (t)
                   && TYPE_FIELDS (t) != NULL_TREE)
-           field = largest_union_member (t);
+           {
+             do
+               {
+                 comp = build (COMPONENT_REF, t, comp, field);
+                 init = build (COMPONENT_REF, t, init, field);
+                 field = largest_union_member (t);
+               }
+             while ((t = TREE_TYPE (field)) != NULL_TREE
+                    && ANON_UNION_TYPE_P (t)
+                    && TYPE_FIELDS (t) != NULL_TREE);
+           }
          else
            continue;
 
-         comp = build (COMPONENT_REF, TREE_TYPE (field), C_C_D, field);
-         init = build (COMPONENT_REF, TREE_TYPE (field), parm, field);
+         comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field);
+         init = build (COMPONENT_REF, TREE_TYPE (field), init, field);
 
          expand_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
        }
     }
-  c_expand_return (C_C_D);
+  c_expand_return (current_class_ref);
   pop_momentary ();
 }
 
@@ -2285,13 +2357,17 @@ synthesize_method (fndecl)
 {
   int nested = (current_function_decl != NULL_TREE);
   tree context = hack_decl_function_context (fndecl);
-  tree base = DECL_CLASS_CONTEXT (fndecl);
 
-  if (nested)
+  if (at_eof)
+    import_export_decl (fndecl);
+
+  if (! context)
+    push_to_top_level ();
+  else if (nested)
     push_cp_function_context (context);
 
   interface_unknown = 1;
-  start_function (NULL_TREE, fndecl, NULL_TREE, NULL_TREE, 1);
+  start_function (NULL_TREE, fndecl, NULL_TREE, 1);
   store_parm_decls ();
 
   if (DECL_NAME (fndecl) == ansi_opname[MODIFY_EXPR])
@@ -2311,17 +2387,9 @@ synthesize_method (fndecl)
 
   finish_function (lineno, 0, nested);
 
-  /* Do we really *want* to inline this function?  */
-  if (DECL_INLINE (fndecl))
-    {
-      /* Turn off DECL_INLINE for the moment so function_cannot_inline_p
-         will check our size.  */
-      DECL_INLINE (fndecl) = 0;
-      if (function_cannot_inline_p (fndecl) == 0)
-       DECL_INLINE (fndecl) = 1;
-    }
-
   extract_interface_info ();
-  if (nested)
+  if (! context)
+    pop_from_top_level ();
+  else if (nested)
     pop_cp_function_context (context);
 }