diff mbox

Symtab cleanups 5/17

Message ID 20130611230858.GA8717@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka June 11, 2013, 11:08 p.m. UTC
Hi,
weakref is a static variable that is an alias of external symbol. Either by GCC
or by GAS it is translated to references to the target and depending on whether
target is used or not it is declared as weak or non-weak symbol.

Now the implementation in c-common.c sets DECL_EXTERNAL flag when building
weakref of variable, while it it keeps original flags (static) when building
alias of function.

While making cgraph implementation of weakref I run into problem with this
inconsistency and fixed it in cgraphunit.c by making all weakrefs external.
This is because dropping the external flag confused fold-const and made us
to miscompile attr-weakref testcase.

This is a lie to compiler - the symbol in question will never be defined by any
external source and it is purely local alias.  This turned out to cause more
harm than benefits - at least I believe so.  I had to hack around in visibility
code (faking weakrefs to be externally-visible), in unreachable code removal,
in LTO partitioning, in static var renaming, in symbol table.

Moreover sometimes this is done by testing DECL_EXTERNAL flag that I hoped to
be safe test for weakref alias. It is not.  C++ FE produces normal external
aliases for same body/extra name machinery. Moreover because aliases used to be
extern at some point (again for wrong reason), the #pragma creates
DECL_EXTERNAL weak aliases in some scenarios, but not in others.

This patch fixes it by making weakrefs to appear local. I kept DECL_WEAK
flag on it that can be used by fold-const to avoid overzealous folding.
I added weakref flag to symtab node and commonized the code special casing
of weakrefs (a lot of it can go away).

I plan to followup with patch cleaning up varasm.c weak/weakref output logic
to be driven by symbol table.

It may be interesting to completely resolve weakref semantic before LTO streaming
time; it is possible if we was able to rewrite weakref uses by the target decl,
but we lack support for it and also weakref symbls may be actualy used by an asm
statements.

Anyway, this patch should solve good part of the problems we are runing into.

Bootstrapped/regtested ppc64-linux with and without weakref support
and x86_64-linux (in earlier version of the patch), comitted.

Honza
	* c-family/c-common.c (handle_alias_ifunc_attribute): Do not set
	DECL_EXTERNAL for weakref variables.
	* c-family/c-pragma.c (handle_pragma_weak): Make sure aliases
	are not declared as external.
	* cgraph.c (cgraph_create_function_alias): Set weakref flag.
	* cgraph.h (symtab_node_base): Add weakref flag.
	* cgraphunit.c (cgraph_reset_node): Clear weakref flag.
	(handle_alias_pairs): Set weakref flag, do not set DECL_EXTERNAL.
	(output_weakrefs): Use weakref flag.
	* fold-const.c (simple_operand_p): Handle WEAK.
	* gimple-fold.c (can_refer_decl_in_current_unit_p): Drop weakref.
	* ipa.c (varpool_externally_visible_p): Drop weakref.
	(function_and_variable_visibility): Update comment; fix weakref
	sanity checks; do not clear DECL_WEAK on them.
	* lto-cgraph.c (lto_output_node): update.
	(lto_output_varpool_node): Update.
	(input_overwrite_node): Update.
	(input_node): Update.
	(input_varpool_node): Update.
	* lto-symtab.c (lto_symtab_symbol_p): Do not special case weakrefs.
	(lto_symtab_merge_symbols): Add sanity check.
	(lto_symtab_prevailing_decl): Do not special case weakrefs.
	* passes.c (rest_of_decl_compilation): Set static flag, too.
	* symtab.c (dump_symtab_base): Dump weakref.
	(verify_symtab_base): Sanity check weakrefs.
	(symtab_make_decl_local): Remove duplicated code.
	(symtab_alias_ultimate_target): Simplify.
	* varpool.c (varpool_create_variable_alias): Set weakref flag.

	* lto-partition.c (get_symbol_class): Simplify weakref handling.
	(add_symbol_to_partition_1): Likewise.
	(contained_in_symbol): Likewise.
	(lto_balanced_map): Likewise.
	(rename_statics): Drop weakref.
diff mbox

