Index: tree.h
===================================================================
--- tree.h	(revision 168508)
+++ tree.h	(working copy)
@@ -5389,6 +5389,18 @@ extern void remove_unreachable_alias_pai
 extern bool decl_replaceable_p (tree);
 extern bool decl_binds_to_current_def_p (tree);
 
+/* Derived type for use by compute_visible_aliases and callers.  A symbol
+   alias set is a pointer set into which we enter IDENTIFIER_NODES bearing
+   the canonicalised assembler-level symbol names corresponding to decls
+   and their aliases.  */
+typedef struct pointer_set_t symbol_alias_set_t;
+
+extern void symbol_alias_set_destroy (symbol_alias_set_t *);
+extern int symbol_alias_set_contains (const symbol_alias_set_t *, tree);
+extern symbol_alias_set_t * propagate_aliases_backward (bool (*)
+							 (tree, tree, void *),
+							void *);
+
 /* In stmt.c */
 extern void expand_computed_goto (tree);
 extern bool parse_output_constraint (const char **, int, int, int,
Index: lto-streamer-out.c
===================================================================
--- lto-streamer-out.c	(revision 168508)
+++ lto-streamer-out.c	(working copy)
@@ -2005,6 +2005,13 @@ output_function (struct cgraph_node *nod
 }
 
 
+/* Used to pass data to trivally_defined_alias callback.  */
+struct sets {
+  cgraph_node_set set;
+  varpool_node_set vset;
+};
+
+
 /* Return true if alias pair P belongs to the set of cgraph nodes in
    SET.  If P is a an alias for a VAR_DECL, it can always be emitted.
    However, for FUNCTION_DECL aliases, we should only output the pair
@@ -2014,16 +2021,51 @@ output_function (struct cgraph_node *nod
    the file processed by LTRANS.  */
 
 static bool
-output_alias_pair_p (alias_pair *p, cgraph_node_set set, varpool_node_set vset)
+trivally_defined_alias (tree decl ATTRIBUTE_UNUSED,
+			tree target, void *data)
+{
+  struct sets *set = (struct sets *) data;
+  struct cgraph_node *fnode = NULL;
+  struct varpool_node *vnode = NULL;
+
+  fnode = cgraph_node_for_asm (target);
+  if (fnode)
+    return cgraph_node_in_set_p (fnode, set->set);
+  vnode = varpool_node_for_asm (target);
+  return vnode && varpool_node_in_set_p (vnode, set->vset);
+}
+
+/* Return true if alias pair P should be output in the current
+   partition contains cgrpah nodes SET and varpool nodes VSET.
+   DEFINED is set of all aliases whose targets are defined in
+   the partition.
+
+   Normal aliases are output when they are defined, while WEAKREF
+   aliases are output when they are used.  */
+
+static bool
+output_alias_pair_p (alias_pair *p, symbol_alias_set_t *defined,
+		     cgraph_node_set set, varpool_node_set vset)
 {
-  if (TREE_CODE (p->decl) == VAR_DECL)
-    return varpool_node_in_set_p (varpool_node_for_asm (p->target), vset);
+  struct cgraph_node *node;
+  struct varpool_node *vnode;
 
-  /* Check if the assembler name for P->TARGET has its cgraph node in SET.  */
-  gcc_assert (TREE_CODE (p->decl) == FUNCTION_DECL);
-  return cgraph_node_in_set_p (cgraph_node_for_asm (p->target), set);
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
+    {
+      if (TREE_CODE (p->decl) == VAR_DECL)
+	{
+	  vnode = varpool_get_node (p->decl);
+	  return (vnode
+		  && referenced_from_this_partition_p (&vnode->ref_list, set, vset));
+	}
+      node = cgraph_get_node (p->decl);
+      return (node
+	      && (referenced_from_this_partition_p (&node->ref_list, set, vset)
+		  || reachable_from_this_partition_p (node, set)));
+    }
+  else
+    return symbol_alias_set_contains (defined, p->decl);
 }
 
 /* Output any unreferenced global symbol defined in SET, alias pairs
    and labels.  */
@@ -2035,6 +2079,11 @@ output_unreferenced_globals (cgraph_node
   alias_pair *p;
   unsigned i;
   struct varpool_node *vnode;
+  symbol_alias_set_t *defined;
+  struct sets setdata;
+
+  setdata.set = set;
+  setdata.vset = vset;
 
   ob = create_output_block (LTO_section_static_initializer);
   ob->cgraph_node = NULL;
@@ -2068,15 +2117,20 @@ output_unreferenced_globals (cgraph_node
 
   output_zero (ob);
 
+  /* We really need to propagate in both directoins:
+     for normal aliases we propagate from first defined alias to
+     all aliases defined based on it.  For weakrefs we propagate in
+     the oposite direction.  */
+  defined = propagate_aliases_backward (trivally_defined_alias, &setdata);
+
   /* Emit the alias pairs for the nodes in SET.  */
   FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
-    {
-      if (output_alias_pair_p (p, set, vset))
-	{
-	  lto_output_tree_ref (ob, p->decl);
-	  lto_output_tree_ref (ob, p->target);
-	}
-    }
+    if (output_alias_pair_p (p, defined, set, vset))
+      {
+	lto_output_tree_ref (ob, p->decl);
+	lto_output_tree_ref (ob, p->target);
+      }
+  symbol_alias_set_destroy (defined);
 
   output_zero (ob);
 
@@ -2474,6 +2530,11 @@ produce_symtab (struct output_block *ob,
   lto_cgraph_encoder_t encoder = ob->decl_state->cgraph_node_encoder;
   int i;
   alias_pair *p;
+  struct sets setdata;
+  symbol_alias_set_t *defined;
+
+  setdata.set = set;
+  setdata.vset = vset;
 
   lto_begin_section (section_name, false);
   free (section_name);
@@ -2551,9 +2612,11 @@ produce_symtab (struct output_block *ob,
     }
 
   /* Write all aliases.  */
+  defined = propagate_aliases_backward (trivally_defined_alias, &setdata);
   FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
-    if (output_alias_pair_p (p, set, vset))
+    if (output_alias_pair_p (p, defined, set, vset))
       write_symbol (cache, &stream, p->decl, seen, true);
+  symbol_alias_set_destroy (defined);
 
   lto_write_stream (&stream);
   pointer_set_destroy (seen);
Index: ipa.c
===================================================================
--- ipa.c	(revision 168508)
+++ ipa.c	(working copy)
@@ -846,6 +846,13 @@ function_and_variable_visibility (bool w
 		
       if ((node = cgraph_node_for_asm (p->target)) != NULL)
         {
+	  /* Weakrefs alias symbols from other compilation unit.  In the case
+	     the destination of weakref became available because of LTO, we must
+	     mark it as needed.  */
+	  if (in_lto_p
+	      && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))
+	      && !node->needed)
+	    cgraph_mark_needed_node (node);
 	  gcc_assert (node->needed);
 	  pointer_set_insert (aliased_nodes, node);
 	  if (dump_file)
@@ -854,6 +861,13 @@ function_and_variable_visibility (bool w
         }
       else if ((vnode = varpool_node_for_asm (p->target)) != NULL)
         {
+	  /* Weakrefs alias symbols from other compilation unit.  In the case
+	     the destination of weakref became available because of LTO, we must
+	     mark it as needed.  */
+	  if (in_lto_p
+	      && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))
+	      && !vnode->needed)
+	    varpool_mark_needed_node (vnode);
 	  gcc_assert (vnode->needed);
 	  pointer_set_insert (aliased_vnodes, vnode);
 	  if (dump_file)
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 168508)
+++ lto/lto.c	(working copy)
@@ -837,6 +837,8 @@ partition_cgraph_node_p (struct cgraph_n
       || (DECL_COMDAT (node->decl)
 	  && !cgraph_used_from_object_file_p (node)))
     return false;
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (node->decl)))
+    return false;
   return true;
 }
 
@@ -854,6 +856,8 @@ partition_varpool_node_p (struct varpool
 	  && !vnode->force_output
 	  && !varpool_used_from_object_file_p (vnode)))
     return false;
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->decl)))
+    return false;
   return true;
 }
 
Index: passes.c
===================================================================
--- passes.c	(revision 168508)
+++ passes.c	(working copy)
@@ -144,6 +144,7 @@ rest_of_decl_compilation (tree decl,
 {
   /* We deferred calling assemble_alias so that we could collect
      other attributes such as visibility.  Emit the alias now.  */
+  if (!in_lto_p)
   {
     tree alias;
     alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl));
