OSDN Git Service

2010-04-06 Matthias Klose <doko@ubuntu.com>
[pf3gnuchains/gcc-fork.git] / gcc / lto-symtab.c
index 90a200f..f02824d 100644 (file)
@@ -33,761 +33,757 @@ along with GCC; see the file COPYING3.  If not see
 /* Vector to keep track of external variables we've seen so far.  */
 VEC(tree,gc) *lto_global_var_decls;
 
-/* Base type for resolution map. It maps NODE to resolution.  */
+/* Symbol table entry.  */
 
-struct GTY(()) lto_symtab_base_def
+struct GTY(()) lto_symtab_entry_def
 {
-  /* Key is either an IDENTIFIER or a DECL.  */
-  tree node;
-};
-typedef struct lto_symtab_base_def *lto_symtab_base_t;
-
-struct GTY(()) lto_symtab_identifier_def
-{
-  struct lto_symtab_base_def base;
+  /* The symbol table entry key, an IDENTIFIER.  */
+  tree id;
+  /* The symbol table entry, a DECL.  */
   tree decl;
-};
-typedef struct lto_symtab_identifier_def *lto_symtab_identifier_t;
-
-struct GTY(()) lto_symtab_decl_def
-{
-  struct lto_symtab_base_def base;
-  enum ld_plugin_symbol_resolution resolution;
+  /* 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;
+  /* Pointer to the next entry with the same key.  Before decl merging
+     this links all symbols from the different TUs.  After decl merging
+     this links merged but incompatible decls, thus all prevailing ones
+     remaining.  */
+  struct lto_symtab_entry_def *next;
 };
-typedef struct lto_symtab_decl_def *lto_symtab_decl_t;
+typedef struct lto_symtab_entry_def *lto_symtab_entry_t;
 
 /* A poor man's symbol table. This hashes identifier to prevailing DECL
    if there is one. */
 
-static GTY ((if_marked ("lto_symtab_identifier_marked_p"),
-            param_is (struct lto_symtab_identifier_def)))
+static GTY ((if_marked ("lto_symtab_entry_marked_p"),
+            param_is (struct lto_symtab_entry_def)))
   htab_t lto_symtab_identifiers;
 
-static GTY ((if_marked ("lto_symtab_decl_marked_p"),
-            param_is (struct lto_symtab_decl_def)))
-  htab_t lto_symtab_decls;
+/* Free symtab hashtable.  */
 
-/* Return the hash value of an lto_symtab_base_t object pointed to by P.  */
-
-static hashval_t
-lto_symtab_base_hash (const void *p)
+void
+lto_symtab_free (void)
 {
-  const struct lto_symtab_base_def *base =
-    (const struct lto_symtab_base_def*) p;
-  return htab_hash_pointer (base->node);
+  htab_delete (lto_symtab_identifiers);
+  lto_symtab_identifiers = NULL;
 }
 
-/* Return non-zero if P1 and P2 points to lto_symtab_base_def structs
-   corresponding to the same tree node.  */
+/* Return the hash value of an lto_symtab_entry_t object pointed to by P.  */
 
-static int
-lto_symtab_base_eq (const void *p1, const void *p2)
+static hashval_t
+lto_symtab_entry_hash (const void *p)
 {
-  const struct lto_symtab_base_def *base1 =
-     (const struct lto_symtab_base_def *) p1;
-  const struct lto_symtab_base_def *base2 =
-     (const struct lto_symtab_base_def *) p2;
-  return (base1->node == base2->node);
+  const struct lto_symtab_entry_def *base =
+    (const struct lto_symtab_entry_def *) p;
+  return IDENTIFIER_HASH_VALUE (base->id);
 }
 
-/* Returns non-zero if P points to an lto_symtab_base_def struct that needs
-   to be marked for GC.  */ 
+/* Return non-zero if P1 and P2 points to lto_symtab_entry_def structs
+   corresponding to the same symbol.  */
 
 static int
-lto_symtab_base_marked_p (const void *p)
+lto_symtab_entry_eq (const void *p1, const void *p2)
 {
-  const struct lto_symtab_base_def *base =
-     (const struct lto_symtab_base_def *) p;
-
-  /* Keep this only if the key node is marked.  */
-  return ggc_marked_p (base->node);
+  const struct lto_symtab_entry_def *base1 =
+     (const struct lto_symtab_entry_def *) p1;
+  const struct lto_symtab_entry_def *base2 =
+     (const struct lto_symtab_entry_def *) p2;
+  return (base1->id == base2->id);
 }
 
