move many gc hashtab to hash_table
[platform/upstream/gcc.git] / gcc / cp / mangle.c
index f4efa67..6b8f706 100644 (file)
@@ -1,6 +1,5 @@
 /* Name mangling for the 3.0 C++ ABI.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010,
-   2011  Free Software Foundation, Inc.
+   Copyright (C) 2000-2014 Free Software Foundation, Inc.
    Written by Alex Samuel <samuel@codesourcery.com>
 
    This file is part of GCC.
@@ -50,12 +49,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "tree-hasher.h"
+#include "stor-layout.h"
+#include "stringpool.h"
 #include "tm_p.h"
 #include "cp-tree.h"
 #include "obstack.h"
 #include "flags.h"
 #include "target.h"
 #include "cgraph.h"
+#include "wide-int.h"
 
 /* Debugging support.  */
 
@@ -70,7 +73,7 @@ along with GCC; see the file COPYING3.  If not see
   fprintf (stderr, "  %-24s: %-24s\n", (FN), (INPUT))
 # define MANGLE_TRACE_TREE(FN, NODE) \
   fprintf (stderr, "  %-24s: %-24s (%p)\n", \
-          (FN), tree_code_name[TREE_CODE (NODE)], (void *) (NODE))
+          (FN), get_tree_code_name (TREE_CODE (NODE)), (void *) (NODE))
 #else
 # define MANGLE_TRACE(FN, INPUT)
 # define MANGLE_TRACE_TREE(FN, NODE)
@@ -91,7 +94,7 @@ along with GCC; see the file COPYING3.  If not see
 typedef struct GTY(()) globals {
   /* An array of the current substitution candidates, in the order
      we've seen them.  */
-  VEC(tree,gc) *substitutions;
+  vec<tree, va_gc> *substitutions;
 
   /* The entity that is being mangled.  */
   tree GTY ((skip)) entity;
@@ -173,12 +176,13 @@ static void mangle_call_offset (const tree, const tree);
 static void write_mangled_name (const tree, bool);
 static void write_encoding (const tree);
 static void write_name (tree, const int);
+static void write_abi_tags (tree);
 static void write_unscoped_name (const tree);
 static void write_unscoped_template_name (const tree);
 static void write_nested_name (const tree);
 static void write_prefix (const tree);
 static void write_template_prefix (const tree);
-static void write_unqualified_name (const tree);
+static void write_unqualified_name (tree);
 static void write_conversion_operator_name (const tree);
 static void write_source_name (tree);
 static void write_literal_operator_name (tree);
@@ -222,7 +226,6 @@ static int local_class_index (tree);
 /* Control functions.  */
 
 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 *);
 
 /* Foreign language functions.  */
@@ -310,7 +313,7 @@ dump_substitution_candidates (void)
   tree el;
 
   fprintf (stderr, "  ++ substitutions  ");
-  FOR_EACH_VEC_ELT (tree, G.substitutions, i, el)
+  FOR_EACH_VEC_ELT (*G.substitutions, i, el)
     {
       const char *name = "???";
 
@@ -321,7 +324,7 @@ dump_substitution_candidates (void)
       else if (TREE_CODE (el) == TREE_LIST)
        name = IDENTIFIER_POINTER (DECL_NAME (TREE_VALUE (el)));
       else if (TYPE_NAME (el))
-       name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (el)));
+       name = TYPE_NAME_STRING (el);
       fprintf (stderr, " S%d_ = ", i - 1);
       if (TYPE_P (el) &&
          (CP_TYPE_RESTRICT_P (el)
@@ -329,7 +332,7 @@ dump_substitution_candidates (void)
           || CP_TYPE_CONST_P (el)))
        fprintf (stderr, "CV-");
       fprintf (stderr, "%s (%s at %p)\n",
-              name, tree_code_name[TREE_CODE (el)], (void *) el);
+              name, get_tree_code_name (TREE_CODE (el)), (void *) el);
     }
 }
 
@@ -350,6 +353,7 @@ canonicalize_for_substitution (tree node)
       && TYPE_CANONICAL (node) != node
       && TYPE_MAIN_VARIANT (node) != node)
     {
+      tree orig = node;
       /* Here we want to strip the topmost typedef only.
          We need to do that so is_std_substitution can do proper
          name matching.  */
@@ -361,6 +365,9 @@ canonicalize_for_substitution (tree node)
       else
        node = cp_build_qualified_type (TYPE_MAIN_VARIANT (node),
                                        cp_type_quals (node));
+      if (TREE_CODE (node) == FUNCTION_TYPE
+         || TREE_CODE (node) == METHOD_TYPE)
+       node = build_ref_qualified_type (node, type_memfn_rqual (orig));
     }
   return node;
 }
@@ -375,13 +382,13 @@ add_substitution (tree node)
 
   if (DEBUG_MANGLE)
     fprintf (stderr, "  ++ add_substitution (%s at %10p)\n",
-            tree_code_name[TREE_CODE (node)], (void *) node);
+            get_tree_code_name (TREE_CODE (node)), (void *) node);
 
   /* Get the canonicalized substitution candidate for NODE.  */
   c = canonicalize_for_substitution (node);
   if (DEBUG_MANGLE && c != node)
     fprintf (stderr, "  ++ using candidate (%s at %10p)\n",
-            tree_code_name[TREE_CODE (node)], (void *) node);
+            get_tree_code_name (TREE_CODE (node)), (void *) node);
   node = c;
 
 #if ENABLE_CHECKING
@@ -390,7 +397,7 @@ add_substitution (tree node)
     int i;
     tree candidate;
 
-    FOR_EACH_VEC_ELT (tree, G.substitutions, i, candidate)
+    FOR_EACH_VEC_SAFE_ELT (G.substitutions, i, candidate)
       {
        gcc_assert (!(DECL_P (node) && node == candidate));
        gcc_assert (!(TYPE_P (node) && TYPE_P (candidate)
@@ -400,7 +407,7 @@ add_substitution (tree node)
 #endif /* ENABLE_CHECKING */
 
   /* Put the decl onto the varray of substitution candidates.  */
-  VEC_safe_push (tree, gc, G.substitutions, node);
+  vec_safe_push (G.substitutions, node);
 
   if (DEBUG_MANGLE)
     dump_substitution_candidates ();
@@ -503,13 +510,14 @@ static int
 find_substitution (tree node)
 {
   int i;
-  const int size = VEC_length (tree, G.substitutions);
+  const int size = vec_safe_length (G.substitutions);
   tree decl;
   tree type;
+  const char *abbr = NULL;
 
   if (DEBUG_MANGLE)
     fprintf (stderr, "  ++ find_substitution (%s at %p)\n",
-            tree_code_name[TREE_CODE (node)], (void *) node);
+            get_tree_code_name (TREE_CODE (node)), (void *) node);
 
   /* Obtain the canonicalized substitution representation for NODE.
      This is what we'll compare against.  */
@@ -524,13 +532,10 @@ find_substitution (tree node)
   if (decl
       && is_std_substitution (decl, SUBID_ALLOCATOR)
       && !CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl)))
-    {
-      write_string ("Sa");
-      return 1;
-    }
+    abbr = "Sa";
 
   /* Check for std::basic_string.  */
-  if (decl && is_std_substitution (decl, SUBID_BASIC_STRING))
+  else if (decl && is_std_substitution (decl, SUBID_BASIC_STRING))
     {
       if (TYPE_P (node))
        {
@@ -549,26 +554,20 @@ find_substitution (tree node)
                                               SUBID_CHAR_TRAITS)
                  && is_std_substitution_char (TREE_VEC_ELT (args, 2),
                                               SUBID_ALLOCATOR))
-               {
-                 write_string ("Ss");
-                 return 1;
-               }
+               abbr = "Ss";
            }
        }
       else
        /* Substitute for the template name only if this isn't a type.  */
