OSDN Git Service

PR c++/51854
[pf3gnuchains/gcc-fork.git] / gcc / cp / mangle.c
index b23e781..34f19ef 100644 (file)
@@ -1,6 +1,6 @@
 /* Name mangling for the 3.0 C++ ABI.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010,
+   2011  Free Software Foundation, Inc.
    Written by Alex Samuel <samuel@codesourcery.com>
 
    This file is part of GCC.
@@ -52,12 +52,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "tm_p.h"
 #include "cp-tree.h"
-#include "real.h"
 #include "obstack.h"
-#include "toplev.h"
-#include "varray.h"
 #include "flags.h"
 #include "target.h"
+#include "cgraph.h"
 
 /* Debugging support.  */
 
@@ -90,8 +88,7 @@ along with GCC; see the file COPYING3.  If not see
           && (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;
@@ -99,6 +96,9 @@ typedef struct globals GTY(())
   /* The entity that is being mangled.  */
   tree GTY ((skip)) entity;
 
+  /* How many parameter scopes we are inside.  */
+  int parm_depth;
+
   /* True if the mangling will be different in a future version of the
      ABI.  */
   bool need_abi_warning;
@@ -150,7 +150,9 @@ integer_type_codes[itk_none] =
   'l',  /* itk_long */
   'm',  /* itk_unsigned_long */
   'x',  /* itk_long_long */
-  'y'   /* itk_unsigned_long_long */
+  'y',  /* itk_unsigned_long_long */
+  'n',  /* itk_int128 */
+  'o',  /* itk_unsigned_int128  */
 };
 
 static int decl_is_template_id (const tree, tree* const);
@@ -179,10 +181,14 @@ 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_literal_operator_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 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 *);
@@ -208,9 +214,10 @@ 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 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 tree mangle_decl_string (const tree);
+static int local_class_index (tree);
 
 /* Control functions.  */
 
@@ -303,7 +310,7 @@ dump_substitution_candidates (void)
   tree el;
 
   fprintf (stderr, "  ++ substitutions  ");
-  for (i = 0; VEC_iterate (tree, G.substitutions, i, el); ++i)
+  FOR_EACH_VEC_ELT (tree, G.substitutions, i, el)
     {
       const char *name = "???";
 
@@ -339,9 +346,22 @@ canonicalize_for_substitution (tree 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.  */
+      if (TREE_CODE (node) == FUNCTION_TYPE)
+       /* Use build_qualified_type and TYPE_QUALS here to preserve
+          the old buggy mangling of attribute noreturn with abi<5.  */
+       node = build_qualified_type (TYPE_MAIN_VARIANT (node),
+                                    TYPE_QUALS (node));
+      else
+       node = cp_build_qualified_type (TYPE_MAIN_VARIANT (node),
+                                       cp_type_quals (node));
+    }
   return node;
 }
 
@@ -370,7 +390,7 @@ add_substitution (tree node)
     int i;
     tree candidate;
 