-/* Returns non-zero if P points to an lto_symtab_identifier_def struct that
-   needs to be marked for GC.  */ 
+/* Returns non-zero if P points to an lto_symtab_entry_def struct that needs
+   to be marked for GC.  */
 
 static int
-lto_symtab_identifier_marked_p (const void *p)
+lto_symtab_entry_marked_p (const void *p)
 {
-  return lto_symtab_base_marked_p (p);
-}
-
-/* Returns non-zero if P points to an lto_symtab_decl_def struct that needs
-   to be marked for GC.  */ 
+  const struct lto_symtab_entry_def *base =
+     (const struct lto_symtab_entry_def *) p;
 
-static int
-lto_symtab_decl_marked_p (const void *p)
-{
-  return lto_symtab_base_marked_p (p);
+  /* 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);
 }
 
-#define lto_symtab_identifier_eq       lto_symtab_base_eq
-#define lto_symtab_identifier_hash     lto_symtab_base_hash
-#define lto_symtab_decl_eq             lto_symtab_base_eq
-#define lto_symtab_decl_hash           lto_symtab_base_hash
-
 /* Lazily initialize resolution hash tables.  */
 
 static void
-lto_symtab_maybe_init_hash_tables (void)
+lto_symtab_maybe_init_hash_table (void)
 {
-  if (!lto_symtab_identifiers)
-    {
-      lto_symtab_identifiers =
-       htab_create_ggc (1021, lto_symtab_identifier_hash,
-                        lto_symtab_identifier_eq, NULL);
-      lto_symtab_decls =
-       htab_create_ggc (1021, lto_symtab_decl_hash,
-                        lto_symtab_decl_eq, NULL);
-    }
-}
+  if (lto_symtab_identifiers)
+    return;
 
-/* Returns true iff the union of ATTRIBUTES_1 and ATTRIBUTES_2 can be
-   applied to DECL.  */
-static bool
-lto_compatible_attributes_p (tree decl ATTRIBUTE_UNUSED, 
-                            tree attributes_1, 
-                            tree attributes_2)
-{
-#if 0
-  /* ??? For now, assume two attribute sets are compatible only if they
-     are both empty.  */
-  return !attributes_1 && !attributes_2;
-#else
-  /* FIXME.  For the moment, live dangerously, and assume the user knows
-     what he's doing. I don't think the linker would distinguish these cases.  */
-  return true || (!attributes_1 && !attributes_2);
-#endif
+  lto_symtab_identifiers =
+    htab_create_ggc (1021, lto_symtab_entry_hash,
+                    lto_symtab_entry_eq, NULL);
 }
 
-/* Helper for lto_symtab_compatible. Return TRUE if DECL is an external
-   variable declaration of an aggregate type. */
+/* Registers DECL with the LTO symbol table as having resolution RESOLUTION
+   and read from FILE_DATA. */
 
-static bool
-external_aggregate_decl_p (tree decl)
+void
+lto_symtab_register_decl (tree decl,
+                         ld_plugin_symbol_resolution_t resolution,
+                         struct lto_file_decl_data *file_data)
 {
-  return (TREE_CODE (decl) == VAR_DECL
-         && DECL_EXTERNAL (decl)
-         && AGGREGATE_TYPE_P (TREE_TYPE (decl)));
-}
+  lto_symtab_entry_t new_entry;
+  void **slot;
 
-static bool maybe_merge_incomplete_and_complete_type (tree, tree);
+  /* Check that declarations reaching this function do not have
+     properties inconsistent with having external linkage.  If any of
+     these asertions fail, then the object file reader has failed to
+     detect these cases and issue appropriate error messages.  */
+  gcc_assert (decl
+             && TREE_PUBLIC (decl)
+             && (TREE_CODE (decl) == VAR_DECL
+                 || TREE_CODE (decl) == FUNCTION_DECL)
+             && DECL_ASSEMBLER_NAME_SET_P (decl));
+  if (TREE_CODE (decl) == VAR_DECL
+      && DECL_INITIAL (decl))
+    gcc_assert (!DECL_EXTERNAL (decl)
+               || (TREE_STATIC (decl) && TREE_READONLY (decl)));
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    gcc_assert (!DECL_ABSTRACT (decl));
+
+  new_entry = GGC_CNEW (struct lto_symtab_entry_def);
+  new_entry->id = DECL_ASSEMBLER_NAME (decl);
+  new_entry->decl = decl;
+  new_entry->resolution = resolution;
+  new_entry->file_data = file_data;
 
-/* Try to merge an incomplete type INCOMPLETE with a complete type
-   COMPLETE of same kinds.
-   Return true if they were merged, false otherwise.  */
+  lto_symtab_maybe_init_hash_table ();
+  slot = htab_find_slot (lto_symtab_identifiers, new_entry, INSERT);
+  new_entry->next = (lto_symtab_entry_t) *slot;
+  *slot = new_entry;
+}
 