-       {
-         write_string ("Sb");
-         return 1;
-       }
+       abbr = "Sb";
     }
 
   /* Check for basic_{i,o,io}stream.  */
-  if (TYPE_P (node)
-      && cp_type_quals (type) == TYPE_UNQUALIFIED
-      && CLASS_TYPE_P (type)
-      && CLASSTYPE_USE_TEMPLATE (type)
-      && CLASSTYPE_TEMPLATE_INFO (type) != NULL)
+  else if (TYPE_P (node)
+          && cp_type_quals (type) == TYPE_UNQUALIFIED
+          && CLASS_TYPE_P (type)
+          && CLASSTYPE_USE_TEMPLATE (type)
+          && CLASSTYPE_TEMPLATE_INFO (type) != NULL)
     {
       /* First, check for the template
         args <char, std::char_traits<char> > .  */
@@ -581,41 +580,35 @@ find_substitution (tree node)
        {
          /* Got them.  Is this basic_istream?  */
          if (is_std_substitution (decl, SUBID_BASIC_ISTREAM))
-           {
-             write_string ("Si");
-             return 1;
-           }
+           abbr = "Si";
          /* Or basic_ostream?  */
          else if (is_std_substitution (decl, SUBID_BASIC_OSTREAM))
-           {
-             write_string ("So");
-             return 1;
-           }
+           abbr = "So";
          /* Or basic_iostream?  */
          else if (is_std_substitution (decl, SUBID_BASIC_IOSTREAM))
-           {
-             write_string ("Sd");
-             return 1;
-           }
+           abbr = "Sd";
        }
     }
 
   /* Check for namespace std.  */
-  if (decl && DECL_NAMESPACE_STD_P (decl))
+  else if (decl && DECL_NAMESPACE_STD_P (decl))
     {
       write_string ("St");
       return 1;
     }
 
+  tree tags = NULL_TREE;
+  if (OVERLOAD_TYPE_P (node))
+    tags = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (type));
   /* Now check the list of available substitutions for this mangling
      operation.  */
-  for (i = 0; i < size; ++i)
+  if (!abbr || tags) for (i = 0; i < size; ++i)
     {
-      tree candidate = VEC_index (tree, G.substitutions, i);
+      tree candidate = (*G.substitutions)[i];
       /* 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))
        {
@@ -624,8 +617,19 @@ find_substitution (tree node)
        }
     }
 
-  /* No substitution found.  */
-  return 0;
+  if (!abbr)
+    /* No substitution found.  */
+    return 0;
+
+  write_string (abbr);
+  if (tags)
+    {
+      /* If there are ABI tags on the abbreviation, it becomes
+        a substitution candidate.  */
+      write_abi_tags (tags);
+      add_substitution (node);
+    }
+  return 1;
 }
 
 
@@ -656,40 +660,25 @@ write_mangled_name (const tree decl, bool top_level)
             <source-name> without a type."  We cannot write
             overloaded operators that way though, because it contains
             characters invalid in assembler.  */
-         if (abi_version_at_least (2))
-           write_string ("_Z");
-         else
-           G.need_abi_warning = true;
+         write_string ("_Z");
          write_source_name (DECL_NAME (decl));
        }
     }
-  else if (TREE_CODE (decl) == VAR_DECL
+  else if (VAR_P (decl)
+          /* Variable template instantiations are mangled.  */
+          && !(DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
           /* The names of non-static global variables aren't mangled.  */
           && DECL_EXTERNAL_LINKAGE_P (decl)
           && (CP_DECL_CONTEXT (decl) == global_namespace
               /* And neither are `extern "C"' variables.  */
               || DECL_EXTERN_C_P (decl)))
     {
-      if (top_level || abi_version_at_least (2))
-       goto unmangled_name;
-      else
-       {
-         G.need_abi_warning = true;
-         goto mangled_name;
-       }
+      goto unmangled_name;
     }
   else
     {
-    mangled_name:;
       write_string ("_Z");
       write_encoding (decl);
-      if (DECL_LANG_SPECIFIC (decl)
-         && (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)
-             || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)))
-       /* We need a distinct mangled name for these entities, but
-          we should never actually output it.  So, we append some
-          characters the assembler won't like.  */
-       write_string (" *INTERNAL* ");
     }
 }
 
@@ -753,6 +742,10 @@ decl_mangling_context (tree decl)
   if (tcontext != NULL_TREE)
     return tcontext;
 
+  if (TREE_CODE (decl) == TEMPLATE_DECL
+      && DECL_TEMPLATE_RESULT (decl))
+    decl = DECL_TEMPLATE_RESULT (decl);
+
   if (TREE_CODE (decl) == TYPE_DECL
       && LAMBDA_TYPE_P (TREE_TYPE (decl)))
     {
@@ -794,15 +787,24 @@ write_name (tree decl, const int ignore_local_scope)
 
   context = decl_mangling_context (decl);
 
+  gcc_assert (context != NULL_TREE);
+
+  if (abi_version_crosses (7)
+      && ignore_local_scope
+      && TREE_CODE (context) == PARM_DECL)
+    G.need_abi_warning = 1;
+
   /* A decl in :: or ::std scope is treated specially.  The former is
      mangled using <unscoped-name> or <unscoped-template-name>, the
      latter with a special substitution.  Also, a name that is
      directly in a local function scope is also mangled with
      <unscoped-name> rather than a full <nested-name>.  */
-  if (context == NULL
-      || context == global_namespace
+  if (context == global_namespace
       || DECL_NAMESPACE_STD_P (context)
-      || (ignore_local_scope && TREE_CODE (context) == FUNCTION_DECL))
+      || (ignore_local_scope
+         && (TREE_CODE (context) == FUNCTION_DECL
+             || (abi_version_at_least (7)
+                 && TREE_CODE (context) == PARM_DECL))))
     {
       tree template_info;
       /* Is this a template instance?  */
@@ -830,10 +832,10 @@ write_name (tree decl, const int ignore_local_scope)
             directly in that function's scope, either decl or one of
             its enclosing scopes.  */
          tree local_entity = decl;
-         while (context != NULL && context != global_namespace)
+         while (context != global_namespace)
            {
              /* Make sure we're always dealing with decls.  */
-             if (context != NULL && TYPE_P (context))
+             if (TYPE_P (context))
                context = TYPE_NAME (context);
              /* Is this a function?  */
              if (TREE_CODE (context) == FUNCTION_DECL
@@ -876,9 +878,10 @@ write_unscoped_name (const tree decl)
   else
     {
       /* If not, it should be either in the global namespace, or directly
-        in a local function scope.  */
+        in a local function scope.  A lambda can also be mangled in the
+        scope of a default argument.  */
       gcc_assert (context == global_namespace
-                 || context != NULL
+                 || TREE_CODE (context) == PARM_DECL
                  || TREE_CODE (context) == FUNCTION_DECL);
 
       write_unqualified_name (decl);
@@ -901,9 +904,11 @@ write_unscoped_template_name (const tree decl)
 
 /* Write the nested name, including CV-qualifiers, of DECL.
 
-   <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
-                ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+   <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+                ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
 
+   <ref-qualifier> ::= R # & ref-qualifier
+                   ::= O # && ref-qualifier
    <CV-qualifiers> ::= [r] [V] [K]  */
 
 static void
@@ -923,6 +928,13 @@ write_nested_name (const tree decl)
        write_char ('V');
       if (DECL_CONST_MEMFUNC_P (decl))
        write_char ('K');
+      if (FUNCTION_REF_QUALIFIED (TREE_TYPE (decl)))
+       {
+         if (FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (decl)))
+           write_char ('O');
+         else
+           write_char ('R');
+       }
     }
 
   /* Is this a template instance?  */
@@ -942,14 +954,14 @@ write_nested_name (const tree decl)
        }
       else
        {
-         write_prefix (CP_DECL_CONTEXT (decl));
+         write_prefix (decl_mangling_context (decl));
          write_unqualified_name (decl);
        }
     }
   else
     {
       /* No, just use <prefix>  */
-      write_prefix (CP_DECL_CONTEXT (decl));
+      write_prefix (decl_mangling_context (decl));
       write_unqualified_name (decl);
     }
   write_char ('E');
@@ -1006,13 +1018,7 @@ write_prefix (const tree node)
        template_info = TYPE_TEMPLATE_INFO (node);
     }
 
