diff --git a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst
index ad0be51..ce6a4da 100644
--- a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst
+++ b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst
@@ -123,6 +123,12 @@ It is also possible to import a C++ exception using the following syntax:
 The ``External_Name`` is the name of the C++ RTTI symbol. You can then
 cover a specific C++ exception in an exception handler.
 
+RTTI symbols undergo C++ name mangling, which can make for identifiers
+that are inconvenient to use.  An alias with a mnemonic name can be
+introduced by adding attribute ``exalias`` to the class that the RTTI
+symbol refers to.
+
+
 .. _Interfacing_to_COBOL:
 
 Interfacing to COBOL
diff --git a/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst b/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
index b8729d0..2a13a24 100644
--- a/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
+++ b/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
@@ -4279,6 +4279,7 @@ and two public primitives to set and get the value of this attribute.
       public:
         virtual void Set_Age (int New_Age);
         virtual int Age ();
+        __attribute__ ((__exalias__ ("Ctor_For_Animal"))) // extra alias
         Animal() {Age_Count = 0;};
       private:
         int Age_Count;
@@ -4311,6 +4312,7 @@ both Carnivore and Domestic, that is:
         virtual int  Number_Of_Teeth ();
         virtual void Set_Owner (char* Name);
 
+        __attribute__ ((__exalias__ ("Ctor_For_Dog"))) // mnemonic alias
         Dog(); // Constructor
       private:
         int  Tooth_Count;
@@ -4349,7 +4351,8 @@ how to import these C++ declarations from the Ada side:
 
        function New_Animal return Animal;
        pragma CPP_Constructor (New_Animal);
-       pragma Import (CPP, New_Animal, "_ZN6AnimalC1Ev");
+       pragma Import (CPP, New_Animal,
+                      "_ZN6AnimalC1Ev"); -- or "Ctor_For_Animal"
 
        type Dog is new Animal and Carnivore and Domestic with record
          Tooth_Count : Natural;
@@ -4365,7 +4368,7 @@ how to import these C++ declarations from the Ada side:
 
        function New_Dog return Dog;
        pragma CPP_Constructor (New_Dog);
-       pragma Import (CPP, New_Dog, "_ZN3DogC2Ev");
+       pragma Import (CPP, New_Dog, "Ctor_For_Dog"); -- or "_ZN3DogC1Ev"
      end Animals;
 
 Thanks to the compatibility between GNAT run-time structures and the C++ ABI,
@@ -4382,12 +4385,13 @@ because the dispatch table associated with these tagged types will be built
 in the C++ side and therefore will not contain the predefined Ada primitives
 which Ada would otherwise expect.
 
-As the reader can see there is no need to indicate the C++ mangled names
-associated with each subprogram because it is assumed that all the calls to
-these primitives will be dispatching calls. The only exception is the
-constructor, which must be registered with the compiler by means of
-``pragma CPP_Constructor`` and needs to provide its associated C++
-mangled name because the Ada compiler generates direct calls to it.
+As the reader can see there is no need to indicate the C++ mangled
+names (or extra aliases) associated with each subprogram because it is
+assumed that all the calls to these primitives will be dispatching
+calls. The only exception is the constructor, which must be registered
+with the compiler by means of ``pragma CPP_Constructor`` and needs to
+provide its associated C++ mangled name because the Ada compiler
+generates direct calls to it.
 
 With the above packages we can now declare objects of type Dog on the Ada side
 and dispatch calls to the corresponding subprograms on the C++ side. We can
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 71dae12..ad357dd 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "diagnostic-core.h"
 #include "attribs.h"
+#include "cgraph.h"
 #include "stor-layout.h"
 #include "langhooks.h"
 #include "plugin.h"
@@ -2076,6 +2077,61 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree fntype)
     }
 }
 
+/* Create an exalias for DECL with linkage name ID.  */
+
+tree
+create_exalias_decl (tree decl, tree id)
+{
+  tree name = get_identifier ("exalias");
+
+  if (symtab_node *sym_node = symtab_node::get_for_asmname (id))
+    {
+      if ((sym_node->analyzed
+	   ? sym_node->get_alias_target ()->decl
+	   : sym_node->alias_target) == decl)
+	return sym_node->decl;
+
+      warning (0, "duplicate symbol name %qE in %qE attribute of %qD",
+	       id, name, decl);
+    }
+
+  tree clone = copy_node (decl);
+  DECL_ATTRIBUTES (clone) = remove_attribute ("exalias",
+					      DECL_ATTRIBUTES (decl));
+  SET_DECL_ASSEMBLER_NAME (clone, id);
+  TREE_USED (id) = 1;
+  TREE_USED (clone) = 1;
+  DECL_PRESERVE_P (clone) = 1;
+  DECL_EXTERNAL (clone) = 0;
+  TREE_STATIC (clone) = 1;
+
+  if (VAR_P (clone))
+    {
+      DECL_READ_P (clone) = 1;
+      varpool_node::create_alias (clone, decl);
+    }
+  else
+    {
+      cgraph_node::create_alias (clone, decl);
+    }
+
+  return clone;
+}
+
+/* Create all exaliases requested in DECL's attributes.  */
+
+void
+create_exalias_decls (tree decl)
+{
+  FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (decl))
+    {
+      tree id = TREE_VALUE (TREE_VALUE (exalias));
+      id = get_identifier (TREE_STRING_POINTER (id));
+
+      create_exalias_decl (decl, id);
+    }
+}
+
 
 #if CHECKING_P
 
diff --git a/gcc/attribs.h b/gcc/attribs.h
index dea0b6c..1ba56ca 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -248,4 +248,11 @@ typedef hash_map<rdwr_access_hash, attr_access> rdwr_map;
 
 extern void init_attr_rdwr_indices (rdwr_map *, tree);
 