-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;
+/* Get the lto_symtab_entry_def struct associated with ID
+   if there is one.  */
 
-  /* ??? 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);
+static lto_symtab_entry_t
+lto_symtab_get (tree id)
+{
+  struct lto_symtab_entry_def temp;
+  void **slot;
 
-  return true;
+  lto_symtab_maybe_init_hash_table ();
+  temp.id = id;
+  slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT);
+  return slot ? (lto_symtab_entry_t) *slot : NULL;
 }
 
-/* Try to merge a maybe complete / incomplete type pair TYPE1 and TYPE2.
-   Return true if they were merged, false otherwise.  */
+/* Get the linker resolution for DECL.  */
 
-static bool
-maybe_merge_incomplete_and_complete_type (tree type1, tree type2)
+enum ld_plugin_symbol_resolution
+lto_symtab_get_resolution (tree decl)
 {
-  bool res = false;
+  lto_symtab_entry_t e;
 
-  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);
+  gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
 
-  /* 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));
+  e = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
+  while (e && e->decl != decl)
+    e = e->next;
+  if (!e)
+    return LDPR_UNKNOWN;
 
-  return res;
+  return e->resolution;
 }
 
-/* Check if OLD_DECL and NEW_DECL are compatible. */
 
-static bool
-lto_symtab_compatible (tree old_decl, tree new_decl)
-{
-  tree merged_type = NULL_TREE;
+/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
+   all edges and removing the old node.  */
 
-  if (TREE_CODE (old_decl) != TREE_CODE (new_decl))
+static void
+lto_cgraph_replace_node (struct cgraph_node *node,
+                        struct cgraph_node *prevailing_node)
+{
+  struct cgraph_edge *e, *next;
+
+  /* Merge node flags.  */
+  if (node->needed)
+    cgraph_mark_needed_node (prevailing_node);
+  if (node->reachable)
+    cgraph_mark_reachable_node (prevailing_node);
+  if (node->address_taken)
     {
-      switch (TREE_CODE (new_decl))
-       {
-       case VAR_DECL:
-         gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL);
-         error_at (DECL_SOURCE_LOCATION (new_decl),
-                   "function %qD redeclared as variable", new_decl);
-         inform (DECL_SOURCE_LOCATION (old_decl),
-                 "previously declared here");
-         return false;
-
-       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;
+      gcc_assert (!prevailing_node->global.inlined_to);
+      cgraph_mark_address_taken_node (prevailing_node);
+    }
 
-       default:
-         gcc_unreachable ();
-       }
+  /* Redirect all incoming edges.  */
+  for (e = node->callers; e; e = next)
+    {
+      next = e->next_caller;
+      cgraph_redirect_edge_callee (e, prevailing_node);
     }
+  /* Redirect incomming references.  */
+  ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
 
-  /* 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.  */
-  if (TREE_CODE (old_decl) == VAR_DECL)
+  if (node->same_body)
     {
-      tree old_type = TREE_TYPE (old_decl);
-      tree 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
+      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)
                {
-                 TREE_TYPE (new_decl) = old_type;
-                 DECL_SIZE (new_decl) = DECL_SIZE (old_decl);
-                 DECL_SIZE_UNIT (new_decl) = DECL_SIZE_UNIT (old_decl);
+                 se->node = NULL;
+                 break;
                }
-           }
-       }
+         }
     }
 