-  /* In G++ 3.2, the name of the template parameter was used.  */
-  if (TREE_CODE (node) == TEMPLATE_TYPE_PARM
-      && !abi_version_at_least (2))
-    G.need_abi_warning = true;
-
-  if (TREE_CODE (node) == TEMPLATE_TYPE_PARM
-      && abi_version_at_least (2))
+  if (TREE_CODE (node) == TEMPLATE_TYPE_PARM)
     write_template_param (node);
   else if (template_info != NULL)
     /* Templated.  */
@@ -1030,7 +1036,7 @@ write_prefix (const tree node)
        }
       else
        {
-         write_prefix (CP_DECL_CONTEXT (decl));
+         write_prefix (decl_mangling_context (decl));
          write_unqualified_name (decl);
        }
     }
@@ -1039,7 +1045,7 @@ write_prefix (const tree node)
     {
       write_prefix (decl_mangling_context (decl));
       write_unqualified_name (decl);
-      if (TREE_CODE (decl) == VAR_DECL
+      if (VAR_P (decl)
          || TREE_CODE (decl) == FIELD_DECL)
        {
          /* <data-member-prefix> := <member source-name> M */
@@ -1060,7 +1066,7 @@ write_template_prefix (const tree node)
 {
   tree decl = DECL_P (node) ? node : TYPE_NAME (node);
   tree type = DECL_P (node) ? TREE_TYPE (node) : node;
-  tree context = CP_DECL_CONTEXT (decl);
+  tree context = decl_mangling_context (decl);
   tree template_info;
   tree templ;
   tree substitution;
@@ -1110,15 +1116,8 @@ write_template_prefix (const tree node)
   if (find_substitution (substitution))
     return;
 
-  /* In G++ 3.2, the name of the template template parameter was used.  */
   if (TREE_TYPE (templ)
-      && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM
-      && !abi_version_at_least (2))
-    G.need_abi_warning = true;
-
-  if (TREE_TYPE (templ)
-      && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM
-      && abi_version_at_least (2))
+      && TREE_CODE (TREE_TYPE (templ)) == TEMPLATE_TEMPLATE_PARM)
     write_template_param (TREE_TYPE (templ));
   else
     {
@@ -1182,25 +1181,27 @@ write_unqualified_id (tree identifier)
 }
 
 static void
-write_unqualified_name (const tree decl)
+write_unqualified_name (tree decl)
 {
   MANGLE_TRACE_TREE ("unqualified-name", decl);
 
-  if (TREE_CODE (decl) == IDENTIFIER_NODE)
+  if (identifier_p (decl))
     {
       write_unqualified_id (decl);
       return;
     }
 
+  bool found = false;
+
   if (DECL_NAME (decl) == NULL_TREE)
     {
+      found = true;
       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;
+      found = true;
       if (DECL_CONSTRUCTOR_P (decl))
        write_special_name_constructor (decl);
       else if (DECL_DESTRUCTOR_P (decl))
@@ -1216,6 +1217,9 @@ write_unqualified_name (const tree decl)
              fn_type = get_mostly_instantiated_function_type (decl);
              type = TREE_TYPE (fn_type);
            }
+         else if (FNDECL_USED_AUTO (decl))
+           type = (DECL_STRUCT_FUNCTION (decl)->language
+                   ->x_auto_return_pattern);
          else
            type = DECL_CONV_FN_TYPE (decl);
          write_conversion_operator_name (type);
@@ -1234,14 +1238,13 @@ write_unqualified_name (const tree decl)
        write_literal_operator_name (DECL_NAME (decl));
       else
        found = false;
-
-      if (found)
-       return;
     }
 
-  if (VAR_OR_FUNCTION_DECL_P (decl) && ! TREE_PUBLIC (decl)
-      && DECL_NAMESPACE_SCOPE_P (decl)
-      && decl_linkage (decl) == lk_internal)
+  if (found)
+    /* OK */;
+  else 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');
@@ -1262,6 +1265,22 @@ write_unqualified_name (const tree decl)
       else
         write_source_name (DECL_NAME (decl));
     }
+
+  /* We use the ABI tags from the primary template, ignoring tags on any
+     specializations.  This is necessary because C++ doesn't require a
+     specialization to be declared before it is used unless the use
+     requires a complete type, but we need to get the tags right on
+     incomplete types as well.  */
+  if (tree tmpl = most_general_template (decl))
+    decl = DECL_TEMPLATE_RESULT (tmpl);
+  /* Don't crash on an unbound class template.  */
+  if (decl)
+    {
+      tree attrs = (TREE_CODE (decl) == TYPE_DECL
+                   ? TYPE_ATTRIBUTES (TREE_TYPE (decl))
+                   : DECL_ATTRIBUTES (decl));
+      write_abi_tags (lookup_attribute ("abi_tag", attrs));
+    }
 }
 
 /* Write the unqualified-name for a conversion operator to TYPE.  */
@@ -1291,19 +1310,64 @@ write_source_name (tree identifier)
   write_identifier (IDENTIFIER_POINTER (identifier));
 }
 
