From 29d2485270f422a4b89bfa79e448843509cd0568 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Sat, 5 Jan 2019 00:57:30 +0000 Subject: [PATCH] PR c/88546 - Copy attribute unusable for weakrefs gcc/c-family/ChangeLog: PR c/88546 * c-attribs.c (handle_copy_attribute): Avoid copying attribute leaf. Handle C++ empty throw specification and C11 _Noreturn. (has_attribute): Also handle C11 _Noreturn. gcc/ChangeLog: PR c/88546 * attribs.c (decls_mismatched_attributes): Avoid warning for attribute leaf. gcc/testsuite/ChangeLog: PR c/88546 * g++.dg/ext/attr-copy.C: New test. * gcc.dg/attr-copy-4.c: Disable macro expansion tracking. * gcc.dg/attr-copy-6.c: New test. * gcc.dg/attr-copy-7.c: New test. From-SVN: r267591 --- gcc/ChangeLog | 6 ++ gcc/attribs.c | 6 ++ gcc/c-family/ChangeLog | 7 +++ gcc/c-family/c-attribs.c | 30 +++++++++ gcc/testsuite/ChangeLog | 8 +++ gcc/testsuite/g++.dg/ext/attr-copy.C | 82 ++++++++++++++++++++++++ gcc/testsuite/gcc.dg/attr-copy-4.c | 2 +- gcc/testsuite/gcc.dg/attr-copy-6.c | 93 ++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/attr-copy-7.c | 76 +++++++++++++++++++++++ libgcc/gthr-posix.h | 3 +- libgfortran/libgfortran.h | 2 +- 11 files changed, 312 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/attr-copy.C create mode 100644 gcc/testsuite/gcc.dg/attr-copy-6.c create mode 100644 gcc/testsuite/gcc.dg/attr-copy-7.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 142323d3006..87be8ae512a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -2,6 +2,12 @@ * params.def (hot-bb-count-ws-permille): Set to 990. +2019-01-04 Martin Sebor + + PR c/88546 + * attribs.c (decls_mismatched_attributes): Avoid warning for attribute + leaf. + 2019-01-04 Martin Sebor PR c/88363 diff --git a/gcc/attribs.c b/gcc/attribs.c index 3b4084efe9b..d9b6a04f87a 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -1912,6 +1912,12 @@ decls_mismatched_attributes (tree tmpl, tree decl, tree attrlist, for (unsigned i = 0; blacklist[i]; ++i) { + /* Attribute leaf only applies to extern functions. Avoid mentioning + it when it's missing from a static declaration. */ + if (!TREE_PUBLIC (decl) + && !strcmp ("leaf", blacklist[i])) + continue; + for (unsigned j = 0; j != 2; ++j) { if (!has_attribute (tmpls[j], tmpl_attrs[j], blacklist[i])) diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 55e6ee869b1..b407f1cc18e 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,10 @@ +2019-01-04 Martin Sebor + + PR c/88546 + * c-attribs.c (handle_copy_attribute): Avoid copying attribute leaf. + Handle C++ empty throw specification and C11 _Noreturn. + (has_attribute): Also handle C11 _Noreturn. + 2019-01-04 Martin Sebor PR c/88363 diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 03978dd1d03..c893baa48e3 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -2461,6 +2461,12 @@ handle_copy_attribute (tree *node, tree name, tree args, || is_attribute_p ("weakref", atname)) continue; + /* Attribute leaf only applies to extern functions. + Avoid copying it to static ones. */ + if (!TREE_PUBLIC (decl) + && is_attribute_p ("leaf", atname)) + continue; + tree atargs = TREE_VALUE (at); /* Create a copy of just the one attribute ar AT, including its argumentsm and add it to DECL. */ @@ -2478,13 +2484,28 @@ handle_copy_attribute (tree *node, tree name, tree args, return NULL_TREE; } + /* A function declared with attribute nothrow has the attribute + attached to it, but a C++ throw() function does not. */ + if (TREE_NOTHROW (ref)) + TREE_NOTHROW (decl) = true; + + /* Similarly, a function declared with attribute noreturn has it + attached on to it, but a C11 _Noreturn function does not. */ tree reftype = ref; + if (DECL_P (ref) + && TREE_THIS_VOLATILE (ref) + && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (reftype))) + TREE_THIS_VOLATILE (decl) = true; + if (DECL_P (ref) || EXPR_P (ref)) reftype = TREE_TYPE (ref); if (POINTER_TYPE_P (reftype)) reftype = TREE_TYPE (reftype); + if (!TYPE_P (reftype)) + return NULL_TREE; + tree attrs = TYPE_ATTRIBUTES (reftype); /* Copy type attributes from REF to DECL. */ @@ -4194,6 +4215,15 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree)) if (expr && DECL_P (expr)) found_match = TREE_READONLY (expr); } + else if (!strcmp ("noreturn", namestr)) + { + /* C11 _Noreturn sets the volatile bit without attaching + an attribute to the decl. */ + if (expr + && DECL_P (expr) + && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (expr))) + found_match = TREE_THIS_VOLATILE (expr); + } else if (!strcmp ("pure", namestr)) { if (expr && DECL_P (expr)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d0add03b609..b3f8d888371 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2019-01-04 Martin Sebor + + PR c/88546 + * g++.dg/ext/attr-copy.C: New test. + * gcc.dg/attr-copy-4.c: Disable macro expansion tracking. + * gcc.dg/attr-copy-6.c: New test. + * gcc.dg/attr-copy-7.c: New test. + 2019-01-04 Martin Sebor PR c/88363 diff --git a/gcc/testsuite/g++.dg/ext/attr-copy.C b/gcc/testsuite/g++.dg/ext/attr-copy.C new file mode 100644 index 00000000000..d475cd58103 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-copy.C @@ -0,0 +1,82 @@ +/* PR middle-end/88546 - Copy attribute unusable for weakrefs + { dg-do compile } + { dg-options "-O1 -Wall -fdump-tree-optimized" } + { dg-require-weak "" } */ + +#define ATTR(...) __attribute__ ((__VA_ARGS__)) +#define ASRT(expr) _Static_assert (expr, #expr) + +extern "C" { + + ATTR (leaf, nothrow) int + fnothrow () + { + return 0; + } + + static __typeof__ (fnothrow) + ATTR (weakref ("fnothrow"), copy (fnothrow)) + alias_fnothrow; + + + ATTR (leaf) int + fthrow_none () throw () + { + return 0; + } + + // Verify that no warning is issued for the alias having less + // restrictive attributes than the target: nothrow. + static __typeof (fthrow_none) + ATTR (weakref ("fthrow_none"), copy (fthrow_none)) + alias_fthrow_none; + + // Same as above but with no definition of the target. + ATTR (leaf) int + fthrow_none_nodef () throw (); + + static __typeof (fthrow_none_nodef) + ATTR (weakref ("fthrow_none_nodef"), copy (fthrow_none_nodef)) + alias_fthrow_none_nodef; + + // And again but without using typeof to make sure the nothrow + // bit is copied by attribute copy alone. + static int + ATTR (weakref ("fthrow_none_nodef"), copy (fthrow_none_nodef)) + alias_fthrow_none_nodef_func (); +} + + +struct UsrClass +{ + ~UsrClass (); +}; + +// Verify that the nothrow attribute/bit was copied to the alias and +// that no exception handling code is emitted in any of these calls. + +int call_alias_fnothrow () +{ + UsrClass usr; + return alias_fnothrow (); +} + +int call_alias_fthrow_none () +{ + UsrClass usr; + return alias_fthrow_none (); +} + +int call_alias_fthrow_none_nodef () +{ + UsrClass usr; + return alias_fthrow_none_nodef (); +} + +int call_alias_fthrow_none_nodef_func () +{ + UsrClass usr; + return alias_fthrow_none_nodef_func (); +} + +// { dg-final { scan-tree-dump-not "__builtin_unwind" "optimized" } } diff --git a/gcc/testsuite/gcc.dg/attr-copy-4.c b/gcc/testsuite/gcc.dg/attr-copy-4.c index 7020bad7aa9..1350a35ec94 100644 --- a/gcc/testsuite/gcc.dg/attr-copy-4.c +++ b/gcc/testsuite/gcc.dg/attr-copy-4.c @@ -1,7 +1,7 @@ /* PR middle-end/81824 - Warn for missing attributes with function aliases Exercise attribute copy for types. { dg-do compile } - { dg-options "-O2 -Wall" } */ + { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ #define Assert(expr) typedef char AssertExpr[2 * !!(expr) - 1] diff --git a/gcc/testsuite/gcc.dg/attr-copy-6.c b/gcc/testsuite/gcc.dg/attr-copy-6.c new file mode 100644 index 00000000000..17e714e2e4c --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-copy-6.c @@ -0,0 +1,93 @@ +/* PR middle-end/88546 - Copy attribute unusable for weakrefs + { dg-do compile } + { dg-options "-O2 -Wall" } + { dg-require-weak "" } */ + +#define ATTR(...) __attribute__ ((__VA_ARGS__)) +#define ASRT(expr) _Static_assert (expr, #expr) + +/* Variable that is local to this translation unit but that can + be modified from other units by calling reset_unit_local(). */ +static int unit_local; + +void reset_unit_local (void) +{ + unit_local = 0; +} + +/* Attribute leaf implies that fleaf() doesn't modify unit_local(). */ +ATTR (leaf, returns_nonnull) +void* fleaf_retnz (void); + +/* Verify both attributes have been applied. */ +ASRT (__builtin_has_attribute (fleaf_retnz, leaf)); +ASRT (__builtin_has_attribute (fleaf_retnz, returns_nonnull)); + +/* Verify that attribute leaf has the expected effect. */ +void call_fleaf_retnz (void) +{ + int i = unit_local; + void *p = fleaf_retnz (); + + /* Expect both tests to be folded to false and the calls eliminated. */ + extern void call_fleaf_retnz_test_leaf_eliminated (void); + if (i != unit_local) + call_fleaf_retnz_test_leaf_eliminated (); + + extern void call_fleaf_retnz_test_nonnull_eliminated (void); + if (p == 0) + call_fleaf_retnz_test_nonnull_eliminated (); +} + + +/* Verify that attribute copy copies the returns_nonnull attribute + but doesn't try to copy attribute leaf which only applies to extern + function. */ +static ATTR (copy (fleaf_retnz), weakref ("fleaf_retnz")) +void* fweakref_fleaf_retnz_copy (void); + +ASRT (!__builtin_has_attribute (fweakref_fleaf_retnz_copy, leaf)); +ASRT (__builtin_has_attribute (fweakref_fleaf_retnz_copy, returns_nonnull)); + +void call_fweakref_fleaf_retnz_copy (void) +{ + int i = unit_local; + void *p = fweakref_fleaf_retnz_copy (); + + /* Since leaf is not copied, expect the following test not to be + folded and the call to be emitted. */ + extern void call_fweakref_test_leaf_emitted (void); + if (i != unit_local) + call_fweakref_test_leaf_emitted (); + + /* Expect the following test to be folded to false and the call + eliminated. */ + extern void call_fweakref_fleaf_nonnull_eliminated (void); + if (p == 0) + call_fweakref_fleaf_nonnull_eliminated (); +} + +/* This is reduced from libgfortran/runtime/error.c. Verify it + doesn't trigger warnings and that the noreturn bit is copied + to the alias by verifying that calling the alias in a non-void + function with no return statement isn't diagnosed. */ + +extern _Noreturn void fnoreturn (void); + +extern __typeof (fnoreturn) + ATTR (visibility ("hidden")) + fnoreturn __asm__ ("fnoreturn_name"); + +void fnoreturn (void) +{ + __builtin_abort (); +} + +extern __typeof (fnoreturn) + ATTR (alias ("fnoreturn_name"), copy (fnoreturn)) + fnoreturn_alias; + +int call_fnoreturn_alias (void) +{ + fnoreturn_alias (); +} diff --git a/gcc/testsuite/gcc.dg/attr-copy-7.c b/gcc/testsuite/gcc.dg/attr-copy-7.c new file mode 100644 index 00000000000..a9c49bd704c --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-copy-7.c @@ -0,0 +1,76 @@ +/* PR middle-end/88546 - Copy attribute unusable for weakrefs + Verify that attribute noreturn (represented as volatile on function + decls) is interpreted correctly and doesn't affect variables. + { dg-do compile } + { dg-options "-O1 -Wall -fdump-tree-optimized" }*/ + +#define ATTR(...) __attribute__ ((__VA_ARGS__)) +#define ASRT(expr) _Static_assert (expr, #expr) + +ATTR (noreturn) void fnoreturn (void); +ATTR (copy (fnoreturn)) void fnoreturn_copy (void); +ASRT (__builtin_has_attribute (fnoreturn_copy, noreturn)); + +int call_fnoreturn_copy (void) +{ + fnoreturn_copy (); + fnoreturn_copy (); // should be eliminated +} + +// { dg-final { scan-tree-dump-times "fnoreturn_copy \\(\\);" 1 "optimized" } } + + +_Noreturn void f_Noreturn (void); +ATTR (copy (f_Noreturn)) void f_Noreturn_copy (void); +ASRT (__builtin_has_attribute (f_Noreturn_copy, noreturn)); + +int call_f_Noreturn_copy (void) +{ + f_Noreturn_copy (); + f_Noreturn_copy (); // should be eliminated +} + +// { dg-final { scan-tree-dump-times "f_Noreturn_copy \\(\\);" 1 "optimized" } } + + +// Verify the combination of both is accepted and works too, +// just for fun. +ATTR (noreturn) _Noreturn void fnoreturn_Noreturn (void); +ATTR (copy (fnoreturn_Noreturn)) void fnoreturn_Noreturn_copy (void); +ASRT (__builtin_has_attribute (fnoreturn_Noreturn_copy, noreturn)); + +int call_fnoreturn_Noreturn_copy (void) +{ + fnoreturn_Noreturn_copy (); + fnoreturn_Noreturn_copy (); // should be eliminated +} + +// { dg-final { scan-tree-dump-times "fnoreturn_Noreturn_copy \\(\\);" 1 "optimized" } } + + +typedef void func_t (void); + +ATTR (noreturn) func_t func_noreturn; +ATTR (copy (func_noreturn)) func_t func_noreturn_copy; +ASRT (__builtin_has_attribute (func_noreturn_copy, noreturn)); + +int call_func_noreturn_copy (void) +{ + func_noreturn_copy (); + func_noreturn_copy (); // should be eliminated +} + +// { dg-final { scan-tree-dump-times "func_noreturn_copy \\(\\);" 1 "optimized" } } + + +// Finally, verify that the volatile bit isn't copied for variables. +extern volatile int vi; + +int read_nonvolatile (void) +{ + ATTR (copy (vi)) int i = 0; + + return i + i; // should be folded to return 0; +} + +// { dg-final { scan-tree-dump-times "return 0;" 1 "optimized" } } diff --git a/libgcc/gthr-posix.h b/libgcc/gthr-posix.h index b1a497d9175..88cbc23937e 100644 --- a/libgcc/gthr-posix.h +++ b/libgcc/gthr-posix.h @@ -87,7 +87,8 @@ typedef struct timespec __gthread_time_t; # define __gthrw_pragma(pragma) # endif # define __gthrw2(name,name2,type) \ - static __typeof(type) name __attribute__ ((__weakref__(#name2))); \ + static __typeof(type) name \ + __attribute__ ((__weakref__(#name2), __copy__ (type))); \ __gthrw_pragma(weak type) # define __gthrw_(name) __gthrw_ ## name #else diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index 04188066300..6b4775a1365 100644 --- a/libgfortran/libgfortran.h +++ b/libgfortran/libgfortran.h @@ -202,7 +202,7 @@ extern int __mingw_snprintf (char *, size_t, const char *, ...) # define iexport(x) iexport1(x, IPREFIX(x)) # define iexport1(x,y) iexport2(x,y) # define iexport2(x,y) \ - extern __typeof(x) PREFIX(x) __attribute__((__alias__(#y))) + extern __typeof(x) PREFIX(x) __attribute__((__alias__(#y), __copy__ (x))) #else # define export_proto(x) sym_rename(x, PREFIX(x)) # define export_proto_np(x) extern char swallow_semicolon -- 2.30.2