OSDN Git Service

* g++.old-deja/g++.benjamin/16077.C: Adjust warnings.
[pf3gnuchains/gcc-fork.git] / gcc / cp / mangle.c
index 594e25c..06d8f96 100644 (file)
@@ -1,21 +1,21 @@
-/* Name mangling for the new standard C++ ABI.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+/* Name mangling for the 3.0 C++ ABI.
+   Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Written by Alex Samuel <sameul@codesourcery.com>
 
-   This file is part of GNU CC.
+   This file is part of GCC.
 
-   GNU CC is free software; you can redistribute it and/or modify it
+   GCC is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
-   GNU CC is distributed in the hope that it will be useful, but
+   GCC is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GNU CC; see the file COPYING.  If not, write to the Free
+   along with GCC; see the file COPYING.  If not, write to the Free
    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA.  */
 
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "cp-tree.h"
+#include "real.h"
 #include "obstack.h"
 #include "toplev.h"
 #include "varray.h"
 /* Macros for tracing the write_* functions.  */
 #if DEBUG_MANGLE
 # define MANGLE_TRACE(FN, INPUT) \
-  fprintf (stderr, "  %-24s: %-24s\n", FN, INPUT)
+  fprintf (stderr, "  %-24s: %-24s\n", (FN), (INPUT))
 # define MANGLE_TRACE_TREE(FN, NODE) \
   fprintf (stderr, "  %-24s: %-24s (%p)\n", \
-           FN, tree_code_name[TREE_CODE (NODE)], (void *) NODE)
+           (FN), tree_code_name[TREE_CODE (NODE)], (void *) (NODE))
 #else
 # define MANGLE_TRACE(FN, INPUT)
 # define MANGLE_TRACE_TREE(FN, NODE)
 #endif
 
-/* Non-zero if NODE is a template-id.  */
-#define DECL_TEMPLATE_ID_P(NODE)                               \
-  (DECL_LANG_SPECIFIC (NODE) != NULL                           \
-   && DECL_USE_TEMPLATE (NODE)                                 \
-   && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (NODE)))
-
-/* Non-zero if NODE is a class template-id.  */
-#define CLASSTYPE_TEMPLATE_ID_P(NODE)                          \
-  (TYPE_LANG_SPECIFIC (NODE) != NULL                           \
-   && CLASSTYPE_USE_TEMPLATE (NODE)                            \
-   && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE)))
+/* Nonzero if NODE is a class template-id.  We can't rely on
+   CLASSTYPE_USE_TEMPLATE here because of tricky bugs in the parser
+   that hard to distinguish A<T> from A, where A<T> is the type as
+   instantiated outside of the template, and A is the type used
+   without parameters inside the template.  */
+#define CLASSTYPE_TEMPLATE_ID_P(NODE)                                  \
+  (TYPE_LANG_SPECIFIC (NODE) != NULL                                   \
+   && (TREE_CODE (NODE) == BOUND_TEMPLATE_TEMPLATE_PARM                        \
+       || (CLASSTYPE_TEMPLATE_INFO (NODE) != NULL                      \
+          && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))
 
 /* Things we only need one of.  This module is not reentrant.  */
 static struct globals
@@ -92,12 +94,21 @@ static struct globals
   /* The name in which we're building the mangled name.  */
   struct obstack name_obstack;
 
-  /* The current innermost template args.  */
-  tree template_args;
-
   /* An array of the current substitution candidates, in the order
      we've seen them.  */
   varray_type substitutions;
+
+  /* The entity that is being mangled.  */
+  tree entity;
+
+  /* We are mangling an internal symbol. It is important to keep those
+     involving template parmeters distinct by distinguishing their level
+     and, for non-type parms, their type.  */
+  bool internal_mangling_p;
+
+  /* True if the mangling will be different in a future version of the
+     ABI.  */
+  bool need_abi_warning;
 } G;
 
 /* Indices into subst_identifiers.  These are identifiers used in
@@ -120,7 +131,7 @@ static tree subst_identifiers[SUBID_MAX];
 
 /* Single-letter codes for builtin integer types, defined in
    <builtin-type>.  These are indexed by integer_type_kind values.  */
-static char
+static const char
 integer_type_codes[itk_none] =
 {
   'c',  /* itk_char */
@@ -136,6 +147,8 @@ integer_type_codes[itk_none] =
   'y'   /* itk_unsigned_long_long */
 };
 
+static int decl_is_template_id PARAMS ((tree, tree*));
+
 /* Functions for handling substitutions.  */
 
 static inline tree canonicalize_for_substitution PARAMS ((tree));
@@ -143,32 +156,34 @@ static void add_substitution PARAMS ((tree));
 static inline int is_std_substitution PARAMS ((tree, substitution_identifier_index_t));
 static inline int is_std_substitution_char PARAMS ((tree, substitution_identifier_index_t));
 static int find_substitution PARAMS ((tree));
+static void mangle_call_offset PARAMS ((tree, tree));
 
 /* Functions for emitting mangled representations of things.  */
 
 static void write_mangled_name PARAMS ((tree));
 static void write_encoding PARAMS ((tree));
-static void write_name PARAMS ((tree));
+static void write_name PARAMS ((tree, int));
 static void write_unscoped_name PARAMS ((tree));
 static void write_unscoped_template_name PARAMS ((tree));
 static void write_nested_name PARAMS ((tree));
 static void write_prefix PARAMS ((tree));
 static void write_template_prefix PARAMS ((tree));
-static void write_component PARAMS ((tree));
 static void write_unqualified_name PARAMS ((tree));
+static void write_conversion_operator_name (tree);
 static void write_source_name PARAMS ((tree));
+static int hwint_to_ascii PARAMS ((unsigned HOST_WIDE_INT, unsigned int, char *, unsigned));
 static void write_number PARAMS ((unsigned HOST_WIDE_INT, int,
                                  unsigned int));
 static void write_integer_cst PARAMS ((tree));
-static void write_identifier PARAMS ((char *));
+static void write_identifier PARAMS ((const char *));
 static void write_special_name_constructor PARAMS ((tree));
 static void write_special_name_destructor PARAMS ((tree));
 static void write_type PARAMS ((tree));
 static int write_CV_qualifiers_for_type PARAMS ((tree));
 static void write_builtin_type PARAMS ((tree));
-static void write_function_type PARAMS ((tree, int));
-static void write_bare_function_type PARAMS ((tree, int));
-static void write_method_parms PARAMS ((tree, int));
+static void write_function_type PARAMS ((tree));
+static void write_bare_function_type PARAMS ((tree, int, tree));
+static void write_method_parms PARAMS ((tree, int, tree));
 static void write_class_enum_type PARAMS ((tree));
 static void write_template_args PARAMS ((tree));
 static void write_expression PARAMS ((tree));
@@ -183,32 +198,35 @@ static void write_substitution PARAMS ((int));
 static int discriminator_for_local_entity PARAMS ((tree));
 static int discriminator_for_string_literal PARAMS ((tree, tree));
 static void write_discriminator PARAMS ((int));
-static void write_local_name PARAMS ((tree, tree));
+static void write_local_name PARAMS ((tree, tree, tree));
 static void dump_substitution_candidates PARAMS ((void));
 static const char *mangle_decl_string PARAMS ((tree));
 
 /* Control functions.  */
 
-static inline void start_mangling PARAMS ((void));
-static inline const char *finish_mangling PARAMS ((void));
+static inline void start_mangling (tree);
+static inline const char *finish_mangling (bool);
 static tree mangle_special_for_type PARAMS ((tree, const char *));
 
+/* Foreign language functions.  */
+
+static void write_java_integer_type_codes PARAMS ((tree));
+
 /* Append a single character to the end of the mangled
    representation.  */
 #define write_char(CHAR)                                              \
   obstack_1grow (&G.name_obstack, (CHAR))
 
+/* Append a sized buffer to the end of the mangled representation.  */
+#define write_chars(CHAR, LEN)                                        \
+  obstack_grow (&G.name_obstack, (CHAR), (LEN))
+
 /* Append a NUL-terminated string to the end of the mangled
    representation.  */
 #define write_string(STRING)                                          \
   obstack_grow (&G.name_obstack, (STRING), strlen (STRING))
 
-/* Return the position at which the next character will be appended to
-   the mangled representation.  */
-#define mangled_position()                                              \
-  obstack_object_size (&G.name_obstack)
-
-/* Non-zero if NODE1 and NODE2 are both TREE_LIST nodes and have the
+/* Nonzero if NODE1 and NODE2 are both TREE_LIST nodes and have the
    same purpose (context, which may be a type) and value (template
    decl).  See write_template_prefix for more information on what this
    is used for.  */
@@ -220,13 +238,53 @@ static tree mangle_special_for_type PARAMS ((tree, const char *));
        || TREE_PURPOSE (NODE1) == TREE_PURPOSE (NODE2))             \
    && TREE_VALUE (NODE1) == TREE_VALUE (NODE2))
 
-/* Write out a signed quantity in base 10.  */
-#define write_signed_number(NUMBER) \
-  write_number (NUMBER, /*unsigned_p=*/0, 10)
-
 /* Write out an unsigned quantity in base 10.  */
 #define write_unsigned_number(NUMBER) \
