OSDN Git Service

* lto-symtab.c (lto_symtab_free): New function.
[pf3gnuchains/gcc-fork.git] / gcc / lto-symtab.c
index 600f75b..f8349cf 100644 (file)
@@ -41,6 +41,12 @@ 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;
+  /* The varpool node if decl is a variable decl.  Filled in during the
+     merging process.  */
+  struct varpool_node *vnode;
   /* LTO file-data and symbol resolution for this decl.  */
   struct lto_file_decl_data * GTY((skip (""))) file_data;
   enum ld_plugin_symbol_resolution resolution;
@@ -59,6 +65,15 @@ static GTY ((if_marked ("lto_symtab_entry_marked_p"),
             param_is (struct lto_symtab_entry_def)))
   htab_t lto_symtab_identifiers;
 
+/* Free symtab hashtable.  */
+
+void
+lto_symtab_free (void)
+{
+  htab_delete (lto_symtab_identifiers);
+  lto_symtab_identifiers = NULL;
+}
+
 /* Return the hash value of an lto_symtab_entry_t object pointed to by P.  */
 
 static hashval_t
@@ -83,7 +98,7 @@ lto_symtab_entry_eq (const void *p1, const void *p2)
 }
 
 /* Returns non-zero if P points to an lto_symtab_entry_def struct that needs
-   to be marked for GC.  */ 
+   to be marked for GC.  */
 
 static int
 lto_symtab_entry_marked_p (const void *p)
@@ -91,9 +106,10 @@ lto_symtab_entry_marked_p (const void *p)
   const struct lto_symtab_entry_def *base =
      (const struct lto_symtab_entry_def *) p;
 
-  /* Keep this only if the decl or the chain is marked.  */
-  return (ggc_marked_p (base->decl)
-         || (base->next && ggc_marked_p (base->next)));
+  /* Keep this only if the common IDENTIFIER_NODE of the symtab chain
+     is marked which it will be if at least one of the DECLs in the
+     chain is marked.  */
+  return ggc_marked_p (base->id);
 }
 
 /* Lazily initialize resolution hash tables.  */
@@ -109,200 +125,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. */
 
@@ -323,8 +145,10 @@ lto_symtab_register_decl (tree decl,
              && (TREE_CODE (decl) == VAR_DECL
                  || TREE_CODE (decl) == FUNCTION_DECL)
              && DECL_ASSEMBLER_NAME_SET_P (decl));
-  if (TREE_CODE (decl) == VAR_DECL)
-    gcc_assert (!(DECL_EXTERNAL (decl) && DECL_INITIAL (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));
 
@@ -333,7 +157,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;
@@ -373,125 +197,252 @@ 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)
-    cgraph_mark_address_taken_node (new_node);
+  if (node->needed)
+    cgraph_mark_needed_node (prevailing_node);
+  if (node->reachable)
+    cgraph_mark_reachable_node (prevailing_node);
+  if (node->address_taken)
+    {
+      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);
     }
+  /* Redirect incomming references.  */
+  ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
 
-  /* 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)
+  if (node->same_body)
     {
-      next = e->next_callee;
-      cgraph_remove_edge (e);
+      struct cgraph_node *alias;
+
+      for (alias = node->same_body; alias; alias = alias->next)
+       if (DECL_ASSEMBLER_NAME_SET_P (alias->decl))
+         {
+           lto_symtab_entry_t se
+             = lto_symtab_get (DECL_ASSEMBLER_NAME (alias->decl));
+
+           for (; se; se = se->next)
+             if (se->node == node)
+               {
+                 se->node = NULL;
+                 break;
+               }
+         }
     }
 
   /* Finally remove the replaced node.  */
-  cgraph_remove_node (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.  */
+/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
+   all edges and removing the old node.  */
 
-static lto_symtab_entry_t
-lto_symtab_merge (lto_symtab_entry_t entry1, lto_symtab_entry_t entry2)
+static void
+lto_varpool_replace_node (struct varpool_node *vnode,
+                         struct varpool_node *prevailing_node)
 {
-  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)
+  /* Merge node flags.  */
+  if (vnode->needed)
     {
-      if ((old_resolution == LDPR_PREVAILING_DEF
-          || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
-         && (old_resolution != new_resolution || flag_no_common))
+      gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
+      varpool_mark_needed_node (prevailing_node);
+    }
+  /* Relink aliases.  */
+  if (vnode->extra_name && !vnode->alias)
+    {
+      struct varpool_node *alias, *last;
+      for (alias = vnode->extra_name;
+          alias; alias = alias->next)
+       {
+         last = alias;
+         alias->extra_name = prevailing_node;
+       }
+
+      if (prevailing_node->extra_name)
        {
-         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;
+         last->next = prevailing_node->extra_name;
+         prevailing_node->extra_name->prev = last;
        }
+      prevailing_node->extra_name = vnode->extra_name;
+      vnode->extra_name = NULL;
     }
+  gcc_assert (!vnode->finalized || prevailing_node->finalized);
+  gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
 
-  /* The linker may ask us to combine two incompatible symbols.  */
-  if (!lto_symtab_compatible (old_decl, new_decl))
-    return NULL;
+  /* When replacing by an alias, the references goes to the original
+     variable.  */
+  if (prevailing_node->alias && prevailing_node->extra_name)
+    prevailing_node = prevailing_node->extra_name;
+  ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list);
 
-  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);
+  /* Finally remove the replaced node.  */
+  varpool_remove_node (vnode);
+}
+
+/* Merge two variable or function symbol table entries PREVAILING and ENTRY.
+   Return false if the symbols are not fully compatible and a diagnostic
+   should be emitted.  */
+
+static bool
+lto_symtab_merge (lto_symtab_entry_t prevailing, lto_symtab_entry_t entry)
+{
+  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 (old_decl) |= TREE_ADDRESSABLE (new_decl);
-  TREE_ADDRESSABLE (new_decl) |= TREE_ADDRESSABLE (old_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;
 
-  gcc_assert (new_resolution != LDPR_UNKNOWN
-             && new_resolution != LDPR_UNDEF
-             && old_resolution != LDPR_UNKNOWN
-             && old_resolution != LDPR_UNDEF);
+      return true;
+    }
 
-  if (new_resolution == LDPR_PREVAILING_DEF
-      || new_resolution == LDPR_PREVAILING_DEF_IRONLY
-      || (!old_node && new_node))
+  /* 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)
     {
-      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;
+      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)
+       {
+         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.  */
     }
 
