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