-  write_number (NUMBER, /*unsigned_p=*/1, 10)
+  write_number ((NUMBER), /*unsigned_p=*/1, 10)
+
+/* If DECL is a template instance, return nonzero and, if
+   TEMPLATE_INFO is non-NULL, set *TEMPLATE_INFO to its template info.
+   Otherwise return zero.  */
+
+static int
+decl_is_template_id (decl, template_info)
+     tree decl;
+     tree* template_info;
+{
+  if (TREE_CODE (decl) == TYPE_DECL)
+    {
+      /* TYPE_DECLs are handled specially.  Look at its type to decide
+        if this is a template instantiation.  */
+      tree type = TREE_TYPE (decl);
+
+      if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_ID_P (type))
+       {
+         if (template_info != NULL)
+           /* For a templated TYPE_DECL, the template info is hanging
+              off the type.  */
+           *template_info = TYPE_TEMPLATE_INFO (type);
+         return 1;
+       }
+    } 
+  else
+    {
+      /* Check if this is a primary template.  */
+      if (DECL_LANG_SPECIFIC (decl) != NULL
+         && DECL_USE_TEMPLATE (decl)
+         && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl))
+         && TREE_CODE (decl) != TEMPLATE_DECL)
+       {
+         if (template_info != NULL)
+           /* For most templated decls, the template info is hanging
+              off the decl.  */
+           *template_info = DECL_TEMPLATE_INFO (decl);
+         return 1;
+       }
+    }
+
+  /* It's not a template id.  */
+  return 0;
+}
 
 /* Produce debugging output of current substitution candidates.  */
 
@@ -274,6 +332,8 @@ canonicalize_for_substitution (node)
   /* For a TYPE_DECL, use the type instead.  */
   if (TREE_CODE (node) == TYPE_DECL)
     node = TREE_TYPE (node);
+  if (TYPE_P (node))
+    node = canonical_type_variant (node);
 
   return node;
 }
@@ -310,7 +370,7 @@ add_substitution (node)
            || (TYPE_P (node) 
                && TYPE_P (candidate) 
                && same_type_p (node, candidate)))
-         my_friendly_abort (20000524);
+         abort ();
       }
   }
 #endif /* ENABLE_CHECKING */
@@ -322,7 +382,7 @@ add_substitution (node)
     dump_substitution_candidates ();
 }
 
-/* Helper function for find_substitution.  Returns non-zero if NODE,
+/* Helper function for find_substitution.  Returns nonzero if NODE,
    which may be a decl or a CLASS_TYPE, is a template-id with template
    name of substitution_index[INDEX] in the ::std namespace.  */
 
@@ -350,12 +410,12 @@ is_std_substitution (node, index)
 
   return (DECL_NAMESPACE_STD_P (CP_DECL_CONTEXT (decl))
          && TYPE_LANG_SPECIFIC (type) 
-         && CLASSTYPE_TEMPLATE_INFO (type)
-         && (DECL_NAME (CLASSTYPE_TI_TEMPLATE (type)) 
+         && TYPE_TEMPLATE_INFO (type)
+         && (DECL_NAME (TYPE_TI_TEMPLATE (type)) 
              == subst_identifiers[index]));
 }
 
-/* Helper function for find_substitution.  Returns non-zero if NODE,
+/* Helper function for find_substitution.  Returns nonzero if NODE,
    which may be a decl or a CLASS_TYPE, is the template-id
    ::std::identifier<char>, where identifier is
    substitution_index[INDEX].  */
@@ -415,7 +475,7 @@ is_std_substitution_char (node, index)
    candidates for entities appearing earlier in the same mangling
 
    If a substitution is found, write its mangled representation and
-   return non-zero.  If none is found, just return zero.  */
+   return nonzero.  If none is found, just return zero.  */
 
 static int
 find_substitution (node)
@@ -458,7 +518,7 @@ find_substitution (node)
                 std::basic_string <char,
                                    std::char_traits<char>,
                                    std::allocator<char> > .  */
