OSDN Git Service

2009-10-28 Jerry Quinn <jlquinn@optonline.net>
[pf3gnuchains/gcc-fork.git] / gcc / cp / mangle.c
index 31676e7..7489665 100644 (file)
@@ -1,5 +1,5 @@
 /* Name mangling for the 3.0 C++ ABI.
 /* Name mangling for the 3.0 C++ ABI.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Written by Alex Samuel <samuel@codesourcery.com>
 
    Free Software Foundation, Inc.
    Written by Alex Samuel <samuel@codesourcery.com>
 
@@ -7,7 +7,7 @@
 
    GCC is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
 
    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)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GCC is distributed in the hope that it will be useful, but
    any later version.
 
    GCC is distributed in the hope that it will be useful, but
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.
 
    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 GCC; see the file COPYING.  If not, write to the Free
-   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This file implements mangling of C++ names according to the IA64
    C++ ABI specification.  A mangled name encodes a function or
 
 /* This file implements mangling of C++ names according to the IA64
    C++ ABI specification.  A mangled name encodes a function or
@@ -91,8 +90,7 @@
           && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))
 
 /* Things we only need one of.  This module is not reentrant.  */
           && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE))))))
 
 /* Things we only need one of.  This module is not reentrant.  */
-typedef struct globals GTY(())
-{
+typedef struct GTY(()) globals {
   /* An array of the current substitution candidates, in the order
      we've seen them.  */
   VEC(tree,gc) *substitutions;
   /* An array of the current substitution candidates, in the order
      we've seen them.  */
   VEC(tree,gc) *substitutions;
@@ -118,13 +116,6 @@ static struct obstack name_obstack;
    allocated on the name_obstack.  */
 static void *name_base;
 
    allocated on the name_obstack.  */
 static void *name_base;
 
-/* An incomplete mangled name.  There will be no NUL terminator.  If
-   there is no incomplete mangled name, this variable is NULL.  */
-static char *partially_mangled_name;
-
-/* The number of characters in the PARTIALLY_MANGLED_NAME.  */
-static size_t partially_mangled_name_len;
-
 /* Indices into subst_identifiers.  These are identifiers used in
    special substitution rules.  */
 typedef enum
 /* Indices into subst_identifiers.  These are identifiers used in
    special substitution rules.  */
 typedef enum
@@ -187,10 +178,13 @@ static void write_template_prefix (const tree);
 static void write_unqualified_name (const tree);
 static void write_conversion_operator_name (const tree);
 static void write_source_name (tree);
 static void write_unqualified_name (const tree);
 static void write_conversion_operator_name (const tree);
 static void write_source_name (tree);
+static void write_unnamed_type_name (const tree);
+static void write_closure_type_name (const tree);
 static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *,
                           const unsigned int);
 static void write_number (unsigned HOST_WIDE_INT, const int,
                          const unsigned int);
 static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *,
                           const unsigned int);
 static void write_number (unsigned HOST_WIDE_INT, const int,
                          const unsigned int);
+static void write_compact_number (int num);
 static void write_integer_cst (const tree);
 static void write_real_cst (const tree);
 static void write_identifier (const char *);
 static void write_integer_cst (const tree);
 static void write_real_cst (const tree);
 static void write_identifier (const char *);
@@ -216,13 +210,14 @@ static void write_substitution (const int);
 static int discriminator_for_local_entity (tree);
 static int discriminator_for_string_literal (tree, tree);
 static void write_discriminator (const int);
 static int discriminator_for_local_entity (tree);
 static int discriminator_for_string_literal (tree, tree);
 static void write_discriminator (const int);
-static void write_local_name (const tree, const tree, const tree);
+static void write_local_name (tree, const tree, const tree);
 static void dump_substitution_candidates (void);
 static void dump_substitution_candidates (void);
-static const char *mangle_decl_string (const tree);
+static tree mangle_decl_string (const tree);
+static int local_class_index (tree);
 
 /* Control functions.  */
 
 
 /* Control functions.  */
 
-static inline void start_mangling (const tree, bool);
+static inline void start_mangling (const tree);
 static inline const char *finish_mangling (const bool);
 static tree mangle_special_for_type (const tree, const char *);
 
 static inline const char *finish_mangling (const bool);
 static tree mangle_special_for_type (const tree, const char *);
 
@@ -260,42 +255,6 @@ static void write_java_integer_type_codes (const tree);
 #define write_unsigned_number(NUMBER)                                  \
   write_number ((NUMBER), /*unsigned_p=*/1, 10)
 
 #define write_unsigned_number(NUMBER)                                  \
   write_number ((NUMBER), /*unsigned_p=*/1, 10)
 
-/* Save the current (incomplete) mangled name and release the obstack
-   storage holding it.  This function should be used during mangling
-   when making a call that could result in a call to get_identifier,
-   as such a call will clobber the same obstack being used for
-   mangling.  This function may not be called twice without an
-   intervening call to restore_partially_mangled_name.  */
-
-static void
-save_partially_mangled_name (void)
-{
-  if (mangle_obstack == &ident_hash->stack)
-    {
-      gcc_assert (!partially_mangled_name);
-      partially_mangled_name_len = obstack_object_size (mangle_obstack);
-      partially_mangled_name = XNEWVEC (char, partially_mangled_name_len);
-      memcpy (partially_mangled_name, obstack_base (mangle_obstack),
-             partially_mangled_name_len);
-      obstack_free (mangle_obstack, obstack_finish (mangle_obstack));
-    }
-}
-
-/* Restore the incomplete mangled name saved with
-   save_partially_mangled_name.  */
-
-static void
-restore_partially_mangled_name (void)
-{
-  if (partially_mangled_name)
-    {
-      obstack_grow (mangle_obstack, partially_mangled_name,
-                   partially_mangled_name_len);
-      free (partially_mangled_name);
-      partially_mangled_name = NULL;
-    }
-}
-
 /* 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.  */
 /* 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.  */
@@ -383,9 +342,14 @@ canonicalize_for_substitution (tree node)
   /* For a TYPE_DECL, use the type instead.  */
   if (TREE_CODE (node) == TYPE_DECL)
     node = TREE_TYPE (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);
-
+  if (TYPE_P (node)
+      && TYPE_CANONICAL (node) != node
+      && TYPE_MAIN_VARIANT (node) != node)
+      /* Here we want to strip the topmost typedef only.
+         We need to do that so is_std_substitution can do proper
+         name matching.  */
+    node = cp_build_qualified_type (TYPE_MAIN_VARIANT (node),
+                                    cp_type_quals (node));
   return node;
 }
 
   return node;
 }
 
@@ -744,9 +708,7 @@ write_encoding (const tree decl)
 
       if (decl_is_template_id (decl, NULL))
        {
 
       if (decl_is_template_id (decl, NULL))
        {
-         save_partially_mangled_name ();
          fn_type = get_mostly_instantiated_function_type (decl);
          fn_type = get_mostly_instantiated_function_type (decl);
-         restore_partially_mangled_name ();
          /* FN_TYPE will not have parameter types for in-charge or
             VTT parameters.  Therefore, we pass NULL_TREE to
             write_bare_function_type -- otherwise, it will get
          /* FN_TYPE will not have parameter types for in-charge or
             VTT parameters.  Therefore, we pass NULL_TREE to
             write_bare_function_type -- otherwise, it will get
@@ -768,6 +730,22 @@ write_encoding (const tree decl)
     }
 }
 
     }
 }
 
+/* Lambdas can have a bit more context for mangling, specifically VAR_DECL
+   or PARM_DECL context, which doesn't belong in DECL_CONTEXT.  */
+
+static tree
+decl_mangling_context (tree decl)
+{
+  if (TREE_CODE (decl) == TYPE_DECL
+      && LAMBDA_TYPE_P (TREE_TYPE (decl)))
+    {
+      tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl));
+      if (extra)
+       return extra;
+    }
+  return CP_DECL_CONTEXT (decl);
+}
+
 /* <name> ::= <unscoped-name>
          ::= <unscoped-template-name> <template-args>
          ::= <nested-name>
 /* <name> ::= <unscoped-name>
          ::= <unscoped-template-name> <template-args>
          ::= <nested-name>
@@ -791,10 +769,9 @@ write_name (tree decl, const int ignore_local_scope)
       /* 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)));
       /* 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);
+
+  context = decl_mangling_context (decl);
 
   /* A decl in :: or ::std scope is treated specially.  The former is
      mangled using <unscoped-name> or <unscoped-template-name>, the
 
   /* A decl in :: or ::std scope is treated specially.  The former is
      mangled using <unscoped-name> or <unscoped-template-name>, the
@@ -838,7 +815,8 @@ write_name (tree decl, const int ignore_local_scope)
              if (context != NULL && TYPE_P (context))
                context = TYPE_NAME (context);
              /* Is this a function?  */
              if (context != NULL && TYPE_P (context))
                context = TYPE_NAME (context);
              /* Is this a function?  */
