Propagate type attribute when merging extern declarations at local scope.

Resolves:
PR c/99420 - bogus -Warray-parameter on a function redeclaration in function scope
PR c/99972 - missing -Wunused-result on a call to a locally redeclared warn_unused_result function

gcc/c/ChangeLog:

	PR c/99420
	PR c/99972
	* c-decl.c (pushdecl): Always propagate type attribute.

gcc/testsuite/ChangeLog:

	PR c/99420
	PR c/99972
	* gcc.dg/Warray-parameter-9.c: New test.
	* gcc.dg/Wnonnull-6.c: New test.
	* gcc.dg/Wreturn-type3.c: New test.
	* gcc.dg/Wunused-result.c: New test.
	* gcc.dg/attr-noreturn.c: New test.
	* gcc.dg/attr-returns-nonnull.c: New test.
This commit is contained in:
Martin Sebor 2021-04-15 15:49:30 -06:00
parent 58fe131b91
commit da879e01ec
7 changed files with 377 additions and 5 deletions

View File

@ -3263,11 +3263,10 @@ pushdecl (tree x)
else
thistype = type;
b->u.type = TREE_TYPE (b->decl);
if (TREE_CODE (b->decl) == FUNCTION_DECL
&& fndecl_built_in_p (b->decl))
thistype
= build_type_attribute_variant (thistype,
TYPE_ATTRIBUTES (b->u.type));
/* Propagate the type attributes to the decl. */
thistype
= build_type_attribute_variant (thistype,
TYPE_ATTRIBUTES (b->u.type));
TREE_TYPE (b->decl) = thistype;
bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true,
locus);

View File

@ -0,0 +1,54 @@
/* PR c/99420 - bogus -Warray-parameter on a function redeclaration
in function scope
{ dg-do compile }
{ dg-options "-Wall" } */
extern int a1[1], a2[2], a3[3], a4[4];
void fa1 (int [1]); // { dg-message "previously declared as 'int\\\[1]'" }
void fa1 (int [1]);
void nested_decl (void)
{
void fa2 (int [2]);
fa2 (a1); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
fa2 (a2);
fa2 (a3);
void fa3 (int [3]);
fa3 (a2); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
fa3 (a3);
}
void nested_redecl (void)
{
void fa1 (int [2]); // { dg-warning "argument 1 of type 'int\\\[2]' with mismatched bound" }
fa1 (a1 + 1); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
fa1 (a1);
void fa2 (int [2]); // { dg-bogus "\\\[-Warray-parameter" }
fa2 (a1); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
fa2 (a2);
fa2 (a3);
void fa3 (int [3]); // { dg-bogus "\\\[-Warray-parameter" }
fa3 (a2); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
fa3 (a3);
void fa4 (int [4]);
}
void fa4 (int [5]); // { dg-warning "\\\[-Warray-parameter" }
void call_fa4 (void)
{
fa4 (a4);
fa4 (a3); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
}

View File

@ -0,0 +1,93 @@
/* Verify that attribute nonnull on global and local function declarations
or those to pointers to functions is merged.
{ dg-do compile }
{ dg-options "-Wall" } */
void fnonnull_local_local (void)
{
extern __attribute__ ((nonnull)) void fnonnull1 (void*);
fnonnull1 (0); // { dg-warning "\\\[-Wnonnull" }
}
void gnonnull_local_local (void)
{
extern void fnonnull1 (void*);
fnonnull1 (0); // { dg-warning "\\\[-Wnonnull" }
}
void fnonnull_local_global (void)
{
extern __attribute__ ((nonnull)) void fnonnull2 (void*);
fnonnull2 (0); // { dg-warning "\\\[-Wnonnull" }
}
extern void fnonnull2 (void*);
void gnonnull_local_global (void)
{
fnonnull2 (0); // { dg-warning "\\\[-Wnonnull" }
}
extern __attribute__ ((nonnull)) void fnonnull3 (void*);
void fnonnull_global_local (void)
{
fnonnull3 (0); // { dg-warning "\\\[-Wnonnull" }
}
void gnonnull_global_local (void)
{
extern void fnonnull3 (void*);
fnonnull3 (0); // { dg-warning "\\\[-Wnonnull" }
}
void pfnonnull_local_local (void)
{
extern __attribute__ ((nonnull)) void (*pfnonnull1) (void*);
pfnonnull1 (0); // { dg-warning "\\\[-Wnonnull" }
}
void gpnonnull_local_local (void)
{
extern void (*pfnonnull1) (void*);
pfnonnull1 (0); // { dg-warning "\\\[-Wnonnull" "pr?????" { xfail *-*-* } }
}
void pfnonnull_local_global (void)
{
extern __attribute__ ((nonnull)) void (*pfnonnull2) (void*);
pfnonnull2 (0); // { dg-warning "\\\[-Wnonnull" }
}
extern void (*pfnonnull2) (void*);
void gpnonnull_local_global (void)
{
pfnonnull2 (0); // { dg-warning "\\\[-Wnonnull" "pr?????" { xfail *-*-* } }
}
extern __attribute__ ((nonnull)) void (*pfnonnull3) (void*);
void pfnonnull_global_local (void)
{
pfnonnull3 (0); // { dg-warning "\\\[-Wnonnull" }
}
void gpnonnull_global_local (void)
{
extern void (*pfnonnull3) (void*);
pfnonnull3 (0); // { dg-warning "\\\[-Wnonnull" }
}

