diff options
Diffstat (limited to 'gcc/lto-symtab.c')
-rw-r--r-- | gcc/lto-symtab.c | 810 |
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" |