-             if (TREE_CODE (context) == FUNCTION_DECL)
+             if (TREE_CODE (context) == FUNCTION_DECL
+                 || TREE_CODE (context) == PARM_DECL)
                {
                  /* Yes, we have local scope.  Use the <local-name>
                     production for the innermost function scope.  */
                {
                  /* Yes, we have local scope.  Use the <local-name>
                     production for the innermost function scope.  */
@@ -847,7 +825,7 @@ write_name (tree decl, const int ignore_local_scope)
                }
              /* Up one scope level.  */
              local_entity = context;
                }
              /* Up one scope level.  */
              local_entity = context;
-             context = CP_DECL_CONTEXT (context);
+             context = decl_mangling_context (context);
            }
 
          /* No local scope found?  Fall through to <nested-name>.  */
            }
 
          /* No local scope found?  Fall through to <nested-name>.  */
@@ -879,7 +857,7 @@ write_unscoped_name (const tree decl)
       /* If not, it should be either in the global namespace, or directly
         in a local function scope.  */
       gcc_assert (context == global_namespace
       /* If not, it should be either in the global namespace, or directly
         in a local function scope.  */
       gcc_assert (context == global_namespace
-                 || context == NULL
+                 || context != NULL
                  || TREE_CODE (context) == FUNCTION_DECL);
 
       write_unqualified_name (decl);
                  || TREE_CODE (context) == FUNCTION_DECL);
 
       write_unqualified_name (decl);
@@ -933,6 +911,20 @@ write_nested_name (const tree decl)
       write_template_prefix (decl);
       write_template_args (TI_ARGS (template_info));
     }
       write_template_prefix (decl);
       write_template_args (TI_ARGS (template_info));
     }