-         if (CP_TYPE_QUALS (type) == TYPE_UNQUALIFIED
+         if (cp_type_quals (type) == TYPE_UNQUALIFIED
              && CLASSTYPE_USE_TEMPLATE (type))
            {
              tree args = CLASSTYPE_TI_ARGS (type);
@@ -484,7 +544,7 @@ find_substitution (node)
 
   /* Check for basic_{i,o,io}stream.  */
   if (TYPE_P (node)
-      && CP_TYPE_QUALS (type) == TYPE_UNQUALIFIED
+      && cp_type_quals (type) == TYPE_UNQUALIFIED
       && CLASS_TYPE_P (type)
       && CLASSTYPE_USE_TEMPLATE (type)
       && CLASSTYPE_TEMPLATE_INFO (type) != NULL)
@@ -527,7 +587,7 @@ find_substitution (node)
     }
 
   /* Now check the list of available substitutions for this mangling
-     operation.    */
+     operation.  */
   for (i = 0; i < size; ++i)
     {
       tree candidate = VARRAY_TREE (G.substitutions, i);
@@ -556,10 +616,14 @@ write_mangled_name (decl)
 {
   MANGLE_TRACE_TREE ("mangled-name", decl);
 
-  if (DECL_LANG_SPECIFIC (decl) && DECL_EXTERN_C_FUNCTION_P (decl))
+  if (DECL_LANG_SPECIFIC (decl)
+      && DECL_EXTERN_C_FUNCTION_P (decl)
+      && ! DECL_OVERLOADED_OPERATOR_P (decl))
     /* The standard notes:
          "The <encoding> of an extern "C" function is treated like
-        global-scope data, i.e. as its <source-name> without a type."  */
+        global-scope data, i.e. as its <source-name> without a type."
+       We cannot write overloaded operators that way though,
+       because it contains characters invalid in assembler.  */
     write_source_name (DECL_NAME (decl));
   else
     /* C++ name; needs to be mangled.  */
@@ -580,68 +644,124 @@ write_encoding (decl)
 
   if (DECL_LANG_SPECIFIC (decl) && DECL_EXTERN_C_FUNCTION_P (decl))
     {
-      write_source_name (DECL_NAME (decl));
+      /* For overloaded operators write just the mangled name
+        without arguments.  */
+      if (DECL_OVERLOADED_OPERATOR_P (decl))
+       write_name (decl, /*ignore_local_scope=*/0);
+      else
+       write_source_name (DECL_NAME (decl));
       return;
     }
 
-  write_name (decl);
+  write_name (decl, /*ignore_local_scope=*/0);
   if (TREE_CODE (decl) == FUNCTION_DECL)
     {
       tree fn_type;
 
-      if (DECL_TEMPLATE_ID_P (decl))
-       fn_type = get_mostly_instantiated_function_type (decl, NULL, NULL);
+      if (decl_is_template_id (decl, NULL))
+       fn_type = get_mostly_instantiated_function_type (decl);
       else
        fn_type = TREE_TYPE (decl);
 
-      write_bare_function_type (fn_type, DECL_TEMPLATE_ID_P (decl));
+      write_bare_function_type (fn_type, 
+                               (!DECL_CONSTRUCTOR_P (decl)
+                                && !DECL_DESTRUCTOR_P (decl)
+                                && !DECL_CONV_FN_P (decl)
+                                && decl_is_template_id (decl, NULL)),
+                               decl);
     }
 }
 
 /* <name> ::= <unscoped-name>
           ::= <unscoped-template-name> <template-args>
          ::= <nested-name>
-         ::= <local-name>  */
+         ::= <local-name>  
+
+   If IGNORE_LOCAL_SCOPE is nonzero, this production of <name> is
+   called from <local-name>, which mangles the enclosing scope
+   elsewhere and then uses this function to mangle just the part
+   underneath the function scope.  So don't use the <local-name>
+   production, to avoid an infinite recursion.  */
 
 static void
-write_name (decl)
+write_name (decl, ignore_local_scope)
      tree decl;
+     int ignore_local_scope;
 {
   tree context;
 
-  context = CP_DECL_CONTEXT (decl);
-
   MANGLE_TRACE_TREE ("name", decl);
 
-  /* Decls in :: or ::std scope are treated specially.  */
-  if (context == global_namespace || DECL_NAMESPACE_STD_P (context))
+  if (TREE_CODE (decl) == TYPE_DECL)
     {
-      if (decl && DECL_TEMPLATE_ID_P (decl))
-       {
-         /* Templated decls get an <unqualified-template-name>.  */
-         write_unscoped_template_name (DECL_TI_TEMPLATE (decl));
-         write_template_args (DECL_TI_ARGS (decl));
-       }
-      else if (TREE_CODE (decl) == TYPE_DECL 
-              && CLASSTYPE_TEMPLATE_ID_P (TREE_TYPE (decl)))
+      /* In case this is a typedef, fish out the corresponding
+        TYPE_DECL for the main variant.  */
+      decl = TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+      context = TYPE_CONTEXT (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+    }
+  else
+    context = (DECL_CONTEXT (decl) == NULL) ? NULL : CP_DECL_CONTEXT (decl);
+
+  /* A decl in :: or ::std scope is treated specially.  The former is
+     mangled using <unscoped-name> or <unscoped-template-name>, the
+     latter with a special substitution.  Also, a name that is
+     directly in a local function scope is also mangled with
+     <unscoped-name> rather than a full <nested-name>.  */
+  if (context == NULL 
+      || context == global_namespace 
+      || DECL_NAMESPACE_STD_P (context)
+      || (ignore_local_scope && TREE_CODE (context) == FUNCTION_DECL))
+    {
+      tree template_info;
+      /* Is this a template instance?  */
+      if (decl_is_template_id (decl, &template_info))
        {
-         tree type;
-
-         /* Templated decls get an <unqualified-template-name>.  */
-         type = TREE_TYPE (decl);
-         write_unscoped_template_name (TYPE_TI_TEMPLATE (type));
-         write_template_args (TYPE_TI_ARGS (type));
+         /* Yes: use <unscoped-template-name>.  */
+         write_unscoped_template_name (TI_TEMPLATE (template_info));
+         write_template_args (TI_ARGS (template_info));
        }
       else
        /* Everything else gets an <unqualified-name>.  */
        write_unscoped_name (decl);
     }
-  /* Handle local names.  */
-  else if (TREE_CODE (context) == FUNCTION_DECL)
-    write_local_name (context, decl);
-  /* Other decls get a <nested-name> to encode their scope.  */
   else
-    write_nested_name (decl);
+    {
+      /* Handle local names, unless we asked not to (that is, invoked
+         under <local-name>, to handle only the part of the name under
+         the local scope).  */
+      if (!ignore_local_scope)
+        {
+         /* Scan up the list of scope context, looking for a
+            function.  If we find one, this entity is in local
+            function scope.  local_entity tracks context one scope
+            level down, so it will contain the element that's
+            directly in that function's scope, either decl or one of
+            its enclosing scopes.  */
+         tree local_entity = decl;
+         while (context != NULL && context != global_namespace)
+           {
+             /* Make sure we're always dealing with decls.  */
+             if (context != NULL && TYPE_P (context))
+               context = TYPE_NAME (context);
+             /* Is this a function?  */
+             if (TREE_CODE (context) == FUNCTION_DECL)
+               {
+                 /* Yes, we have local scope.  Use the <local-name>
+                    production for the innermost function scope.  */
+                 write_local_name (context, local_entity, decl);
+                 return;
+               }
+             /* Up one scope level.  */
+             local_entity = context;
+             context = CP_DECL_CONTEXT (context);
+           }
+
+         /* No local scope found?  Fall through to <nested-name>.  */
+       }
+
+      /* Other decls get a <nested-name> to encode their scope.  */
+      write_nested_name (decl);
+    }
 }
 
 /* <unscoped-name> ::= <unqualified-name>
@@ -661,11 +781,14 @@ write_unscoped_name (decl)
       write_string ("St");
       write_unqualified_name (decl);
     }
-  /* If not, it should be in the global namespace.  */
-  else if (context == global_namespace || context == NULL)
+  /* If not, it should be either in the global namespace, or directly
+     in a local function scope.  */
+  else if (context == global_namespace 
+          || context == NULL
+          || TREE_CODE (context) == FUNCTION_DECL)
     write_unqualified_name (decl);
   else 
-    my_friendly_abort (20000521);
+    abort ();
 }
 
 /* <unscoped-template-name> ::= <unscoped-name>
@@ -685,7 +808,7 @@ write_unscoped_template_name (decl)
 
 /* Write the nested name, including CV-qualifiers, of DECL.
 
-   <nested-name> ::= N [<CV-qualifiers>] <prefix> <component> E  
+   <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E  
                  ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
 
    <CV-qualifiers> ::= [r] [V] [K]  */
@@ -694,6 +817,8 @@ static void
 write_nested_name (decl)
      tree decl;
 {
+  tree template_info;
+
   MANGLE_TRACE_TREE ("nested-name", decl);
 
   write_char ('N');
@@ -708,25 +833,24 @@ write_nested_name (decl)
        write_char ('K');
     }
 
-  if (DECL_TEMPLATE_ID_P (decl))
-    {
-      write_template_prefix (decl);
-      write_template_args (DECL_TI_ARGS (decl));
-    }
-  else if (CLASSTYPE_TEMPLATE_ID_P (TREE_TYPE (decl)))
+  /* Is this a template instance?  */
+  if (decl_is_template_id (decl, &template_info))
     {
+      /* Yes, use <template-prefix>.  */
       write_template_prefix (decl);
-      write_template_args (CLASSTYPE_TI_ARGS (TREE_TYPE (decl)));
+      write_template_args (TI_ARGS (template_info));
     }
   else
     {
+      /* No, just use <prefix>  */
       write_prefix (DECL_CONTEXT (decl));
-      write_component (decl);
+      write_unqualified_name (decl);
     }
   write_char ('E');
 }
 
-/* <prefix> ::= <prefix> <component>
+/* <prefix> ::= <prefix> <unqualified-name>
+            ::= <template-param>
             ::= <template-prefix> <template-args>
            ::= # empty
            ::= <substitution>  */
@@ -736,47 +860,65 @@ write_prefix (node)
      tree node;
 {
   tree decl;
-  tree type;
-  tree context;
+  /* Non-NULL if NODE represents a template-id.  */
+  tree template_info = NULL;
+
+  MANGLE_TRACE_TREE ("prefix", node);
 
   if (node == NULL
       || node == global_namespace)
     return;
 
-  MANGLE_TRACE_TREE ("prefix", node);
-
-  decl = DECL_P (node) ? node : TYPE_NAME (node);
-  type = DECL_P (node) ? TREE_TYPE (node) : node;
-  context = CP_DECL_CONTEXT (decl);
-
   if (find_substitution (node))
     return;
 
-  /* Check if this is a template-id.  For a template member, the
-     template info will be hanging off the decl.  */
-  if (DECL_TEMPLATE_ID_P (decl))
+  if (DECL_P (node))
     {
-      write_template_prefix (decl);
-      write_template_args (DECL_TI_ARGS (decl));
+      /* If this is a function decl, that means we've hit function
+        scope, so this prefix must be for a local name.  In this
+        case, we're under the <local-name> production, which encodes
+        the enclosing function scope elsewhere.  So don't continue
+        here.  */
+      if (TREE_CODE (node) == FUNCTION_DECL)
+       return;
+
+      decl = node;
+      decl_is_template_id (decl, &template_info);
     }
-  /* For a template class, the template info will be hanging off the
-     type.  */
-  else if (type && CLASSTYPE_TEMPLATE_ID_P (type))
+  else
     {
-      write_template_prefix (type);
-      write_template_args (CLASSTYPE_TI_ARGS (type));
+      /* Node is a type.  */
+      decl = TYPE_NAME (node);
+      if (CLASSTYPE_TEMPLATE_ID_P (node))
+       template_info = TYPE_TEMPLATE_INFO (node);
+    }
+
+  /* In G++ 3.2, the name of the template parameter was used.  */
+  if (TREE_CODE (node) == TEMPLATE_TYPE_PARM 
+      && !abi_version_at_least (2))
+    G.need_abi_warning = true;
+
+  if (TREE_CODE (node) == TEMPLATE_TYPE_PARM
+      && abi_version_at_least (2))
+    write_template_param (node);
+  else if (template_info != NULL)
+    /* Templated.  */
+    {
+      write_template_prefix (decl);
+      write_template_args (TI_ARGS (template_info));
     }
   else
     /* Not templated.  */
     {
-      write_prefix (context);
-      write_component (decl);
+      write_prefix (CP_DECL_CONTEXT (decl));
+      write_unqualified_name (decl);
     }
 
   add_substitution (node);
 }
 
 /* <template-prefix> ::= <prefix> <template component>
+                     ::= <template-param>
                      ::= <substitution>  */
 
 static void
@@ -786,19 +928,20 @@ write_template_prefix (node)
   tree decl = DECL_P (node) ? node : TYPE_NAME (node);
   tree type = DECL_P (node) ? TREE_TYPE (node) : node;
   tree context = CP_DECL_CONTEXT (decl);
+  tree template_info;
   tree template;
   tree substitution;
 
   MANGLE_TRACE_TREE ("template-prefix", node);
 
   /* Find the template decl.  */
-  if (DECL_TEMPLATE_ID_P (decl))
-    template = DECL_TI_TEMPLATE (decl);
+  if (decl_is_template_id (decl, &template_info))
+    template = TI_TEMPLATE (template_info);
   else if (CLASSTYPE_TEMPLATE_ID_P (type))
-    template = CLASSTYPE_TI_TEMPLATE (type);
+    template = TYPE_TI_TEMPLATE (type);
   else
     /* Oops, not a template.  */
-    my_friendly_abort (20000524);
+    abort ();
 
   /* For a member template, though, the template name for the
      innermost name must have all the outer template levels
@@ -830,38 +973,21 @@ write_template_prefix (node)
   if (find_substitution (substitution))
     return;
 
-  write_prefix (context);
-  write_component (decl);
-
-  add_substitution (substitution);
-}
-
-/* <component> ::= <unqualified-name>
-               ::= <local-name> */
+  /* In G++ 3.2, the name of the template template parameter was used.  */
+  if (TREE_CODE (TREE_TYPE (template)) == TEMPLATE_TEMPLATE_PARM
+      && !abi_version_at_least (2))
+    G.need_abi_warning = true;
 
-static void
-write_component (decl)
-     tree decl;
-{
-  MANGLE_TRACE_TREE ("component", decl);
-
-  switch (TREE_CODE (decl))
+  if (TREE_CODE (TREE_TYPE (template)) == TEMPLATE_TEMPLATE_PARM
+      && abi_version_at_least (2))
+    write_template_param (TREE_TYPE (template));
+  else
     {
-    case TEMPLATE_DECL:
-    case NAMESPACE_DECL:
-    case VAR_DECL:
-    case TYPE_DECL:
-    case FUNCTION_DECL:
-    case FIELD_DECL:
-      if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL)
-       write_local_name (CP_DECL_CONTEXT (decl), decl);
-      else
-       write_unqualified_name (decl);
-      break;
-
-    default:
-      my_friendly_abort (2000509);
+      write_prefix (context);
+      write_unqualified_name (decl);
     }
+
+  add_substitution (substitution);
 }
 
 /* We don't need to handle thunks, vtables, or VTTs here.  Those are
@@ -885,8 +1011,15 @@ write_unqualified_name (decl)
     {
       /* Conversion operator. Handle it right here.  
            <operator> ::= cv <type>  */
-      write_string ("cv");
-      write_type (TREE_TYPE (DECL_NAME (decl)));
+      tree type;
+      if (decl_is_template_id (decl, NULL))
+       {
+         tree fn_type = get_mostly_instantiated_function_type (decl);
+         type = TREE_TYPE (fn_type);
+       }
+      else
+       type = TREE_TYPE (DECL_NAME (decl));
+      write_conversion_operator_name (type);
     }
   else if (DECL_OVERLOADED_OPERATOR_P (decl))
     {
@@ -902,6 +1035,15 @@ write_unqualified_name (decl)
     write_source_name (DECL_NAME (decl));
 }
 
