OSDN Git Service

PR other/4372
authoraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 9 Nov 2005 20:13:41 +0000 (20:13 +0000)
committeraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 9 Nov 2005 20:13:41 +0000 (20:13 +0000)
* tree.h (IDENTIFIER_TRANSPARENT_ALIAS): New.
(TREE_DEPRECATED): Adjust comment.  Check for a DECL.
* c-common.c (handle_weakref_attribute): New.
(c_common_attribute_table): Add weakref.
* configure.ac (HAVE_GAS_WEAKREF): Check for weakref support
in the assembler.
* configure, config.in: Rebuilt.
* defaults.h (ASM_OUTPUT_WEAKREF): Define if HAVE_GAS_WEAKREF.
* doc/extend.texi: Document weakref attribute.
* varasm.c (ultimate_transparent_alias_target): New
(assemble_name): Use it.
(weak_finish_1): Split out of...
(weak_finish): ... and deal with weakrefs in...
(weakref_targets): ... new list.
(globalize_decl): Clean up weakref_targets.
(do_assemble_alias): Handle weakrefs.
(finish_aliases_1): Do not reject weakrefs to external symbols.
(assemble_alias): Handle weakrefs.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@106703 138bc75d-0d04-0410-961f-82ee72b054a4

13 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/config.in
gcc/configure
gcc/configure.ac
gcc/defaults.h
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.old-deja/g++.abi/vtable2.C
gcc/testsuite/gcc.dg/attr-weakref-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-weakref-1a.c [new file with mode: 0644]
gcc/tree.h
gcc/varasm.c

index 10cad44..cdbf858 100644 (file)
@@ -1,3 +1,25 @@
+2005-11-09  Alexandre Oliva  <aoliva@redhat.com>
+
+       PR other/4372
+       * tree.h (IDENTIFIER_TRANSPARENT_ALIAS): New.
+       (TREE_DEPRECATED): Adjust comment.  Check for a DECL.
+       * c-common.c (handle_weakref_attribute): New.
+       (c_common_attribute_table): Add weakref.
+       * configure.ac (HAVE_GAS_WEAKREF): Check for weakref support
+       in the assembler.
+       * configure, config.in: Rebuilt.
+       * defaults.h (ASM_OUTPUT_WEAKREF): Define if HAVE_GAS_WEAKREF.
+       * doc/extend.texi: Document weakref attribute.
+       * varasm.c (ultimate_transparent_alias_target): New
+       (assemble_name): Use it.
+       (weak_finish_1): Split out of...
+       (weak_finish): ... and deal with weakrefs in...
+       (weakref_targets): ... new list.
+       (globalize_decl): Clean up weakref_targets.
+       (do_assemble_alias): Handle weakrefs.
+       (finish_aliases_1): Do not reject weakrefs to external symbols.
+       (assemble_alias): Handle weakrefs.
+
 2005-11-09  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/24716
index abd33d2..4501841 100644 (file)
@@ -520,6 +520,7 @@ static tree handle_section_attribute (tree *, tree, tree, int, bool *);
 static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
 static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_alias_attribute (tree *, tree, tree, int, bool *);
+static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_visibility_attribute (tree *, tree, tree, int,
                                         bool *);
 static tree handle_tls_model_attribute (tree *, tree, tree, int,
@@ -599,6 +600,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_weak_attribute },
   { "alias",                  1, 1, true,  false, false,
                              handle_alias_attribute },
