From da879e01ecd35737c18be1da3324f4560aba1961 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Thu, 15 Apr 2021 15:49:30 -0600 Subject: [PATCH] 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. --- gcc/c/c-decl.c | 9 +- gcc/testsuite/gcc.dg/Warray-parameter-9.c | 54 ++++++++++++ gcc/testsuite/gcc.dg/Wnonnull-6.c | 93 +++++++++++++++++++++ gcc/testsuite/gcc.dg/Wreturn-type3.c | 54 ++++++++++++ gcc/testsuite/gcc.dg/Wunused-result.c | 50 +++++++++++ gcc/testsuite/gcc.dg/attr-noreturn.c | 64 ++++++++++++++ gcc/testsuite/gcc.dg/attr-returns-nonnull.c | 58 +++++++++++++ 7 files changed, 377 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-parameter-9.c create mode 100644 gcc/testsuite/gcc.dg/Wnonnull-6.c create mode 100644 gcc/testsuite/gcc.dg/Wreturn-type3.c create mode 100644 gcc/testsuite/gcc.dg/Wunused-result.c create mode 100644 gcc/testsuite/gcc.dg/attr-noreturn.c create mode 100644 gcc/testsuite/gcc.dg/attr-returns-nonnull.c diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 3c254511bd8..3ea4708c507 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -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); diff --git a/gcc/testsuite/gcc.dg/Warray-parameter-9.c b/gcc/testsuite/gcc.dg/Warray-parameter-9.c new file mode 100644 index 00000000000..b5d3d963c88 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-parameter-9.c @@ -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" } +} diff --git a/gcc/testsuite/gcc.dg/Wnonnull-6.c b/gcc/testsuite/gcc.dg/Wnonnull-6.c new file mode 100644 index 00000000000..48f09da996f --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wnonnull-6.c @@ -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" } +} diff --git a/gcc/testsuite/gcc.dg/Wreturn-type3.c b/gcc/testsuite/gcc.dg/Wreturn-type3.c new file mode 100644 index 00000000000..93596b399f1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wreturn-type3.c @@ -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) +} diff --git a/gcc/testsuite/gcc.dg/Wunused-result.c b/gcc/testsuite/gcc.dg/Wunused-result.c new file mode 100644 index 00000000000..c0bb9ae35e2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wunused-result.c @@ -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" } +} diff --git a/gcc/testsuite/gcc.dg/attr-noreturn.c b/gcc/testsuite/gcc.dg/attr-noreturn.c new file mode 100644 index 00000000000..8d58f6ece9b --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-noreturn.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/attr-returns-nonnull.c b/gcc/testsuite/gcc.dg/attr-returns-nonnull.c new file mode 100644 index 00000000000..22ee30ac5df --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-returns-nonnull.c @@ -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" } } */