-  if (!gimple_types_compatible_p (TREE_TYPE (old_decl), TREE_TYPE (new_decl)))
+  /* Finally remove the replaced node.  */
+  cgraph_remove_node (node);
+}
+
+/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
+   all edges and removing the old node.  */
+
+static void
+lto_varpool_replace_node (struct varpool_node *vnode,
+                         struct varpool_node *prevailing_node)
+{
+  /* Merge node flags.  */
+  if (vnode->needed)
     {
-      if (TREE_CODE (new_decl) == FUNCTION_DECL)
+      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)
        {
-         if (!merged_type
-             /* We want either of the types to have argument types,
-                but not both.  */
-             && ((TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != NULL)
-                 ^ (TYPE_ARG_TYPES (TREE_TYPE (new_decl)) != NULL)))
-           {
-             /* The situation here is that (in C) somebody was smart
-                enough to use proper declarations in a header file, but
-                the actual definition of the function uses
-                non-ANSI-style argument lists.  Or we have a situation
-                where declarations weren't used anywhere and we're
-                merging the actual definition with a use.  One of the
-                decls will then have a complete function type, whereas
-                the other will only have a result type.  Assume that
-                the more complete type is the right one and don't
-                complain.  */
-             if (TYPE_ARG_TYPES (TREE_TYPE (old_decl)))
-               {
-                 merged_type = TREE_TYPE (old_decl);
-               }
-             else
-               {
-                 merged_type = 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.  */
-         if (!merged_type)
-           {
-             if (!DECL_EXTERNAL (new_decl))
-               {
-                 merged_type = TREE_TYPE (new_decl);
-               }
-             else
-               {
-                 merged_type = TREE_TYPE (old_decl);
-               }
-           }
+         last = alias;
+         alias->extra_name = prevailing_node;
        }
 
-      if (!merged_type)
+      if (prevailing_node->extra_name)
        {
-         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;
+         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);
+
+  /* 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);
+
+  /* Be sure we can garbage collect the initializer.  */
+  if (DECL_INITIAL (vnode->decl))
+    DECL_INITIAL (vnode->decl) = error_mark_node;
+  /* 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 (prevailing_decl) |= TREE_ADDRESSABLE (decl);
+  TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (prevailing_decl);
 
-  if (DECL_UNSIGNED (old_decl) != DECL_UNSIGNED (new_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)
     {
-      error_at (DECL_SOURCE_LOCATION (new_decl),
-               "signedness of %qD does not match original declaration",
-               new_decl);
-      inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
-      return false;
+      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;
     }
 
-  if (!tree_int_cst_equal (DECL_SIZE (old_decl),
-                          DECL_SIZE (new_decl))
-      || !tree_int_cst_equal (DECL_SIZE_UNIT (old_decl),
-                             DECL_SIZE_UNIT (new_decl)))
+  /* 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)
     {
-      /* Permit cases where we are declaring aggregates and at least one
-        of the decls is external and one of the decls has a size whereas
-        the other one does not.  This is perfectly legal in C:
-
-         struct s;
-        extern struct s x;
-
-        void*
-        f (void)
-        {
-          return &x;
-        }
-
-        There is no way a compiler can tell the size of x.  So we cannot
-        assume that external aggreates have complete types.  */
-
-      if (!((TREE_CODE (TREE_TYPE (old_decl))
-            == TREE_CODE (TREE_TYPE (new_decl)))
-           && ((external_aggregate_decl_p (old_decl)
-                && DECL_SIZE (old_decl) == NULL_TREE)
-               || (external_aggregate_decl_p (new_decl)
-                   && DECL_SIZE (new_decl) == NULL_TREE))))
+      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),
-                   "size of %qD does not match original declaration",
-                   new_decl);
-         inform (DECL_SOURCE_LOCATION (old_decl),
-                 "previously declared here");
-         return false;
+         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;
        }
-    }
 
-  /* Report an error 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))
-    {
-      error_at (DECL_SOURCE_LOCATION (new_decl),
-               "alignment of %qD does not match original declaration",
-               new_decl);
-      inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
-      return false;
+      /* Fallthru.  Compatible enough.  */
     }
 
-  /* Do not compare the modes of the decls.  The type compatibility
-     checks or the completing of types has properly dealt with all issues.  */
+  /* ???  We might want to emit a warning here if type qualification
+     differences were spotted.  Do not do this unconditionally though.  */
 
-  if (!lto_compatible_attributes_p (old_decl,
-                                   DECL_ATTRIBUTES (old_decl),
-                                   DECL_ATTRIBUTES (new_decl)))
-    {
-      error_at (DECL_SOURCE_LOCATION (new_decl),
-               "attributes applied to %qD are incompatible with original "
-               "declaration", new_decl);
-      inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
-      return false;
-    }
+  /* 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.  */
 
-  /* We do not require matches for:
+  /* The following should all not invoke fatal errors as in non-LTO
+     mode the linker wouldn't complain either.  Just emit warnings.  */
 
-     - DECL_NAME
+  /* 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;
 
-       Only the name used in object files matters.
+  return true;
+}
 
-     - DECL_CONTEXT  
+/* Return true if the symtab entry E can be replaced by another symtab
+   entry.  */
 
-       An entity might be declared in a C++ namespace in one file and
-       with a C identifier in another file.  
+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;
 