-    for (i = 0; VEC_iterate (tree, G.substitutions, i, candidate); i++)
+    FOR_EACH_VEC_ELT (tree, G.substitutions, i, candidate)
       {
        gcc_assert (!(DECL_P (node) && node == candidate));
        gcc_assert (!(TYPE_P (node) && TYPE_P (candidate)
@@ -595,7 +615,7 @@ find_substitution (tree node)
       /* NODE is a matched to a candidate if it's the same decl node or
         if it's the same type.  */
       if (decl == candidate
-         || (TYPE_P (candidate) && type && TYPE_P (type)
+         || (TYPE_P (candidate) && type && TYPE_P (node)
              && same_type_p (type, candidate))
          || NESTED_TEMPLATE_MATCH (node, candidate))
        {
@@ -722,6 +742,31 @@ 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)
+{
+  tree tcontext = targetm.cxx.decl_mangling_context (decl);
+
+  if (tcontext != NULL_TREE)
+    return tcontext;
+
+  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;
+    }
+    else if (TREE_CODE (decl) == TYPE_DECL
+            && TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TYPE_PARM)
+     /* template type parms have no mangling context.  */
+      return NULL_TREE;
+  return CP_DECL_CONTEXT (decl);
+}
+
 /* <name> ::= <unscoped-name>
          ::= <unscoped-template-name> <template-args>
          ::= <nested-name>
@@ -745,10 +790,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)));
-      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
@@ -792,7 +836,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 (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.  */
@@ -801,7 +846,7 @@ write_name (tree decl, const int ignore_local_scope)
                }
              /* 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>.  */
@@ -818,7 +863,7 @@ write_name (tree decl, const int ignore_local_scope)
 static void
 write_unscoped_name (const tree decl)
 {
-  tree context = CP_DECL_CONTEXT (decl);
+  tree context = decl_mangling_context (decl);
 
   MANGLE_TRACE_TREE ("unscoped-name", decl);
 
@@ -833,7 +878,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
-                 || context == NULL
+                 || context != NULL
                  || TREE_CODE (context) == FUNCTION_DECL);
 
       write_unqualified_name (decl);
@@ -887,10 +932,24 @@ write_nested_name (const tree decl)
       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>  */
-      write_prefix (DECL_CONTEXT (decl));
+      write_prefix (decl_mangling_context (decl));
       write_unqualified_name (decl);
     }
   write_char ('E');
@@ -899,6 +958,7 @@ write_nested_name (const tree decl)
 /* <prefix> ::= <prefix> <unqualified-name>
            ::= <template-param>
            ::= <template-prefix> <template-args>
+           ::= <decltype>
            ::= # empty
            ::= <substitution>  */
 
@@ -909,23 +969,30 @@ write_prefix (const tree node)
   /* 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);
+
+  if (TREE_CODE (node) == DECLTYPE_TYPE)
+    {
+      write_type (node);
+      return;
+    }
+
   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.  */
-      if (TREE_CODE (node) == FUNCTION_DECL)
+      if (TREE_CODE (node) == FUNCTION_DECL
+         || TREE_CODE (node) == PARM_DECL)
        return;
 
       decl = node;
@@ -953,11 +1020,32 @@ write_prefix (const tree node)
       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.  */
     {
-      write_prefix (CP_DECL_CONTEXT (decl));
+      write_prefix (decl_mangling_context (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);
@@ -974,19 +1062,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 template;
+  tree templ;
   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));
 
-      template = TYPE_TI_TEMPLATE (type);
+      templ = TYPE_TI_TEMPLATE (type);
     }
 
   /* For a member template, though, the template name for the
@@ -1012,21 +1103,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 = build_tree_list (context, template);
+    substitution = build_tree_list (context, templ);
   else
-    substitution = template;
+    substitution = templ;
 
   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;
 
-  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))
-    write_template_param (TREE_TYPE (template));
+    write_template_param (TREE_TYPE (templ));
   else
     {
       write_prefix (context);
@@ -1042,49 +1135,113 @@ write_template_prefix (const tree node)
     <unqualified-name>  ::= <operator-name>
                        ::= <special-name>
                        ::= <source-name>
+                       ::= <unnamed-type-name>
                        ::= <local-source-name> 
 
     <local-source-name>        ::= L <source-name> <discriminator> */
 
 static void
+write_unqualified_id (tree identifier)
+{
+  if (IDENTIFIER_TYPENAME_P (identifier))
+    write_conversion_operator_name (TREE_TYPE (identifier));
+  else if (IDENTIFIER_OPNAME_P (identifier))
+    {
+      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 < MAX_TREE_CODES; ++i)
+       if (operator_name_info[i].identifier == identifier)
+         {
+           /* 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
+                == identifier)
+         {
+           mangled_name
+             = assignment_operator_name_info[i].mangled_name;
+           break;
+         }
+      write_string (mangled_name);
+    }
+  else if (UDLIT_OPER_P (identifier))
+    write_literal_operator_name (identifier);
+  else
+    write_source_name (identifier);
+}
+
+static void
 write_unqualified_name (const tree 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;
-         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);
+  if (TREE_CODE (decl) == IDENTIFIER_NODE)
+    {
+      write_unqualified_id (decl);
+      return;
     }
-  else if (DECL_OVERLOADED_OPERATOR_P (decl))
+
+  if (DECL_NAME (decl) == NULL_TREE)
     {
-      operator_name_info_t *oni;
-      if (DECL_ASSIGNMENT_OPERATOR_P (decl))
-       oni = assignment_operator_name_info;
+      gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
+      write_source_name (DECL_ASSEMBLER_NAME (decl));
+      return;
+    }
+  else if (DECL_DECLARES_FUNCTION_P (decl))
+    {
+      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 if (UDLIT_OPER_P (DECL_NAME (decl)))
+       write_literal_operator_name (DECL_NAME (decl));
       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');
@@ -1093,7 +1250,18 @@ write_unqualified_name (const tree decl)
         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.  */
@@ -1123,6 +1291,93 @@ write_source_name (tree identifier)
   write_identifier (IDENTIFIER_POINTER (identifier));
 }
 
+/* Write a user-defined literal operator.
+   IDENTIFIER is an LITERAL_IDENTIFIER_NODE.  */
+
+static void
+write_literal_operator_name (tree identifier)
+{
+  const char* suffix = UDLIT_OP_SUFFIX (identifier);
+  char* buffer = XNEWVEC (char, strlen (UDLIT_OP_MANGLED_PREFIX)
+                             + strlen (suffix) + 10);
+  sprintf (buffer, UDLIT_OP_MANGLED_FORMAT, suffix);
+
+  write_unsigned_number (strlen (buffer));
+  write_identifier (buffer);
+}
+
+/* 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 = DECL_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, /*method_p=*/1, 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
@@ -1213,16 +1468,16 @@ write_integer_cst (const tree cst)
       if (sign < 0)
        {
          write_char ('n');
-         n = fold_build1 (NEGATE_EXPR, type, n);
+         n = fold_build1_loc (input_location, NEGATE_EXPR, type, n);
        }
       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);
