On Thu, Jul 20, 2023 at 1:11 AM Alexandre Oliva <ol...@adacore.com> wrote:
>
> On Jul 18, 2023, Richard Biener <richard.guent...@gmail.com> wrote:
>
> > I think the __symver__ attribute does something similar already so
> > maybe use __attribute__((__sym__("foo")))?
>
> Cool, thanks, that will do.  Regstrapped on x86_64-linux-gnu.  Ok to
> install?
>
>
> This patch introduces an attribute to add extra asm names (aliases)
> for a decl 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 class types, 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 sym aliases
> with _Base and _Del suffixes are defined for variants other than
> complete-object ones.  This changes the assumption that clones always
> carry the same attributes as their abstract declarations, so there is
> now a function to adjust them.
>
> C++ also had a bug in which attributes from local extern declarations
> failed to be propagated to a preexisting corresponding
> namespace-scoped decl.  I've fixed that, and adjusted acc tests that
> distinguished between C and C++ in this regard.
>
> 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.

I wonder if we could have shared some of the cgraph/varasm bits
with the symver attribute handling?  It's just a new 'sym' but
without the version part?

I hope Honza can chime in here.

Thanks,
Richard.

> for  gcc/ChangeLog
>
>         * attribs.cc: Include cgraph.h.
>         (decl_attributes): Allow late introduction of sym alias in
>         types.
>         (create_sym_alias_decl, create_sym_alias_decls): New.
>         * attribs.h: Declare them.
>         (FOR_EACH_SYM_ALIAS): New macro.
>         * cgraph.cc (cgraph_node::create): Create sym alias decls.
>         * varpool.cc (varpool_node::get_create): Create sym alias
>         decls.
>         * cgraph.h (symtab_node::remap_sym_alias_target): New.
>         * symtab.cc (symtab_node::remap_sym_alias_target): Define.
>         * cgraphunit.cc (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 (sym): Document for variables, functions and
>         types.
>
> for  gcc/ada/ChangeLog
>
>         * doc/gnat_rm/interfacing_to_other_languages.rst: Mention
>         attribute sym to give RTTI symbols mnemonic names.
>         * doc/gnat_ugn/the_gnat_compilation_model.rst: Mention
>         aliases.  Fix incorrect ref to C1 ctor variant.
>
> for  gcc/c-family/ChangeLog
>
>         * c-ada-spec.cc (pp_asm_name): Use first sym alias if
>         available.
>         * c-attribs.cc (handle_sym_attribute): New.
>         (c_common_attribute_table): Add sym.
>         (handle_copy_attribute): Do not copy sym attribute.
>
> for  gcc/c/ChangeLog
>
>         * c-decl.cc (duplicate_decls): Remap sym alias target.
>
> for  gcc/cp/ChangeLog
>
>         * class.cc (adjust_clone_attributes): New.
>         (copy_fndecl_with_name, build_clone): Call it.
>         * cp-tree.h (adjust_clone_attributes): Declare.
>         (update_sym_alias_interface): Declare.
>         (update_tinfo_sym_alias): Declare.
>         * decl.cc (duplicate_decls): Remap sym_alias target.
>         Adjust clone attributes.
>         (grokfndecl): Tentatively create sym alias decls after
>         adding attributes in e.g. a template member function explicit
>         instantiation.
>         * decl2.cc (cplus_decl_attributes): Update tinfo sym alias.
>         (copy_interface, update_sym_alias_interface): New.
>         (determine_visibility): Update sym alias interface.
>         (tentative_decl_linkage, import_export_decl): Likewise.
>         * name-lookup.cc: Include target.h and cgraph.h.
>         (push_local_extern_decl_alias): Merge attributes with
>         namespace-scoped decl, and drop duplicate sym alias.
>         * optimize.cc (maybe_clone_body): Re-adjust attributes after
>         cloning them.  Update sym alias interface.
>         * rtti.cc: Include attribs.h and cgraph.h.
>         (get_tinfo_decl): Copy sym attributes from type to tinfo decl.
>         Create sym alias decls.
>         (update_tinfo_sym_alias): New.
>
> for  gcc/testsuite/ChangeLog
>
>         * c-c++-common/goacc/declare-1.c: Adjust.
>         * c-c++-common/goacc/declare-2.c: Adjust.
>         * c-c++-common/torture/attr-sym-1.c: New.
>         * c-c++-common/torture/attr-sym-2.c: New.
>         * c-c++-common/torture/attr-sym-3.c: New.
>         * c-c++-common/torture/attr-sym-4.c: New.
>         * g++.dg/torture/attr-sym-1.C: New.
>         * g++.dg/torture/attr-sym-2.C: New.
>         * g++.dg/torture/attr-sym-3.C: New.
>         * g++.dg/torture/attr-sym-4.C: New.
>         * g++.dg/torture/attr-sym-5.C: New.
> ---
>  .../doc/gnat_rm/interfacing_to_other_languages.rst |    6 +
>  .../doc/gnat_ugn/the_gnat_compilation_model.rst    |   10 ++
>  gcc/attribs.cc                                     |   68 ++++++++++++++++
>  gcc/attribs.h                                      |    7 ++
>  gcc/c-family/c-ada-spec.cc                         |    7 ++
>  gcc/c-family/c-attribs.cc                          |   33 +++++++-
>  gcc/c/c-decl.cc                                    |    2
>  gcc/cgraph.cc                                      |    2
>  gcc/cgraph.h                                       |    4 +
>  gcc/cgraphunit.cc                                  |    2
>  gcc/cp/class.cc                                    |   64 +++++++++++++++
>  gcc/cp/cp-tree.h                                   |    4 +
>  gcc/cp/decl.cc                                     |    4 +
>  gcc/cp/decl2.cc                                    |   50 ++++++++++++
>  gcc/cp/name-lookup.cc                              |   11 +++
>  gcc/cp/optimize.cc                                 |    3 +
>  gcc/cp/rtti.cc                                     |   71 +++++++++++++++++
>  gcc/doc/extend.texi                                |   52 +++++++++++++
>  gcc/symtab.cc                                      |   36 +++++++++
>  gcc/testsuite/c-c++-common/goacc/declare-1.c       |    6 +
>  gcc/testsuite/c-c++-common/goacc/declare-2.c       |   14 ++-
>  gcc/testsuite/c-c++-common/torture/attr-sym-1.c    |   39 +++++++++
>  gcc/testsuite/c-c++-common/torture/attr-sym-2.c    |   13 +++
>  gcc/testsuite/c-c++-common/torture/attr-sym-3.c    |   41 ++++++++++
>  gcc/testsuite/c-c++-common/torture/attr-sym-4.c    |   28 +++++++
>  gcc/testsuite/g++.dg/torture/attr-sym-1.C          |   72 +++++++++++++++++
>  gcc/testsuite/g++.dg/torture/attr-sym-2.C          |   26 ++++++
>  gcc/testsuite/g++.dg/torture/attr-sym-3.C          |   83 
> ++++++++++++++++++++
>  gcc/testsuite/g++.dg/torture/attr-sym-4.C          |   28 +++++++
>  gcc/testsuite/g++.dg/torture/attr-sym-5.C          |   14 +++
>  gcc/varpool.cc                                     |    3 +
>  31 files changed, 784 insertions(+), 19 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/torture/attr-sym-1.c
>  create mode 100644 gcc/testsuite/c-c++-common/torture/attr-sym-2.c
>  create mode 100644 gcc/testsuite/c-c++-common/torture/attr-sym-3.c
>  create mode 100644 gcc/testsuite/c-c++-common/torture/attr-sym-4.c
>  create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-1.C
>  create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-2.C
>  create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-3.C
>  create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-4.C
>  create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-5.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 ad0be511d4800..5e30912e434aa 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 ``sym`` 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 148d40815b8f8..fcae7e912ef36 100644
> --- a/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
> +++ b/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
> @@ -4274,6 +4274,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__ ((__sym__ ("Ctor_For_Animal")))
>          Animal() {Age_Count = 0;};
>        private:
>          int Age_Count;
> @@ -4306,6 +4307,7 @@ both Carnivore and Domestic, that is:
>          virtual int  Number_Of_Teeth ();
>          virtual void Set_Owner (char* Name);
>
> +        __attribute__ ((__sym__ ("Ctor_For_Dog"))) // mnemonic alias
>          Dog(); // Constructor
>        private:
>          int  Tooth_Count;
> @@ -4344,7 +4346,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;
> @@ -4360,7 +4363,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,7 +4385,8 @@ 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.
> +mangled name (or an alias) 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.cc b/gcc/attribs.cc
> index b8cb55b97df38..cd394f4c5f608 100644
> --- a/gcc/attribs.cc
> +++ b/gcc/attribs.cc
> @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "coretypes.h"
>  #include "target.h"
>  #include "tree.h"
> +#include "cgraph.h"
>  #include "stringpool.h"
>  #include "diagnostic-core.h"
>  #include "attribs.h"
> @@ -819,7 +820,8 @@ decl_attributes (tree *node, tree attributes, int flags,
>
>        if (TYPE_P (*anode)
>           && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
> -         && COMPLETE_TYPE_P (*anode))
> +         && COMPLETE_TYPE_P (*anode)
> +         && !is_attribute_p ("sym", name))
>         {
>           warning (OPT_Wattributes, "type attributes ignored after type is 
> already defined");
>           continue;
> @@ -2631,6 +2633,70 @@ attr_access::array_as_string (tree type) const
>    return typstr;
>  }
>
> +/* Create a sym attribute for DECL to be visible with linkage name ID.  */
> +
> +tree
> +create_sym_alias_decl (tree decl, tree id)
> +{
> +  const char *attr_str = "sym";
> +
> +  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;
> +
> +      tree attr_name = get_identifier (attr_str);
> +      error_at (DECL_SOURCE_LOCATION (decl),
> +               "duplicate symbol name %qE in %qE attribute of %qD",
> +               id, attr_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 (attr_str,
> +                                             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 decls for all sym aliases requested in DECL's attributes.  */
> +
> +void
> +create_sym_alias_decls (tree decl)
> +{
> +  if (!decl_in_symtab_p (decl)
> +      || !symtab_node::get (decl)
> +      || DECL_ABSTRACT_P (decl))
> +    return;
> +
> +  FOR_EACH_SYM_ALIAS (sym, DECL_ATTRIBUTES (decl))
> +    {
> +      tree id = TREE_VALUE (TREE_VALUE (sym));
> +      id = get_identifier (TREE_STRING_POINTER (id));
> +
> +      create_sym_alias_decl (decl, id);
> +    }
> +}
> +
>  #if CHECKING_P
>
>  namespace selftest
> diff --git a/gcc/attribs.h b/gcc/attribs.h
> index 84a43658a70da..734fa83f8d572 100644
> --- a/gcc/attribs.h
> +++ b/gcc/attribs.h
> @@ -398,4 +398,11 @@ extern void init_attr_rdwr_indices (rdwr_map *, tree);
>  extern attr_access *get_parm_access (rdwr_map &, tree,
>                                      tree = current_function_decl);
>
> +extern tree create_sym_alias_decl (tree, tree);
> +extern void create_sym_alias_decls (tree);
> +
> +#define FOR_EACH_SYM_ALIAS(sym, attrs)                                 \
> +  for (tree sym = lookup_attribute ("sym", (attrs));                   \
> +       sym; sym = lookup_attribute ("sym", TREE_CHAIN (sym)))
> +
>  #endif // GCC_ATTRIBS_H
> diff --git a/gcc/c-family/c-ada-spec.cc b/gcc/c-family/c-ada-spec.cc
> index 050994d841665..5042b9cfecd80 100644
> --- a/gcc/c-family/c-ada-spec.cc
> +++ b/gcc/c-family/c-ada-spec.cc
> @@ -1431,6 +1431,13 @@ pp_ada_tree_identifier (pretty_printer *buffer, tree 
> node, tree type,
>  static void
>  pp_asm_name (pretty_printer *buffer, tree t)
>  {
> +  FOR_EACH_SYM_ALIAS (sym, DECL_ATTRIBUTES (t))
> +    {
> +      tree id = TREE_VALUE (TREE_VALUE (sym));
> +      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.cc b/gcc/c-family/c-attribs.cc
> index e2792ca6898b3..f5d72cef49794 100644
> --- a/gcc/c-family/c-attribs.cc
> +++ b/gcc/c-family/c-attribs.cc
> @@ -108,7 +108,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_sym_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,
> @@ -383,6 +384,8 @@ const struct attribute_spec c_common_attribute_table[] =
>                               handle_alias_attribute, NULL },
>    { "weakref",                0, 1, true,  false, false, false,
>                               handle_weakref_attribute, NULL },
> +  { "sym",                    1, 1, false,  false, false, false,
> +                             handle_sym_attribute, NULL },
>    { "no_instrument_function", 0, 0, true,  false, false, false,
>                               handle_no_instrument_function_attribute,
>                               NULL },
> @@ -2855,7 +2858,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
> @@ -2865,7 +2868,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
> @@ -2875,6 +2878,29 @@ handle_alias_attribute (tree *node, tree name, tree 
> args,
>    return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
>  }
>
> +/* Handle a "sym" attribute; arguments as in struct
> +   attribute_spec.handler.  */
> +
> +static tree
> +handle_sym_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.  */
>
> @@ -3008,6 +3034,7 @@ handle_copy_attribute (tree *node, tree name, tree args,
>               || is_attribute_p ("visibility", atname)
>               || is_attribute_p ("weak", atname)
>               || is_attribute_p ("weakref", atname)
> +             || is_attribute_p ("sym", atname)
>               || is_attribute_p ("target_clones", atname))
>             continue;
>
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index ecd10ebb69caf..5d6ce11cbb3ab 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -3073,6 +3073,8 @@ duplicate_decls (tree newdecl, tree olddecl)
>
>    merge_decls (newdecl, olddecl, newtype, oldtype);
>
> +  symtab_node::remap_sym_alias_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.cc b/gcc/cgraph.cc
> index e41e5ad3ae74d..c45ce2d0a1332 100644
> --- a/gcc/cgraph.cc
> +++ b/gcc/cgraph.cc
> @@ -523,6 +523,8 @@ cgraph_node::create (tree decl)
>    node->register_symbol ();
>    maybe_record_nested_function (node);
>
> +  create_sym_alias_decls (decl);
> +
>    return node;
>  }
>
> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
> index cedaaac3a45b7..6a444e6fa5bcf 100644
> --- a/gcc/cgraph.h
> +++ b/gcc/cgraph.h
> @@ -327,6 +327,10 @@ public:
>    /* Return DECL that alias is aliasing.  */
>    inline tree get_alias_target_tree ();
>
> +  /* Remap sym alias nodes recorded as aliasing REPLACED to alias REPLACEMENT
> +     instead.  */
> +  static void remap_sym_alias_target (tree replaced, tree replacement);
> +
>    /* Set section for symbol and its aliases.  */
>    void set_section (const char *section);
>
> diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
> index bccd2f2abb5a3..eb2d05094e989 100644
> --- a/gcc/cgraphunit.cc
> +++ b/gcc/cgraphunit.cc
> @@ -1175,7 +1175,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.cc b/gcc/cp/class.cc
> index 778759237dc72..d6218bab28b21 100644
> --- a/gcc/cp/class.cc
> +++ b/gcc/cp/class.cc
> @@ -4859,6 +4859,68 @@ check_methods (tree t)
>      }
>  }
>
> +/* Adjust sym alias name for CLONE, cloned from FN and named NAME,
> +   if it is a cdtor, and drop the sym alias from other clones.  */
> +
> +void
> +adjust_clone_attributes (tree fn, tree clone, tree name, bool skip_copy_p)
> +{
> +  if (IDENTIFIER_CDTOR_P (name))
> +    {
> +      bool found = false;
> +      FOR_EACH_SYM_ALIAS (sym, DECL_ATTRIBUTES (clone))
> +       {
> +         found = true;
> +         break;
> +       }
> +
> +      if (found
> +         && (name == complete_ctor_identifier
> +             || name == complete_dtor_identifier))
> +       {
> +         /* Reuse the sym alias decls created for the primary cdtor
> +            decl.  */
> +         symtab_node::remap_sym_alias_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);
> +
> +         if (!skip_copy_p)
> +           DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (clone));
> +
> +         FOR_EACH_SYM_ALIAS (sym, DECL_ATTRIBUTES (clone))
> +           {
> +             /* We need to copy this even with skip_copy_p, because
> +                even then copying was shallow.  */
> +             TREE_VALUE (sym) = copy_list (TREE_VALUE (sym));
> +             /* Append suf to the sym alias name.  */
> +             tree str = TREE_VALUE (TREE_VALUE (sym));
> +             char *symname = concat (TREE_STRING_POINTER (str), suf, NULL);
> +             str = build_string (TREE_STRING_LENGTH (str) + xlen, symname);
> +             TREE_VALUE (TREE_VALUE (sym)) = str;
> +             free (symname);
> +           }
> +
> +         if (symtab_node::get (clone))
> +           create_sym_alias_decls (clone);
> +       }
> +    }
> +  else
> +    DECL_ATTRIBUTES (clone)
> +      = remove_attribute ("sym", DECL_ATTRIBUTES (clone));
> +}
> +
>  /* FN is constructor, destructor or operator function.  Clone the
>     declaration to create a NAME'd variant.  NEED_VTT_PARM_P and
>     OMIT_INHERITED_PARMS_P are relevant if it's a cdtor.  */
> @@ -5026,6 +5088,8 @@ build_clone (tree fn, tree name, bool need_vtt_parm_p,
>    DECL_CHAIN (clone) = DECL_CHAIN (fn);
>    DECL_CHAIN (fn) = clone;
>
> +  adjust_clone_attributes (fn, clone, name);
> +
>    return clone;
>  }
>
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 3de0e154c124c..0a998d0bafd15 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -5747,6 +5747,8 @@ struct GTY((for_user)) spec_entry
>
>  extern int current_class_depth;
>
> +void adjust_clone_attributes (tree fn, tree clone, tree name, bool = false);
> +
>  /* in decl.cc */
>
>  /* An array of static vars & fns.  */
> @@ -6960,6 +6962,7 @@ extern void do_push_parm_decls                    
> (tree, tree, tree *);
>  extern tree do_aggregate_paren_init            (tree, tree);
>
>  /* in decl2.cc */
> +extern void update_sym_alias_interface         (tree);
>  extern void record_mangling                    (tree, bool);
>  extern void overwrite_mangling                 (tree, tree);
>  extern void note_mangling_alias                        (tree, tree);
> @@ -7535,6 +7538,7 @@ extern bool emit_tinfo_decl                       
> (tree);
>  extern unsigned get_pseudo_tinfo_index         (tree);
>  extern tree get_pseudo_tinfo_type              (unsigned);
>  extern tree build_if_nonnull                   (tree, tree, tsubst_flags_t);
> +extern void update_tinfo_sym_alias             (tree);
>
>  /* in search.cc */
>  extern tree get_parent_with_private_access     (tree decl, tree binfo);
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 60f107d50c4c5..28f7dbaf35d75 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -3195,6 +3195,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
> hiding, bool was_hidden)
>               && TREE_STATIC (olddecl))))
>      make_decl_rtl (olddecl);
>
> +  symtab_node::remap_sym_alias_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.
> @@ -3218,6 +3220,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
> hiding, bool was_hidden)
>        FOR_EACH_CLONE (clone, olddecl)
>         {
>           DECL_ATTRIBUTES (clone) = DECL_ATTRIBUTES (olddecl);
> +         adjust_clone_attributes (olddecl, clone, DECL_NAME (clone));
>           DECL_PRESERVE_P (clone) |= DECL_PRESERVE_P (olddecl);
>         }
>      }
> @@ -10683,6 +10686,7 @@ grokfndecl (tree ctype,
>      {
>        cplus_decl_attributes (&decl, *attrlist, 0);
>        *attrlist = NULL_TREE;
> +      create_sym_alias_decls (decl);
>      }
>
>    if (DECL_HAS_CONTRACTS_P (decl))
> diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
> index b402befba6da4..68232b8863f16 100644
> --- a/gcc/cp/decl2.cc
> +++ b/gcc/cp/decl2.cc
> @@ -1773,6 +1773,9 @@ cplus_decl_attributes (tree *decl, tree attributes, int 
> flags)
>    if (late_attrs)
>      save_template_attributes (late_attrs, decl, flags);
>
> +  if (TYPE_P (*decl) && attributes)
> +    update_tinfo_sym_alias (*decl);
> +
>    /* Propagate deprecation out to the template.  */
>    if (TREE_DEPRECATED (*decl))
>      if (tree ti = get_template_info (*decl))
> @@ -2129,6 +2132,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 sym aliases.  */
> +
> +void
> +update_sym_alias_interface (tree decl)
> +{
> +  if (!decl_in_symtab_p (decl)
> +      || !symtab_node::get (decl))
> +    return;
> +
> +  FOR_EACH_SYM_ALIAS (sym, DECL_ATTRIBUTES (decl))
> +    {
> +      tree id = TREE_VALUE (TREE_VALUE (sym));
> +      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.  */
>
> @@ -2936,6 +2980,8 @@ determine_visibility (tree decl)
>         translation unit, we can make the type internal.  */
>      constrain_visibility (decl, VISIBILITY_ANON, false);
>
> +  update_sym_alias_interface (decl);
> +
>    /* If visibility changed and DECL already has DECL_RTL, ensure
>       symbol flags are updated.  */
>    if ((DECL_VISIBILITY (decl) != orig_visibility
> @@ -3198,6 +3244,8 @@ tentative_decl_linkage (tree decl)
>        else if (VAR_P (decl))
>         maybe_commonize_var (decl);
>      }
> +
> +  update_sym_alias_interface (decl);
>  }
>
>  /* DECL is a FUNCTION_DECL or VAR_DECL.  If the object file linkage
> @@ -3432,6 +3480,8 @@ import_export_decl (tree decl)
>      }
>
>    DECL_INTERFACE_KNOWN (decl) = 1;
> +
> +  update_sym_alias_interface (decl);
>  }
>
>  /* Return an expression that performs the destruction of DECL, which
> diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
> index 74565184403c1..12e4c78086016 100644
> --- a/gcc/cp/name-lookup.cc
> +++ b/gcc/cp/name-lookup.cc
> @@ -22,9 +22,11 @@ along with GCC; see the file COPYING3.  If not see
>  #define INCLUDE_MEMORY
>  #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"
> @@ -3466,6 +3468,15 @@ push_local_extern_decl_alias (tree decl)
>           /* Adjust visibility.  */
>           determine_visibility (alias);
>         }
> +      else if (DECL_P (alias))
> +       DECL_ATTRIBUTES (alias)
> +         = targetm.merge_decl_attributes (alias, decl);
> +      if (DECL_P (alias))
> +       {
> +         symtab_node::remap_sym_alias_target (decl, alias);
> +         DECL_ATTRIBUTES (decl)
> +           = remove_attribute ("sym", DECL_ATTRIBUTES (alias));
> +       }
>      }
>
>    retrofit_lang_decl (decl);
> diff --git a/gcc/cp/optimize.cc b/gcc/cp/optimize.cc
> index 9e8926e4cc603..4a2e8cb435404 100644
> --- a/gcc/cp/optimize.cc
> +++ b/gcc/cp/optimize.cc
> @@ -528,9 +528,12 @@ maybe_clone_body (tree fn)
>        DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn);
>        DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn);
>        DECL_ATTRIBUTES (clone) = clone_attrs (DECL_ATTRIBUTES (fn));
> +      adjust_clone_attributes (fn, clone, DECL_NAME (clone), true);
>        DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS 
> (fn);
>        set_decl_section_name (clone, fn);
>
> +      update_sym_alias_interface (clone);
> +
>        /* Adjust the parameter names and locations.  */
>        parm = DECL_ARGUMENTS (fn);
>        clone_parm = DECL_ARGUMENTS (clone);
> diff --git a/gcc/cp/rtti.cc b/gcc/cp/rtti.cc
> index 7878929c24679..4bb7b8c8c6e78 100644
> --- a/gcc/cp/rtti.cc
> +++ b/gcc/cp/rtti.cc
> @@ -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
> @@ -479,8 +481,13 @@ get_tinfo_decl_direct (tree type, tree name, int 
> pseudo_ix)
>           = build_tree_list (get_identifier ("non overlapping"),
>                              NULL_TREE);
>        else
> +       /* Share the non overlapping attribute, without assuming it's
> +          the only attribute, but assuming it's the last if it's
> +          present.  There may be sym aliases too, and those are not
> +          to be shared.  */
>         DECL_ATTRIBUTES (d)
> -         = DECL_ATTRIBUTES ((*unemitted_tinfo_decls)[0]);
> +         = lookup_attribute ("non overlapping",
> +                             DECL_ATTRIBUTES ((*unemitted_tinfo_decls)[0]));
>
>        /* Mark the variable as undefined -- but remember that we can
>          define it later if we need to do so.  */
> @@ -492,6 +499,16 @@ get_tinfo_decl_direct (tree type, tree name, int 
> pseudo_ix)
>        if (CLASS_TYPE_P (type))
>         CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
>
> +      /* Copy sym alias attributes from the type to the rtti obj decl.  */
> +      tree *attrs = &DECL_ATTRIBUTES (d);
> +      FOR_EACH_SYM_ALIAS (sym, TYPE_ATTRIBUTES (type))
> +       {
> +         tree attr = tree_cons (TREE_PURPOSE (sym), TREE_VALUE (sym), 
> *attrs);
> +         *attrs = attr;
> +         attrs = &TREE_CHAIN (attr);
> +       }
> +      create_sym_alias_decls (d);
> +
>        /* Add decl to the global array of tinfo decls.  */
>        vec_safe_push (unemitted_tinfo_decls, d);
>      }
> @@ -499,6 +516,58 @@ get_tinfo_decl_direct (tree type, tree name, int 
> pseudo_ix)
>    return d;
>  }
>
> +/* After modifying the attributes of TYPE, check whether tinfo was
> +   already created and, if so, add to it any sym alias attributes
> +   that were not already present.  */
> +
> +void
> +update_tinfo_sym_alias (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_SYM_ALIAS (sym, TYPE_ATTRIBUTES (type))
> +    {
> +      bool found = false;
> +      FOR_EACH_SYM_ALIAS (d_sym, *attrs)
> +       if (TREE_VALUE (sym) == TREE_VALUE (d_sym))
> +         {
> +           found = true;
> +           break;
> +         }
> +
> +      if (found)
> +       continue;
> +
> +      tree attr = tree_cons (TREE_PURPOSE (sym),
> +                            TREE_VALUE (sym),
> +                            *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 (sym));
> +      id = get_identifier (TREE_STRING_POINTER (id));
> +      create_sym_alias_decl (d, id);
> +    }
> +}
> +
>  /* Return the type_info object for TYPE.  */
>
>  tree
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index dda35358ce746..4ffe06dc805cd 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -4057,6 +4057,39 @@ Function Attributes}, @ref{PowerPC Function 
> Attributes},
>  @ref{Nios II Function Attributes}, and @ref{S/390 Function Attributes}
>  for details.
>
> +@cindex @code{sym} function attribute
> +@item sym ("@var{name}")
> +The @code{sym} attribute causes @var{name} to be output as an alias to
> +the definition.  For instance,
> +
> +@smallexample
> +void f (uint64_t) __attribute__ ((__sym__ ("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 for aliases,
> +and may not be available on all targets.
> +
>  @cindex @code{symver} function attribute
>  @item symver ("@var{name2}@@@var{nodename}")
>  On ELF targets this attribute creates a symbol version.  The @var{name2} part
> @@ -7873,6 +7906,10 @@ will be placed in new, unique sections.
>
>  This additional functionality requires Binutils version 2.36 or later.
>
> +@cindex @code{sym} variable attribute
> +@item sym ("@var{name}")
> +See @pxref{Common Function Attributes}.
> +
>  @cindex @code{uninitialized} variable attribute
>  @item uninitialized
>  This attribute, attached to a variable with automatic storage, means that
> @@ -8902,6 +8939,21 @@ is not supported; that is to say, if a given scalar 
> object can be accessed
>  through distinct types that assign a different storage order to it, then the
>  behavior is undefined.
>
> +@cindex @code{sym} type attribute
> +@item sym ("@var{name}")
> +The @code{sym} type 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__ ((__sym__ ("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.
> +
>  @cindex @code{transparent_union} type attribute
>  @item transparent_union
>
> diff --git a/gcc/symtab.cc b/gcc/symtab.cc
> index 0470509a98d2a..0812088e59f38 100644
> --- a/gcc/symtab.cc
> +++ b/gcc/symtab.cc
> @@ -1943,6 +1943,42 @@ symtab_node::noninterposable_alias (symtab_node *node, 
> void *data)
>    return false;
>  }
>
> +/* Remap sym alias nodes recorded as aliasing REPLACED to alias
> +   REPLACEMENT instead.  */
> +
> +void
> +symtab_node::remap_sym_alias_target (tree replaced, tree replacement)
> +{
> +  if (!decl_in_symtab_p (replacement)
> +      || !symtab_node::get (replacement))
> +    return;
> +
> +  FOR_EACH_SYM_ALIAS (sym, DECL_ATTRIBUTES (replaced))
> +    {
> +      tree id = TREE_VALUE (TREE_VALUE (sym));
> +      id = get_identifier (TREE_STRING_POINTER (id));
> +
> +      symtab_node *sym_node = symtab_node::get_for_asmname (id);
> +
> +      if (!sym_node)
> +       {
> +         create_sym_alias_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/goacc/declare-1.c 
> b/gcc/testsuite/c-c++-common/goacc/declare-1.c
> index 46ee01b675950..f284289331807 100644
> --- a/gcc/testsuite/c-c++-common/goacc/declare-1.c
> +++ b/gcc/testsuite/c-c++-common/goacc/declare-1.c
> @@ -113,11 +113,11 @@ f_2 (void)
>    int va3;
>  #pragma acc declare device_resident(va3)
>
> -#ifndef __cplusplus
> +#if 0
>    /* TODO PR90868
>
> -     C: "error: variable '[...]' used more than once with '#pragma acc 
> declare'".  */
> -#else
> +     "error: variable '[...]' used more than once with '#pragma acc 
> declare'".  */
> +
>    extern int ve0;
>  #pragma acc declare create(ve0)
>
> diff --git a/gcc/testsuite/c-c++-common/goacc/declare-2.c 
> b/gcc/testsuite/c-c++-common/goacc/declare-2.c
> index e2e22be57e9e4..aec59b69754c5 100644
> --- a/gcc/testsuite/c-c++-common/goacc/declare-2.c
> +++ b/gcc/testsuite/c-c++-common/goacc/declare-2.c
> @@ -137,25 +137,25 @@ void
>  f_pr90868_2 (void)
>  {
>    extern int we0;
> -#pragma acc declare create(we0) /* { dg-error "variable 'we0' used more than 
> once with '#pragma acc declare'" "" { target c } } */
> +#pragma acc declare create(we0) /* { dg-error "variable 'we0' used more than 
> once with '#pragma acc declare'" "" } */
>
>    extern int we1;
> -#pragma acc declare copyin(we1) /* { dg-error "variable 'we1' used more than 
> once with '#pragma acc declare'" "" { target c } } */
> +#pragma acc declare copyin(we1) /* { dg-error "variable 'we1' used more than 
> once with '#pragma acc declare'" "" } */
>
>    extern int *we2;
> -#pragma acc declare deviceptr(we2) /* { dg-error "variable 'we2' used more 
> than once with '#pragma acc declare'" "" { target c } } */
> +#pragma acc declare deviceptr(we2) /* { dg-error "variable 'we2' used more 
> than once with '#pragma acc declare'" "" } */
>
>    extern int we3;
> -#pragma acc declare device_resident(we3) /* { dg-error "variable 'we3' used 
> more than once with '#pragma acc declare'" "" { target c } } */
> +#pragma acc declare device_resident(we3) /* { dg-error "variable 'we3' used 
> more than once with '#pragma acc declare'" "" } */
>
>    extern int we4;
> -#pragma acc declare link(we4) /* { dg-error "variable 'we4' used more than 
> once with '#pragma acc declare'" "" { target c } } */
> +#pragma acc declare link(we4) /* { dg-error "variable 'we4' used more than 
> once with '#pragma acc declare'" "" } */
>
>    extern int we5;
> -#pragma acc declare present_or_copyin(we5) /* { dg-error "variable 'we5' 
> used more than once with '#pragma acc declare'" "" { target c } } */
> +#pragma acc declare present_or_copyin(we5) /* { dg-error "variable 'we5' 
> used more than once with '#pragma acc declare'" "" } */
>
>    extern int we6;
> -#pragma acc declare present_or_create(we6) /* { dg-error "variable 'we6' 
> used more than once with '#pragma acc declare'" "" { target c } } */
> +#pragma acc declare present_or_create(we6) /* { dg-error "variable 'we6' 
> used more than once with '#pragma acc declare'" "" } */
>  }
>
>
> diff --git a/gcc/testsuite/c-c++-common/torture/attr-sym-1.c 
> b/gcc/testsuite/c-c++-common/torture/attr-sym-1.c
> new file mode 100644
> index 0000000000000..6254c4ffd35bb
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/torture/attr-sym-1.c
> @@ -0,0 +1,39 @@
> +/* { dg-do compile } */
> +/* { dg-require-alias "" } */
> +
> +extern int var_a __attribute__ ((__sym__ ("FOOVAR_A")));
> +int var_a = 1;
> +
> +void foo_a () __attribute__ ((__sym__ ("FOOBAR_A")));
> +
> +void
> +foo_a ()
> +{
> +}
> +
> +
> +int var_b;
> +extern int var_b __attribute__ ((__sym__ ("FOOVAR_B")));
> +
> +void
> +foo_b ()
> +{
> +}
> +
> +void foo_b () __attribute__ ((__sym__ ("FOOBAR_B")));
> +
> +
> +int var_c __attribute__ ((__sym__ ("FOOVAR_C")));
> +
> +void __attribute__ ((__sym__ ("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-sym-2.c 
> b/gcc/testsuite/c-c++-common/torture/attr-sym-2.c
> new file mode 100644
> index 0000000000000..62a62d772f40c
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/torture/attr-sym-2.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-require-alias "" } */
> +
> +struct s
> +{
> +  int mem __attribute__ ((__sym__ ("MEMFOO"))); /* { dg-warning "attribute 
> ignored" } */
> +};
> +
> +void foo()
> +{
> +  extern void bar () __attribute__ ((__sym__ ("FOOBAR")));
> +  int var __attribute__ ((__sym__ ("FOOVAR"))); /* { dg-warning "attribute 
> ignored" } */
> +}
> diff --git a/gcc/testsuite/c-c++-common/torture/attr-sym-3.c 
> b/gcc/testsuite/c-c++-common/torture/attr-sym-3.c
> new file mode 100644
> index 0000000000000..5f0da2813fc37
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/torture/attr-sym-3.c
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +/* { dg-require-alias "" } */
> +
> +int var_a = 1;
> +
> +void
> +foo_a ()
> +{
> +  extern int var_a __attribute__ ((__sym__ ("FOOVAR_A")));
> +  void foo_a () __attribute__ ((__sym__ ("FOOBAR_A")));
> +}
> +
> +#if 0 // __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__ ((__sym__ ("FOOVAR_B")));
> +}
> +
> +int var_b;
> +
> +void __attribute__ ((__sym__ ("FOOBAR_C")))
> +foo_c ()
> +{
> +  void foo_b () __attribute__ ((__sym__ ("FOOBAR_B")));
> +  /* Another sym for var_b.  */
> +  extern int var_b __attribute__ ((__sym__ ("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-sym-4.c 
> b/gcc/testsuite/c-c++-common/torture/attr-sym-4.c
> new file mode 100644
> index 0000000000000..93312a38de61c
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/torture/attr-sym-4.c
> @@ -0,0 +1,28 @@
> +/* { dg-do run } */
> +/* { dg-require-alias "" } */
> +
> +int var_a __attribute__ ((__sym__ ("FOOVAR_A"))) = 42;
> +
> +int __attribute__ ((__sym__ ("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-sym-1.C 
> b/gcc/testsuite/g++.dg/torture/attr-sym-1.C
> new file mode 100644
> index 0000000000000..11aaabfa6599c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/torture/attr-sym-1.C
> @@ -0,0 +1,72 @@
> +/* { dg-do compile } */
> +/* { dg-require-alias "" } */
> +
> +class __attribute__ ((__sym__ ("FOOCLS_A"),
> +                     __sym__ ("FOOCLS_A_Dupe"))) foo {
> +  static int var __attribute__ ((__sym__ ("FOOVAR_A")));
> +  __attribute__ ((__sym__ ("FOOCTR_A"))) foo ();
> +  void __attribute__ ((__sym__ ("FOOBAR_A"))) bar ();
> +  virtual __attribute__ ((__sym__ ("FOODTR_A"))) ~foo() {}
> +};
> +
> +int foo::var = 1;
> +
> +foo::foo () {}
> +
> +void foo::bar () {}
> +
> +namespace b {
> +  class __attribute__ ((__sym__ ("FOOCLS_B"))) foo {
> +    static int var __attribute__ ((__sym__ ("FOOVAR_B")));
> +    __attribute__ ((__sym__ ("FOOCTR_B"))) foo ();
> +    void __attribute__ ((__sym__ ("FOOBAR_B"))) bar () {}
> +    virtual __attribute__ ((__sym__ ("FOODTR_B"))) ~foo() {}
> +  };
> +
> +  int foo::var = 2;
> +
> +  foo::foo () {
> +    void (foo::*pbar)() = &foo::bar;
> +  }
> +}
> +
> +namespace c {
> +  namespace cd {
> +    class __attribute__ ((__sym__ ("FOOCLS_C"))) foo {
> +      static int var __attribute__ ((__sym__ ("FOOVAR_C")));
> +      __attribute__ ((__sym__ ("FOOCTR_C"))) foo () {
> +       void (foo::*pbar)() = &foo::bar;
> +      }
> +      void __attribute__ ((__sym__ ("FOOBAR_C"))) bar () {}
> +      virtual __attribute__ ((__sym__ ("FOODTR_C"))) ~foo() {}
> +    };
> +
> +    int foo::var = 3;
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "FOOCLS_A" } } */
> +/* { dg-final { scan-assembler "FOOCLS_A_Dupe" } } */
> +/* { 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-sym-2.C 
> b/gcc/testsuite/g++.dg/torture/attr-sym-2.C
> new file mode 100644
> index 0000000000000..f4714ea1ce5bd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/torture/attr-sym-2.C
> @@ -0,0 +1,26 @@
> +/* { dg-do compile } */
> +/* { dg-require-alias "" } */
> +
> +namespace {
> +  class __attribute__ ((__sym__ ("FOOCLS_A"))) foo {
> +    static int var __attribute__ ((__sym__ ("FOOVAR_A")));
> +    __attribute__ ((__sym__ ("FOOCTR_A"))) foo ();
> +    virtual __attribute__ ((__sym__ ("FOODTR_A"))) ~foo ();
> +    void __attribute__ ((__sym__ ("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-sym-3.C 
> b/gcc/testsuite/g++.dg/torture/attr-sym-3.C
> new file mode 100644
> index 0000000000000..f819d5a02ce47
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/torture/attr-sym-3.C
> @@ -0,0 +1,83 @@
> +/* { dg-do compile } */
> +/* { dg-require-alias "" } */
> +
> +// sym can be applied to template function explicit instantiations.
> +
> +template <typename T>
> +void
> +fn(T) {
> +};
> +
> +template void __attribute__ ((__sym__ ("FOOFUN_UINT"))) fn<>(unsigned int);
> +template void __attribute__ ((__sym__ ("FOOFUN_LONG"))) fn<>(long);
> +
> +template<> void __attribute__ ((__sym__ ("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__ ((__sym__ ("FOOCLS_CHAR_VIRT"))) foo<char>::virtfun();
> +
> +template class __attribute__ ((__sym__ ("FOOCLS_CHAR_TI"))) foo<char>;
> +
> +// Though they're only output if the enclosing class is.
> +template void
> +__attribute__ ((__sym__ ("FOOCLS_LONG_VIRT"))) foo<long>::virtfun();
> +extern
> +template class __attribute__ ((__sym__ ("FOOCLS_LONG_TI_X"))) foo<long>;
> +
> +
> +template void
> +__attribute__ ((__sym__ ("FOOCLS_VOID_ST"))) foo<void>::stfun();
> +
> +template class __attribute__ ((__sym__ ("FOOCLS_VOID_TI"))) foo<>;
> +
> +
> +extern
> +template class __attribute__ ((__sym__ ("FOOCLS_SHORT_TI_X"))) foo<short>;
> +
> +template void
> +__attribute__ ((__sym__ ("FOOCLS_SHORT_ST"))) foo<short>::stfun();
> +template void
> +__attribute__ ((__sym__ ("FOOCLS_SHORT_INL"))) foo<short>::inlfun();
> +
> +template class __attribute__ ((__sym__ ("FOOCLS_SHORT_TI_D"))) foo<short>;
> +
> +// Explicit specializations work too.
> +
> +template <>
> +struct  __attribute__ ((__sym__ ("FOOCLS_INT_TI")))
> +foo<int>
> +{
> +  virtual ~foo() {}
> +  virtual void __attribute__ ((__sym__ ("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-sym-4.C 
> b/gcc/testsuite/g++.dg/torture/attr-sym-4.C
> new file mode 100644
> index 0000000000000..cc6a25a7962e6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/torture/attr-sym-4.C
> @@ -0,0 +1,28 @@
> +/* { dg-do compile } */
> +/* { dg-require-alias "" } */
> +
> +template <typename T = void>
> +class
> +__attribute__ ((__sym__ ("FOOCLS")))
> +foo // { dg-error "duplicate|already" }
> +{
> +  virtual ~foo() {}
> +
> +  template <typename U>
> +  void
> +    __attribute__ ((__sym__ ("FOOTMF")))
> +    tmemfun () {} // { dg-error "duplicate|already" }
> +};
> +
> +template <typename T>
> +void
> +__attribute__ ((__sym__ ("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/testsuite/g++.dg/torture/attr-sym-5.C 
> b/gcc/testsuite/g++.dg/torture/attr-sym-5.C
> new file mode 100644
> index 0000000000000..2f79408b8d8ec
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/torture/attr-sym-5.C
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target c++11 } } */
> +/* { dg-require-alias "" } */
> +
> +struct foo {
> +  __attribute__ ((__sym__ ("FOOCTR_A"))) foo ();
> +  virtual __attribute__ ((__sym__ ("FOODTR_A"))) ~foo() {}
> +};
> +
> +foo::foo () {}
> +
> +// Make sure the inherited cdtors don't duplicate the syms.
> +struct bar : foo {
> +  using foo::foo;
> +};
> diff --git a/gcc/varpool.cc b/gcc/varpool.cc
> index e7b51b15e4a84..33649906d1d11 100644
> --- a/gcc/varpool.cc
> +++ b/gcc/varpool.cc
> @@ -163,6 +163,9 @@ varpool_node::get_create (tree decl)
>      }
>
>    node->register_symbol ();
> +
> +  create_sym_alias_decls (decl);
> +
>    return node;
>  }
>
>
>
> --
> Alexandre Oliva, happy hacker                https://FSFLA.org/blogs/lxo/
>    Free Software Activist                       GNU Toolchain Engineer
> Disinformation flourishes because many people care deeply about injustice
> but very few check the facts.  Ask me about <https://stallmansupport.org>

Reply via email to