From f4a30bd79f3157bbcbde8aa853c04871575db926 Mon Sep 17 00:00:00 2001 From: aoliva Date: Wed, 9 Nov 2005 20:13:41 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@106703 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 22 +++ gcc/c-common.c | 42 ++++- gcc/config.in | 6 + gcc/configure | 37 +++++ gcc/configure.ac | 5 + gcc/defaults.h | 21 +++ gcc/doc/extend.texi | 32 ++++ gcc/testsuite/ChangeLog | 6 + gcc/testsuite/g++.old-deja/g++.abi/vtable2.C | 8 +- gcc/testsuite/gcc.dg/attr-weakref-1.c | 226 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/attr-weakref-1a.c | 8 + gcc/tree.h | 13 +- gcc/varasm.c | 237 +++++++++++++++++++++++---- 13 files changed, 628 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/attr-weakref-1.c create mode 100644 gcc/testsuite/gcc.dg/attr-weakref-1a.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 10cad44a68c..cdbf858843c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,25 @@ +2005-11-09 Alexandre Oliva + + 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 PR tree-optimization/24716 diff --git a/gcc/c-common.c b/gcc/c-common.c index abd33d2a183..45018411096 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -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. */ diff --git a/gcc/config.in b/gcc/config.in index fa39a356efc..3577c8c1d22 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -744,6 +744,12 @@ #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 diff --git a/gcc/configure b/gcc/configure index df77571c5ca..ba43b58a4c9 100755 --- a/gcc/configure +++ b/gcc/configure @@ -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 diff --git a/gcc/configure.ac b/gcc/configure.ac index 0648caaf81f..5cee180e021 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -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$ diff --git a/gcc/defaults.h b/gcc/defaults.h index 9ac1afc6c11..9d82960e987 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -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 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 52a8cc27142..a796da62685 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index af46bf210f9..43444c85dc0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2005-11-09 Alexandre Oliva + + 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 PR tree-optimization/24716 diff --git a/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C index 9371b856ce7..a36cf0e7f17 100644 --- a/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C +++ b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C @@ -1,5 +1,4 @@ // { dg-do run } -// { dg-require-alias "" } // { dg-options "-fno-strict-aliasing" } // Origin: Mark Mitchell @@ -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 index 00000000000..df58be96c13 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-weakref-1.c @@ -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 + +// 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 + +#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 index 00000000000..5ce1e4e72da --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-weakref-1a.c @@ -0,0 +1,8 @@ +int uv4; +int uv5; +int uv7; +int uv8; +void uf4 (void) {} +void uf5 (void) {} +void uf7 (void) {} +void uf8 (void) {} diff --git a/gcc/tree.h b/gcc/tree.h index 7b1796c0800..0df8b3c28d1 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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 diff --git a/gcc/varasm.c b/gcc/varasm.c index 83f47ac486e..f9fa0fdf181 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -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) -- 2.11.4.GIT