-     - TREE_PRIVATE, TREE_PROTECTED
+  if (TREE_CODE (e->decl) == VAR_DECL)
+    return (DECL_COMMON (e->decl)
+           || (!flag_no_common && !DECL_INITIAL (e->decl)));
 
-       Access control is the problem of the front end that created the
-       object file.  
-       
-     Therefore, at this point we have decided to merge the declarations.  */
-  return true;
+  return false;
 }
 
+/* Return true if the symtab entry E can be the prevailing one.  */
 
-/* Marks decl DECL as having resolution RESOLUTION. */
-
-static void
-lto_symtab_set_resolution_and_file_data (tree decl,
-                                        ld_plugin_symbol_resolution_t
-                                        resolution,
-                                        struct lto_file_decl_data *file_data)
+static bool
+lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
 {
-  lto_symtab_decl_t new_entry;
-  void **slot;
+  /* 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;
 
-  gcc_assert (decl);
+  /* For functions we need a non-discarded body.  */
+  if (TREE_CODE (e->decl) == FUNCTION_DECL)
+    return (e->node && e->node->analyzed);
 
-  gcc_assert (TREE_PUBLIC (decl));
-  gcc_assert (TREE_CODE (decl) != FUNCTION_DECL || !DECL_ABSTRACT (decl));
+  /* 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;
+    }
 
-  new_entry = GGC_CNEW (struct lto_symtab_decl_def);
-  new_entry->base.node = decl;
-  new_entry->resolution = resolution;
-  new_entry->file_data = file_data;
-  
-  lto_symtab_maybe_init_hash_tables ();
-  slot = htab_find_slot (lto_symtab_decls, new_entry, INSERT);
-  gcc_assert (!*slot);
-  *slot = new_entry;
+  gcc_unreachable ();
 }
 
-/* Get the lto_symtab_identifier_def struct associated with ID
-   if there is one.  If there is none and INSERT_P is true, create
-   a new one.  */
+/* Resolve the symbol with the candidates in the chain *SLOT and store
+   their resolutions.  */
 
-static lto_symtab_identifier_t
-lto_symtab_get_identifier (tree id, bool insert_p)
+static void
+lto_symtab_resolve_symbols (void **slot)
 {
-  struct lto_symtab_identifier_def temp;
-  lto_symtab_identifier_t symtab_id;
-  void **slot;
+  lto_symtab_entry_t e;
+  lto_symtab_entry_t prevailing = NULL;
 
-  lto_symtab_maybe_init_hash_tables ();
-  temp.base.node = id;
-  slot = htab_find_slot (lto_symtab_identifiers, &temp,
-                        insert_p ? INSERT : NO_INSERT);
-  if (insert_p)
+  /* 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 (*slot)
-       return (lto_symtab_identifier_t) *slot;
-      else
+      if (TREE_CODE (e->decl) == FUNCTION_DECL)
+       e->node = cgraph_get_node (e->decl);
+      else if (TREE_CODE (e->decl) == VAR_DECL)
        {
-         symtab_id = GGC_CNEW (struct lto_symtab_identifier_def);
-         symtab_id->base.node = id;
-         *slot = symtab_id;
-         return symtab_id;
+         e->vnode = varpool_get_node (e->decl);
+         /* The LTO plugin for gold doesn't handle common symbols
+            properly.  Let us choose manually.  */
+         if (DECL_COMMON (e->decl))
+           e->resolution = LDPR_UNKNOWN;
        }
     }
-  else
-    return slot ? (lto_symtab_identifier_t) *slot : NULL;
-}
 
-/* Return the DECL associated with an IDENTIFIER ID or return NULL_TREE
-   if there is none.  */
+  e = (lto_symtab_entry_t) *slot;
 
-static tree
-lto_symtab_get_identifier_decl (tree id)
-{
-  lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, false);
-  return symtab_id ? symtab_id->decl : NULL_TREE;
-}
-
-/* SET the associated DECL of an IDENTIFIER ID to be DECL.  */
+  /* If the chain is already resolved there is nothing else to do.  */
+  if (e->resolution != LDPR_UNKNOWN)
+    return;
 