+extern tree create_exalias_decl (tree, tree);
+extern void create_exalias_decls (tree);
+
+#define FOR_EACH_EXALIAS(exalias, attrs)				\
+  for (tree exalias = lookup_attribute ("exalias", (attrs)); exalias;	\
+       exalias = lookup_attribute ("exalias", TREE_CHAIN (exalias)))
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c
index c75b173..22a5c38 100644
--- a/gcc/c-family/c-ada-spec.c
+++ b/gcc/c-family/c-ada-spec.c
@@ -1434,6 +1434,13 @@ pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type,
 static void
 pp_asm_name (pretty_printer *buffer, tree t)
 {
+  FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (t))
+    {
+      tree id = TREE_VALUE (TREE_VALUE (exalias));
+      pp_string (buffer, TREE_STRING_POINTER (id));
+      return;
+    }
+  
   tree name = DECL_ASSEMBLER_NAME (t);
   char *ada_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (name) + 1), *s;
   const char *ident = IDENTIFIER_POINTER (name);
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 3721483..b726f44 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -99,7 +99,8 @@ static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
 static tree handle_ifunc_attribute (tree *, tree, tree, int, bool *);
 static tree handle_alias_attribute (tree *, tree, tree, int, bool *);
-static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ;
+static tree handle_weakref_attribute (tree *, tree, tree, int, bool *);
+static tree handle_exalias_attribute (tree *, tree, tree, int, bool *);
 static tree handle_visibility_attribute (tree *, tree, tree, int,
 					 bool *);
 static tree handle_tls_model_attribute (tree *, tree, tree, int,
@@ -333,6 +334,8 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_alias_attribute, NULL },
   { "weakref",                0, 1, true,  false, false, false,
 			      handle_weakref_attribute, NULL },
+  { "exalias",                1, 1, false,  false, false, false,
+			      handle_exalias_attribute, NULL },
   { "no_instrument_function", 0, 0, true,  false, false, false,
 			      handle_no_instrument_function_attribute,
 			      NULL },
@@ -2424,7 +2427,7 @@ handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
-/* Handle an "alias" or "ifunc" attribute; arguments as in
+/* Handle an "ifunc" attribute; arguments as in
    struct attribute_spec.handler.  */
 
 static tree
@@ -2434,7 +2437,7 @@ handle_ifunc_attribute (tree *node, tree name, tree args,
   return handle_alias_ifunc_attribute (false, node, name, args, no_add_attrs);
 }
 
-/* Handle an "alias" or "ifunc" attribute; arguments as in
+/* Handle an "alias" attribute; arguments as in
    struct attribute_spec.handler.  */
 
 static tree
@@ -2444,6 +2447,38 @@ handle_alias_attribute (tree *node, tree name, tree args,
   return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
 }
 
+/* Handle an "exalias" attribute; arguments as in struct
+   attribute_spec.handler.  */
+
+static tree
+handle_exalias_attribute (tree *pnode, tree name, tree args,
+			  int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree node = *pnode;
+
+  *no_add_attrs = true;
+
+  if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+    error ("%qE attribute argument not a string", name);
+  else if (VAR_OR_FUNCTION_DECL_P (node)
+	   /* Variables must not be automatic.  */
+	   && !(VAR_P (node) && !TREE_STATIC (node) && !DECL_EXTERNAL (node)))
+    {
+      tree id = TREE_VALUE (args);
+      id = get_identifier (TREE_STRING_POINTER (id));
+
+      create_exalias_decl (node, id);
+
+      *no_add_attrs = false;
+    }
+  else if (TYPE_P (node) && c_dialect_cxx ())
+    *no_add_attrs = false;
+  else
+    warning (OPT_Wattributes, "%qE attribute ignored", name);
+
+  return NULL_TREE;
+}
+
 /* Handle the "copy" attribute NAME by copying the set of attributes
    from the symbol referenced by ARGS to the declaration of *NODE.  */
 
@@ -2571,6 +2606,7 @@ handle_copy_attribute (tree *node, tree name, tree args,
 	  tree atname = get_attribute_name (at);
 	  if (is_attribute_p ("alias", atname)
 	      || is_attribute_p ("always_inline", atname)
+	      || is_attribute_p ("exalias", atname)
 	      || is_attribute_p ("gnu_inline", atname)
 	      || is_attribute_p ("ifunc", atname)
 	      || is_attribute_p ("noinline", atname)
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 5d6b504..79a3de1 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2942,6 +2942,8 @@ duplicate_decls (tree newdecl, tree olddecl)
 
   merge_decls (newdecl, olddecl, newtype, oldtype);
 
+  symtab_node::remap_exalias_target (newdecl, olddecl);
+
   /* The NEWDECL will no longer be needed.
 
      Before releasing the node, be sure to remove function from symbol
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index cfae6e9..bf36f5b 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -319,6 +319,10 @@ public:
   /* Return node that alias is aliasing.  */
   inline symtab_node *get_alias_target (void);
 
+  /* Remap exalias nodes recorded as aliasing REPLACED to alias
+     REPLACEMENT instead.  */
+  static void remap_exalias_target (tree replaced, tree replacement);
+
   /* Set section for symbol and its aliases.  */
   void set_section (const char *section);
 
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index ea9a34b..c569f52 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -641,7 +641,7 @@ cgraph_node::analyze (void)
 	return;
     }
   if (alias)
-    resolve_alias (cgraph_node::get (alias_target), transparent_alias);
+    resolve_alias (cgraph_node::get_create (alias_target), transparent_alias);
   else if (dispatcher_function)
     {
       /* Generate the dispatcher body of multi-versioned functions.  */
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a3913f4..ed911ef 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4822,6 +4822,57 @@ copy_fndecl_with_name (tree fn, tree name, tree_code code,
 
   /* Create the RTL for this function.  */
   SET_DECL_RTL (clone, NULL);
+
+  if (code == ERROR_MARK)
+    {
+      bool found = false;
+      FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (clone))
+	{
+	  found = true;
+	  break;
+	}
+
+      if (found
+	  && (name == complete_ctor_identifier
+	      || name == complete_dtor_identifier))
+	{
+	  /* Reuse the exalias decls created for the primary cdtor decl.  */
+	  symtab_node::remap_exalias_target (fn, clone);
+	}
+      else if (found)
+	{
+	  const char *suf;
+
+	  if (name == base_ctor_identifier
+	      || name == base_dtor_identifier)
+	    suf = "_Base";
+	  else if (name == deleting_dtor_identifier)
+	    suf = "_Del";
+	  else
+	    gcc_unreachable ();
+
+	  size_t xlen = strlen (suf);
+
+	  DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (clone));
+
+	  FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (clone))
+	    {
+	      TREE_VALUE (exalias) = copy_list (TREE_VALUE (exalias));
+	      /* Append suf to the exalias name.  */
+	      tree str = TREE_VALUE (TREE_VALUE (exalias));
+	      char *symname = concat (TREE_STRING_POINTER (str), suf, NULL);
+	      str = build_string (TREE_STRING_LENGTH (str) + xlen, symname);
+	      TREE_VALUE (TREE_VALUE (exalias)) = str;
+	      free (symname);
+	    }
+
+	  create_exalias_decls (clone);
+	}
+    }
+  else
+    DECL_ATTRIBUTES (clone)
+      = remove_attribute ("exalias", DECL_ATTRIBUTES (clone));
+
   rest_of_decl_compilation (clone, namespace_bindings_p (), at_eof);
 
   return clone;
