> On Nov 30, 2023, Jan Hubicka <hubi...@ucw.cz> wrote: > > >> + if (VAR_P (replaced)) > >> + varpool_node::create_alias (sym_node->decl, replacement); > >> + else > >> + cgraph_node::create_alias (sym_node->decl, replacement); > > Unfortunately, this change didn't work. Several of the C++ tests > regressed with it. Going back to same-body aliases, they work. > > I suspect this may have to do with the infrastructure put in to deal > with cdtors clones.
Do you have short testcase for this? THe main oddities with same body aliases comes from the fact that C++ FE creates them early during parsing before all declaration flags are finished. Later we do: /* Ugly, but the fixup cannot happen at a time same body alias is created; 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) node->fixup_same_cpp_alias_visibility (node->get_alias_target ()); Fixup copies some flags such as inline flags, visibility and comdat groups which can change during parsing process. Since you produce aliases late at finalization time, I do not see how this could be relevant. Pehraps unless you manage to copy wrong flags from implicit aliases before the fixup happens which would be simple ordering problem.... Honza > > I've also found some discrepancies between C and C++ WRT sym_alias in > static local variables, and failure to detect and report symbol name > clashes between sym_aliases and unrelated declarations. Thanks, Joseph, > for pushing me to consider other cases I hadn't thought of before :-) > I'm going to look into these, but for now, the patch below gets a full > pass, with these issues XFAILed. > > > > The IPA bits are fine. I will take a look on your second patch. > > Thanks! > > > Introduce attribute sym_alias > > 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. > > 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_alias): Document for variables, > functions and types. > > for gcc/ada/ChangeLog > > * doc/gnat_rm/interfacing_to_other_languages.rst: Mention > attribute sym_alias 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_alias_attribute): New. > (c_common_attribute_table): Add sym_alias. > (handle_copy_attribute): Do not copy sym_alias 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_alias 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-alias-1.c: New. > * c-c++-common/torture/attr-sym-alias-2.c: New. > * c-c++-common/torture/attr-sym-alias-3.c: New. > * c-c++-common/torture/attr-sym-alias-4.c: New. > * c-c++-common/torture/attr-sym-alias-5.c: New. > * c-c++-common/attr-sym-alias-neg.c: New. > * g++.dg/torture/attr-sym-alias-1.C: New. > * g++.dg/torture/attr-sym-alias-2.C: New. > * g++.dg/torture/attr-sym-alias-3.C: New. > * g++.dg/torture/attr-sym-alias-4.C: New. > * g++.dg/torture/attr-sym-alias-5.C: New. > --- > .../doc/gnat_rm/interfacing_to_other_languages.rst | 6 + > .../doc/gnat_ugn/the_gnat_compilation_model.rst | 10 ++ > gcc/attribs.cc | 66 ++++++++++++++++ > 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 | 56 +++++++++++++ > gcc/symtab.cc | 38 +++++++++ > gcc/testsuite/c-c++-common/attr-sym-alias-neg.c | 80 +++++++++++++++++++ > gcc/testsuite/c-c++-common/goacc/declare-1.c | 6 + > gcc/testsuite/c-c++-common/goacc/declare-2.c | 14 ++- > .../c-c++-common/torture/attr-sym-alias-1.c | 39 +++++++++ > .../c-c++-common/torture/attr-sym-alias-2.c | 13 +++ > .../c-c++-common/torture/attr-sym-alias-3.c | 41 ++++++++++ > .../c-c++-common/torture/attr-sym-alias-4.c | 28 +++++++ > .../c-c++-common/torture/attr-sym-alias-5.c | 54 +++++++++++++ > gcc/testsuite/g++.dg/torture/attr-sym-alias-1.C | 72 +++++++++++++++++ > gcc/testsuite/g++.dg/torture/attr-sym-alias-2.C | 26 ++++++ > gcc/testsuite/g++.dg/torture/attr-sym-alias-3.C | 83 > ++++++++++++++++++++ > gcc/testsuite/g++.dg/torture/attr-sym-alias-4.C | 28 +++++++ > gcc/testsuite/g++.dg/torture/attr-sym-alias-5.C | 14 +++ > gcc/varpool.cc | 3 + > 33 files changed, 922 insertions(+), 19 deletions(-) > create mode 100644 gcc/testsuite/c-c++-common/attr-sym-alias-neg.c > create mode 100644 gcc/testsuite/c-c++-common/torture/attr-sym-alias-1.c > create mode 100644 gcc/testsuite/c-c++-common/torture/attr-sym-alias-2.c > create mode 100644 gcc/testsuite/c-c++-common/torture/attr-sym-alias-3.c > create mode 100644 gcc/testsuite/c-c++-common/torture/attr-sym-alias-4.c > create mode 100644 gcc/testsuite/c-c++-common/torture/attr-sym-alias-5.c > create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-alias-1.C > create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-alias-2.C > create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-alias-3.C > create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-alias-4.C > create mode 100644 gcc/testsuite/g++.dg/torture/attr-sym-alias-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..b8de16ebf7c0c 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_alias`` 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 fd15459203a5c..2004569896268 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_alias__ ("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_alias__ ("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 c7209c26acc9f..c75ca6974cb71 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" > @@ -825,7 +826,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_alias", name)) > { > warning (OPT_Wattributes, "type attributes ignored after type is > already defined"); > continue; > @@ -2640,6 +2642,68 @@ 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_alias"; > + > + 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); > + varpool_node::create_alias (clone, decl); > + else > + cgraph_node::create_same_body_alias (clone, decl); > + // cgraph_node::create_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..156f2c2058800 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_alias", (attrs)); \ > + sym; sym = lookup_attribute ("sym_alias", 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 2b20e58c922c8..392437eab3b7d 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_alias_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, > @@ -388,6 +389,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_alias", 1, 1, false, false, false, false, > + handle_sym_alias_attribute, NULL }, > { "no_instrument_function", 0, 0, true, false, false, false, > handle_no_instrument_function_attribute, > NULL }, > @@ -3002,7 +3005,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 > @@ -3012,7 +3015,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 > @@ -3022,6 +3025,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_alias" attribute; arguments as in struct > + attribute_spec.handler. */ > + > +static tree > +handle_sym_alias_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. */ > > @@ -3155,6 +3181,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_alias", atname) > || is_attribute_p ("target_clones", atname)) > continue; > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc > index cf1df82c0f405..e5a1ee54cb3ee 100644 > --- a/gcc/c/c-decl.cc > +++ b/gcc/c/c-decl.cc > @@ -3119,6 +3119,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 f93259a8c70c4..0bef2179e89c4 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 cfdd9f693a889..cb5ac01f7e290 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 6fdb56abfb9f8..fa8fc63db82a5 100644 > --- a/gcc/cp/class.cc > +++ b/gcc/cp/class.cc > @@ -4896,6 +4896,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_alias", 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. */ > @@ -5065,6 +5127,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 964af1ddd85c5..2bafed4e9939b 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -5787,6 +5787,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. */ > @@ -7022,6 +7024,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); > @@ -7596,6 +7599,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 2f2dbb8d10723..5636d694b6894 100644 > --- a/gcc/cp/decl.cc > +++ b/gcc/cp/decl.cc > @@ -3237,6 +3237,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. > @@ -3260,6 +3262,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); > } > } > @@ -10789,6 +10792,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 9e666e5eecee0..c7f009beaf08e 100644 > --- a/gcc/cp/decl2.cc > +++ b/gcc/cp/decl2.cc > @@ -1844,6 +1844,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)) > @@ -2200,6 +2203,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. */ > > @@ -3007,6 +3051,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 > @@ -3269,6 +3315,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 > @@ -3503,6 +3551,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 d19ea5d121c8d..f877780b2acae 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" > @@ -3479,6 +3481,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_alias", 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 e6de0815846a6..5dcdec76c1ebc 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -4141,6 +4141,43 @@ Function Attributes}, @ref{PowerPC Function > Attributes}, > @ref{Nios II Function Attributes}, and @ref{S/390 Function Attributes} > for details. > > +@cindex @code{sym_alias} function attribute > +@item sym_alias ("@var{name}") > +The @code{sym_alias} attribute causes @var{name} to be output as an > +alias to the function, with the same linkage and visibility as the > +function, when the function definition is output, provided that the > +function could be an alias target. For instance, > + > +@smallexample > +void f (uint64_t) __attribute__ ((__sym_alias__ ("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}, > +with the same linkage and visibility. 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. > + > +Aliases introduced with this attribute, such as @samp{f_u64} in the > +example above, are assembly symbol names: they do not undergo C++ name > +mangling, and are not made visible in any scope in the source language. > +They can, however, can be named as alias targets. > + > +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 > @@ -8069,6 +8106,10 @@ will be placed in new, unique sections. > > This additional functionality requires Binutils version 2.36 or later. > > +@cindex @code{sym_alias} variable attribute > +@item sym_alias ("@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 > @@ -9164,6 +9205,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_alias} type attribute > +@item sym_alias ("@var{name}") > +The @code{sym_alias} 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_alias__ ("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..43ba88d793925 100644 > --- a/gcc/symtab.cc > +++ b/gcc/symtab.cc > @@ -1943,6 +1943,44 @@ 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); > + varpool_node::create_alias (sym_node->decl, replacement); > + else > + cgraph_node::create_same_body_alias (sym_node->decl, replacement); > + // cgraph_node::create_alias (sym_node->decl, replacement); > + } > +} > + > /* If node cannot be overwriten by static or dynamic linker to point to > different definition, return NODE. Otherwise look for alias with such > property and if none exists, introduce new one. */ > diff --git a/gcc/testsuite/c-c++-common/attr-sym-alias-neg.c > b/gcc/testsuite/c-c++-common/attr-sym-alias-neg.c > new file mode 100644 > index 0000000000000..f64e5bb1ac44b > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/attr-sym-alias-neg.c > @@ -0,0 +1,80 @@ > +/* { dg-do compile } */ > +/* { dg-require-alias "" } */ > + > +int f () { > + int i __attribute__ ((sym_alias ("f_i"))); /* { dg-warning "ignored" } */ > + /* ??? X cannot be an alias target; should this be flagged? ... */ > + static int x __attribute__ ((sym_alias ("f_x"))); > + static int sx __attribute__ ((alias ("f_x"))); /* { dg-warning "ignored" } > */ > + extern int xx __attribute__ ((alias ("f_x"))); /* { dg-warning "ignored" } > */ > + return i; > +} > + > +/* ??? ... or should XR be accepted? */ > +extern int xr __attribute__ ((alias ("f_x"))); /* { dg-error "undefined" "" > { xfail c++ } } */ > +int dr __attribute__ ((alias ("f_x"))); /* { dg-error "defined both" } */ > + > + > +struct s { > + int j __attribute__ ((sym_alias ("s_j"))); /* { dg-warning "ignored" } */ > +}; > + > + > +int j __attribute__ ((sym_alias ("J_var"))); > +void __attribute__ ((alias ("J_var"))) > +j_fn (); /* { dg-error "between function and variable" } */ > + > + > +void __attribute__ ((sym_alias ("K_fn"))) > +k () { > +} > +extern int __attribute__ ((alias ("K_fn"))) > +k_var; /* { dg-error "between function and variable" } */ > + > + > +int l __attribute__ ((sym_alias ("L_fn"))); > + > +/* These should be detected and reported, not because the names clash at the > + source level, but because the asm symbols do. */ > +#ifdef __cplusplus > +extern "C" > +#endif > +void > +L_fn () /* { dg-error "duplicate" "" { xfail *-*-* } } */ > +{ > +} > + > + > +#ifdef __cplusplus > +extern "C" > +#endif > +void __attribute__ ((sym_alias ("M_var"))) > +m () > +{ > +} > + > +int M_var; /* { dg-error "duplicate" "" { xfail *-*-* } } */ > + > + > +#ifdef __cplusplus > +extern "C" > +#endif > +void __attribute__ ((sym_alias ("N_sym"))) > +n_fn () > +{ > +} > + > +int __attribute__ ((sym_alias ("N_sym"))) > +n_var; /* { dg-error "duplicate" } */ > + > + > +int __attribute__ ((sym_alias ("O_sym"))) > +o_var; > + > +#ifdef __cplusplus > +extern "C" > +#endif > +void __attribute__ ((sym_alias ("O_sym"))) > +o_fn () /* { dg-error "duplicate" } */ > +{ > +} > 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-alias-1.c > b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-1.c > new file mode 100644 > index 0000000000000..61af50cb5527f > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-1.c > @@ -0,0 +1,39 @@ > +/* { dg-do compile } */ > +/* { dg-require-alias "" } */ > + > +extern int var_a __attribute__ ((__sym_alias__ ("FOOVAR_A"))); > +int var_a = 1; > + > +void foo_a () __attribute__ ((__sym_alias__ ("FOOBAR_A"))); > + > +void > +foo_a () > +{ > +} > + > + > +int var_b; > +extern int var_b __attribute__ ((__sym_alias__ ("FOOVAR_B"))); > + > +void > +foo_b () > +{ > +} > + > +void foo_b () __attribute__ ((__sym_alias__ ("FOOBAR_B"))); > + > + > +int var_c __attribute__ ((__sym_alias__ ("FOOVAR_C"))); > + > +void __attribute__ ((__sym_alias__ ("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-alias-2.c > b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-2.c > new file mode 100644 > index 0000000000000..6f0d55ca42cc8 > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-2.c > @@ -0,0 +1,13 @@ > +/* { dg-do compile } */ > +/* { dg-require-alias "" } */ > + > +struct s > +{ > + int mem __attribute__ ((__sym_alias__ ("MEMFOO"))); /* { dg-warning > "attribute ignored" } */ > +}; > + > +void foo() > +{ > + extern void bar () __attribute__ ((__sym_alias__ ("FOOBAR"))); > + int var __attribute__ ((__sym_alias__ ("FOOVAR"))); /* { dg-warning > "attribute ignored" } */ > +} > diff --git a/gcc/testsuite/c-c++-common/torture/attr-sym-alias-3.c > b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-3.c > new file mode 100644 > index 0000000000000..0052485a30afb > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-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_alias__ ("FOOVAR_A"))); > + void foo_a () __attribute__ ((__sym_alias__ ("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_alias__ ("FOOVAR_B"))); > +} > + > +int var_b; > + > +void __attribute__ ((__sym_alias__ ("FOOBAR_C"))) > +foo_c () > +{ > + void foo_b () __attribute__ ((__sym_alias__ ("FOOBAR_B"))); > + /* Another sym for var_b. */ > + extern int var_b __attribute__ ((__sym_alias__ ("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-alias-4.c > b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-4.c > new file mode 100644 > index 0000000000000..2beafa4637923 > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-4.c > @@ -0,0 +1,28 @@ > +/* { dg-do run } */ > +/* { dg-require-alias "" } */ > + > +int var_a __attribute__ ((__sym_alias__ ("FOOVAR_A"))) = 42; > + > +int __attribute__ ((__sym_alias__ ("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/c-c++-common/torture/attr-sym-alias-5.c > b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-5.c > new file mode 100644 > index 0000000000000..bee90136dafd5 > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/torture/attr-sym-alias-5.c > @@ -0,0 +1,54 @@ > +/* { dg-do compile } */ > +/* { dg-require-alias "" } */ > +/* { dg-require-visibility "" } */ > + > +int __attribute__ ((sym_alias ("A_hid"), visibility ("hidden"))) a; > + > +extern int __attribute__ ((sym_alias ("B_prt"))) b; > + > +int b __attribute__ ((visibility ("protected"))); > + > +extern int __attribute__ ((sym_alias ("C_ntr"))) c; > + > +extern int c __attribute__ ((visibility ("internal"))); > + > +int c; > + > +static int d __attribute__ ((sym_alias ("D_stt"))); > + > + > +extern void __attribute__ ((sym_alias ("F_hid"), visibility ("hidden"))) > +f (); > + > +void > +f () { > +} > + > +extern void __attribute__ ((sym_alias ("G_prt"))) > +g (); > + > +void __attribute__ ((visibility ("protected"))) > +g () { > +} > + > +extern void __attribute__ ((sym_alias ("H_ntr"))) > +h (); > + > +void __attribute__ ((visibility ("internal"))) > +h (); > + > +void h () { > +} > + > +static void __attribute__ ((sym_alias ("I_stt"))) > +i () { > +} > + > +/* { dg-final { scan-assembler {hidden[^\n]*A_hid} } } */ > +/* { dg-final { scan-assembler {protected[^\n]*B_prt} } } */ > +/* { dg-final { scan-assembler {internal[^\n]*C_ntr} } } */ > +/* { dg-final { scan-assembler-not {glob[^\n]*D_stt} } } */ > +/* { dg-final { scan-assembler {hidden[^\n]*F_hid} } } */ > +/* { dg-final { scan-assembler {protected[^\n]*G_prt} } } */ > +/* { dg-final { scan-assembler {internal[^\n]*H_ntr} } } */ > +/* { dg-final { scan-assembler-not {glob[^\n]*I_stt} } } */ > diff --git a/gcc/testsuite/g++.dg/torture/attr-sym-alias-1.C > b/gcc/testsuite/g++.dg/torture/attr-sym-alias-1.C > new file mode 100644 > index 0000000000000..579eda1a473f6 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/torture/attr-sym-alias-1.C > @@ -0,0 +1,72 @@ > +/* { dg-do compile } */ > +/* { dg-require-alias "" } */ > + > +class __attribute__ ((__sym_alias__ ("FOOCLS_A"), > + __sym_alias__ ("FOOCLS_A_Dupe"))) foo { > + static int var __attribute__ ((__sym_alias__ ("FOOVAR_A"))); > + __attribute__ ((__sym_alias__ ("FOOCTR_A"))) foo (); > + void __attribute__ ((__sym_alias__ ("FOOBAR_A"))) bar (); > + virtual __attribute__ ((__sym_alias__ ("FOODTR_A"))) ~foo() {} > +}; > + > +int foo::var = 1; > + > +foo::foo () {} > + > +void foo::bar () {} > + > +namespace b { > + class __attribute__ ((__sym_alias__ ("FOOCLS_B"))) foo { > + static int var __attribute__ ((__sym_alias__ ("FOOVAR_B"))); > + __attribute__ ((__sym_alias__ ("FOOCTR_B"))) foo (); > + void __attribute__ ((__sym_alias__ ("FOOBAR_B"))) bar () {} > + virtual __attribute__ ((__sym_alias__ ("FOODTR_B"))) ~foo() {} > + }; > + > + int foo::var = 2; > + > + foo::foo () { > + void (foo::*pbar)() = &foo::bar; > + } > +} > + > +namespace c { > + namespace cd { > + class __attribute__ ((__sym_alias__ ("FOOCLS_C"))) foo { > + static int var __attribute__ ((__sym_alias__ ("FOOVAR_C"))); > + __attribute__ ((__sym_alias__ ("FOOCTR_C"))) foo () { > + void (foo::*pbar)() = &foo::bar; > + } > + void __attribute__ ((__sym_alias__ ("FOOBAR_C"))) bar () {} > + virtual __attribute__ ((__sym_alias__ ("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-alias-2.C > b/gcc/testsuite/g++.dg/torture/attr-sym-alias-2.C > new file mode 100644 > index 0000000000000..6facfcc2cd9a9 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/torture/attr-sym-alias-2.C > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-require-alias "" } */ > + > +namespace { > + class __attribute__ ((__sym_alias__ ("FOOCLS_A"))) foo { > + static int var __attribute__ ((__sym_alias__ ("FOOVAR_A"))); > + __attribute__ ((__sym_alias__ ("FOOCTR_A"))) foo (); > + virtual __attribute__ ((__sym_alias__ ("FOODTR_A"))) ~foo (); > + void __attribute__ ((__sym_alias__ ("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-alias-3.C > b/gcc/testsuite/g++.dg/torture/attr-sym-alias-3.C > new file mode 100644 > index 0000000000000..42c7288ad4ad2 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/torture/attr-sym-alias-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_alias__ ("FOOFUN_UINT"))) fn<>(unsigned > int); > +template void __attribute__ ((__sym_alias__ ("FOOFUN_LONG"))) fn<>(long); > + > +template<> void __attribute__ ((__sym_alias__ ("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_alias__ ("FOOCLS_CHAR_VIRT"))) foo<char>::virtfun(); > + > +template class __attribute__ ((__sym_alias__ ("FOOCLS_CHAR_TI"))) foo<char>; > + > +// Though they're only output if the enclosing class is. > +template void > +__attribute__ ((__sym_alias__ ("FOOCLS_LONG_VIRT"))) foo<long>::virtfun(); > +extern > +template class __attribute__ ((__sym_alias__ ("FOOCLS_LONG_TI_X"))) > foo<long>; > + > + > +template void > +__attribute__ ((__sym_alias__ ("FOOCLS_VOID_ST"))) foo<void>::stfun(); > + > +template class __attribute__ ((__sym_alias__ ("FOOCLS_VOID_TI"))) foo<>; > + > + > +extern > +template class __attribute__ ((__sym_alias__ ("FOOCLS_SHORT_TI_X"))) > foo<short>; > + > +template void > +__attribute__ ((__sym_alias__ ("FOOCLS_SHORT_ST"))) foo<short>::stfun(); > +template void > +__attribute__ ((__sym_alias__ ("FOOCLS_SHORT_INL"))) foo<short>::inlfun(); > + > +template class __attribute__ ((__sym_alias__ ("FOOCLS_SHORT_TI_D"))) > foo<short>; > + > +// Explicit specializations work too. > + > +template <> > +struct __attribute__ ((__sym_alias__ ("FOOCLS_INT_TI"))) > +foo<int> > +{ > + virtual ~foo() {} > + virtual void __attribute__ ((__sym_alias__ ("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-alias-4.C > b/gcc/testsuite/g++.dg/torture/attr-sym-alias-4.C > new file mode 100644 > index 0000000000000..59b779de35d80 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/torture/attr-sym-alias-4.C > @@ -0,0 +1,28 @@ > +/* { dg-do compile } */ > +/* { dg-require-alias "" } */ > + > +template <typename T = void> > +class > +__attribute__ ((__sym_alias__ ("FOOCLS"))) > +foo // { dg-error "duplicate|already" } > +{ > + virtual ~foo() {} > + > + template <typename U> > + void > + __attribute__ ((__sym_alias__ ("FOOTMF"))) > + tmemfun () {} // { dg-error "duplicate|already" } > +}; > + > +template <typename T> > +void > +__attribute__ ((__sym_alias__ ("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-alias-5.C > b/gcc/testsuite/g++.dg/torture/attr-sym-alias-5.C > new file mode 100644 > index 0000000000000..45d59b953c325 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/torture/attr-sym-alias-5.C > @@ -0,0 +1,14 @@ > +/* { dg-do compile { target c++11 } } */ > +/* { dg-require-alias "" } */ > + > +struct foo { > + __attribute__ ((__sym_alias__ ("FOOCTR_A"))) foo (); > + virtual __attribute__ ((__sym_alias__ ("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 > More tolerance and less prejudice are key for inclusion and diversity > Excluding neuro-others for not behaving ""normal"" is *not* inclusive