mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-05 18:43:52 +08:00
re PR lto/61886 (LTO breaks fread with _FORTIFY_SOURCE=2)
PR ipa/61886 * symtab.c (ultimate_transparent_alias_target): New inline function. (symbol_table::assembler_names_equal_p): New method; break out from ... (symbol_table::decl_assembler_name_equal): ... here. (symbol_table::change_decl_assembler_name): Also update names and translation links of transparent aliases. (symtab_node::dump_base): Dump transparent_alias. (symtab_node::verify_base): Implement basic transparent alias verification. (symtab_node::make_decl_local): Support localization of weakrefs; recurse to transparent aliases; set TREE_STATIC. (symtab_node::ultimate_alias_target_1): Handle visibility of transparent aliases. (symtab_node::resolve_alias): New parmaeter transparent; handle transparent aliases; recurse to aliases of aliases to fix comdat groups. (symtab_node::get_partitioning_class): Handle transparent aliases. * ipa-visibility.c (cgraph_externally_visible_p, varpool_node::externally_visible_p): Visibility of transparent alias depends on its target. (function_and_variable_visibility): Do not tweak visibility of transparent laiases. (function_and_variable_visibility): Likewise. * ipa.c (symbol_table::remove_unreachable_nodes): Clear transparent_alias flag. * alias.c (cgraph_node::create_alias, cgraph_node::get_availability): Support transparent aliases. * cgraph.h (symtab_node): Update prototype of resolve_alias; add transparent_alias flag. (symbol_table: Add assembler_names_equal_p. (symtab_node::real_symbol_p): Skip transparent aliases. * cgraphunit.c (cgraph_node::reset): Reset transparent_alias flag. (handle_alias_pairs): Set transparent_alias for weakref. (cgraph_node::assemble_thunks_and_aliases): Do not asemble transparent aliases. * lto-cgraph.c (lto_output_node): When outputting same_comdat_group skip symbols not put into boundary; stream transparent_alias. (lto_output_varpool_node): Likewise. (input_overwrite_node, input_varpool_node): Stream transparent alias. * varpool.c (ctor_for_folding, varpool_node::get_availability, varpool_node::assemble_aliases, symbol_table::remove_unreferenced_decls): Handle transparent aliase. (varpool_node::create_alias): Set transparent_alias. * lto-partition.c (add_symbol_to_partition_1, contained_in_symbol, rename_statics, rename_statics): Handle transparent aliases. From-SVN: r231373
This commit is contained in:
parent
058c6384fe
commit
71e546870c
@ -1,3 +1,49 @@
|
||||
2015-12-07 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
PR ipa/61886
|
||||
* symtab.c (ultimate_transparent_alias_target): New inline function.
|
||||
(symbol_table::assembler_names_equal_p): New method; break out from ...
|
||||
(symbol_table::decl_assembler_name_equal): ... here.
|
||||
(symbol_table::change_decl_assembler_name): Also update names and
|
||||
translation links of transparent aliases.
|
||||
(symtab_node::dump_base): Dump transparent_alias.
|
||||
(symtab_node::verify_base): Implement basic transparent alias
|
||||
verification.
|
||||
(symtab_node::make_decl_local): Support localization of weakrefs;
|
||||
recurse to transparent aliases; set TREE_STATIC.
|
||||
(symtab_node::ultimate_alias_target_1): Handle visibility of
|
||||
transparent aliases.
|
||||
(symtab_node::resolve_alias): New parmaeter transparent; handle
|
||||
transparent aliases; recurse to aliases of aliases to fix comdat
|
||||
groups.
|
||||
(symtab_node::get_partitioning_class): Handle transparent aliases.
|
||||
* ipa-visibility.c (cgraph_externally_visible_p,
|
||||
varpool_node::externally_visible_p): Visibility of transparent alias
|
||||
depends on its target.
|
||||
(function_and_variable_visibility): Do not tweak visibility of
|
||||
transparent laiases.
|
||||
(function_and_variable_visibility): Likewise.
|
||||
* ipa.c (symbol_table::remove_unreachable_nodes): Clear
|
||||
transparent_alias flag.
|
||||
* alias.c (cgraph_node::create_alias, cgraph_node::get_availability):
|
||||
Support transparent aliases.
|
||||
* cgraph.h (symtab_node): Update prototype of resolve_alias;
|
||||
add transparent_alias flag.
|
||||
(symbol_table: Add assembler_names_equal_p.
|
||||
(symtab_node::real_symbol_p): Skip transparent aliases.
|
||||
* cgraphunit.c (cgraph_node::reset): Reset transparent_alias flag.
|
||||
(handle_alias_pairs): Set transparent_alias for weakref.
|
||||
(cgraph_node::assemble_thunks_and_aliases): Do not asemble transparent
|
||||
aliases.
|
||||
* lto-cgraph.c (lto_output_node): When outputting same_comdat_group
|
||||
skip symbols not put into boundary; stream transparent_alias.
|
||||
(lto_output_varpool_node): Likewise.
|
||||
(input_overwrite_node, input_varpool_node): Stream transparent alias.
|
||||
* varpool.c (ctor_for_folding, varpool_node::get_availability,
|
||||
varpool_node::assemble_aliases,
|
||||
symbol_table::remove_unreferenced_decls): Handle transparent aliase.
|
||||
(varpool_node::create_alias): Set transparent_alias.
|
||||
|
||||
2015-12-07 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
PR middle-end/68291
|
||||
|
@ -560,7 +560,7 @@ cgraph_node::create_alias (tree alias, tree target)
|
||||
alias_node->definition = true;
|
||||
alias_node->alias = true;
|
||||
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
|
||||
alias_node->weakref = true;
|
||||
alias_node->transparent_alias = alias_node->weakref = true;
|
||||
return alias_node;
|
||||
}
|
||||
|
||||
@ -2147,7 +2147,7 @@ cgraph_node::get_availability (void)
|
||||
avail = AVAIL_NOT_AVAILABLE;
|
||||
else if (local.local)
|
||||
avail = AVAIL_LOCAL;
|
||||
else if (alias && weakref)
|
||||
else if (transparent_alias)
|
||||
ultimate_alias_target (&avail);
|
||||
else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
|
||||
avail = AVAIL_INTERPOSABLE;
|
||||
|
31
gcc/cgraph.h
31
gcc/cgraph.h
@ -249,9 +249,10 @@ public:
|
||||
inline symtab_node *next_defined_symbol (void);
|
||||
|
||||
/* Add reference recording that symtab node is alias of TARGET.
|
||||
If TRANSPARENT is true make the alias to be transparent alias.
|
||||
The function can fail in the case of aliasing cycles; in this case
|
||||
it returns false. */
|
||||
bool resolve_alias (symtab_node *target);
|
||||
bool resolve_alias (symtab_node *target, bool transparent = false);
|
||||
|
||||
/* C++ FE sometimes change linkage flags after producing same
|
||||
body aliases. */
|
||||
@ -421,6 +422,28 @@ public:
|
||||
/* True when symbol is an alias.
|
||||
Set by ssemble_alias. */
|
||||
unsigned alias : 1;
|
||||
/* When true the alias is translated into its target symbol either by GCC
|
||||
or assembler (it also may just be a duplicate declaration of the same
|
||||
linker name).
|
||||
|
||||
Currently transparent aliases come in three different flavors
|
||||
- aliases having the same assembler name as their target (aka duplicated
|
||||
declarations). In this case the assembler names compare via
|
||||
assembler_names_equal_p and weakref is false
|
||||
- aliases that are renamed at a time being output to final file
|
||||
by varasm.c. For those DECL_ASSEMBLER_NAME have
|
||||
IDENTIFIER_TRANSPARENT_ALIAS set and thus also their assembler
|
||||
name must be unique.
|
||||
Weakrefs belong to this cateogry when we target assembler without
|
||||
.weakref directive.
|
||||
- weakrefs that are renamed by assembler via .weakref directive.
|
||||
In this case the alias may or may not be definition (depending if
|
||||
target declaration was seen by the compiler), weakref is set.
|
||||
Unless we are before renaming statics, assembler names are different.
|
||||
|
||||
Given that we now support duplicate declarations, the second option is
|
||||
redundant and will be removed. */
|
||||
unsigned transparent_alias : 1;
|
||||
/* True when alias is a weakref. */
|
||||
unsigned weakref : 1;
|
||||
/* C++ frontend produce same body aliases and extra name aliases for
|
||||
@ -2098,6 +2121,10 @@ public:
|
||||
/* Set the DECL_ASSEMBLER_NAME and update symtab hashtables. */
|
||||
void change_decl_assembler_name (tree decl, tree name);
|
||||
|
||||
/* Return true if assembler names NAME1 and NAME2 leads to the same symbol
|
||||
name. */
|
||||
static bool assembler_names_equal_p (const char *name1, const char *name2);
|
||||
|
||||
int cgraph_count;
|
||||
int cgraph_max_uid;
|
||||
int cgraph_max_summary_uid;
|
||||
@ -2251,6 +2278,8 @@ symtab_node::real_symbol_p (void)
|
||||
|
||||
if (DECL_ABSTRACT_P (decl))
|
||||
return false;
|
||||
if (transparent_alias && definition)
|
||||
return false;
|
||||
if (!is_a <cgraph_node *> (this))
|
||||
return true;
|
||||
cnode = dyn_cast <cgraph_node *> (this);
|
||||
|
@ -369,6 +369,7 @@ cgraph_node::reset (void)
|
||||
analyzed = false;
|
||||
definition = false;
|
||||
alias = false;
|
||||
transparent_alias = false;
|
||||
weakref = false;
|
||||
cpp_implicit_alias = false;
|
||||
|
||||
@ -594,7 +595,7 @@ cgraph_node::analyze (void)
|
||||
thunk.alias = NULL;
|
||||
}
|
||||
if (alias)
|
||||
resolve_alias (cgraph_node::get (alias_target));
|
||||
resolve_alias (cgraph_node::get (alias_target), transparent_alias);
|
||||
else if (dispatcher_function)
|
||||
{
|
||||
/* Generate the dispatcher body of multi-versioned functions. */
|
||||
@ -1254,6 +1255,7 @@ handle_alias_pairs (void)
|
||||
node->alias_target = p->target;
|
||||
node->weakref = true;
|
||||
node->alias = true;
|
||||
node->transparent_alias = true;
|
||||
}
|
||||
alias_pairs->unordered_remove (i);
|
||||
continue;
|
||||
@ -1908,15 +1910,18 @@ cgraph_node::assemble_thunks_and_aliases (void)
|
||||
FOR_EACH_ALIAS (this, ref)
|
||||
{
|
||||
cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
|
||||
bool saved_written = TREE_ASM_WRITTEN (decl);
|
||||
if (!alias->transparent_alias)
|
||||
{
|
||||
bool saved_written = TREE_ASM_WRITTEN (decl);
|
||||
|
||||
/* Force assemble_alias to really output the alias this time instead
|
||||
of buffering it in same alias pairs. */
|
||||
TREE_ASM_WRITTEN (decl) = 1;
|
||||
do_assemble_alias (alias->decl,
|
||||
DECL_ASSEMBLER_NAME (decl));
|
||||
alias->assemble_thunks_and_aliases ();
|
||||
TREE_ASM_WRITTEN (decl) = saved_written;
|
||||
/* Force assemble_alias to really output the alias this time instead
|
||||
of buffering it in same alias pairs. */
|
||||
TREE_ASM_WRITTEN (decl) = 1;
|
||||
do_assemble_alias (alias->decl,
|
||||
DECL_ASSEMBLER_NAME (decl));
|
||||
alias->assemble_thunks_and_aliases ();
|
||||
TREE_ASM_WRITTEN (decl) = saved_written;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,6 +185,8 @@ static bool
|
||||
cgraph_externally_visible_p (struct cgraph_node *node,
|
||||
bool whole_program)
|
||||
{
|
||||
while (node->transparent_alias && node->definition)
|
||||
node = node->get_alias_target ();
|
||||
if (!node->definition)
|
||||
return false;
|
||||
if (!TREE_PUBLIC (node->decl)
|
||||
@ -248,6 +250,8 @@ cgraph_externally_visible_p (struct cgraph_node *node,
|
||||
bool
|
||||
varpool_node::externally_visible_p (void)
|
||||
{
|
||||
while (transparent_alias && definition)
|
||||
return get_alias_target ()->externally_visible_p ();
|
||||
if (DECL_EXTERNAL (decl))
|
||||
return true;
|
||||
|
||||
@ -531,7 +535,8 @@ function_and_variable_visibility (bool whole_program)
|
||||
next->set_comdat_group (NULL);
|
||||
if (!next->alias)
|
||||
next->set_section (NULL);
|
||||
next->make_decl_local ();
|
||||
if (!next->transparent_alias)
|
||||
next->make_decl_local ();
|
||||
next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
|
||||
|| next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
|
||||
&& TREE_PUBLIC (next->decl)
|
||||
@ -547,7 +552,8 @@ function_and_variable_visibility (bool whole_program)
|
||||
node->set_comdat_group (NULL);
|
||||
if (DECL_COMDAT (node->decl) && !node->alias)
|
||||
node->set_section (NULL);
|
||||
node->make_decl_local ();
|
||||
if (!node->transparent_alias)
|
||||
node->make_decl_local ();
|
||||
}
|
||||
|
||||
if (node->thunk.thunk_p
|
||||
@ -654,7 +660,7 @@ function_and_variable_visibility (bool whole_program)
|
||||
DECL_ATTRIBUTES (vnode->decl)))
|
||||
vnode->no_reorder = 1;
|
||||
if (!vnode->externally_visible
|
||||
&& !vnode->weakref)
|
||||
&& !vnode->transparent_alias)
|
||||
{
|
||||
gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl));
|
||||
vnode->unique_name |= ((vnode->resolution == LDPR_PREVAILING_DEF_IRONLY
|
||||
@ -675,11 +681,14 @@ function_and_variable_visibility (bool whole_program)
|
||||
next->set_comdat_group (NULL);
|
||||
if (!next->alias)
|
||||
next->set_section (NULL);
|
||||
next->make_decl_local ();
|
||||
next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
|
||||
|| next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
|
||||
&& TREE_PUBLIC (next->decl)
|
||||
&& !flag_incremental_link);
|
||||
if (!next->transparent_alias)
|
||||
{
|
||||
next->make_decl_local ();
|
||||
next->unique_name |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
|
||||
|| next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
|
||||
&& TREE_PUBLIC (next->decl)
|
||||
&& !flag_incremental_link);
|
||||
}
|
||||
}
|
||||
vnode->dissolve_same_comdat_group_list ();
|
||||
}
|
||||
@ -687,8 +696,11 @@ function_and_variable_visibility (bool whole_program)
|
||||
vnode->set_comdat_group (NULL);
|
||||
if (DECL_COMDAT (vnode->decl) && !vnode->alias)
|
||||
vnode->set_section (NULL);
|
||||
vnode->make_decl_local ();
|
||||
vnode->resolution = LDPR_PREVAILING_DEF_IRONLY;
|
||||
if (!vnode->transparent_alias)
|
||||
{
|
||||
vnode->make_decl_local ();
|
||||
vnode->resolution = LDPR_PREVAILING_DEF_IRONLY;
|
||||
}
|
||||
}
|
||||
update_visibility_by_resolution_info (vnode);
|
||||
|
||||
|
@ -543,6 +543,7 @@ symbol_table::remove_unreachable_nodes (FILE *file)
|
||||
node->definition = false;
|
||||
node->cpp_implicit_alias = false;
|
||||
node->alias = false;
|
||||
node->transparent_alias = false;
|
||||
node->thunk.thunk_p = false;
|
||||
node->weakref = false;
|
||||
/* After early inlining we drop always_inline attributes on
|
||||
|
@ -485,11 +485,12 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
|
||||
|
||||
if (group)
|
||||
{
|
||||
if (node->same_comdat_group && !boundary_p)
|
||||
if (node->same_comdat_group)
|
||||
{
|
||||
ref = lto_symtab_encoder_lookup (encoder,
|
||||
node->same_comdat_group);
|
||||
gcc_assert (ref != LCC_NOT_FOUND);
|
||||
ref = LCC_NOT_FOUND;
|
||||
for (struct symtab_node *n = node->same_comdat_group;
|
||||
ref == LCC_NOT_FOUND && n != node; n = n->same_comdat_group)
|
||||
ref = lto_symtab_encoder_lookup (encoder, n);
|
||||
}
|
||||
else
|
||||
ref = LCC_NOT_FOUND;
|
||||
@ -523,6 +524,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
|
||||
bp_pack_value (&bp, node->lowered, 1);
|
||||
bp_pack_value (&bp, in_other_partition, 1);
|
||||
bp_pack_value (&bp, node->alias, 1);
|
||||
bp_pack_value (&bp, node->transparent_alias, 1);
|
||||
bp_pack_value (&bp, node->weakref, 1);
|
||||
bp_pack_value (&bp, node->frequency, 2);
|
||||
bp_pack_value (&bp, node->only_called_at_startup, 1);
|
||||
@ -599,8 +601,9 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node,
|
||||
bp_pack_value (&bp, node->definition && (encode_initializer_p || node->alias),
|
||||
1);
|
||||
bp_pack_value (&bp, node->alias, 1);
|
||||
bp_pack_value (&bp, node->transparent_alias, 1);
|
||||
bp_pack_value (&bp, node->weakref, 1);
|
||||
bp_pack_value (&bp, node->analyzed && !boundary_p, 1);
|
||||
bp_pack_value (&bp, node->analyzed && (!boundary_p || node->alias), 1);
|
||||
gcc_assert (node->definition || !node->analyzed);
|
||||
/* Constant pool initializers can be de-unified into individual ltrans units.
|
||||
FIXME: Alternatively at -Os we may want to avoid generating for them the local
|
||||
@ -632,11 +635,12 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node,
|
||||
|
||||
if (group)
|
||||
{
|
||||
if (node->same_comdat_group && !boundary_p)
|
||||
if (node->same_comdat_group)
|
||||
{
|
||||
ref = lto_symtab_encoder_lookup (encoder,
|
||||
node->same_comdat_group);
|
||||
gcc_assert (ref != LCC_NOT_FOUND);
|
||||
ref = LCC_NOT_FOUND;
|
||||
for (struct symtab_node *n = node->same_comdat_group;
|
||||
ref == LCC_NOT_FOUND && n != node; n = n->same_comdat_group)
|
||||
ref = lto_symtab_encoder_lookup (encoder, n);
|
||||
}
|
||||
else
|
||||
ref = LCC_NOT_FOUND;
|
||||
@ -1170,6 +1174,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
|
||||
TREE_STATIC (node->decl) = 0;
|
||||
}
|
||||
node->alias = bp_unpack_value (bp, 1);
|
||||
node->transparent_alias = bp_unpack_value (bp, 1);
|
||||
node->weakref = bp_unpack_value (bp, 1);
|
||||
node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);
|
||||
node->only_called_at_startup = bp_unpack_value (bp, 1);
|
||||
@ -1369,6 +1374,7 @@ input_varpool_node (struct lto_file_decl_data *file_data,
|
||||
node->writeonly = bp_unpack_value (&bp, 1);
|
||||
node->definition = bp_unpack_value (&bp, 1);
|
||||
node->alias = bp_unpack_value (&bp, 1);
|
||||
node->transparent_alias = bp_unpack_value (&bp, 1);
|
||||
node->weakref = bp_unpack_value (&bp, 1);
|
||||
node->analyzed = bp_unpack_value (&bp, 1);
|
||||
node->used_from_other_partition = bp_unpack_value (&bp, 1);
|
||||
|
@ -1,3 +1,9 @@
|
||||
2015-12-07 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
PR ipa/61886
|
||||
* lto-partition.c (add_symbol_to_partition_1, contained_in_symbol,
|
||||
rename_statics, rename_statics): Handle transparent aliases.
|
||||
|
||||
2015-12-04 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* lto-symtab.c (lto_cgraph_replace_node): Update code computing
|
||||
|
@ -1035,7 +1035,15 @@ rename_statics (lto_symtab_encoder_t encoder, symtab_node *node)
|
||||
/* Assign every symbol in the set that shares the same ASM name an unique
|
||||
mangled name. */
|
||||
for (s = symtab_node::get_for_asmname (name); s;)
|
||||
if (!s->externally_visible
|
||||
if ((!s->externally_visible || s->weakref)
|
||||
/* Transparent aliases having same name as target are renamed at a
|
||||
time their target gets new name. Transparent aliases that use
|
||||
separate assembler name require the name to be unique. */
|
||||
&& (!s->transparent_alias || !s->definition || s->weakref
|
||||
|| !symbol_table::assembler_names_equal_p
|
||||
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (s->decl)),
|
||||
IDENTIFIER_POINTER
|
||||
(DECL_ASSEMBLER_NAME (s->get_alias_target()->decl))))
|
||||
&& ((s->real_symbol_p ()
|
||||
&& !DECL_EXTERNAL (node->decl)
|
||||
&& !TREE_PUBLIC (node->decl))
|
||||
|
266
gcc/symtab.c
266
gcc/symtab.c
@ -52,6 +52,26 @@ const char * const ld_plugin_symbol_resolution_names[]=
|
||||
"prevailing_def_ironly_exp"
|
||||
};
|
||||
|
||||
/* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at ALIAS
|
||||
until we find an identifier that is not itself a transparent alias. */
|
||||
|
||||
static inline tree
|
||||
ultimate_transparent_alias_target (tree alias)
|
||||
{
|
||||
tree target = alias;
|
||||
|
||||
while (IDENTIFIER_TRANSPARENT_ALIAS (target))
|
||||
{
|
||||
gcc_checking_assert (TREE_CHAIN (target));
|
||||
target = TREE_CHAIN (target);
|
||||
}
|
||||
gcc_checking_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target)
|
||||
&& ! TREE_CHAIN (target));
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/* Hash asmnames ignoring the user specified marks. */
|
||||
|
||||
hashval_t
|
||||
@ -73,6 +93,44 @@ symbol_table::decl_assembler_name_hash (const_tree asmname)
|
||||
return htab_hash_string (IDENTIFIER_POINTER (asmname));
|
||||
}
|
||||
|
||||
/* Return true if assembler names NAME1 and NAME2 leads to the same symbol
|
||||
name. */
|
||||
|
||||
bool
|
||||
symbol_table::assembler_names_equal_p (const char *name1, const char *name2)
|
||||
{
|
||||
if (name1 != name2)
|
||||
{
|
||||
if (name1[0] == '*')
|
||||
{
|
||||
size_t ulp_len = strlen (user_label_prefix);
|
||||
|
||||
name1 ++;
|
||||
|
||||
if (ulp_len == 0)
|
||||
;
|
||||
else if (strncmp (name1, user_label_prefix, ulp_len) == 0)
|
||||
name1 += ulp_len;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
if (name2[0] == '*')
|
||||
{
|
||||
size_t ulp_len = strlen (user_label_prefix);
|
||||
|
||||
name2 ++;
|
||||
|
||||
if (ulp_len == 0)
|
||||
;
|
||||
else if (strncmp (name2, user_label_prefix, ulp_len) == 0)
|
||||
name2 += ulp_len;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return !strcmp (name1, name2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */
|
||||
|
||||
@ -82,51 +140,13 @@ symbol_table::decl_assembler_name_equal (tree decl, const_tree asmname)
|
||||
tree decl_asmname = DECL_ASSEMBLER_NAME (decl);
|
||||
const char *decl_str;
|
||||
const char *asmname_str;
|
||||
bool test = false;
|
||||
|
||||
if (decl_asmname == asmname)
|
||||
return true;
|
||||
|
||||
decl_str = IDENTIFIER_POINTER (decl_asmname);
|
||||
asmname_str = IDENTIFIER_POINTER (asmname);
|
||||
|
||||
|
||||
/* If the target assembler name was set by the user, things are trickier.
|
||||
We have a leading '*' to begin with. After that, it's arguable what
|
||||
is the correct thing to do with -fleading-underscore. Arguably, we've
|
||||
historically been doing the wrong thing in assemble_alias by always
|
||||
printing the leading underscore. Since we're not changing that, make
|
||||
sure user_label_prefix follows the '*' before matching. */
|
||||
if (decl_str[0] == '*')
|
||||
{
|
||||
size_t ulp_len = strlen (user_label_prefix);
|
||||
|
||||
decl_str ++;
|
||||
|
||||
if (ulp_len == 0)
|
||||
test = true;
|
||||
else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0)
|
||||
decl_str += ulp_len, test=true;
|
||||
else
|
||||
decl_str --;
|
||||
}
|
||||
if (asmname_str[0] == '*')
|
||||
{
|
||||
size_t ulp_len = strlen (user_label_prefix);
|
||||
|
||||
asmname_str ++;
|
||||
|
||||
if (ulp_len == 0)
|
||||
test = true;
|
||||
else if (strncmp (asmname_str, user_label_prefix, ulp_len) == 0)
|
||||
asmname_str += ulp_len, test=true;
|
||||
else
|
||||
asmname_str --;
|
||||
}
|
||||
|
||||
if (!test)
|
||||
return false;
|
||||
return strcmp (decl_str, asmname_str) == 0;
|
||||
return assembler_names_equal_p (decl_str, asmname_str);
|
||||
}
|
||||
|
||||
|
||||
@ -273,6 +293,8 @@ symbol_table::change_decl_assembler_name (tree decl, tree name)
|
||||
: NULL);
|
||||
if (node)
|
||||
unlink_from_assembler_name_hash (node, true);
|
||||
|
||||
const char *old_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
|
||||
if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
|
||||
&& DECL_RTL_SET_P (decl))
|
||||
warning (0, "%D renamed after being referenced in assembly", decl);
|
||||
@ -283,8 +305,48 @@ symbol_table::change_decl_assembler_name (tree decl, tree name)
|
||||
IDENTIFIER_TRANSPARENT_ALIAS (name) = 1;
|
||||
TREE_CHAIN (name) = alias;
|
||||
}
|
||||
/* If we change assembler name, also all transparent aliases must
|
||||
be updated. There are three kinds - those having same assembler name,
|
||||
those being renamed in varasm.c and weakref being renamed by the
|
||||
assembler. */
|
||||
if (node)
|
||||
insert_to_assembler_name_hash (node, true);
|
||||
{
|
||||
insert_to_assembler_name_hash (node, true);
|
||||
ipa_ref *ref;
|
||||
for (unsigned i = 0; node->iterate_direct_aliases (i, ref); i++)
|
||||
{
|
||||
struct symtab_node *alias = ref->referring;
|
||||
if (alias->transparent_alias && !alias->weakref
|
||||
&& symbol_table::assembler_names_equal_p
|
||||
(old_name, IDENTIFIER_POINTER (
|
||||
DECL_ASSEMBLER_NAME (alias->decl))))
|
||||
change_decl_assembler_name (alias->decl, name);
|
||||
else if (alias->transparent_alias
|
||||
&& IDENTIFIER_TRANSPARENT_ALIAS (alias->decl))
|
||||
{
|
||||
gcc_assert (TREE_CHAIN (DECL_ASSEMBLER_NAME (alias->decl))
|
||||
&& IDENTIFIER_TRANSPARENT_ALIAS
|
||||
(DECL_ASSEMBLER_NAME (alias->decl)));
|
||||
|
||||
TREE_CHAIN (DECL_ASSEMBLER_NAME (alias->decl)) =
|
||||
ultimate_transparent_alias_target
|
||||
(DECL_ASSEMBLER_NAME (node->decl));
|
||||
}
|
||||
#ifdef ASM_OUTPUT_WEAKREF
|
||||
else gcc_assert (!alias->transparent_alias || alias->weakref);
|
||||
#else
|
||||
else gcc_assert (!alias->transparent_alias);
|
||||
#endif
|
||||
}
|
||||
gcc_assert (!node->transparent_alias || !node->definition
|
||||
|| node->weakref
|
||||
|| TREE_CHAIN (DECL_ASSEMBLER_NAME (decl))
|
||||
|| symbol_table::assembler_names_equal_p
|
||||
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
|
||||
IDENTIFIER_POINTER
|
||||
(DECL_ASSEMBLER_NAME
|
||||
(node->get_alias_target ()->decl))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -727,6 +789,8 @@ symtab_node::dump_base (FILE *f)
|
||||
fprintf (f, " analyzed");
|
||||
if (alias)
|
||||
fprintf (f, " alias");
|
||||
if (transparent_alias)
|
||||
fprintf (f, " transparent_alias");
|
||||
if (weakref)
|
||||
fprintf (f, " weakref");
|
||||
if (cpp_implicit_alias)
|
||||
@ -973,9 +1037,14 @@ symtab_node::verify_base (void)
|
||||
error ("node is alias but not definition");
|
||||
error_found = true;
|
||||
}
|
||||
if (weakref && !alias)
|
||||
if (weakref && !transparent_alias)
|
||||
{
|
||||
error ("node is weakref but not an alias");
|
||||
error ("node is weakref but not an transparent_alias");
|
||||
error_found = true;
|
||||
}
|
||||
if (transparent_alias && !alias)
|
||||
{
|
||||
error ("node is transparent_alias but not an alias");
|
||||
error_found = true;
|
||||
}
|
||||
if (same_comdat_group)
|
||||
@ -1061,6 +1130,29 @@ symtab_node::verify_base (void)
|
||||
get_alias_target ()->dump (stderr);
|
||||
error_found = true;
|
||||
}
|
||||
if (transparent_alias && definition && !weakref)
|
||||
{
|
||||
symtab_node *to = get_alias_target ();
|
||||
const char *name1
|
||||
= IDENTIFIER_POINTER (
|
||||
ultimate_transparent_alias_target (DECL_ASSEMBLER_NAME (decl)));
|
||||
const char *name2
|
||||
= IDENTIFIER_POINTER (
|
||||
ultimate_transparent_alias_target (DECL_ASSEMBLER_NAME (to->decl)));
|
||||
if (!symbol_table::assembler_names_equal_p (name1, name2))
|
||||
{
|
||||
error ("Transparent alias and target's assembler names differs");
|
||||
get_alias_target ()->dump (stderr);
|
||||
error_found = true;
|
||||
}
|
||||
}
|
||||
if (transparent_alias && definition
|
||||
&& get_alias_target()->transparent_alias && get_alias_target()->analyzed)
|
||||
{
|
||||
error ("Chained transparent aliases");
|
||||
get_alias_target ()->dump (stderr);
|
||||
error_found = true;
|
||||
}
|
||||
|
||||
return error_found;
|
||||
}
|
||||
@ -1132,15 +1224,35 @@ symtab_node::make_decl_local (void)
|
||||
{
|
||||
rtx rtl, symbol;
|
||||
|
||||
if (weakref)
|
||||
{
|
||||
weakref = false;
|
||||
IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (decl)) = 0;
|
||||
TREE_CHAIN (DECL_ASSEMBLER_NAME (decl)) = NULL_TREE;
|
||||
symtab->change_decl_assembler_name
|
||||
(decl, DECL_ASSEMBLER_NAME (get_alias_target ()->decl));
|
||||
DECL_ATTRIBUTES (decl) = remove_attribute ("weakref",
|
||||
DECL_ATTRIBUTES (decl));
|
||||
}
|
||||
/* Avoid clearing comdat_groups on comdat-local decls. */
|
||||
if (TREE_PUBLIC (decl) == 0)
|
||||
else if (TREE_PUBLIC (decl) == 0)
|
||||
return;
|
||||
|
||||
/* Localizing a symbol also make all its transparent aliases local. */
|
||||
ipa_ref *ref;
|
||||
for (unsigned i = 0; iterate_direct_aliases (i, ref); i++)
|
||||
{
|
||||
struct symtab_node *alias = ref->referring;
|
||||
if (alias->transparent_alias)
|
||||
alias->make_decl_local ();
|
||||
}
|
||||
|
||||
if (TREE_CODE (decl) == VAR_DECL)
|
||||
{
|
||||
DECL_COMMON (decl) = 0;
|
||||
/* ADDRESSABLE flag is not defined for public symbols. */
|
||||
TREE_ADDRESSABLE (decl) = 1;
|
||||
TREE_STATIC (decl) = 1;
|
||||
}
|
||||
else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
|
||||
|
||||
@ -1175,29 +1287,28 @@ symtab_node::make_decl_local (void)
|
||||
symtab_node *
|
||||
symtab_node::ultimate_alias_target_1 (enum availability *availability)
|
||||
{
|
||||
bool weakref_p = false;
|
||||
bool transparent_p = false;
|
||||
|
||||
/* To determine visibility of the target, we follow ELF semantic of aliases.
|
||||
Here alias is an alternative assembler name of a given definition. Its
|
||||
availability prevails the availability of its target (i.e. static alias of
|
||||
weak definition is available.
|
||||
|
||||
Weakref is a different animal (and not part of ELF per se). It is just
|
||||
alternative name of a given symbol used within one complation unit
|
||||
and is translated prior hitting the object file. It inherits the
|
||||
visibility of its target (i.e. weakref of non-overwritable definition
|
||||
is non-overwritable, while weakref of weak definition is weak).
|
||||
Transaparent alias is just alternative anme of a given symbol used within
|
||||
one compilation unit and is translated prior hitting the object file. It
|
||||
inherits the visibility of its target.
|
||||
Weakref is a different animal (and noweak definition is weak).
|
||||
|
||||
If we ever get into supporting targets with different semantics, a target
|
||||
hook will be needed here. */
|
||||
|
||||
if (availability)
|
||||
{
|
||||
weakref_p = weakref;
|
||||
if (!weakref_p)
|
||||
transparent_p = transparent_alias;
|
||||
if (!transparent_p)
|
||||
*availability = get_availability ();
|
||||
else
|
||||
*availability = AVAIL_LOCAL;
|
||||
*availability = AVAIL_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
symtab_node *node = this;
|
||||
@ -1207,27 +1318,19 @@ symtab_node::ultimate_alias_target_1 (enum availability *availability)
|
||||
node = node->get_alias_target ();
|
||||
else
|
||||
{
|
||||
if (!availability)
|
||||
if (!availability || (!transparent_p && node->analyzed))
|
||||
;
|
||||
else if (node->analyzed)
|
||||
{
|
||||
if (weakref_p)
|
||||
{
|
||||
enum availability a = node->get_availability ();
|
||||
if (a < *availability)
|
||||
*availability = a;
|
||||
}
|
||||
}
|
||||
else if (node->analyzed && !node->transparent_alias)
|
||||
*availability = node->get_availability ();
|
||||
else
|
||||
*availability = AVAIL_NOT_AVAILABLE;
|
||||
return node;
|
||||
}
|
||||
if (node && availability && weakref_p)
|
||||
if (node && availability && transparent_p
|
||||
&& node->transparent_alias)
|
||||
{
|
||||
enum availability a = node->get_availability ();
|
||||
if (a < *availability)
|
||||
*availability = a;
|
||||
weakref_p = node->weakref;
|
||||
*availability = node->get_availability ();
|
||||
transparent_p = false;
|
||||
}
|
||||
}
|
||||
if (availability)
|
||||
@ -1442,7 +1545,7 @@ symtab_node::set_implicit_section (symtab_node *n,
|
||||
it returns false. */
|
||||
|
||||
bool
|
||||
symtab_node::resolve_alias (symtab_node *target)
|
||||
symtab_node::resolve_alias (symtab_node *target, bool transparent)
|
||||
{
|
||||
symtab_node *n;
|
||||
|
||||
@ -1468,6 +1571,11 @@ symtab_node::resolve_alias (symtab_node *target)
|
||||
definition = true;
|
||||
alias = true;
|
||||
analyzed = true;
|
||||
transparent |= transparent_alias;
|
||||
transparent_alias = transparent;
|
||||
if (transparent)
|
||||
while (target->transparent_alias && target->analyzed)
|
||||
target = target->get_alias_target ();
|
||||
create_reference (target, IPA_REF_ALIAS, NULL);
|
||||
|
||||
/* Add alias into the comdat group of its target unless it is already there. */
|
||||
@ -1492,19 +1600,29 @@ symtab_node::resolve_alias (symtab_node *target)
|
||||
when renaming symbols. */
|
||||
alias_target = NULL;
|
||||
|
||||
if (cpp_implicit_alias && symtab->state >= CONSTRUCTION)
|
||||
if (!transparent && cpp_implicit_alias && symtab->state >= CONSTRUCTION)
|
||||
fixup_same_cpp_alias_visibility (target);
|
||||
|
||||
/* If alias has address taken, so does the target. */
|
||||
if (address_taken)
|
||||
target->ultimate_alias_target ()->address_taken = true;
|
||||
|
||||
/* All non-weakref aliases of THIS are now in fact aliases of TARGET. */
|
||||
/* All non-transparent aliases of THIS are now in fact aliases of TARGET.
|
||||
If alias is transparent, also all transparent aliases of THIS are now
|
||||
aliases of TARGET.
|
||||
Also merge same comdat group lists. */
|
||||
ipa_ref *ref;
|
||||
for (unsigned i = 0; iterate_direct_aliases (i, ref);)
|
||||
{
|
||||
struct symtab_node *alias_alias = ref->referring;
|
||||
if (!alias_alias->weakref)
|
||||
if (alias_alias->get_comdat_group ())
|
||||
{
|
||||
alias_alias->remove_from_same_comdat_group ();
|
||||
alias_alias->set_comdat_group (NULL);
|
||||
if (target->get_comdat_group ())
|
||||
alias_alias->add_to_same_comdat_group (target);
|
||||
}
|
||||
if (!alias_alias->transparent_alias || transparent)
|
||||
{
|
||||
alias_alias->remove_all_references ();
|
||||
alias_alias->create_reference (target, IPA_REF_ALIAS, NULL);
|
||||
@ -1648,9 +1766,9 @@ symtab_node::get_partitioning_class (void)
|
||||
if (cnode && cnode->global.inlined_to)
|
||||
return SYMBOL_DUPLICATE;
|
||||
|
||||
/* Weakref aliases are always duplicated. */
|
||||
if (weakref)
|
||||
return SYMBOL_DUPLICATE;
|
||||
/* Transparent aliases are always duplicated. */
|
||||
if (transparent_alias)
|
||||
return definition ? SYMBOL_DUPLICATE : SYMBOL_EXTERNAL;
|
||||
|
||||
/* External declarations are external. */
|
||||
if (DECL_EXTERNAL (decl))
|
||||
|
57
gcc/tree.c
57
gcc/tree.c
@ -13423,6 +13423,12 @@ gimple_canonical_types_compatible_p (const_tree t1, const_tree t2,
|
||||
{
|
||||
tree f1, f2;
|
||||
|
||||
/* Don't try to compare variants of an incomplete type, before
|
||||
TYPE_FIELDS has been copied around. */
|
||||
if (!COMPLETE_TYPE_P (t1) && !COMPLETE_TYPE_P (t2))
|
||||
return true;
|
||||
|
||||
|
||||
if (TYPE_REVERSE_STORAGE_ORDER (t1) != TYPE_REVERSE_STORAGE_ORDER (t2))
|
||||
return false;
|
||||
|
||||
@ -13709,28 +13715,35 @@ verify_type (const_tree t)
|
||||
}
|
||||
}
|
||||
else if (RECORD_OR_UNION_TYPE_P (t))
|
||||
for (tree fld = TYPE_FIELDS (t); fld; fld = TREE_CHAIN (fld))
|
||||
{
|
||||
/* TODO: verify properties of decls. */
|
||||
if (TREE_CODE (fld) == FIELD_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == TYPE_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == CONST_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == VAR_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == TEMPLATE_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == USING_DECL)
|
||||
;
|
||||
else
|
||||
{
|
||||
error ("Wrong tree in TYPE_FIELDS list");
|
||||
debug_tree (fld);
|
||||
error_found = true;
|
||||
}
|
||||
}
|
||||
{
|
||||
if (TYPE_FIELDS (t) && !COMPLETE_TYPE_P (t) && in_lto_p)
|
||||
{
|
||||
error ("TYPE_FIELDS defined in incomplete type");
|
||||
error_found = true;
|
||||
}
|
||||
for (tree fld = TYPE_FIELDS (t); fld; fld = TREE_CHAIN (fld))
|
||||
{
|
||||
/* TODO: verify properties of decls. */
|
||||
if (TREE_CODE (fld) == FIELD_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == TYPE_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == CONST_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == VAR_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == TEMPLATE_DECL)
|
||||
;
|
||||
else if (TREE_CODE (fld) == USING_DECL)
|
||||
;
|
||||
else
|
||||
{
|
||||
error ("Wrong tree in TYPE_FIELDS list");
|
||||
debug_tree (fld);
|
||||
error_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (t) == INTEGER_TYPE
|
||||
|| TREE_CODE (t) == BOOLEAN_TYPE
|
||||
|| TREE_CODE (t) == OFFSET_TYPE
|
||||
|
@ -440,7 +440,7 @@ ctor_for_folding (tree decl)
|
||||
gcc_assert (!DECL_INITIAL (decl)
|
||||
|| (node->alias && node->get_alias_target () == real_node)
|
||||
|| DECL_INITIAL (decl) == error_mark_node);
|
||||
if (node->weakref)
|
||||
while (node->transparent_alias && node->analyzed)
|
||||
{
|
||||
node = node->get_alias_target ();
|
||||
decl = node->decl;
|
||||
@ -490,11 +490,11 @@ varpool_node::get_availability (void)
|
||||
if (DECL_IN_CONSTANT_POOL (decl)
|
||||
|| DECL_VIRTUAL_P (decl))
|
||||
return AVAIL_AVAILABLE;
|
||||
if (alias && weakref)
|
||||
if (transparent_alias)
|
||||
{
|
||||
enum availability avail;
|
||||
|
||||
ultimate_alias_target (&avail)->get_availability ();
|
||||
ultimate_alias_target (&avail);
|
||||
return avail;
|
||||
}
|
||||
/* If the variable can be overwritten, return OVERWRITABLE. Takes
|
||||
@ -536,8 +536,9 @@ varpool_node::assemble_aliases (void)
|
||||
FOR_EACH_ALIAS (this, ref)
|
||||
{
|
||||
varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
|
||||
do_assemble_alias (alias->decl,
|
||||
DECL_ASSEMBLER_NAME (decl));
|
||||
if (!alias->transparent_alias)
|
||||
do_assemble_alias (alias->decl,
|
||||
DECL_ASSEMBLER_NAME (decl));
|
||||
alias->assemble_aliases ();
|
||||
}
|
||||
}
|
||||
@ -665,7 +666,14 @@ symbol_table::remove_unreferenced_decls (void)
|
||||
&& vnode->analyzed)
|
||||
enqueue_node (vnode, &first);
|
||||
else
|
||||
referenced.add (node);
|
||||
{
|
||||
referenced.add (node);
|
||||
while (node->alias && node->definition)
|
||||
{
|
||||
node = node->get_alias_target ();
|
||||
referenced.add (node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dump_file)
|
||||
@ -760,7 +768,7 @@ varpool_node::create_alias (tree alias, tree decl)
|
||||
alias_node->definition = true;
|
||||
alias_node->alias_target = decl;
|
||||
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
|
||||
alias_node->weakref = true;
|
||||
alias_node->weakref = alias_node->transparent_alias = true;
|
||||
return alias_node;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user