+/* Compare two TREE_STRINGs like strcmp.  */
+
+int
+tree_string_cmp (const void *p1, const void *p2)
+{
+  if (p1 == p2)
+    return 0;
+  tree s1 = *(const tree*)p1;
+  tree s2 = *(const tree*)p2;
+  return strcmp (TREE_STRING_POINTER (s1),
+                TREE_STRING_POINTER (s2));
+}
+
+/* ID is the name of a function or type with abi_tags attribute TAGS.
+   Write out the name, suitably decorated.  */
+
+static void
+write_abi_tags (tree tags)
+{
+  if (tags == NULL_TREE)
+    return;
+
+  tags = TREE_VALUE (tags);
+
+  vec<tree, va_gc> * vec = make_tree_vector();
+
+  for (tree t = tags; t; t = TREE_CHAIN (t))
+    {
+      if (ABI_TAG_IMPLICIT (t))
+       continue;
+      tree str = TREE_VALUE (t);
+      vec_safe_push (vec, str);
+    }
+
+  vec->qsort (tree_string_cmp);
+
+  unsigned i; tree str;
+  FOR_EACH_VEC_ELT (*vec, i, str)
+    {
+      write_string ("B");
+      write_unsigned_number (TREE_STRING_LENGTH (str) - 1);
+      write_identifier (TREE_STRING_POINTER (str));
+    }
+
+  release_tree_vector (vec);
+}
+
 /* Write a user-defined literal operator.
+          ::= li <source-name>    # "" <source-name>
    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);
+  write_identifier (UDLIT_OP_MANGLED_PREFIX);
+  write_unsigned_number (strlen (suffix));
+  write_identifier (suffix);
 }
 
 /* Encode 0 as _, and 1+ as n-1_.  */
@@ -1339,7 +1403,7 @@ nested_anon_class_index (tree type)
 /* <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ */
 
 static void
-write_unnamed_type_name (const tree type ATTRIBUTE_UNUSED)
+write_unnamed_type_name (const tree type)
 {
   int discriminator;
   MANGLE_TRACE_TREE ("unnamed-type-name", type);
@@ -1381,7 +1445,7 @@ write_closure_type_name (const tree type)
 /* Convert NUMBER to ascii using base BASE and generating at least
    MIN_DIGITS characters. BUFFER points to the _end_ of the buffer
    into which to store the characters. Returns the number of
-   characters generated (these will be layed out in advance of where
+   characters generated (these will be laid out in advance of where
    BUFFER points).  */
 
 static int
@@ -1435,8 +1499,8 @@ static inline void
 write_integer_cst (const tree cst)
 {
   int sign = tree_int_cst_sgn (cst);
-
-  if (TREE_INT_CST_HIGH (cst) + (sign < 0))
+  widest_int abs_value = wi::abs (wi::to_widest (cst));
+  if (!wi::fits_uhwi_p (abs_value))
     {
       /* A bignum. We do this in chunks, each of which fits in a
         HOST_WIDE_INT.  */
@@ -1462,8 +1526,7 @@ write_integer_cst (const tree cst)
 
       type = c_common_signed_or_unsigned_type (1, TREE_TYPE (cst));
       base = build_int_cstu (type, chunk);
-      n = build_int_cst_wide (type,
-                             TREE_INT_CST_LOW (cst), TREE_INT_CST_HIGH (cst));
+      n = wide_int_to_tree (type, cst);
 
       if (sign < 0)
        {
@@ -1490,14 +1553,9 @@ write_integer_cst (const tree cst)
   else
     {
       /* A small num.  */
-      unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (cst);
-
       if (sign < 0)
-       {
-         write_char ('n');
-         low = -low;
-       }
-      write_unsigned_number (low);
+       write_char ('n');
+      write_unsigned_number (abs_value.to_uhwi ());
     }
 }
 
@@ -1524,45 +1582,29 @@ write_integer_cst (const tree cst)
 static void
 write_real_cst (const tree value)
 {
-  if (abi_version_at_least (2))
-    {
-      long target_real[4];  /* largest supported float */
-      char buffer[9];       /* eight hex digits in a 32-bit number */
-      int i, limit, dir;
+  long target_real[4];  /* largest supported float */
+  char buffer[9];       /* eight hex digits in a 32-bit number */
+  int i, limit, dir;
 
-      tree type = TREE_TYPE (value);
-      int words = GET_MODE_BITSIZE (TYPE_MODE (type)) / 32;
+  tree type = TREE_TYPE (value);
+  int words = GET_MODE_BITSIZE (TYPE_MODE (type)) / 32;
 
-      real_to_target (target_real, &TREE_REAL_CST (value),
-                     TYPE_MODE (type));
+  real_to_target (target_real, &TREE_REAL_CST (value),
+                 TYPE_MODE (type));
 
-      /* The value in target_real is in the target word order,
-        so we must write it out backward if that happens to be
-        little-endian.  write_number cannot be used, it will
-        produce uppercase.  */
-      if (FLOAT_WORDS_BIG_ENDIAN)
-       i = 0, limit = words, dir = 1;
-      else
-       i = words - 1, limit = -1, dir = -1;
-
-      for (; i != limit; i += dir)
-       {
-         sprintf (buffer, "%08lx", (unsigned long) target_real[i]);
-         write_chars (buffer, 8);
-       }
-    }
+  /* The value in target_real is in the target word order,
+     so we must write it out backward if that happens to be
+     little-endian.  write_number cannot be used, it will
+     produce uppercase.  */
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    i = 0, limit = words, dir = 1;
   else
+    i = words - 1, limit = -1, dir = -1;
+
+  for (; i != limit; i += dir)
     {
-      /* In G++ 3.3 and before the REAL_VALUE_TYPE was written out
-        literally.  Note that compatibility with 3.2 is impossible,
-        because the old floating-point emulator used a different
-        format for REAL_VALUE_TYPE.  */
-      size_t i;
-      for (i = 0; i < sizeof (TREE_REAL_CST (value)); ++i)
-       write_number (((unsigned char *) &TREE_REAL_CST (value))[i],
-                     /*unsigned_p*/ 1,
-                     /*base*/ 16);
-      G.need_abi_warning = 1;
+      sprintf (buffer, "%08lx", (unsigned long) target_real[i]);
+      write_chars (buffer, 8);
     }
 }
 
@@ -1584,25 +1626,21 @@ write_identifier (const char *identifier)
                    ::= C2   # base object constructor
                    ::= C3   # complete object allocating constructor
 
-   Currently, allocating constructors are never used.
-
-   We also need to provide mangled names for the maybe-in-charge
-   constructor, so we treat it here too.  mangle_decl_string will
-   append *INTERNAL* to that, to make sure we never emit it.  */
+   Currently, allocating constructors are never used.  */
 
 static void
 write_special_name_constructor (const tree ctor)
 {
   if (DECL_BASE_CONSTRUCTOR_P (ctor))
     write_string ("C2");
+  /* This is the old-style "[unified]" constructor.
+     In some cases, we may emit this function and call
+     it from the clones in order to share code and save space.  */
+  else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor))
+    write_string ("C4");
   else
     {
-      gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (ctor)
-                 /* Even though we don't ever emit a definition of
-                    the old-style destructor, we still have to
-                    consider entities (like static variables) nested
-                    inside it.  */
-                 || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor));
+      gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (ctor));
       write_string ("C1");
     }
 }
@@ -1612,11 +1650,7 @@ write_special_name_constructor (const tree ctor)
 
      <special-name> ::= D0 # deleting (in-charge) destructor
                    ::= D1 # complete object (in-charge) destructor
-                   ::= D2 # base object (not-in-charge) destructor
-
-   We also need to provide mangled names for the maybe-incharge
-   destructor, so we treat it here too.  mangle_decl_string will
-   append *INTERNAL* to that, to make sure we never emit it.  */
+                   ::= D2 # base object (not-in-charge) destructor  */
 
 static void
 write_special_name_destructor (const tree dtor)
