aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog46
-rw-r--r--gcc/cgraph.c4
-rw-r--r--gcc/cgraph.h31
-rw-r--r--gcc/cgraphunit.c25
-rw-r--r--gcc/ipa-visibility.c32
-rw-r--r--gcc/ipa.c1
-rw-r--r--gcc/lto-cgraph.c24
-rw-r--r--gcc/lto/ChangeLog6
-rw-r--r--gcc/lto/lto-partition.c10
-rw-r--r--gcc/symtab.c266
-rw-r--r--gcc/tree.c57
-rw-r--r--gcc/varpool.c22
12 files changed, 388 insertions, 136 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index abd648e..d60a6da 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 2a55978..35cd98c 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -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;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index e689fcd..7c643502 100644
--- a/gcc/cgraph.h
+++ b/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);
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 4ab6414..3d86c36 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -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);
-
- /* 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;
+ }
}
}
diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
index 2eab214..0423f24 100644
--- a/gcc/ipa-visibility.c
+++ b/gcc/ipa-visibility.c
@@ -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);
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 77f2dd1..ce891e1 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -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
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index 67a9024..e1c2595 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -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);
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index df2eaa9..bdbc866 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -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
diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
index 4fd445f..ac1b618 100644
--- a/gcc/lto/lto-partition.c
+++ b/gcc/lto/lto-partition.c
@@ -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))
diff --git a/gcc/symtab.c b/gcc/symtab.c
index c188710..06d618b 100644
--- a/gcc/symtab.c
+++ b/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))
diff --git a/gcc/tree.c b/gcc/tree.c
index c8b3ab8..de67c4f 100644
--- a/gcc/tree.c
+++ b/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
diff --git a/gcc/varpool.c b/gcc/varpool.c
index 36f19a6..ffbec6d 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -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;
}