+  { "weakref",                0, 1, true,  false, false,
+                             handle_weakref_attribute },
   { "no_instrument_function", 0, 0, true,  false, false,
                              handle_no_instrument_function_attribute },
   { "malloc",                 0, 0, true,  false, false,
@@ -4742,7 +4745,10 @@ handle_alias_attribute (tree *node, tree name, tree args,
        DECL_INITIAL (decl) = error_mark_node;
       else
        {
-         DECL_EXTERNAL (decl) = 0;
+         if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+           DECL_EXTERNAL (decl) = 1;
+         else
+           DECL_EXTERNAL (decl) = 0;
          TREE_STATIC (decl) = 1;
        }
     }
@@ -4755,6 +4761,40 @@ handle_alias_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
+/* Handle a "weakref" attribute; arguments as in struct
+   attribute_spec.handler.  */
+
+static tree
+handle_weakref_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+                         int flags, bool *no_add_attrs)
+{
+  tree attr = NULL_TREE;
+
+  /* The idea here is that `weakref("name")' mutates into `weakref,
+     alias("name")', and weakref without arguments, in turn,
+     implicitly adds weak. */
+
+  if (args)
+    {
+      attr = tree_cons (get_identifier ("alias"), args, attr);
+      attr = tree_cons (get_identifier ("weakref"), NULL_TREE, attr);
+
+      *no_add_attrs = true;
+    }
+  else
+    {
+      if (lookup_attribute ("alias", DECL_ATTRIBUTES (*node)))
+       error ("%Jweakref attribute must appear before alias attribute",
+              *node);
+
+      attr = tree_cons (get_identifier ("weak"), NULL_TREE, attr);
+    }
+
+  decl_attributes (node, attr, flags);
+
+  return NULL_TREE;
+}
+
 /* Handle an "visibility" attribute; arguments as in
    struct attribute_spec.handler.  */
 
index fa39a35..3577c8c 100644 (file)
 #endif
 
 
+/* Define if your assembler supports .weakref. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GAS_WEAKREF
+#endif
+
+
 /* Define to 1 if you have the `getchar_unlocked' function. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GETCHAR_UNLOCKED
index df77571..ba43b58 100755 (executable)
@@ -13988,6 +13988,43 @@ _ACEOF
 
 fi
 
+echo "$as_me:$LINENO: checking assembler for .weakref" >&5
+echo $ECHO_N "checking assembler for .weakref... $ECHO_C" >&6
+if test "${gcc_cv_as_weakref+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  gcc_cv_as_weakref=no
+    if test $in_tree_gas = yes; then
+    if test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 17 \) \* 1000 + 0`
+  then gcc_cv_as_weakref=yes
+fi
+  elif test x$gcc_cv_as != x; then
+    echo '     .weakref foobar, barfnot' > conftest.s
+    if { ac_try='$gcc_cv_as  -o conftest.o conftest.s >&5'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }
+    then
+       gcc_cv_as_weakref=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+echo "$as_me:$LINENO: result: $gcc_cv_as_weakref" >&5
+echo "${ECHO_T}$gcc_cv_as_weakref" >&6
+if test $gcc_cv_as_weakref = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GAS_WEAKREF 1
+_ACEOF
+
+fi
+
 echo "$as_me:$LINENO: checking assembler for .nsubspa comdat" >&5
 echo $ECHO_N "checking assembler for .nsubspa comdat... $ECHO_C" >&6
 if test "${gcc_cv_as_nsubspa_comdat+set}" = set; then
index 0648caa..5cee180 100644 (file)
@@ -1947,6 +1947,11 @@ gcc_GAS_CHECK_FEATURE([.weak], gcc_cv_as_weak,
  [     .weak foobar],,
 [AC_DEFINE(HAVE_GAS_WEAK, 1, [Define if your assembler supports .weak.])])
 
+gcc_GAS_CHECK_FEATURE([.weakref], gcc_cv_as_weakref,
+ [2,17,0],,
+ [     .weakref foobar, barfnot],,
+[AC_DEFINE(HAVE_GAS_WEAKREF, 1, [Define if your assembler supports .weakref.])])
+
 gcc_GAS_CHECK_FEATURE([.nsubspa comdat], gcc_cv_as_nsubspa_comdat,
  [2,15,91],,
  [     .SPACE $TEXT$
index 9ac1afc..9d82960 100644 (file)
@@ -166,6 +166,27 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #endif
 #endif
 
+/* This is how we tell the assembler that a symbol is a weak alias to
+   another symbol that doesn't require the other symbol to be defined.
+   Uses of the former will turn into weak uses of the latter, i.e.,
+   uses that, in case the latter is undefined, will not cause errors,
+   and will add it to the symbol table as weak undefined.  However, if
+   the latter is referenced directly, a strong reference prevails.  */
+#ifndef ASM_OUTPUT_WEAKREF
+#if defined HAVE_GAS_WEAKREF
+#define ASM_OUTPUT_WEAKREF(FILE, NAME, VALUE)                          \
+  do                                                                   \
+    {                                                                  \
+      fprintf ((FILE), "\t.weakref\t");                                        \
+      assemble_name ((FILE), (NAME));                                  \
+      fprintf ((FILE), ",");                                           \
+      assemble_name ((FILE), (VALUE));                                 \
+      fprintf ((FILE), "\n");                                          \
+    }                                                                  \
+  while (0)
+#endif
+#endif
+
 /* How to emit a .type directive.  */
 #ifndef ASM_OUTPUT_TYPE_DIRECTIVE
 #if defined TYPE_ASM_OP && defined TYPE_OPERAND_FMT
