Since last week's patchlet, I've delayed the creation of the exalias
decls, improved the merging of attributes, minimizing
interface/visibility updates, found a better way to assign exaliases to
nested explicit instantiations, even after enabling aliases to
already-defined types, so now I'm reasonably happy with the patch.


This patch introduces an attribute to add extra aliases to a symbol
when its definition is output.  The main goal is to ease interfacing
C++ with Ada, as C++ mangled names have to be named, and in some cases
(e.g. when using stdint.h typedefs in function arguments) the symbol
names may vary across platforms.

The attribute is usable in C and C++, presumably in all C-family
languages.  It can be attached to global variables and functions.  In
C++, it can also be attached to namespace-scoped variables and
functions, static data members, member functions, explicit
instantiations and specializations of template functions, members and
classes.  When applied to constructors or destructor, additional
exaliases with _Base and _Del suffixes are defined for variants other
than complete-object ones.

Applying the attribute to class types is only valid in C++, and the
effect is to attach the alias to the RTTI object associated with the
class type.


While working on this, I noticed C++ didn't merge attributes of extern
local declarations with those of the namespace-scoped declaration.
I've added code to merge the attributes if there is a namespace-scoped
declaration, but if there isn't one, there won't be any merging, and
the effects are noticeable, as in the added attr-weak-1.C.  I'm also
slightly concerned that an earlier local decl would go out of sync if
a subsequent local decl, say within the same or even in another
function, introduces additional attributes in the global decl.


Regstrapped on x86_64-linux-gnu.  Ok to install?


(The newly-introduced attr-weak-1.c passes in C, but is marked as XFAIL
for C++, so it gets an XPASS in C; I could move it to some C++-only
subtree, or drop it altogether and file a PR instead)


for  gcc/ChangeLog

        * attribs.c: Include cgraph.h.
        (decl_attributes): Allow late introduction of exalias in
        types.
        (create_exalias_decl, create_exalias_decls): New.
        * attribs.h: Declare them.
        (FOR_EACH_EXALIAS): New macro.
        * cgraph.c (cgraph_node::create): Create exalias decls.
        * varpool.c (varpool_node::get_create): Create exalias decls.
        * cgraph.h (symtab_node::remap_exalias_target): New.
        * symtab.c (symtab_node::remap_exalias_target): Define.
        * cgraphunit.c (cgraph_node::analyze): Create alias_target
        node if needed.
        (analyze_functions): Fixup visibility of implicit alias only
        after its node is analyzed.
        * doc/extend.texi (exalias): Document for variables, functions
        and types.

for  gcc/ada/ChangeLog

        * doc/gnat_rm/interfacing_to_other_languages.rst: Mention
        attribute exalias to give RTTI symbols mnemonic names.
        * doc/gnat_ugn/the_gnat_compilation_model.rst: Mention
        attribute exalias.  Fix incorrect ref to C1 ctor variant.

for  gcc/c-family/ChangeLog

        * c-ada-spec.c (pp_asm_name): Use first exalias if available.
        * c-attribs.c (handle_exalias_attribute): New.
        (c_common_attribute_table): Add exalias.
        (handle_copy_attribute): Do not copy exalias.
        * c-decl.c (duplicate_decls): Remap exalias target.

for  gcc/cp/ChangeLog

        * class.c (copy_fndecl_with_name): Move/adjust exalias to
        cdtor variants.
        (build_cdtor_clones): Drop exalias from primary variant.
        * cp-tree.h (update_exalias_interface, update_tinfo_exalias):
        Declare.
        * decl.c (duplicate_decls): Remap exalias target.
        (grokfndecl): Tentatively create exalias decls after adding
        attributes in e.g. a template member function explicit
        instantiation.
        * decl2.c (cplus_decl_attributes): Update tinfo exalias.
        (copy_interface, update_exalias_interface): New.
        (determine_visibility): Update exalias interface.
        (tentative_decl_linkage, import_export_decl): Likewise.
        * name-lookup.c: Include target.h and cgraph.h.
        (set_local_extern_decl_linkage): Merge attributes with a
        namespace-scoped decl if one is found.  Remap exalias
        targets, and drop exaliases from the local decl.
        * optimize.c (maybe_clone_body): Only copy attributes if they
        haven't been copied yet.  Update exalias interface.
        * rtti.c: Include attribs.h and cgraph.h.
        (get_tinfo_decl): Copy exalias attributes from type to tinfo
        decl.  Create exalias decls.
        (update_tinfo_exalias): New.