@@ -1625,14 +1659,14 @@ write_special_name_destructor (const tree dtor)
     write_string ("D0");
   else if (DECL_BASE_DESTRUCTOR_P (dtor))
     write_string ("D2");
+  else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor))
+    /* This is the old-style "[unified]" destructor.
+       In some cases, we may emit this function and call
+       it from the clones in order to share code and save space.  */
+    write_string ("D4");
   else
     {
-      gcc_assert (DECL_COMPLETE_DESTRUCTOR_P (dtor)
-                 /* Even though we don't ever emit a definition of
-                    the old-style destructor, we still have to
-                    consider entities (like static variables) nested
-                    inside it.  */
-                 || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (dtor));
+      gcc_assert (DECL_COMPLETE_DESTRUCTOR_P (dtor));
       write_string ("D1");
     }
 }
@@ -1649,7 +1683,7 @@ local_class_index (tree entity)
   tree ctx = TYPE_CONTEXT (entity);
   for (ix = 0; ; ix++)
     {
-      tree type = VEC_index (tree, local_classes, ix);
+      tree type = (*local_classes)[ix];
       if (type == entity)
        return discriminator;
       if (TYPE_CONTEXT (type) == ctx
@@ -1696,8 +1730,8 @@ discriminator_for_local_entity (tree entity)
    string literals used in FUNCTION.  */
 
 static int
-discriminator_for_string_literal (tree function ATTRIBUTE_UNUSED,
-                                 tree string ATTRIBUTE_UNUSED)
+discriminator_for_string_literal (tree /*function*/,
+                                 tree /*string*/)
 {
   /* For now, we don't discriminate amongst string literals.  */
   return 0;
@@ -1828,7 +1862,23 @@ write_type (tree type)
        mangle the unqualified type.  The recursive call is needed here
        since both the qualified and unqualified types are substitution
        candidates.  */
-    write_type (TYPE_MAIN_VARIANT (type));
+    {
+      tree t = TYPE_MAIN_VARIANT (type);
+      if (TREE_CODE (t) == FUNCTION_TYPE
+         || TREE_CODE (t) == METHOD_TYPE)
+       {
+         t = build_ref_qualified_type (t, type_memfn_rqual (type));
+         if (abi_version_at_least (8))
+           /* Avoid adding the unqualified function type as a substitution.  */
+           write_function_type (t);
+         else
+           write_type (t);
+         if (abi_version_crosses (8))
+           G.need_abi_warning = 1;
+       }
+      else
+       write_type (t);
+    }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     /* It is important not to use the TYPE_MAIN_VARIANT of TYPE here
        so that the cv-qualification of the element type is available
@@ -1840,6 +1890,9 @@ write_type (tree type)
 
       /* See through any typedefs.  */
       type = TYPE_MAIN_VARIANT (type);
+      if (TREE_CODE (type) == FUNCTION_TYPE
+         || TREE_CODE (type) == METHOD_TYPE)
+       type = build_ref_qualified_type (type, type_memfn_rqual (type_orig));
 
       /* According to the C++ ABI, some library classes are passed the
         same as the scalar type of their single member and use the same
@@ -1847,7 +1900,7 @@ write_type (tree type)
       if (TREE_CODE (type) == RECORD_TYPE && TYPE_TRANSPARENT_AGGR (type))
        type = TREE_TYPE (first_field (type));
 
-      if (TYPE_PTRMEM_P (type))
+      if (TYPE_PTRDATAMEM_P (type))
        write_pointer_to_member_type (type);
       else
         {
@@ -1860,7 +1913,7 @@ write_type (tree type)
              write_string (target_mangling);
              /* Add substitutions for types other than fundamental
                 types.  */
-             if (TREE_CODE (type) != VOID_TYPE
+             if (!VOID_TYPE_P (type)
                  && TREE_CODE (type) != INTEGER_TYPE
                  && TREE_CODE (type) != REAL_TYPE
                  && TREE_CODE (type) != BOOLEAN_TYPE)
@@ -1914,7 +1967,7 @@ write_type (tree type)
 
            case POINTER_TYPE:
            case REFERENCE_TYPE:
-             if (TREE_CODE (type) == POINTER_TYPE)
+             if (TYPE_PTR_P (type))
                write_char ('P');
              else if (TYPE_REF_IS_RVALUE (type))
                write_char ('O');
@@ -1927,14 +1980,29 @@ write_type (tree type)
                   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);
+               if (TREE_CODE (target) == FUNCTION_TYPE)
+                 {
+                   if (abi_version_crosses (5)
+                       && TYPE_QUALS (target) != TYPE_UNQUALIFIED)
+                     G.need_abi_warning = 1;
+                   if (abi_version_at_least (5))
+                     target = build_qualified_type (target, TYPE_UNQUALIFIED);
+                 }
                write_type (target);
              }
              break;
 
            case TEMPLATE_TYPE_PARM:
+             if (is_auto (type))
+               {
+                 if (AUTO_IS_DECLTYPE (type))
+                   write_identifier ("Dc");
+                 else
+                   write_identifier ("Da");
+                 ++is_builtin_type;
+                 break;
+               }
+             /* else fall through.  */
            case TEMPLATE_PARM_INDEX:
              write_template_param (type);
              break;
@@ -1959,10 +2027,9 @@ write_type (tree type)
                  write_char ('_');
                }
              else
-               {
-                 G.need_abi_warning = 1;
-                 write_string ("U8__vector");
-               }
+               write_string ("U8__vector");
+             if (abi_version_crosses (4))
+               G.need_abi_warning = 1;
              write_type (TREE_TYPE (type));
              break;
 
@@ -1977,8 +2044,7 @@ write_type (tree 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))
+             if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
                {
                  tree expr = DECLTYPE_TYPE_EXPR (type);
                  tree etype = NULL_TREE;
@@ -1999,9 +2065,13 @@ write_type (tree type)
 
                  if (etype && !type_uses_auto (etype))
                    {
-                     G.need_abi_warning = 1;
-                     write_type (etype);
-                     return;
+                     if (abi_version_crosses (5))
+                       G.need_abi_warning = 1;
+                     if (!abi_version_at_least (5))
+                       {
+                         write_type (etype);
+                         return;
+                       }
                    }
                }
 
@@ -2018,6 +2088,10 @@ write_type (tree type)
 
            case NULLPTR_TYPE:
              write_string ("Dn");
+             if (abi_version_at_least (7))
+               ++is_builtin_type;
+             if (abi_version_crosses (7))
+               G.need_abi_warning = 1;
              break;
 
            case TYPEOF_TYPE:
@@ -2266,7 +2340,7 @@ write_builtin_type (tree type)
    METHOD_TYPE.  The return type is mangled before the parameter
    types.
 
-     <function-type> ::= F [Y] <bare-function-type> E   */
+     <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E   */
 
 static void
 write_function_type (const tree type)
@@ -2299,6 +2373,13 @@ write_function_type (const tree type)
      See [dcl.link].  */
   write_bare_function_type (type, /*include_return_type_p=*/1,
                            /*decl=*/NULL);
+  if (FUNCTION_REF_QUALIFIED (type))
+    {
+      if (FUNCTION_RVALUE_QUALIFIED (type))
+       write_char ('O');
+      else
+       write_char ('R');
+    }
   write_char ('E');
 }
 