+/* Write the unqualified-name for a conversion operator to TYPE.  */
+
+static void
+write_conversion_operator_name (tree type)
+{
+  write_string ("cv");
+  write_type (type);
+}
+
 /* Non-termial <source-name>.  IDENTIFIER is an IDENTIFIER_NODE.  
 
      <source-name> ::= </length/ number> <identifier>  */
@@ -921,6 +1063,38 @@ write_source_name (identifier)
   write_identifier (IDENTIFIER_POINTER (identifier));
 }
 
+/* Convert NUMBER to ascii using base BASE and generating at least
+   MIN_DIGITS characters. BUFFER points to the _end_ of the buffer
+   into which to store the characters. Returns the number of
+   characters generated (these will be layed out in advance of where
+   BUFFER points).  */
+
+static int
+hwint_to_ascii (number, base, buffer, min_digits)
+     unsigned HOST_WIDE_INT number;
+     unsigned int base;
+     char *buffer;
+     unsigned min_digits;
+{
+  static const char base_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  unsigned digits = 0;
+  
+  while (number)
+    {
+      unsigned HOST_WIDE_INT d = number / base;
+      
+      *--buffer = base_digits[number - d * base];
+      digits++;
+      number = d;
+    }
+  while (digits < min_digits)
+    {
+      *--buffer = base_digits[0];
+      digits++;
+    }
+  return digits;
+}
+
 /* Non-terminal <number>.
 
      <number> ::= [n] </decimal integer/>  */
@@ -931,50 +1105,91 @@ write_number (number, unsigned_p, base)
      int unsigned_p;
      unsigned int base;
 {
-  static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-  unsigned HOST_WIDE_INT n;
-  unsigned HOST_WIDE_INT m = 1;
+  char buffer[sizeof (HOST_WIDE_INT) * 8];
+  unsigned count = 0;
 
   if (!unsigned_p && (HOST_WIDE_INT) number < 0)
     {
       write_char ('n');
       number = -((HOST_WIDE_INT) number);
     }
-  
-  /* Figure out how many digits there are.  */
-  n = number;
-  while (n >= base)
-    {
-      n /= base;
-      m *= base;
-    }
-
-  /* Write them out.  */
-  while (m > 0)
-    {
-      int digit = number / m;
-      write_char (digits[digit]);
-      number -= digit * m;
-      m /= base;
-    }
-
-  my_friendly_assert (number == 0, 20000407);
+  count = hwint_to_ascii (number, base, buffer + sizeof (buffer), 1);
+  write_chars (buffer + sizeof (buffer) - count, count);
 }
 
-/* Write out an integeral CST in decimal.  */
+/* Write out an integral CST in decimal. Most numbers are small, and
+   representable in a HOST_WIDE_INT. Occasionally we'll have numbers
+   bigger than that, which we must deal with.  */
 
 static inline void
 write_integer_cst (cst)
      tree cst;
 {
-  if (tree_int_cst_sgn (cst) >= 0) 
+  int sign = tree_int_cst_sgn (cst);
+
+  if (TREE_INT_CST_HIGH (cst) + (sign < 0))
     {
-      if (TREE_INT_CST_HIGH (cst) != 0)
-       sorry ("mangling very large integers");
-      write_unsigned_number (TREE_INT_CST_LOW (cst));
+      /* A bignum. We do this in chunks, each of which fits in a
+        HOST_WIDE_INT.  */
+      char buffer[sizeof (HOST_WIDE_INT) * 8 * 2];
+      unsigned HOST_WIDE_INT chunk;
+      unsigned chunk_digits;
+      char *ptr = buffer + sizeof (buffer);
+      unsigned count = 0;
+      tree n, base, type;
+      int done;
+
+      /* HOST_WIDE_INT must be at least 32 bits, so 10^9 is
+        representable.  */
+      chunk = 1000000000;
+      chunk_digits = 9;
+      
+      if (sizeof (HOST_WIDE_INT) >= 8)
+       {
+         /* It is at least 64 bits, so 10^18 is representable.  */
+         chunk_digits = 18;
+         chunk *= chunk;
+       }
+      
+      type = c_common_signed_or_unsigned_type (1, TREE_TYPE (cst));
+      base = build_int_2 (chunk, 0);
+      n = build_int_2 (TREE_INT_CST_LOW (cst), TREE_INT_CST_HIGH (cst));
+      TREE_TYPE (n) = TREE_TYPE (base) = type;
+
+      if (sign < 0)
+       {
+         write_char ('n');
+         n = fold (build1 (NEGATE_EXPR, type, n));
+       }
+      do
+       {
+         tree d = fold (build (FLOOR_DIV_EXPR, type, n, base));
+         tree tmp = fold (build (MULT_EXPR, type, d, base));
+         unsigned c;
+         
+         done = integer_zerop (d);
+         tmp = fold (build (MINUS_EXPR, type, n, tmp));
+         c = hwint_to_ascii (TREE_INT_CST_LOW (tmp), 10, ptr,
+                               done ? 1 : chunk_digits);
+         ptr -= c;
+         count += c;
+         n = d;
+       }
+      while (!done);
+      write_chars (ptr, count);
+    }
+  else 
+    {
+      /* A small num.  */
+      unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (cst);
+      
+      if (sign < 0)
+       {
+         write_char ('n');
+         low = -low;
+       }
+      write_unsigned_number (low);
     }
-  else
-    write_signed_number (tree_low_cst (cst, 0));
 }
 
 /* Non-terminal <identifier>.
@@ -983,7 +1198,7 @@ write_integer_cst (cst)
 
 static void
 write_identifier (identifier)
-     char *identifier;
+     const char *identifier;
 {
   MANGLE_TRACE ("identifier", identifier);
   write_string (identifier);
@@ -995,37 +1210,39 @@ write_identifier (identifier)
      <special-name> ::= C1   # complete object constructor
                     ::= C2   # base object constructor
                     ::= C3   # complete object allocating constructor
-                    ::= C4   # base object allocating constructor  
 
    Currently, allocating constructors are never used. 
 
-   We also need to provide unique mangled names (which should never be
-   exported) for the constructor that takes an in-charge parameter,
-   and for a constructor whose name is the same as its class's name.
-   We use "C*INTERNAL*" for these.  */
+   We also need to provide mangled names for the maybe-in-charge
+   constructor, so we treat it here too.  mangle_decl_string will
+   append *INTERNAL* to that, to make sure we never emit it.  */
 
 static void
 write_special_name_constructor (ctor)
      tree ctor;
 {
-  if (DECL_COMPLETE_CONSTRUCTOR_P (ctor))
+  if (DECL_COMPLETE_CONSTRUCTOR_P (ctor)
+      /* Even though we don't ever emit a definition of the
+        old-style destructor, we still have to consider entities
+        (like static variables) nested inside it.  */
+      || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor))
     write_string ("C1");
   else if (DECL_BASE_CONSTRUCTOR_P (ctor))
     write_string ("C2");
   else
-    write_string ("C*INTERNAL*");
+    abort ();
 }
 
 /* Handle destructor productions of non-terminal <special-name>.
-   DTOR is a denstructor FUNCTION_DECL. 
+   DTOR is a destructor FUNCTION_DECL. 
 
      <special-name> ::= D0 # deleting (in-charge) destructor
                     ::= D1 # complete object (in-charge) destructor
-                    ::= D2 # base object (not-in-charge) destructor 
+                    ::= D2 # base object (not-in-charge) destructor
 
-   We also need to provide unique mngled names for old-ABI
-   destructors, sometimes.  These should only be used internally.  We
-   use "D*INTERNAL*" for these.  */
+   We also need to provide mangled names for the maybe-incharge
+   destructor, so we treat it here too.  mangle_decl_string will
+   append *INTERNAL* to that, to make sure we never emit it.  */
 
 static void
 write_special_name_destructor (dtor)
@@ -1033,13 +1250,16 @@ write_special_name_destructor (dtor)
 {
   if (DECL_DELETING_DESTRUCTOR_P (dtor))
     write_string ("D0");
-  else if (DECL_COMPLETE_DESTRUCTOR_P (dtor))
+  else if (DECL_COMPLETE_DESTRUCTOR_P (dtor)
+          /* Even though we don't ever emit a definition of the
+             old-style destructor, we still have to consider entities
+             (like static variables) nested inside it.  */
+          || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor))
     write_string ("D1");
   else if (DECL_BASE_DESTRUCTOR_P (dtor))
     write_string ("D2");
   else
-    /* Old-ABI destructor.   */
-    write_string ("D*INTERNAL*");
+    abort ();
 }
 
 /* Return the discriminator for ENTITY appearing inside
@@ -1056,16 +1276,17 @@ discriminator_for_local_entity (entity)
   /* Assume this is the only local entity with this name.  */
   discriminator = 0;
 
-  /* For now, we don't discriminate amongst local variables.  */
-  if (TREE_CODE (entity) != TYPE_DECL)
-    return 0;
-
-  /* Scan the list of local classes.  */
-  entity = TREE_TYPE (entity);
-  for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
-    if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
-       && TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
-      ++discriminator;
+  if (DECL_DISCRIMINATOR_P (entity) && DECL_LANG_SPECIFIC (entity))
+    discriminator = DECL_DISCRIMINATOR (entity);
+  else if (TREE_CODE (entity) == TYPE_DECL)
+    {
+      /* Scan the list of local classes.  */
+      entity = TREE_TYPE (entity);
+      for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
+        if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
+            && TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
+         ++discriminator;
+    }  
 
   return discriminator;
 }
