From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from rock.gnat.com (rock.gnat.com [IPv6:2620:20:4000:0:a9e:1ff:fe9b:1d1]) by sourceware.org (Postfix) with ESMTP id 5DE1B388A83C for ; Fri, 7 Aug 2020 17:39:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 5DE1B388A83C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=oliva@adacore.com Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 0A3E511700D; Fri, 7 Aug 2020 13:39:11 -0400 (EDT) X-Virus-Scanned: Debian amavisd-new at gnat.com Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id UN2LAsHk4tGy; Fri, 7 Aug 2020 13:39:10 -0400 (EDT) Received: from free.home (tron.gnat.com [IPv6:2620:20:4000:0:46a8:42ff:fe0e:e294]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by rock.gnat.com (Postfix) with ESMTPS id 01E7D116FEC; Fri, 7 Aug 2020 13:39:09 -0400 (EDT) Received: from livre.home (livre.home [172.31.160.2]) by free.home (8.15.2/8.15.2) with ESMTPS id 077HctNT147859 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 7 Aug 2020 14:38:57 -0300 From: Alexandre Oliva To: gcc-patches@gcc.gnu.org Cc: jason@redhat.com, nathan@acm.org, joseph@codesourcery.com, hainque@adacore.com, ebotcazou@adacore.com Subject: [PATCH] introduce attribute exalias Organization: Free thinker, does not speak for AdaCore References: Errors-To: aoliva@lxoliva.fsfla.org Date: Fri, 07 Aug 2020 14:38:55 -0300 In-Reply-To: (Alexandre Oliva's message of "Wed, 29 Jul 2020 17:56:00 -0300") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Scanned-By: MIMEDefang 2.84 X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 07 Aug 2020 17:39:15 -0000 Since last week's patchlet, I've delayed the creation of the exalias decls, improved the merging of attributes, minimizing interface/visibility updates, found a better way to assign exaliases to nested explicit instantiations, even after enabling aliases to already-defined types, so now I'm reasonably happy with the patch. This patch introduces an attribute to add extra aliases to a symbol when its definition is output. The main goal is to ease interfacing C++ with Ada, as C++ mangled names have to be named, and in some cases (e.g. when using stdint.h typedefs in function arguments) the symbol names may vary across platforms. The attribute is usable in C and C++, presumably in all C-family languages. It can be attached to global variables and functions. In C++, it can also be attached to namespace-scoped variables and functions, static data members, member functions, explicit instantiations and specializations of template functions, members and classes. When applied to constructors or destructor, additional exaliases with _Base and _Del suffixes are defined for variants other than complete-object ones. Applying the attribute to class types is only valid in C++, and the effect is to attach the alias to the RTTI object associated with the class type. While working on this, I noticed C++ didn't merge attributes of extern local declarations with those of the namespace-scoped declaration. I've added code to merge the attributes if there is a namespace-scoped declaration, but if there isn't one, there won't be any merging, and the effects are noticeable, as in the added attr-weak-1.C. I'm also slightly concerned that an earlier local decl would go out of sync if a subsequent local decl, say within the same or even in another function, introduces additional attributes in the global decl. Regstrapped on x86_64-linux-gnu. Ok to install? (The newly-introduced attr-weak-1.c passes in C, but is marked as XFAIL for C++, so it gets an XPASS in C; I could move it to some C++-only subtree, or drop it altogether and file a PR instead) for gcc/ChangeLog * attribs.c: Include cgraph.h. (decl_attributes): Allow late introduction of exalias in types. (create_exalias_decl, create_exalias_decls): New. * attribs.h: Declare them. (FOR_EACH_EXALIAS): New macro. * cgraph.c (cgraph_node::create): Create exalias decls. * varpool.c (varpool_node::get_create): Create exalias decls. * cgraph.h (symtab_node::remap_exalias_target): New. * symtab.c (symtab_node::remap_exalias_target): Define. * cgraphunit.c (cgraph_node::analyze): Create alias_target node if needed. (analyze_functions): Fixup visibility of implicit alias only after its node is analyzed. * doc/extend.texi (exalias): Document for variables, functions and types. for gcc/ada/ChangeLog * doc/gnat_rm/interfacing_to_other_languages.rst: Mention attribute exalias to give RTTI symbols mnemonic names. * doc/gnat_ugn/the_gnat_compilation_model.rst: Mention attribute exalias. Fix incorrect ref to C1 ctor variant. for gcc/c-family/ChangeLog * c-ada-spec.c (pp_asm_name): Use first exalias if available. * c-attribs.c (handle_exalias_attribute): New. (c_common_attribute_table): Add exalias. (handle_copy_attribute): Do not copy exalias. * c-decl.c (duplicate_decls): Remap exalias target. for gcc/cp/ChangeLog * class.c (copy_fndecl_with_name): Move/adjust exalias to cdtor variants. (build_cdtor_clones): Drop exalias from primary variant. * cp-tree.h (update_exalias_interface, update_tinfo_exalias): Declare. * decl.c (duplicate_decls): Remap exalias target. (grokfndecl): Tentatively create exalias decls after adding attributes in e.g. a template member function explicit instantiation. * decl2.c (cplus_decl_attributes): Update tinfo exalias. (copy_interface, update_exalias_interface): New. (determine_visibility): Update exalias interface. (tentative_decl_linkage, import_export_decl): Likewise. * name-lookup.c: Include target.h and cgraph.h. (set_local_extern_decl_linkage): Merge attributes with a namespace-scoped decl if one is found. Remap exalias targets, and drop exaliases from the local decl. * optimize.c (maybe_clone_body): Only copy attributes if they haven't been copied yet. Update exalias interface. * rtti.c: Include attribs.h and cgraph.h. (get_tinfo_decl): Copy exalias attributes from type to tinfo decl. Create exalias decls. (update_tinfo_exalias): New. for gcc/testsuite/ChangeLog * c-c++-common/attr-weak-1.c: New, xfailed. * c-c++-common/torture/attr-exalias-1.c: New. * c-c++-common/torture/attr-exalias-2.c: New. * c-c++-common/torture/attr-exalias-3.c: New. * c-c++-common/torture/attr-exalias-4.c: New. * g++.dg/torture/attr-exalias-1.C: New. * g++.dg/torture/attr-exalias-2.C: New. * g++.dg/torture/attr-exalias-3.C: New. * g++.dg/torture/attr-exalias-4.C: New. --- .../doc/gnat_rm/interfacing_to_other_languages.rst | 6 + .../doc/gnat_ugn/the_gnat_compilation_model.rst | 20 +++-- gcc/attribs.c | 66 ++++++++++++++++ gcc/attribs.h | 7 ++ gcc/c-family/c-ada-spec.c | 7 ++ gcc/c-family/c-attribs.c | 33 +++++++- gcc/c/c-decl.c | 2 gcc/cgraph.c | 3 + gcc/cgraph.h | 4 + gcc/cgraphunit.c | 2 gcc/cp/class.c | 55 +++++++++++++ gcc/cp/cp-tree.h | 2 gcc/cp/decl.c | 3 + gcc/cp/decl2.c | 49 ++++++++++++ gcc/cp/name-lookup.c | 8 ++ gcc/cp/optimize.c | 7 +- gcc/cp/rtti.c | 66 ++++++++++++++++ gcc/doc/extend.texi | 52 +++++++++++++ gcc/symtab.c | 36 +++++++++ gcc/testsuite/c-c++-common/attr-weak-1.c | 19 +++++ .../c-c++-common/torture/attr-exalias-1.c | 39 +++++++++ .../c-c++-common/torture/attr-exalias-2.c | 13 +++ .../c-c++-common/torture/attr-exalias-3.c | 41 ++++++++++ .../c-c++-common/torture/attr-exalias-4.c | 28 +++++++ gcc/testsuite/g++.dg/torture/attr-exalias-1.C | 70 +++++++++++++++++ gcc/testsuite/g++.dg/torture/attr-exalias-2.C | 26 ++++++ gcc/testsuite/g++.dg/torture/attr-exalias-3.C | 83 ++++++++++++++++++++ gcc/testsuite/g++.dg/torture/attr-exalias-4.C | 28 +++++++ gcc/varpool.c | 3 + 29 files changed, 764 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/attr-weak-1.c create mode 100644 gcc/testsuite/c-c++-common/torture/attr-exalias-1.c create mode 100644 gcc/testsuite/c-c++-common/torture/attr-exalias-2.c create mode 100644 gcc/testsuite/c-c++-common/torture/attr-exalias-3.c create mode 100644 gcc/testsuite/c-c++-common/torture/attr-exalias-4.c create mode 100644 gcc/testsuite/g++.dg/torture/attr-exalias-1.C create mode 100644 gcc/testsuite/g++.dg/torture/attr-exalias-2.C create mode 100644 gcc/testsuite/g++.dg/torture/attr-exalias-3.C create mode 100644 gcc/testsuite/g++.dg/torture/attr-exalias-4.C diff --git a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst index ad0be51..ce6a4da 100644 --- a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst +++ b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst @@ -123,6 +123,12 @@ It is also possible to import a C++ exception using the following syntax: The ``External_Name`` is the name of the C++ RTTI symbol. You can then cover a specific C++ exception in an exception handler. +RTTI symbols undergo C++ name mangling, which can make for identifiers +that are inconvenient to use. An alias with a mnemonic name can be +introduced by adding attribute ``exalias`` to the class that the RTTI +symbol refers to. + + .. _Interfacing_to_COBOL: Interfacing to COBOL diff --git a/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst b/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst index b8729d0..2a13a24 100644 --- a/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst +++ b/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst @@ -4279,6 +4279,7 @@ and two public primitives to set and get the value of this attribute. public: virtual void Set_Age (int New_Age); virtual int Age (); + __attribute__ ((__exalias__ ("Ctor_For_Animal"))) // extra alias Animal() {Age_Count = 0;}; private: int Age_Count; @@ -4311,6 +4312,7 @@ both Carnivore and Domestic, that is: virtual int Number_Of_Teeth (); virtual void Set_Owner (char* Name); + __attribute__ ((__exalias__ ("Ctor_For_Dog"))) // mnemonic alias Dog(); // Constructor private: int Tooth_Count; @@ -4349,7 +4351,8 @@ how to import these C++ declarations from the Ada side: function New_Animal return Animal; pragma CPP_Constructor (New_Animal); - pragma Import (CPP, New_Animal, "_ZN6AnimalC1Ev"); + pragma Import (CPP, New_Animal, + "_ZN6AnimalC1Ev"); -- or "Ctor_For_Animal" type Dog is new Animal and Carnivore and Domestic with record Tooth_Count : Natural; @@ -4365,7 +4368,7 @@ how to import these C++ declarations from the Ada side: function New_Dog return Dog; pragma CPP_Constructor (New_Dog); - pragma Import (CPP, New_Dog, "_ZN3DogC2Ev"); + pragma Import (CPP, New_Dog, "Ctor_For_Dog"); -- or "_ZN3DogC1Ev" end Animals; Thanks to the compatibility between GNAT run-time structures and the C++ ABI, @@ -4382,12 +4385,13 @@ because the dispatch table associated with these tagged types will be built in the C++ side and therefore will not contain the predefined Ada primitives which Ada would otherwise expect. -As the reader can see there is no need to indicate the C++ mangled names -associated with each subprogram because it is assumed that all the calls to -these primitives will be dispatching calls. The only exception is the -constructor, which must be registered with the compiler by means of -``pragma CPP_Constructor`` and needs to provide its associated C++ -mangled name because the Ada compiler generates direct calls to it. +As the reader can see there is no need to indicate the C++ mangled +names (or extra aliases) associated with each subprogram because it is +assumed that all the calls to these primitives will be dispatching +calls. The only exception is the constructor, which must be registered +with the compiler by means of ``pragma CPP_Constructor`` and needs to +provide its associated C++ mangled name because the Ada compiler +generates direct calls to it. With the above packages we can now declare objects of type Dog on the Ada side and dispatch calls to the corresponding subprograms on the C++ side. We can diff --git a/gcc/attribs.c b/gcc/attribs.c index 71dae12..3768053 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "diagnostic-core.h" #include "attribs.h" +#include "cgraph.h" #include "stor-layout.h" #include "langhooks.h" #include "plugin.h" @@ -663,7 +664,8 @@ decl_attributes (tree *node, tree attributes, int flags, if (TYPE_P (*anode) && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) - && TYPE_SIZE (*anode) != NULL_TREE) + && TYPE_SIZE (*anode) != NULL_TREE + && !is_attribute_p ("exalias", name)) { warning (OPT_Wattributes, "type attributes ignored after type is already defined"); continue; @@ -2076,6 +2078,68 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree fntype) } } +/* Create an exalias for DECL with linkage name ID. */ + +tree +create_exalias_decl (tree decl, tree id) +{ + tree name = get_identifier ("exalias"); + + if (symtab_node *sym_node = symtab_node::get_for_asmname (id)) + { + if ((sym_node->analyzed + ? sym_node->get_alias_target ()->decl + : sym_node->alias_target) == decl) + return sym_node->decl; + + error_at (DECL_SOURCE_LOCATION (decl), + "duplicate symbol name %qE in %qE attribute of %qD", + id, name, decl); + inform (DECL_SOURCE_LOCATION (sym_node->decl), + "already used by %qD", sym_node->decl); + } + + tree clone = copy_node (decl); + DECL_ATTRIBUTES (clone) = remove_attribute ("exalias", + DECL_ATTRIBUTES (decl)); + SET_DECL_ASSEMBLER_NAME (clone, id); + TREE_USED (id) = 1; + TREE_USED (clone) = 1; + DECL_PRESERVE_P (clone) = 1; + DECL_EXTERNAL (clone) = 0; + TREE_STATIC (clone) = 1; + + if (VAR_P (clone)) + { + DECL_READ_P (clone) = 1; + varpool_node::create_extra_name_alias (clone, decl); + } + else + { + cgraph_node::create_same_body_alias (clone, decl); + } + + return clone; +} + +/* Create all exaliases requested in DECL's attributes. */ + +void +create_exalias_decls (tree decl) +{ + if (!decl_in_symtab_p (decl) + || !symtab_node::get (decl)) + return; + + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (decl)) + { + tree id = TREE_VALUE (TREE_VALUE (exalias)); + id = get_identifier (TREE_STRING_POINTER (id)); + + create_exalias_decl (decl, id); + } +} + #if CHECKING_P diff --git a/gcc/attribs.h b/gcc/attribs.h index dea0b6c..1ba56ca 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -248,4 +248,11 @@ typedef hash_map rdwr_map; extern void init_attr_rdwr_indices (rdwr_map *, tree); +extern tree create_exalias_decl (tree, tree); +extern void create_exalias_decls (tree); + +#define FOR_EACH_EXALIAS(exalias, attrs) \ + for (tree exalias = lookup_attribute ("exalias", (attrs)); exalias; \ + exalias = lookup_attribute ("exalias", TREE_CHAIN (exalias))) + #endif // GCC_ATTRIBS_H diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c index c75b173..127eca6 100644 --- a/gcc/c-family/c-ada-spec.c +++ b/gcc/c-family/c-ada-spec.c @@ -1434,6 +1434,13 @@ pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type, static void pp_asm_name (pretty_printer *buffer, tree t) { + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (t)) + { + tree id = TREE_VALUE (TREE_VALUE (exalias)); + pp_string (buffer, TREE_STRING_POINTER (id)); + return; + } + tree name = DECL_ASSEMBLER_NAME (t); char *ada_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (name) + 1), *s; const char *ident = IDENTIFIER_POINTER (name); diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 3721483..c00de3f 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -99,7 +99,8 @@ static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ; static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *); static tree handle_ifunc_attribute (tree *, tree, tree, int, bool *); static tree handle_alias_attribute (tree *, tree, tree, int, bool *); -static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ; +static tree handle_weakref_attribute (tree *, tree, tree, int, bool *); +static tree handle_exalias_attribute (tree *, tree, tree, int, bool *); static tree handle_visibility_attribute (tree *, tree, tree, int, bool *); static tree handle_tls_model_attribute (tree *, tree, tree, int, @@ -333,6 +334,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_alias_attribute, NULL }, { "weakref", 0, 1, true, false, false, false, handle_weakref_attribute, NULL }, + { "exalias", 1, 1, false, false, false, false, + handle_exalias_attribute, NULL }, { "no_instrument_function", 0, 0, true, false, false, false, handle_no_instrument_function_attribute, NULL }, @@ -2424,7 +2427,7 @@ handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args, return NULL_TREE; } -/* Handle an "alias" or "ifunc" attribute; arguments as in +/* Handle an "ifunc" attribute; arguments as in struct attribute_spec.handler. */ static tree @@ -2434,7 +2437,7 @@ handle_ifunc_attribute (tree *node, tree name, tree args, return handle_alias_ifunc_attribute (false, node, name, args, no_add_attrs); } -/* Handle an "alias" or "ifunc" attribute; arguments as in +/* Handle an "alias" attribute; arguments as in struct attribute_spec.handler. */ static tree @@ -2444,6 +2447,29 @@ handle_alias_attribute (tree *node, tree name, tree args, return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs); } +/* Handle an "exalias" attribute; arguments as in struct + attribute_spec.handler. */ + +static tree +handle_exalias_attribute (tree *pnode, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree node = *pnode; + + *no_add_attrs = true; + + if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) + error ("%qE attribute argument not a string", name); + else if (decl_in_symtab_p (node)) + *no_add_attrs = false; + else if (TYPE_P (node) && c_dialect_cxx ()) + *no_add_attrs = false; + else + return error_mark_node; + + return NULL_TREE; +} + /* Handle the "copy" attribute NAME by copying the set of attributes from the symbol referenced by ARGS to the declaration of *NODE. */ @@ -2571,6 +2597,7 @@ handle_copy_attribute (tree *node, tree name, tree args, tree atname = get_attribute_name (at); if (is_attribute_p ("alias", atname) || is_attribute_p ("always_inline", atname) + || is_attribute_p ("exalias", atname) || is_attribute_p ("gnu_inline", atname) || is_attribute_p ("ifunc", atname) || is_attribute_p ("noinline", atname) diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 5d6b504..79a3de1 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -2942,6 +2942,8 @@ duplicate_decls (tree newdecl, tree olddecl) merge_decls (newdecl, olddecl, newtype, oldtype); + symtab_node::remap_exalias_target (newdecl, olddecl); + /* The NEWDECL will no longer be needed. Before releasing the node, be sure to remove function from symbol diff --git a/gcc/cgraph.c b/gcc/cgraph.c index c0b4579..a0121a0 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -524,6 +524,9 @@ cgraph_node::create (tree decl) node->next_nested = node->origin->nested; node->origin->nested = node; } + + create_exalias_decls (decl); + return node; } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 0211f08..ab5bda5 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -319,6 +319,10 @@ public: /* Return node that alias is aliasing. */ inline symtab_node *get_alias_target (void); + /* Remap exalias nodes recorded as aliasing REPLACED to alias + REPLACEMENT instead. */ + static void remap_exalias_target (tree replaced, tree replacement); + /* Set section for symbol and its aliases. */ void set_section (const char *section); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 0b1009d..c96f720 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -1157,7 +1157,7 @@ analyze_functions (bool first_time) C++ FE is confused about the COMDAT groups being right. */ if (symtab->cpp_implicit_aliases_done) FOR_EACH_SYMBOL (node) - if (node->cpp_implicit_alias) + if (node->cpp_implicit_alias && node->analyzed) node->fixup_same_cpp_alias_visibility (node->get_alias_target ()); build_type_inheritance_graph (); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index b39bdaa..7e8f35f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4831,6 +4831,58 @@ copy_fndecl_with_name (tree fn, tree name, tree_code code, /* Create the RTL for this function. */ SET_DECL_RTL (clone, NULL); + + if (code == ERROR_MARK) + { + bool found = false; + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (clone)) + { + found = true; + break; + } + + if (found + && (name == complete_ctor_identifier + || name == complete_dtor_identifier)) + { + /* Reuse the exalias decls created for the primary cdtor decl. */ + symtab_node::remap_exalias_target (fn, clone); + } + else if (found) + { + const char *suf; + + if (name == base_ctor_identifier + || name == base_dtor_identifier) + suf = "_Base"; + else if (name == deleting_dtor_identifier) + suf = "_Del"; + else + gcc_unreachable (); + + size_t xlen = strlen (suf); + + DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (clone)); + + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (clone)) + { + TREE_VALUE (exalias) = copy_list (TREE_VALUE (exalias)); + /* Append suf to the exalias name. */ + tree str = TREE_VALUE (TREE_VALUE (exalias)); + char *symname = concat (TREE_STRING_POINTER (str), suf, NULL); + str = build_string (TREE_STRING_LENGTH (str) + xlen, symname); + TREE_VALUE (TREE_VALUE (exalias)) = str; + free (symname); + } + + if (symtab_node::get (clone)) + create_exalias_decls (clone); + } + } + else + DECL_ATTRIBUTES (clone) + = remove_attribute ("exalias", DECL_ATTRIBUTES (clone)); + rest_of_decl_compilation (clone, namespace_bindings_p (), at_eof); return clone; @@ -4928,6 +4980,9 @@ build_cdtor_clones (tree fn, bool needs_vtt_parm_p, bool omit_inherited_parms_p) count += 2; } + DECL_ATTRIBUTES (fn) + = remove_attribute ("exalias", DECL_ATTRIBUTES (fn)); + return count; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fc54e6b..9ff45e0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6601,6 +6601,7 @@ extern tree build_explicit_specifier (tree, tsubst_flags_t); extern void do_push_parm_decls (tree, tree, tree *); /* in decl2.c */ +extern void update_exalias_interface (tree); extern void record_mangling (tree, bool); extern void overwrite_mangling (tree, tree); extern void note_mangling_alias (tree, tree); @@ -7043,6 +7044,7 @@ extern tree build_dynamic_cast (location_t, tree, tree, tsubst_flags_t); extern void emit_support_tinfos (void); extern bool emit_tinfo_decl (tree); +extern void update_tinfo_exalias (tree); /* in search.c */ extern bool accessible_base_p (tree, tree, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index a68bbe0..c1afde1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2899,6 +2899,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) && TREE_STATIC (olddecl)))) make_decl_rtl (olddecl); + symtab_node::remap_exalias_target (newdecl, olddecl); + /* The NEWDECL will no longer be needed. Because every out-of-class declaration of a member results in a call to duplicate_decls, freeing these nodes represents in a significant savings. @@ -9823,6 +9825,7 @@ grokfndecl (tree ctype, { cplus_decl_attributes (&decl, *attrlist, 0); *attrlist = NULL_TREE; + create_exalias_decls (decl); } /* Check main's type after attributes have been applied. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 33c8377..d020e95 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1601,6 +1601,8 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) if (TREE_CODE (*decl) == TYPE_DECL) SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl)); + else if (TYPE_P (*decl) && attributes) + update_tinfo_exalias (*decl); /* Propagate deprecation out to the template. */ if (TREE_DEPRECATED (*decl)) @@ -1951,6 +1953,47 @@ adjust_var_decl_tls_model (tree decl) set_decl_tls_model (decl, decl_default_tls_model (decl)); } +/* Copy externalness and linkage from DECL to DEST. */ + +static void +copy_interface (tree dest, tree decl) +{ + TREE_PUBLIC (dest) = TREE_PUBLIC (decl); + TREE_STATIC (dest) = TREE_STATIC (decl); + DECL_COMMON (dest) = DECL_COMMON (decl); + DECL_COMDAT (dest) = DECL_COMDAT (decl); + DECL_WEAK (dest) = DECL_WEAK (decl); + DECL_EXTERNAL (dest) = DECL_EXTERNAL (decl); + if (DECL_LANG_SPECIFIC (dest) && DECL_LANG_SPECIFIC (decl)) + DECL_NOT_REALLY_EXTERN (dest) = DECL_NOT_REALLY_EXTERN (decl); + DECL_INTERFACE_KNOWN (dest) = DECL_INTERFACE_KNOWN (decl); + DECL_VISIBILITY (dest) = DECL_VISIBILITY (decl); + DECL_VISIBILITY_SPECIFIED (dest) = DECL_VISIBILITY_SPECIFIED (decl); +} + +/* Propagate linkage changes to exaliases. */ + +void +update_exalias_interface (tree decl) +{ + if (!decl_in_symtab_p (decl) + || !symtab_node::get (decl)) + return; + + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (decl)) + { + tree id = TREE_VALUE (TREE_VALUE (exalias)); + id = get_identifier (TREE_STRING_POINTER (id)); + symtab_node *sym_node = symtab_node::get_for_asmname (id); + + if (sym_node + && (sym_node->analyzed + ? sym_node->get_alias_target ()->decl + : sym_node->alias_target) == decl) + copy_interface (sym_node->decl, decl); + } +} + /* Set DECL up to have the closest approximation of "initialized common" linkage available. */ @@ -2747,6 +2790,8 @@ determine_visibility (tree decl) translation unit, we can make the type internal. */ constrain_visibility (decl, VISIBILITY_ANON, false); + update_exalias_interface (decl); + /* If visibility changed and DECL already has DECL_RTL, ensure symbol flags are updated. */ if ((DECL_VISIBILITY (decl) != orig_visibility @@ -3013,6 +3058,8 @@ tentative_decl_linkage (tree decl) else if (VAR_P (decl)) maybe_commonize_var (decl); } + + update_exalias_interface (decl); } /* DECL is a FUNCTION_DECL or VAR_DECL. If the object file linkage @@ -3247,6 +3294,8 @@ import_export_decl (tree decl) } DECL_INTERFACE_KNOWN (decl) = 1; + + update_exalias_interface (decl); } /* Return an expression that performs the destruction of DECL, which diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 9f30d90..26bdc25 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -22,9 +22,11 @@ along with GCC; see the file COPYING3. If not see #define INCLUDE_UNIQUE_PTR #include "system.h" #include "coretypes.h" +#include "target.h" #include "cp-tree.h" #include "timevar.h" #include "stringpool.h" +#include "cgraph.h" #include "print-tree.h" #include "attribs.h" #include "debug.h" @@ -2924,6 +2926,12 @@ set_local_extern_decl_linkage (tree decl, bool shadowed) different decl. */ TREE_PUBLIC (decl) = TREE_PUBLIC (*iter); + DECL_ATTRIBUTES (*iter) + = targetm.merge_decl_attributes (*iter, decl); + symtab_node::remap_exalias_target (decl, *iter); + DECL_ATTRIBUTES (decl) + = remove_attribute ("exalias", DECL_ATTRIBUTES (*iter)); + if (cp_function_chain->extern_decl_map == NULL) cp_function_chain->extern_decl_map = hash_table::create_ggc (20); diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index abdcd7f..62568d7 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -516,10 +516,15 @@ maybe_clone_body (tree fn) DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn); DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn); DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn); - DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn)); + /* We may have already copied them in copy_fndecl_with_name, + before dropping exaliases from fn. Don't overwrite it if so. */ + if (!DECL_ATTRIBUTES (clone)) + DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn)); DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn); set_decl_section_name (clone, DECL_SECTION_NAME (fn)); + update_exalias_interface (clone); + /* Adjust the parameter names and locations. */ parm = DECL_ARGUMENTS (fn); clone_parm = DECL_ARGUMENTS (clone); diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index d43248c..223c608 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -28,8 +28,10 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "intl.h" #include "stor-layout.h" +#include "attribs.h" #include "c-family/c-pragma.h" #include "gcc-rich-location.h" +#include "cgraph.h" /* C++ returns type information to the user in struct type_info objects. We also use type information to implement dynamic_cast and @@ -469,6 +471,18 @@ get_tinfo_decl (tree type) if (CLASS_TYPE_P (type)) CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d; + /* Copy exalias attributes from the type to the rtti obj decl. */ + tree *attrs = &DECL_ATTRIBUTES (d); + FOR_EACH_EXALIAS (exalias, TYPE_ATTRIBUTES (type)) + { + tree attr = tree_cons (TREE_PURPOSE (exalias), + TREE_VALUE (exalias), + *attrs); + *attrs = attr; + attrs = &TREE_CHAIN (attr); + } + create_exalias_decls (d); + /* Add decl to the global array of tinfo decls. */ vec_safe_push (unemitted_tinfo_decls, d); } @@ -476,6 +490,58 @@ get_tinfo_decl (tree type) return d; } +/* After modifying the attributes of TYPE, check whether tinfo was + already created and, if so, add to it any exalias attributes that + were not already present. */ + +void +update_tinfo_exalias (tree type) +{ + if (!TYPE_SIZE (type) || !CLASS_TYPE_P (type)) + return; + + tree d = CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)); + if (!d) + return; + + bool first = true; + symtab_node *node = NULL; + + tree *attrs = &DECL_ATTRIBUTES (d); + FOR_EACH_EXALIAS (exalias, TYPE_ATTRIBUTES (type)) + { + bool found = false; + FOR_EACH_EXALIAS (dexalias, *attrs) + if (TREE_VALUE (exalias) == TREE_VALUE (dexalias)) + { + found = true; + break; + } + + if (found) + continue; + + tree attr = tree_cons (TREE_PURPOSE (exalias), + TREE_VALUE (exalias), + *attrs); + *attrs = attr; + attrs = &TREE_CHAIN (attr); + + if (first) + { + first = false; + node = symtab_node::get (d); + } + + if (!node) + continue; + + tree id = TREE_VALUE (TREE_VALUE (exalias)); + id = get_identifier (TREE_STRING_POINTER (id)); + create_exalias_decl (d, id); + } +} + /* Return a pointer to a type_info object describing TYPE, suitably cast to the language defined type. */ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 37a675a..0ba880f 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2882,6 +2882,39 @@ when using these attributes the problem is diagnosed earlier and with exact location of the call even in presence of inline functions or when not emitting debugging information. +@item exalias ("@var{name}") +@cindex @code{exalias} function attribute +The @code{exalias} attribute causes @var{name} to be emitted as an alias +to the definition. For instance, + +@smallexample +void f (uint64_t) __attribute__ ((__exalias__ ("f_u64"))); +void f (uint64_t) @{ /* @r{Do something.} */; @} +@end smallexample + +@noindent +defines @samp{f}, and outputs @samp{f_u64} as an alias for @samp{f}. +This is particularly useful when exporting C++ names for use in other +languages, or as an alias target, when machine-dependent types would +make mangled names harder to deal with. + +In the case of C++ constructors and destructors, in which a single +definition may output multiple symbols, the specified name is associated +with the variant that constructs or destructs a complete object. The +variant that applies to a base subobject gets a @code{_Base} suffix, and +the deleting destructor gets a @code{_Del} suffix. + +This attribute is silently ignored if @samp{f} is not defined in the +same translation unit, so that the attribute can be attached to forward +declarations. + +The name @samp{f_u64} is an assembly symbol name: it does not undergo +C++ name mangling, and it is not made visible in any scope in the source +language, but it can be named as an alias target. + +This attribute requires assembler and object file support, +and may not be available on all targets. + @item externally_visible @cindex @code{externally_visible} function attribute This attribute, attached to a global variable or function, nullifies @@ -6929,6 +6962,10 @@ align them on any target. The @code{aligned} attribute can also be used for functions (@pxref{Common Function Attributes}.) +@item exalias ("@var{name}") +@cindex @code{exalias} variable attribute +See @pxref{Common Function Attributes}. + @cindex @code{warn_if_not_aligned} variable attribute @item warn_if_not_aligned (@var{alignment}) This attribute specifies a threshold for the structure field, measured @@ -7067,6 +7104,21 @@ types (@pxref{Common Function Attributes}, The message attached to the attribute is affected by the setting of the @option{-fmessage-length} option. +@item exalias ("@var{name}") +@cindex @code{exalias} type attribute +The @code{exalias} attribute causes @var{name} to be emitted as an alias +to the definition of the C++ Run-Time Type Information (RTTI) +@code{std::type_info} object associated with the type. For instance, + +@smallexample +class foo __attribute__ ((__exalias__ ("TI_foo"))); +@end smallexample + +@noindent +arranges for @samp{TI_foo} to be defined as an alias to the RTTI object +for class @samp{foo}, once the class is defined and used in ways that +cause its RTTI object to be synthesized and output. + @item mode (@var{mode}) @cindex @code{mode} variable attribute This attribute specifies the data type for the declaration---whichever diff --git a/gcc/symtab.c b/gcc/symtab.c index d7dfbb6..0ea8532 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -1874,6 +1874,42 @@ symtab_node::noninterposable_alias (symtab_node *node, void *data) return false; } +/* Remap exalias nodes recorded as aliasing REPLACED to alias + REPLACEMENT instead. */ + +void +symtab_node::remap_exalias_target (tree replaced, tree replacement) +{ + if (!decl_in_symtab_p (replacement) + || !symtab_node::get (replacement)) + return; + + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (replaced)) + { + tree id = TREE_VALUE (TREE_VALUE (exalias)); + id = get_identifier (TREE_STRING_POINTER (id)); + + symtab_node *sym_node = symtab_node::get_for_asmname (id); + + if (!sym_node) + { + create_exalias_decl (replacement, id); + continue; + } + + gcc_assert (!sym_node->analyzed); + if (sym_node->alias_target != replaced) + continue; + + sym_node->definition = 0; + + if (VAR_P (replaced)) + varpool_node::create_extra_name_alias (sym_node->decl, replacement); + else + cgraph_node::create_same_body_alias (sym_node->decl, replacement); + } +} + /* If node cannot be overwriten by static or dynamic linker to point to different definition, return NODE. Otherwise look for alias with such property and if none exists, introduce new one. */ diff --git a/gcc/testsuite/c-c++-common/attr-weak-1.c b/gcc/testsuite/c-c++-common/attr-weak-1.c new file mode 100644 index 00000000..b11ef71 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-weak-1.c @@ -0,0 +1,19 @@ +/* { dg-do run { xfail *-*-* } } */ +/* { dg-require-effective-target weak_undefined } */ + +/* C++ wouldn't combine attributes from local declarations with a + namespace-scoped symbol. Now it does, but only if there is a + visible declaration. */ + +void foo () { + extern void __attribute__ ((__weak__)) undef_fn (void); + extern int __attribute__ ((__weak__)) undef_var; +} + +int main () { + extern void undef_fn (void); + extern int undef_var; + + if (&undef_fn || &undef_var) + __builtin_abort (); +} diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-1.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-1.c new file mode 100644 index 00000000..3a471cc --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-1.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +extern int var_a __attribute__ ((__exalias__ ("FOOVAR_A"))); +int var_a = 1; + +void foo_a () __attribute__ ((__exalias__ ("FOOBAR_A"))); + +void +foo_a () +{ +} + + +int var_b; +extern int var_b __attribute__ ((__exalias__ ("FOOVAR_B"))); + +void +foo_b () +{ +} + +void foo_b () __attribute__ ((__exalias__ ("FOOBAR_B"))); + + +int var_c __attribute__ ((__exalias__ ("FOOVAR_C"))); + +void __attribute__ ((__exalias__ ("FOOBAR_C"))) +foo_c () +{ +} + + +/* { dg-final { scan-assembler "FOOBAR_A" } } */ +/* { dg-final { scan-assembler "FOOVAR_A" } } */ +/* { dg-final { scan-assembler "FOOBAR_B" } } */ +/* { dg-final { scan-assembler "FOOVAR_B" } } */ +/* { dg-final { scan-assembler "FOOBAR_C" } } */ +/* { dg-final { scan-assembler "FOOVAR_C" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-2.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-2.c new file mode 100644 index 00000000..a0fe686 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-2.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +struct s +{ + int mem __attribute__ ((__exalias__ ("MEMFOO"))); /* { dg-warning "attribute ignored" } */ +}; + +void foo() +{ + extern void bar () __attribute__ ((__exalias__ ("FOOBAR"))); + int var __attribute__ ((__exalias__ ("FOOVAR"))); /* { dg-warning "attribute ignored" } */ +} diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-3.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-3.c new file mode 100644 index 00000000..d94b618 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-3.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +int var_a = 1; + +void +foo_a () +{ + extern int var_a __attribute__ ((__exalias__ ("FOOVAR_A"))); + void foo_a () __attribute__ ((__exalias__ ("FOOBAR_A"))); +} + +#if __cplusplus +/* Without this declaration before the local declaration below, the + attributes of the local declaration do not get propagated to the + (global) namespace scope. */ +extern int var_b; +#endif + +void +foo_b () +{ + extern int var_b __attribute__ ((__exalias__ ("FOOVAR_B"))); +} + +int var_b; + +void __attribute__ ((__exalias__ ("FOOBAR_C"))) +foo_c () +{ + void foo_b () __attribute__ ((__exalias__ ("FOOBAR_B"))); + /* Another exalias for var_b. */ + extern int var_b __attribute__ ((__exalias__ ("FOOVAR_C"))); +} + +/* { dg-final { scan-assembler "FOOBAR_A" } } */ +/* { dg-final { scan-assembler "FOOVAR_A" } } */ +/* { dg-final { scan-assembler "FOOBAR_B" } } */ +/* { dg-final { scan-assembler "FOOVAR_B" } } */ +/* { dg-final { scan-assembler "FOOBAR_C" } } */ +/* { dg-final { scan-assembler "FOOVAR_C" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-4.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-4.c new file mode 100644 index 00000000..6320d1a4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-4.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-require-alias "" } */ + +int var_a __attribute__ ((__exalias__ ("FOOVAR_A"))) = 42; + +int __attribute__ ((__exalias__ ("FOOBAR_A"))) +foo_a (int p) +{ + return p; +} + +extern int __attribute__ ((__alias__ (("FOOVAR_A")))) var_b; +extern int __attribute__ ((__alias__ (("FOOBAR_A")))) foo_b (int p); + +int +foo_c () +{ + return foo_b (var_b); +} + +int +main () +{ + if (foo_c () != 42) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-1.C b/gcc/testsuite/g++.dg/torture/attr-exalias-1.C new file mode 100644 index 00000000..ac355f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/attr-exalias-1.C @@ -0,0 +1,70 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo { + static int var __attribute__ ((__exalias__ ("FOOVAR_A"))); + __attribute__ ((__exalias__ ("FOOCTR_A"))) foo (); + void __attribute__ ((__exalias__ ("FOOBAR_A"))) bar (); + virtual __attribute__ ((__exalias__ ("FOODTR_A"))) ~foo() {} +}; + +int foo::var = 1; + +foo::foo () {} + +void foo::bar () {} + +namespace b { + class __attribute__ ((__exalias__ ("FOOCLS_B"))) foo { + static int var __attribute__ ((__exalias__ ("FOOVAR_B"))); + __attribute__ ((__exalias__ ("FOOCTR_B"))) foo (); + void __attribute__ ((__exalias__ ("FOOBAR_B"))) bar () {} + virtual __attribute__ ((__exalias__ ("FOODTR_B"))) ~foo() {} + }; + + int foo::var = 2; + + foo::foo () { + void (foo::*pbar)() = &foo::bar; + } +} + +namespace c { + namespace cd { + class __attribute__ ((__exalias__ ("FOOCLS_C"))) foo { + static int var __attribute__ ((__exalias__ ("FOOVAR_C"))); + __attribute__ ((__exalias__ ("FOOCTR_C"))) foo () { + void (foo::*pbar)() = &foo::bar; + } + void __attribute__ ((__exalias__ ("FOOBAR_C"))) bar () {} + virtual __attribute__ ((__exalias__ ("FOODTR_C"))) ~foo() {} + }; + + int foo::var = 3; + } +} + +/* { dg-final { scan-assembler "FOOCLS_A" } } */ +/* { dg-final { scan-assembler "FOOBAR_A" } } */ +/* { dg-final { scan-assembler "FOOCTR_A" } } */ +/* { dg-final { scan-assembler "FOOCTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_A" } } */ +/* { dg-final { scan-assembler "FOODTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_A_Del" } } */ +/* { dg-final { scan-assembler "FOOVAR_A" } } */ +/* { dg-final { scan-assembler "FOOCLS_B" } } */ +/* { dg-final { scan-assembler "FOOBAR_B" } } */ +/* { dg-final { scan-assembler "FOOCTR_B" } } */ +/* { dg-final { scan-assembler "FOOCTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_B" } } */ +/* { dg-final { scan-assembler "FOODTR_B_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_B_Del" } } */ +/* { dg-final { scan-assembler "FOOVAR_B" } } */ +/* { dg-final { scan-assembler "FOOCLS_C" } } */ +/* { dg-final { scan-assembler "FOOBAR_C" } } */ +/* { dg-final { scan-assembler "FOOCTR_C" } } */ +/* { dg-final { scan-assembler "FOOCTR_C_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_C" } } */ +/* { dg-final { scan-assembler "FOODTR_C_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_C_Del" } } */ +/* { dg-final { scan-assembler "FOOVAR_C" } } */ diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-2.C b/gcc/testsuite/g++.dg/torture/attr-exalias-2.C new file mode 100644 index 00000000..266ee0c --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/attr-exalias-2.C @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +namespace { + class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo { + static int var __attribute__ ((__exalias__ ("FOOVAR_A"))); + __attribute__ ((__exalias__ ("FOOCTR_A"))) foo (); + virtual __attribute__ ((__exalias__ ("FOODTR_A"))) ~foo (); + void __attribute__ ((__exalias__ ("FOOBAR_A"))) bar (); + }; + + int foo::var = 3; + foo::foo () {} + foo::~foo () {} + void foo::bar () {} +} + +/* { dg-final { scan-assembler-not "\.globl" } } */ +/* { dg-final { scan-assembler "FOOCLS_A" } } */ +/* { dg-final { scan-assembler "FOOBAR_A" } } */ +/* { dg-final { scan-assembler "FOOCTR_A" } } */ +/* { dg-final { scan-assembler "FOOCTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_A" } } */ +/* { dg-final { scan-assembler "FOODTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_A_Del" } } */ +/* { dg-final { scan-assembler "FOOVAR_A" } } */ diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-3.C b/gcc/testsuite/g++.dg/torture/attr-exalias-3.C new file mode 100644 index 00000000..a81348a --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/attr-exalias-3.C @@ -0,0 +1,83 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +// exalias can be applied to template function explicit instantiations. + +template +void +fn(T) { +}; + +template void __attribute__ ((__exalias__ ("FOOFUN_UINT"))) fn<>(unsigned int); +template void __attribute__ ((__exalias__ ("FOOFUN_LONG"))) fn<>(long); + +template<> void __attribute__ ((__exalias__ ("FOOFUN_CHAR"))) fn<>(char) {} + + +template +struct +foo { + virtual ~foo() {} + + virtual void virtfun() {} + + static void stfun() {} + void inlfun() {} +}; + +// Explicitly instantiate members before the enclosing class. + +template void +__attribute__ ((__exalias__ ("FOOCLS_CHAR_VIRT"))) foo::virtfun(); + +template class __attribute__ ((__exalias__ ("FOOCLS_CHAR_TI"))) foo; + +// Though they're only output if the enclosing class is. +template void +__attribute__ ((__exalias__ ("FOOCLS_LONG_VIRT"))) foo::virtfun(); +extern +template class __attribute__ ((__exalias__ ("FOOCLS_LONG_TI_X"))) foo; + + +template void +__attribute__ ((__exalias__ ("FOOCLS_VOID_ST"))) foo::stfun(); + +template class __attribute__ ((__exalias__ ("FOOCLS_VOID_TI"))) foo<>; + + +extern +template class __attribute__ ((__exalias__ ("FOOCLS_SHORT_TI_X"))) foo; + +template void +__attribute__ ((__exalias__ ("FOOCLS_SHORT_ST"))) foo::stfun(); +template void +__attribute__ ((__exalias__ ("FOOCLS_SHORT_INL"))) foo::inlfun(); + +template class __attribute__ ((__exalias__ ("FOOCLS_SHORT_TI_D"))) foo; + +// Explicit specializations work too. + +template <> +struct __attribute__ ((__exalias__ ("FOOCLS_INT_TI"))) +foo +{ + virtual ~foo() {} + virtual void __attribute__ ((__exalias__ ("FOOCLS_INT_VIRT"))) virtfun() {} +}; + +/* { dg-final { scan-assembler "FOOFUN_UINT" } } */ +/* { dg-final { scan-assembler "FOOFUN_LONG" } } */ +/* { dg-final { scan-assembler "FOOFUN_CHAR" } } */ + +/* { dg-final { scan-assembler "FOOCLS_VOID_TI" } } */ +/* { dg-final { scan-assembler "FOOCLS_VOID_ST" } } */ +/* { dg-final { scan-assembler "FOOCLS_CHAR_TI" } } */ +/* { dg-final { scan-assembler "FOOCLS_CHAR_VIRT" } } */ +/* { dg-final { scan-assembler "FOOCLS_SHORT_TI_X" } } */ +/* { dg-final { scan-assembler "FOOCLS_SHORT_ST" } } */ +/* { dg-final { scan-assembler "FOOCLS_SHORT_INL" } } */ +/* { dg-final { scan-assembler "FOOCLS_SHORT_TI_D" } } */ +/* { dg-final { scan-assembler-not "FOOCLS_LONG_TI_X" } } */ +/* { dg-final { scan-assembler-not "FOOCLS_LONG_VIRT" } } */ +/* { dg-final { scan-assembler "FOOCLS_INT_TI" } } */ +/* { dg-final { scan-assembler "FOOCLS_INT_VIRT" } } */ diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-4.C b/gcc/testsuite/g++.dg/torture/attr-exalias-4.C new file mode 100644 index 00000000..9623bef --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/attr-exalias-4.C @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +template +class +__attribute__ ((__exalias__ ("FOOCLS"))) +foo // { dg-error "duplicate|already" } +{ + virtual ~foo() {} + + template + void + __attribute__ ((__exalias__ ("FOOTMF"))) + tmemfun () {} // { dg-error "duplicate|already" } +}; + +template +void +__attribute__ ((__exalias__ ("FOOTFN"))) +fn(T) { // { dg-error "duplicate|already" } +}; + +template class foo<>; +template class foo; +template void foo<>::tmemfun(); +template void foo::tmemfun(); +template void fn<>(int); +template void fn<>(long); diff --git a/gcc/varpool.c b/gcc/varpool.c index 458cdf1..5f89662 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -162,6 +162,9 @@ varpool_node::get_create (tree decl) } node->register_symbol (); + + create_exalias_decls (decl); + return node; } -- Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/ Free Software Activist GNU Toolchain Engineer