for  gcc/testsuite/ChangeLog

        * c-c++-common/attr-weak-1.c: New, xfailed.
        * c-c++-common/torture/attr-exalias-1.c: New.
        * c-c++-common/torture/attr-exalias-2.c: New.
        * c-c++-common/torture/attr-exalias-3.c: New.
        * c-c++-common/torture/attr-exalias-4.c: New.
        * g++.dg/torture/attr-exalias-1.C: New.
        * g++.dg/torture/attr-exalias-2.C: New.
        * g++.dg/torture/attr-exalias-3.C: New.
        * g++.dg/torture/attr-exalias-4.C: New.
---
 .../doc/gnat_rm/interfacing_to_other_languages.rst |    6 +
 .../doc/gnat_ugn/the_gnat_compilation_model.rst    |   20 +++--
 gcc/attribs.c                                      |   66 ++++++++++++++++
 gcc/attribs.h                                      |    7 ++
 gcc/c-family/c-ada-spec.c                          |    7 ++
 gcc/c-family/c-attribs.c                           |   33 +++++++-
 gcc/c/c-decl.c                                     |    2 
 gcc/cgraph.c                                       |    3 +
 gcc/cgraph.h                                       |    4 +
 gcc/cgraphunit.c                                   |    2 
 gcc/cp/class.c                                     |   55 +++++++++++++
 gcc/cp/cp-tree.h                                   |    2 
 gcc/cp/decl.c                                      |    3 +
 gcc/cp/decl2.c                                     |   49 ++++++++++++
 gcc/cp/name-lookup.c                               |    8 ++
 gcc/cp/optimize.c                                  |    7 +-
 gcc/cp/rtti.c                                      |   66 ++++++++++++++++
 gcc/doc/extend.texi                                |   52 +++++++++++++
 gcc/symtab.c                                       |   36 +++++++++
 gcc/testsuite/c-c++-common/attr-weak-1.c           |   19 +++++
 .../c-c++-common/torture/attr-exalias-1.c          |   39 +++++++++
 .../c-c++-common/torture/attr-exalias-2.c          |   13 +++
 .../c-c++-common/torture/attr-exalias-3.c          |   41 ++++++++++
 .../c-c++-common/torture/attr-exalias-4.c          |   28 +++++++
 gcc/testsuite/g++.dg/torture/attr-exalias-1.C      |   70 +++++++++++++++++
 gcc/testsuite/g++.dg/torture/attr-exalias-2.C      |   26 ++++++
 gcc/testsuite/g++.dg/torture/attr-exalias-3.C      |   83 ++++++++++++++++++++
 gcc/testsuite/g++.dg/torture/attr-exalias-4.C      |   28 +++++++
 gcc/varpool.c                                      |    3 +
 29 files changed, 764 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/attr-weak-1.c
 create mode 100644 gcc/testsuite/c-c++-common/torture/attr-exalias-1.c
 create mode 100644 gcc/testsuite/c-c++-common/torture/attr-exalias-2.c
 create mode 100644 gcc/testsuite/c-c++-common/torture/attr-exalias-3.c
 create mode 100644 gcc/testsuite/c-c++-common/torture/attr-exalias-4.c
 create mode 100644 gcc/testsuite/g++.dg/torture/attr-exalias-1.C
 create mode 100644 gcc/testsuite/g++.dg/torture/attr-exalias-2.C
 create mode 100644 gcc/testsuite/g++.dg/torture/attr-exalias-3.C
 create mode 100644 gcc/testsuite/g++.dg/torture/attr-exalias-4.C

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..3768053 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"
@@ -663,7 +664,8 @@ decl_attributes (tree *node, tree attributes, int flags,
 
       if (TYPE_P (*anode)
          && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
-         && TYPE_SIZE (*anode) != NULL_TREE)
+         && TYPE_SIZE (*anode) != NULL_TREE
+         && !is_attribute_p ("exalias", name))
        {
          warning (OPT_Wattributes, "type attributes ignored after type is 
already defined");
          continue;
@@ -2076,6 +2078,68 @@ 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;
+
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "duplicate symbol name %qE in %qE attribute of %qD",
+               id, name, decl);
+      inform (DECL_SOURCE_LOCATION (sym_node->decl),
+             "already used by %qD", sym_node->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_extra_name_alias (clone, decl);
+    }
+  else
+    {
+      cgraph_node::create_same_body_alias (clone, decl);
+    }
+
+  return clone;
+}
+
+/* Create all exaliases requested in DECL's attributes.  */
+
+void
+create_exalias_decls (tree decl)
+{
+  if (!decl_in_symtab_p (decl)
+      || !symtab_node::get (decl))
+    return;
+
+  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..127eca6 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..c00de3f 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,29 @@ 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 (decl_in_symtab_p (node))
+    *no_add_attrs = false;
+  else if (TYPE_P (node) && c_dialect_cxx ())
+    *no_add_attrs = false;
+  else
+    return error_mark_node;
+
+  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 +2597,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.c b/gcc/cgraph.c
index c0b4579..a0121a0 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -524,6 +524,9 @@ cgraph_node::create (tree decl)
       node->next_nested = node->origin->nested;
       node->origin->nested = node;
     }