@@ -1093,27 +1314,27 @@ static void
 write_discriminator (discriminator)
      int discriminator;
 {
-  /* If discriminator is zero, don't write anything.  Otherwise... */
+  /* If discriminator is zero, don't write anything.  Otherwise...  */
   if (discriminator > 0)
     {
       write_char ('_');
-      /* The number is omitted for discriminator == 1.  Beyond 1, the
-        numbering starts at 0.  */
-      if (discriminator > 1)
-       write_unsigned_number (discriminator - 2);
+      write_unsigned_number (discriminator - 1);
     }
 }
 
 /* Mangle the name of a function-scope entity.  FUNCTION is the
    FUNCTION_DECL for the enclosing function.  ENTITY is the decl for
-   the entity itself.
+   the entity itself.  LOCAL_ENTITY is the entity that's directly
+   scoped in FUNCTION_DECL, either ENTITY itself or an enclosing scope
+   of ENTITY.
 
      <local-name> := Z <function encoding> E <entity name> [<discriminator>]
                   := Z <function encoding> E s [<discriminator>]  */
 
 static void
-write_local_name (function, entity)
+write_local_name (function, local_entity, entity)
      tree function;
+     tree local_entity;
      tree entity;
 {
   MANGLE_TRACE_TREE ("local-name", entity);
@@ -1129,8 +1350,11 @@ write_local_name (function, entity)
     }
   else
     {
-      write_unqualified_name (entity);
-      write_discriminator (discriminator_for_local_entity (entity));
+      /* Now the <entity name>.  Let write_name know its being called
+        from <local-name>, so it doesn't try to process the enclosing
+        function scope again.  */
+      write_name (entity, /*ignore_local_scope=*/1);
+      write_discriminator (discriminator_for_local_entity (local_entity));
     }
 }
 
@@ -1146,10 +1370,9 @@ write_local_name (function, entity)
             ::= <CV-qualifier>
             ::= P <type>    # pointer-to
             ::= R <type>    # reference-to
-            ::= C <type>    # complex pair (C 2000)  [not supported]
+            ::= C <type>    # complex pair (C 2000)
             ::= G <type>    # imaginary (C 2000)     [not supported]
             ::= U <source-name> <type>   # vendor extended type qualifier 
-                                                     [not supported]
 
    TYPE is a type node.  */
 
@@ -1157,12 +1380,15 @@ static void
 write_type (type)
      tree type;
 {
-  /* This gets set to non-zero if TYPE turns out to be a (possibly
+  /* This gets set to nonzero if TYPE turns out to be a (possibly
      CV-qualified) builtin type.  */
   int is_builtin_type = 0;
 
   MANGLE_TRACE_TREE ("type", type);
 
+  if (type == error_mark_node)
+    return;
+
   if (find_substitution (type))
     return;
   
@@ -1172,6 +1398,11 @@ write_type (type)
        since both the qualified and uqualified types are substitution
        candidates.  */
     write_type (TYPE_MAIN_VARIANT (type));
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    /* It is important not to use the TYPE_MAIN_VARIANT of TYPE here
+       so that the cv-qualification of the element type is available
+       in write_array_type.  */
+    write_array_type (type);
   else
     {
       /* See through any typedefs.  */
@@ -1197,7 +1428,7 @@ write_type (type)
 
        case FUNCTION_TYPE:
        case METHOD_TYPE:
-         write_function_type (type, 1);
+         write_function_type (type);
          break;
 
        case UNION_TYPE:
@@ -1212,14 +1443,12 @@ write_type (type)
          break;
 
        case TYPENAME_TYPE:
-         /* We handle TYPENAME_TYPEs like ordinary nested names.  */
+       case UNBOUND_CLASS_TEMPLATE:
+         /* We handle TYPENAME_TYPEs and UNBOUND_CLASS_TEMPLATEs like
+            ordinary nested names.  */
          write_nested_name (TYPE_STUB_DECL (type));
          break;
 
-       case ARRAY_TYPE:
-         write_array_type (type);
-         break;
-
        case POINTER_TYPE:
          /* A pointer-to-member variable is represented by a POINTER_TYPE
             to an OFFSET_TYPE, so check for this first.  */
@@ -1244,17 +1473,25 @@ write_type (type)
 
        case TEMPLATE_TEMPLATE_PARM:
          write_template_template_param (type);
-         if (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (type))
-           write_template_args 
-             (TI_ARGS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (type)));
+         break;
+
+       case BOUND_TEMPLATE_TEMPLATE_PARM:
+         write_template_template_param (type);
+         write_template_args 
+           (TI_ARGS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (type)));
          break;
 
        case OFFSET_TYPE:
          write_pointer_to_member_type (build_pointer_type (type));
          break;
 
+       case VECTOR_TYPE:
+         write_string ("U8__vector");
+         write_type (TREE_TYPE (type));
+         break;
+
        default:
-         my_friendly_abort (20000409);
+         abort ();
        }
     }
 
@@ -1278,19 +1515,23 @@ write_CV_qualifiers_for_type (type)
 
        "In cases where multiple order-insensitive qualifiers are
        present, they should be ordered 'K' (closest to the base type),
-       'V', 'r', and 'U' (farthest from the base type) ..."  */
+       'V', 'r', and 'U' (farthest from the base type) ..."  
 
-  if (CP_TYPE_RESTRICT_P (type))
+     Note that we do not use cp_type_quals below; given "const
+     int[3]", the "const" is emitted with the "int", not with the
+     array.  */
+
+  if (TYPE_QUALS (type) & TYPE_QUAL_RESTRICT)
     {
       write_char ('r');
       ++num_qualifiers;
     }
-  if (CP_TYPE_VOLATILE_P (type))
+  if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
     {
       write_char ('V');
       ++num_qualifiers;
     }
-  if (CP_TYPE_CONST_P (type))
+  if (TYPE_QUALS (type) & TYPE_QUAL_CONST)
     {
       write_char ('K');
       ++num_qualifiers;
@@ -1315,12 +1556,13 @@ write_CV_qualifiers_for_type (type)
                     ::= m   # unsigned long
                     ::= x   # long long, __int64
                     ::= y   # unsigned long long, __int64  
-                    ::= n   # __int128            [not supported]
-                    ::= o   # unsigned __int128   [not supported] 
+                    ::= n   # __int128
+                    ::= o   # unsigned __int128
                     ::= f   # float
                     ::= d   # double
                     ::= e   # long double, __float80 
-                    ::= g   # __float128          [not supported]  */
+                    ::= g   # __float128          [not supported]
+                    ::= u <source-name>  # vendor extended type */
 
 static void 
 write_builtin_type (type)
@@ -1345,11 +1587,14 @@ write_builtin_type (type)
         integer_type_nodes.  */
       if (type == wchar_type_node)
        write_char ('w');
+      else if (TYPE_FOR_JAVA (type))
+       write_java_integer_type_codes (type);
       else
        {
          size_t itk;
          /* Assume TYPE is one of the shared integer type nodes.  Find
             it in the array of these nodes.  */
+       iagain:
          for (itk = 0; itk < itk_none; ++itk)
            if (type == integer_types[itk])
              {
@@ -1357,42 +1602,69 @@ write_builtin_type (type)
                write_char (integer_type_codes[itk]);
                break;
              }
-         
+
          if (itk == itk_none)
-           /* Couldn't find this type.  */
-           my_friendly_abort (20000408);
+           {
+             tree t = c_common_type_for_mode (TYPE_MODE (type),
+                                              TREE_UNSIGNED (type));
+             if (type == t)
+               {
+                 if (TYPE_PRECISION (type) == 128)
+                   write_char (TREE_UNSIGNED (type) ? 'o' : 'n');
+                 else
+                   /* Couldn't find this type.  */
+                   abort ();
+               }
+             else
+               {
+                 type = t;
+                 goto iagain;
+               }
+           }
        }
       break;
 
     case REAL_TYPE:
-      if (type == float_type_node)
+      if (type == float_type_node
+         || type == java_float_type_node)
        write_char ('f');
-      else if (type == double_type_node)
+      else if (type == double_type_node
+              || type == java_double_type_node)
        write_char ('d');
       else if (type == long_double_type_node)
        write_char ('e');
       else
-       my_friendly_abort (20000409);
+       abort ();
       break;
 
     default:
-      my_friendly_abort (20000509);
+      abort ();
     }
 }
 
 /* Non-terminal <function-type>.  NODE is a FUNCTION_TYPE or
-   METHOD_TYPE.  If INCLUDE_RETURN_TYPE is non-zero, the return type
-   is mangled before the parameter types.
+   METHOD_TYPE.  The return type is mangled before the parameter
+   types.
 
      <function-type> ::= F [Y] <bare-function-type> E   */
 
 static void
-write_function_type (type, include_return_type)
+write_function_type (type)
      tree type;
-     int include_return_type;
 {
   MANGLE_TRACE_TREE ("function-type", type);
 
+  /* For a pointer to member function, the function type may have
+     cv-qualifiers, indicating the quals for the artificial 'this'
+     parameter.  */
+  if (TREE_CODE (type) == METHOD_TYPE)
+    {
+      /* The first parameter must be a POINTER_TYPE pointing to the
+        `this' parameter.  */
+      tree this_type = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)));
+      write_CV_qualifiers_for_type (this_type);
+    }
+
   write_char ('F');
   /* We don't track whether or not a type is `extern "C"'.  Note that
      you can have an `extern "C"' function that does not have
@@ -1406,20 +1678,23 @@ write_function_type (type, include_return_type)
        extern "C" function_t f; // Vice versa.
 
      See [dcl.link].  */
-  write_bare_function_type (type, include_return_type);
+  write_bare_function_type (type, /*include_return_type_p=*/1, 
+                           /*decl=*/NULL);
   write_char ('E');
 }
 
-/* Non-terminal <bare-function-type>.  NODE is a FUNCTION_DECL or a
-   METHOD_TYPE.  If INCLUDE_RETURN_TYPE is non-zero, the return value
-   is mangled before the parameter types.
+/* Non-terminal <bare-function-type>.  TYPE is a FUNCTION_TYPE or
+   METHOD_TYPE.  If INCLUDE_RETURN_TYPE is nonzero, the return value
+   is mangled before the parameter types.  If non-NULL, DECL is
+   FUNCTION_DECL for the function whose type is being emitted.
 
      <bare-function-type> ::= </signature/ type>+  */
 
 static void