@@ -4919,6 +4970,9 @@ build_cdtor_clones (tree fn, bool needs_vtt_parm_p, bool omit_inherited_parms_p)
       count += 2;
     }
 
+  DECL_ATTRIBUTES (fn)
+    = remove_attribute ("exalias", DECL_ATTRIBUTES (fn));
+
   return count;
 }
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index d43c53a..07e2c1c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6591,6 +6591,7 @@ extern tree build_explicit_specifier		(tree, tsubst_flags_t);
 extern void do_push_parm_decls			(tree, tree, tree *);
 
 /* in decl2.c */
+extern void update_exalias_interface		(tree);
 extern void record_mangling			(tree, bool);
 extern void overwrite_mangling			(tree, tree);
 extern void note_mangling_alias			(tree, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index de53a7b..c489535 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2899,6 +2899,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 	      && TREE_STATIC (olddecl))))
     make_decl_rtl (olddecl);
 
+  symtab_node::remap_exalias_target (newdecl, olddecl);
+
   /* The NEWDECL will no longer be needed.  Because every out-of-class
      declaration of a member results in a call to duplicate_decls,
      freeing these nodes represents in a significant savings.
@@ -16508,6 +16510,8 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
   if (!processing_template_decl)
     maybe_instantiate_noexcept (decl1);
 
+  update_exalias_interface (decl1);
+
   begin_scope (sk_function_parms, decl1);
 
   ++function_depth;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 33c8377..518bb3a 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1951,6 +1951,43 @@ adjust_var_decl_tls_model (tree decl)
     set_decl_tls_model (decl, decl_default_tls_model (decl));
 }
 
+/* Copy externalness and linkage from DECL to DEST.  */
+
+static void
+copy_interface (tree dest, tree decl)
+{
+  TREE_PUBLIC (dest) = TREE_PUBLIC (decl);
+  TREE_STATIC (dest) = TREE_STATIC (decl);
+  DECL_COMMON (dest) = DECL_COMMON (decl);
+  DECL_COMDAT (dest) = DECL_COMDAT (decl);
+  DECL_WEAK (dest) = DECL_WEAK (decl);
+  DECL_EXTERNAL (dest) = DECL_EXTERNAL (decl);
+  if (DECL_LANG_SPECIFIC (dest) && DECL_LANG_SPECIFIC (decl))
+    DECL_NOT_REALLY_EXTERN (dest) = DECL_NOT_REALLY_EXTERN (decl);
+  DECL_INTERFACE_KNOWN (dest) = DECL_INTERFACE_KNOWN (decl);
+  DECL_VISIBILITY (dest) = DECL_VISIBILITY (decl);
+  DECL_VISIBILITY_SPECIFIED (dest) = DECL_VISIBILITY_SPECIFIED (decl);
+}
+
+/* Propagate linkage changes to exaliases.  */
+
+void
+update_exalias_interface (tree decl)
+{
+  FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (decl))
+    {
+      tree id = TREE_VALUE (TREE_VALUE (exalias));
+      id = get_identifier (TREE_STRING_POINTER (id));
+      symtab_node *sym_node = symtab_node::get_for_asmname (id);
+
+      if (sym_node
+	  && (sym_node->analyzed
+	      ? sym_node->get_alias_target ()->decl
+	      : sym_node->alias_target) == decl)
+	copy_interface (sym_node->decl, decl);
+    }
+}
+
 /* Set DECL up to have the closest approximation of "initialized common"
    linkage available.  */
 
@@ -2485,6 +2522,8 @@ constrain_visibility (tree decl, int visibility, bool tmpl)
       /* This visibility was not specified.  */
       DECL_VISIBILITY_SPECIFIED (decl) = false;
     }
+
+  update_exalias_interface (decl);
 }
 
 /* Constrain the visibility of DECL based on the visibility of its template
@@ -3013,6 +3052,8 @@ tentative_decl_linkage (tree decl)
       else if (VAR_P (decl))
 	maybe_commonize_var (decl);
     }
+
+  update_exalias_interface (decl);
 }
 
 /* DECL is a FUNCTION_DECL or VAR_DECL.  If the object file linkage
@@ -3247,6 +3288,8 @@ import_export_decl (tree decl)
     }
 
   DECL_INTERFACE_KNOWN (decl) = 1;
+
+  update_exalias_interface (decl);
 }
 
 /* Return an expression that performs the destruction of DECL, which
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 9f30d90..26bdc25 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -22,9 +22,11 @@ along with GCC; see the file COPYING3.  If not see
 #define INCLUDE_UNIQUE_PTR
 #include "system.h"
 #include "coretypes.h"
+#include "target.h"
 #include "cp-tree.h"
 #include "timevar.h"
 #include "stringpool.h"
+#include "cgraph.h"
 #include "print-tree.h"
 #include "attribs.h"
 #include "debug.h"
@@ -2924,6 +2926,12 @@ set_local_extern_decl_linkage (tree decl, bool shadowed)
 	       different decl.  */
 	    TREE_PUBLIC (decl) = TREE_PUBLIC (*iter);
 