-  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;
+  /* ???  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 (prevailing_decl) && DECL_USER_ALIGN (decl))
+      && DECL_ALIGN (prevailing_decl) < DECL_ALIGN (decl))
+    return false;
+
+  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)
+{
+  /* The C++ frontend ends up neither setting TREE_STATIC nor
+     DECL_EXTERNAL on virtual methods but only TREE_PUBLIC.
+     So do not reject !TREE_STATIC here but only DECL_EXTERNAL.  */
+  if (DECL_EXTERNAL (e->decl))
+    return false;
+
+  /* For functions we need a non-discarded body.  */
+  if (TREE_CODE (e->decl) == FUNCTION_DECL)
+    return (e->node && e->node->analyzed);
+
+  /* A variable should have a size.  */
+  else if (TREE_CODE (e->decl) == VAR_DECL)
+    {
+      if (!e->vnode)
+       return false;
+      if (e->vnode->finalized)
+       return true;
+      return e->vnode->alias && e->vnode->extra_name->finalized;
+    }
+
+  gcc_unreachable ();
 }
 
 /* Resolve the symbol with the candidates in the chain *SLOT and store
@@ -500,115 +451,130 @@ lto_symtab_merge (lto_symtab_entry_t entry1, lto_symtab_entry_t entry2)
 static void
 lto_symtab_resolve_symbols (void **slot)
 {
-  lto_symtab_entry_t e = (lto_symtab_entry_t) *slot;
+  lto_symtab_entry_t e;
+  lto_symtab_entry_t prevailing = NULL;
+
+  /* Always set e->node so that edges are updated to reflect decl merging. */
+  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+    {
+      if (TREE_CODE (e->decl) == FUNCTION_DECL)
+       e->node = cgraph_get_node (e->decl);
+      else if (TREE_CODE (e->decl) == VAR_DECL)
+       e->vnode = varpool_get_node (e->decl);
+    }
+
+  e = (lto_symtab_entry_t) *slot;
 
-  /* If the chain is already resolved there is nothing to do.  */
+  /* If the chain is already resolved there is nothing else to do.  */
   if (e->resolution != LDPR_UNKNOWN)
     return;
 
-  /* This is a poor mans resolver.  */
-  for (; e; e = e->next)
+  /* Find the single non-replaceable prevailing symbol and
+     diagnose ODR violations.  */
+  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
+    {
+      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)
     {
-      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 (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.  */
@@ -616,33 +582,112 @@ 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;
+      /* For variables chose with a priority variant with vnode
+        attached (i.e. from unit where external declaration of
+        variable is actually used).
+        When there are multiple variants, chose one with size.
+        This is needed for C++ typeinfos, for example in
+        lto/20081204-1 there are typeifos in both units, just
+        one of them do have size.  */
+      if (TREE_CODE (prevailing->decl) == VAR_DECL)
+       {
+         for (e = prevailing->next; e; e = e->next)
+           if ((!prevailing->vnode && e->vnode)
+               || ((prevailing->vnode != NULL) == (e->vnode != NULL)
+                   && !COMPLETE_TYPE_P (TREE_TYPE (prevailing->decl))
+                   && COMPLETE_TYPE_P (TREE_TYPE (e->decl))))
+             prevailing = e;
+       }
+    }
 
-  /* 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;
+
+       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;
 
-  /* Fixup variables in case there are multiple prevailing ones.  */
-  if (e->next)
-    lto_symtab_fixup_var_decls (slot);
+       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.  */
+  if (TREE_CODE (prevailing->decl) != FUNCTION_DECL
+      && TREE_CODE (prevailing->decl) != VAR_DECL)
+    prevailing->next = NULL;
 
   return 1;
 }
@@ -656,6 +701,55 @@ 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;
+
+  /* Replace the cgraph node of each entry with the prevailing one.  */
+  for (e = prevailing->next; e; e = e->next)
+    {
+      if (e->node != NULL)
+       {
+         if (e->node->decl != e->decl && e->node->same_body)
+           {
+             struct cgraph_node *alias;
+
+             for (alias = e->node->same_body; alias; alias = alias->next)
+               if (alias->decl == e->decl)
+                 break;
+             if (alias)
+               {
+                 cgraph_remove_same_body_alias (alias);
+                 continue;
+               }
+           }
+         lto_cgraph_replace_node (e->node, prevailing->node);
+       }
+      if (e->vnode != NULL)
+       lto_varpool_replace_node (e->vnode, prevailing->vnode);
+    }
+
+  /* Drop all but the prevailing decl from the symtab.  */
+  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. */
 
@@ -680,70 +774,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"