+  else if (TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
+    {
+      tree name = TYPENAME_TYPE_FULLNAME (TREE_TYPE (decl));
+      if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+       {
+         write_template_prefix (decl);
+         write_template_args (TREE_OPERAND (name, 1));
+       }
+      else
+       {
+         write_prefix (CP_DECL_CONTEXT (decl));
+         write_unqualified_name (decl);
+       }
+    }
   else
     {
       /* No, just use <prefix>  */
   else
     {
       /* No, just use <prefix>  */
@@ -955,23 +947,24 @@ write_prefix (const tree node)
   /* Non-NULL if NODE represents a template-id.  */
   tree template_info = NULL;
 
   /* Non-NULL if NODE represents a template-id.  */
   tree template_info = NULL;
 
-  MANGLE_TRACE_TREE ("prefix", node);
-
   if (node == NULL
       || node == global_namespace)
     return;
 
   if (node == NULL
       || node == global_namespace)
     return;
 
+  MANGLE_TRACE_TREE ("prefix", node);
+
   if (find_substitution (node))
     return;
 
   if (DECL_P (node))
     {
   if (find_substitution (node))
     return;
 
   if (DECL_P (node))
     {
-      /* If this is a function decl, that means we've hit function
+      /* If this is a function or parm 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.  */
         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)
+      if (TREE_CODE (node) == FUNCTION_DECL
+         || TREE_CODE (node) == PARM_DECL)
        return;
 
       decl = node;
        return;
 
       decl = node;
@@ -999,11 +992,32 @@ write_prefix (const tree node)
       write_template_prefix (decl);
       write_template_args (TI_ARGS (template_info));
     }
       write_template_prefix (decl);
       write_template_args (TI_ARGS (template_info));
     }
+  else if (TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
+    {
+      tree name = TYPENAME_TYPE_FULLNAME (TREE_TYPE (decl));
+      if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+       {
+         write_template_prefix (decl);
+         write_template_args (TREE_OPERAND (name, 1));
+       }
+      else
+       {
+         write_prefix (CP_DECL_CONTEXT (decl));
+         write_unqualified_name (decl);
+       }
+    }
   else
     /* Not templated.  */
     {
   else
     /* Not templated.  */
     {
-      write_prefix (CP_DECL_CONTEXT (decl));
+      write_prefix (decl_mangling_context (decl));
       write_unqualified_name (decl);
       write_unqualified_name (decl);
+      if (TREE_CODE (decl) == VAR_DECL
+         || TREE_CODE (decl) == FIELD_DECL)
+       {
+         /* <data-member-prefix> := <member source-name> M */
+         write_char ('M');
+         return;
+       }
     }
 
   add_substitution (node);
     }
 
   add_substitution (node);
@@ -1020,19 +1034,22 @@ write_template_prefix (const tree node)
   tree type = DECL_P (node) ? TREE_TYPE (node) : node;
   tree context = CP_DECL_CONTEXT (decl);
   tree template_info;
   tree type = DECL_P (node) ? TREE_TYPE (node) : node;
   tree context = CP_DECL_CONTEXT (decl);
   tree template_info;
-  tree template;
+  tree templ;
   tree substitution;
 
   MANGLE_TRACE_TREE ("template-prefix", node);
 
   /* Find the template decl.  */
   if (decl_is_template_id (decl, &template_info))
   tree substitution;
 
   MANGLE_TRACE_TREE ("template-prefix", node);
 
   /* Find the template decl.  */
   if (decl_is_template_id (decl, &template_info))
-    template = TI_TEMPLATE (template_info);
+    templ = TI_TEMPLATE (template_info);
+  else if (TREE_CODE (type) == TYPENAME_TYPE)
+    /* For a typename type, all we have is the name.  */
+    templ = DECL_NAME (decl);
   else
     {
       gcc_assert (CLASSTYPE_TEMPLATE_ID_P (type));
 
   else
     {
       gcc_assert (CLASSTYPE_TEMPLATE_ID_P (type));
 
-      template = TYPE_TI_TEMPLATE (type);
+      templ = TYPE_TI_TEMPLATE (type);
     }
 
   /* For a member template, though, the template name for the
     }
 
   /* For a member template, though, the template name for the
@@ -1058,21 +1075,23 @@ write_template_prefix (const tree node)
      substitution candidate by a TREE_LIST whose purpose is `Outer<int>'
      and whose value is `Outer<T>::Inner<U>'.  */
   if (TYPE_P (context))
      substitution candidate by a TREE_LIST whose purpose is `Outer<int>'
      and whose value is `Outer<T>::Inner<U>'.  */
   if (TYPE_P (context))
-    substitution = build_tree_list (context, template);
+    substitution = build_tree_list (context, templ);
   else
   else
-    substitution = template;
+    substitution = templ;
 
   if (find_substitution (substitution))
     return;
 
   /* In G++ 3.2, the name of the template template parameter was used.  */
 
   if (find_substitution (substitution))
     return;
 
   /* In G++ 3.2, the name of the template template parameter was used.  */
-  if (TREE_CODE (TREE_TYPE (template)) == TEMPLATE_TEMPLATE_PARM
+  if (TREE_TYPE (templ)
+      && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM
       && !abi_version_at_least (2))
     G.need_abi_warning = true;
 
       && !abi_version_at_least (2))
     G.need_abi_warning = true;
 
-  if (TREE_CODE (TREE_TYPE (template)) == TEMPLATE_TEMPLATE_PARM
+  if (TREE_TYPE (templ)
+      && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM
       && abi_version_at_least (2))
       && abi_version_at_least (2))
-    write_template_param (TREE_TYPE (template));
+    write_template_param (TREE_TYPE (templ));
   else
     {
       write_prefix (context);
   else
     {
       write_prefix (context);
@@ -1088,6 +1107,7 @@ write_template_prefix (const tree node)
     <unqualified-name>  ::= <operator-name>
                        ::= <special-name>
                        ::= <source-name>
     <unqualified-name>  ::= <operator-name>
                        ::= <special-name>
                        ::= <source-name>
+                       ::= <unnamed-type-name>
                        ::= <local-source-name> 
 
     <local-source-name>        ::= L <source-name> <discriminator> */
                        ::= <local-source-name> 
 
     <local-source-name>        ::= L <source-name> <discriminator> */
@@ -1097,42 +1117,54 @@ write_unqualified_name (const tree decl)
 {
   MANGLE_TRACE_TREE ("unqualified-name", decl);
 
 {
   MANGLE_TRACE_TREE ("unqualified-name", decl);
 
-  if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_CONSTRUCTOR_P (decl))
-    write_special_name_constructor (decl);
-  else if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_DESTRUCTOR_P (decl))
-    write_special_name_destructor (decl);
-  else if (DECL_NAME (decl) == NULL_TREE)
-    write_source_name (DECL_ASSEMBLER_NAME (decl));
-  else if (DECL_CONV_FN_P (decl))
-    {
-      /* Conversion operator. Handle it right here.
-          <operator> ::= cv <type>  */
-      tree type;
-      if (decl_is_template_id (decl, NULL))
-       {
-         tree fn_type;
-         save_partially_mangled_name ();
-         fn_type = get_mostly_instantiated_function_type (decl);
-         restore_partially_mangled_name ();
-         type = TREE_TYPE (fn_type);
-       }
-      else
-       type = DECL_CONV_FN_TYPE (decl);
-      write_conversion_operator_name (type);
+  if (DECL_NAME (decl) == NULL_TREE)
+    {
+      gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
+      write_source_name (DECL_ASSEMBLER_NAME (decl));
+      return;
     }
     }
-  else if (DECL_OVERLOADED_OPERATOR_P (decl))
+  else if (DECL_DECLARES_FUNCTION_P (decl))
     {
     {
-      operator_name_info_t *oni;
-      if (DECL_ASSIGNMENT_OPERATOR_P (decl))
-       oni = assignment_operator_name_info;
+      bool found = true;
+      if (DECL_CONSTRUCTOR_P (decl))
+       write_special_name_constructor (decl);
+      else if (DECL_DESTRUCTOR_P (decl))
+       write_special_name_destructor (decl);
+      else if (DECL_CONV_FN_P (decl))
+       {
+         /* Conversion operator. Handle it right here.
+            <operator> ::= cv <type>  */
+         tree type;
+         if (decl_is_template_id (decl, NULL))
+           {
+             tree fn_type;
+             fn_type = get_mostly_instantiated_function_type (decl);
+             type = TREE_TYPE (fn_type);
+           }
+         else
+           type = DECL_CONV_FN_TYPE (decl);
+         write_conversion_operator_name (type);
+       }
+      else if (DECL_OVERLOADED_OPERATOR_P (decl))
+       {
+         operator_name_info_t *oni;
+         if (DECL_ASSIGNMENT_OPERATOR_P (decl))
+           oni = assignment_operator_name_info;
+         else
+           oni = operator_name_info;
+
+         write_string (oni[DECL_OVERLOADED_OPERATOR_P (decl)].mangled_name);
+       }
       else
       else
-       oni = operator_name_info;
+       found = false;
 
 
-      write_string (oni[DECL_OVERLOADED_OPERATOR_P (decl)].mangled_name);
+      if (found)
+       return;
     }
     }
-  else if (VAR_OR_FUNCTION_DECL_P (decl) && ! TREE_PUBLIC (decl)
-          && DECL_NAMESPACE_SCOPE_P (decl)
-          && decl_linkage (decl) == lk_internal)
+
+  if (VAR_OR_FUNCTION_DECL_P (decl) && ! TREE_PUBLIC (decl)
+      && DECL_NAMESPACE_SCOPE_P (decl)
+      && decl_linkage (decl) == lk_internal)
     {
       MANGLE_TRACE_TREE ("local-source-name", decl);
       write_char ('L');
     {
       MANGLE_TRACE_TREE ("local-source-name", decl);
       write_char ('L');
@@ -1141,7 +1173,18 @@ write_unqualified_name (const tree decl)
         so there's no code to output one here.  */
     }
   else
         so there's no code to output one here.  */
     }
   else
-    write_source_name (DECL_NAME (decl));
+    {
+      tree type = TREE_TYPE (decl);
+
+      if (TREE_CODE (decl) == TYPE_DECL
+          && TYPE_ANONYMOUS_P (type))
+        write_unnamed_type_name (type);
+      else if (TREE_CODE (decl) == TYPE_DECL
+               && LAMBDA_TYPE_P (type))
+        write_closure_type_name (type);
+      else
+        write_source_name (DECL_NAME (decl));
+    }
 }
 
 /* Write the unqualified-name for a conversion operator to TYPE.  */
 }
 
 /* Write the unqualified-name for a conversion operator to TYPE.  */
@@ -1171,6 +1214,78 @@ write_source_name (tree identifier)
   write_identifier (IDENTIFIER_POINTER (identifier));
 }
 
   write_identifier (IDENTIFIER_POINTER (identifier));
 }
 
+/* Encode 0 as _, and 1+ as n-1_.  */
+
+static void
+write_compact_number (int num)
+{
+  if (num > 0)
+    write_unsigned_number (num - 1);
+  write_char ('_');
+}
+
+/* Return how many unnamed types precede TYPE in its enclosing class.  */
+
+static int
+nested_anon_class_index (tree type)
+{
+  int index = 0;
+  tree member = TYPE_FIELDS (TYPE_CONTEXT (type));
+  for (; member; member = TREE_CHAIN (member))
+    if (DECL_IMPLICIT_TYPEDEF_P (member))
+      {
+       tree memtype = TREE_TYPE (member);
+       if (memtype == type)
+         return index;
+       else if (TYPE_ANONYMOUS_P (memtype))
+         ++index;
+      }
+
+  gcc_unreachable ();
+}
+
+/* <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ */
+
+static void
+write_unnamed_type_name (const tree type __attribute__ ((__unused__)))
+{
+  int discriminator;
+  MANGLE_TRACE_TREE ("unnamed-type-name", type);
+
+  if (TYPE_FUNCTION_SCOPE_P (type))
+    discriminator = local_class_index (type);
+  else if (TYPE_CLASS_SCOPE_P (type))
+    discriminator = nested_anon_class_index (type);
+  else
+    {
+      gcc_assert (no_linkage_check (type, /*relaxed_p=*/true));
+      /* Just use the old mangling at namespace scope.  */
+      write_source_name (TYPE_IDENTIFIER (type));
+      return;
+    }
+
+  write_string ("Ut");
+  write_compact_number (discriminator);
+}
+
+/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+   <lambda-sig> ::= <parameter type>+  # Parameter types or "v" if the lambda has no parameters */
+
+static void
+write_closure_type_name (const tree type)
+{
+  tree fn = lambda_function (type);
+  tree lambda = CLASSTYPE_LAMBDA_EXPR (type);
+  tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+
+  MANGLE_TRACE_TREE ("closure-type-name", type);
+
+  write_string ("Ul");
+  write_method_parms (parms, DECL_NONSTATIC_MEMBER_FUNCTION_P (fn), fn);
+  write_char ('E');
+  write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda));
+}
+
 /* 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
 /* 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
@@ -1261,16 +1376,16 @@ write_integer_cst (const tree cst)
       if (sign < 0)
        {
          write_char ('n');
       if (sign < 0)
        {
          write_char ('n');
-         n = fold_build1 (NEGATE_EXPR, type, n);
+         n = fold_build1_loc (input_location, NEGATE_EXPR, type, n);
        }
       do
        {
        }
       do
        {
-         tree d = fold_build2 (FLOOR_DIV_EXPR, type, n, base);
-         tree tmp = fold_build2 (MULT_EXPR, type, d, base);
+         tree d = fold_build2_loc (input_location, FLOOR_DIV_EXPR, type, n, base);
+         tree tmp = fold_build2_loc (input_location, MULT_EXPR, type, d, base);
          unsigned c;
 
          done = integer_zerop (d);
          unsigned c;
 
          done = integer_zerop (d);
-         tmp = fold_build2 (MINUS_EXPR, type, n, tmp);
+         tmp = fold_build2_loc (input_location, MINUS_EXPR, type, n, tmp);
          c = hwint_to_ascii (TREE_INT_CST_LOW (tmp), 10, ptr,
                              done ? 1 : chunk_digits);
          ptr -= c;
          c = hwint_to_ascii (TREE_INT_CST_LOW (tmp), 10, ptr,
                              done ? 1 : chunk_digits);
          ptr -= c;
@@ -1340,7 +1455,7 @@ write_real_cst (const tree value)
 
       for (; i != limit; i += dir)
        {
 
       for (; i != limit; i += dir)
        {
-         sprintf (buffer, "%08lx", target_real[i]);
+         sprintf (buffer, "%08lx", (unsigned long) target_real[i]);
          write_chars (buffer, 8);
        }
     }
          write_chars (buffer, 8);
        }
     }
@@ -1430,6 +1545,29 @@ write_special_name_destructor (const tree dtor)
     }
 }
 
     }
 }
 
+/* Scan the vector of local classes and return how many others with the
+   same name (or same no name) and context precede ENTITY.  */
+
+static int
+local_class_index (tree entity)
+{
+  int ix, discriminator = 0;
+  tree name = (TYPE_ANONYMOUS_P (entity) ? NULL_TREE
+              : TYPE_IDENTIFIER (entity));
+  tree ctx = TYPE_CONTEXT (entity);
+  for (ix = 0; ; ix++)
+    {
+      tree type = VEC_index (tree, local_classes, ix);
+      if (type == entity)
+       return discriminator;
+      if (TYPE_CONTEXT (type) == ctx
+         && (name ? TYPE_IDENTIFIER (type) == name
+             : TYPE_ANONYMOUS_P (type)))
+       ++discriminator;
+    }
+  gcc_unreachable ();
+}
+
 /* Return the discriminator for ENTITY appearing inside
    FUNCTION.  The discriminator is the lexical ordinal of VAR among
    entities with the same name in the same FUNCTION.  */
 /* Return the discriminator for ENTITY appearing inside
    FUNCTION.  The discriminator is the lexical ordinal of VAR among
    entities with the same name in the same FUNCTION.  */