Patch

Index: c-family/c-common.c
===================================================================
--- c-family/c-common.c	(revision 199959)
+++ c-family/c-common.c	(working copy)
@@ -7576,13 +7576,7 @@  handle_alias_ifunc_attribute (bool is_al
       if (TREE_CODE (decl) == FUNCTION_DECL)
 	DECL_INITIAL (decl) = error_mark_node;
       else
-	{
-	  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
-	    DECL_EXTERNAL (decl) = 1;
-	  else
-	    DECL_EXTERNAL (decl) = 0;
-	  TREE_STATIC (decl) = 1;
-	}
+	TREE_STATIC (decl) = 1;
 
       if (!is_alias)
 	/* ifuncs are also aliases, so set that attribute too. */
Index: c-family/c-pragma.c
===================================================================
--- c-family/c-pragma.c	(revision 199959)
+++ c-family/c-pragma.c	(working copy)
@@ -367,7 +367,12 @@  handle_pragma_weak (cpp_reader * ARG_UNU
     {
       apply_pragma_weak (decl, value);
       if (value)
-	assemble_alias (decl, value);
+	{
+	  DECL_EXTERNAL (decl) = 0;
+	  if (TREE_CODE (decl) == VAR_DECL)
+	    TREE_STATIC (decl) = 1;
+	  assemble_alias (decl, value);
+	}
     }
   else
     {
Index: cgraph.c
===================================================================
--- cgraph.c	(revision 199959)
+++ cgraph.c	(working copy)
@@ -568,6 +568,8 @@  cgraph_create_function_alias (tree alias
   alias_node->symbol.alias_target = target;
   alias_node->symbol.definition = true;
   alias_node->symbol.alias = true;
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
+    alias_node->symbol.weakref = true;
   return alias_node;
 }
 
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 199959)
+++ cgraph.h	(working copy)
@@ -56,6 +56,8 @@  struct GTY(()) symtab_node_base
   /* True when symbol is an alias.  
      Set by assemble_alias.  */
   unsigned alias : 1;
+  /* True when alias is a weakref.  */
+  unsigned weakref : 1;
   /* C++ frontend produce same body aliases and extra name aliases for
      virutal functions and vtables that are obviously equivalent.
      Those aliases are bit special, especially because C++ frontend
Index: cgraphunit.c
===================================================================
--- cgraphunit.c	(revision 199959)
+++ cgraphunit.c	(working copy)
@@ -379,6 +379,7 @@  cgraph_reset_node (struct cgraph_node *n
   node->symbol.analyzed = false;
   node->symbol.definition = false;
   node->symbol.alias = false;
+  node->symbol.weakref = false;
   node->symbol.cpp_implicit_alias = false;
 
   cgraph_node_remove_callees (node);
@@ -1021,9 +1022,9 @@  handle_alias_pairs (void)
 	  if (node)
 	    {
 	      node->symbol.alias_target = p->target;
+	      node->symbol.weakref = true;
 	      node->symbol.alias = true;
 	    }
-	  DECL_EXTERNAL (p->decl) = 1;
 	  alias_pairs->unordered_remove (i);
 	  continue;
 	}
@@ -1034,16 +1035,6 @@  handle_alias_pairs (void)
 	  continue;
 	}
 
-      /* Normally EXTERNAL flag is used to mark external inlines,
-	 however for aliases it seems to be allowed to use it w/o
-	 any meaning. See gcc.dg/attr-alias-3.c  
-	 However for weakref we insist on EXTERNAL flag being set.
-	 See gcc.dg/attr-alias-5.c  */
-      if (DECL_EXTERNAL (p->decl))
-	DECL_EXTERNAL (p->decl)
-	  = lookup_attribute ("weakref",
-			      DECL_ATTRIBUTES (p->decl)) != NULL;
-
       if (DECL_EXTERNAL (target_node->symbol.decl)
 	  /* We use local aliases for C++ thunks to force the tailcall
 	     to bind locally.  This is a hack - to keep it working do
@@ -1885,9 +1876,9 @@  output_weakrefs (void)
 {
   symtab_node node;
   FOR_EACH_SYMBOL (node)
-    if (node->symbol.alias && DECL_EXTERNAL (node->symbol.decl)
+    if (node->symbol.alias
         && !TREE_ASM_WRITTEN (node->symbol.decl)
-	&& lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+	&& node->symbol.weakref)
       {
 	tree target;
 
Index: fold-const.c
===================================================================
--- fold-const.c	(revision 199959)
+++ fold-const.c	(working copy)
@@ -3755,6 +3755,10 @@  simple_operand_p (const_tree exp)
 		 #pragma weak, etc).  */
 	      && ! TREE_PUBLIC (exp)
 	      && ! DECL_EXTERNAL (exp)
+	      /* Weakrefs are not safe to be read, since they can be NULL.
+ 		 They are !TREE_PUBLIC && !DECL_EXTERNAL but still
+		 have DECL_WEAK flag set.  */
+	      && (! VAR_OR_FUNCTION_DECL_P (exp) || ! DECL_WEAK (exp))
 	      /* Loading a static variable is unduly expensive, but global
 		 registers aren't expensive.  */
 	      && (! TREE_STATIC (exp) || DECL_REGISTER (exp))));
Index: gimple-fold.c
===================================================================
--- gimple-fold.c	(revision 199959)
+++ gimple-fold.c	(working copy)
@@ -73,11 +73,6 @@  can_refer_decl_in_current_unit_p (tree d
   if ((!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
       || (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL))
     return true;
-  /* Weakrefs have somewhat confusing DECL_EXTERNAL flag set; they
-     are always safe.  */
-  if (DECL_EXTERNAL (decl)
-      && lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
-    return true;
   /* We are folding reference from external vtable.  The vtable may reffer
      to a symbol keyed to other compilation unit.  The other compilation
      unit may be in separate DSO and the symbol may be hidden.  */
Index: ipa.c
===================================================================
--- ipa.c	(revision 199959)
+++ ipa.c	(working copy)
@@ -664,12 +664,6 @@  cgraph_externally_visible_p (struct cgra
 bool
 varpool_externally_visible_p (struct varpool_node *vnode)
 {
-  /* Do not touch weakrefs; while they are not externally visible,
-     dropping their DECL_EXTERNAL flags confuse most
-     of code handling them.  */
-  if (vnode->symbol.alias && DECL_EXTERNAL (vnode->symbol.decl))
-    return true;
-
   if (DECL_EXTERNAL (vnode->symbol.decl))
     return true;
 
@@ -784,9 +778,9 @@  function_and_variable_visibility (bool w
 	 happy.  Clear the flag here to avoid confusion in middle-end.  */
       if (DECL_COMDAT (node->symbol.decl) && !TREE_PUBLIC (node->symbol.decl))
         DECL_COMDAT (node->symbol.decl) = 0;
-      /* For external decls stop tracking same_comdat_group, it doesn't matter
-	 what comdat group they are in when they won't be emitted in this TU,
-	 and simplifies later passes.  */
+
+      /* For external decls stop tracking same_comdat_group. It doesn't matter
+	 what comdat group they are in when they won't be emitted in this TU.  */
       if (node->symbol.same_comdat_group && DECL_EXTERNAL (node->symbol.decl))
 	{
 #ifdef ENABLE_CHECKING
@@ -804,6 +798,7 @@  function_and_variable_visibility (bool w
       gcc_assert ((!DECL_WEAK (node->symbol.decl)
 		  && !DECL_COMDAT (node->symbol.decl))
       	          || TREE_PUBLIC (node->symbol.decl)
+		  || node->symbol.weakref
 		  || DECL_EXTERNAL (node->symbol.decl));
       if (cgraph_externally_visible_p (node, whole_program))
         {
@@ -815,7 +810,8 @@  function_and_variable_visibility (bool w
 	  node->symbol.externally_visible = false;
 	  node->symbol.forced_by_abi = false;
 	}
-      if (!node->symbol.externally_visible && node->symbol.definition
+      if (!node->symbol.externally_visible
+	  && node->symbol.definition && !node->symbol.weakref
 	  && !DECL_EXTERNAL (node->symbol.decl))
 	{
 	  gcc_assert (whole_program || in_lto_p
@@ -860,6 +856,7 @@  function_and_variable_visibility (bool w
     {
       /* weak flag makes no sense on local variables.  */
       gcc_assert (!DECL_WEAK (vnode->symbol.decl)
+		  || vnode->symbol.weakref
       		  || TREE_PUBLIC (vnode->symbol.decl)
 		  || DECL_EXTERNAL (vnode->symbol.decl));
       /* In several cases declarations can not be common:
@@ -897,7 +894,8 @@  function_and_variable_visibility (bool w
           vnode->symbol.externally_visible = false;
 	  vnode->symbol.forced_by_abi = false;
 	}
-      if (!vnode->symbol.externally_visible)
+      if (!vnode->symbol.externally_visible
+	  && !vnode->symbol.weakref)
 	{
 	  gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->symbol.decl));
 	  symtab_make_decl_local (vnode->symbol.decl);
Index: lto/lto-partition.c
===================================================================
--- lto/lto-partition.c	(revision 199959)
+++ lto/lto-partition.c	(working copy)
@@ -60,7 +60,7 @@  get_symbol_class (symtab_node node)
     return SYMBOL_DUPLICATE;
 
   /* Weakref aliases are always duplicated.  */
-  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+  if (node->symbol.weakref)
     return SYMBOL_DUPLICATE;
 
   /* External declarations are external.  */
@@ -218,10 +218,7 @@  add_symbol_to_partition_1 (ltrans_partit
 
   /* Add all aliases associated with the symbol.  */
   for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); i++)
-    if (ref->use == IPA_REF_ALIAS
-	&& !lookup_attribute ("weakref",
-			      DECL_ATTRIBUTES
-				(ref->referring->symbol.decl)))
+    if (ref->use == IPA_REF_ALIAS && !node->symbol.weakref)
       add_symbol_to_partition_1 (part, ref->referring);
 
   /* Ensure that SAME_COMDAT_GROUP lists all allways added in a group.  */
@@ -243,8 +240,7 @@  static symtab_node
 contained_in_symbol (symtab_node node)
 {
   /* Weakrefs are never contained in anything.  */
-  if (lookup_attribute ("weakref",
-			DECL_ATTRIBUTES (node->symbol.decl)))
+  if (node->symbol.weakref)
     return node;
   if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
     {
@@ -561,8 +557,7 @@  lto_balanced_map (void)
 
 	      last_visited_node++;
 
-	      gcc_assert (node->symbol.definition
-			  || lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)));
+	      gcc_assert (node->symbol.definition || node->symbol.weakref);
 
 	      /* Compute boundary cost of callgraph edges.  */
 	      for (edge = node->callees; edge; edge = edge->next_callee)
@@ -871,8 +866,7 @@  rename_statics (lto_symtab_encoder_t enc
 	 once this is fixed.  */
         || DECL_EXTERNAL (node->symbol.decl)
         || !symtab_real_symbol_p (node))
-       && !may_need_named_section_p (encoder, node)
-       && !lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+       && !may_need_named_section_p (encoder, node))
     return;
 
   /* Now walk symbols sharing the same name and see if there are any conflicts.
@@ -897,11 +891,9 @@  rename_statics (lto_symtab_encoder_t enc
   /* Assign every symbol in the set that shares the same ASM name an unique
      mangled name.  */
   for (s = symtab_node_for_asm (name); s;)
-    if ((!s->symbol.externally_visible
-	 || lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+    if (!s->symbol.externally_visible
 	&& ((symtab_real_symbol_p (s)
-             && (!DECL_EXTERNAL (node->symbol.decl)
-	         || lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+             && !DECL_EXTERNAL (node->symbol.decl)
 	     && !TREE_PUBLIC (node->symbol.decl))
  	    || may_need_named_section_p (encoder, s))
 	&& (!encoder
Index: lto-cgraph.c
===================================================================
--- lto-cgraph.c	(revision 199959)
+++ lto-cgraph.c	(working copy)
@@ -487,8 +487,9 @@  lto_output_node (struct lto_simple_outpu
      defined in other unit, we may use the info on aliases to resolve 
      symbol1 != symbol2 type tests that we can do only for locally defined objects
      otherwise.  */
-  alias_p = node->symbol.alias && (!boundary_p || DECL_EXTERNAL (node->symbol.decl));
+  alias_p = node->symbol.alias && (!boundary_p || node->symbol.weakref);
   bp_pack_value (&bp, alias_p, 1);
+  bp_pack_value (&bp, node->symbol.weakref, 1);
   bp_pack_value (&bp, node->frequency, 2);
   bp_pack_value (&bp, node->only_called_at_startup, 1);
   bp_pack_value (&bp, node->only_called_at_exit, 1);
@@ -531,8 +532,9 @@  lto_output_varpool_node (struct lto_simp
   bp_pack_value (&bp, node->symbol.forced_by_abi, 1);
   bp_pack_value (&bp, node->symbol.unique_name, 1);
   bp_pack_value (&bp, node->symbol.definition, 1);
-  alias_p = node->symbol.alias && (!boundary_p || DECL_EXTERNAL (node->symbol.decl));
+  alias_p = node->symbol.alias && (!boundary_p || node->symbol.weakref);
   bp_pack_value (&bp, alias_p, 1);
+  bp_pack_value (&bp, node->symbol.weakref, 1);
   bp_pack_value (&bp, node->symbol.analyzed && !boundary_p, 1);
   gcc_assert (node->symbol.definition || !node->symbol.analyzed);
   /* Constant pool initializers can be de-unified into individual ltrans units.
@@ -906,6 +908,7 @@  input_overwrite_node (struct lto_file_de
       TREE_STATIC (node->symbol.decl) = 0;
     }
   node->symbol.alias = bp_unpack_value (bp, 1);
+  node->symbol.weakref = bp_unpack_value (bp, 1);
   node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);
   node->only_called_at_startup = bp_unpack_value (bp, 1);
   node->only_called_at_exit = bp_unpack_value (bp, 1);
@@ -1010,8 +1013,7 @@  input_node (struct lto_file_decl_data *f
       node->thunk.virtual_value = virtual_value;
       node->thunk.virtual_offset_p = (type & 4);
     }
-  if (node->symbol.alias && !node->symbol.analyzed
-      && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+  if (node->symbol.alias && !node->symbol.analyzed && node->symbol.weakref)
     node->symbol.alias_target = get_alias_symbol (node->symbol.decl);
   return node;
 }
@@ -1046,6 +1048,7 @@  input_varpool_node (struct lto_file_decl
   node->symbol.unique_name = bp_unpack_value (&bp, 1);
   node->symbol.definition = bp_unpack_value (&bp, 1);
   node->symbol.alias = bp_unpack_value (&bp, 1);
+  node->symbol.weakref = bp_unpack_value (&bp, 1);
   node->symbol.analyzed = bp_unpack_value (&bp, 1);
   node->symbol.used_from_other_partition = bp_unpack_value (&bp, 1);
   node->symbol.in_other_partition = bp_unpack_value (&bp, 1);
@@ -1054,8 +1057,7 @@  input_varpool_node (struct lto_file_decl
       DECL_EXTERNAL (node->symbol.decl) = 1;
       TREE_STATIC (node->symbol.decl) = 0;
     }
-  if (node->symbol.alias && !node->symbol.analyzed
-      && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+  if (node->symbol.alias && !node->symbol.analyzed && node->symbol.weakref)
     node->symbol.alias_target = get_alias_symbol (node->symbol.decl);
   ref = streamer_read_hwi (ib);
   /* Store a reference for now, and fix up later to be a pointer.  */
Index: lto-symtab.c
===================================================================
--- lto-symtab.c	(revision 199959)
+++ lto-symtab.c	(working copy)
@@ -235,9 +235,6 @@  lto_symtab_symbol_p (symtab_node e)
 {
   if (!TREE_PUBLIC (e->symbol.decl) && !DECL_EXTERNAL (e->symbol.decl))
     return false;
-  /* weakrefs are really static variables that are made external by a hack.  */
-  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (e->symbol.decl)))
-    return false;
   return symtab_real_symbol_p (e);
 }
 
@@ -589,6 +586,7 @@  lto_symtab_merge_symbols (void)
 	  if (!node->symbol.analyzed && node->symbol.alias_target)
 	    {
 	      symtab_node tgt = symtab_node_for_asm (node->symbol.alias_target);
+	      gcc_assert (node->symbol.weakref);
 	      if (tgt)
 		symtab_resolve_alias (node, tgt);
 	    }
@@ -617,11 +615,6 @@  lto_symtab_prevailing_decl (tree decl)
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
     return decl;
 
-  /* As an anoying special cases weakrefs are really static variables with
-     EXTERNAL flag.  */
-  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
-    return decl;
-
   /* Ensure DECL_ASSEMBLER_NAME will not set assembler name.  */
   gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
 
Index: passes.c
===================================================================
--- passes.c	(revision 199959)
+++ passes.c	(working copy)
@@ -136,8 +136,8 @@  rest_of_decl_compilation (tree decl,
 	/* A quirk of the initial implementation of aliases required that the
 	   user add "extern" to all of them.  Which is silly, but now
 	   historical.  Do note that the symbol is in fact locally defined.  */
-	if (!lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
-	  DECL_EXTERNAL (decl) = 0;
+	DECL_EXTERNAL (decl) = 0;
+	TREE_STATIC (decl) = 1;
 	assemble_alias (decl, alias);
       }
   }
Index: symtab.c
===================================================================
--- symtab.c	(revision 199959)
+++ symtab.c	(working copy)
@@ -481,6 +481,8 @@  dump_symtab_base (FILE *f, symtab_node n
     fprintf (f, " analyzed");
   if (node->symbol.alias)
     fprintf (f, " alias");
+  if (node->symbol.weakref)
+    fprintf (f, " weakref");
   if (node->symbol.cpp_implicit_alias)
     fprintf (f, " cpp_implicit_alias");
   if (node->symbol.alias_target)
@@ -682,11 +684,16 @@  verify_symtab_base (symtab_node node)
       error_found = true;
     }
   if (node->symbol.alias && !node->symbol.definition
-      && !lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl)))
+      && !node->symbol.weakref)
     {
       error ("node is alias but not definition");
       error_found = true;
     }
+  if (node->symbol.weakref && !node->symbol.alias)
+    {
+      error ("node is weakref but not an alias");
+      error_found = true;
+    }
   if (node->symbol.same_comdat_group)
     {
       symtab_node n = node->symbol.same_comdat_group;
@@ -799,8 +806,6 @@  symtab_make_decl_local (tree decl)
   DECL_VISIBILITY_SPECIFIED (decl) = 0;
   DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
   TREE_PUBLIC (decl) = 0;
-  DECL_VISIBILITY_SPECIFIED (decl) = 0;
-  DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
   if (!DECL_RTL_SET_P (decl))
     return;
 
@@ -861,7 +866,7 @@  symtab_alias_ultimate_target (symtab_nod
 
   if (availability)
     {
-      weakref_p = DECL_EXTERNAL (node->symbol.decl) && node->symbol.alias;
+      weakref_p = node->symbol.weakref;
       if (!weakref_p)
         *availability = symtab_node_availability (node);
       else
@@ -893,7 +898,7 @@  symtab_alias_ultimate_target (symtab_nod
 	  enum availability a = symtab_node_availability (node);
 	  if (a < *availability)
 	    *availability = a;
-          weakref_p = DECL_EXTERNAL (node->symbol.decl) && node->symbol.alias;
+          weakref_p = node->symbol.weakref;
 	}
     }
   if (availability)
Index: varpool.c
===================================================================
--- varpool.c	(revision 199959)
+++ varpool.c	(working copy)
@@ -452,6 +452,8 @@  varpool_create_variable_alias (tree alia
   alias_node->symbol.alias = true;
   alias_node->symbol.definition = true;
   alias_node->symbol.alias_target = decl;
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
+    alias_node->symbol.weakref = true;
   return alias_node;
 }