View File

@ -0,0 +1,54 @@
/* Verify that attribute noreturn on global and local function declarations
is merged.
{ dg-do compile }
{ dg-options "-Wall" } */
int fnr_local_local (void)
{
__attribute__ ((noreturn)) void fnr1 (void);
fnr1 ();
// no return, no warning (good)
}
int gnr_local_local (void)
{
void fnr1 (void);
fnr1 ();
// no return, no warning (good)
}
int fnr_local_global (void)
{
__attribute__ ((noreturn)) void fnr2 (void);
fnr2 ();
// no return, no warning (good)
}
void fnr2 (void);
int gnr_local_global (void)
{
fnr2 ();
// no return, no warning (good)
}
__attribute__ ((noreturn)) void fnr3 (void);
int fnr_global_local (void)
{
fnr3 ();
// no return, no warning (good)
}
int gnr_global_local (void)
{
void fnr3 (void);
fnr3 ();
// no return, no warning (good)
}

View File

@ -0,0 +1,50 @@
/* PR c/99972 - missing -Wunused-result on a call to a locally redeclared
warn_unused_result function
{ dg-do compile }
{ dg-options "-Wall" } */
void gwur_local_local (void)
{
__attribute__ ((warn_unused_result)) int fwur1 (void);
fwur1 (); // { dg-warning "\\\[-Wunused-result" }
}
void hwur_local_local (void)
{
/* Verify the attribute from the declaration above is copied/merged
into the declaration below. */
int fwur1 (void);
fwur1 (); // { dg-warning "\\\[-Wunused-result" }
}
void gwur_local_global (void)
{
__attribute__ ((warn_unused_result)) int fwur2 (void);
fwur2 (); // { dg-warning "\\\[-Wunused-result" }
}
int fwur2 (void);
void hwur_local_global (void)
{
fwur2 (); // { dg-warning "\\\[-Wunused-result" }
}
__attribute__ ((warn_unused_result)) int fwur3 (void);
void gwur_global_local (void)
{
fwur3 (); // { dg-warning "\\\[-Wunused-result" }
}
void hwur_global_local (void)
{
int fwur3 (void);
fwur3 (); // { dg-warning "\\\[-Wunused-result" }
}

View File

@ -0,0 +1,64 @@
/* Verify that attribute noreturn on global and local function declarations
is merged.
{ dg-do compile }
{ dg-options "-Wall -fdump-tree-optimized" } */
void foo (void);
int fnr_local_local (void)
{
__attribute__ ((noreturn)) void fnr1 (void);
fnr1 ();
foo ();
}
int gnr_local_local (void)
{
void fnr1 (void);
fnr1 ();
foo ();
}
int fnr_local_global (void)
{
__attribute__ ((noreturn)) void fnr2 (void);
fnr2 ();
foo ();
}
void fnr2 (void);
int gnr_local_global (void)
{
fnr2 ();
foo ();
}
__attribute__ ((noreturn)) void fnr3 (void);
int fnr_global_local (void)
{
fnr3 ();
foo ();
}
int gnr_global_local (void)
{
void fnr3 (void);
fnr3 ();
foo ();
}
/* { dg-final { scan-tree-dump-not "foo" "optimized" } } */

View File

@ -0,0 +1,58 @@
/* Verify that attribute returns_nonnull on global and local function
declarations is merged.
{ dg-do compile }
{ dg-options "-Wall -fdump-tree-optimized" } */
void foo (void);
void frnn_local_local (void)
{
__attribute__ ((returns_nonnull)) void* frnn1 (void);
if (!frnn1 ())
foo ();
}
void gnr_local_local (void)
{
void* frnn1 (void);
if (!frnn1 ())
foo ();
}
void frnn_local_global (void)
{
__attribute__ ((returns_nonnull)) void* frnn2 (void);
if (!frnn2 ())
foo ();
}
void* frnn2 (void);
void gnr_local_global (void)
{
if (!frnn2 ())
foo ();
}
__attribute__ ((returns_nonnull)) void* frnn3 (void);
void frnn_global_local (void)
{
if (!frnn3 ())
foo ();
}
void gnr_global_local (void)
{
void* frnn3 (void);
if (!frnn3 ())
foo ();
}
/* { dg-final { scan-tree-dump-not "foo" "optimized" } } */