PR c++/98646 - spurious -Wnonnull calling a member on the result of static_cast
authorMartin Sebor <msebor@redhat.com>
Mon, 25 Jan 2021 19:41:28 +0000 (12:41 -0700)
committerMartin Sebor <msebor@redhat.com>
Mon, 25 Jan 2021 19:41:28 +0000 (12:41 -0700)
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
gcc/cp/cvt.c
gcc/testsuite/g++.dg/warn/Wnonnull10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wnonnull5.C
gcc/testsuite/g++.dg/warn/Wnonnull9.C [new file with mode: 0644]
gcc/tree-ssa-ccp.c

index 2028e93b4d7c04c903571d6d8ce2b27e9e8c6040..813212cc21d64edc39707f6fc57666bfe3856abf 100644 (file)
@@ -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",
index f94488b1114beffdbc6910c4c18dd0ba586f1966..e809f0e406857383f7c4d7203ac55443bd627c0d 100644 (file)
@@ -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 (file)
index 0000000..a7e795c
--- /dev/null
@@ -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<S*>(0)->f ();         // { dg-warning "-Wnonnull" }
+  static_cast<S*>(0)->g ();
+  static_cast<S*>(0)->h ();         // { dg-warning "-Wnonnull" }
+}
+
+void f1 ()
+{
+  static_cast<S*>(nullptr)->f ();   // { dg-warning "-Wnonnull" }
+  static_cast<S*>(nullptr)->g ();
+  static_cast<S*>(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" }
+}
index 78862d489931c68f3c1fa7e8467bb80c1ef688c0..959cf1840f81afc0078cef19bfa7ba72ce97e2fe 100644 (file)
@@ -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 (file)
index 0000000..b6135c4
--- /dev/null
@@ -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<C*>(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<const C*>(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<C*>(p->bptr ())->g ();         // { dg-warning "\\\[-Wnonnull" }
+}
+
+void dynamic_cast_const_C_ptr (B *p)
+{
+  dynamic_cast<const C*>(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<C&>(p->bref ()).g ();
+}
+
+void static_cast_const_C_ref (B *p)
+{
+  static_cast<const C&>(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<C&>(p->bref ()).g ();
+}
+
+void dynamic_cast_const_C_ref (B *p)
+{
+  dynamic_cast<const C&>(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<D*>(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<const D*>(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<D*>(p->bptr ())->g ();         // { dg-warning "\\\[-Wnonnull" }
+}
+
+void dynamic_cast_const_D_ptr (B *p)
+{
+  dynamic_cast<const D*>(p->bptr ())->g ();   // { dg-warning "\\\[-Wnonnull" }
+}
index 965f092ccccb4a6f7b947b069eea2bfe286b4610..3bfd4a6265c1e7739696164ea2efe4d1591be803 100644 (file)
@@ -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",