+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
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;
}
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;
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. */
/* 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
/* 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;
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);
analyzed = false;
definition = false;
alias = false;
+ transparent_alias = false;
weakref = false;
cpp_implicit_alias = false;
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. */
node->alias_target = p->target;
node->weakref = true;
node->alias = true;
+ node->transparent_alias = true;
}
alias_pairs->unordered_remove (i);
continue;
FOR_EACH_ALIAS (this, ref)
{
cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
- 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;
+ 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;
+ }
}
}
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)
bool
varpool_node::externally_visible_p (void)
{
+ while (transparent_alias && definition)
+ return get_alias_target ()->externally_visible_p ();
if (DECL_EXTERNAL (decl))
return true;
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)
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
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
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 ();
}
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);
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
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;
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);
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
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;
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);
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);
+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
/* 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))
"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
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. */
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);
}
: 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);
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))));
+ }
}
}
fprintf (f, " analyzed");
if (alias)
fprintf (f, " alias");
+ if (transparent_alias)
+ fprintf (f, " transparent_alias");
if (weakref)
fprintf (f, " weakref");
if (cpp_implicit_alias)
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)
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;
}
{
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);
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;
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)
it returns false. */
bool
-symtab_node::resolve_alias (symtab_node *target)
+symtab_node::resolve_alias (symtab_node *target, bool transparent)
{
symtab_node *n;
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. */
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);
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))
{
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;
}
}
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
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;
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
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 ();
}
}
&& 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)
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;
}