-write_bare_function_type (type, include_return_type_p)
+write_bare_function_type (type, include_return_type_p, decl)
      tree type;
      int include_return_type_p;
+     tree decl;
 {
   MANGLE_TRACE_TREE ("bare-function-type", type);
 
@@ -1429,21 +1704,25 @@ write_bare_function_type (type, include_return_type_p)
 
   /* Now mangle the types of the arguments.  */
   write_method_parms (TYPE_ARG_TYPES (type), 
-                     TREE_CODE (type) == METHOD_TYPE);
+                     TREE_CODE (type) == METHOD_TYPE,
+                     decl);
 }
 
 /* Write the mangled representation of a method parameter list of
-   types given in PARM_LIST.  If METHOD_P is non-zero, the function is 
+   types given in PARM_TYPES.  If METHOD_P is nonzero, the function is
    considered a non-static method, and the this parameter is omitted.
-   If VARARGS_P is non-zero, an additional token designating varargs
-   is appended.  */
+   If non-NULL, DECL is the FUNCTION_DECL for the function whose
+   parameters are being emitted.  */
 
 static void
-write_method_parms (parm_list, method_p)
-     tree parm_list;
+write_method_parms (parm_types, method_p, decl)
+     tree decl;
+     tree parm_types;
      int method_p;
 {
-  tree first_parm;
+  tree first_parm_type;
+  tree parm_decl = decl ? DECL_ARGUMENTS (decl) : NULL_TREE;
+
   /* Assume this parameter type list is variable-length.  If it ends
      with a void type, then it's not.  */
   int varargs_p = 1;
@@ -1451,28 +1730,39 @@ write_method_parms (parm_list, method_p)
   /* If this is a member function, skip the first arg, which is the
      this pointer.  
        "Member functions do not encode the type of their implicit this
-       parameter."  */
+       parameter."  
+  
+     Similarly, there's no need to mangle artificial parameters, like
+     the VTT parameters for constructors and destructors.  */
   if (method_p)
-    parm_list = TREE_CHAIN (parm_list);
-
-  for (first_parm = parm_list; 
-       parm_list; 
-       parm_list = TREE_CHAIN (parm_list))
     {
-      tree parm = TREE_VALUE (parm_list);
+      parm_types = TREE_CHAIN (parm_types);
+      parm_decl = parm_decl ? TREE_CHAIN (parm_decl) : NULL_TREE;
 
+      while (parm_decl && DECL_ARTIFICIAL (parm_decl))
+       {
+         parm_types = TREE_CHAIN (parm_types);
+         parm_decl = TREE_CHAIN (parm_decl);
+       }
+    }
+
+  for (first_parm_type = parm_types; 
+       parm_types; 
+       parm_types = TREE_CHAIN (parm_types))
+    {
+      tree parm = TREE_VALUE (parm_types);
       if (parm == void_type_node)
        {
          /* "Empty parameter lists, whether declared as () or
             conventionally as (void), are encoded with a void parameter
             (v)."  */
-         if (parm_list == first_parm)
+         if (parm_types == first_parm_type)
            write_type (parm);
          /* If the parm list is terminated with a void type, it's
             fixed-length.  */
          varargs_p = 0;
          /* A void type better be the last one.  */
-         my_friendly_assert (TREE_CHAIN (parm_list) == NULL, 20000523);
+         my_friendly_assert (TREE_CHAIN (parm_types) == NULL, 20000523);
        }
       else
        write_type (parm);
@@ -1489,7 +1779,7 @@ static void
 write_class_enum_type (type)
      tree type;
 {
-  write_name (TYPE_NAME (type));
+  write_name (TYPE_NAME (type), /*ignore_local_scope=*/0);
 }
 
 /* Non-terminal <template-args>.  ARGS is a TREE_VEC of template
@@ -1501,24 +1791,37 @@ static void
 write_template_args (args)
      tree args;
 {
-  int i;
-  int length = TREE_VEC_LENGTH (args);
-
   MANGLE_TRACE_TREE ("template-args", args);
 
-  my_friendly_assert (length > 0, 20000422);
+  write_char ('I');
 
-  if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+  if (TREE_CODE (args) == TREE_VEC)
+    {
+      int i;
+      int length = TREE_VEC_LENGTH (args);
+      my_friendly_assert (length > 0, 20000422);
+
+      if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+       {
+         /* We have nested template args.  We want the innermost template
+            argument list.  */
+         args = TREE_VEC_ELT (args, length - 1);
+         length = TREE_VEC_LENGTH (args);
+       }
+      for (i = 0; i < length; ++i)
+       write_template_arg (TREE_VEC_ELT (args, i));
+    }
+  else 
     {
-      /* We have nested template args.  We want the innermost template
-        argument list.  */
-      args = TREE_VEC_ELT (args, length - 1);
-      length = TREE_VEC_LENGTH (args);
+      my_friendly_assert (TREE_CODE (args) == TREE_LIST, 20021014);
+
+      while (args)
+       {
+         write_template_arg (TREE_VALUE (args));
+         args = TREE_CHAIN (args);
+       }
     }
 
-  write_char ('I');
-  for (i = 0; i < length; ++i)
-    write_template_arg (TREE_VEC_ELT (args, i));
   write_char ('E');
 }
 
@@ -1528,7 +1831,9 @@ write_template_args (args)
 
    <expr-primary> ::= <template-param>
                  ::= L <type> <value number> E  # literal
-                 ::= L <mangled-name> E         # external name  */
+                 ::= L <mangled-name> E         # external name  
+                  ::= sr <type> <unqualified-name>
+                  ::= sr <type> <unqualified-name> <template-args> */
 
 static void
 write_expression (expr)
@@ -1549,32 +1854,114 @@ write_expression (expr)
       code = TREE_CODE (expr);
     }
 
-  /* Handle template parameters. */
+  /* Skip NOP_EXPRs.  They can occur when (say) a pointer argument
+     is converted (via qualification conversions) to another
+     type.  */
+  while (TREE_CODE (expr) == NOP_EXPR
+        || TREE_CODE (expr) == NON_LVALUE_EXPR)
+    {
+      expr = TREE_OPERAND (expr, 0);
+      code = TREE_CODE (expr);
+    }
+
+  /* Handle template parameters.  */
   if (code == TEMPLATE_TYPE_PARM 
       || code == TEMPLATE_TEMPLATE_PARM
-      ||  code == TEMPLATE_PARM_INDEX)
+      || code == BOUND_TEMPLATE_TEMPLATE_PARM
+      || code == TEMPLATE_PARM_INDEX)
     write_template_param (expr);
   /* Handle literals.  */
-  else if (TREE_CODE_CLASS (code) == 'c')
+  else if (TREE_CODE_CLASS (code) == 'c' 
+          || (abi_version_at_least (2) && code == CONST_DECL))
     write_template_arg_literal (expr);
   else if (DECL_P (expr))
     {
+      /* G++ 3.2 incorrectly mangled non-type template arguments of
+        enumeration type using their names.  */
+      if (code == CONST_DECL)
+       G.need_abi_warning = 1;
       write_char ('L');
       write_mangled_name (expr);
       write_char ('E');
     }
-  else
+  else if (TREE_CODE (expr) == SIZEOF_EXPR 
+          && TYPE_P (TREE_OPERAND (expr, 0)))
     {
-      int i;
-
-      /* Skip NOP_EXPRs.  They can occur when (say) a pointer argument
-        is converted (via qualification conversions) to another
-        type.  */
-      while (TREE_CODE (expr) == NOP_EXPR)
+      write_string ("st");
+      write_type (TREE_OPERAND (expr, 0));
+    }
+  else if (abi_version_at_least (2) && TREE_CODE (expr) == SCOPE_REF)
+    {
+      tree scope = TREE_OPERAND (expr, 0);
+      tree member = TREE_OPERAND (expr, 1);
+
+      /* If the MEMBER is a real declaration, then the qualifying
+        scope was not dependent.  Ideally, we would not have a
+        SCOPE_REF in those cases, but sometimes we do.  If the second
+        argument is a DECL, then the name must not have been
+        dependent.  */
+      if (DECL_P (member))
+       write_expression (member);
+      else
        {
-         expr = TREE_OPERAND (expr, 0);
-         code = TREE_CODE (expr);
+         tree template_args;
+
+         write_string ("sr");
+         write_type (scope);
+         /* If MEMBER is a template-id, separate the template
+            from the arguments.  */
+         if (TREE_CODE (member) == TEMPLATE_ID_EXPR)
+           {
+             template_args = TREE_OPERAND (member, 1);
+             member = TREE_OPERAND (member, 0);
+             if (TREE_CODE (member) == LOOKUP_EXPR)
+               member = TREE_OPERAND (member, 0);
+           }
+         else
+           template_args = NULL_TREE;
+         /* Write out the name of the MEMBER.  */
+         if (IDENTIFIER_TYPENAME_P (member))
+           write_conversion_operator_name (TREE_TYPE (member));
+         else if (IDENTIFIER_OPNAME_P (member))
+           {
+             int i;
+             const char *mangled_name = NULL;
+
+             /* Unfortunately, there is no easy way to go from the
+                name of the operator back to the corresponding tree
+                code.  */
+             for (i = 0; i < LAST_CPLUS_TREE_CODE; ++i)
+               if (operator_name_info[i].identifier == member)
+                 {
+                   /* The ABI says that we prefer binary operator
+                      names to unary operator names.  */
+                   if (operator_name_info[i].arity == 2)
+                     {
+                       mangled_name = operator_name_info[i].mangled_name;
+                       break;
+                     }
+                   else if (!mangled_name)
+                     mangled_name = operator_name_info[i].mangled_name;
+                 }
+               else if (assignment_operator_name_info[i].identifier
+                        == member)
+                 {
+                   mangled_name 
+                     = assignment_operator_name_info[i].mangled_name;
+                   break;
+                 }
+             write_string (mangled_name);
+           }
+         else
+           write_source_name (member);
+         /* Write out the template arguments.  */
+         if (template_args)
+           write_template_args (template_args);
        }
+    }
+  else
+    {
+      int i;
 
       /* When we bind a variable or function to a non-type template
         argument with reference type, we create an ADDR_EXPR to show
@@ -1593,22 +1980,42 @@ write_expression (expr)
 
          code = TREE_CODE (expr);
        }
-      
+
       /* If it wasn't any of those, recursively expand the expression.  */
       write_string (operator_name_info[(int) code].mangled_name);
 
-      /* Handle pointers-to-members specially.  */
-      if (code == SCOPE_REF)
+      switch (code)
        {
+       case CAST_EXPR:
+         write_type (TREE_TYPE (expr));
+         write_expression (TREE_VALUE (TREE_OPERAND (expr, 0)));
+         break;
+
+       case STATIC_CAST_EXPR:
+       case CONST_CAST_EXPR:
+         write_type (TREE_TYPE (expr));
+         write_expression (TREE_OPERAND (expr, 0));
+         break;
+
+         
+       /* Handle pointers-to-members specially.  */
+       case SCOPE_REF:
          write_type (TREE_OPERAND (expr, 0));
          if (TREE_CODE (TREE_OPERAND (expr, 1)) == IDENTIFIER_NODE)
            write_source_name (TREE_OPERAND (expr, 1));
          else
-           write_encoding (TREE_OPERAND (expr, 1));
+           {
+             /* G++ 3.2 incorrectly put out both the "sr" code and
+                the nested name of the qualified name.  */
+             G.need_abi_warning = 1;
+             write_encoding (TREE_OPERAND (expr, 1));
+           }
+         break;
+
+       default:
+         for (i = 0; i < TREE_CODE_LENGTH (code); ++i)
+           write_expression (TREE_OPERAND (expr, i));
        }
-      else
-       for (i = 0; i < TREE_CODE_LENGTH (code); ++i)
-         write_expression (TREE_OPERAND (expr, i));
     }
 }
 