-static void
-lto_symtab_set_identifier_decl (tree id, tree decl)
-{
-  lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, true);
-  symtab_id->decl = decl;
-}
+  /* 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;
+       }
 
-/* Common helper function for merging variable and function declarations.
-   NEW_DECL is the newly found decl. RESOLUTION is the decl's resolution
-   provided by the linker. */
+      /* 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;
 
-static void
-lto_symtab_merge_decl (tree new_decl,
-                      enum ld_plugin_symbol_resolution resolution,
-                      struct lto_file_decl_data *file_data)
-{
-  tree old_decl;
-  tree name;
-  ld_plugin_symbol_resolution_t old_resolution;
+  /* 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;
 
-  gcc_assert (TREE_CODE (new_decl) == VAR_DECL
-             || TREE_CODE (new_decl) == FUNCTION_DECL);
+      /* Choose the first function that can prevail as prevailing.  */
+      if (TREE_CODE (e->decl) == FUNCTION_DECL)
+       {
+         prevailing = e;
+         break;
+       }
 
-  gcc_assert (TREE_PUBLIC (new_decl));
+      /* 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;
+    }
 
-  gcc_assert (DECL_LANG_SPECIFIC (new_decl) == NULL);
+  if (!prevailing)
+    return;
 
-  /* Check that declarations reaching this function do not have
-     properties inconsistent with having external linkage.  If any of
-     these asertions fail, then the object file reader has failed to
-     detect these cases and issue appropriate error messages.  */
-  if (TREE_CODE (new_decl) == VAR_DECL)
-    gcc_assert (!(DECL_EXTERNAL (new_decl) && DECL_INITIAL (new_decl)));
+found:
+  if (TREE_CODE (prevailing->decl) == VAR_DECL
+      && TREE_READONLY (prevailing->decl))
+    prevailing->resolution = LDPR_PREVAILING_DEF_IRONLY;
+  else
+    prevailing->resolution = LDPR_PREVAILING_DEF;
+}
 
-  /* Remember the resolution of this symbol. */
-  lto_symtab_set_resolution_and_file_data (new_decl, resolution, file_data);
+/* Merge all decls in the symbol table chain to the prevailing decl and
+   issue diagnostics about type mismatches.  */
 
-  /* Ensure DECL_ASSEMBLER_NAME will not set assembler name.  */
-  gcc_assert (DECL_ASSEMBLER_NAME_SET_P (new_decl));
+static void
+lto_symtab_merge_decls_2 (void **slot)
+{
+  lto_symtab_entry_t prevailing, e;
+  VEC(tree, heap) *mismatches = NULL;
+  unsigned i;
+  tree decl;
+  bool diagnosed_p = false;
 
-  /* Retrieve the previous declaration.  */
-  name = DECL_ASSEMBLER_NAME (new_decl);
-  old_decl = lto_symtab_get_identifier_decl (name);
+  /* Nothing to do for a single entry.  */
+  prevailing = (lto_symtab_entry_t) *slot;
+  if (!prevailing->next)
+    return;
 
-  /* If there was no previous declaration, then there is nothing to
-     merge.  */
-  if (!old_decl)
+  /* Try to merge each entry with the prevailing one.  */
+  for (e = prevailing->next; e; e = e->next)
     {
-      lto_symtab_set_identifier_decl (name, new_decl);
-      VEC_safe_push (tree, gc, lto_global_var_decls, new_decl);
-      return;
+      if (!lto_symtab_merge (prevailing, e))
+       VEC_safe_push (tree, heap, mismatches, e->decl);
     }
+  if (VEC_empty (tree, mismatches))
+    return;
 
-  /* Give ODR violation errors.  */
-  old_resolution = lto_symtab_get_resolution (old_decl);
-  if (resolution == LDPR_PREVAILING_DEF
-      || resolution == LDPR_PREVAILING_DEF_IRONLY)
+  /* Diagnose all mismatched re-declarations.  */
+  for (i = 0; VEC_iterate (tree, mismatches, i, decl); ++i)
     {
-      if ((old_resolution == LDPR_PREVAILING_DEF
-          || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
-         && (old_resolution != resolution || flag_no_common))
+      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))
        {
-         error_at (DECL_SOURCE_LOCATION (new_decl),
-                   "%qD has already been defined", new_decl);
-         inform (DECL_SOURCE_LOCATION (old_decl),
-                 "previously defined here");
-         return;
+         diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0,
+                                    "alignment of %qD is bigger than "
+                                    "original declaration", decl);
        }
     }
+  if (diagnosed_p)
+    inform (DECL_SOURCE_LOCATION (prevailing->decl),
+           "previously declared here");
 
