@@ -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
@@ -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
@@ -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"
@@ -2076,6 +2077,61 @@ 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;
+
+ warning (0, "duplicate symbol name %qE in %qE attribute of %qD",
+ id, name, 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_alias (clone, decl);
+ }
+ else
+ {
+ cgraph_node::create_alias (clone, decl);
+ }
+
+ return clone;
+}
+
+/* Create all exaliases requested in DECL's attributes. */
+
+void
+create_exalias_decls (tree decl)
+{
+ 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
@@ -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
@@ -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);
@@ -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,38 @@ 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 (VAR_OR_FUNCTION_DECL_P (node)
+ /* Variables must not be automatic. */
+ && !(VAR_P (node) && !TREE_STATIC (node) && !DECL_EXTERNAL (node)))
+ {
+ tree id = TREE_VALUE (args);
+ id = get_identifier (TREE_STRING_POINTER (id));
+
+ create_exalias_decl (node, id);
+
+ *no_add_attrs = false;
+ }
+ else if (TYPE_P (node) && c_dialect_cxx ())
+ *no_add_attrs = false;
+ else
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+
+ 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 +2606,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)
@@ -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
@@ -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);
@@ -641,7 +641,7 @@ cgraph_node::analyze (void)
return;
}
if (alias)
- resolve_alias (cgraph_node::get (alias_target), transparent_alias);
+ resolve_alias (cgraph_node::get_create (alias_target), transparent_alias);
else if (dispatcher_function)
{
/* Generate the dispatcher body of multi-versioned functions. */
@@ -4822,6 +4822,57 @@ 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);
+ }
+
+ 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;
@@ -4919,6 +4970,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;
}
@@ -6591,6 +6591,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);
@@ -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.
@@ -16508,6 +16510,8 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
if (!processing_template_decl)
maybe_instantiate_noexcept (decl1);
+ update_exalias_interface (decl1);
+
begin_scope (sk_function_parms, decl1);
++function_depth;
@@ -1951,6 +1951,43 @@ 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)
+{
+ 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. */
@@ -2485,6 +2522,8 @@ constrain_visibility (tree decl, int visibility, bool tmpl)
/* This visibility was not specified. */
DECL_VISIBILITY_SPECIFIED (decl) = false;
}
+
+ update_exalias_interface (decl);
}
/* Constrain the visibility of DECL based on the visibility of its template
@@ -3013,6 +3052,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 +3288,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
@@ -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);
@@ -516,10 +516,14 @@ 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. */
+ if (DECL_ATTRIBUTES (clone) == DECL_ATTRIBUTES (fn))
+ 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);
@@ -28,6 +28,7 @@ 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"
@@ -469,6 +470,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);
}
@@ -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
@@ -6928,6 +6961,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
@@ -7066,6 +7103,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
@@ -1861,6 +1861,32 @@ 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)
+{
+ 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);
+
+ gcc_assert (!sym_node->analyzed);
+ if (sym_node->alias_target != replaced)
+ continue;
+
+ sym_node->definition = 0;
+
+ if (VAR_P (replaced))
+ varpool_node::create_alias (sym_node->decl, replacement);
+ else
+ cgraph_node::create_alias (sym_node->decl, replacement);
+ }
+}
+
/* If node cannot be overwriten by static or dynamic linker to point to
different definition, return NODE. Otherwise look for alias with such
property and if none exists, introduce new one. */
new file mode 100644
@@ -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 ();
+}
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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 "public objects" } */
+}
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -0,0 +1,66 @@
+/* { 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 () {}
+}
+
+namespace c {
+ namespace cd {
+ class __attribute__ ((__exalias__ ("FOOCLS_C"))) foo {
+ static int var __attribute__ ((__exalias__ ("FOOVAR_C")));
+ __attribute__ ((__exalias__ ("FOOCTR_C"))) foo () {}
+ 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" } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -0,0 +1,61 @@
+/* { 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 <typename T = void>
+class
+foo {
+ virtual ~foo() {}
+
+ // Member functions that we wish to name with exalias must be
+ // defined outside the class body, *after* any exalias-named
+ // instantiations of the enclosing template types. If they are
+ // defined in the class body, or before the explicit instantiation,
+ // they will be implicitly instantiated along with the enclosing
+ // template class type, and then the explicit instantiation of the
+ // member function will be rejected as a duplicate. If we attempt
+ // to explicitly instantiate the member functions first, their
+ // naming the enclosing template type will trigger the implicit
+ // instantiation thereof, and then the subsequent explicit
+ // instantiation of the class type will have attributes ignored.
+ virtual void virtfun();
+
+ static void stfun() {}
+ void inlfun() {}
+};
+
+template class __attribute__ ((__exalias__ ("FOOCLS_VOID_TI"))) foo<>;
+template class __attribute__ ((__exalias__ ("FOOCLS_CHAR_TI"))) foo<char>;
+
+template void
+__attribute__ ((__exalias__ ("FOOCLS_SHORT_ST"))) foo<short>::stfun();
+template void
+__attribute__ ((__exalias__ ("FOOCLS_SHORT_INL"))) foo<short>::inlfun();
+
+template <typename T>
+void foo<T>::virtfun() {}
+
+template void
+__attribute__ ((__exalias__ ("FOOCLS_CHAR_VIRT"))) foo<char>::virtfun();
+
+template void
+__attribute__ ((__exalias__ ("FOOCLS_LONG_VIRT"))) foo<long>::virtfun();
+
+/* { dg-final { scan-assembler "FOOCLS_VOID_TI" } } */
+/* { dg-final { scan-assembler "FOOCLS_CHAR_TI" } } */
+/* { dg-final { scan-assembler "FOOCLS_SHORT_ST" } } */
+/* { dg-final { scan-assembler "FOOCLS_SHORT_INL" } } */
+/* { dg-final { scan-assembler "FOOCLS_CHAR_VIRT" } } */
+/* { dg-final { scan-assembler "FOOCLS_LONG_VIRT" } } */
+/* { dg-final { scan-assembler "FOOFUN_UINT" } } */
+/* { dg-final { scan-assembler "FOOFUN_LONG" } } */
new file mode 100644
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+
+template <typename T = void>
+class
+__attribute__ ((__exalias__ ("FOOCLS"))) foo // { dg-warning "duplicate" }
+{
+ virtual ~foo() {}
+
+ virtual void
+ __attribute__ ((__exalias__ ("FOOVFN"))) // { dg-warning "duplicate" { xfail *-*-* } }
+ virtfun () {}
+};
+
+template <typename T>
+void
+__attribute__ ((__exalias__ ("FOOTFN"))) // { dg-warning "duplicate" { xfail *-*-* } }
+fn(T) {
+};
+
+template class foo<>;
+template class foo<int>;
+template void fn<>(int);
+template void fn<>(long);
+
+/* { dg-final { scan-assembler "FOOCLS" } } */
+/* { dg-final { scan-assembler "FOOVFN" { xfail *-*-* } } } */
+/* { dg-final { scan-assembler "FOOFUN" { xfail *-*-* } } } */
@@ -523,7 +523,7 @@ varpool_node::analyze (void)
align_variable (decl, 0);
}
if (alias)
- resolve_alias (varpool_node::get (alias_target));
+ resolve_alias (varpool_node::get_create (alias_target));
else if (DECL_INITIAL (decl))
record_references_in_initializer (decl, analyzed);
analyzed = true;
introduce exrtti as a separate attribute for types
From: Alexandre Oliva <oliva@adacore.com>
Make attribute exalias apply to declarations only. Use a separate
attribute exrtti to name exaliases for the RTTI object associated with
classes.
---
.../doc/gnat_rm/interfacing_to_other_languages.rst | 2 +-
gcc/attribs.h | 3 +++
gcc/c-family/c-attribs.c | 9 ++++++---
gcc/cp/rtti.c | 6 +++---
gcc/doc/extend.texi | 8 ++++----
gcc/testsuite/g++.dg/torture/attr-exalias-1.C | 6 +++---
gcc/testsuite/g++.dg/torture/attr-exalias-2.C | 2 +-
gcc/testsuite/g++.dg/torture/attr-exalias-3.C | 6 +++---
gcc/testsuite/g++.dg/torture/attr-exalias-4.C | 2 +-
9 files changed, 25 insertions(+), 19 deletions(-)
@@ -125,7 +125,7 @@ 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
+introduced by adding attribute ``exrtti`` to the class that the RTTI
symbol refers to.
@@ -254,5 +254,8 @@ 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)))
+#define FOR_EACH_EXRTTI(exalias, attrs) \
+ for (tree exalias = lookup_attribute ("exrtti", (attrs)); exalias; \
+ exalias = lookup_attribute ("exrtti", TREE_CHAIN (exalias)))
#endif // GCC_ATTRIBS_H
@@ -334,7 +334,9 @@ 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,
+ { "exalias", 1, 1, true, false, false, false,
+ handle_exalias_attribute, NULL },
+ { "exrtti", 1, 1, false, true, false, false,
handle_exalias_attribute, NULL },
{ "no_instrument_function", 0, 0, true, false, false, false,
handle_no_instrument_function_attribute,
@@ -2447,8 +2449,8 @@ 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. */
+/* Handle an "exalias" or "exrtti" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
handle_exalias_attribute (tree *pnode, tree name, tree args,
@@ -2607,6 +2609,7 @@ handle_copy_attribute (tree *node, tree name, tree args,
if (is_attribute_p ("alias", atname)
|| is_attribute_p ("always_inline", atname)
|| is_attribute_p ("exalias", atname)
+ || is_attribute_p ("exrtti", atname)
|| is_attribute_p ("gnu_inline", atname)
|| is_attribute_p ("ifunc", atname)
|| is_attribute_p ("noinline", atname)
@@ -470,11 +470,11 @@ 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. */
+ /* Copy exrtti attributes from the type to the rtti obj decl. */
tree *attrs = &DECL_ATTRIBUTES (d);
- FOR_EACH_EXALIAS (exalias, TYPE_ATTRIBUTES (type))
+ FOR_EACH_EXRTTI (exalias, TYPE_ATTRIBUTES (type))
{
- tree attr = tree_cons (TREE_PURPOSE (exalias),
+ tree attr = tree_cons (get_identifier ("exalias"),
TREE_VALUE (exalias),
*attrs);
*attrs = attr;
@@ -7103,14 +7103,14 @@ 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
+@item exrtti ("@var{name}")
+@cindex @code{exrtti} type attribute
+The @code{exrtti} 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")));
+class foo __attribute__ ((__exrtti__ ("TI_foo")));
@end smallexample
@noindent
@@ -1,7 +1,7 @@
/* { dg-do compile } */
/* { dg-require-alias "" } */
-class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo {
+class __attribute__ ((__exrtti__ ("FOOCLS_A"))) foo {
static int var __attribute__ ((__exalias__ ("FOOVAR_A")));
__attribute__ ((__exalias__ ("FOOCTR_A"))) foo ();
void __attribute__ ((__exalias__ ("FOOBAR_A"))) bar ();
@@ -15,7 +15,7 @@ foo::foo () {}
void foo::bar () {}
namespace b {
- class __attribute__ ((__exalias__ ("FOOCLS_B"))) foo {
+ class __attribute__ ((__exrtti__ ("FOOCLS_B"))) foo {
static int var __attribute__ ((__exalias__ ("FOOVAR_B")));
__attribute__ ((__exalias__ ("FOOCTR_B"))) foo ();
void __attribute__ ((__exalias__ ("FOOBAR_B"))) bar () {}
@@ -29,7 +29,7 @@ namespace b {
namespace c {
namespace cd {
- class __attribute__ ((__exalias__ ("FOOCLS_C"))) foo {
+ class __attribute__ ((__exrtti__ ("FOOCLS_C"))) foo {
static int var __attribute__ ((__exalias__ ("FOOVAR_C")));
__attribute__ ((__exalias__ ("FOOCTR_C"))) foo () {}
void __attribute__ ((__exalias__ ("FOOBAR_C"))) bar () {}
@@ -2,7 +2,7 @@
/* { dg-require-alias "" } */
namespace {
- class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo {
+ class __attribute__ ((__exrtti__ ("FOOCLS_A"))) foo {
static int var __attribute__ ((__exalias__ ("FOOVAR_A")));
__attribute__ ((__exalias__ ("FOOCTR_A"))) foo ();
virtual __attribute__ ((__exalias__ ("FOODTR_A"))) ~foo ();
@@ -18,7 +18,7 @@ foo {
virtual ~foo() {}
// Member functions that we wish to name with exalias must be
- // defined outside the class body, *after* any exalias-named
+ // defined outside the class body, *after* any exrtti-named
// instantiations of the enclosing template types. If they are
// defined in the class body, or before the explicit instantiation,
// they will be implicitly instantiated along with the enclosing
@@ -34,8 +34,8 @@ foo {
void inlfun() {}
};
-template class __attribute__ ((__exalias__ ("FOOCLS_VOID_TI"))) foo<>;
-template class __attribute__ ((__exalias__ ("FOOCLS_CHAR_TI"))) foo<char>;
+template class __attribute__ ((__exrtti__ ("FOOCLS_VOID_TI"))) foo<>;
+template class __attribute__ ((__exrtti__ ("FOOCLS_CHAR_TI"))) foo<char>;
template void
__attribute__ ((__exalias__ ("FOOCLS_SHORT_ST"))) foo<short>::stfun();
@@ -3,7 +3,7 @@
template <typename T = void>
class
-__attribute__ ((__exalias__ ("FOOCLS"))) foo // { dg-warning "duplicate" }
+__attribute__ ((__exrtti__ ("FOOCLS"))) foo // { dg-warning "duplicate" }
{
virtual ~foo() {}