@@ -1642,7 +2049,7 @@ write_template_arg_literal (value)
          else if (value == boolean_true_node)
            write_unsigned_number (1);
          else 
-           my_friendly_abort (20000412);
+           abort ();
        }
       else
        write_integer_cst (value);
@@ -1667,7 +2074,7 @@ write_template_arg_literal (value)
 #endif
     }
   else
-    my_friendly_abort (20000412);
+    abort ();
 
   write_char ('E');
 }
@@ -1705,15 +2112,20 @@ write_template_arg (node)
   else if (code == TEMPLATE_DECL)
     /* A template appearing as a template arg is a template template arg.  */
     write_template_template_arg (node);
+  else if ((TREE_CODE_CLASS (code) == 'c' && code != PTRMEM_CST)
+          || (abi_version_at_least (2) && code == CONST_DECL))
+    write_template_arg_literal (node);
   else if (DECL_P (node))
     {
+      /* G++ 3.2 incorrectly mangled non-type template arguments of
+        enumeration type using their names.  */
+      if (code == CONST_DECL)
+       G.need_abi_warning = 1;
       write_char ('L');
       write_char ('Z');
       write_encoding (node);
       write_char ('E');
     }
-  else if (TREE_CODE_CLASS (code) == 'c' && code != PTRMEM_CST)
-    write_template_arg_literal (node);
   else
     {
       /* Template arguments may be expressions.  */
@@ -1734,7 +2146,7 @@ write_template_template_arg (tree decl)
 
   if (find_substitution (decl))
     return;
-  write_name (decl);
+  write_name (decl, /*ignore_local_scope=*/0);
   add_substitution (decl);
 }
 
@@ -1742,6 +2154,7 @@ write_template_template_arg (tree decl)
 /* Non-terminal <array-type>.  TYPE is an ARRAY_TYPE.  
 
      <array-type> ::= A [</dimension/ number>] _ </element/ type>  
+                  ::= A <expression> _ </element/ type>
 
      "Array types encode the dimension (number of elements) and the
      element type. For variable length arrays, the dimension (but not
@@ -1790,15 +2203,25 @@ write_pointer_to_member_type (type)
 }
 
 /* Non-terminal <template-param>.  PARM is a TEMPLATE_TYPE_PARM,
-   TEMPLATE_TEMPLATE_PARM, or a TEMPLATE_PARM_INDEX.
+   TEMPLATE_TEMPLATE_PARM, BOUND_TEMPLATE_TEMPLATE_PARM or a
+   TEMPLATE_PARM_INDEX.
 
-     <template-param> ::= T </parameter/ number> _  */
+     <template-param> ::= T </parameter/ number> _
+
+   If we are internally mangling then we distinguish level and, for
+   non-type parms, type too. The mangling appends
+   
+     </level/ number> _ </non-type type/ type> _
+
+   This is used by mangle_conv_op_name_for_type.  */
 
 static void
 write_template_param (parm)
      tree parm;
 {
   int parm_index;
+  int parm_level;
+  tree parm_type = NULL_TREE;
 
   MANGLE_TRACE_TREE ("template-parm", parm);
 
@@ -1806,15 +2229,19 @@ write_template_param (parm)
     {
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
+    case BOUND_TEMPLATE_TEMPLATE_PARM:
       parm_index = TEMPLATE_TYPE_IDX (parm);
+      parm_level = TEMPLATE_TYPE_LEVEL (parm);
       break;
 
     case TEMPLATE_PARM_INDEX:
       parm_index = TEMPLATE_PARM_IDX (parm);
+      parm_level = TEMPLATE_PARM_LEVEL (parm);
+      parm_type = TREE_TYPE (TEMPLATE_PARM_DECL (parm));
       break;
 
     default:
-      my_friendly_abort (20000523);
+      abort ();
     }
 
   write_char ('T');
@@ -1823,6 +2250,15 @@ write_template_param (parm)
   if (parm_index > 0)
     write_unsigned_number (parm_index - 1);
   write_char ('_');
+  if (G.internal_mangling_p)
+    {
+      if (parm_level > 0)
+       write_unsigned_number (parm_level - 1);
+      write_char ('_');
+      if (parm_type)
+       write_type (parm_type);
+      write_char ('_');
+    }
 }
 
 /*  <template-template-param>
@@ -1838,7 +2274,7 @@ write_template_template_param (parm)
   /* PARM, a TEMPLATE_TEMPLATE_PARM, is an instantiation of the
      template template parameter.  The substitution candidate here is
      only the template.  */
-  if (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm))
+  if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
     {
       template 
        = TI_TEMPLATE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm));
@@ -1870,21 +2306,31 @@ write_substitution (seq_id)
   write_char ('_');
 }
 
-/* Start mangling a new name or type.  */
+/* Start mangling ENTITY.  */
 
 static inline void
-start_mangling ()
+start_mangling (tree entity)
 {
+  G.entity = entity;
+  G.need_abi_warning = false;
+  VARRAY_TREE_INIT (G.substitutions, 1, "mangling substitutions");
   obstack_free (&G.name_obstack, obstack_base (&G.name_obstack));
 }
 
-/* Done with mangling.  Return the generated mangled name.  */
+/* Done with mangling.  Return the generated mangled name.  If WARN is
+   true, and the name of G.entity will be mangled differently in a
+   future version of the ABI, issue a warning.  */
 
 static inline const char *