+	    DECL_ATTRIBUTES (*iter)
+	      = targetm.merge_decl_attributes (*iter, decl);
+	    symtab_node::remap_exalias_target (decl, *iter);
+	    DECL_ATTRIBUTES (decl)
+	      = remove_attribute ("exalias", DECL_ATTRIBUTES (*iter));
+
 	    if (cp_function_chain->extern_decl_map == NULL)
 	      cp_function_chain->extern_decl_map
 		= hash_table<cxx_int_tree_map_hasher>::create_ggc (20);
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index abdcd7f..1bcf7a9 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -516,10 +516,14 @@ maybe_clone_body (tree fn)
       DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn);
       DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn);
       DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn);
-      DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn));
+      /* We may have already copied them in copy_fndecl_with_name.  */
+      if (DECL_ATTRIBUTES (clone) == DECL_ATTRIBUTES (fn))
+	DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn));
       DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn);
       set_decl_section_name (clone, DECL_SECTION_NAME (fn));
 
+      update_exalias_interface (clone);
+
       /* Adjust the parameter names and locations.  */
       parm = DECL_ARGUMENTS (fn);
       clone_parm = DECL_ARGUMENTS (clone);
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index d43248c..a5cbb78 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "intl.h"
 #include "stor-layout.h"
+#include "attribs.h"
 #include "c-family/c-pragma.h"
 #include "gcc-rich-location.h"
 
@@ -469,6 +470,18 @@ get_tinfo_decl (tree type)
       if (CLASS_TYPE_P (type))
 	CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
 
+      /* Copy exalias attributes from the type to the rtti obj decl.  */
+      tree *attrs = &DECL_ATTRIBUTES (d);
+      FOR_EACH_EXALIAS (exalias, TYPE_ATTRIBUTES (type))
+	{
+	  tree attr = tree_cons (TREE_PURPOSE (exalias),
+				 TREE_VALUE (exalias),
+				 *attrs);
+	  *attrs = attr;
+	  attrs = &TREE_CHAIN (attr);
+	}
+      create_exalias_decls (d);
+
       /* Add decl to the global array of tinfo decls.  */
       vec_safe_push (unemitted_tinfo_decls, d);
     }
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0fb7e27..720b7f3 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -2882,6 +2882,39 @@ when using these attributes the problem is diagnosed
 earlier and with exact location of the call even in presence of inline
 functions or when not emitting debugging information.
 
+@item exalias ("@var{name}")
+@cindex @code{exalias} function attribute
+The @code{exalias} attribute causes @var{name} to be emitted as an alias
+to the definition.  For instance,
+
+@smallexample
+void f (uint64_t) __attribute__ ((__exalias__ ("f_u64")));
+void f (uint64_t) @{ /* @r{Do something.} */; @}
+@end smallexample
+
+@noindent
+defines @samp{f}, and outputs @samp{f_u64} as an alias for @samp{f}.
+This is particularly useful when exporting C++ names for use in other
+languages, or as an alias target, when machine-dependent types would
+make mangled names harder to deal with.
+
+In the case of C++ constructors and destructors, in which a single
+definition may output multiple symbols, the specified name is associated
+with the variant that constructs or destructs a complete object.  The
+variant that applies to a base subobject gets a @code{_Base} suffix, and
+the deleting destructor gets a @code{_Del} suffix.
+
+This attribute is silently ignored if @samp{f} is not defined in the
+same translation unit, so that the attribute can be attached to forward
+declarations.
+
+The name @samp{f_u64} is an assembly symbol name: it does not undergo
+C++ name mangling, and it is not made visible in any scope in the source
+language, but it can be named as an alias target.
+
+This attribute requires assembler and object file support,
+and may not be available on all targets.
+
 @item externally_visible
 @cindex @code{externally_visible} function attribute
 This attribute, attached to a global variable or function, nullifies
@@ -6928,6 +6961,10 @@ align them on any target.
 The @code{aligned} attribute can also be used for functions
 (@pxref{Common Function Attributes}.)
 
+@item exalias ("@var{name}")
+@cindex @code{exalias} variable attribute
+See @pxref{Common Function Attributes}.
+
 @cindex @code{warn_if_not_aligned} variable attribute
 @item warn_if_not_aligned (@var{alignment})
 This attribute specifies a threshold for the structure field, measured
@@ -7066,6 +7103,21 @@ types (@pxref{Common Function Attributes},
 The message attached to the attribute is affected by the setting of
 the @option{-fmessage-length} option.
 
+@item exalias ("@var{name}")
+@cindex @code{exalias} type attribute
+The @code{exalias} attribute causes @var{name} to be emitted as an alias
+to the definition of the C++ Run-Time Type Information (RTTI)
+@code{std::type_info} object associated with the type.  For instance,
+
+@smallexample
+class foo __attribute__ ((__exalias__ ("TI_foo")));
+@end smallexample
+
+@noindent
+arranges for @samp{TI_foo} to be defined as an alias to the RTTI object
+for class @samp{foo}, once the class is defined and used in ways that
+cause its RTTI object to be synthesized and output.
+
 @item mode (@var{mode})
 @cindex @code{mode} variable attribute
 This attribute specifies the data type for the declaration---whichever
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 0e852d4..ce438e1 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -1861,6 +1861,32 @@ symtab_node::noninterposable_alias (symtab_node *node, void *data)
   return false;
 }
 
