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
This commit is contained in:
Martin Sebor 2019-01-05 00:57:30 +00:00 committed by Martin Sebor
parent f6be1179bb
commit 29d2485270
11 changed files with 312 additions and 3 deletions

View File

@ -2,6 +2,12 @@
* params.def (hot-bb-count-ws-permille): Set to 990.
2019-01-04 Martin Sebor <msebor@redhat.com>
PR c/88546
* attribs.c (decls_mismatched_attributes): Avoid warning for attribute
leaf.
2019-01-04 Martin Sebor <msebor@redhat.com>
PR c/88363

View File

@ -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]))

View File

@ -1,3 +1,10 @@
2019-01-04 Martin Sebor <msebor@redhat.com>
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 <msebor@redhat.com>
PR c/88363

View File

@ -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))

View File

@ -1,3 +1,11 @@
2019-01-04 Martin Sebor <msebor@redhat.com>
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 <msebor@redhat.com>
PR c/88363

View File

@ -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" } }

View File

@ -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]

View File

@ -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 ();
}

View File

@ -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" } }

View File

@ -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

View File

@ -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