@@ -2458,7 +2539,7 @@ write_template_args (tree args)
 static void
 write_member_name (tree member)
 {
-  if (TREE_CODE (member) == IDENTIFIER_NODE)
+  if (identifier_p (member))
     write_unqualified_id (member);
   else if (DECL_P (member))
     write_unqualified_name (member);
@@ -2494,13 +2575,17 @@ write_expression (tree expr)
      is converted (via qualification conversions) to another
      type.  */
   while (TREE_CODE (expr) == NOP_EXPR
+        /* Parentheses aren't mangled.  */
+        || code == PAREN_EXPR
         || TREE_CODE (expr) == NON_LVALUE_EXPR)
     {
       expr = TREE_OPERAND (expr, 0);
       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);
@@ -2526,7 +2611,7 @@ write_expression (tree expr)
     write_template_param (expr);
   /* Handle literals.  */
   else if (TREE_CODE_CLASS (code) == tcc_constant
-          || (abi_version_at_least (2) && code == CONST_DECL))
+          || code == CONST_DECL)
     write_template_arg_literal (expr);
   else if (code == PARM_DECL && DECL_ARTIFICIAL (expr))
     {
@@ -2555,7 +2640,7 @@ write_expression (tree expr)
              write_char ('L');
              write_unsigned_number (delta - 1);
            }
-         else
+         if (abi_version_crosses (5))
            G.need_abi_warning = true;
        }
       write_char ('p');
@@ -2563,15 +2648,17 @@ write_expression (tree expr)
     }
   else if (DECL_P (expr))
     {
-      /* G++ 3.2 incorrectly mangled non-type template arguments of
-        enumeration type using their names.  */
-      if (code == CONST_DECL)
-       G.need_abi_warning = 1;
       write_char ('L');
       write_mangled_name (expr, false);
       write_char ('E');
     }
   else if (TREE_CODE (expr) == SIZEOF_EXPR
+          && SIZEOF_EXPR_TYPE_P (expr))
+    {
+      write_string ("st");
+      write_type (TREE_TYPE (TREE_OPERAND (expr, 0)));
+    }
+  else if (TREE_CODE (expr) == SIZEOF_EXPR
           && TYPE_P (TREE_OPERAND (expr, 0)))
     {
       write_string ("st");
@@ -2583,19 +2670,19 @@ write_expression (tree expr)
       write_string ("at");
       write_type (TREE_OPERAND (expr, 0));
     }
-  else if (TREE_CODE (expr) == SCOPE_REF)
+  else if (code == SCOPE_REF
+          || code == BASELINK)
     {
-      tree scope = TREE_OPERAND (expr, 0);
-      tree member = TREE_OPERAND (expr, 1);
-
-      if (!abi_version_at_least (2) && DECL_P (member))
+      tree scope, member;
+      if (code == SCOPE_REF)
        {
-         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);
+         scope = TREE_OPERAND (expr, 0);
+         member = TREE_OPERAND (expr, 1);
+       }
+      else
+       {
+         scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (expr));
+         member = BASELINK_FUNCTIONS (expr);
        }
 
       /* If the MEMBER is a real declaration, then the qualifying
@@ -2603,7 +2690,7 @@ write_expression (tree expr)
         SCOPE_REF in those cases, but sometimes we do.  If the second
         argument is a DECL, then the name must not have been
         dependent.  */
-      else if (DECL_P (member))
+      if (DECL_P (member))
        write_expression (member);
       else
        {
@@ -2612,13 +2699,13 @@ write_expression (tree expr)
          write_member_name (member);
        }
     }
-  else if (TREE_CODE (expr) == INDIRECT_REF
+  else if (INDIRECT_REF_P (expr)
           && 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)
+  else if (identifier_p (expr))
     {
       /* An operator name appearing as a dependent name needs to be
         specially marked to disambiguate between a use of the operator
@@ -2685,14 +2772,13 @@ write_expression (tree expr)
       write_type (type);
 
       if (init && TREE_CODE (init) == TREE_LIST
-         && TREE_CODE (TREE_VALUE (init)) == CONSTRUCTOR
-         && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))
+         && DIRECT_LIST_INIT_P (TREE_VALUE (init)))
        write_expression (TREE_VALUE (init));
       else
        {
          if (init)
            write_string ("pi");
-         if (init && init != void_zero_node)
+         if (init && init != void_node)
            for (t = init; t; t = TREE_CHAIN (t))
              write_expression (TREE_VALUE (t));
          write_char ('E');
@@ -2724,7 +2810,7 @@ write_expression (tree expr)
     }
   else if (code == CONSTRUCTOR)
     {
-      VEC(constructor_elt,gc)* elts = CONSTRUCTOR_ELTS (expr);
+      vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (expr);
       unsigned i; tree val;
 
       if (BRACE_ENCLOSED_INITIALIZER_P (expr))
@@ -2773,11 +2859,16 @@ write_expression (tree expr)
            {
              write_string (operator_name_info[(int)code].mangled_name);
              ob = TREE_OPERAND (ob, 0);
+             write_expression (ob);
            }
-         else
-           write_string ("dt");
+         else if (!is_dummy_object (ob))
+           {
+             write_string ("dt");
+             write_expression (ob);
+           }
+         /* else, for a non-static data member with no associated object (in
+            unevaluated context), use the unresolved-name mangling.  */
 
-         write_expression (ob);
          write_member_name (TREE_OPERAND (expr, 1));
          return;
        }
@@ -2786,17 +2877,28 @@ write_expression (tree expr)
       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))
+      if (code == CONST_CAST_EXPR
+         || code == STATIC_CAST_EXPR)
        {
-         name = operator_name_info[CAST_EXPR].mangled_name;
-         G.need_abi_warning = 1;
+         if (abi_version_crosses (6))
+           G.need_abi_warning = 1;
+         if (!abi_version_at_least (6))
+           name = operator_name_info[CAST_EXPR].mangled_name;
        }
 
       if (name == NULL)
        {
-         sorry ("mangling %C", code);
+         switch (code)
+           {
+           case TRAIT_EXPR:
+             error ("use of built-in trait %qE in function signature; "
+                    "use library traits instead", expr);
+             break;
+
+           default:
+             sorry ("mangling %C", code);
+             break;
+           }
          return;
        }
       else
@@ -2852,7 +2954,7 @@ write_expression (tree expr)
        case PREDECREMENT_EXPR:
          if (abi_version_at_least (6))
            write_char ('_');
-         else
+         if (abi_version_crosses (6))
            G.need_abi_warning = 1;
          /* Fall through.  */
 
@@ -2915,6 +3017,25 @@ write_template_arg_literal (const tree value)
        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;
@@ -2960,10 +3081,7 @@ write_template_arg (tree node)
         internal consistency, such arguments use a conversion from
         address of object to reference type.  */
       gcc_assert (TREE_CODE (TREE_OPERAND (node, 0)) == ADDR_EXPR);