+/* Remap exalias nodes recorded as aliasing REPLACED to alias
+   REPLACEMENT instead.  */
+
+void
+symtab_node::remap_exalias_target (tree replaced, tree replacement)
+{
+  FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (replaced))
+    {
+      tree id = TREE_VALUE (TREE_VALUE (exalias));
+      id = get_identifier (TREE_STRING_POINTER (id));
+
+      symtab_node *sym_node = symtab_node::get_for_asmname (id);
+
+      gcc_assert (!sym_node->analyzed);
+      if (sym_node->alias_target != replaced)
+	continue;
+
+      sym_node->definition = 0;
+
+      if (VAR_P (replaced))
+	varpool_node::create_alias (sym_node->decl, replacement);
+      else
+	cgraph_node::create_alias (sym_node->decl, replacement);
+    }
+}
+
 /* If node cannot be overwriten by static or dynamic linker to point to
    different definition, return NODE. Otherwise look for alias with such
    property and if none exists, introduce new one.  */
diff --git a/gcc/testsuite/c-c++-common/attr-weak-1.c b/gcc/testsuite/c-c++-common/attr-weak-1.c
new file mode 100644
index 00000000..b11ef71
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-weak-1.c
@@ -0,0 +1,19 @@
+/* { dg-do run { xfail *-*-* } } */
+/* { dg-require-effective-target weak_undefined } */
+
+/* C++ wouldn't combine attributes from local declarations with a
+   namespace-scoped symbol.  Now it does, but only if there is a
+   visible declaration.  */
+
+void foo () {
+  extern void __attribute__ ((__weak__)) undef_fn (void);
+  extern int __attribute__ ((__weak__)) undef_var;
+}
+
+int main () {
+  extern void undef_fn (void);
+  extern int undef_var;
+
+  if (&undef_fn || &undef_var)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-1.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-1.c
new file mode 100644
index 00000000..3a471cc
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-1.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+
+extern int var_a __attribute__ ((__exalias__ ("FOOVAR_A")));
+int var_a = 1;
+
+void foo_a () __attribute__ ((__exalias__ ("FOOBAR_A")));
+
+void
+foo_a ()
+{
+}
+
+
+int var_b;
+extern int var_b __attribute__ ((__exalias__ ("FOOVAR_B")));
+
+void
+foo_b ()
+{
+}
+
+void foo_b () __attribute__ ((__exalias__ ("FOOBAR_B")));
+
+
+int var_c __attribute__ ((__exalias__ ("FOOVAR_C")));
+
+void __attribute__ ((__exalias__ ("FOOBAR_C")))
+foo_c ()
+{
+}
+
+
+/* { dg-final { scan-assembler "FOOBAR_A" } } */
+/* { dg-final { scan-assembler "FOOVAR_A" } } */
+/* { dg-final { scan-assembler "FOOBAR_B" } } */
+/* { dg-final { scan-assembler "FOOVAR_B" } } */
+/* { dg-final { scan-assembler "FOOBAR_C" } } */
+/* { dg-final { scan-assembler "FOOVAR_C" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-2.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-2.c
new file mode 100644
index 00000000..4ab1f07
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+
+struct s
+{
+  int mem __attribute__ ((__exalias__ ("MEMFOO"))); /* { dg-warning "attribute ignored" } */
+};
+
+void foo()
+{
+  extern void bar () __attribute__ ((__exalias__ ("FOOBAR")));
+  int var __attribute__ ((__exalias__ ("FOOVAR"))); /* { dg-warning "public objects" } */
+}
diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-3.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-3.c
new file mode 100644
index 00000000..d94b618
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-3.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+
+int var_a = 1;
+
+void
+foo_a ()
+{
+  extern int var_a __attribute__ ((__exalias__ ("FOOVAR_A")));
+  void foo_a () __attribute__ ((__exalias__ ("FOOBAR_A")));
+}
+
+#if __cplusplus
+/* Without this declaration before the local declaration below, the
+   attributes of the local declaration do not get propagated to the
+   (global) namespace scope.  */
+extern int var_b;
+#endif
+
+void
+foo_b ()
+{
+  extern int var_b __attribute__ ((__exalias__ ("FOOVAR_B")));
+}
+
+int var_b;
+
+void __attribute__ ((__exalias__ ("FOOBAR_C")))
+foo_c ()
+{
+  void foo_b () __attribute__ ((__exalias__ ("FOOBAR_B")));
+  /* Another exalias for var_b.  */
+  extern int var_b __attribute__ ((__exalias__ ("FOOVAR_C")));
+}
+
+/* { dg-final { scan-assembler "FOOBAR_A" } } */
+/* { dg-final { scan-assembler "FOOVAR_A" } } */
+/* { dg-final { scan-assembler "FOOBAR_B" } } */
+/* { dg-final { scan-assembler "FOOVAR_B" } } */
+/* { dg-final { scan-assembler "FOOBAR_C" } } */
+/* { dg-final { scan-assembler "FOOVAR_C" } } */
diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-4.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-4.c
new file mode 100644
index 00000000..6320d1a4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-4.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-require-alias "" } */
+
+int var_a __attribute__ ((__exalias__ ("FOOVAR_A"))) = 42;
+
+int __attribute__ ((__exalias__ ("FOOBAR_A")))
+foo_a (int p)
+{
+  return p;
+}
+
+extern int __attribute__ ((__alias__ (("FOOVAR_A")))) var_b;
+extern int __attribute__ ((__alias__ (("FOOBAR_A")))) foo_b (int p);
+
+int
+foo_c ()
+{
+  return foo_b (var_b);
+}
+
+int
+main ()
+{
+  if (foo_c () != 42)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-1.C b/gcc/testsuite/g++.dg/torture/attr-exalias-1.C
new file mode 100644
index 00000000..9bd82a2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-1.C
@@ -0,0 +1,66 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+
+class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo {
+  static int var __attribute__ ((__exalias__ ("FOOVAR_A")));
+  __attribute__ ((__exalias__ ("FOOCTR_A"))) foo ();
+  void __attribute__ ((__exalias__ ("FOOBAR_A"))) bar ();
+  virtual __attribute__ ((__exalias__ ("FOODTR_A"))) ~foo() {}
+};
+
+int foo::var = 1;
+
+foo::foo () {}
+
+void foo::bar () {}
+
+namespace b {
+  class __attribute__ ((__exalias__ ("FOOCLS_B"))) foo {
+    static int var __attribute__ ((__exalias__ ("FOOVAR_B")));
+    __attribute__ ((__exalias__ ("FOOCTR_B"))) foo ();
+    void __attribute__ ((__exalias__ ("FOOBAR_B"))) bar () {}
+    virtual __attribute__ ((__exalias__ ("FOODTR_B"))) ~foo() {}
+  };
+
+  int foo::var = 2;
+
+  foo::foo () {}
+}
+
+namespace c {
+  namespace cd {
+    class __attribute__ ((__exalias__ ("FOOCLS_C"))) foo {
+      static int var __attribute__ ((__exalias__ ("FOOVAR_C")));
+      __attribute__ ((__exalias__ ("FOOCTR_C"))) foo () {}
+      void __attribute__ ((__exalias__ ("FOOBAR_C"))) bar () {}
+      virtual __attribute__ ((__exalias__ ("FOODTR_C"))) ~foo() {}
+    };
+
+    int foo::var = 3;
+  }
+}
+
+/* { dg-final { scan-assembler "FOOCLS_A" } } */
+/* { dg-final { scan-assembler "FOOBAR_A" } } */
+/* { dg-final { scan-assembler "FOOCTR_A" } } */
+/* { dg-final { scan-assembler "FOOCTR_A_Base" } } */
+/* { dg-final { scan-assembler "FOODTR_A" } } */
+/* { dg-final { scan-assembler "FOODTR_A_Base" } } */
+/* { dg-final { scan-assembler "FOODTR_A_Del" } } */
+/* { dg-final { scan-assembler "FOOVAR_A" } } */
+/* { dg-final { scan-assembler "FOOCLS_B" } } */
+/* { dg-final { scan-assembler "FOOBAR_B" } } */
+/* { dg-final { scan-assembler "FOOCTR_B" } } */
+/* { dg-final { scan-assembler "FOOCTR_A_Base" } } */
+/* { dg-final { scan-assembler "FOODTR_B" } } */
+/* { dg-final { scan-assembler "FOODTR_B_Base" } } */
+/* { dg-final { scan-assembler "FOODTR_B_Del" } } */
+/* { dg-final { scan-assembler "FOOVAR_B" } } */
+/* { dg-final { scan-assembler "FOOCLS_C" } } */
+/* { dg-final { scan-assembler "FOOBAR_C" } } */
+/* { dg-final { scan-assembler "FOOCTR_C" } } */
+/* { dg-final { scan-assembler "FOOCTR_C_Base" } } */
+/* { dg-final { scan-assembler "FOODTR_C" } } */
+/* { dg-final { scan-assembler "FOODTR_C_Base" } } */
+/* { dg-final { scan-assembler "FOODTR_C_Del" } } */
+/* { dg-final { scan-assembler "FOOVAR_C" } } */
diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-2.C b/gcc/testsuite/g++.dg/torture/attr-exalias-2.C
new file mode 100644
index 00000000..a4cf015
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-2.C
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+
+namespace {
+  class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo {
+    static int var __attribute__ ((__exalias__ ("FOOVAR_A")));
+    __attribute__ ((__exalias__ ("FOOCTR_A"))) foo ();
+    virtual __attribute__ ((__exalias__ ("FOODTR_A"))) ~foo ();
+    void __attribute__ ((__exalias__ ("FOOBAR_A"))) bar ();
+  };
+
+  int foo::var = 3;
+  foo::foo () {}
+  foo::~foo () {}
+  void foo::bar () {}
+}
+
+/* { dg-final { scan-assembler-not "\.globl" } */
+/* { dg-final { scan-assembler "FOOCLS_A" } } */
+/* { dg-final { scan-assembler "FOOBAR_A" } } */
+/* { dg-final { scan-assembler "FOOCTR_A" } } */
+/* { dg-final { scan-assembler "FOOCTR_A_Base" } } */
+/* { dg-final { scan-assembler "FOODTR_A" } } */
+/* { dg-final { scan-assembler "FOODTR_A_Base" } } */
+/* { dg-final { scan-assembler "FOODTR_A_Del" } } */
+/* { dg-final { scan-assembler "FOOVAR_A" } } */
diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-3.C b/gcc/testsuite/g++.dg/torture/attr-exalias-3.C
new file mode 100644
index 00000000..6e4a868
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-3.C
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+
+// exalias can be applied to template function explicit instantiations.
+
+template <typename T>
+void
+fn(T) {
+};
+
+template void __attribute__ ((__exalias__ ("FOOFUN_UINT"))) fn<>(unsigned int);
+template void __attribute__ ((__exalias__ ("FOOFUN_LONG"))) fn<>(long);
+
+
+template <typename T = void>
+class
+foo {
+  virtual ~foo() {}
+
+  // Member functions that we wish to name with exalias must be
+  // defined outside the class body, *after* any exalias-named
+  // instantiations of the enclosing template types.  If they are
+  // defined in the class body, or before the explicit instantiation,
+  // they will be implicitly instantiated along with the enclosing
+  // template class type, and then the explicit instantiation of the
+  // member function will be rejected as a duplicate.  If we attempt
+  // to explicitly instantiate the member functions first, their
+  // naming the enclosing template type will trigger the implicit
+  // instantiation thereof, and then the subsequent explicit
+  // instantiation of the class type will have attributes ignored.
+  virtual void virtfun();
+
+  static void stfun() {}
+  void inlfun() {}
+};
+
+template class __attribute__ ((__exalias__ ("FOOCLS_VOID_TI"))) foo<>;
+template class __attribute__ ((__exalias__ ("FOOCLS_CHAR_TI"))) foo<char>;
+
+template void
+__attribute__ ((__exalias__ ("FOOCLS_SHORT_ST"))) foo<short>::stfun();
+template void
+__attribute__ ((__exalias__ ("FOOCLS_SHORT_INL"))) foo<short>::inlfun();
+
+template <typename T>
+void foo<T>::virtfun() {}
+
+template void
+__attribute__ ((__exalias__ ("FOOCLS_CHAR_VIRT"))) foo<char>::virtfun();
+
+template void
+__attribute__ ((__exalias__ ("FOOCLS_LONG_VIRT"))) foo<long>::virtfun();
+
+/* { dg-final { scan-assembler "FOOCLS_VOID_TI" } } */
+/* { dg-final { scan-assembler "FOOCLS_CHAR_TI" } } */
+/* { dg-final { scan-assembler "FOOCLS_SHORT_ST" } } */
+/* { dg-final { scan-assembler "FOOCLS_SHORT_INL" } } */
+/* { dg-final { scan-assembler "FOOCLS_CHAR_VIRT" } } */
+/* { dg-final { scan-assembler "FOOCLS_LONG_VIRT" } } */
+/* { dg-final { scan-assembler "FOOFUN_UINT" } } */
+/* { dg-final { scan-assembler "FOOFUN_LONG" } } */
diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-4.C b/gcc/testsuite/g++.dg/torture/attr-exalias-4.C
new file mode 100644
index 00000000..1ca7406a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-4.C
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+
+template <typename T = void>
+class
+__attribute__ ((__exalias__ ("FOOCLS"))) foo // { dg-warning "duplicate" }
+{
+  virtual ~foo() {}
+
+  virtual void
+    __attribute__ ((__exalias__ ("FOOVFN"))) // { dg-warning "duplicate" { xfail *-*-* } }
+    virtfun () {}
+};
+
+template <typename T>
+void
+__attribute__ ((__exalias__ ("FOOTFN"))) // { dg-warning "duplicate" { xfail *-*-* } }
+fn(T) {
+};
+
+template class foo<>;
+template class foo<int>;
+template void fn<>(int);
+template void fn<>(long);
+
+/* { dg-final { scan-assembler "FOOCLS" } } */
+/* { dg-final { scan-assembler "FOOVFN" { xfail *-*-* } } } */
+/* { dg-final { scan-assembler "FOOFUN" { xfail *-*-* } } } */
diff --git a/gcc/varpool.c b/gcc/varpool.c
index 458cdf1..cd84b1f 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -523,7 +523,7 @@ varpool_node::analyze (void)
       align_variable (decl, 0);
     }
   if (alias)