@@ -1437,29 +1575,28 @@ write_special_name_destructor (const tree dtor)
 static int
 discriminator_for_local_entity (tree entity)
 {
 static int
 discriminator_for_local_entity (tree entity)
 {
-  /* Assume this is the only local entity with this name.  */
-  int discriminator = 0;
-
-  if (DECL_DISCRIMINATOR_P (entity) && DECL_LANG_SPECIFIC (entity))
-    discriminator = DECL_DISCRIMINATOR (entity);
+  if (DECL_DISCRIMINATOR_P (entity))
+    {
+      if (DECL_LANG_SPECIFIC (entity))
+       return DECL_DISCRIMINATOR (entity);
+      else
+       /* The first entity with a particular name doesn't get
+          DECL_LANG_SPECIFIC/DECL_DISCRIMINATOR.  */
+       return 0;
+    }
   else if (TREE_CODE (entity) == TYPE_DECL)
     {
   else if (TREE_CODE (entity) == TYPE_DECL)
     {
-      int ix;
-
       /* Scan the list of local classes.  */
       entity = TREE_TYPE (entity);
       /* Scan the list of local classes.  */
       entity = TREE_TYPE (entity);
-      for (ix = 0; ; ix++)
-       {
-         tree type = VEC_index (tree, local_classes, ix);
-         if (type == entity)
-           break;
-         if (TYPE_IDENTIFIER (type) == TYPE_IDENTIFIER (entity)
-             && TYPE_CONTEXT (type) == TYPE_CONTEXT (entity))
-           ++discriminator;
-       }
-    }
 
 
-  return discriminator;
+      /* Lambdas and unnamed types have their own discriminators.  */
+      if (LAMBDA_TYPE_P (entity) || TYPE_ANONYMOUS_P (entity))
+       return 0;
+
+      return local_class_index (entity);
+    }
+  else
+    gcc_unreachable ();
 }
 
 /* Return the discriminator for STRING, a string literal used inside
 }
 
 /* Return the discriminator for STRING, a string literal used inside
@@ -1492,23 +1629,49 @@ write_discriminator (const int discriminator)
 }
 
 /* Mangle the name of a function-scope entity.  FUNCTION is the
 }
 
 /* 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.  LOCAL_ENTITY is the entity that's directly
-   scoped in FUNCTION_DECL, either ENTITY itself or an enclosing scope
-   of ENTITY.
+   FUNCTION_DECL for the enclosing function, or a PARM_DECL for lambdas in
+   default argument scope.  ENTITY is the decl for 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>]
 
      <local-name> := Z <function encoding> E <entity name> [<discriminator>]
-                 := Z <function encoding> E s [<discriminator>]  */
+                 := Z <function encoding> E s [<discriminator>]
+                 := Z <function encoding> Ed [ <parameter number> ] _ <entity name> */
 
 static void
 
 static void
-write_local_name (const tree function, const tree local_entity,
+write_local_name (tree function, const tree local_entity,
                  const tree entity)
 {
                  const tree entity)
 {
+  tree parm = NULL_TREE;
+
   MANGLE_TRACE_TREE ("local-name", entity);
 
   MANGLE_TRACE_TREE ("local-name", entity);
 
+  if (TREE_CODE (function) == PARM_DECL)
+    {
+      parm = function;
+      function = DECL_CONTEXT (parm);
+    }
+
   write_char ('Z');
   write_encoding (function);
   write_char ('E');
   write_char ('Z');
   write_encoding (function);
   write_char ('E');
+
+  /* For this purpose, parameters are numbered from right-to-left.  */
+  if (parm)
+    {
+      tree t;
+      int i = 0;
+      for (t = DECL_ARGUMENTS (function); t; t = TREE_CHAIN (t))
+       {
+         if (t == parm)
+           i = 1;
+         else if (i)
+           ++i;
+       }
+      write_char ('d');
+      write_compact_number (i - 1);
+    }
+
   if (TREE_CODE (entity) == STRING_CST)
     {
       write_char ('s');
   if (TREE_CODE (entity) == STRING_CST)
     {
       write_char ('s');
@@ -1541,6 +1704,13 @@ write_local_name (const tree function, const tree local_entity,
            ::= G <type>    # imaginary (C 2000)     [not supported]
            ::= U <source-name> <type>   # vendor extended type qualifier
 
            ::= G <type>    # imaginary (C 2000)     [not supported]
            ::= U <source-name> <type>   # vendor extended type qualifier
 
+   C++0x extensions
+
+     <type> ::= RR <type>   # rvalue reference-to
+     <type> ::= Dt <expression> # decltype of an id-expression or 
+                                # class member access
+     <type> ::= DT <expression> # decltype of an expression
+
    TYPE is a type node.  */
 
 static void
    TYPE is a type node.  */
 
 static void
@@ -1571,101 +1741,137 @@ write_type (tree type)
     write_array_type (type);
   else
     {
     write_array_type (type);
   else
     {
+      tree type_orig = type;
+
       /* See through any typedefs.  */
       type = TYPE_MAIN_VARIANT (type);
 
       if (TYPE_PTRMEM_P (type))
        write_pointer_to_member_type (type);
       /* See through any typedefs.  */
       type = TYPE_MAIN_VARIANT (type);
 
       if (TYPE_PTRMEM_P (type))
        write_pointer_to_member_type (type);
-      else switch (TREE_CODE (type))
-       {
-       case VOID_TYPE:
-       case BOOLEAN_TYPE:
-       case INTEGER_TYPE:  /* Includes wchar_t.  */
-       case REAL_TYPE:
-       {
+      else
+        {
          /* Handle any target-specific fundamental types.  */
          const char *target_mangling
          /* Handle any target-specific fundamental types.  */
          const char *target_mangling
-           = targetm.mangle_fundamental_type (type);
+           = targetm.mangle_type (type_orig);
 
          if (target_mangling)
            {
              write_string (target_mangling);
 
          if (target_mangling)
            {
              write_string (target_mangling);
+             /* Add substitutions for types other than fundamental
+                types.  */
+             if (TREE_CODE (type) != VOID_TYPE
+                 && TREE_CODE (type) != INTEGER_TYPE
+                 && TREE_CODE (type) != REAL_TYPE
+                 && TREE_CODE (type) != BOOLEAN_TYPE)
+               add_substitution (type);
              return;
            }
 
              return;
            }
 
-         /* If this is a typedef, TYPE may not be one of
-            the standard builtin type nodes, but an alias of one.  Use
-            TYPE_MAIN_VARIANT to get to the underlying builtin type.  */
-         write_builtin_type (TYPE_MAIN_VARIANT (type));
-         ++is_builtin_type;
-         break;
-       }
-
-       case COMPLEX_TYPE:
-         write_char ('C');
-         write_type (TREE_TYPE (type));
-         break;
-
-       case FUNCTION_TYPE:
-       case METHOD_TYPE:
-         write_function_type (type);
-         break;
-
-       case UNION_TYPE:
-       case RECORD_TYPE:
-       case ENUMERAL_TYPE:
-         /* A pointer-to-member function is represented as a special
-            RECORD_TYPE, so check for this first.  */
-         if (TYPE_PTRMEMFUNC_P (type))
-           write_pointer_to_member_type (type);
-         else
-           write_class_enum_type (type);
-         break;
-
-       case TYPENAME_TYPE:
-       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 POINTER_TYPE:
-         write_char ('P');
-         write_type (TREE_TYPE (type));
-         break;
-
-       case REFERENCE_TYPE:
-         write_char ('R');
-         write_type (TREE_TYPE (type));
-         break;
-
-       case TEMPLATE_TYPE_PARM:
-       case TEMPLATE_PARM_INDEX:
-         write_template_param (type);
-         break;
-
-       case TEMPLATE_TEMPLATE_PARM:
-         write_template_template_param (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 VECTOR_TYPE:
-         write_string ("U8__vector");
-         write_type (TREE_TYPE (type));
-         break;
-
-        case TYPE_PACK_EXPANSION:
-          write_string ("U10__variadic");
-          write_type (PACK_EXPANSION_PATTERN (type));
-          break;
-
-       default:
-         gcc_unreachable ();
+         switch (TREE_CODE (type))
+           {
+           case VOID_TYPE:
+           case BOOLEAN_TYPE:
+           case INTEGER_TYPE:  /* Includes wchar_t.  */
+           case REAL_TYPE:
+           case FIXED_POINT_TYPE:
+             {
+               /* If this is a typedef, TYPE may not be one of
+                  the standard builtin type nodes, but an alias of one.  Use
+                  TYPE_MAIN_VARIANT to get to the underlying builtin type.  */
+               write_builtin_type (TYPE_MAIN_VARIANT (type));
+               ++is_builtin_type;
+             }
+             break;
+
+           case COMPLEX_TYPE:
+             write_char ('C');
+             write_type (TREE_TYPE (type));
+             break;
+
+           case FUNCTION_TYPE:
+           case METHOD_TYPE:
+             write_function_type (type);
+             break;
+
+           case UNION_TYPE:
+           case RECORD_TYPE:
+           case ENUMERAL_TYPE:
+             /* A pointer-to-member function is represented as a special
+                RECORD_TYPE, so check for this first.  */
+             if (TYPE_PTRMEMFUNC_P (type))
+               write_pointer_to_member_type (type);
+             else
+               write_class_enum_type (type);
+             break;
+
+           case TYPENAME_TYPE:
+           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 POINTER_TYPE:
+             write_char ('P');
+             write_type (TREE_TYPE (type));
+             break;
+
+           case REFERENCE_TYPE:
+             if (TYPE_REF_IS_RVALUE (type))
+               write_char('O');
+              else
+                write_char ('R');
+             write_type (TREE_TYPE (type));
+             break;
+
+           case TEMPLATE_TYPE_PARM:
+           case TEMPLATE_PARM_INDEX:
+             write_template_param (type);
+             break;
+
+           case TEMPLATE_TEMPLATE_PARM:
+             write_template_template_param (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 VECTOR_TYPE:
+             write_string ("U8__vector");
+             write_type (TREE_TYPE (type));
+             break;
+
+            case TYPE_PACK_EXPANSION:
+              write_string ("Dp");
+              write_type (PACK_EXPANSION_PATTERN (type));
+              break;
+
+            case DECLTYPE_TYPE:
+             /* These shouldn't make it into mangling.  */
+             gcc_assert (!DECLTYPE_FOR_LAMBDA_CAPTURE (type)
+                         && !DECLTYPE_FOR_LAMBDA_RETURN (type));
+
+              write_char ('D');
+              if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
+                write_char ('t');
+              else
+                write_char ('T');
+             ++cp_unevaluated_operand;
+              write_expression (DECLTYPE_TYPE_EXPR (type));
+             --cp_unevaluated_operand;
+              write_char ('E');
+              break;
+
+           case TYPEOF_TYPE:
+             sorry ("mangling typeof, use decltype instead");
+             break;
+
+           default:
+             gcc_unreachable ();
+           }
        }
     }
 
        }
     }
 
@@ -1740,6 +1946,9 @@ write_CV_qualifiers_for_type (const tree type)
 static void
 write_builtin_type (tree type)
 {
 static void
 write_builtin_type (tree type)
 {
+  if (TYPE_CANONICAL (type))
+    type = TYPE_CANONICAL (type);
+
   switch (TREE_CODE (type))
     {
     case VOID_TYPE:
   switch (TREE_CODE (type))
     {
     case VOID_TYPE:
@@ -1751,10 +1960,14 @@ write_builtin_type (tree type)
       break;
 
     case INTEGER_TYPE:
       break;
 
     case INTEGER_TYPE:
-      /* TYPE may still be wchar_t, since that isn't in
-        integer_type_nodes.  */
+      /* TYPE may still be wchar_t, char16_t, or char32_t, since that
+        isn't in integer_type_nodes.  */
       if (type == wchar_type_node)
        write_char ('w');
       if (type == wchar_type_node)
        write_char ('w');
+      else if (type == char16_type_node)
+       write_string ("Ds");
+      else if (type == char32_type_node)
+       write_string ("Di");
       else if (TYPE_FOR_JAVA (type))
        write_java_integer_type_codes (type);
       else
       else if (TYPE_FOR_JAVA (type))
        write_java_integer_type_codes (type);
       else
@@ -1817,10 +2030,69 @@ write_builtin_type (tree type)
        write_char ('d');
       else if (type == long_double_type_node)
        write_char ('e');
        write_char ('d');
       else if (type == long_double_type_node)
        write_char ('e');
+      else if (type == dfloat32_type_node)
+       write_string ("Df");
+      else if (type == dfloat64_type_node)
+       write_string ("Dd");
+      else if (type == dfloat128_type_node)
+       write_string ("De");
       else
        gcc_unreachable ();
       break;
 
       else
        gcc_unreachable ();
       break;
 
+    case FIXED_POINT_TYPE:
+      write_string ("DF");
+      if (GET_MODE_IBIT (TYPE_MODE (type)) > 0)
+       write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type)));
+      if (type == fract_type_node
+         || type == sat_fract_type_node
+         || type == accum_type_node
+         || type == sat_accum_type_node)
+       write_char ('i');
+      else if (type == unsigned_fract_type_node
+              || type == sat_unsigned_fract_type_node
+              || type == unsigned_accum_type_node
+              || type == sat_unsigned_accum_type_node)
+       write_char ('j');
+      else if (type == short_fract_type_node
+              || type == sat_short_fract_type_node
+              || type == short_accum_type_node
+              || type == sat_short_accum_type_node)
+       write_char ('s');
+      else if (type == unsigned_short_fract_type_node
+              || type == sat_unsigned_short_fract_type_node
+              || type == unsigned_short_accum_type_node
+              || type == sat_unsigned_short_accum_type_node)
+       write_char ('t');
+      else if (type == long_fract_type_node
+              || type == sat_long_fract_type_node
+              || type == long_accum_type_node
+              || type == sat_long_accum_type_node)
+       write_char ('l');
+      else if (type == unsigned_long_fract_type_node
+              || type == sat_unsigned_long_fract_type_node
+              || type == unsigned_long_accum_type_node
+              || type == sat_unsigned_long_accum_type_node)
+       write_char ('m');
+      else if (type == long_long_fract_type_node
+              || type == sat_long_long_fract_type_node
+              || type == long_long_accum_type_node
+              || type == sat_long_long_accum_type_node)
+       write_char ('x');
+      else if (type == unsigned_long_long_fract_type_node
+              || type == sat_unsigned_long_long_fract_type_node
+              || type == unsigned_long_long_accum_type_node
+              || type == sat_unsigned_long_long_accum_type_node)
+       write_char ('y');
+      else
+       sorry ("mangling unknown fixed point type");
+      write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type)));
+      if (TYPE_SATURATING (type))
+       write_char ('s');
+      else
+       write_char ('n');
+      break;
+
     default:
       gcc_unreachable ();
     }
     default:
       gcc_unreachable ();
     }
@@ -1984,21 +2256,22 @@ write_class_enum_type (const tree type)
 /* Non-terminal <template-args>.  ARGS is a TREE_VEC of template
    arguments.
 
 /* Non-terminal <template-args>.  ARGS is a TREE_VEC of template
    arguments.
 
-     <template-args> ::= I <template-arg>+ E  */
+     <template-args> ::= I <template-arg>* E  */
 
 static void
 write_template_args (tree args)
 {
   int i;
 
 static void
 write_template_args (tree args)
 {
   int i;
-  int length = TREE_VEC_LENGTH (args);
+  int length = 0;
 
   MANGLE_TRACE_TREE ("template-args", args);
 
   write_char ('I');
 
 
   MANGLE_TRACE_TREE ("template-args", args);
 
   write_char ('I');
 
-  gcc_assert (length > 0);
+  if (args)
+    length = TREE_VEC_LENGTH (args);
 
 
-  if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+  if (args && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
     {
       /* We have nested template args.  We want the innermost template
         argument list.  */
     {
       /* We have nested template args.  We want the innermost template
         argument list.  */
@@ -2011,6 +2284,35 @@ write_template_args (tree args)
   write_char ('E');
 }
 
   write_char ('E');
 }
 
+/* Write out the
+   <unqualified-name>
+   <unqualified-name> <template-args>
+   part of SCOPE_REF or COMPONENT_REF mangling.  */
+
+static void
+write_member_name (tree member)
+{
+  if (TREE_CODE (member) == IDENTIFIER_NODE)
+    write_source_name (member);
+  else if (DECL_P (member))
+    {
+      /* G++ 3.2 incorrectly put out both the "sr" code and
+        the nested name of the qualified name.  */
+      G.need_abi_warning = 1;
+      write_unqualified_name (member);
+    }
+  else if (TREE_CODE (member) == TEMPLATE_ID_EXPR)
+    {
+      tree name = TREE_OPERAND (member, 0);
+      if (TREE_CODE (name) == OVERLOAD)
+       name = OVL_FUNCTION (name);
+      write_member_name (name);
+      write_template_args (TREE_OPERAND (member, 1));
+    }
+  else
+    write_expression (member);
+}
+
 /* <expression> ::= <unary operator-name> <expression>
                ::= <binary operator-name> <expression> <expression>
                ::= <expr-primary>
 /* <expression> ::= <unary operator-name> <expression>
                ::= <binary operator-name> <expression> <expression>
                ::= <expr-primary>
@@ -2018,15 +2320,14 @@ write_template_args (tree args)
    <expr-primary> ::= <template-param>
                  ::= L <type> <value number> E         # literal
                  ::= L <mangled-name> E                # external name
    <expr-primary> ::= <template-param>
                  ::= L <type> <value number> E         # literal
                  ::= L <mangled-name> E                # external name
-                 ::= sr <type> <unqualified-name>
+                 ::= st <type>                         # sizeof
+                 ::= sr <type> <unqualified-name>      # dependent name
                  ::= sr <type> <unqualified-name> <template-args> */
 
 static void
 write_expression (tree expr)
 {
                  ::= sr <type> <unqualified-name> <template-args> */
 
 static void
 write_expression (tree expr)
 {
-  enum tree_code code;
-
-  code = TREE_CODE (expr);
+  enum tree_code code = TREE_CODE (expr);
 
   /* Skip NOP_EXPRs.  They can occur when (say) a pointer argument
      is converted (via qualification conversions) to another
 
   /* Skip NOP_EXPRs.  They can occur when (say) a pointer argument
      is converted (via qualification conversions) to another
@@ -2066,6 +2367,14 @@ write_expression (tree expr)
   else if (TREE_CODE_CLASS (code) == tcc_constant
           || (abi_version_at_least (2) && code == CONST_DECL))
     write_template_arg_literal (expr);
   else if (TREE_CODE_CLASS (code) == tcc_constant
           || (abi_version_at_least (2) && code == CONST_DECL))
     write_template_arg_literal (expr);
+  else if (code == PARM_DECL)
+    {
+      /* A function parameter used in a late-specified return type.  */
+      int index = DECL_PARM_INDEX (expr);
+      gcc_assert (index >= 1);
+      write_string ("fp");
+      write_compact_number (index - 1);
+    }
   else if (DECL_P (expr))
     {
       /* G++ 3.2 incorrectly mangled non-type template arguments of
   else if (DECL_P (expr))
     {
       /* G++ 3.2 incorrectly mangled non-type template arguments of
@@ -2082,6 +2391,12 @@ write_expression (tree expr)
       write_string ("st");
       write_type (TREE_OPERAND (expr, 0));
     }
       write_string ("st");
       write_type (TREE_OPERAND (expr, 0));
     }
+  else if (TREE_CODE (expr) == ALIGNOF_EXPR
+          && TYPE_P (TREE_OPERAND (expr, 0)))
+    {
+      write_string ("at");
+      write_type (TREE_OPERAND (expr, 0));
+    }
   else if (abi_version_at_least (2) && TREE_CODE (expr) == SCOPE_REF)
     {
       tree scope = TREE_OPERAND (expr, 0);
   else if (abi_version_at_least (2) && TREE_CODE (expr) == SCOPE_REF)
     {
       tree scope = TREE_OPERAND (expr, 0);
@@ -2120,7 +2435,7 @@ write_expression (tree expr)
              /* Unfortunately, there is no easy way to go from the
                 name of the operator back to the corresponding tree
                 code.  */
              /* 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)
+             for (i = 0; i < MAX_TREE_CODES; ++i)
                if (operator_name_info[i].identifier == member)
                  {
                    /* The ABI says that we prefer binary operator
                if (operator_name_info[i].identifier == member)
                  {
                    /* The ABI says that we prefer binary operator
@@ -2149,9 +2464,16 @@ write_expression (tree expr)
            write_template_args (template_args);
        }
     }
            write_template_args (template_args);
        }
     }
+  else if (TREE_CODE (expr) == INDIRECT_REF
+          && TREE_TYPE (TREE_OPERAND (expr, 0))
+          && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
+    {
+      write_expression (TREE_OPERAND (expr, 0));
+    }
   else
     {
       int i;
   else
     {
       int i;
+      const char *name;
 
       /* When we bind a variable or function to a non-type template
         argument with reference type, we create an ADDR_EXPR to show
 
       /* When we bind a variable or function to a non-type template
         argument with reference type, we create an ADDR_EXPR to show
@@ -2171,57 +2493,89 @@ write_expression (tree expr)
          code = TREE_CODE (expr);
        }
 
          code = TREE_CODE (expr);
        }
 
+      if (code == COMPONENT_REF)
+       {
+         tree ob = TREE_OPERAND (expr, 0);
+
+         if (TREE_CODE (ob) == ARROW_EXPR)
+           {
+             write_string (operator_name_info[(int)code].mangled_name);
+             ob = TREE_OPERAND (ob, 0);
+           }
+         else
+           write_string ("dt");
+
+         write_expression (ob);
+         write_member_name (TREE_OPERAND (expr, 1));
+         return;
+       }
+
       /* If it wasn't any of those, recursively expand the expression.  */
       /* If it wasn't any of those, recursively expand the expression.  */
-      write_string (operator_name_info[(int) code].mangled_name);
+      name = operator_name_info[(int) code].mangled_name;
+      if (name == NULL)
+       {
+         sorry ("mangling %C", code);
+         return;
+       }
+      else
+       write_string (name);    
 
       switch (code)
        {
        case CALL_EXPR:
 
       switch (code)
        {
        case CALL_EXPR:
-         sorry ("call_expr cannot be mangled due to a defect in the C++ ABI");
+         {
+           tree fn = CALL_EXPR_FN (expr);
+
+           if (TREE_CODE (fn) == ADDR_EXPR)
+             fn = TREE_OPERAND (fn, 0);
+
+           /* Mangle a dependent name as the name, not whatever happens to
+              be the first function in the overload set.  */
+           if ((TREE_CODE (fn) == FUNCTION_DECL
+                || TREE_CODE (fn) == OVERLOAD)
+               && type_dependent_expression_p_push (expr))
+             fn = DECL_NAME (get_first_fn (fn));
+
+           if (TREE_CODE (fn) == IDENTIFIER_NODE)
+             write_source_name (fn);
+           else
+             write_expression (fn);
+         }
+
+         for (i = 0; i < call_expr_nargs (expr); ++i)
+           write_expression (CALL_EXPR_ARG (expr, i));
+         write_char ('E');
          break;
 
        case CAST_EXPR:
          write_type (TREE_TYPE (expr));
          break;
 
        case CAST_EXPR:
          write_type (TREE_TYPE (expr));
-         /* There is no way to mangle a zero-operand cast like
-            "T()".  */
-         if (!TREE_OPERAND (expr, 0))
-           sorry ("zero-operand casts cannot be mangled due to a defect "
-                  "in the C++ ABI");
-         else
+         if (list_length (TREE_OPERAND (expr, 0)) == 1)          
            write_expression (TREE_VALUE (TREE_OPERAND (expr, 0)));
            write_expression (TREE_VALUE (TREE_OPERAND (expr, 0)));
+         else
+           {
+             tree args = TREE_OPERAND (expr, 0);
+             write_char ('_');
+             for (; args; args = TREE_CHAIN (args))
+               write_expression (TREE_VALUE (args));
+             write_char ('E');
+           }
          break;
 
          break;
 
+         /* FIXME these should have a distinct mangling.  */
        case STATIC_CAST_EXPR:
        case CONST_CAST_EXPR:
          write_type (TREE_TYPE (expr));
          write_expression (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;
 
+       case NEW_EXPR:
+         sorry ("mangling new-expression");
+         break;
 
        /* Handle pointers-to-members specially.  */
        case SCOPE_REF:
          write_type (TREE_OPERAND (expr, 0));
 
        /* 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 if (TREE_CODE (TREE_OPERAND (expr, 1)) == TEMPLATE_ID_EXPR)
-           {
-             tree template_id;
-             tree name;
-
-             template_id = TREE_OPERAND (expr, 1);
-             name = TREE_OPERAND (template_id, 0);
-             /* FIXME: What about operators?  */
-             gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
-             write_source_name (TREE_OPERAND (template_id, 0));
-             write_template_args (TREE_OPERAND (template_id, 1));
-           }
-         else
-           {
-             /* 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));
-           }
+         write_member_name (TREE_OPERAND (expr, 1));
          break;
 
        default:
          break;
 
        default:
@@ -2326,8 +2680,10 @@ write_template_arg (tree node)
       /* Expand the template argument pack. */
       tree args = ARGUMENT_PACK_ARGS (node);
       int i, length = TREE_VEC_LENGTH (args);
       /* Expand the template argument pack. */
       tree args = ARGUMENT_PACK_ARGS (node);
       int i, length = TREE_VEC_LENGTH (args);
+      write_char ('I');
       for (i = 0; i < length; ++i)
         write_template_arg (TREE_VEC_ELT (args, i));
       for (i = 0; i < length; ++i)
         write_template_arg (TREE_VEC_ELT (args, i));
+      write_char ('E');
     }
   else if (TYPE_P (node))
     write_type (node);
     }
   else if (TYPE_P (node))
     write_type (node);
@@ -2480,9 +2836,7 @@ write_template_param (const tree parm)
   write_char ('T');
   /* NUMBER as it appears in the mangling is (-1)-indexed, with the
      earliest template param denoted by `_'.  */
   write_char ('T');
   /* NUMBER as it appears in the mangling is (-1)-indexed, with the
      earliest template param denoted by `_'.  */
-  if (parm_index > 0)
-    write_unsigned_number (parm_index - 1);
-  write_char ('_');
+  write_compact_number (parm_index);
 }
 
 /*  <template-template-param>
 }
 
 /*  <template-template-param>
@@ -2492,24 +2846,24 @@ write_template_param (const tree parm)
 static void
 write_template_template_param (const tree parm)
 {
 static void
 write_template_template_param (const tree parm)
 {
-  tree template = NULL_TREE;
+  tree templ = NULL_TREE;
 
   /* PARM, a TEMPLATE_TEMPLATE_PARM, is an instantiation of the
      template template parameter.  The substitution candidate here is
      only the template.  */
   if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
     {
 
   /* PARM, a TEMPLATE_TEMPLATE_PARM, is an instantiation of the
      template template parameter.  The substitution candidate here is
      only the template.  */
   if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
     {
-      template
+      templ
        = TI_TEMPLATE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm));
        = TI_TEMPLATE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (parm));
-      if (find_substitution (template))
+      if (find_substitution (templ))
        return;
     }
 
   /* <template-param> encodes only the template parameter position,
      not its template arguments, which is fine here.  */
   write_template_param (parm);
        return;
     }
 
   /* <template-param> encodes only the template parameter position,
      not its template arguments, which is fine here.  */
   write_template_param (parm);
-  if (template)
-    add_substitution (template);
+  if (templ)
+    add_substitution (templ);
 }
 
 /* Non-terminal <substitution>.
 }
 
 /* Non-terminal <substitution>.
@@ -2531,26 +2885,21 @@ write_substitution (const int seq_id)
 /* Start mangling ENTITY.  */
 
 static inline void
 /* Start mangling ENTITY.  */
 
 static inline void
-start_mangling (const tree entity, const bool ident_p)
+start_mangling (const tree entity)
 {
   G.entity = entity;
   G.need_abi_warning = false;
 {
   G.entity = entity;
   G.need_abi_warning = false;
-  if (!ident_p)
-    {
-      obstack_free (&name_obstack, name_base);
-      mangle_obstack = &name_obstack;
-      name_base = obstack_alloc (&name_obstack, 0);
-    }
-  else
-    mangle_obstack = &ident_hash->stack;
+  obstack_free (&name_obstack, name_base);
+  mangle_obstack = &name_obstack;
+  name_base = obstack_alloc (&name_obstack, 0);
 }
 
 }
 
-/* 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.  */
+/* Done with mangling. 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 (const bool warn)
+static void
+finish_mangling_internal (const bool warn)
 {
   if (warn_abi && warn && G.need_abi_warning)
     warning (OPT_Wabi, "the mangled name of %qD will change in a future "
 {
   if (warn_abi && warn && G.need_abi_warning)
     warning (OPT_Wabi, "the mangled name of %qD will change in a future "
@@ -2562,10 +2911,29 @@ finish_mangling (const bool warn)
 
   /* Null-terminate the string.  */
   write_char ('\0');
 
   /* Null-terminate the string.  */
   write_char ('\0');
+}
+
 
 
+/* Like finish_mangling_internal, but return the mangled string.  */
+
+static inline const char *
+finish_mangling (const bool warn)
+{
+  finish_mangling_internal (warn);
   return (const char *) obstack_finish (mangle_obstack);
 }
 
   return (const char *) obstack_finish (mangle_obstack);
 }
 
+/* Like finish_mangling_internal, but return an identifier.  */
+
+static tree
+finish_mangling_get_identifier (const bool warn)
+{
+  finish_mangling_internal (warn);
+  /* Don't obstack_finish here, and the next start_mangling will
+     remove the identifier.  */
+  return get_identifier ((const char *) obstack_base (mangle_obstack));
+}
+
 /* Initialize data structures for mangling.  */
 
 void
 /* Initialize data structures for mangling.  */
 
 void
@@ -2587,42 +2955,33 @@ init_mangle (void)
 
 /* Generate the mangled name of DECL.  */
 
 
 /* Generate the mangled name of DECL.  */
 
-static const char *
+static tree
 mangle_decl_string (const tree decl)
 {
 mangle_decl_string (const tree decl)
 {
-  const char *result;
+  tree result;
 
 
-  start_mangling (decl, /*ident_p=*/true);
+  start_mangling (decl);
 
   if (TREE_CODE (decl) == TYPE_DECL)
     write_type (TREE_TYPE (decl));
   else
     write_mangled_name (decl, true);
 
 
   if (TREE_CODE (decl) == TYPE_DECL)
     write_type (TREE_TYPE (decl));
   else
     write_mangled_name (decl, true);
 
-  result = finish_mangling (/*warn=*/true);
+  result = finish_mangling_get_identifier (/*warn=*/true);
   if (DEBUG_MANGLE)
   if (DEBUG_MANGLE)
-    fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
+    fprintf (stderr, "mangle_decl_string = '%s'\n\n",
+            IDENTIFIER_POINTER (result));
   return result;
 }
 
   return result;
 }
 
-/* Like get_identifier, except that NAME is assumed to have been
-   allocated on the obstack used by the identifier hash table.  */
-
-static inline tree
-get_identifier_nocopy (const char *name)
-{
-  hashnode ht_node = ht_lookup (ident_hash, (const unsigned char *) name,
-                               strlen (name), HT_ALLOCED);
-  return HT_IDENT_TO_GCC_IDENT (ht_node);
-}
-
 /* Create an identifier for the external mangled name of DECL.  */
 
 void
 mangle_decl (const tree decl)
 {
 /* Create an identifier for the external mangled name of DECL.  */
 
 void
 mangle_decl (const tree decl)
 {
-  SET_DECL_ASSEMBLER_NAME (decl,
-                          get_identifier_nocopy (mangle_decl_string (decl)));
+  tree id = mangle_decl_string (decl);
+  id = targetm.mangle_decl_assembler_name (decl, id);
+  SET_DECL_ASSEMBLER_NAME (decl, id);
 }
 
 /* Generate the mangled representation of TYPE.  */
 }
 
 /* Generate the mangled representation of TYPE.  */
@@ -2632,7 +2991,7 @@ mangle_type_string (const tree type)
 {
   const char *result;
 
 {
   const char *result;
 
-  start_mangling (type, /*ident_p=*/false);
+  start_mangling (type);
   write_type (type);
   result = finish_mangling (/*warn=*/false);
   if (DEBUG_MANGLE)
   write_type (type);
   result = finish_mangling (/*warn=*/false);
   if (DEBUG_MANGLE)
@@ -2647,11 +3006,11 @@ mangle_type_string (const tree type)
 static tree
 mangle_special_for_type (const tree type, const char *code)
 {
 static tree
 mangle_special_for_type (const tree type, const char *code)
 {
-  const char *result;
+  tree result;
 
   /* We don't have an actual decl here for the special component, so
      we can't just process the <encoded-name>.  Instead, fake it.  */
 
   /* 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 (type, /*ident_p=*/true);
+  start_mangling (type);
 
   /* Start the mangling.  */
   write_string ("_Z");
 
   /* Start the mangling.  */
   write_string ("_Z");
@@ -2659,12 +3018,13 @@ mangle_special_for_type (const tree type, const char *code)
 
   /* Add the type.  */
   write_type (type);
 
   /* Add the type.  */
   write_type (type);
-  result = finish_mangling (/*warn=*/false);
+  result = finish_mangling_get_identifier (/*warn=*/false);
 
   if (DEBUG_MANGLE)
 
   if (DEBUG_MANGLE)
-    fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
+    fprintf (stderr, "mangle_special_for_type = %s\n\n",
+            IDENTIFIER_POINTER (result));
 
 
-  return get_identifier_nocopy (result);
+  return result;
 }
 
 /* Create an identifier for the mangled representation of the typeinfo
 }
 
 /* Create an identifier for the mangled representation of the typeinfo
@@ -2718,9 +3078,9 @@ mangle_vtt_for_type (const tree type)
 tree
 mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
 {
 tree
 mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
 {
-  const char *result;
+  tree result;
 
 
-  start_mangling (type, /*ident_p=*/true);
+  start_mangling (type);
 
   write_string ("_Z");
   write_string ("TC");
 
   write_string ("_Z");
   write_string ("TC");
@@ -2729,10 +3089,11 @@ mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
   write_char ('_');
   write_type (BINFO_TYPE (binfo));
 
   write_char ('_');
   write_type (BINFO_TYPE (binfo));
 
-  result = finish_mangling (/*warn=*/false);
+  result = finish_mangling_get_identifier (/*warn=*/false);
   if (DEBUG_MANGLE)
   if (DEBUG_MANGLE)
-    fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
-  return get_identifier_nocopy (result);
+    fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n",
+            IDENTIFIER_POINTER (result));
+  return result;
 }
 
 /* Mangle a this pointer or result pointer adjustment.
 }
 
 /* Mangle a this pointer or result pointer adjustment.
@@ -2774,9 +3135,9 @@ tree
 mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
              tree virtual_offset)
 {
 mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
              tree virtual_offset)
 {
-  const char *result;
+  tree result;
 
 
-  start_mangling (fn_decl, /*ident_p=*/true);
+  start_mangling (fn_decl);
 
   write_string ("_Z");
   write_char ('T');
 
   write_string ("_Z");
   write_char ('T');
@@ -2807,10 +3168,10 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
   /* Scoped name.  */
   write_encoding (fn_decl);
 
   /* Scoped name.  */
   write_encoding (fn_decl);
 
-  result = finish_mangling (/*warn=*/false);
+  result = finish_mangling_get_identifier (/*warn=*/false);
   if (DEBUG_MANGLE)
   if (DEBUG_MANGLE)
-    fprintf (stderr, "mangle_thunk = %s\n\n", result);
-  return get_identifier_nocopy (result);
+    fprintf (stderr, "mangle_thunk = %s\n\n", IDENTIFIER_POINTER (result));
+  return result;
 }
 
 /* This hash table maps TYPEs to the IDENTIFIER for a conversion
 }
 
 /* This hash table maps TYPEs to the IDENTIFIER for a conversion
@@ -2824,7 +3185,7 @@ static GTY ((param_is (union tree_node))) htab_t conv_type_names;
 static hashval_t
 hash_type (const void *val)
 {
 static hashval_t
 hash_type (const void *val)
 {
-  return (hashval_t) TYPE_UID (TREE_TYPE ((tree) val));
+  return (hashval_t) TYPE_UID (TREE_TYPE ((const_tree) val));
 }
 
 /* Compare VAL1 (a node in the table) with VAL2 (a TYPE).  */
 }
 
 /* Compare VAL1 (a node in the table) with VAL2 (a TYPE).  */