-  /* The linker may ask us to combine two incompatible symbols.
-     Find a decl we can merge with or chain it in the list of decls
-     for that symbol.  */
-  while (old_decl
-        && !lto_symtab_compatible (old_decl, new_decl))
-    old_decl = (tree) DECL_LANG_SPECIFIC (old_decl);
-  if (!old_decl)
+  VEC_free (tree, heap, mismatches);
+}
+
+/* Helper to process the decl chain for the symbol table entry *SLOT.  */
+
+static int
+lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+  lto_symtab_entry_t e, prevailing;
+  bool diagnosed_p = false;
+
+  /* Compute the symbol resolutions.  This is a no-op when using the
+     linker plugin.  */
+  lto_symtab_resolve_symbols (slot);
+
+  /* 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)
     {
-      old_decl = lto_symtab_get_identifier_decl (name);
-      while (DECL_LANG_SPECIFIC (old_decl) != NULL)
-       old_decl = (tree) DECL_LANG_SPECIFIC (old_decl);
-      DECL_LANG_SPECIFIC (old_decl) = (struct lang_decl *) new_decl;
-      return;
+      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 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);
+  /* 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;
+    }
 
-  gcc_assert (resolution != LDPR_UNKNOWN
-             && resolution != LDPR_UNDEF
-             && old_resolution != LDPR_UNKNOWN
-             && old_resolution != LDPR_UNDEF);
+  /* Record the prevailing variable.  */
+  if (TREE_CODE (prevailing->decl) == VAR_DECL)
+    VEC_safe_push (tree, gc, lto_global_var_decls, prevailing->decl);
 
-  if (resolution == LDPR_PREVAILING_DEF
-      || resolution == LDPR_PREVAILING_DEF_IRONLY)
+  /* Diagnose mismatched objects.  */
+  for (e = prevailing->next; e; e = e->next)
     {
-      tree decl;
-      gcc_assert (old_resolution == LDPR_PREEMPTED_IR
-                 || old_resolution ==  LDPR_RESOLVED_IR
-                 || (old_resolution == resolution && !flag_no_common));
-      DECL_LANG_SPECIFIC (new_decl) = DECL_LANG_SPECIFIC (old_decl);
-      DECL_LANG_SPECIFIC (old_decl) = NULL;
-      decl = lto_symtab_get_identifier_decl (name);
-      if (decl == old_decl)
+      if (TREE_CODE (prevailing->decl) == TREE_CODE (e->decl))
+       continue;
+
+      switch (TREE_CODE (prevailing->decl))
        {
-         lto_symtab_set_identifier_decl (name, new_decl);
-         return;
+       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;
+
+       default:
+         gcc_unreachable ();
        }
-      while ((tree) DECL_LANG_SPECIFIC (decl) != old_decl)
-       decl = (tree) DECL_LANG_SPECIFIC (decl);
-      DECL_LANG_SPECIFIC (decl) = (struct lang_decl *) new_decl;
-      return;
+
+      diagnosed_p = true;
     }
+  if (diagnosed_p)
+      inform (DECL_SOURCE_LOCATION (prevailing->decl),
+             "previously declared here");
 
-  if (resolution == LDPR_PREEMPTED_REG
-      || resolution == LDPR_RESOLVED_EXEC
-      || resolution == LDPR_RESOLVED_DYN)
-    gcc_assert (old_resolution == LDPR_PREEMPTED_REG
-               || old_resolution == LDPR_RESOLVED_EXEC
-               || old_resolution == LDPR_RESOLVED_DYN);
-
-  if (resolution == LDPR_PREEMPTED_IR
-      || 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);
-
-  return;
-}
+  /* 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));
 
+  /* Merge the chain to the single prevailing decl and diagnose
+     mismatches.  */
+  lto_symtab_merge_decls_2 (slot);
 
-/* Merge the VAR_DECL NEW_VAR with resolution RESOLUTION with any previous
-   declaration with the same name. */
+  /* 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;
 
-void
-lto_symtab_merge_var (tree new_var, enum ld_plugin_symbol_resolution resolution)
-{
-  lto_symtab_merge_decl (new_var, resolution, NULL);
+  return 1;
 }
 
-/* Merge the FUNCTION_DECL NEW_FN with resolution RESOLUTION with any previous
-   declaration with the same name. */
+/* Resolve and merge all symbol table chains to a prevailing decl.  */
 
 void
-lto_symtab_merge_fn (tree new_fn, enum ld_plugin_symbol_resolution resolution,
-                    struct lto_file_decl_data *file_data)
+lto_symtab_merge_decls (void)
 {
-  lto_symtab_merge_decl (new_fn, resolution, file_data);
+  lto_symtab_maybe_init_hash_table ();
+  htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL);
 }
 
-/* Given the decl DECL, return the prevailing decl with the same name. */
+/* Helper to process the decl chain for the symbol table entry *SLOT.  */
 