index 52a8cc2..a796da6 100644 (file)
@@ -2364,6 +2364,38 @@ also be used with non-function declarations.  Weak symbols are supported
 for ELF targets, and also for a.out targets when using the GNU assembler
 and linker.
 
+@item weakref
+@itemx weakref ("@var{target}")
+@cindex @code{weakref} attribute
+The @code{weakref} attribute marks a declaration as a weak reference.
+Without arguments, it should be accompanied by an @code{alias} attribute
+naming the target symbol.  Optionally, the @var{target} may be given as
+an argument to @code{weakref} itself.  In either case, @code{weakref}
+implicitly marks the declaration as @code{weak}.  Without a
+@var{target}, given as an argument to @code{weakref} or to @code{alias},
+@code{weakref} is equivalent to @code{weak}.
+
+@smallexample
+extern int x() __attribute__ ((weakref ("y")));
+/* is equivalent to... */
+extern int x() __attribute__ ((weak, weakref, alias ("y")));
+/* and to... */
+extern int x() __attribute__ ((weakref));
+extern int x() __attribute__ ((alias ("y")));
+@end smallexample
+
+A weak reference is an alias that does not by itself require a
+definition to be given for the target symbol.  If the target symbol is
+only referenced through weak references, then the becomes a @code{weak}
+undefined symbol.  If it is directly referenced, however, then such
+strong references prevail, and a definition will be required for the
+symbol, not necessarily in the same translation unit.
+
+The effect is equivalent to moving all references to the alias to a
+separate translation unit, renaming the alias to the aliased symbol,
+declaring it as weak, compiling the two separate translation units and
+performing a reloadable link on them.
+
 @item externally_visible
 @cindex @code{externally_visible} attribute.
 This attribute, attached to a global variable or function nullify
index af46bf2..43444c8 100644 (file)
@@ -1,3 +1,9 @@
+2005-11-09  Alexandre Oliva  <aoliva@redhat.com>
+
+       PR other/4372
+       * gcc.dg/attr-weakref-1.c, gcc.dg/attr-weakref-1a.c: New test.
+       * g++.old-deja/g++.abi/vtable2.C: Use weakref instead of alias.
+
 2005-11-09  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/24716
index 9371b85..a36cf0e 100644 (file)
@@ -1,5 +1,4 @@
 // { dg-do run  }
-// { dg-require-alias "" }
 // { dg-options "-fno-strict-aliasing" }
 // Origin: Mark Mitchell <mark@codesourcery.com>
 
@@ -125,8 +124,11 @@ void S4::s1 ()
 // These are tricks to allow us to get raw function pointers for
 // member functions.
 extern "C" {
-  void S3_s3 () __attribute__((__alias__ ("_ZN2S32s3Ev")));
-  void S4_s1 () __attribute__((__alias__ ("_ZN2S42s1Ev")));
+  /* We can use weakref here without dg-require-weak, because we know
+     the symbols are defined, so we don't actually issue the .weak
+     directives.  */
+  void S3_s3 () __attribute__((__weakref__ ("_ZN2S32s3Ev")));
+  void S4_s1 () __attribute__((__weakref__ ("_ZN2S42s1Ev")));
 }
 
 // IA-64 uses function descriptors not function pointers in its vtables.