-    resolve_alias (varpool_node::get (alias_target));
+    resolve_alias (varpool_node::get_create (alias_target));
   else if (DECL_INITIAL (decl))
     record_references_in_initializer (decl, analyzed);
   analyzed = true;


introduce exrtti as a separate attribute for types

From: Alexandre Oliva <oliva@adacore.com>

Make attribute exalias apply to declarations only.  Use a separate
attribute exrtti to name exaliases for the RTTI object associated with
classes.
---
 .../doc/gnat_rm/interfacing_to_other_languages.rst |    2 +-
 gcc/attribs.h                                      |    3 +++
 gcc/c-family/c-attribs.c                           |    9 ++++++---
 gcc/cp/rtti.c                                      |    6 +++---
 gcc/doc/extend.texi                                |    8 ++++----
 gcc/testsuite/g++.dg/torture/attr-exalias-1.C      |    6 +++---
 gcc/testsuite/g++.dg/torture/attr-exalias-2.C      |    2 +-
 gcc/testsuite/g++.dg/torture/attr-exalias-3.C      |    6 +++---
 gcc/testsuite/g++.dg/torture/attr-exalias-4.C      |    2 +-
 9 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst
index ce6a4da..483ae4a 100644
--- a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst
+++ b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst
@@ -125,7 +125,7 @@ cover a specific C++ exception in an exception handler.
 
 RTTI symbols undergo C++ name mangling, which can make for identifiers
 that are inconvenient to use.  An alias with a mnemonic name can be
