[gcc r11-7458] PR c++/99251 - inconsistent -Wnonnull warning behaviour with dynamic_cast

Martin Sebor msebor@gcc.gnu.org
Tue Mar 2 18:17:33 GMT 2021


https://gcc.gnu.org/g:66ecb059c9d77cfcfb06cbdc3cac6a63b9e67f3d

commit r11-7458-g66ecb059c9d77cfcfb06cbdc3cac6a63b9e67f3d
Author: Martin Sebor <msebor@redhat.com>
Date:   Tue Mar 2 11:12:50 2021 -0700

    PR c++/99251 - inconsistent -Wnonnull warning behaviour with dynamic_cast
    
    gcc/cp/ChangeLog:
    
            PR c++/99251
            * class.c (build_base_path): Call build_if_nonnull.
            * cp-tree.h (build_if_nonnull): Declare.
            * rtti.c (ifnonnull): Rename...
            (build_if_nonnull): ...to this.  Set no-warning bit on COND_EXPR.
            (build_dynamic_cast_1): Adjust to name change.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/99251
            * g++.dg/warn/Wnonnull9.C: Expect no warnings.
            * g++.dg/warn/Wnonnull12.C: New test.

Diff:
---
 gcc/cp/class.c                         | 21 ++++-----------------
 gcc/cp/cp-tree.h                       |  1 +
 gcc/cp/rtti.c                          | 24 +++++++++++++++---------
 gcc/testsuite/g++.dg/warn/Wnonnull12.C | 29 +++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/warn/Wnonnull9.C  | 20 ++++++++++++++------
 5 files changed, 63 insertions(+), 32 deletions(-)

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index ea007e88e6e..856e81e3d1a 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -402,16 +402,9 @@ build_base_path (enum tree_code code,
   if (TREE_SIDE_EFFECTS (expr) && (null_test || virtual_access))
     expr = save_expr (expr);
 
-  /* Now that we've saved expr, build the real null test.  */
+  /* Store EXPR and build the real null test just before returning.  */
   if (null_test)
-    {
-      tree zero = cp_convert (TREE_TYPE (expr), nullptr_node, complain);
-      null_test = build2_loc (input_location, NE_EXPR, boolean_type_node,
-			      expr, zero);
-      /* This is a compiler generated comparison, don't emit
-	 e.g. -Wnonnull-compare warning for it.  */
-      TREE_NO_WARNING (null_test) = 1;
-    }
+    null_test = expr;
 
   /* If this is a simple base reference, express it as a COMPONENT_REF.  */
   if (code == PLUS_EXPR && !virtual_access
@@ -516,14 +509,8 @@ build_base_path (enum tree_code code,
 
  out:
   if (null_test)
-    {
-      expr = fold_build3_loc (input_location, COND_EXPR, target_type, null_test,
-			      expr, build_zero_cst (target_type));
-      /* Avoid warning for the whole conditional expression (in addition
-	 to NULL_TEST itself -- see above) in case the result is used in
-	 a nonnull context that the front end -Wnonnull checks.  */
-      TREE_NO_WARNING (expr) = 1;
-    }
+    /* Wrap EXPR in a null test.  */
+    expr = build_if_nonnull (null_test, expr, complain);
 
   return expr;
 }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 544e99538a4..b4728c87d0b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7279,6 +7279,7 @@ extern void emit_support_tinfos			(void);
 extern bool emit_tinfo_decl			(tree);
 extern unsigned get_pseudo_tinfo_index		(tree);
 extern tree get_pseudo_tinfo_type		(unsigned);
+extern tree build_if_nonnull			(tree, tree, tsubst_flags_t);
 
 /* in search.c */
 extern tree get_parent_with_private_access 	(tree decl, tree binfo);
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index b41d95469c6..5a33b83afd0 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -121,7 +121,6 @@ vec<tree, va_gc> *unemitted_tinfo_decls;
    and are generated as needed. */
 static GTY (()) vec<tinfo_s, va_gc> *tinfo_descs;
 
-static tree ifnonnull (tree, tree, tsubst_flags_t);
 static tree tinfo_name (tree, bool);
 static tree build_dynamic_cast_1 (location_t, tree, tree, tsubst_flags_t);
 static tree throw_bad_cast (void);
@@ -529,16 +528,23 @@ get_typeid (tree type, tsubst_flags_t complain)
 /* Check whether TEST is null before returning RESULT.  If TEST is used in
    RESULT, it must have previously had a save_expr applied to it.  */
 
-static tree
-ifnonnull (tree test, tree result, tsubst_flags_t complain)
+tree
+build_if_nonnull (tree test, tree result, tsubst_flags_t complain)
 {
-  tree cond = build2 (NE_EXPR, boolean_type_node, test,
-		      cp_convert (TREE_TYPE (test), nullptr_node, complain));
+  tree null_ptr = cp_convert (TREE_TYPE (test), nullptr_node, complain);
+  tree cond = build2 (NE_EXPR, boolean_type_node, test, null_ptr);
+
   /* This is a compiler generated comparison, don't emit
      e.g. -Wnonnull-compare warning for it.  */
   TREE_NO_WARNING (cond) = 1;
-  return build3 (COND_EXPR, TREE_TYPE (result), cond, result,
-		 cp_convert (TREE_TYPE (result), nullptr_node, complain));
+
+  null_ptr = cp_convert (TREE_TYPE (result), nullptr_node, complain);
+  cond = build3 (COND_EXPR, TREE_TYPE (result), cond, result, null_ptr);
+
+  /* Likewise, don't emit -Wnonnull for using the result to call
+     a member function.  */
+  TREE_NO_WARNING (cond) = 1;
+  return cond;
 }
 
 /* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
@@ -671,7 +677,7 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr,
 	  expr1 = build_headof (expr);
 	  if (TREE_TYPE (expr1) != type)
 	    expr1 = build1 (NOP_EXPR, type, expr1);
-	  return ifnonnull (expr, expr1, complain);
+	  return build_if_nonnull (expr, expr1, complain);
 	}
       else
 	{
@@ -786,7 +792,7 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr,
 
 	  /* Now back to the type we want from a void*.  */
 	  result = cp_convert (type, result, complain);
-	  return ifnonnull (expr, result, complain);
+	  return build_if_nonnull (expr, result, complain);
 	}
     }
   else
diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull12.C b/gcc/testsuite/g++.dg/warn/Wnonnull12.C
new file mode 100644
index 00000000000..7b2606302f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wnonnull12.C
@@ -0,0 +1,29 @@
+/* PR c++/99251 - inconsistent -Wnonnull warning behaviour with dynamic_cast
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+struct A
+{
+  virtual ~A ();
+};
+
+struct B: A
+{
+  int f (int);
+};
+
+int f1 (A *p)
+{
+  if (!p)
+    return 0;
+
+  return (dynamic_cast<B *>(p))->f (1);
+}
+
+int f2 (A *p)
+{
+  if (!p)
+    return 0;
+
+  return dynamic_cast<B *>(p)->f (2);   // { dg-bogus "\\\[-Wnonnull" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull9.C b/gcc/testsuite/g++.dg/warn/Wnonnull9.C
index b6135c4a624..88bf55adba2 100644
--- a/gcc/testsuite/g++.dg/warn/Wnonnull9.C
+++ b/gcc/testsuite/g++.dg/warn/Wnonnull9.C
@@ -38,13 +38,17 @@ void static_cast_const_C_ptr (B *p)
 
 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" }
+  /* Unlike static_cast, dynamic cast may return null even for a nonnull
+     operand but detecting assumptions to the contrary isn't -Wnonnull's
+     purpose.  Verify -Wnonnull isn't issued, either for the implicitly
+     emitted null check or for other reasons (the latter may be worth
+     warning for by some other warning).  See also pr99251.  */
+  dynamic_cast<C*>(p->bptr ())->g ();         // { dg-bogus "\\\[-Wnonnull" }
 }
 
 void dynamic_cast_const_C_ptr (B *p)
 {
-  dynamic_cast<const C*>(p->bptr ())->g ();   // { dg-warning "\\\[-Wnonnull" }
+  dynamic_cast<const C*>(p->bptr ())->g ();   // { dg-bogus "\\\[-Wnonnull" }
 }
 
 
@@ -107,11 +111,15 @@ void static_cast_const_D_ptr (B *p)
 
 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" }
+  /* Unlike static_cast, dynamic cast may return null even for a nonnull
+     operand but detecting assumptions to the contrary isn't -Wnonnull's
+     purpose.  Verify -Wnonnull isn't issued, either for the implicitly
+     emitted null check or for other reasons (the latter may be worth
+     warning for by some other warning).  See also pr99251.  */
+  dynamic_cast<D*>(p->bptr ())->g ();         // { dg-bogus "\\\[-Wnonnull" }
 }
 
 void dynamic_cast_const_D_ptr (B *p)
 {
-  dynamic_cast<const D*>(p->bptr ())->g ();   // { dg-warning "\\\[-Wnonnull" }
+  dynamic_cast<const D*>(p->bptr ())->g ();   // { dg-bogus "\\\[-Wnonnull" }
 }


More information about the Gcc-cvs mailing list