diff --git a/gcc/testsuite/gcc.dg/attr-weakref-1.c b/gcc/testsuite/gcc.dg/attr-weakref-1.c
new file mode 100644 (file)
index 0000000..df58be9
--- /dev/null
@@ -0,0 +1,226 @@
+// { dg-do run }
+// { dg-additional-sources " attr-weakref-1a.c" }
+// { dg-require-weak "" }
+// { dg-options "-O2" }
+
+// Copyright 2005 Free Software Foundation, Inc.
+// Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+// Torture test for weakrefs.  The first letter of an identifier
+// indicates whether/how it is defined; the second letter indicates
+// whether it is part of a variable or function test; the number that
+// follows is a test counter, and a letter that may follow enables
+// multiple identifiers within the same test (e.g., multiple weakrefs
+// or pointers to the same identifier).
+
+// Identifiers starting with W are weakrefs; those with p are
+// pointers; those with g are global definitions; those with l are
+// local definitions; those with w are expected to be weak undefined
+// in the symbol table; those with u are expected to be marked as
+// non-weak undefined in the symbol table.
+
+#include <stdlib.h>
+
+#define USED __attribute__((used))
+
+typedef int vtype;
+
+extern vtype wv1;
+extern vtype Wv1a __attribute__((weakref ("wv1")));
+static vtype *pv1a USED = &Wv1a;
+extern vtype Wv1b __attribute__((weak, weakref, alias ("wv1")));
+static vtype *pv1b USED = &Wv1b;
+extern vtype Wv1c __attribute__((weakref));
+extern vtype Wv1c __attribute__((alias ("wv1")));
+static vtype *pv1c USED = &Wv1c;
+
+vtype gv2;
+extern vtype Wv2a __attribute__((weakref ("gv2")));
+static vtype *pv2a USED = &Wv2a;
+
+static vtype lv3;
+extern vtype Wv3a __attribute__((weakref ("lv3")));
+static vtype *pv3a USED = &Wv3a;
+
+extern vtype uv4;
+extern vtype Wv4a __attribute__((weakref ("uv4")));
+static vtype *pv4a USED = &Wv4a;
+static vtype *pv4 USED = &uv4;
+
+extern vtype Wv5a __attribute__((weakref ("uv5")));
+static vtype *pv5a USED = &Wv5a;
+extern vtype uv5;
+static vtype *pv5 USED = &uv5;
+
+extern vtype Wv6a __attribute__((weakref ("wv6")));
+static vtype *pv6a USED = &Wv6a;
+extern vtype wv6;
+
+extern vtype Wv7a __attribute__((weakref ("uv7")));
+static vtype* USED fv7 (void) {
+  return &Wv7a;
+}
+extern vtype uv7;
+static vtype* USED fv7a (void) {
+  return &uv7;
+}
+
+extern vtype uv8;
+static vtype* USED fv8a (void) {
+  return &uv8;
+}
+extern vtype Wv8a __attribute__((weakref ("uv8")));
+static vtype* USED fv8 (void) {
+  return &Wv8a;
+}
+
+extern vtype wv9 __attribute__((weak));
+extern vtype Wv9a __attribute__((weakref ("wv9")));
+static vtype *pv9a USED = &Wv9a;
+
+extern vtype Wv10a __attribute__((weakref ("Wv10b")));
+extern vtype Wv10b __attribute__((weakref ("Wv10c")));
+extern vtype Wv10c __attribute__((weakref ("Wv10d")));
+extern vtype Wv10d __attribute__((weakref ("wv10")));
+extern vtype wv10;
+
+extern vtype wv11;
+extern vtype Wv11d __attribute__((weakref ("wv11")));
+extern vtype Wv11c __attribute__((weakref ("Wv11d")));
+extern vtype Wv11b __attribute__((weakref ("Wv11c")));
+extern vtype Wv11a __attribute__((weakref ("Wv11b")));
+
+extern vtype Wv12 __attribute__((weakref ("wv12")));
+extern vtype wv12 __attribute__((weak));
+
+extern vtype Wv13 __attribute__((weakref ("wv13")));
+extern vtype wv13 __attribute__((weak));
+
+extern vtype Wv14a __attribute__((weakref ("wv14")));
+extern vtype Wv14b __attribute__((weakref ("wv14")));
+extern vtype wv14 __attribute__((weak));
+
+typedef void ftype(void);
+
+extern ftype wf1;
+extern ftype Wf1a __attribute__((weakref ("wf1")));
+static ftype *pf1a USED = &Wf1a;
+extern ftype Wf1b __attribute__((weak, weakref, alias ("wf1")));
+static ftype *pf1b USED = &Wf1b;
+extern ftype Wf1c __attribute__((weakref));
+extern ftype Wf1c __attribute__((alias ("wf1")));
+static ftype *pf1c USED = &Wf1c;
+
+void gf2(void) {}
+extern ftype Wf2a __attribute__((weakref ("gf2")));
+static ftype *pf2a USED = &Wf2a;
+
+static void lf3(void) {}
+extern ftype Wf3a __attribute__((weakref ("lf3")));
+static ftype *pf3a USED = &Wf3a;
+
+extern ftype uf4;
+extern ftype Wf4a __attribute__((weakref ("uf4")));
+static ftype *pf4a USED = &Wf4a;
+static ftype *pf4 USED = &uf4;
+
+extern ftype Wf5a __attribute__((weakref ("uf5")));
+static ftype *pf5a USED = &Wf5a;
+extern ftype uf5;
+static ftype *pf5 USED = &uf5;
+
+extern ftype Wf6a __attribute__((weakref ("wf6")));
+static ftype *pf6a USED = &Wf6a;
+extern ftype wf6;
+
+extern ftype Wf7a __attribute__((weakref ("uf7")));
+static ftype* USED ff7 (void) {
+  return &Wf7a;
+}
+extern ftype uf7;
+static ftype* USED ff7a (void) {
+  return &uf7;
+}
+
+extern ftype uf8;
+static ftype* USED ff8a (void) {
+  return &uf8;
+}
+extern ftype Wf8a __attribute__((weakref ("uf8")));
+static ftype* USED ff8 (void) {
+  return &Wf8a;
+}
+
+extern ftype wf9 __attribute__((weak));
+extern ftype Wf9a __attribute__((weakref ("wf9")));
+static ftype *pf9a USED = &Wf9a;
+
+extern ftype Wf10a __attribute__((weakref ("Wf10b")));
+extern ftype Wf10b __attribute__((weakref ("Wf10c")));
+extern ftype Wf10c __attribute__((weakref ("Wf10d")));
+extern ftype Wf10d __attribute__((weakref ("wf10")));
+extern ftype wf10;
+
+extern ftype wf11;
+extern ftype Wf11d __attribute__((weakref ("wf11")));
+extern ftype Wf11c __attribute__((weakref ("Wf11d")));
+extern ftype Wf11b __attribute__((weakref ("Wf11c")));
+extern ftype Wf11a __attribute__((weakref ("Wf11b")));
+
+extern ftype Wf12 __attribute__((weakref ("wf12")));
+extern ftype wf12 __attribute__((weak));
+
+extern ftype Wf13 __attribute__((weakref ("wf13")));
+extern ftype wf13 __attribute__((weak));
+
+extern ftype Wf14a __attribute__((weakref ("wf14")));
+extern ftype Wf14b __attribute__((weakref ("wf14")));
+extern ftype wf14 __attribute__((weak));
+
+#define chk(p) do { if (!p) abort (); } while (0)
+
+int main () {
+  chk (!pv1a);
+  chk (!pv1b);
+  chk (!pv1c);
+  chk (pv2a);
+  chk (pv3a);
+  chk (pv4a);
+  chk (pv4);
+  chk (pv5a);
+  chk (pv5);
+  chk (!pv6a);
+  chk (fv7 ());
+  chk (fv7a ());
+  chk (fv8 ());
+  chk (fv8a ());
+  chk (!pv9a);
+  chk (!&Wv10a);
+  chk (!&Wv11a);
+  chk (!&Wv12);
+  chk (!&wv12);
+  chk (!&wv13);
+  chk (!&Wv14a);
+
+  chk (!pf1a);
+  chk (!pf1b);
+  chk (!pf1c);
+  chk (pf2a);
+  chk (pf3a);
+  chk (pf4a);
+  chk (pf4);
+  chk (pf5a);
+  chk (pf5);
+  chk (!pf6a);
+  chk (ff7 ());
+  chk (ff7a ());
+  chk (ff8 ());
+  chk (ff8a ());
+  chk (!pf9a);
+  chk (!&Wf10a);
+  chk (!&Wf11a);
+  chk (!&Wf12);
+  chk (!&wf12);
+  chk (!&wf13);
+  chk (!&Wf14a);
+}
diff --git a/gcc/testsuite/gcc.dg/attr-weakref-1a.c b/gcc/testsuite/gcc.dg/attr-weakref-1a.c
new file mode 100644 (file)
index 0000000..5ce1e4e
--- /dev/null
@@ -0,0 +1,8 @@
+int uv4;
+int uv5;
+int uv7;
+int uv8;
+void uf4 (void) {}
+void uf5 (void) {}
+void uf7 (void) {}
+void uf8 (void) {}
index 7b1796c..0df8b3c 100644 (file)
@@ -428,6 +428,9 @@ struct tree_common GTY(())
        TREE_DEPRECATED in
           ..._DECL
 