-      if (abi_version_at_least (2))
-       node = TREE_OPERAND (TREE_OPERAND (node, 0), 0);
-      else
-       G.need_abi_warning = 1;
+      node = TREE_OPERAND (TREE_OPERAND (node, 0), 0);
     }
 
   if (TREE_CODE (node) == BASELINK
@@ -2971,7 +3089,7 @@ write_template_arg (tree node)
     {
       if (abi_version_at_least (6))
        node = BASELINK_FUNCTIONS (node);
-      else
+      if (abi_version_crosses (6))
        /* We wrongly wrapped a class-scope function in X/E.  */
        G.need_abi_warning = 1;
     }
@@ -2984,10 +3102,9 @@ write_template_arg (tree node)
       if (abi_version_at_least (6))
        write_char ('J');
       else
-       {
-         write_char ('I');
-         G.need_abi_warning = 1;
-       }
+       write_char ('I');
+      if (abi_version_crosses (6))
+       G.need_abi_warning = 1;
       for (i = 0; i < length; ++i)
         write_template_arg (TREE_VEC_ELT (args, i));
       write_char ('E');
@@ -2998,25 +3115,20 @@ 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)
+          || code == CONST_DECL
           || null_member_pointer_value_p (node))
     write_template_arg_literal (node);
   else if (DECL_P (node))
     {
-      /* Until ABI version 2, non-type template arguments of
-        enumeration type were mangled using their names.  */
-      if (code == CONST_DECL && !abi_version_at_least (2))
-       G.need_abi_warning = 1;
       write_char ('L');
       /* Until ABI version 3, the underscore before the mangled name
         was incorrectly omitted.  */
       if (!abi_version_at_least (3))
-       {
-         G.need_abi_warning = 1;
-         write_char ('Z');
-       }
+       write_char ('Z');
       else
        write_string ("_Z");
+      if (abi_version_crosses (3))
+       G.need_abi_warning = 1;
       write_encoding (node);
       write_char ('E');
     }
@@ -3071,21 +3183,16 @@ write_array_type (const tree type)
        {
          /* The ABI specifies that we should mangle the number of
             elements in the array, not the largest allowed index.  */
-         max = size_binop (PLUS_EXPR, max, size_one_node);
-         write_unsigned_number (tree_low_cst (max, 1));
+         offset_int wmax = wi::to_offset (max) + 1;
+         /* Truncate the result - this will mangle [0, SIZE_INT_MAX]
+            number of elements as zero.  */
+         wmax = wi::zext (wmax, TYPE_PRECISION (TREE_TYPE (max)));
+         gcc_assert (wi::fits_uhwi_p (wmax));
+         write_unsigned_number (wmax.to_uhwi ());
        }
       else
        {
          max = TREE_OPERAND (max, 0);
-         if (!abi_version_at_least (2))
-           {
-             /* value_dependent_expression_p presumes nothing is
-                dependent when PROCESSING_TEMPLATE_DECL is zero.  */
-             ++processing_template_decl;
-             if (!value_dependent_expression_p (max))
-               G.need_abi_warning = 1;
-             --processing_template_decl;
-           }
          write_expression (max);
        }
 
@@ -3202,15 +3309,10 @@ start_mangling (const tree entity)
    warning.  */
 
 static void
-finish_mangling_internal (const bool warn)
+finish_mangling_internal (void)
 {
-  if (warn_abi && warn && G.need_abi_warning)
-    warning (OPT_Wabi, "the mangled name of %qD will change in a future "
-            "version of GCC",
-            G.entity);
-
   /* Clear all the substitutions.  */
-  VEC_truncate (tree, G.substitutions, 0);
+  vec_safe_truncate (G.substitutions, 0);
 
   /* Null-terminate the string.  */
   write_char ('\0');
@@ -3220,18 +3322,18 @@ finish_mangling_internal (const bool warn)
 /* Like finish_mangling_internal, but return the mangled string.  */
 
 static inline const char *
-finish_mangling (const bool warn)
+finish_mangling (void)
 {
-  finish_mangling_internal (warn);
+  finish_mangling_internal ();
   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_get_identifier (void)
 {
-  finish_mangling_internal (warn);
+  finish_mangling_internal ();
   /* Don't obstack_finish here, and the next start_mangling will
      remove the identifier.  */
   return get_identifier ((const char *) obstack_base (mangle_obstack));
@@ -3244,7 +3346,7 @@ init_mangle (void)
 {
   gcc_obstack_init (&name_obstack);
   name_base = obstack_alloc (&name_obstack, 0);
-  G.substitutions = NULL;
+  vec_alloc (G.substitutions, 0);
 
   /* Cache these identifiers for quick comparison when checking for
      standard substitutions.  */
@@ -3289,7 +3391,7 @@ mangle_decl_string (const tree decl)
   else
     write_mangled_name (decl, true);
 
-  result = finish_mangling_get_identifier (/*warn=*/true);
+  result = finish_mangling_get_identifier ();
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_decl_string = '%s'\n\n",
             IDENTIFIER_POINTER (result));
@@ -3318,43 +3420,83 @@ get_mangled_id (tree decl)
 void
 mangle_decl (const tree decl)
 {
-  tree id = get_mangled_id (decl);
+  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.  */
+      && TREE_CODE (decl) != TYPE_DECL
       && !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
+      tree id2;
 
       SET_IDENTIFIER_GLOBAL_VALUE (id, decl);
       if (IDENTIFIER_GLOBAL_VALUE (id) != decl)
-       inform (DECL_SOURCE_LOCATION (decl), "-fabi-version=6 (or =0) "
+       inform (DECL_SOURCE_LOCATION (decl), "a later -fabi-version= (or =0) "
                "avoids this error with a change in mangling");
 
-#ifdef ASM_OUTPUT_DEF
       save_ver = flag_abi_version;
-      flag_abi_version = 0;
+      flag_abi_version = flag_abi_compat_version;
       id2 = mangle_decl_string (decl);
       id2 = targetm.mangle_decl_assembler_name (decl, id2);
       flag_abi_version = save_ver;
 
-      alias = make_alias_for (decl, id2);
+      if (id2 == id)
+       return;
+
+      if (warn_abi)
+       {
+         if (flag_abi_compat_version != 0
+             && abi_version_at_least (flag_abi_compat_version))
+           warning (OPT_Wabi, "the mangled name of %q+D changed between "
+                    "-fabi-version=%d (%D) and -fabi-version=%d (%D)",
+                    G.entity, flag_abi_compat_version, id2,
+                    flag_abi_version, id);
+         else
+           warning (OPT_Wabi, "the mangled name of %q+D changes between "
+                    "-fabi-version=%d (%D) and -fabi-version=%d (%D)",
+                    G.entity, flag_abi_version, id,
+                    flag_abi_compat_version, id2);
+       }
+
+#ifdef ASM_OUTPUT_DEF
+      if (flag_abi_compat_version != 0
+         && IDENTIFIER_GLOBAL_VALUE (id2))
+       return;
+
+      tree alias = make_alias_for (decl, id2);
+      SET_IDENTIFIER_GLOBAL_VALUE (id2, alias);
       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);
+       {
+         /* Don't create an alias to an unreferenced function.  */
+         if (struct cgraph_node *n = cgraph_node::get (decl))
+           n->create_same_body_alias (alias, decl);
+       }
       else
-       varpool_extra_name_alias (alias, decl);
+       varpool_node::create_extra_name_alias (alias, decl);
 #endif
     }
 }
@@ -3368,7 +3510,7 @@ mangle_type_string (const tree type)
 
   start_mangling (type);
   write_type (type);
-  result = finish_mangling (/*warn=*/false);
+  result = finish_mangling ();
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_type_string = '%s'\n\n", result);
   return result;
@@ -3393,7 +3535,7 @@ mangle_special_for_type (const tree type, const char *code)
 
   /* Add the type.  */
   write_type (type);
-  result = finish_mangling_get_identifier (/*warn=*/false);
+  result = finish_mangling_get_identifier ();
 
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_special_for_type = %s\n\n",
@@ -3464,7 +3606,7 @@ mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
   write_char ('_');
   write_type (BINFO_TYPE (binfo));
 
-  result = finish_mangling_get_identifier (/*warn=*/false);
+  result = finish_mangling_get_identifier ();
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n",
             IDENTIFIER_POINTER (result));
@@ -3543,32 +3685,38 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
   /* Scoped name.  */
   write_encoding (fn_decl);
 
-  result = finish_mangling_get_identifier (/*warn=*/false);
+  result = finish_mangling_get_identifier ();
   if (DEBUG_MANGLE)
     fprintf (stderr, "mangle_thunk = %s\n\n", IDENTIFIER_POINTER (result));
   return result;
 }
 
