move many gc hashtab to hash_table
[platform/upstream/gcc.git] / gcc / cp / mangle.c
index a48d476..6b8f706 100644 (file)
@@ -1,5 +1,5 @@
 /* Name mangling for the 3.0 C++ ABI.
-   Copyright (C) 2000-2013 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.
@@ -49,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.  */
 
@@ -69,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)
@@ -178,7 +182,7 @@ 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.  */
@@ -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
@@ -506,10 +513,11 @@ find_substitution (tree node)
   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,35 +580,29 @@ 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 = (*G.substitutions)[i];
       /* NODE is a matched to a candidate if it's the same decl node or
@@ -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,13 +787,19 @@ 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
@@ -833,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
@@ -879,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);
@@ -904,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
@@ -926,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?  */
@@ -1009,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.  */
@@ -1042,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 */
@@ -1113,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
     {
@@ -1185,11 +1181,11 @@ 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;
@@ -1221,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);
@@ -1267,10 +1266,21 @@ write_unqualified_name (const tree decl)
         write_source_name (DECL_NAME (decl));
     }
 
-  tree attrs = (TREE_CODE (decl) == TYPE_DECL
-               ? TYPE_ATTRIBUTES (TREE_TYPE (decl))
-               : DECL_ATTRIBUTES (decl));
-  write_abi_tags (lookup_attribute ("abi_tag", attrs));
+  /* 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.  */
@@ -1328,6 +1338,8 @@ write_abi_tags (tree tags)
 
   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);
     }
@@ -1433,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
@@ -1487,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.  */
@@ -1514,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)
        {
@@ -1542,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 ());
     }
 }
 
@@ -1576,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);
     }
 }
 
@@ -1636,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");
     }
 }
@@ -1664,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)
@@ -1677,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");
     }
 }
@@ -1880,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
@@ -1892,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
@@ -1912,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)
@@ -1966,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');
@@ -1979,9 +1980,14 @@ 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;
@@ -1989,7 +1995,10 @@ write_type (tree type)
            case TEMPLATE_TYPE_PARM:
              if (is_auto (type))
                {
-                 write_identifier ("Da");
+                 if (AUTO_IS_DECLTYPE (type))
+                   write_identifier ("Dc");
+                 else
+                   write_identifier ("Da");
                  ++is_builtin_type;
                  break;
                }
@@ -2018,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;
 
@@ -2036,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;
@@ -2058,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;
+                       }
                    }
                }
 
@@ -2079,6 +2090,8 @@ write_type (tree 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:
@@ -2327,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)
@@ -2360,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');
 }
 
@@ -2519,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);
@@ -2555,6 +2575,8 @@ 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);
@@ -2589,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))
     {
@@ -2618,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');
@@ -2626,10 +2648,6 @@ 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');
@@ -2667,22 +2685,12 @@ write_expression (tree 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.  */
-      else if (DECL_P (member))
+      if (DECL_P (member))
        write_expression (member);
       else
        {
@@ -2691,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
@@ -2764,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');
@@ -2852,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;
        }
@@ -2865,12 +2877,13 @@ 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)
@@ -2941,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.  */
 
@@ -3068,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
@@ -3079,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;
     }
@@ -3092,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');
@@ -3106,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');
     }
@@ -3179,25 +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.  */
-         double_int dmax = tree_to_double_int (max) + double_int_one;
+         offset_int wmax = wi::to_offset (max) + 1;
          /* Truncate the result - this will mangle [0, SIZE_INT_MAX]
             number of elements as zero.  */
-         dmax = dmax.zext (TYPE_PRECISION (TREE_TYPE (max)));
-         gcc_assert (dmax.fits_uhwi ());
-         write_unsigned_number (dmax.low);
+         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);
        }
 
@@ -3314,13 +3309,8 @@ 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_safe_truncate (G.substitutions, 0);
 
@@ -3332,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));
@@ -3401,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));
@@ -3449,38 +3439,64 @@ mangle_decl (const tree decl)
 
   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
     }
 }
@@ -3494,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;
@@ -3519,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",
@@ -3590,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));
@@ -3669,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
@@ -3704,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;
 
@@ -3744,7 +3766,8 @@ mangle_conv_op_name_for_type (const tree type)
 static void
 write_guarded_var_name (const tree variable)
 {
-  if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
+  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);
@@ -3761,7 +3784,7 @@ mangle_guard_variable (const tree variable)
   start_mangling (variable);
   write_string ("_ZGV");
   write_guarded_var_name (variable);
-  return finish_mangling_get_identifier (/*warn=*/false);
+  return finish_mangling_get_identifier ();
 }
 
 /* Return an identifier for the name of a thread_local initialization
@@ -3773,7 +3796,7 @@ mangle_tls_init_fn (const tree variable)
   start_mangling (variable);
   write_string ("_ZTH");
   write_guarded_var_name (variable);
-  return finish_mangling_get_identifier (/*warn=*/false);
+  return finish_mangling_get_identifier ();
 }
 
 /* Return an identifier for the name of a thread_local wrapper
@@ -3787,7 +3810,7 @@ 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 (/*warn=*/false);
+  return finish_mangling_get_identifier ();
 }
 
 /* Return true iff FN is a thread_local wrapper function.  */
@@ -3817,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
 
@@ -3844,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"