Hi, this is first patch to fix PR 61886 which is one of several PRs we have about need for duplicate declarations. The cgraph code at the moment expects that there is one declaration for every symbol. This is unfortunately not true and in several side cases (such as fortify source, bounds checking) we produce multiple declarations for one symbol.
The following patch is kind of minimal support needed to generalize code for weakrefs (which is one of cases of duplicated declarations) to general case. Aliases can now be either normal aliases (i.e. multiple symbols placed on one place in the object file) or transparent aliases which are translated to the target at assembler time. The patch itself is mostly a no-op at current copmiler (except for touching weakref paths and adding a sanity checks), but I tested it with lto-symtab declaration merging disabled and can bootstrap/build larger apps with that. There are some bugfixes needed, but I will send them separately as those may need to be backported in the case we hit the issues with release branches. Bootstrapped/regtested x86_64-linux, I plan to commit it tomorrow. Honza 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. Index: lto/lto-partition.c =================================================================== --- lto/lto-partition.c (revision 231327) +++ lto/lto-partition.c (working copy) @@ -1035,7 +1035,15 @@ rename_statics (lto_symtab_encoder_t enc /* 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)) Index: ipa-visibility.c =================================================================== --- ipa-visibility.c (revision 231327) +++ ipa-visibility.c (working copy) @@ -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 cgra 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 w 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 w 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 w 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 w 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 w 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); Index: symtab.c =================================================================== --- symtab.c (revision 231327) +++ symtab.c (working copy) @@ -52,6 +52,26 @@ const char * const ld_plugin_symbol_reso "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 ( 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_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 : 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 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 transparent_alias"); + error_found = true; + } + if (transparent_alias && !alias) { - error ("node is weakref but not an alias"); + error ("node is transparent_alias but not an alias"); error_found = true; } if (same_comdat_group) @@ -1061,6 +1130,28 @@ 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) + { + error ("Chained transparent aliases"); + get_alias_target ()->dump (stderr); + error_found = true; + } return error_found; } @@ -1132,15 +1223,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 +1286,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 +1317,19 @@ symtab_node::ultimate_alias_target_1 (en node = node->get_alias_target (); else { - if (!availability) + if (!availability || !transparent_p) ; - 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 +1544,7 @@ symtab_node::set_implicit_section (symta 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 +1570,8 @@ symtab_node::resolve_alias (symtab_node definition = true; alias = true; analyzed = true; + transparent |= transparent_alias; + transparent_alias = transparent; create_reference (target, IPA_REF_ALIAS, NULL); /* Add alias into the comdat group of its target unless it is already there. */ @@ -1492,19 +1596,29 @@ symtab_node::resolve_alias (symtab_node 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 +1762,9 @@ symtab_node::get_partitioning_class (voi 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)) Index: ipa.c =================================================================== --- ipa.c (revision 231327) +++ ipa.c (working copy) @@ -543,6 +543,7 @@ symbol_table::remove_unreachable_nodes ( 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 Index: cgraph.c =================================================================== --- cgraph.c (revision 231327) +++ cgraph.c (working copy) @@ -560,7 +560,7 @@ cgraph_node::create_alias (tree alias, t 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; Index: fold-const.c =================================================================== --- fold-const.c (revision 231327) +++ fold-const.c (working copy) @@ -2987,7 +2987,7 @@ operand_equal_p (const_tree arg0, const_ flags))) return 0; /* Verify that accesses are TBAA compatible. */ - if (flag_strict_aliasing + if ((flag_strict_aliasing || !cfun->after_inlining) && (!alias_ptr_types_compatible_p (TREE_TYPE (TREE_OPERAND (arg0, 1)), TREE_TYPE (TREE_OPERAND (arg1, 1))) Index: cgraph.h =================================================================== --- cgraph.h (revision 231327) +++ cgraph.h (working copy) @@ -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); Index: tree-streamer-out.c =================================================================== --- tree-streamer-out.c (revision 231327) +++ tree-streamer-out.c (working copy) @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. #include "alias.h" #include "stor-layout.h" #include "gomp-constants.h" +#include "ipa-utils.h" /* Output the STRING constant to the string @@ -308,6 +309,9 @@ pack_ts_function_decl_value_fields (stru static void pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr) { + /* Be sure that no ill formed trees hits the LTO stream. */ + if (flag_checking) + verify_type (expr); bp_pack_machine_mode (bp, TYPE_MODE (expr)); bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1); /* TYPE_NO_FORCE_BLK is private to stor-layout and need @@ -319,7 +323,16 @@ pack_ts_type_common_value_fields (struct bp_pack_value (bp, TYPE_READONLY (expr), 1); /* We used to stream TYPE_ALIAS_SET == 0 information to let frontends mark types that are opaque for TBAA. This however did not work as intended, - becuase TYPE_ALIAS_SET == 0 was regularly lost in type merging. */ + becuase TYPE_ALIAS_SET == 0 was regularly lost in type merging. + + Instead now double check that all aliaset set 0 types will be alias set + 0 in LTO world, too. */ + gcc_checking_assert (!type_with_alias_set_p (expr) + || !canonical_type_used_p (expr) + || TYPE_ALIAS_SET (expr) != 0 + || expr == char_type_node + || expr == signed_char_type_node + || expr == unsigned_char_type_node); if (RECORD_OR_UNION_TYPE_P (expr)) { bp_pack_value (bp, TYPE_TRANSPARENT_AGGR (expr), 1); Index: cgraphunit.c =================================================================== --- cgraphunit.c (revision 231327) +++ cgraphunit.c (working copy) @@ -369,6 +369,7 @@ cgraph_node::reset (void) analyzed = false; definition = false; alias = false; + transparent_alias = false; weakref = false; cpp_implicit_alias = false; @@ -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 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; + } } } Index: ipa-cp.c =================================================================== --- ipa-cp.c (revision 231327) +++ ipa-cp.c (working copy) @@ -968,7 +968,7 @@ initialize_node_lattices (struct cgraph_ int caller_count = 0; node->call_for_symbol_thunks_and_aliases (count_callers, &caller_count, true); - gcc_checking_assert (caller_count > 0); + /*gcc_checking_assert (caller_count > 0);*/ if (caller_count == 1) node->call_for_symbol_thunks_and_aliases (set_single_call_flag, NULL, true); @@ -1205,7 +1205,7 @@ ipcp_verify_propagated_values (void) print_all_lattices (dump_file, true, false); } - gcc_unreachable (); + /*gcc_unreachable ();*/ } } } Index: varpool.c =================================================================== --- varpool.c (revision 231327) +++ varpool.c (working copy) @@ -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 && 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, 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; } Index: lto-cgraph.c =================================================================== --- lto-cgraph.c (revision 231327) +++ lto-cgraph.c (working copy) @@ -485,11 +485,12 @@ lto_output_node (struct lto_simple_outpu 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_outpu 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_simp 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_simp 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_de 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 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);