-tree
-lto_symtab_prevailing_decl (tree decl)
+static int
+lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
 {
-  tree ret;
-  gcc_assert (decl);
+  lto_symtab_entry_t e, prevailing = (lto_symtab_entry_t) *slot;
 
-  /* Builtins and local symbols are their own prevailing decl.  */
-  if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
-    return decl;
+  if (!prevailing->next)
+    return 1;
 
-  /* DECL_ABSTRACTs are their own prevailng decl.  */
-  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
-    return decl;
-
-  /* Ensure DECL_ASSEMBLER_NAME will not set assembler name.  */
-  gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
-
-  /* Walk through the list of candidates and return the one we merged to.  */
-  ret = lto_symtab_get_identifier_decl (DECL_ASSEMBLER_NAME (decl));
-  if (!ret
-      || DECL_LANG_SPECIFIC (ret) == NULL)
-    return ret;
-
-  /* If there are multiple decls to choose from find the one we merged
-     with and return that.  */
-  while (ret)
+  /* Replace the cgraph node of each entry with the prevailing one.  */
+  for (e = prevailing->next; e; e = e->next)
     {
-      if (gimple_types_compatible_p (TREE_TYPE (decl), TREE_TYPE (ret)))
-       return ret;
+      if (e->node != NULL)
+       {
+         if (e->node->decl != e->decl && e->node->same_body)
+           {
+             struct cgraph_node *alias;
 
-      ret = (tree) DECL_LANG_SPECIFIC (ret);
+             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);
     }
 
-  gcc_unreachable ();
+  /* Drop all but the prevailing decl from the symtab.  */
+  prevailing->next = NULL;
+
+  return 1;
 }
 
-/* Return the hash table entry of DECL. */
+/* Merge cgraph nodes according to the symbol merging done by
+   lto_symtab_merge_decls.  */
 
-static struct lto_symtab_decl_def *
-lto_symtab_get_symtab_def (tree decl)
+void
+lto_symtab_merge_cgraph_nodes (void)
 {
-  struct lto_symtab_decl_def temp, *symtab_decl;
-  void **slot;
-
-  gcc_assert (decl);
-
-  lto_symtab_maybe_init_hash_tables ();
-  temp.base.node = decl;
-  slot = htab_find_slot (lto_symtab_decls, &temp, NO_INSERT);
-  gcc_assert (slot && *slot);
-  symtab_decl = (struct lto_symtab_decl_def*) *slot;
-  return symtab_decl;
+  lto_symtab_maybe_init_hash_table ();
+  htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
 }
 
-/* Return the resolution of DECL. */
+/* Given the decl DECL, return the prevailing decl with the same name. */
 
-enum ld_plugin_symbol_resolution
-lto_symtab_get_resolution (tree decl)
+tree
+lto_symtab_prevailing_decl (tree decl)
 {
-  gcc_assert (decl);
+  lto_symtab_entry_t ret;
 
+  /* Builtins and local symbols are their own prevailing decl.  */
   if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
-    return LDPR_PREVAILING_DEF_IRONLY;
+    return decl;
 
-  /* FIXME lto: There should be no DECL_ABSTRACT in the middle end. */
+  /* DECL_ABSTRACTs are their own prevailng decl.  */
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
-    return LDPR_PREVAILING_DEF_IRONLY;
-
-  return lto_symtab_get_symtab_def (decl)->resolution;
-}
-
-/* Return the file of DECL. */
-
-struct lto_file_decl_data *
-lto_symtab_get_file_data (tree decl)
-{
-  return lto_symtab_get_symtab_def (decl)->file_data;
-}
-
-/* Remove any storage used to store resolution of DECL.  */
-
-void
-lto_symtab_clear_resolution (tree decl)
-{
-  struct lto_symtab_decl_def temp;
-  gcc_assert (decl);
+    return decl;
 
-  if (!TREE_PUBLIC (decl))
-    return;
+  /* Ensure DECL_ASSEMBLER_NAME will not set assembler name.  */
+  gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
 
-  /* LTO FIXME: There should be no DECL_ABSTRACT in the middle end. */
-  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
-    return;
+  /* Walk through the list of candidates and return the one we merged to.  */
+  ret = lto_symtab_get (DECL_ASSEMBLER_NAME (decl));
+  if (!ret)
+    return NULL_TREE;
 
-  lto_symtab_maybe_init_hash_tables ();
-  temp.base.node = decl;
-  htab_remove_elt (lto_symtab_decls, &temp);
+  return ret->decl;
 }
 
 #include "gt-lto-symtab.h"