Hi, my testcase unfortunately passes with plugin disabled only. With plugin enabled it hits a bug where we won't associate alais with its taerget across units and we optimize out the target as unused.
Funilly enough this hits yet another bug in GNU LD that makes the testcase to run infinitely, while with Gold it ICEs. This patch fixes the GCC part of th ebug. It is ugly by overusing ->alias field to store identifier node when decl is not around and by duplicating cycle detection for aliases. I have patch in queue to cleanup the whole area, but I would like to fix this first, since release branches are also affected and this makes the patch easier to backport. Bootstrap/regtest of x86_64-linux in progress. Will commit the patch if it passes. Honza * cgraphunit.c (handle_alias_pairs): Save target of weakref alias. (output_weakrefs): Do not ice on unresolved weakrefs. * lto-symtab.c (lto_symtab_merge_cgraph_nodes): Resolve weakrefs. * cgraph.c (dump_cgraph_node): Do not ICE on unresolved weakrefs. Index: cgraphunit.c =================================================================== --- cgraphunit.c (revision 198926) +++ cgraphunit.c (working copy) @@ -1069,9 +1069,17 @@ handle_alias_pairs (void) if (!target_node && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)) != NULL) { if (TREE_CODE (p->decl) == FUNCTION_DECL) - cgraph_get_create_node (p->decl)->alias = true; + { + struct cgraph_node *anode = cgraph_get_create_node (p->decl); + anode->alias = true; + anode->thunk.alias = p->target; + } else - varpool_get_node (p->decl)->alias = true; + { + struct varpool_node *anode = varpool_get_node (p->decl); + anode->alias = true; + anode->alias_of = p->target; + } DECL_EXTERNAL (p->decl) = 1; alias_pairs->unordered_remove (i); continue; @@ -1939,14 +1947,14 @@ output_weakrefs (void) && !TREE_ASM_WRITTEN (node->symbol.decl) && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl))) do_assemble_alias (node->symbol.decl, - node->thunk.alias ? DECL_ASSEMBLER_NAME (node->thunk.alias) + node->thunk.alias && DECL_P (node->thunk.alias) ? DECL_ASSEMBLER_NAME (node->thunk.alias) : get_alias_symbol (node->symbol.decl)); FOR_EACH_VARIABLE (vnode) if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl) && !TREE_ASM_WRITTEN (vnode->symbol.decl) && lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl))) do_assemble_alias (vnode->symbol.decl, - vnode->alias_of ? DECL_ASSEMBLER_NAME (vnode->alias_of) + vnode->alias_of && DECL_P (vnode->alias_of) ? DECL_ASSEMBLER_NAME (vnode->alias_of) : get_alias_symbol (vnode->symbol.decl)); } Index: lto-symtab.c =================================================================== --- lto-symtab.c (revision 198926) +++ lto-symtab.c (working copy) @@ -593,13 +593,67 @@ lto_symtab_merge_cgraph_nodes (void) FOR_EACH_FUNCTION (cnode) { + /* Resolve weakrefs to symbol defined in other unit. */ + if (!cnode->analyzed && cnode->thunk.alias && !DECL_P (cnode->thunk.alias)) + { + symtab_node node = symtab_node_for_asm (cnode->thunk.alias); + if (node && is_a <cgraph_node> (node)) + { + struct cgraph_node *n; + + for (n = cgraph (node); n && n->alias; + n = n->analyzed ? cgraph_alias_aliased_node (n) : NULL) + if (n == cnode) + { + error ("function %q+D part of alias cycle", cnode->symbol.decl); + cnode->alias = false; + break; + } + if (cnode->alias) + { + cgraph_create_function_alias (cnode->symbol.decl, node->symbol.decl); + ipa_record_reference ((symtab_node)cnode, (symtab_node)node, + IPA_REF_ALIAS, NULL); + cnode->analyzed = true; + } + } + else if (node) + error ("%q+D alias in between function and variable is not supported", cnode->symbol.decl); + } if ((cnode->thunk.thunk_p || cnode->alias) - && cnode->thunk.alias) + && cnode->thunk.alias && DECL_P (cnode->thunk.alias)) cnode->thunk.alias = lto_symtab_prevailing_decl (cnode->thunk.alias); cnode->symbol.aux = NULL; } FOR_EACH_VARIABLE (vnode) { + /* Resolve weakrefs to symbol defined in other unit. */ + if (!vnode->analyzed && vnode->alias_of && !DECL_P (vnode->alias_of)) + { + symtab_node node = symtab_node_for_asm (vnode->alias_of); + if (node && is_a <cgraph_node> (node)) + { + struct varpool_node *n; + + for (n = varpool (node); n && n->alias; + n = n->analyzed ? varpool_alias_aliased_node (n) : NULL) + if (n == vnode) + { + error ("function %q+D part of alias cycle", vnode->symbol.decl); + vnode->alias = false; + break; + } + if (vnode->alias) + { + varpool_create_variable_alias (vnode->symbol.decl, node->symbol.decl); + ipa_record_reference ((symtab_node)vnode, (symtab_node)node, + IPA_REF_ALIAS, NULL); + vnode->analyzed = true; + } + } + else if (node) + error ("%q+D alias in between function and variable is not supported", vnode->symbol.decl); + } if (vnode->alias_of) vnode->alias_of = lto_symtab_prevailing_decl (vnode->alias_of); vnode->symbol.aux = NULL; Index: cgraph.c =================================================================== --- cgraph.c (revision 198926) +++ cgraph.c (working copy) @@ -1558,7 +1558,7 @@ dump_cgraph_node (FILE *f, struct cgraph (int)node->thunk.virtual_value, (int)node->thunk.virtual_offset_p); } - if (node->alias && node->thunk.alias) + if (node->alias && node->thunk.alias && DECL_P (node->thunk.alias)) { fprintf (f, " Alias of %s", lang_hooks.decl_printable_name (node->thunk.alias, 2));