+
+  create_exalias_decls (decl);
+
   return node;
 }
 
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 0211f08..ab5bda5 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 0b1009d..c96f720 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -1157,7 +1157,7 @@ analyze_functions (bool first_time)
      C++ FE is confused about the COMDAT groups being right.  */
   if (symtab->cpp_implicit_aliases_done)
     FOR_EACH_SYMBOL (node)
-      if (node->cpp_implicit_alias)
+      if (node->cpp_implicit_alias && node->analyzed)
          node->fixup_same_cpp_alias_visibility (node->get_alias_target ());
   build_type_inheritance_graph ();
 
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b39bdaa..7e8f35f 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4831,6 +4831,58 @@ 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);
+           }
+
+         if (symtab_node::get (clone))
+           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;
@@ -4928,6 +4980,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 fc54e6b..9ff45e0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6601,6 +6601,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);
@@ -7043,6 +7044,7 @@ extern tree build_dynamic_cast                    
(location_t, tree, tree,
                                                 tsubst_flags_t);
 extern void emit_support_tinfos                        (void);
 extern bool emit_tinfo_decl                    (tree);
+extern void update_tinfo_exalias               (tree);
 
 /* in search.c */
 extern bool accessible_base_p                  (tree, tree, bool);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index a68bbe0..c1afde1 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.