+       IDENTIFIER_TRANSPARENT_ALIAS in
+          IDENTIFIER_NODE
+
    visited:
 
        Used in tree traversals to mark visited nodes.
@@ -1042,9 +1045,15 @@ extern void tree_operand_check_failed (int, enum tree_code,
    In a BLOCK node, this is BLOCK_HANDLER_BLOCK.  */
 #define TREE_PROTECTED(NODE) ((NODE)->common.protected_flag)
 
-/* Nonzero in an IDENTIFIER_NODE if the use of the name is defined as a
+/* Nonzero in a _DECL if the use of the name is defined as a
    deprecated feature by __attribute__((deprecated)).  */
-#define TREE_DEPRECATED(NODE) ((NODE)->common.deprecated_flag)
+#define TREE_DEPRECATED(NODE) \
+  ((NODE)->common.deprecated_flag)
+
+/* Nonzero in an IDENTIFIER_NODE if the name is a local alias, whose
+   uses are to be substituted for uses of the TREE_CHAINed identifier.  */
+#define IDENTIFIER_TRANSPARENT_ALIAS(NODE) \
+  (IDENTIFIER_NODE_CHECK (NODE)->common.deprecated_flag)
 
 /* Value of expression is function invariant.  A strict subset of
    TREE_CONSTANT, such an expression is constant over any one function
index 83f47ac..f9fa0fd 100644 (file)
@@ -1995,6 +1995,23 @@ mark_decl_referenced (tree decl)
      which do not need to be marked.  */
 }
 