+struct conv_type_hasher : ggc_hasher<tree>
+{
+  static hashval_t hash (tree);
+  static bool equal (tree, tree);
+};
+
 /* This hash table maps TYPEs to the IDENTIFIER for a conversion
    operator to TYPE.  The nodes are IDENTIFIERs whose TREE_TYPE is the
    TYPE.  */
 
-static GTY ((param_is (union tree_node))) htab_t conv_type_names;
+static GTY (()) hash_table<conv_type_hasher> *conv_type_names;
 
 /* Hash a node (VAL1) in the table.  */
 
-static hashval_t
-hash_type (const void *val)
+hashval_t
+conv_type_hasher::hash (tree val)
 {
-  return (hashval_t) TYPE_UID (TREE_TYPE ((const_tree) val));
+  return (hashval_t) TYPE_UID (TREE_TYPE (val));
 }
 
 /* Compare VAL1 (a node in the table) with VAL2 (a TYPE).  */
 
-static int
-compare_type (const void *val1, const void *val2)
+bool
+conv_type_hasher::equal (tree val1, tree val2)
 {
-  return TREE_TYPE ((const_tree) val1) == (const_tree) val2;
+  return TREE_TYPE (val1) == val2;
 }
 
 /* Return an identifier for the mangled unqualified name for a
@@ -3578,25 +3726,25 @@ compare_type (const void *val1, const void *val2)
 tree
 mangle_conv_op_name_for_type (const tree type)
 {
-  void **slot;
+  tree *slot;
   tree identifier;
 
   if (type == error_mark_node)
     return error_mark_node;
 
   if (conv_type_names == NULL)
-    conv_type_names = htab_create_ggc (31, &hash_type, &compare_type, NULL);
+    conv_type_names = hash_table<conv_type_hasher>::create_ggc (31);
 
-  slot = htab_find_slot_with_hash (conv_type_names, type,
-                                  (hashval_t) TYPE_UID (type), INSERT);
-  identifier = (tree)*slot;
+  slot = conv_type_names->find_slot_with_hash (type,
+                                              (hashval_t) TYPE_UID (type),
+                                              INSERT);
+  identifier = *slot;
   if (!identifier)
     {
       char buffer[64];
 
        /* Create a unique name corresponding to TYPE.  */
-      sprintf (buffer, "operator %lu",
-              (unsigned long) htab_elements (conv_type_names));
+      sprintf (buffer, "operator %lu", conv_type_names->elements ());
       identifier = get_identifier (buffer);
       *slot = identifier;
 
@@ -3612,6 +3760,21 @@ mangle_conv_op_name_for_type (const tree type)
   return identifier;
 }
 
+/* Write out the appropriate string for this variable when generating
+   another mangled name based on this one.  */
+
+static void
+write_guarded_var_name (const tree variable)
+{
+  if (DECL_NAME (variable)
+      && strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
+    /* The name of a guard variable for a reference temporary should refer
+       to the reference, not the temporary.  */
+    write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
+  else
+    write_name (variable, /*ignore_local_scope=*/0);
+}
+
 /* Return an identifier for the name of an initialization guard
    variable for indicated VARIABLE.  */
 
@@ -3620,13 +3783,46 @@ mangle_guard_variable (const tree variable)
 {
   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
-       to the reference, not the temporary.  */
-    write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
-  else
-    write_name (variable, /*ignore_local_scope=*/0);
-  return finish_mangling_get_identifier (/*warn=*/false);
+  write_guarded_var_name (variable);
+  return finish_mangling_get_identifier ();
+}
+
+/* Return an identifier for the name of a thread_local initialization
+   function for VARIABLE.  */
+
+tree
+mangle_tls_init_fn (const tree variable)
+{
+  start_mangling (variable);
+  write_string ("_ZTH");
+  write_guarded_var_name (variable);
+  return finish_mangling_get_identifier ();
+}
+
+/* Return an identifier for the name of a thread_local wrapper
+   function for VARIABLE.  */
+
+#define TLS_WRAPPER_PREFIX "_ZTW"
+
+tree
+mangle_tls_wrapper_fn (const tree variable)
+{
+  start_mangling (variable);
+  write_string (TLS_WRAPPER_PREFIX);
+  write_guarded_var_name (variable);
+  return finish_mangling_get_identifier ();
+}
+
+/* Return true iff FN is a thread_local wrapper function.  */
+
+bool
+decl_tls_wrapper_p (const tree fn)
+{
+  if (TREE_CODE (fn) != FUNCTION_DECL)
+    return false;
+  tree name = DECL_NAME (fn);
+  return strncmp (IDENTIFIER_POINTER (name), TLS_WRAPPER_PREFIX,
+                 strlen (TLS_WRAPPER_PREFIX)) == 0;
 }
 
 /* Return an identifier for the name of a temporary variable used to
@@ -3644,7 +3840,7 @@ mangle_ref_init_variable (const tree variable)
   /* Avoid name clashes with aggregate initialization of multiple
      references at once.  */
   write_unsigned_number (temp_count++);
-  return finish_mangling_get_identifier (/*warn=*/false);
+  return finish_mangling_get_identifier ();
 }
 \f
 
@@ -3671,4 +3867,34 @@ write_java_integer_type_codes (const tree type)
     gcc_unreachable ();
 }
 
+/* Given a CLASS_TYPE, such as a record for std::bad_exception this
+   function generates a mangled name for the vtable map variable of
+   the class type.  For example, if the class type is
+   "std::bad_exception", the mangled name for the class is
+   "St13bad_exception".  This function would generate the name
+   "_ZN4_VTVISt13bad_exceptionE12__vtable_mapE", which unmangles as:
+   "_VTV<std::bad_exception>::__vtable_map".  */
+
+
+char *
+get_mangled_vtable_map_var_name (tree class_type)
+{
+  char *var_name = NULL;
+  const char *prefix = "_ZN4_VTVI";
+  const char *postfix = "E12__vtable_mapE";
+
+  gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
+
+  tree class_id = DECL_ASSEMBLER_NAME (TYPE_NAME (class_type));
+  unsigned int len = strlen (IDENTIFIER_POINTER (class_id)) +
+                     strlen (prefix) +
+                     strlen (postfix) + 1;
+
+  var_name = (char *) xmalloc (len);
+
+  sprintf (var_name, "%s%s%s", prefix, IDENTIFIER_POINTER (class_id), postfix);
+
+  return var_name;
+}
+
 #include "gt-cp-mangle.h"