/* The cgraph node if decl is a function decl. Filled in during the
merging process. */
struct cgraph_node *node;
+ /* The varpool node if decl is a variable decl. Filled in during the
+ merging process. */
+ struct varpool_node *vnode;
/* LTO file-data and symbol resolution for this decl. */
struct lto_file_decl_data * GTY((skip (""))) file_data;
enum ld_plugin_symbol_resolution resolution;
}
/* Returns non-zero if P points to an lto_symtab_entry_def struct that needs
- to be marked for GC. */
+ to be marked for GC. */
static int
lto_symtab_entry_marked_p (const void *p)
cgraph_remove_edge (e);
}
+ if (node->same_body)
+ {
+ struct cgraph_node *alias;
+
+ for (alias = node->same_body; alias; alias = alias->next)
+ if (DECL_ASSEMBLER_NAME_SET_P (alias->decl))
+ {
+ lto_symtab_entry_t se
+ = lto_symtab_get (DECL_ASSEMBLER_NAME (alias->decl));
+
+ for (; se; se = se->next)
+ if (se->node == node)
+ {
+ se->node = NULL;
+ break;
+ }
+ }
+ }
+
/* Finally remove the replaced node. */
cgraph_remove_node (node);
}
+/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
+ all edges and removing the old node. */
+
+static void
+lto_varpool_replace_node (struct varpool_node *vnode,
+ struct varpool_node *prevailing_node)
+{
+ /* Merge node flags. */
+ if (vnode->needed)
+ {
+ gcc_assert (prevailing_node->analyzed);
+ varpool_mark_needed_node (prevailing_node);
+ }
+ gcc_assert (!vnode->finalized || prevailing_node->finalized);
+ gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
+
+ /* Finally remove the replaced node. */
+ varpool_remove_node (vnode);
+}
+
/* Merge two variable or function symbol table entries PREVAILING and ENTRY.
Return false if the symbols are not fully compatible and a diagnostic
should be emitted. */
static bool
lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
{
- if (!TREE_STATIC (e->decl))
+ /* The C++ frontend ends up neither setting TREE_STATIC nor
+ DECL_EXTERNAL on virtual methods but only TREE_PUBLIC.
+ So do not reject !TREE_STATIC here but only DECL_EXTERNAL. */
+ if (DECL_EXTERNAL (e->decl))
return false;
/* For functions we need a non-discarded body. */
static void
lto_symtab_resolve_symbols (void **slot)
{
- lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
+ lto_symtab_entry_t e;
lto_symtab_entry_t prevailing = NULL;
- /* If the chain is already resolved there is nothing to do. */
+ /* Always set e->node so that edges are updated to reflect decl merging. */
+ for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+ {
+ if (TREE_CODE (e->decl) == FUNCTION_DECL)
+ e->node = cgraph_get_node (e->decl);
+ else if (TREE_CODE (e->decl) == VAR_DECL)
+ e->vnode = varpool_get_node (e->decl);
+ }
+
+ e = (lto_symtab_entry_t) *slot;
+
+ /* If the chain is already resolved there is nothing else to do. */
if (e->resolution != LDPR_UNKNOWN)
return;
/* Find the single non-replaceable prevailing symbol and
diagnose ODR violations. */
- for (; e; e = e->next)
+ for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
{
- if (TREE_CODE (e->decl) == FUNCTION_DECL)
- e->node = cgraph_get_node (e->decl);
-
if (!lto_symtab_resolve_can_prevail_p (e))
{
e->resolution = LDPR_RESOLVED_IR;
while (!prevailing->node
&& prevailing->next)
prevailing = prevailing->next;
+ if (TREE_CODE (prevailing->decl) == VAR_DECL)
+ while (!prevailing->vnode
+ && prevailing->next)
+ prevailing = prevailing->next;
/* We do not stream varpool nodes, so the first decl has to
be good enough for now.
??? For QOI choose a variable with readonly initializer
lto_symtab_merge_decls_2 (slot);
/* Drop all but the prevailing decl from the symtab. */
- if (TREE_CODE (prevailing->decl) != FUNCTION_DECL)
+ if (TREE_CODE (prevailing->decl) != FUNCTION_DECL
+ && TREE_CODE (prevailing->decl) != VAR_DECL)
prevailing->next = NULL;
return 1;
if (!prevailing->next)
return 1;
- gcc_assert (TREE_CODE (prevailing->decl) == FUNCTION_DECL);
-
/* Replace the cgraph node of each entry with the prevailing one. */
for (e = prevailing->next; e; e = e->next)
{
if (e->node != NULL)
- lto_cgraph_replace_node (e->node, prevailing->node);
+ {
+ if (e->node->decl != e->decl && e->node->same_body)
+ {
+ struct cgraph_node *alias;
+
+ for (alias = e->node->same_body; alias; alias = alias->next)
+ if (alias->decl == e->decl)
+ break;
+ if (alias)
+ {
+ cgraph_remove_same_body_alias (alias);
+ continue;
+ }
+ }
+ lto_cgraph_replace_node (e->node, prevailing->node);
+ }
+ if (e->vnode != NULL)
+ lto_varpool_replace_node (e->vnode, prevailing->vnode);
}
/* Drop all but the prevailing decl from the symtab. */