-introduced by adding attribute ``exalias`` to the class that the RTTI
+introduced by adding attribute ``exrtti`` to the class that the RTTI
 symbol refers to.
 
 
diff --git a/gcc/attribs.h b/gcc/attribs.h
index 1ba56ca..fa04890 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -254,5 +254,8 @@ extern void create_exalias_decls (tree);
 #define FOR_EACH_EXALIAS(exalias, attrs)				\
   for (tree exalias = lookup_attribute ("exalias", (attrs)); exalias;	\
        exalias = lookup_attribute ("exalias", TREE_CHAIN (exalias)))
+#define FOR_EACH_EXRTTI(exalias, attrs)					\
+  for (tree exalias = lookup_attribute ("exrtti", (attrs)); exalias;	\
+       exalias = lookup_attribute ("exrtti", TREE_CHAIN (exalias)))
 
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index b726f44..4342bf4 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -334,7 +334,9 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_alias_attribute, NULL },
   { "weakref",                0, 1, true,  false, false, false,
 			      handle_weakref_attribute, NULL },
-  { "exalias",                1, 1, false,  false, false, false,
+  { "exalias",                1, 1, true,  false, false, false,
+			      handle_exalias_attribute, NULL },
+  { "exrtti",                 1, 1, false, true, false, false,
 			      handle_exalias_attribute, NULL },
   { "no_instrument_function", 0, 0, true,  false, false, false,
 			      handle_no_instrument_function_attribute,
@@ -2447,8 +2449,8 @@ handle_alias_attribute (tree *node, tree name, tree args,
   return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
 }
 
-/* Handle an "exalias" attribute; arguments as in struct
-   attribute_spec.handler.  */
+/* Handle an "exalias" or "exrtti" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
 static tree
 handle_exalias_attribute (tree *pnode, tree name, tree args,
@@ -2607,6 +2609,7 @@ handle_copy_attribute (tree *node, tree name, tree args,
 	  if (is_attribute_p ("alias", atname)
 	      || is_attribute_p ("always_inline", atname)
 	      || is_attribute_p ("exalias", atname)
+	      || is_attribute_p ("exrtti", atname)
 	      || is_attribute_p ("gnu_inline", atname)
 	      || is_attribute_p ("ifunc", atname)
 	      || is_attribute_p ("noinline", atname)
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index a5cbb78..f91ab9b 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -470,11 +470,11 @@ get_tinfo_decl (tree type)
       if (CLASS_TYPE_P (type))
 	CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
 
-      /* Copy exalias attributes from the type to the rtti obj decl.  */
+      /* Copy exrtti attributes from the type to the rtti obj decl.  */
       tree *attrs = &DECL_ATTRIBUTES (d);
-      FOR_EACH_EXALIAS (exalias, TYPE_ATTRIBUTES (type))
+      FOR_EACH_EXRTTI (exalias, TYPE_ATTRIBUTES (type))
 	{
-	  tree attr = tree_cons (TREE_PURPOSE (exalias),
+	  tree attr = tree_cons (get_identifier ("exalias"),
 				 TREE_VALUE (exalias),
 				 *attrs);
 	  *attrs = attr;
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 720b7f3..915e7bd 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7103,14 +7103,14 @@ types (@pxref{Common Function Attributes},
 The message attached to the attribute is affected by the setting of
 the @option{-fmessage-length} option.
 
-@item exalias ("@var{name}")
-@cindex @code{exalias} type attribute
-The @code{exalias} attribute causes @var{name} to be emitted as an alias
+@item exrtti ("@var{name}")
+@cindex @code{exrtti} type attribute
+The @code{exrtti} attribute causes @var{name} to be emitted as an alias
 to the definition of the C++ Run-Time Type Information (RTTI)
 @code{std::type_info} object associated with the type.  For instance,
 
 @smallexample
-class foo __attribute__ ((__exalias__ ("TI_foo")));
+class foo __attribute__ ((__exrtti__ ("TI_foo")));
 @end smallexample
 
 @noindent
diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-1.C b/gcc/testsuite/g++.dg/torture/attr-exalias-1.C
index 9bd82a2..432c32bc 100644
--- a/gcc/testsuite/g++.dg/torture/attr-exalias-1.C
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-1.C
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-require-alias "" } */
 
-class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo {
+class __attribute__ ((__exrtti__ ("FOOCLS_A"))) foo {
   static int var __attribute__ ((__exalias__ ("FOOVAR_A")));
   __attribute__ ((__exalias__ ("FOOCTR_A"))) foo ();
   void __attribute__ ((__exalias__ ("FOOBAR_A"))) bar ();
@@ -15,7 +15,7 @@ foo::foo () {}
 void foo::bar () {}
 
 namespace b {
-  class __attribute__ ((__exalias__ ("FOOCLS_B"))) foo {
+  class __attribute__ ((__exrtti__ ("FOOCLS_B"))) foo {
     static int var __attribute__ ((__exalias__ ("FOOVAR_B")));
     __attribute__ ((__exalias__ ("FOOCTR_B"))) foo ();
     void __attribute__ ((__exalias__ ("FOOBAR_B"))) bar () {}
@@ -29,7 +29,7 @@ namespace b {
 
 namespace c {
   namespace cd {
-    class __attribute__ ((__exalias__ ("FOOCLS_C"))) foo {
+    class __attribute__ ((__exrtti__ ("FOOCLS_C"))) foo {
       static int var __attribute__ ((__exalias__ ("FOOVAR_C")));
       __attribute__ ((__exalias__ ("FOOCTR_C"))) foo () {}
       void __attribute__ ((__exalias__ ("FOOBAR_C"))) bar () {}
diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-2.C b/gcc/testsuite/g++.dg/torture/attr-exalias-2.C
index a4cf015..c36d2f9b 100644
--- a/gcc/testsuite/g++.dg/torture/attr-exalias-2.C
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-2.C
@@ -2,7 +2,7 @@
 /* { dg-require-alias "" } */
 
 namespace {
-  class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo {
+  class __attribute__ ((__exrtti__ ("FOOCLS_A"))) foo {
     static int var __attribute__ ((__exalias__ ("FOOVAR_A")));
     __attribute__ ((__exalias__ ("FOOCTR_A"))) foo ();
     virtual __attribute__ ((__exalias__ ("FOODTR_A"))) ~foo ();
diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-3.C b/gcc/testsuite/g++.dg/torture/attr-exalias-3.C
index 6e4a868..6af9217 100644
--- a/gcc/testsuite/g++.dg/torture/attr-exalias-3.C
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-3.C
@@ -18,7 +18,7 @@ foo {
   virtual ~foo() {}
 
   // Member functions that we wish to name with exalias must be
-  // defined outside the class body, *after* any exalias-named
+  // defined outside the class body, *after* any exrtti-named
   // instantiations of the enclosing template types.  If they are
   // defined in the class body, or before the explicit instantiation,
   // they will be implicitly instantiated along with the enclosing
@@ -34,8 +34,8 @@ foo {
   void inlfun() {}
 };
 
-template class __attribute__ ((__exalias__ ("FOOCLS_VOID_TI"))) foo<>;
-template class __attribute__ ((__exalias__ ("FOOCLS_CHAR_TI"))) foo<char>;
+template class __attribute__ ((__exrtti__ ("FOOCLS_VOID_TI"))) foo<>;
+template class __attribute__ ((__exrtti__ ("FOOCLS_CHAR_TI"))) foo<char>;
 
 template void
 __attribute__ ((__exalias__ ("FOOCLS_SHORT_ST"))) foo<short>::stfun();
diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-4.C b/gcc/testsuite/g++.dg/torture/attr-exalias-4.C
index 1ca7406a..1e76ac8 100644
--- a/gcc/testsuite/g++.dg/torture/attr-exalias-4.C
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-4.C
@@ -3,7 +3,7 @@
 
 template <typename T = void>
 class
-__attribute__ ((__exalias__ ("FOOCLS"))) foo // { dg-warning "duplicate" }
+__attribute__ ((__exrtti__ ("FOOCLS"))) foo // { dg-warning "duplicate" }
 {
   virtual ~foo() {}
 