+static inline tree
+ultimate_transparent_alias_target (tree *alias)
+{
+  tree target = *alias;
+
+  if (IDENTIFIER_TRANSPARENT_ALIAS (target))
+    {
+      gcc_assert (TREE_CHAIN (target));
+      target = ultimate_transparent_alias_target (&TREE_CHAIN (target));
+      gcc_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target)
+                 && ! TREE_CHAIN (target));
+      *alias = target;
+    }
+
+  return target;
+}
+
 /* Output to FILE (an assembly file) a reference to NAME.  If NAME
    starts with a *, the rest of NAME is output verbatim.  Otherwise
    NAME is transformed in a target-specific way (usually by the
@@ -2024,7 +2041,12 @@ assemble_name (FILE *file, const char *name)
 
   id = maybe_get_identifier (real_name);
   if (id)
-    mark_referenced (id);
+    {
+      mark_referenced (id);
+      ultimate_transparent_alias_target (&id);
+      name = IDENTIFIER_POINTER (id);
+      gcc_assert (! TREE_CHAIN (id));
+    }
 
   assemble_name_raw (file, name);
 }
@@ -4464,35 +4486,121 @@ declare_weak (tree decl)
   mark_weak (decl);
 }
 
-/* Emit any pending weak declarations.  */
-
-void
-weak_finish (void)
+static void
+weak_finish_1 (tree decl)
 {
-  tree t;
-
-  for (t = weak_decls; t; t = TREE_CHAIN (t))
-    {
-      tree decl = TREE_VALUE (t);
 #if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
-      const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 #endif
 
-      if (! TREE_USED (decl))
-       continue;
+  if (! TREE_USED (decl))
+    return;
+
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
+      && lookup_attribute ("alias", DECL_ATTRIBUTES (decl)))
+    return;
 
 #ifdef ASM_WEAKEN_DECL
-      ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
+  ASM_WEAKEN_DECL (asm_out_file, decl, name, NULL);
 #else
 #ifdef ASM_WEAKEN_LABEL
-      ASM_WEAKEN_LABEL (asm_out_file, name);
+  ASM_WEAKEN_LABEL (asm_out_file, name);
 #else
 #ifdef ASM_OUTPUT_WEAK_ALIAS
-      warning (0, "only weak aliases are supported in this configuration");
-      return;
+  {
+    static bool warn_once = 0;
+    if (! warn_once)
+      {
+       warning (0, "only weak aliases are supported in this configuration");
+       warn_once = 1;
+      }
+    return;
+  }
+#endif
 #endif
 #endif
+}
+
+/* This TREE_LIST contains weakref targets.  */
+
+static GTY(()) tree weakref_targets;
+
+/* Forward declaration.  */
+static tree find_decl_and_mark_needed (tree decl, tree target);
+
+/* Emit any pending weak declarations.  */
+
+void
+weak_finish (void)
+{
+  tree t;
+
+  for (t = weakref_targets; t; t = TREE_CHAIN (t))
+    {
+      tree alias_decl = TREE_PURPOSE (t);
+      tree target = ultimate_transparent_alias_target (&TREE_VALUE (t));
+
+      if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias_decl)))
+       /* Remove alias_decl from the weak list, but leave entries for
+          the target alone.  */
+       target = NULL_TREE;
+#ifndef ASM_OUTPUT_WEAKREF
+      else if (! TREE_SYMBOL_REFERENCED (target))
+       {
+# ifdef ASM_WEAKEN_LABEL
+         ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
+# else
+         tree decl = find_decl_and_mark_needed (alias_decl, target);
+
+         if (! decl)
+           {
+             decl = build_decl (TREE_CODE (alias_decl), target,
+                                TREE_TYPE (alias_decl));
+
+             DECL_EXTERNAL (decl) = 1;
+             TREE_PUBLIC (decl) = 1;
+             DECL_ARTIFICIAL (decl) = 1;
+             TREE_NOTHROW (decl) = TREE_NOTHROW (alias_decl);
+             TREE_USED (decl) = 1;
+           }
+
+         weak_finish_1 (decl);
+# endif
+       }
 #endif