-finish_mangling ()
+finish_mangling (bool warn)
 {
+  if (warn_abi && warn && G.need_abi_warning)
+    warning ("the mangled name of `%D' will change in a future "
+            "version of GCC",
+            G.entity);
+
   /* Clear all the substitutions.  */
-  VARRAY_POP_ALL (G.substitutions);
+  G.substitutions = 0;
 
   /* Null-terminate the string.  */
   write_char ('\0');
@@ -1898,7 +2344,6 @@ void
 init_mangle ()
 {
   gcc_obstack_init (&G.name_obstack);
-  VARRAY_TREE_INIT (G.substitutions, 1, "mangling substitutions");
 
   /* Cache these identifiers for quick comparison when checking for
      standard substitutions.  */
@@ -1918,14 +2363,34 @@ mangle_decl_string (decl)
 {
   const char *result;
 
-  start_mangling ();
+  start_mangling (decl);
 
   if (TREE_CODE (decl) == TYPE_DECL)
     write_type (TREE_TYPE (decl));
+  else if (/* The names of `extern "C"' functions are not mangled.  */
+          (DECL_EXTERN_C_FUNCTION_P (decl)
+           /* But overloaded operator names *are* mangled.  */
+           && !DECL_OVERLOADED_OPERATOR_P (decl))
+          /* The names of global variables aren't mangled either.  */
+          || (TREE_CODE (decl) == VAR_DECL
+              && CP_DECL_CONTEXT (decl) == global_namespace)
+          /* And neither are `extern "C"' variables.  */
+          || (TREE_CODE (decl) == VAR_DECL
+              && DECL_EXTERN_C_P (decl)))
+    write_string (IDENTIFIER_POINTER (DECL_NAME (decl)));
   else
-    write_mangled_name (decl);
+    {
+      write_mangled_name (decl);
+      if (DECL_LANG_SPECIFIC (decl)
+         && (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)
+             || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)))
+       /* We need a distinct mangled name for these entities, but
+          we should never actually output it.  So, we append some
+          characters the assembler won't like.  */
+       write_string (" *INTERNAL* ");
+    }
 
-  result = finish_mangling ();
+  result = finish_mangling (/*warn=*/true);
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
   return result;
@@ -1933,11 +2398,13 @@ mangle_decl_string (decl)
 
 /* Create an identifier for the external mangled name of DECL.  */
 
-tree
+void
 mangle_decl (decl)
      tree decl;
 {
-  return get_identifier (mangle_decl_string (decl));
+  tree id = get_identifier (mangle_decl_string (decl));
+
+  SET_DECL_ASSEMBLER_NAME (decl, id);
 }
 
 /* Generate the mangled representation of TYPE.  */
@@ -1948,9 +2415,9 @@ mangle_type_string (type)
 {
   const char *result;
 
-  start_mangling ();
+  start_mangling (type);
   write_type (type);
-  result = finish_mangling ();
+  result = finish_mangling (/*warn=*/false);
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_type_string = '%s'\n\n", result);
   return result;
@@ -1978,7 +2445,7 @@ mangle_special_for_type (type, code)
 
   /* We don't have an actual decl here for the special component, so
      we can't just process the <encoded-name>.  Instead, fake it.  */
-  start_mangling ();
+  start_mangling (type);
 
   /* Start the mangling.  */
   write_string ("_Z");
@@ -1986,7 +2453,7 @@ mangle_special_for_type (type, code)
 
   /* Add the type.  */
   write_type (type);
-  result = finish_mangling ();
+  result = finish_mangling (/*warn=*/false);
 
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
@@ -2053,7 +2520,7 @@ mangle_ctor_vtbl_for_type (type, binfo)
 {
   const char *result;
 
-  start_mangling ();
+  start_mangling (type);
 
   write_string ("_Z");
   write_string ("TC");
@@ -2062,57 +2529,91 @@ mangle_ctor_vtbl_for_type (type, binfo)
   write_char ('_');
   write_type (BINFO_TYPE (binfo));
 
-  result = finish_mangling ();
+  result = finish_mangling (/*warn=*/false);
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
   return get_identifier (result);
 }
 
-/* Return an identifier for the mangled name of a thunk to FN_DECL.
-   OFFSET is the initial adjustment to this used to find the vptr.  If
-   VCALL_OFFSET is non-NULL, this is a virtual thunk, and it is the
-   vtbl offset in bytes.  
+/* Mangle a this pointer or result pointer adjustment.
+   
+   <call-offset> ::= h <fixed offset number> _
+                ::= v <fixed offset number> _ <virtual offset number> _ */
+   
+static void
+mangle_call_offset (fixed_offset, virtual_offset)
+     tree fixed_offset;
+     tree virtual_offset;
+{
+  write_char (virtual_offset ? 'v' : 'h');
+
+  /* For either flavor, write the fixed offset.  */
+  write_integer_cst (fixed_offset);
+  write_char ('_');
 
-    <special-name> ::= Th <offset number> _ <base encoding>
-                   ::= Tv <offset number> _ <vcall offset number> _
-                                                           <base encoding>
+  /* For a virtual thunk, add the virtual offset.  */
+  if (virtual_offset)
+    {
+      write_integer_cst (virtual_offset);
+      write_char ('_');
+    }
+}
+
+/* Return an identifier for the mangled name of a this-adjusting or
+   covariant thunk to FN_DECL.  FIXED_OFFSET is the initial adjustment
+   to this used to find the vptr.  If VIRTUAL_OFFSET is non-NULL, this
+   is a virtual thunk, and it is the vtbl offset in
+   bytes. THIS_ADJUSTING is non-zero for a this adjusting thunk and
+   zero for a covariant thunk. Note, that FN_DECL might be a covariant
+   thunk itself. A covariant thunk name always includes the adjustment
+   for the this pointer, even if there is none.
+
+   <special-name> ::= T <call-offset> <base encoding>
+                  ::= Tc <this_adjust call-offset> <result_adjust call-offset>
+                                       <base encoding>
 */
 
 tree
-mangle_thunk (fn_decl, offset, vcall_offset)
+mangle_thunk (fn_decl, this_adjusting, fixed_offset, virtual_offset)
      tree fn_decl;
-     tree offset;
-     tree vcall_offset;
+     int this_adjusting;
+     tree fixed_offset;
+     tree virtual_offset;
 {
   const char *result;
   
-  start_mangling ();
+  start_mangling (fn_decl);
 
   write_string ("_Z");
-  /* The <special-name> for virtual thunks is Tv, for non-virtual
-     thunks Th.  */
   write_char ('T');
-  if (vcall_offset != 0)
-    write_char ('v');
+  
+  if (!this_adjusting)
+    {
+      /* Covariant thunk with no this adjustment */
+      write_char ('c');
+      mangle_call_offset (integer_zero_node, NULL_TREE);
+      mangle_call_offset (fixed_offset, virtual_offset);
+    }
+  else if (!DECL_THUNK_P (fn_decl))
+    /* Plain this adjusting thunk.  */
+    mangle_call_offset (fixed_offset, virtual_offset);
   else
-    write_char ('h');
-
-  /* For either flavor, write the offset to this.  */
-  write_integer_cst (offset);
-  write_char ('_');
-
-  /* For a virtual thunk, add the vcall offset.  */
-  if (vcall_offset)
     {
-      /* Virtual thunk.  Write the vcall offset and base type name.  */
-      write_integer_cst (vcall_offset);
-      write_char ('_');
+      /* This adjusting thunk to covariant thunk.  */
+      write_char ('c');
+      mangle_call_offset (fixed_offset, virtual_offset);
+      fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn_decl));
+      virtual_offset = THUNK_VIRTUAL_OFFSET (fn_decl);
+      if (virtual_offset)
+       virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
+      mangle_call_offset (fixed_offset, virtual_offset);
+      fn_decl = THUNK_TARGET (fn_decl);
     }
 
   /* Scoped name.  */
   write_encoding (fn_decl);
 
-  result = finish_mangling ();
+  result = finish_mangling (/*warn=*/false);
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_thunk = %s\n\n", result);
   return get_identifier (result);
@@ -2120,34 +2621,40 @@ mangle_thunk (fn_decl, offset, vcall_offset)
 
 /* Return an identifier for the mangled unqualified name for a
    conversion operator to TYPE.  This mangling is not specified by the
-   ABI spec; it is only used internally.
-
-   For compatibility with existing conversion operator mechanisms,
-   the mangled form is `__op<type>' where <type> is the mangled
-   representation of TYPE.  
-
-   FIXME: Though identifiers with starting with __op are reserved for
-   the implementation, it would eventually be nice to use inaccessible
-   names for these operators.  */
+   ABI spec; it is only used internally.  */
 
 tree
 mangle_conv_op_name_for_type (type)
      tree type;
 {
   tree identifier;
+  const char *mangled_type;
+  char *op_name;
 
-  /* Build the mangling for TYPE.  */
-  const char *mangled_type = mangle_type_string (type);
+  /* Build the internal mangling for TYPE.  */
+  G.internal_mangling_p = true;
+  mangled_type = mangle_type_string (type);
+  G.internal_mangling_p = false;
+  
   /* Allocate a temporary buffer for the complete name.  */
-  char *op_name = (char *) xmalloc (strlen (OPERATOR_TYPENAME_FORMAT) 
-                                   + strlen (mangled_type) + 1);
-  /* Assemble the mangling.  */
-  strcpy (op_name, OPERATOR_TYPENAME_FORMAT);
-  strcat (op_name, mangled_type);
+  op_name = concat ("operator ", mangled_type, NULL);
   /* Find or create an identifier.  */
   identifier = get_identifier (op_name);
   /* Done with the temporary buffer.  */
   free (op_name);
+
+  /* It had better be a unique mangling for the type.  */
+  if (IDENTIFIER_TYPENAME_P (identifier)
+      && !same_type_p (type, TREE_TYPE (identifier)))
+    {
+      /* In G++ 3.2, the name mangling scheme was ambiguous.  In later
+        versions of the ABI, this problem has been fixed.  */
+      if (abi_version_at_least (2))
+       abort ();
+      error ("due to a defect in the G++ 3.2 ABI, G++ has assigned the "
+            "same mangled name to two different types");
+    }
+  
   /* Set bits on the identifier so we know later it's a conversion.  */
   IDENTIFIER_OPNAME_P (identifier) = 1;
   IDENTIFIER_TYPENAME_P (identifier) = 1;
@@ -2165,8 +2672,53 @@ tree
 mangle_guard_variable (variable)
      tree variable;
 {
-  start_mangling ();
+  start_mangling (variable);
   write_string ("_ZGV");
-  write_name (variable);
-  return get_identifier (finish_mangling ());
+  if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
+    /* The name of a guard variable for a reference temporary should refer
+       to the reference, not the temporary.  */
+    write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
+  else
+    write_name (variable, /*ignore_local_scope=*/0);
+  return get_identifier (finish_mangling (/*warn=*/false));
 }
+
+/* Return an identifier for the name of a temporary variable used to
+   initialize a static reference.  This isn't part of the ABI, but we might
+   as well call them something readable.  */
+
+tree
+mangle_ref_init_variable (variable)
+     tree variable;
+{
+  start_mangling (variable);
+  write_string ("_ZGR");
+  write_name (variable, /*ignore_local_scope=*/0);
+  return get_identifier (finish_mangling (/*warn=*/false));
+}
+\f
+
+/* Foreign language type mangling section.  */
+
+/* How to write the type codes for the integer Java type.  */
+
+static void
+write_java_integer_type_codes (type)
+     tree type;
+{
+  if (type == java_int_type_node)
+    write_char ('i');
+  else if (type == java_short_type_node)
+    write_char ('s');
+  else if (type == java_byte_type_node)
+    write_char ('c');
+  else if (type == java_char_type_node)
+    write_char ('w');
+  else if (type == java_long_type_node)
+    write_char ('x');
+  else if (type == java_boolean_type_node)
+    write_char ('b');
+  else
+    abort ();
+}
+