lto_symtab_entry_eq, NULL);
}
+/* Registers DECL with the LTO symbol table as having resolution RESOLUTION
+ and read from FILE_DATA. */
+
+void
+lto_symtab_register_decl (tree decl,
+ ld_plugin_symbol_resolution_t resolution,
+ struct lto_file_decl_data *file_data)
+{
+ lto_symtab_entry_t new_entry;
+ void **slot;
+
+ /* Check that declarations reaching this function do not have
+ properties inconsistent with having external linkage. If any of
+ these asertions fail, then the object file reader has failed to
+ detect these cases and issue appropriate error messages. */
+ gcc_assert (decl
+ && TREE_PUBLIC (decl)
+ && (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ && DECL_ASSEMBLER_NAME_SET_P (decl));
+ if (TREE_CODE (decl) == VAR_DECL
+ && DECL_INITIAL (decl))
+ gcc_assert (!DECL_EXTERNAL (decl)
+ || (TREE_STATIC (decl) && TREE_READONLY (decl)));
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ gcc_assert (!DECL_ABSTRACT (decl));
+
+ new_entry = GGC_CNEW (struct lto_symtab_entry_def);
+ new_entry->id = DECL_ASSEMBLER_NAME (decl);
+ new_entry->decl = decl;
+ new_entry->resolution = resolution;
+ new_entry->file_data = file_data;
+
+ lto_symtab_maybe_init_hash_table ();
+ slot = htab_find_slot (lto_symtab_identifiers, new_entry, INSERT);
+ new_entry->next = (lto_symtab_entry_t) *slot;
+ *slot = new_entry;
+}
+
+/* Get the lto_symtab_entry_def struct associated with ID
+ if there is one. */
+
+static lto_symtab_entry_t
+lto_symtab_get (tree id)
+{
+ struct lto_symtab_entry_def temp;
+ void **slot;
+
+ lto_symtab_maybe_init_hash_table ();
+ temp.id = id;
+ slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT);
+ return slot ? (lto_symtab_entry_t) *slot : NULL;
+}
+
+/* Get the linker resolution for DECL. */
+
+enum ld_plugin_symbol_resolution
+lto_symtab_get_resolution (tree decl)
+{
+ lto_symtab_entry_t e;
+
+ gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
+
+ e = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
+ while (e && e->decl != decl)
+ e = e->next;
+ if (!e)
+ return LDPR_UNKNOWN;
+
+ return e->resolution;
+}
+
+
static bool maybe_merge_incomplete_and_complete_type (tree, tree);
/* Try to merge an incomplete type INCOMPLETE with a complete type
return res;
}
-/* Check if OLD_DECL and NEW_DECL are compatible. */
+/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
+ all edges and removing the old node. */
-static bool
-lto_symtab_compatible (tree old_decl, tree new_decl)
+static void
+lto_cgraph_replace_node (struct cgraph_node *node,
+ struct cgraph_node *prevailing_node)
{
- tree old_type, new_type;
+ struct cgraph_edge *e, *next;
- if (TREE_CODE (old_decl) != TREE_CODE (new_decl))
+ /* Merge node flags. */
+ if (node->needed)
+ cgraph_mark_needed_node (prevailing_node);
+ if (node->reachable)
+ cgraph_mark_reachable_node (prevailing_node);
+ if (node->address_taken)
{
- switch (TREE_CODE (new_decl))
- {
- case VAR_DECL:
- gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL);
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "function %qD redeclared as variable", new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl),
- "previously declared here");
- return false;
+ gcc_assert (!prevailing_node->global.inlined_to);
+ cgraph_mark_address_taken_node (prevailing_node);
+ }
- case FUNCTION_DECL:
- gcc_assert (TREE_CODE (old_decl) == VAR_DECL);
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "variable %qD redeclared as function", new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl),
- "previously declared here");
- return false;
+ /* Redirect all incoming edges. */
+ for (e = node->callers; e; e = next)
+ {
+ next = e->next_caller;
+ cgraph_redirect_edge_callee (e, prevailing_node);
+ }
- default:
- gcc_unreachable ();
- }
+ /* There are not supposed to be any outgoing edges from a node we
+ replace. Still this can happen for multiple instances of weak
+ functions. */
+ for (e = node->callees; e; e = next)
+ {
+ next = e->next_callee;
+ cgraph_remove_edge (e);
}
- if (TREE_CODE (new_decl) == FUNCTION_DECL)
+ /* Finally remove the replaced node. */
+ cgraph_remove_node (node);
+}
+
+/* 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_merge (lto_symtab_entry_t prevailing, lto_symtab_entry_t entry)
+{
+ tree prevailing_decl = prevailing->decl;
+ tree decl = entry->decl;
+ tree prevailing_type, type;
+ struct cgraph_node *node;
+
+ /* Merge decl state in both directions, we may still end up using
+ the new decl. */
+ TREE_ADDRESSABLE (prevailing_decl) |= TREE_ADDRESSABLE (decl);
+ TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (prevailing_decl);
+
+ /* Replace a cgraph node of entry with the prevailing one. */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && (node = cgraph_get_node (decl)) != NULL)
+ lto_cgraph_replace_node (node, cgraph_get_node (prevailing_decl));
+
+ /* The linker may ask us to combine two incompatible symbols.
+ Detect this case and notify the caller of required diagnostics. */
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
{
- if (!gimple_types_compatible_p (TREE_TYPE (old_decl),
- TREE_TYPE (new_decl)))
+ if (!gimple_types_compatible_p (TREE_TYPE (prevailing_decl),
+ TREE_TYPE (decl)))
/* If we don't have a merged type yet...sigh. The linker
wouldn't complain if the types were mismatched, so we
probably shouldn't either. Just use the type from
??? In principle all types involved in the two decls should
be merged forcefully, for example without considering type or
field names. */
- old_type = TREE_TYPE (old_decl);
- new_type = TREE_TYPE (new_decl);
-
- if (DECL_EXTERNAL (old_decl) || DECL_EXTERNAL (new_decl))
- maybe_merge_incomplete_and_complete_type (old_type, new_type);
- else if (POINTER_TYPE_P (old_type)
- && POINTER_TYPE_P (new_type))
- maybe_merge_incomplete_and_complete_type (TREE_TYPE (old_type),
- TREE_TYPE (new_type));
-
- /* For array types we have to accept external declarations with
- different sizes than the actual definition (164.gzip).
- ??? We could emit a warning here. */
- if (TREE_CODE (old_type) == TREE_CODE (new_type)
- && TREE_CODE (old_type) == ARRAY_TYPE
- && COMPLETE_TYPE_P (old_type)
- && COMPLETE_TYPE_P (new_type)
- && tree_int_cst_compare (TYPE_SIZE (old_type),
- TYPE_SIZE (new_type)) != 0
- && gimple_types_compatible_p (TREE_TYPE (old_type),
- TREE_TYPE (new_type)))
- {
- /* If only one is external use the type of the non-external decl.
- Else use the larger one and also adjust the decl size.
- ??? Directional merging would allow us to simply pick the
- larger one instead of rewriting it. */
- if (DECL_EXTERNAL (old_decl) ^ DECL_EXTERNAL (new_decl))
- {
- if (DECL_EXTERNAL (old_decl))
- TREE_TYPE (old_decl) = new_type;
- else if (DECL_EXTERNAL (new_decl))
- TREE_TYPE (new_decl) = old_type;
- }
- else
- {
- if (tree_int_cst_compare (TYPE_SIZE (old_type),
- TYPE_SIZE (new_type)) < 0)
- {
- TREE_TYPE (old_decl) = new_type;
- DECL_SIZE (old_decl) = DECL_SIZE (new_decl);
- DECL_SIZE_UNIT (old_decl) = DECL_SIZE_UNIT (new_decl);
- }
- else
- {
- TREE_TYPE (new_decl) = old_type;
- DECL_SIZE (new_decl) = DECL_SIZE (old_decl);
- DECL_SIZE_UNIT (new_decl) = DECL_SIZE_UNIT (old_decl);
- }
- }
- }
+ prevailing_type = TREE_TYPE (prevailing_decl);
+ type = TREE_TYPE (decl);
+
+ /* If the types are structurally equivalent we can use the knowledge
+ that both bind to the same symbol to complete incomplete types
+ of external declarations or of pointer targets.
+ ??? We should apply this recursively to aggregate members here
+ and get rid of the completion in gimple_types_compatible_p. */
+ if (DECL_EXTERNAL (prevailing_decl) || DECL_EXTERNAL (decl))
+ maybe_merge_incomplete_and_complete_type (prevailing_type, type);
+ else if (POINTER_TYPE_P (prevailing_type)
+ && POINTER_TYPE_P (type))
+ maybe_merge_incomplete_and_complete_type (TREE_TYPE (prevailing_type),
+ TREE_TYPE (type));
/* We can tolerate differences in type qualification, the
qualification of the prevailing definition will prevail. */
- old_type = TYPE_MAIN_VARIANT (TREE_TYPE (old_decl));
- new_type = TYPE_MAIN_VARIANT (TREE_TYPE (new_decl));
- if (!gimple_types_compatible_p (old_type, new_type))
- {
- if (warning_at (DECL_SOURCE_LOCATION (new_decl), 0,
- "type of %qD does not match original declaration",
- new_decl))
- inform (DECL_SOURCE_LOCATION (old_decl),
- "previously declared here");
- return false;
- }
+ prevailing_type = TYPE_MAIN_VARIANT (TREE_TYPE (prevailing_decl));
+ type = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
+ if (!gimple_types_compatible_p (prevailing_type, type))
+ return false;
/* ??? We might want to emit a warning here if type qualification
differences were spotted. Do not do this unconditionally though. */
mode the linker wouldn't complain either. Just emit warnings. */
/* Report a warning if user-specified alignments do not match. */
- if ((DECL_USER_ALIGN (old_decl) && DECL_USER_ALIGN (new_decl))
- && DECL_ALIGN (old_decl) != DECL_ALIGN (new_decl))
- {
- warning_at (DECL_SOURCE_LOCATION (new_decl), 0,
- "alignment of %qD does not match original declaration",
- new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
- return false;
- }
+ if ((DECL_USER_ALIGN (prevailing_decl) && DECL_USER_ALIGN (decl))
+ && DECL_ALIGN (prevailing_decl) < DECL_ALIGN (decl))
+ return false;
return true;
}
-/* Registers DECL with the LTO symbol table as having resolution RESOLUTION
- and read from FILE_DATA. */
-
-void
-lto_symtab_register_decl (tree decl,
- ld_plugin_symbol_resolution_t resolution,
- struct lto_file_decl_data *file_data)
-{
- lto_symtab_entry_t new_entry;
- void **slot;
-
- /* Check that declarations reaching this function do not have
- properties inconsistent with having external linkage. If any of
- these asertions fail, then the object file reader has failed to
- detect these cases and issue appropriate error messages. */
- gcc_assert (decl
- && TREE_PUBLIC (decl)
- && (TREE_CODE (decl) == VAR_DECL
- || TREE_CODE (decl) == FUNCTION_DECL)
- && DECL_ASSEMBLER_NAME_SET_P (decl));
- if (TREE_CODE (decl) == VAR_DECL
- && DECL_INITIAL (decl))
- gcc_assert (!DECL_EXTERNAL (decl)
- || (TREE_STATIC (decl) && TREE_READONLY (decl)));
- if (TREE_CODE (decl) == FUNCTION_DECL)
- gcc_assert (!DECL_ABSTRACT (decl));
-
- new_entry = GGC_CNEW (struct lto_symtab_entry_def);
- new_entry->id = DECL_ASSEMBLER_NAME (decl);
- new_entry->decl = decl;
- new_entry->resolution = resolution;
- new_entry->file_data = file_data;
-
- lto_symtab_maybe_init_hash_table ();
- slot = htab_find_slot (lto_symtab_identifiers, new_entry, INSERT);
- new_entry->next = (lto_symtab_entry_t) *slot;
- *slot = new_entry;
-}
-
-/* Get the lto_symtab_entry_def struct associated with ID
- if there is one. */
+/* Return true if the symtab entry E can be replaced by another symtab
+ entry. */
-static lto_symtab_entry_t
-lto_symtab_get (tree id)
+static bool
+lto_symtab_resolve_replaceable_p (lto_symtab_entry_t e)
{
- struct lto_symtab_entry_def temp;
- void **slot;
-
- lto_symtab_maybe_init_hash_table ();
- temp.id = id;
- slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT);
- return slot ? (lto_symtab_entry_t) *slot : NULL;
-}
+ if (DECL_EXTERNAL (e->decl)
+ || DECL_COMDAT (e->decl)
+ || DECL_WEAK (e->decl))
+ return true;
-/* Get the linker resolution for DECL. */
+ if (TREE_CODE (e->decl) == VAR_DECL)
+ return (DECL_COMMON (e->decl)
+ || (!flag_no_common && !DECL_INITIAL (e->decl)));
-enum ld_plugin_symbol_resolution
-lto_symtab_get_resolution (tree decl)
-{
- lto_symtab_entry_t e;
-
- gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
-
- e = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
- while (e && e->decl != decl)
- e = e->next;
- if (!e)
- return LDPR_UNKNOWN;
-
- return e->resolution;
+ return false;
}
-/* Replace the cgraph node OLD_NODE with NEW_NODE in the cgraph, merging
- all edges and removing the old node. */
+/* Return true if the symtab entry E can be the prevailing one. */
-static void
-lto_cgraph_replace_node (struct cgraph_node *old_node,
- struct cgraph_node *new_node)
+static bool
+lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
{
- struct cgraph_edge *e, *next;
-
- /* Merge node flags. */
- if (old_node->needed)
- cgraph_mark_needed_node (new_node);
- if (old_node->reachable)
- cgraph_mark_reachable_node (new_node);
- if (old_node->address_taken)
- {
- gcc_assert (!new_node->global.inlined_to);
- cgraph_mark_address_taken_node (new_node);
- }
-
- /* Redirect all incoming edges. */
- for (e = old_node->callers; e; e = next)
- {
- next = e->next_caller;
- cgraph_redirect_edge_callee (e, new_node);
- }
-
- /* There are not supposed to be any outgoing edges from a node we
- replace. Still this can happen for multiple instances of weak
- functions.
- ??? For now do what the old code did. Do not create edges for them. */
- for (e = old_node->callees; e; e = next)
- {
- next = e->next_callee;
- cgraph_remove_edge (e);
- }
-
- /* Finally remove the replaced node. */
- cgraph_remove_node (old_node);
-}
-
-/* Merge two variable or function symbol table entries ENTRY1 and ENTRY2.
- Return the prevailing one or NULL if a merge is not possible. */
+ struct cgraph_node *node;
-static lto_symtab_entry_t
-lto_symtab_merge (lto_symtab_entry_t entry1, lto_symtab_entry_t entry2)
-{
- tree old_decl = entry1->decl;
- tree new_decl = entry2->decl;
- ld_plugin_symbol_resolution_t old_resolution = entry1->resolution;
- ld_plugin_symbol_resolution_t new_resolution = entry2->resolution;
- struct cgraph_node *old_node = NULL;
- struct cgraph_node *new_node = NULL;
-
- /* Give ODR violation errors. */
- if (new_resolution == LDPR_PREVAILING_DEF
- || new_resolution == LDPR_PREVAILING_DEF_IRONLY)
- {
- if ((old_resolution == LDPR_PREVAILING_DEF
- || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
- && (old_resolution != new_resolution || flag_no_common))
- {
- error_at (DECL_SOURCE_LOCATION (new_decl),
- "%qD has already been defined", new_decl);
- inform (DECL_SOURCE_LOCATION (old_decl),
- "previously defined here");
- return NULL;
- }
- }
-
- /* The linker may ask us to combine two incompatible symbols. */
- if (!lto_symtab_compatible (old_decl, new_decl))
- return NULL;
-
- if (TREE_CODE (old_decl) == FUNCTION_DECL)
- old_node = cgraph_get_node (old_decl);
- if (TREE_CODE (new_decl) == FUNCTION_DECL)
- new_node = cgraph_get_node (new_decl);
-
- /* Merge decl state in both directions, we may still end up using
- the new decl. */
- TREE_ADDRESSABLE (old_decl) |= TREE_ADDRESSABLE (new_decl);
- TREE_ADDRESSABLE (new_decl) |= TREE_ADDRESSABLE (old_decl);
+ if (!TREE_STATIC (e->decl))
+ return false;
- gcc_assert (new_resolution != LDPR_UNKNOWN
- && new_resolution != LDPR_UNDEF
- && old_resolution != LDPR_UNKNOWN
- && old_resolution != LDPR_UNDEF);
+ /* For functions we need a non-discarded body. */
+ if (TREE_CODE (e->decl) == FUNCTION_DECL)
+ return ((node = cgraph_get_node (e->decl))
+ && node->analyzed);
- if (new_resolution == LDPR_PREVAILING_DEF
- || new_resolution == LDPR_PREVAILING_DEF_IRONLY
- || (!old_node && new_node))
- {
- gcc_assert ((!old_node && new_node)
- || old_resolution == LDPR_PREEMPTED_IR
- || old_resolution == LDPR_RESOLVED_IR
- || (old_resolution == new_resolution && !flag_no_common));
- if (old_node)
- lto_cgraph_replace_node (old_node, new_node);
- /* Choose new_decl, entry2. */
- return entry2;
- }
+ /* A variable should have a size. */
+ else if (TREE_CODE (e->decl) == VAR_DECL)
+ return (DECL_SIZE (e->decl) != NULL_TREE
+ /* The C++ frontend retains TREE_STATIC on the declaration
+ of foo_ in struct Foo { static Foo *foo_; }; but it is
+ not a definition. g++.dg/lto/20090315_0.C. */
+ && !DECL_EXTERNAL (e->decl));
- if (new_resolution == LDPR_PREEMPTED_REG
- || new_resolution == LDPR_RESOLVED_EXEC
- || new_resolution == LDPR_RESOLVED_DYN)
- gcc_assert (old_resolution == LDPR_PREEMPTED_REG
- || old_resolution == LDPR_RESOLVED_EXEC
- || old_resolution == LDPR_RESOLVED_DYN);
-
- if (new_resolution == LDPR_PREEMPTED_IR
- || new_resolution == LDPR_RESOLVED_IR)
- gcc_assert (old_resolution == LDPR_PREVAILING_DEF
- || old_resolution == LDPR_PREVAILING_DEF_IRONLY
- || old_resolution == LDPR_PREEMPTED_IR
- || old_resolution == LDPR_RESOLVED_IR);
-
- if (new_node)
- lto_cgraph_replace_node (new_node, old_node);
-
- /* Choose old_decl, entry1. */
- return entry1;
+ gcc_unreachable ();
}
/* Resolve the symbol with the candidates in the chain *SLOT and store
lto_symtab_resolve_symbols (void **slot)
{
lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
+ lto_symtab_entry_t prevailing = NULL;
/* If the chain is already resolved there is nothing to do. */
if (e->resolution != LDPR_UNKNOWN)
return;
- /* This is a poor mans resolver. */
+ /* Find the single non-replaceable prevailing symbol and
+ diagnose ODR violations. */
for (; e; e = e->next)
{
- gcc_assert (e->resolution == LDPR_UNKNOWN);
- if (DECL_EXTERNAL (e->decl)
- || (TREE_CODE (e->decl) == FUNCTION_DECL
- && !cgraph_get_node (e->decl)))
- e->resolution = LDPR_RESOLVED_IR;
- else
+ if (!lto_symtab_resolve_can_prevail_p (e))
+ {
+ e->resolution = LDPR_RESOLVED_IR;
+ continue;
+ }
+
+ /* Set a default resolution - the final prevailing one will get
+ adjusted later. */
+ e->resolution = LDPR_PREEMPTED_IR;
+ if (!lto_symtab_resolve_replaceable_p (e))
+ {
+ if (prevailing)
+ {
+ error_at (DECL_SOURCE_LOCATION (e->decl),
+ "%qD has already been defined", e->decl);
+ inform (DECL_SOURCE_LOCATION (prevailing->decl),
+ "previously defined here");
+ }
+ prevailing = e;
+ }
+ }
+ if (prevailing)
+ goto found;
+
+ /* Do a second round choosing one from the replaceable prevailing decls. */
+ for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+ {
+ if (e->resolution != LDPR_PREEMPTED_IR)
+ continue;
+
+ /* Choose the first function that can prevail as prevailing. */
+ if (TREE_CODE (e->decl) == FUNCTION_DECL)
{
- if (TREE_READONLY (e->decl))
- e->resolution = LDPR_PREVAILING_DEF_IRONLY;
- else
- e->resolution = LDPR_PREVAILING_DEF;
+ prevailing = e;
+ break;
}
+
+ /* From variables that can prevail choose the largest one. */
+ if (!prevailing
+ || tree_int_cst_lt (DECL_SIZE (prevailing->decl),
+ DECL_SIZE (e->decl)))
+ prevailing = e;
}
+
+ if (!prevailing)
+ return;
+
+found:
+ if (TREE_CODE (prevailing->decl) == VAR_DECL
+ && TREE_READONLY (prevailing->decl))
+ prevailing->resolution = LDPR_PREVAILING_DEF_IRONLY;
+ else
+ prevailing->resolution = LDPR_PREVAILING_DEF;
}
-/* Merge one symbol table chain to a (set of) prevailing decls. */
+/* Merge all decls in the symbol table chain to the prevailing decl and
+ issue diagnostics about type mismatches. */
static void
lto_symtab_merge_decls_2 (void **slot)
{
- lto_symtab_entry_t e2, e1;
+ lto_symtab_entry_t prevailing, e;
+ VEC(tree, heap) *mismatches = NULL;
+ unsigned i;
+ tree decl;
+ bool diagnosed_p = false;
/* Nothing to do for a single entry. */
- e1 = (lto_symtab_entry_t) *slot;
- if (!e1->next)
+ prevailing = (lto_symtab_entry_t) *slot;
+ if (!prevailing->next)
return;
- /* Try to merge each entry with each other entry. In case of a
- single prevailing decl this is linear. */
-restart:
- for (; e1; e1 = e1->next)
- for (e2 = e1->next; e2; e2 = e2->next)
- {
- lto_symtab_entry_t prevailing = lto_symtab_merge (e1, e2);
- if (prevailing == e1)
- {
- lto_symtab_entry_t tmp = prevailing;
- while (tmp->next != e2)
- tmp = tmp->next;
- tmp->next = e2->next;
- e2->next = NULL;
- e2 = tmp;
- }
- else if (prevailing == e2)
- {
- lto_symtab_entry_t tmp = (lto_symtab_entry_t) *slot;
- if (tmp == e1)
- {
- *slot = e1->next;
- tmp = e1->next;
- }
- else
- {
- while (tmp->next != e1)
- tmp = tmp->next;
- tmp->next = e1->next;
- }
- e1->next = NULL;
- e1 = tmp;
- goto restart;
- }
- }
-}
-
-/* Fixup the chain of prevailing variable decls *SLOT that are commonized
- during link-time. */
+ /* Try to merge each entry with the prevailing one. */
+ for (e = prevailing->next; e; e = e->next)
+ {
+ if (!lto_symtab_merge (prevailing, e))
+ VEC_safe_push (tree, heap, mismatches, e->decl);
+ }
+ if (VEC_empty (tree, mismatches))
+ return;
-static void
-lto_symtab_fixup_var_decls (void **slot)
-{
- lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
- tree size = bitsize_zero_node;
-
- /* Find the largest prevailing decl and move it to the front of the chain.
- This is the decl we will output as representative for the common
- section. */
- size = bitsize_zero_node;
- if (e->resolution == LDPR_PREVAILING_DEF_IRONLY
- || e->resolution == LDPR_PREVAILING_DEF)
- size = DECL_SIZE (e->decl);
- for (; e->next;)
+ /* Diagnose all mismatched re-declarations. */
+ for (i = 0; VEC_iterate (tree, mismatches, i, decl); ++i)
{
- lto_symtab_entry_t next = e->next;
- if ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
- || next->resolution == LDPR_PREVAILING_DEF)
- && tree_int_cst_lt (size, DECL_SIZE (next->decl)))
+ if (!gimple_types_compatible_p (TREE_TYPE (prevailing->decl),
+ TREE_TYPE (decl)))
+ diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0,
+ "type of %qD does not match original "
+ "declaration", decl);
+
+ else if ((DECL_USER_ALIGN (prevailing->decl) && DECL_USER_ALIGN (decl))
+ && DECL_ALIGN (prevailing->decl) < DECL_ALIGN (decl))
{
- size = DECL_SIZE (next->decl);
- e->next = next->next;
- next->next = (lto_symtab_entry_t) *slot;
- *slot = next;
+ diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0,
+ "alignment of %qD is bigger than "
+ "original declaration", decl);
}
- else
- e = next;
}
+ if (diagnosed_p)
+ inform (DECL_SOURCE_LOCATION (prevailing->decl),
+ "previously declared here");
- /* Mark everything apart from the first var as written out. */
- e = (lto_symtab_entry_t) *slot;
- for (e = e->next; e; e = e->next)
- TREE_ASM_WRITTEN (e->decl) = true;
+ VEC_free (tree, heap, mismatches);
}
/* Helper to process the decl chain for the symbol table entry *SLOT. */
static int
lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
{
- lto_symtab_entry_t e;
+ lto_symtab_entry_t e, prevailing;
+ bool diagnosed_p = false;
- /* Compute the symbol resolutions. */
+ /* Compute the symbol resolutions. This is a no-op when using the
+ linker plugin. */
lto_symtab_resolve_symbols (slot);
- /* Register and adjust types of the entries. */
- for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
- TREE_TYPE (e->decl) = gimple_register_type (TREE_TYPE (e->decl));
+ /* Find the prevailing decl. */
+ for (prevailing = (lto_symtab_entry_t) *slot;
+ prevailing
+ && prevailing->resolution != LDPR_PREVAILING_DEF_IRONLY
+ && prevailing->resolution != LDPR_PREVAILING_DEF;
+ prevailing = prevailing->next)
+ ;
+
+ /* Assert it's the only one. */
+ if (prevailing)
+ for (e = prevailing->next; e; e = e->next)
+ gcc_assert (e->resolution != LDPR_PREVAILING_DEF_IRONLY
+ && e->resolution != LDPR_PREVAILING_DEF);
+
+ /* If there's not a prevailing symbol yet it's an external reference.
+ Happens a lot during ltrans. Choose the first symbol with a
+ cgraph or a varpool node. */
+ if (!prevailing)
+ {
+ prevailing = (lto_symtab_entry_t) *slot;
+ /* For functions choose one with a cgraph node. */
+ if (TREE_CODE (prevailing->decl) == FUNCTION_DECL)
+ while (!cgraph_get_node (prevailing->decl)
+ && 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
+ if there is one. This matches C++
+ struct Foo { static const int i = 1; }; without a real
+ definition. */
+ if (TREE_CODE (prevailing->decl) == VAR_DECL)
+ while (!(TREE_READONLY (prevailing->decl)
+ && DECL_INITIAL (prevailing->decl))
+ && prevailing->next)
+ prevailing = prevailing->next;
+ }
- /* Merge the chain to a (hopefully) single prevailing decl. */
- lto_symtab_merge_decls_2 (slot);
+ /* Move it first in the list. */
+ if ((lto_symtab_entry_t) *slot != prevailing)
+ {
+ for (e = (lto_symtab_entry_t) *slot; e->next != prevailing; e = e->next)
+ ;
+ e->next = prevailing->next;
+ prevailing->next = (lto_symtab_entry_t) *slot;
+ *slot = (void *) prevailing;
+ }
- /* ??? Ideally we should delay all diagnostics until this point to
- avoid duplicates. */
+ /* Record the prevailing variable. */
+ if (TREE_CODE (prevailing->decl) == VAR_DECL)
+ VEC_safe_push (tree, gc, lto_global_var_decls, prevailing->decl);
- /* All done for FUNCTION_DECLs. */
- e = (lto_symtab_entry_t) *slot;
- if (TREE_CODE (e->decl) == FUNCTION_DECL)
- return 1;
+ /* Diagnose mismatched objects. */
+ for (e = prevailing->next; e; e = e->next)
+ {
+ if (TREE_CODE (prevailing->decl) == TREE_CODE (e->decl))
+ continue;
+
+ switch (TREE_CODE (prevailing->decl))
+ {
+ case VAR_DECL:
+ gcc_assert (TREE_CODE (e->decl) == FUNCTION_DECL);
+ error_at (DECL_SOURCE_LOCATION (e->decl),
+ "variable %qD redeclared as function", prevailing->decl);
+ break;
- /* Fixup variables in case there are multiple prevailing ones. */
- if (e->next)
- lto_symtab_fixup_var_decls (slot);
+ case FUNCTION_DECL:
+ gcc_assert (TREE_CODE (e->decl) == VAR_DECL);
+ error_at (DECL_SOURCE_LOCATION (e->decl),
+ "function %qD redeclared as variable", prevailing->decl);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
- /* Insert all variable decls into the global variable decl vector. */
+ diagnosed_p = true;
+ }
+ if (diagnosed_p)
+ inform (DECL_SOURCE_LOCATION (prevailing->decl),
+ "previously declared here");
+
+ /* Register and adjust types of the entries. */
for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
- VEC_safe_push (tree, gc, lto_global_var_decls, e->decl);
+ TREE_TYPE (e->decl) = gimple_register_type (TREE_TYPE (e->decl));
+
+ /* Merge the chain to the single prevailing decl and diagnose
+ mismatches. */
+ lto_symtab_merge_decls_2 (slot);
+
+ /* Drop all but the prevailing decl from the symtab. */
+ prevailing->next = NULL;
return 1;
}
if (!ret)
return NULL_TREE;
- /* If there is only one candidate return it. */
- if (ret->next == NULL)
- return ret->decl;
-
- /* If there are multiple decls to choose from find the one we merged
- with and return that. */
- while (ret)
- {
- if (gimple_types_compatible_p (TREE_TYPE (decl), TREE_TYPE (ret->decl)))
- return ret->decl;
-
- ret = ret->next;
- }
-
- gcc_unreachable ();
+ return ret->decl;
}
/* Remove any storage used to store resolution of DECL. */