+
+      {
+       tree *p;
+       tree t2;
+
+       /* Remove the alias and the target from the pending weak list
+          so that we do not emit any .weak directives for the former,
+          nor multiple .weak directives for the latter.  */
+       for (p = &weak_decls; (t2 = *p) ; )
+         {
+           if (TREE_VALUE (t2) == alias_decl
+               || target == DECL_ASSEMBLER_NAME (TREE_VALUE (t2)))
+             *p = TREE_CHAIN (t2);
+           else
+             p = &TREE_CHAIN (t2);
+         }
+
+       /* Remove other weakrefs to the same target, to speed things up.  */
+       for (p = &TREE_CHAIN (t); (t2 = *p) ; )
+         {
+           if (target == ultimate_transparent_alias_target (&TREE_VALUE (t2)))
+             *p = TREE_CHAIN (t2);
+           else
+             p = &TREE_CHAIN (t2);
+         }
+      }
+    }
+
+  for (t = weak_decls; t; t = TREE_CHAIN (t))
+    {
+      tree decl = TREE_VALUE (t);
+
+      weak_finish_1 (decl);
     }
 }
 
@@ -4523,6 +4631,18 @@ globalize_decl (tree decl)
          else
            p = &TREE_CHAIN (t);
        }
+
+       /* Remove weakrefs to the same target from the pending weakref
+          list, for the same reason.  */
+       for (p = &weakref_targets; (t = *p) ; )
+         {
+           if (DECL_ASSEMBLER_NAME (decl)
+               == ultimate_transparent_alias_target (&TREE_VALUE (t)))
+             *p = TREE_CHAIN (t);
+           else
+             p = &TREE_CHAIN (t);
+         }
+
       return;
     }
 #elif defined(ASM_MAKE_LABEL_LINKONCE)