@@ -2832,7 +3193,7 @@ hash_type (const void *val)
 static int
 compare_type (const void *val1, const void *val2)
 {
 static int
 compare_type (const void *val1, const void *val2)
 {
-  return TREE_TYPE ((tree) val1) == (tree) val2;
+  return TREE_TYPE ((const_tree) val1) == (const_tree) val2;
 }
 
 /* Return an identifier for the mangled unqualified name for a
 }
 
 /* Return an identifier for the mangled unqualified name for a
@@ -2882,7 +3243,7 @@ mangle_conv_op_name_for_type (const tree type)
 tree
 mangle_guard_variable (const tree variable)
 {
 tree
 mangle_guard_variable (const tree variable)
 {
-  start_mangling (variable, /*ident_p=*/true);
+  start_mangling (variable);
   write_string ("_ZGV");
   if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
     /* The name of a guard variable for a reference temporary should refer
   write_string ("_ZGV");
   if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
     /* The name of a guard variable for a reference temporary should refer
@@ -2890,7 +3251,7 @@ mangle_guard_variable (const tree variable)
     write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
   else
     write_name (variable, /*ignore_local_scope=*/0);
     write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
   else
     write_name (variable, /*ignore_local_scope=*/0);
-  return get_identifier_nocopy (finish_mangling (/*warn=*/false));
+  return finish_mangling_get_identifier (/*warn=*/false);
 }
 
 /* Return an identifier for the name of a temporary variable used to
 }
 
 /* Return an identifier for the name of a temporary variable used to
@@ -2900,10 +3261,10 @@ mangle_guard_variable (const tree variable)
 tree
 mangle_ref_init_variable (const tree variable)
 {
 tree
 mangle_ref_init_variable (const tree variable)
 {
-  start_mangling (variable, /*ident_p=*/true);
+  start_mangling (variable);
   write_string ("_ZGR");
   write_name (variable, /*ignore_local_scope=*/0);
   write_string ("_ZGR");
   write_name (variable, /*ignore_local_scope=*/0);
-  return get_identifier_nocopy (finish_mangling (/*warn=*/false));
+  return finish_mangling_get_identifier (/*warn=*/false);
 }
 \f
 
 }
 \f