From d6f1cf644c45b76a27b6a6869dedaa030e3c7570 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Mon, 25 Jan 2021 12:41:28 -0700 Subject: [PATCH] PR c++/98646 - spurious -Wnonnull calling a member on the result of static_cast gcc/c-family/ChangeLog: PR c++/98646 * c-common.c (check_nonnull_arg): Adjust warning text. gcc/cp/ChangeLog: PR c++/98646 * cvt.c (cp_fold_convert): Propagate TREE_NO_WARNING. gcc/ChangeLog: PR c++/98646 * tree-ssa-ccp.c (pass_post_ipa_warn::execute): Adjust warning text. gcc/testsuite/ChangeLog: PR c++/98646 * g++.dg/warn/Wnonnull5.C: Adjust text of an expected warning. * g++.dg/warn/Wnonnull10.C: New test. * g++.dg/warn/Wnonnull9.C: New test. --- gcc/c-family/c-common.c | 2 +- gcc/cp/cvt.c | 9 +- gcc/testsuite/g++.dg/warn/Wnonnull10.C | 63 +++++++++++++ gcc/testsuite/g++.dg/warn/Wnonnull5.C | 10 +-- gcc/testsuite/g++.dg/warn/Wnonnull9.C | 117 +++++++++++++++++++++++++ gcc/tree-ssa-ccp.c | 2 +- 6 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wnonnull10.C create mode 100644 gcc/testsuite/g++.dg/warn/Wnonnull9.C diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 2028e93b4d7..813212cc21d 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5595,7 +5595,7 @@ check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num) if (param_num == 0) { warned = warning_at (loc, OPT_Wnonnull, - "%qs pointer null", "this"); + "%qs pointer is null", "this"); if (warned && pctx->fndecl) inform (DECL_SOURCE_LOCATION (pctx->fndecl), "in a call to non-static member function %qD", diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index f94488b1114..e809f0e4068 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -599,11 +599,14 @@ ignore_overflows (tree expr, tree orig) } /* Fold away simple conversions, but make sure TREE_OVERFLOW is set - properly. */ + properly and propagate TREE_NO_WARNING if folding EXPR results + in the same expression code. */ tree cp_fold_convert (tree type, tree expr) { + bool nowarn = TREE_NO_WARNING (expr); + tree conv; if (TREE_TYPE (expr) == type) conv = expr; @@ -626,6 +629,10 @@ cp_fold_convert (tree type, tree expr) conv = fold_convert (type, expr); conv = ignore_overflows (conv, expr); } + + if (nowarn && TREE_CODE (expr) == TREE_CODE (conv)) + TREE_NO_WARNING (conv) = nowarn; + return conv; } diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull10.C b/gcc/testsuite/g++.dg/warn/Wnonnull10.C new file mode 100644 index 00000000000..a7e795ceb8a --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wnonnull10.C @@ -0,0 +1,63 @@ +/* Very that -Wnonnull is issued for calls to inline member functions + with a null this pointer. + { dg-do compile } + { dg-options "-Wall" } */ + +#if __cplusplus < 201103L +# define nullptr 0 +#endif + +struct S +{ + void f () { } + static void g () { } + virtual void h () { } +}; + +void f0 () +{ + static_cast(0)->f (); // { dg-warning "-Wnonnull" } + static_cast(0)->g (); + static_cast(0)->h (); // { dg-warning "-Wnonnull" } +} + +void f1 () +{ + static_cast(nullptr)->f (); // { dg-warning "-Wnonnull" } + static_cast(nullptr)->g (); + static_cast(nullptr)->h (); // { dg-warning "-Wnonnull" } +} + +void f2 () +{ + S* const p = 0; + + p->f (); // { dg-warning "-Wnonnull" } + p->g (); + p->h (); // { dg-warning "-Wnonnull" } +} + + +#pragma GCC optimize "1" + +void f3 () +{ + S *p = 0; + + p->f (); // { dg-warning "-Wnonnull" } + p->g (); + p->h (); // { dg-warning "-Wnonnull" } +} + + +#pragma GCC optimize "2" + +void f4 (S *p) +{ + if (p) + return; + + p->f (); // { dg-warning "-Wnonnull" } + p->g (); + p->h (); // { dg-warning "-Wnonnull" } +} diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull5.C b/gcc/testsuite/g++.dg/warn/Wnonnull5.C index 78862d48993..959cf1840f8 100644 --- a/gcc/testsuite/g++.dg/warn/Wnonnull5.C +++ b/gcc/testsuite/g++.dg/warn/Wnonnull5.C @@ -35,21 +35,21 @@ struct S void warn_nullptr_this () { - ((S*)nullptr)->f0 (""); // { dg-warning "3:'this' pointer null" "pr86568" { xfail *-*-* } } - // { dg-warning "this' pointer null" "pr86568 second variant" { target *-*-* } .-1 } + ((S*)nullptr)->f0 (""); // { dg-warning "3:'this' pointer is null" "pr86568" { xfail *-*-* } } + // { dg-warning "this' pointer is null" "pr86568 second variant" { target *-*-* } .-1 } } void warn_null_this_cst () { S* const null = 0; - null->f1 (""); // { dg-warning "3:'this' pointer null" } + null->f1 (""); // { dg-warning "3:'this' pointer is null" } } void warn_null_this_var () { S* null = 0; - null->f2 (&null); // { dg-warning "3:'this' pointer null" "pr86568" { xfail *-*-* } } - // { dg-warning "'this' pointer null" "pr86568 second variant" { target *-*-* } .-1 } + null->f2 (&null); // { dg-warning "3:'this' pointer is null" "pr86568" { xfail *-*-* } } + // { dg-warning "'this' pointer is null" "pr86568 second variant" { target *-*-* } .-1 } } void warn_nullptr (S s) diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull9.C b/gcc/testsuite/g++.dg/warn/Wnonnull9.C new file mode 100644 index 00000000000..b6135c4a624 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wnonnull9.C @@ -0,0 +1,117 @@ +/* PR c++/98646 - spurious -Wnonnull calling a member on the result + of static_cast + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +struct A { virtual ~A (); }; +struct B +{ + virtual ~B (); + B* bptr (); + B& bref (); +}; + +struct C: A, B { virtual ~C (); void g () const; }; + + +void c_cast_C_ptr (B *p) +{ + ((C*)p->bptr ())->g (); +} + +void c_cast_const_C_ptr (B *p) +{ + ((const C*)p->bptr ())->g (); +} + +void static_cast_C_ptr (B *p) +{ + static_cast(p->bptr ())->g (); +} + +void static_cast_const_C_ptr (B *p) +{ + /* The static_cast can't fail so verify that no warning is issued + here, even though GCC emits a null check for its argument. */ + static_cast(p->bptr ())->g (); // { dg-bogus "\\\[-Wnonnull" } +} + +void dynamic_cast_C_ptr (B *p) +{ + // The dynamic_cast might fail so a warning is justified. + dynamic_cast(p->bptr ())->g (); // { dg-warning "\\\[-Wnonnull" } +} + +void dynamic_cast_const_C_ptr (B *p) +{ + dynamic_cast(p->bptr ())->g (); // { dg-warning "\\\[-Wnonnull" } +} + + +void c_cast_C_ref (B *p) +{ + ((C&)p->bref ()).g (); +} + +void c_cast_const_C_ref (B *p) +{ + ((const C&)p->bref ()).g (); +} + +void static_cast_C_ref (B *p) +{ + static_cast(p->bref ()).g (); +} + +void static_cast_const_C_ref (B *p) +{ + static_cast(p->bref ()).g (); +} + +void dynamic_cast_C_ref (B *p) +{ + /* The dynamic_cast fails by throwing an exception so verify that + no warning is issued. */ + dynamic_cast(p->bref ()).g (); +} + +void dynamic_cast_const_C_ref (B *p) +{ + dynamic_cast(p->bref ()).g (); +} + + +struct D: B, A { virtual ~D (); void g () const; }; + +void c_cast_D_ptr (B *p) +{ + ((D*)p->bptr ())->g (); +} + +void c_cast_const_D_ptr (B *p) +{ + ((const D*)p->bptr ())->g (); +} + +void static_cast_D_ptr (B *p) +{ + static_cast(p->bptr ())->g (); +} + +void static_cast_const_D_ptr (B *p) +{ + /* The static_cast can't fail so verify that no warning is issued + here, even though GCC emits a null check for its argument. */ + static_cast(p->bptr ())->g (); // { dg-bogus "\\\[-Wnonnull" } +} + +void dynamic_cast_D_ptr (B *p) +{ + // The dynamic_cast might fail so a warning is justified. + dynamic_cast(p->bptr ())->g (); // { dg-warning "\\\[-Wnonnull" } +} + +void dynamic_cast_const_D_ptr (B *p) +{ + dynamic_cast(p->bptr ())->g (); // { dg-warning "\\\[-Wnonnull" } +} diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 965f092cccc..3bfd4a6265c 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -3564,7 +3564,7 @@ pass_post_ipa_warn::execute (function *fun) if (argno == 0) { if (warning_at (loc, OPT_Wnonnull, - "%G%qs pointer null", stmt, "this") + "%G%qs pointer is null", stmt, "this") && fndecl) inform (DECL_SOURCE_LOCATION (fndecl), "in a call to non-static member function %qD", -- 2.30.2