@@ -4596,7 +4716,7 @@ find_decl_and_mark_needed (tree decl, tree target)
    tree node is DECL to have the value of the tree node TARGET.  */
 
 static void
-do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
+do_assemble_alias (tree decl, tree target)
 {
   if (TREE_ASM_WRITTEN (decl))
     return;
@@ -4604,6 +4724,27 @@ do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
   TREE_ASM_WRITTEN (decl) = 1;
   TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
 
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+    {
+      ultimate_transparent_alias_target (&target);
+
+      if (!TREE_SYMBOL_REFERENCED (target))
+       weakref_targets = tree_cons (decl, target, weakref_targets);
+
+#ifdef ASM_OUTPUT_WEAKREF
+      ASM_OUTPUT_WEAKREF (asm_out_file,
+                         IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+                         IDENTIFIER_POINTER (target));
+#else
+      if (!SUPPORTS_WEAK)
+       {
+         error ("%Jweakref is not supported in this configuration", decl);
+         return;
+       }
+#endif
+      return;
+    }
+
 #ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
 
@@ -4638,6 +4779,17 @@ do_assemble_alias (tree decl, tree target ATTRIBUTE_UNUSED)
        *p = TREE_CHAIN (t);
       else
        p = &TREE_CHAIN (t);
+
+    /* Remove weakrefs to the same target from the pending weakref
+       list, for the same reason.  */
+    for (p = &weakref_targets; (t = *p) ; )
+      {
+       if (DECL_ASSEMBLER_NAME (decl)
+           == ultimate_transparent_alias_target (&TREE_VALUE (t)))
+         *p = TREE_CHAIN (t);
+       else
+         p = &TREE_CHAIN (t);
+      }
   }
 #endif
 }
@@ -4657,9 +4809,13 @@ finish_aliases_1 (void)
 
       target_decl = find_decl_and_mark_needed (p->decl, p->target);
       if (target_decl == NULL)
-       error ("%q+D aliased to undefined symbol %qs",
-              p->decl, IDENTIFIER_POINTER (p->target));
-      else if (DECL_EXTERNAL (target_decl))
+       {
+         if (! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
+           error ("%q+D aliased to undefined symbol %qs",
+                  p->decl, IDENTIFIER_POINTER (p->target));
+       }
+      else if (DECL_EXTERNAL (target_decl)
+              && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
        error ("%q+D aliased to external symbol %qs",
               p->decl, IDENTIFIER_POINTER (p->target));
     }
@@ -4688,19 +4844,41 @@ void
 assemble_alias (tree decl, tree target)
 {
   tree target_decl;
+  bool is_weakref = false;
 
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+    {
+      tree alias = DECL_ASSEMBLER_NAME (decl);
+
+      is_weakref = true;
+
+      ultimate_transparent_alias_target (&target);
+
+      if (alias == target)
+       error ("%Jweakref %qD ultimately targets itself", decl, decl);
+      else
+       {
+#ifndef ASM_OUTPUT_WEAKREF
+         IDENTIFIER_TRANSPARENT_ALIAS (alias) = 1;
+         TREE_CHAIN (alias) = target;
+#endif
+       }
+    }
+  else
+    {
 #if !defined (ASM_OUTPUT_DEF)
 # if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
-  error ("%Jalias definitions not supported in this configuration", decl);
-  return;
-# else
-  if (!DECL_WEAK (decl))
-    {
-      error ("%Jonly weak aliases are supported in this configuration", decl);
+      error ("%Jalias definitions not supported in this configuration", decl);
       return;
-    }
+# else
+      if (!DECL_WEAK (decl))
+       {
+         error ("%Jonly weak aliases are supported in this configuration", decl);
+         return;
+       }
 # endif
 #endif
+    }
 
   /* We must force creation of DECL_RTL for debug info generation, even though
      we don't use it here.  */
@@ -4710,7 +4888,8 @@ assemble_alias (tree decl, tree target)
   /* 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.  */
-  DECL_EXTERNAL (decl) = 0;
+  if (! is_weakref)
+    DECL_EXTERNAL (decl) = 0;
 
   /* Allow aliases to aliases.  */
   if (TREE_CODE (decl) == FUNCTION_DECL)