aboutsummaryrefslogtreecommitdiff
path: root/gcc/lto-symtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/lto-symtab.c')
-rw-r--r--gcc/lto-symtab.c810
1 files changed, 366 insertions, 444 deletions
diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c
index 2a0783a12be..642b6235d90 100644
--- a/gcc/lto-symtab.c
+++ b/gcc/lto-symtab.c
@@ -41,6 +41,9 @@ struct GTY(()) lto_symtab_entry_def
tree id;
/* The symbol table entry, a DECL. */
tree decl;
+ /* The cgraph node if decl is a function decl. Filled in during the
+ merging process. */
+ struct cgraph_node *node;
/* LTO file-data and symbol resolution for this decl. */
struct lto_file_decl_data * GTY((skip (""))) file_data;
enum ld_plugin_symbol_resolution resolution;
@@ -109,200 +112,6 @@ lto_symtab_maybe_init_hash_table (void)
lto_symtab_entry_eq, NULL);
}
-static bool maybe_merge_incomplete_and_complete_type (tree, tree);
-
-/* Try to merge an incomplete type INCOMPLETE with a complete type
- COMPLETE of same kinds.
- Return true if they were merged, false otherwise. */
-
-static bool
-merge_incomplete_and_complete_type (tree incomplete, tree complete)
-{
- /* For merging array types do some extra sanity checking. */
- if (TREE_CODE (incomplete) == ARRAY_TYPE
- && !maybe_merge_incomplete_and_complete_type (TREE_TYPE (incomplete),
- TREE_TYPE (complete))
- && !gimple_types_compatible_p (TREE_TYPE (incomplete),
- TREE_TYPE (complete)))
- return false;
-
- /* ??? Ideally we would do this by means of a common canonical type, but
- that's difficult as we do not have links from the canonical type
- back to all its children. */
- gimple_force_type_merge (incomplete, complete);
-
- return true;
-}
-
-/* Try to merge a maybe complete / incomplete type pair TYPE1 and TYPE2.
- Return true if they were merged, false otherwise. */
-
-static bool
-maybe_merge_incomplete_and_complete_type (tree type1, tree type2)
-{
- bool res = false;
-
- if (TREE_CODE (type1) != TREE_CODE (type2))
- return false;
-
- if (!COMPLETE_TYPE_P (type1) && COMPLETE_TYPE_P (type2))
- res = merge_incomplete_and_complete_type (type1, type2);
- else if (COMPLETE_TYPE_P (type1) && !COMPLETE_TYPE_P (type2))
- res = merge_incomplete_and_complete_type (type2, type1);
-
- /* Recurse on pointer targets. */
- if (!res
- && POINTER_TYPE_P (type1)
- && POINTER_TYPE_P (type2))
- res = maybe_merge_incomplete_and_complete_type (TREE_TYPE (type1),
- TREE_TYPE (type2));
-
- return res;
-}
-
-/* Check if OLD_DECL and NEW_DECL are compatible. */
-
-static bool
-lto_symtab_compatible (tree old_decl, tree new_decl)
-{
- tree old_type, new_type;
-
- if (TREE_CODE (old_decl) != TREE_CODE (new_decl))
- {
- 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;
-
- 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;
-
- default:
- gcc_unreachable ();
- }
- }
-
- if (TREE_CODE (new_decl) == FUNCTION_DECL)
- {
- if (!gimple_types_compatible_p (TREE_TYPE (old_decl),
- TREE_TYPE (new_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
- whichever decl appears to be associated with the
- definition. If for some odd reason neither decl is, the
- older one wins. */
- (void) 0;
-
- return true;
- }
-
- /* Now we exclusively deal with VAR_DECLs. */
-
- /* Handle external declarations with incomplete type or pointed-to
- incomplete types by forcefully merging the types.
- ??? 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);
- }
- }
- }
-
- /* 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;
- }
-
- /* ??? We might want to emit a warning here if type qualification
- differences were spotted. Do not do this unconditionally though. */
-
- /* There is no point in comparing too many details of the decls here.
- The type compatibility checks or the completing of types has properly
- dealt with most issues. */
-
- /* The following should all not invoke fatal errors as in non-LTO
- 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;
- }
-
- return true;
-}
-
/* Registers DECL with the LTO symbol table as having resolution RESOLUTION
and read from FILE_DATA. */
@@ -335,7 +144,7 @@ lto_symtab_register_decl (tree 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;
@@ -375,128 +184,190 @@ lto_symtab_get_resolution (tree decl)
return e->resolution;
}
-/* Replace the cgraph node OLD_NODE with NEW_NODE in the cgraph, merging
+
+/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
all edges and removing the old node. */
static void
-lto_cgraph_replace_node (struct cgraph_node *old_node,
- struct cgraph_node *new_node)
+lto_cgraph_replace_node (struct cgraph_node *node,
+ struct cgraph_node *prevailing_node)
{
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)
+ if (node->needed)
+ cgraph_mark_needed_node (prevailing_node);
+ if (node->reachable)
+ cgraph_mark_reachable_node (prevailing_node);
+ if (node->address_taken)
{
- gcc_assert (!new_node->global.inlined_to);
- cgraph_mark_address_taken_node (new_node);
+ gcc_assert (!prevailing_node->global.inlined_to);
+ cgraph_mark_address_taken_node (prevailing_node);
}
/* Redirect all incoming edges. */
- for (e = old_node->callers; e; e = next)
+ for (e = node->callers; e; e = next)
{
next = e->next_caller;
- cgraph_redirect_edge_callee (e, new_node);
+ cgraph_redirect_edge_callee (e, prevailing_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)
+ functions. */
+ for (e = node->callees; e; e = next)
{
next = e->next_callee;
cgraph_remove_edge (e);
}
/* Finally remove the replaced node. */
- cgraph_remove_node (old_node);
+ cgraph_remove_node (node);
}
-/* Merge two variable or function symbol table entries ENTRY1 and ENTRY2.
- Return the prevailing one or NULL if a merge is not possible. */
+/* 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 lto_symtab_entry_t
-lto_symtab_merge (lto_symtab_entry_t entry1, lto_symtab_entry_t entry2)
+static bool
+lto_symtab_merge (lto_symtab_entry_t prevailing, lto_symtab_entry_t entry)
{
- 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)
+ tree prevailing_decl = prevailing->decl;
+ tree decl = entry->decl;
+ tree prevailing_type, type;
+
+ /* 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);
+
+ /* 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 (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
+ whichever decl appears to be associated with the
+ definition. If for some odd reason neither decl is, the
+ older one wins. */
+ (void) 0;
+
+ return true;
+ }
+
+ /* Now we exclusively deal with VAR_DECLs. */
+
+ /* Sharing a global symbol is a strong hint that two types are
+ compatible. We could use this information to complete
+ incomplete pointed-to types more aggressively here, ignoring
+ mismatches in both field and tag names. It's difficult though
+ to guarantee that this does not have side-effects on merging
+ more compatible types from other translation units though. */
+
+ /* We can tolerate differences in type qualification, the
+ qualification of the prevailing definition will prevail.
+ ??? In principle we might want to only warn for structurally
+ incompatible types here, but unless we have protective measures
+ for TBAA in place that would hide useful information. */
+ prevailing_type = TYPE_MAIN_VARIANT (TREE_TYPE (prevailing_decl));
+ type = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
+
+ /* We have to register and fetch canonical types here as the global
+ fixup process didn't yet run. */
+ prevailing_type = gimple_register_type (prevailing_type);
+ type = gimple_register_type (type);
+ if (prevailing_type != type)
{
- if ((old_resolution == LDPR_PREVAILING_DEF
- || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
- && (old_resolution != new_resolution || flag_no_common))
+ if (COMPLETE_TYPE_P (type))
+ return false;
+
+ /* If type is incomplete then avoid warnings in the cases
+ that TBAA handles just fine. */
+
+ if (TREE_CODE (prevailing_type) != TREE_CODE (type))
+ return false;
+
+ if (TREE_CODE (prevailing_type) == ARRAY_TYPE)
{
- 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;
+ tree tem1 = TREE_TYPE (prevailing_type);
+ tree tem2 = TREE_TYPE (type);
+ while (TREE_CODE (tem1) == ARRAY_TYPE
+ && TREE_CODE (tem2) == ARRAY_TYPE)
+ {
+ tem1 = TREE_TYPE (tem1);
+ tem2 = TREE_TYPE (tem2);
+ }
+
+ if (TREE_CODE (tem1) != TREE_CODE (tem2))
+ return false;
+
+ if (gimple_register_type (tem1) != gimple_register_type (tem2))
+ return false;
}
+
+ /* Fallthru. Compatible enough. */
}
- /* The linker may ask us to combine two incompatible symbols. */
- if (!lto_symtab_compatible (old_decl, new_decl))
- return NULL;
+ /* ??? We might want to emit a warning here if type qualification
+ differences were spotted. Do not do this unconditionally though. */
- 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);
+ /* There is no point in comparing too many details of the decls here.
+ The type compatibility checks or the completing of types has properly
+ dealt with most issues. */
- /* 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);
+ /* The following should all not invoke fatal errors as in non-LTO
+ mode the linker wouldn't complain either. Just emit warnings. */
- gcc_assert (new_resolution != LDPR_UNKNOWN
- && new_resolution != LDPR_UNDEF
- && old_resolution != LDPR_UNKNOWN
- && old_resolution != LDPR_UNDEF);
+ /* Report a warning if user-specified alignments do not match. */
+ if ((DECL_USER_ALIGN (prevailing_decl) && DECL_USER_ALIGN (decl))
+ && DECL_ALIGN (prevailing_decl) < DECL_ALIGN (decl))
+ return false;
- 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;
- }
+ return true;
+}
+
+/* Return true if the symtab entry E can be replaced by another symtab
+ entry. */
+
+static bool
+lto_symtab_resolve_replaceable_p (lto_symtab_entry_t e)
+{
+ if (DECL_EXTERNAL (e->decl)
+ || DECL_COMDAT (e->decl)
+ || DECL_WEAK (e->decl))
+ return true;
+
+ if (TREE_CODE (e->decl) == VAR_DECL)
+ return (DECL_COMMON (e->decl)
+ || (!flag_no_common && !DECL_INITIAL (e->decl)));
+
+ return false;
+}
+
+/* Return true if the symtab entry E can be the prevailing one. */
+
+static bool
+lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
+{
+ if (!TREE_STATIC (e->decl))
+ return false;
+
+ /* For functions we need a non-discarded body. */
+ if (TREE_CODE (e->decl) == FUNCTION_DECL)
+ return (e->node && e->node->analyzed);
- 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;
+ /* 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));
+
+ gcc_unreachable ();
}
/* Resolve the symbol with the candidates in the chain *SLOT and store
@@ -506,114 +377,121 @@ 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 (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;
+ 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 (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 +499,106 @@ 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 (!prevailing->node
+ && 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;
- /* Insert all variable decls into the global variable decl vector. */
+ default:
+ gcc_unreachable ();
+ }
+
+ 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. */
+ if (TREE_CODE (prevailing->decl) != FUNCTION_DECL)
+ prevailing->next = NULL;
return 1;
}
@@ -661,6 +612,40 @@ lto_symtab_merge_decls (void)
htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL);
}
+/* Helper to process the decl chain for the symbol table entry *SLOT. */
+
+static int
+lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+ lto_symtab_entry_t e, prevailing = (lto_symtab_entry_t) *slot;
+
+ 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);
+ }
+
+ /* Drop all but the prevailing decl from the symtab. */
+ prevailing->next = NULL;
+
+ return 1;
+}
+
+/* Merge cgraph nodes according to the symbol merging done by
+ lto_symtab_merge_decls. */
+
+void
+lto_symtab_merge_cgraph_nodes (void)
+{
+ lto_symtab_maybe_init_hash_table ();
+ htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
+}
/* Given the decl DECL, return the prevailing decl with the same name. */
@@ -685,70 +670,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 ();
-}
-
-/* Remove any storage used to store resolution of DECL. */
-
-void
-lto_symtab_clear_resolution (tree decl)
-{
- struct lto_symtab_entry_def temp;
- lto_symtab_entry_t head;
- void **slot;
-
- if (!TREE_PUBLIC (decl))
- return;
-
- /* LTO FIXME: There should be no DECL_ABSTRACT in the middle end. */
- if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
- return;
-
- gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
-
- lto_symtab_maybe_init_hash_table ();
- temp.id = DECL_ASSEMBLER_NAME (decl);
- slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT);
- if (!*slot)
- return;
-
- head = (lto_symtab_entry_t) *slot;
- if (head->decl == decl)
- {
- if (head->next)
- {
- *slot = head->next;
- head->next = NULL;
- }
- else
- htab_remove_elt (lto_symtab_identifiers, &temp);
- }
- else
- {
- lto_symtab_entry_t e;
- while (head->next && head->next->decl != decl)
- head = head->next;
- if (head->next)
- {
- e = head->next;
- head->next = e->next;
- e->next = NULL;
- }
- }
+ return ret->decl;
}
#include "gt-lto-symtab.h"