-         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;
@@ -1382,6 +1637,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.  */
@@ -1389,29 +1667,28 @@ write_special_name_destructor (const tree dtor)
 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_DISCRIMINATOR_SET_P (entity))
+       return DECL_DISCRIMINATOR (entity);
+      else
+       /* The first entity with a particular name doesn't get
+          DECL_DISCRIMINATOR set up.  */
+       return 0;
+    }
   else if (TREE_CODE (entity) == TYPE_DECL)
     {
-      int ix;
-
       /* 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
@@ -1444,23 +1721,49 @@ write_discriminator (const int discriminator)
 }
 
 /* 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>]
-                 := Z <function encoding> E s [<discriminator>]  */
+                 := Z <function encoding> E s [<discriminator>]
+                 := Z <function encoding> Ed [ <parameter number> ] _ <entity name> */
 
 static void
-write_local_name (const tree function, const tree local_entity,
+write_local_name (tree function, const tree local_entity,
                  const tree entity)
 {
+  tree parm = NULL_TREE;
+
   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');
+
+  /* For this purpose, parameters are numbered from right-to-left.  */
+  if (parm)
+    {
+      tree t;
+      int i = 0;
+      for (t = DECL_ARGUMENTS (function); t; t = DECL_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');
@@ -1499,6 +1802,7 @@ write_local_name (const tree function, const tree local_entity,
      <type> ::= Dt <expression> # decltype of an id-expression or 
                                 # class member access
      <type> ::= DT <expression> # decltype of an expression
+     <type> ::= Dn              # decltype of nullptr
 
    TYPE is a type node.  */
 
@@ -1514,9 +1818,11 @@ write_type (tree type)
   if (type == error_mark_node)
     return;
 
+  type = canonicalize_for_substitution (type);
   if (find_substitution (type))
     return;
 
+
   if (write_CV_qualifiers_for_type (type) > 0)
     /* If TYPE was CV-qualified, we just wrote the qualifiers; now
        mangle the unqualified type.  The recursive call is needed here
@@ -1535,6 +1841,12 @@ write_type (tree type)
       /* See through any typedefs.  */
       type = TYPE_MAIN_VARIANT (type);
 
+      /* According to the C++ ABI, some library classes are passed the
+        same as the scalar type of their single member and use the same
+        mangling.  */
+      if (TREE_CODE (type) == RECORD_TYPE && TYPE_TRANSPARENT_AGGR (type))
+       type = TREE_TYPE (first_field (type));
+
       if (TYPE_PTRMEM_P (type))
        write_pointer_to_member_type (type);
       else
@@ -1546,6 +1858,13 @@ write_type (tree type)
          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;
            }
 
@@ -1555,6 +1874,7 @@ write_type (tree 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
@@ -1593,16 +1913,25 @@ write_type (tree 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');
+             if (TREE_CODE (type) == POINTER_TYPE)
+               write_char ('P');
+             else if (TYPE_REF_IS_RVALUE (type))
+               write_char ('O');
               else
                 write_char ('R');
-             write_type (TREE_TYPE (type));
+             {
+               tree target = TREE_TYPE (type);
+               /* Attribute const/noreturn are not reflected in mangling.
+                  We strip them here rather than at a lower level because
+                  a typedef or template argument can have function type
+                  with function-cv-quals (that use the same representation),
+                  but you can't have a pointer/reference to such a type.  */
+               if (abi_version_at_least (5)
+                   && TREE_CODE (target) == FUNCTION_TYPE)
+                 target = build_qualified_type (target, TYPE_UNQUALIFIED);
+               write_type (target);
+             }
              break;
 
            case TEMPLATE_TYPE_PARM:
@@ -1621,29 +1950,87 @@ write_type (tree type)
              break;
 
            case VECTOR_TYPE:
-             write_string ("U8__vector");
+             if (abi_version_at_least (4))
+               {
+                 write_string ("Dv");
+                 /* Non-constant vector size would be encoded with
+                    _ expression, but we don't support that yet.  */
+                 write_unsigned_number (TYPE_VECTOR_SUBPARTS (type));
+                 write_char ('_');
+               }
+             else
+               {
+                 G.need_abi_warning = 1;
+                 write_string ("U8__vector");
+               }
              write_type (TREE_TYPE (type));
              break;
 
             case TYPE_PACK_EXPANSION:
-              write_string ("U10__variadic");
+              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_PROXY (type));
+
+             /* In ABI <5, we stripped decltype of a plain decl.  */
+             if (!abi_version_at_least (5)
+                 && DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
+               {
+                 tree expr = DECLTYPE_TYPE_EXPR (type);
+                 tree etype = NULL_TREE;
+                 switch (TREE_CODE (expr))
+                   {
+                   case VAR_DECL:
+                   case PARM_DECL:
+                   case RESULT_DECL:
+                   case FUNCTION_DECL:
+                   case CONST_DECL:
+                   case TEMPLATE_PARM_INDEX:
+                     etype = TREE_TYPE (expr);
+                     break;
+
+                   default:
+                     break;
+                   }
+
+                 if (etype && !type_uses_auto (etype))
+                   {
+                     G.need_abi_warning = 1;
+                     write_type (etype);
+                     return;
+                   }
+               }
+
               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 NULLPTR_TYPE:
+             write_string ("Dn");
+             break;
+
            case TYPEOF_TYPE:
              sorry ("mangling typeof, use decltype instead");
              break;
 
+           case UNDERLYING_TYPE:
+             sorry ("mangling __underlying_type");
+             break;
+
+           case LANG_TYPE:
+             /* fall through.  */
+
            default:
              gcc_unreachable ();
            }
@@ -1674,18 +2061,19 @@ write_CV_qualifiers_for_type (const tree 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.  */
+  cp_cv_quals quals = TYPE_QUALS (type);
 
-  if (TYPE_QUALS (type) & TYPE_QUAL_RESTRICT)
+  if (quals & TYPE_QUAL_RESTRICT)
     {
       write_char ('r');
       ++num_qualifiers;
     }
-  if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
+  if (quals & TYPE_QUAL_VOLATILE)
     {
       write_char ('V');
       ++num_qualifiers;
     }
-  if (TYPE_QUALS (type) & TYPE_QUAL_CONST)
+  if (quals & TYPE_QUAL_CONST)
     {
       write_char ('K');
       ++num_qualifiers;
@@ -1740,9 +2128,9 @@ write_builtin_type (tree type)
       if (type == wchar_type_node)
        write_char ('w');
       else if (type == char16_type_node)
-       write_string ("u8char16_t");
+       write_string ("Ds");
       else if (type == char32_type_node)
-       write_string ("u8char32_t");
+       write_string ("Di");
       else if (TYPE_FOR_JAVA (type))
        write_java_integer_type_codes (type);
       else
@@ -1752,7 +2140,8 @@ write_builtin_type (tree type)
             it in the array of these nodes.  */
        iagain:
          for (itk = 0; itk < itk_none; ++itk)
-           if (type == integer_types[itk])
+           if (integer_types[itk] != NULL_TREE
+               && type == integer_types[itk])
              {
                /* Print the corresponding single-letter code.  */
                write_char (integer_type_codes[itk]);
@@ -1805,10 +2194,69 @@ write_builtin_type (tree type)
        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;
 
+    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 ();
     }
@@ -1832,7 +2280,7 @@ write_function_type (const tree 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)));
+      tree this_type = class_of_this_parm (type);
       write_CV_qualifiers_for_type (this_type);
     }
 
@@ -1894,9 +2342,11 @@ write_bare_function_type (const tree type, const int include_return_type_p,
     write_type (TREE_TYPE (type));
 
   /* Now mangle the types of the arguments.  */
+  ++G.parm_depth;
   write_method_parms (TYPE_ARG_TYPES (type),
                      TREE_CODE (type) == METHOD_TYPE,
                      decl);
+  --G.parm_depth;
 }
 
 /* Write the mangled representation of a method parameter list of
@@ -1925,12 +2375,12 @@ write_method_parms (tree parm_types, const int method_p, const tree decl)
   if (method_p)
     {
       parm_types = TREE_CHAIN (parm_types);
-      parm_decl = parm_decl ? TREE_CHAIN (parm_decl) : NULL_TREE;
+      parm_decl = parm_decl ? DECL_CHAIN (parm_decl) : NULL_TREE;
 
       while (parm_decl && DECL_ARTIFICIAL (parm_decl))
        {
          parm_types = TREE_CHAIN (parm_types);
-         parm_decl = TREE_CHAIN (parm_decl);
+         parm_decl = DECL_CHAIN (parm_decl);
        }
     }
 
@@ -1972,21 +2422,22 @@ write_class_enum_type (const tree type)
 /* 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;
-  int length = TREE_VEC_LENGTH (args);
+  int length = 0;
 
   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.  */
@@ -1999,6 +2450,30 @@ write_template_args (tree args)
   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_unqualified_id (member);
+  else if (DECL_P (member))
+    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>
@@ -2006,15 +2481,14 @@ write_template_args (tree args)
    <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)
 {
-  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
@@ -2026,7 +2500,9 @@ write_expression (tree expr)
       code = TREE_CODE (expr);
     }
 
-  if (code == BASELINK)
+  if (code == BASELINK
+      && (!type_unknown_p (expr)
+         || !BASELINK_QUALIFIED_P (expr)))
     {
       expr = BASELINK_FUNCTIONS (expr);
       code = TREE_CODE (expr);
@@ -2054,6 +2530,39 @@ 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 (code == PARM_DECL && DECL_ARTIFICIAL (expr))
+    {
+      gcc_assert (!strcmp ("this", IDENTIFIER_POINTER (DECL_NAME (expr))));
+      write_string ("fpT");
+    }
+  else if (code == PARM_DECL)
+    {
+      /* A function parameter used in a late-specified return type.  */
+      int index = DECL_PARM_INDEX (expr);
+      int level = DECL_PARM_LEVEL (expr);
+      int delta = G.parm_depth - level + 1;
+      gcc_assert (index >= 1);
+      write_char ('f');
+      if (delta != 0)
+       {
+         if (abi_version_at_least (5))
+           {
+             /* Let L be the number of function prototype scopes from the
+                innermost one (in which the parameter reference occurs) up
+                to (and including) the one containing the declaration of
+                the referenced parameter.  If the parameter declaration
+                clause of the innermost function prototype scope has been
+                completely seen, it is not counted (in that case -- which
+                is perhaps the most common -- L can be zero).  */
+             write_char ('L');
+             write_unsigned_number (delta - 1);
+           }
+         else
+           G.need_abi_warning = true;
+       }
+      write_char ('p');
+      write_compact_number (index - 1);
+    }
   else if (DECL_P (expr))
     {
       /* G++ 3.2 incorrectly mangled non-type template arguments of
@@ -2070,76 +2579,185 @@ write_expression (tree expr)
       write_string ("st");
       write_type (TREE_OPERAND (expr, 0));
     }
-  else if (abi_version_at_least (2) && TREE_CODE (expr) == SCOPE_REF)
+  else if (TREE_CODE (expr) == ALIGNOF_EXPR
+          && TYPE_P (TREE_OPERAND (expr, 0)))
+    {
+      write_string ("at");
+      write_type (TREE_OPERAND (expr, 0));
+    }
+  else if (code == SCOPE_REF
+          || code == BASELINK)
     {
-      tree scope = TREE_OPERAND (expr, 0);
-      tree member = TREE_OPERAND (expr, 1);
+      tree scope, member;
+      if (code == SCOPE_REF)
+       {
+         scope = TREE_OPERAND (expr, 0);
+         member = TREE_OPERAND (expr, 1);
+       }
+      else
+       {
+         scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (expr));
+         member = BASELINK_FUNCTIONS (expr);
+       }
+
+      if (!abi_version_at_least (2) && DECL_P (member))
+       {
+         write_string ("sr");
+         write_type (scope);
+         /* 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 (member);
+       }
 
       /* 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))
+      else if (DECL_P (member))
        write_expression (member);
       else
        {
-         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);
-           }
-         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);
+         write_member_name (member);
+       }
+    }
+  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 if (TREE_CODE (expr) == IDENTIFIER_NODE)
+    {
+      /* An operator name appearing as a dependent name needs to be
+        specially marked to disambiguate between a use of the operator
+        name and a use of the operator in an expression.  */
+      if (IDENTIFIER_OPNAME_P (expr))
+       write_string ("on");
+      write_unqualified_id (expr);
+    }
+  else if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
+    {
+      tree fn = TREE_OPERAND (expr, 0);
+      if (is_overloaded_fn (fn))
+       fn = DECL_NAME (get_first_fn (fn));
+      if (IDENTIFIER_OPNAME_P (fn))
+       write_string ("on");
+      write_unqualified_id (fn);
+      write_template_args (TREE_OPERAND (expr, 1));
+    }
+  else if (TREE_CODE (expr) == MODOP_EXPR)
+    {
+      enum tree_code subop = TREE_CODE (TREE_OPERAND (expr, 1));
+      const char *name = (assignment_operator_name_info[(int) subop]
+                         .mangled_name);
+      write_string (name);
+      write_expression (TREE_OPERAND (expr, 0));
+      write_expression (TREE_OPERAND (expr, 2));
+    }
+  else if (code == NEW_EXPR || code == VEC_NEW_EXPR)
+    {
+      /* ::= [gs] nw <expression>* _ <type> E
+        ::= [gs] nw <expression>* _ <type> <initializer>
+        ::= [gs] na <expression>* _ <type> E
+        ::= [gs] na <expression>* _ <type> <initializer>
+        <initializer> ::= pi <expression>* E  */
+      tree placement = TREE_OPERAND (expr, 0);
+      tree type = TREE_OPERAND (expr, 1);
+      tree nelts = TREE_OPERAND (expr, 2);
+      tree init = TREE_OPERAND (expr, 3);
+      tree t;
+
+      gcc_assert (code == NEW_EXPR);
+      if (TREE_OPERAND (expr, 2))
+       code = VEC_NEW_EXPR;
+
+      if (NEW_EXPR_USE_GLOBAL (expr))
+       write_string ("gs");
+
+      write_string (operator_name_info[(int) code].mangled_name);
+
+      for (t = placement; t; t = TREE_CHAIN (t))
+       write_expression (TREE_VALUE (t));
+
+      write_char ('_');
+
+      if (nelts)
+       {
+         tree domain;
+         ++processing_template_decl;
+         domain = compute_array_index_type (NULL_TREE, nelts,
+                                            tf_warning_or_error);
+         type = build_cplus_array_type (type, domain);
+         --processing_template_decl;
+       }
+      write_type (type);
+
+      if (init && TREE_CODE (init) == TREE_LIST
+         && TREE_CODE (TREE_VALUE (init)) == CONSTRUCTOR
+         && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))
+       write_expression (TREE_VALUE (init));
+      else
+       {
+         if (init)
+           write_string ("pi");
+         if (init && init != void_zero_node)
+           for (t = init; t; t = TREE_CHAIN (t))
+             write_expression (TREE_VALUE (t));
+         write_char ('E');
+       }
+    }
+  else if (code == DELETE_EXPR || code == VEC_DELETE_EXPR)
+    {
+      gcc_assert (code == DELETE_EXPR);
+      if (DELETE_EXPR_USE_VEC (expr))
+       code = VEC_DELETE_EXPR;
+
+      if (DELETE_EXPR_USE_GLOBAL (expr))
+       write_string ("gs");
+
+      write_string (operator_name_info[(int) code].mangled_name);
+
+      write_expression (TREE_OPERAND (expr, 0));
+    }
+  else if (code == THROW_EXPR)
+    {
+      tree op = TREE_OPERAND (expr, 0);
+      if (op)
+       {
+         write_string ("tw");
+         write_expression (op);
+       }
+      else
+       write_string ("tr");
+    }
+  else if (code == CONSTRUCTOR)
+    {
+      VEC(constructor_elt,gc)* elts = CONSTRUCTOR_ELTS (expr);
+      unsigned i; tree val;
+
+      if (BRACE_ENCLOSED_INITIALIZER_P (expr))
+       write_string ("il");
+      else
+       {
+         write_string ("tl");
+         write_type (TREE_TYPE (expr));
        }
+      FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
+       write_expression (val);
+      write_char ('E');
+    }
+  else if (dependent_name (expr))
+    {
+      write_unqualified_id (dependent_name (expr));
     }
   else
     {
-      int i;
+      int i, len;
+      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
@@ -2159,61 +2777,103 @@ write_expression (tree 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.  */
-      write_string (operator_name_info[(int) code].mangled_name);
+      name = operator_name_info[(int) code].mangled_name;
+
+      /* We used to mangle const_cast and static_cast like a C cast.  */
+      if (!abi_version_at_least (6)
+         && (code == CONST_CAST_EXPR
+             || code == STATIC_CAST_EXPR))
+       {
+         name = operator_name_info[CAST_EXPR].mangled_name;
+         G.need_abi_warning = 1;
+       }
+
+      if (name == NULL)
+       {
+         sorry ("mangling %C", code);
+         return;
+       }
+      else
+       write_string (name);    
 
       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));
+
+           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));
-         /* 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)));
+         else
+           {
+             tree args = TREE_OPERAND (expr, 0);
+             write_char ('_');
+             for (; args; args = TREE_CHAIN (args))
+               write_expression (TREE_VALUE (args));
+             write_char ('E');
+           }
          break;
 
+       case DYNAMIC_CAST_EXPR:
+       case REINTERPRET_CAST_EXPR:
        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 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));
-           }
+       case PREINCREMENT_EXPR:
+       case PREDECREMENT_EXPR:
+         if (abi_version_at_least (6))
+           write_char ('_');
          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));
-           }
-         break;
+           G.need_abi_warning = 1;
+         /* Fall through.  */
 
        default:
-         for (i = 0; i < TREE_OPERAND_LENGTH (expr); ++i)
+         /* In the middle-end, some expressions have more operands than
+            they do in templates (and mangling).  */
+         len = cp_tree_operand_length (expr);
+
+         for (i = 0; i < len; ++i)
            {
              tree operand = TREE_OPERAND (expr, i);
              /* As a GNU extension, the middle operand of a
@@ -2246,25 +2906,53 @@ write_template_arg_literal (const tree value)
   write_char ('L');
   write_type (TREE_TYPE (value));
 
-  switch (TREE_CODE (value))
-    {
-    case CONST_DECL:
-      write_integer_cst (DECL_INITIAL (value));
-      break;
-
-    case INTEGER_CST:
-      gcc_assert (!same_type_p (TREE_TYPE (value), boolean_type_node)
-                 || integer_zerop (value) || integer_onep (value));
-      write_integer_cst (value);
-      break;
-
-    case REAL_CST:
-      write_real_cst (value);
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
+  /* Write a null member pointer value as (type)0, regardless of its
+     real representation.  */
+  if (null_member_pointer_value_p (value))
+    write_integer_cst (integer_zero_node);
+  else
+    switch (TREE_CODE (value))
+      {
+      case CONST_DECL:
+       write_integer_cst (DECL_INITIAL (value));
+       break;
+
+      case INTEGER_CST:
+       gcc_assert (!same_type_p (TREE_TYPE (value), boolean_type_node)
+                   || integer_zerop (value) || integer_onep (value));
+       write_integer_cst (value);
+       break;
+
+      case REAL_CST:
+       write_real_cst (value);
+       break;
+
+      case COMPLEX_CST:
+       if (TREE_CODE (TREE_REALPART (value)) == INTEGER_CST
+           && TREE_CODE (TREE_IMAGPART (value)) == INTEGER_CST)
+         {
+           write_integer_cst (TREE_REALPART (value));
+           write_char ('_');
+           write_integer_cst (TREE_IMAGPART (value));
+         }
+       else if (TREE_CODE (TREE_REALPART (value)) == REAL_CST
+                && TREE_CODE (TREE_IMAGPART (value)) == REAL_CST)
+         {
+           write_real_cst (TREE_REALPART (value));
+           write_char ('_');
+           write_real_cst (TREE_IMAGPART (value));
+         }
+       else
+         gcc_unreachable ();
+       break;
+
+      case STRING_CST:
+       sorry ("string literal in function template signature");
+       break;
+
+      default:
+       gcc_unreachable ();
+      }
 
   write_char ('E');
 }
@@ -2309,13 +2997,31 @@ write_template_arg (tree node)
        G.need_abi_warning = 1;
     }
 
+  if (TREE_CODE (node) == BASELINK
+      && !type_unknown_p (node))
+    {
+      if (abi_version_at_least (6))
+       node = BASELINK_FUNCTIONS (node);
+      else
+       /* We wrongly wrapped a class-scope function in X/E.  */
+       G.need_abi_warning = 1;
+    }
+
   if (ARGUMENT_PACK_P (node))
     {
       /* Expand the template argument pack. */
       tree args = ARGUMENT_PACK_ARGS (node);
       int i, length = TREE_VEC_LENGTH (args);
+      if (abi_version_at_least (6))
+       write_char ('J');
+      else
+       {
+         write_char ('I');
+         G.need_abi_warning = 1;
+       }
       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);
@@ -2323,7 +3029,8 @@ write_template_arg (tree node)
     /* A template appearing as a template arg is a template template arg.  */
     write_template_template_arg (node);
   else if ((TREE_CODE_CLASS (code) == tcc_constant && code != PTRMEM_CST)
-          || (abi_version_at_least (2) && code == CONST_DECL))
+          || (abi_version_at_least (2) && code == CONST_DECL)
+          || null_member_pointer_value_p (node))
     write_template_arg_literal (node);
   else if (DECL_P (node))
     {
@@ -2441,8 +3148,6 @@ static void
 write_template_param (const tree parm)
 {
   int parm_index;
-  int parm_level;
-  tree parm_type = NULL_TREE;
 
   MANGLE_TRACE_TREE ("template-parm", parm);
 
@@ -2452,13 +3157,10 @@ write_template_param (const tree 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:
@@ -2468,9 +3170,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 `_'.  */
-  if (parm_index > 0)
-    write_unsigned_number (parm_index - 1);
-  write_char ('_');
+  write_compact_number (parm_index);
 }
 
 /*  <template-template-param>
@@ -2480,24 +3180,24 @@ write_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)
     {
-      template
+      templ
        = 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);
-  if (template)
-    add_substitution (template);
+  if (templ)
+    add_substitution (templ);
 }
 
 /* Non-terminal <substitution>.
@@ -2565,7 +3265,7 @@ 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 *) name_base);
+  return get_identifier ((const char *) obstack_base (mangle_obstack));
 }
 
 /* Initialize data structures for mangling.  */
@@ -2593,6 +3293,25 @@ static tree
 mangle_decl_string (const tree decl)
 {
   tree result;
+  location_t saved_loc = input_location;
+  tree saved_fn = NULL_TREE;
+  bool template_p = false;
+
+  /* We shouldn't be trying to mangle an uninstantiated template.  */
+  gcc_assert (!type_dependent_expression_p (decl));
+
+  if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl))
+    {
+      struct tinst_level *tl = current_instantiation ();
+      if ((!tl || tl->decl != decl)
+         && push_tinst_level (decl))
+       {
+         template_p = true;
+         saved_fn = current_function_decl;
+         current_function_decl = NULL_TREE;
+       }
+    }
+  input_location = DECL_SOURCE_LOCATION (decl);
 
   start_mangling (decl);
 
@@ -2605,17 +3324,84 @@ mangle_decl_string (const tree decl)
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_decl_string = '%s'\n\n",
             IDENTIFIER_POINTER (result));
+
+  if (template_p)
+    {
+      pop_tinst_level ();
+      current_function_decl = saved_fn;
+    }
+  input_location = saved_loc;
+
   return result;
 }
 
+/* Return an identifier for the external mangled name of DECL.  */
+
+static tree
+get_mangled_id (tree decl)
+{
+  tree id = mangle_decl_string (decl);
+  return targetm.mangle_decl_assembler_name (decl, id);
+}
+
 /* Create an identifier for the external mangled name of DECL.  */
 
 void
 mangle_decl (const tree decl)
 {
-  tree id = mangle_decl_string (decl);
-  id = targetm.mangle_decl_assembler_name (decl, id);
+  tree id;
+  bool dep;
+
+  /* Don't bother mangling uninstantiated templates.  */
+  ++processing_template_decl;
+  if (TREE_CODE (decl) == TYPE_DECL)
+    dep = dependent_type_p (TREE_TYPE (decl));
+  else
+    dep = (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
+          && any_dependent_template_arguments_p (DECL_TI_ARGS (decl)));
+  --processing_template_decl;
+  if (dep)
+    return;
+
+  id = get_mangled_id (decl);
   SET_DECL_ASSEMBLER_NAME (decl, id);
+
+  if (G.need_abi_warning
+      /* Don't do this for a fake symbol we aren't going to emit anyway.  */
+      && !DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
+      && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
+    {
+#ifdef ASM_OUTPUT_DEF
+      /* If the mangling will change in the future, emit an alias with the
+        future mangled name for forward-compatibility.  */
+      int save_ver;
+      tree id2, alias;
+#endif
+
+      SET_IDENTIFIER_GLOBAL_VALUE (id, decl);
+      if (IDENTIFIER_GLOBAL_VALUE (id) != decl)
+       inform (DECL_SOURCE_LOCATION (decl), "-fabi-version=6 (or =0) "
+               "avoids this error with a change in mangling");
+
+#ifdef ASM_OUTPUT_DEF
+      save_ver = flag_abi_version;
+      flag_abi_version = 0;
+      id2 = mangle_decl_string (decl);
+      id2 = targetm.mangle_decl_assembler_name (decl, id2);
+      flag_abi_version = save_ver;
+
+      alias = make_alias_for (decl, id2);
+      DECL_IGNORED_P (alias) = 1;
+      TREE_PUBLIC (alias) = TREE_PUBLIC (decl);
+      DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
+      if (vague_linkage_p (decl))
+       DECL_WEAK (alias) = 1;
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       cgraph_same_body_alias (cgraph_get_create_node (decl), alias, decl);
+      else
+       varpool_extra_name_alias (alias, decl);
+#endif
+    }
 }
 
 /* Generate the mangled representation of TYPE.  */
@@ -2892,12 +3678,17 @@ mangle_guard_variable (const tree variable)
    initialize a static reference.  This isn't part of the ABI, but we might
    as well call them something readable.  */
 
+static GTY(()) int temp_count;
+
 tree
 mangle_ref_init_variable (const tree variable)
 {
   start_mangling (variable);
   write_string ("_ZGR");
   write_name (variable, /*ignore_local_scope=*/0);
+  /* Avoid name clashes with aggregate initialization of multiple
+     references at once.  */
+  write_unsigned_number (temp_count++);
   return finish_mangling_get_identifier (/*warn=*/false);
 }
 \f