summaryrefslogtreecommitdiff
path: root/gcc/lto-symtab.c
diff options
context:
space:
mode:
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-14 14:14:44 +0000
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-14 14:14:44 +0000
commitbc0ed27cfa8d09e9ea1060918377d3d2b205478e (patch)
tree3d83178500a3538048d92b6df95e7c2182d671f7 /gcc/lto-symtab.c
parent9c03157769e0ce3c58c191dd898eb6e9726912a3 (diff)
downloadgcc-bc0ed27cfa8d09e9ea1060918377d3d2b205478e.tar.gz
2009-10-14 Richard Guenther <rguenther@suse.de>
* lto-symtab.c (lto_symtab_compatible): Fold in ... (lto_symtab_merge): ... here. Rewrite both to take the prevailing and a to-be-merged entry and to queue diagnostics properly. (lto_symtab_resolve_replaceable_p): New predicate for symbol resolution. (lto_symtab_resolve_can_prevail_p): Likewise. (lto_symtab_resolve_symbols): Rewrite. Fold in code that handles merging commons by choosing the largest decl. Fold in code that gives ODR errors. (lto_symtab_merge_decls_2): Simplify a lot. Emit queued diagnostics here. (lto_symtab_merge_decls_1): Re-structure. Deal with the case of no prevailing decl here. Diagnose mismatches in object types here. Drop all but the prevailing decls. (lto_symtab_prevailing_decl): Return the single prevailing decl. * lto-streamer-in.c (lto_input_tree_ref): Deal with VIEW_CONVERT_EXPRs in decl slots. Unshare the tree in this case. lto/ * lto.c (lto_fixup_tree): In case the prevailing decl is not compatible with the one we replace wrap it around a VIEW_CONVERT_EXPR. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152768 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/lto-symtab.c')
-rw-r--r--gcc/lto-symtab.c756
1 files changed, 362 insertions, 394 deletions
diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c
index 2a0783a12be..b2fb9629943 100644
--- a/gcc/lto-symtab.c
+++ b/gcc/lto-symtab.c
@@ -109,6 +109,79 @@ lto_symtab_maybe_init_hash_table (void)
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
@@ -160,42 +233,75 @@ maybe_merge_incomplete_and_complete_type (tree type1, tree type2)
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
@@ -214,70 +320,27 @@ lto_symtab_compatible (tree old_decl, tree new_decl)
??? 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. */
@@ -290,213 +353,55 @@ lto_symtab_compatible (tree old_decl, tree new_decl)
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
@@ -506,114 +411,119 @@ static void
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. */
@@ -621,33 +531,105 @@ lto_symtab_fixup_var_decls (void **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;
}
@@ -685,21 +667,7 @@ lto_symtab_prevailing_decl (tree decl)
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. */