@@ -9823,6 +9825,7 @@ grokfndecl (tree ctype,
     {
       cplus_decl_attributes (&decl, *attrlist, 0);
       *attrlist = NULL_TREE;
+      create_exalias_decls (decl);
     }
 
   /* Check main's type after attributes have been applied.  */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 33c8377..d020e95 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1601,6 +1601,8 @@ cplus_decl_attributes (tree *decl, tree attributes, int 
flags)
 
   if (TREE_CODE (*decl) == TYPE_DECL)
     SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
+  else if (TYPE_P (*decl) && attributes)
+    update_tinfo_exalias (*decl);
 
   /* Propagate deprecation out to the template.  */
   if (TREE_DEPRECATED (*decl))
@@ -1951,6 +1953,47 @@ 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)
+{
+  if (!decl_in_symtab_p (decl)
+      || !symtab_node::get (decl))
+    return;
+
+  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.  */
 
@@ -2747,6 +2790,8 @@ determine_visibility (tree decl)
        translation unit, we can make the type internal.  */
     constrain_visibility (decl, VISIBILITY_ANON, false);
 
+  update_exalias_interface (decl);
+
   /* If visibility changed and DECL already has DECL_RTL, ensure
      symbol flags are updated.  */
   if ((DECL_VISIBILITY (decl) != orig_visibility
@@ -3013,6 +3058,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 +3294,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..62568d7 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -516,10 +516,15 @@ 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,
+        before dropping exaliases from fn.  Don't overwrite it if so.  */
+      if (!DECL_ATTRIBUTES (clone))
+       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..223c608 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -28,8 +28,10 @@ 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"
+#include "cgraph.h"
 
 /* C++ returns type information to the user in struct type_info
    objects. We also use type information to implement dynamic_cast and
@@ -469,6 +471,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);
     }
@@ -476,6 +490,58 @@ get_tinfo_decl (tree type)
   return d;
 }
 
+/* After modifying the attributes of TYPE, check whether tinfo was
+   already created and, if so, add to it any exalias attributes that
+   were not already present.  */
+
+void
+update_tinfo_exalias (tree type)
+{
+  if (!TYPE_SIZE (type) || !CLASS_TYPE_P (type))
+    return;
+
+  tree d = CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type));
+  if (!d)
+    return;
+
+  bool first = true;
+  symtab_node *node = NULL;
+
+  tree *attrs = &DECL_ATTRIBUTES (d);
+  FOR_EACH_EXALIAS (exalias, TYPE_ATTRIBUTES (type))
+    {
+      bool found = false;
+      FOR_EACH_EXALIAS (dexalias, *attrs)
+       if (TREE_VALUE (exalias) == TREE_VALUE (dexalias))
+         {
+           found = true;
+           break;
+         }
+
+      if (found)
+       continue;
+
+      tree attr = tree_cons (TREE_PURPOSE (exalias),
+                            TREE_VALUE (exalias),
+                            *attrs);
+      *attrs = attr;
+      attrs = &TREE_CHAIN (attr);
+
+      if (first)
+       {
+         first = false;
+         node = symtab_node::get (d);
+       }
+
+      if (!node)
+       continue;
+
+      tree id = TREE_VALUE (TREE_VALUE (exalias));
+      id = get_identifier (TREE_STRING_POINTER (id));
+      create_exalias_decl (d, id);
+    }
+}
+
 /* Return a pointer to a type_info object describing TYPE, suitably
    cast to the language defined type.  */
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 37a675a..0ba880f 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
@@ -6929,6 +6962,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
@@ -7067,6 +7104,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 d7dfbb6..0ea8532 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -1874,6 +1874,42 @@ 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)
+{
+  if (!decl_in_symtab_p (replacement)
+      || !symtab_node::get (replacement))
+    return;
+
+  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);
+
+      if (!sym_node)
+       {
+         create_exalias_decl (replacement, id);
+         continue;
+       }
+
+      gcc_assert (!sym_node->analyzed);
+      if (sym_node->alias_target != replaced)
+       continue;
+
+      sym_node->definition = 0;
+
+      if (VAR_P (replaced))
+       varpool_node::create_extra_name_alias (sym_node->decl, replacement);
+      else
+       cgraph_node::create_same_body_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..a0fe686
--- /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 "attribute 
ignored" } */
+}
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..ac355f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-1.C
@@ -0,0 +1,70 @@
+/* { 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 () {
+    void (foo::*pbar)() = &foo::bar;
+  }
+}
+
+namespace c {
+  namespace cd {
+    class __attribute__ ((__exalias__ ("FOOCLS_C"))) foo {
+      static int var __attribute__ ((__exalias__ ("FOOVAR_C")));
+      __attribute__ ((__exalias__ ("FOOCTR_C"))) foo () {
+       void (foo::*pbar)() = &foo::bar;
+      }
+      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..266ee0c
--- /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..a81348a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/attr-exalias-3.C
@@ -0,0 +1,83 @@
+/* { 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<> void __attribute__ ((__exalias__ ("FOOFUN_CHAR"))) fn<>(char) {}
+
+
+template <typename T = void>
+struct
+foo {
+  virtual ~foo() {}
+
+  virtual void virtfun() {}
+
+  static void stfun() {}
+  void inlfun() {}
+};
+
+// Explicitly instantiate members before the enclosing class.
+
+template void
+__attribute__ ((__exalias__ ("FOOCLS_CHAR_VIRT"))) foo<char>::virtfun();
+
+template class __attribute__ ((__exalias__ ("FOOCLS_CHAR_TI"))) foo<char>;
+
+// Though they're only output if the enclosing class is.
+template void
+__attribute__ ((__exalias__ ("FOOCLS_LONG_VIRT"))) foo<long>::virtfun();
+extern
+template class __attribute__ ((__exalias__ ("FOOCLS_LONG_TI_X"))) foo<long>;
+
+
+template void
+__attribute__ ((__exalias__ ("FOOCLS_VOID_ST"))) foo<void>::stfun();
+
+template class __attribute__ ((__exalias__ ("FOOCLS_VOID_TI"))) foo<>;
+
+
+extern
+template class __attribute__ ((__exalias__ ("FOOCLS_SHORT_TI_X"))) foo<short>;
+
+template void
+__attribute__ ((__exalias__ ("FOOCLS_SHORT_ST"))) foo<short>::stfun();
+template void
+__attribute__ ((__exalias__ ("FOOCLS_SHORT_INL"))) foo<short>::inlfun();
+
+template class __attribute__ ((__exalias__ ("FOOCLS_SHORT_TI_D"))) foo<short>;
+
+// Explicit specializations work too.
+
+template <>
+struct  __attribute__ ((__exalias__ ("FOOCLS_INT_TI")))
+foo<int>
+{
+  virtual ~foo() {}
+  virtual void __attribute__ ((__exalias__ ("FOOCLS_INT_VIRT"))) virtfun() {}
+};
+
+/* { dg-final { scan-assembler "FOOFUN_UINT" } } */
+/* { dg-final { scan-assembler "FOOFUN_LONG" } } */
+/* { dg-final { scan-assembler "FOOFUN_CHAR" } } */
+
+/* { dg-final { scan-assembler "FOOCLS_VOID_TI" } } */
+/* { dg-final { scan-assembler "FOOCLS_VOID_ST" } } */
+/* { dg-final { scan-assembler "FOOCLS_CHAR_TI" } } */
+/* { dg-final { scan-assembler "FOOCLS_CHAR_VIRT" } } */
+/* { dg-final { scan-assembler "FOOCLS_SHORT_TI_X" } } */
+/* { dg-final { scan-assembler "FOOCLS_SHORT_ST" } } */
+/* { dg-final { scan-assembler "FOOCLS_SHORT_INL" } } */
+/* { dg-final { scan-assembler "FOOCLS_SHORT_TI_D" } } */
+/* { dg-final { scan-assembler-not "FOOCLS_LONG_TI_X" } } */
+/* { dg-final { scan-assembler-not "FOOCLS_LONG_VIRT" } } */
+/* { dg-final { scan-assembler "FOOCLS_INT_TI" } } */
+/* { dg-final { scan-assembler "FOOCLS_INT_VIRT" } } */
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..9623bef
--- /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-error "duplicate|already" }
+{
+  virtual ~foo() {}
+
+  template <typename U>
+  void
+    __attribute__ ((__exalias__ ("FOOTMF")))
+    tmemfun () {} // { dg-error "duplicate|already" }
+};
+
+template <typename T>
+void
+__attribute__ ((__exalias__ ("FOOTFN")))
+fn(T) { // { dg-error "duplicate|already" }
+};
+
+template class foo<>;
+template class foo<int>;
+template void foo<>::tmemfun<void>();
+template void foo<int>::tmemfun<void>();
+template void fn<>(int);
+template void fn<>(long);
diff --git a/gcc/varpool.c b/gcc/varpool.c
index 458cdf1..5f89662 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -162,6 +162,9 @@ varpool_node::get_create (tree decl)
     }
 
   node->register_symbol ();
+
+  create_exalias_decls (decl);
+
   return node;
 }
 


-- 
Alexandre Oliva, happy hacker
https://FSFLA.org/blogs/lxo/
Free Software Activist
GNU Toolchain Engineer

Reply via email to