PR c++/69922
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 24 Feb 2016 22:01:24 +0000 (22:01 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 24 Feb 2016 22:01:24 +0000 (22:01 +0000)
* class.c (build_base_path): Set TREE_NO_WARNING on the null_test.
Avoid folding it.
* init.c (build_vec_delete_1, build_delete): Don't fold the non-NULL
tests.
* cp-gimplify.c (cp_fold): For TREE_NO_WARNING comparisons with NULL,
unless they are folded into INTEGER_CST, error_mark_node or some
comparison with NULL, avoid folding them and use either the original
comparison or non-folded comparison of folded arguments.
* cp-ubsan.c (cp_ubsan_instrument_vptr): Set TREE_NO_WARNING on the
comparison, don't fold the comparison right away.

* g++.dg/warn/Wnonnull-compare-6.C: New test.
* g++.dg/warn/Wnonnull-compare-7.C: New test.
* g++.dg/ubsan/pr69922.C: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@233684 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-gimplify.c
gcc/cp/cp-ubsan.c
gcc/cp/init.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ubsan/pr69922.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wnonnull-compare-6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wnonnull-compare-7.C [new file with mode: 0644]

index 897c28f..28a3168 100644 (file)
@@ -1,3 +1,17 @@
+2016-02-24  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/69922
+       * class.c (build_base_path): Set TREE_NO_WARNING on the null_test.
+       Avoid folding it.
+       * init.c (build_vec_delete_1, build_delete): Don't fold the non-NULL
+       tests.
+       * cp-gimplify.c (cp_fold): For TREE_NO_WARNING comparisons with NULL,
+       unless they are folded into INTEGER_CST, error_mark_node or some
+       comparison with NULL, avoid folding them and use either the original
+       comparison or non-folded comparison of folded arguments.
+       * cp-ubsan.c (cp_ubsan_instrument_vptr): Set TREE_NO_WARNING on the
+       comparison, don't fold the comparison right away.
+
 2016-02-24  Jason Merrill  <jason@redhat.com>
 
        PR c++/69323
index b705d6b..f6ad696 100644 (file)
@@ -392,8 +392,11 @@ build_base_path (enum tree_code code,
   if (null_test)
     {
       tree zero = cp_convert (TREE_TYPE (expr), nullptr_node, complain);
-      null_test = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
-                              expr, zero);
+      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;
     }
 
   /* If this is a simple base reference, express it as a COMPONENT_REF.  */
index c59cd90..a77b242 100644 (file)
@@ -2069,8 +2069,24 @@ cp_fold (tree x)
        x = fold (x);
 
       if (TREE_NO_WARNING (org_x)
-         && TREE_CODE (x) == TREE_CODE (org_x))
-       TREE_NO_WARNING (x) = 1;
+         && warn_nonnull_compare
+         && COMPARISON_CLASS_P (org_x))
+       {
+         if (x == error_mark_node || TREE_CODE (x) == INTEGER_CST)
+           ;
+         else if (COMPARISON_CLASS_P (x))
+           TREE_NO_WARNING (x) = 1;
+         /* Otherwise give up on optimizing these, let GIMPLE folders
+            optimize those later on.  */
+         else if (op0 != TREE_OPERAND (org_x, 0)
+                  || op1 != TREE_OPERAND (org_x, 1))
+           {
+             x = build2_loc (loc, code, TREE_TYPE (org_x), op0, op1);
+             TREE_NO_WARNING (x) = 1;
+           }
+         else
+           x = org_x;
+       }
       break;
 
     case VEC_COND_EXPR:
index 7454c0a..a5aefcf 100644 (file)
@@ -70,10 +70,15 @@ cp_ubsan_instrument_vptr (location_t loc, tree op, tree type, bool is_addr,
   vptr = fold_convert_loc (loc, pointer_sized_int_node, vptr);
   vptr = fold_convert_loc (loc, uint64_type_node, vptr);
   if (ckind == UBSAN_DOWNCAST_POINTER)
-    vptr = fold_build3 (COND_EXPR, uint64_type_node,
-                       fold_build2 (NE_EXPR, boolean_type_node, op,
-                                    build_zero_cst (TREE_TYPE (op))),
-                       vptr, build_int_cst (uint64_type_node, 0));
+    {
+      tree cond = build2_loc (loc, NE_EXPR, boolean_type_node, op,
+                             build_zero_cst (TREE_TYPE (op)));
+      /* This is a compiler generated comparison, don't emit
+        e.g. -Wnonnull-compare warning for it.  */
+      TREE_NO_WARNING (cond) = 1;
+      vptr = build3_loc (loc, COND_EXPR, uint64_type_node, cond,
+                        vptr, build_int_cst (uint64_type_node, 0));
+    }
   tree ti_decl = get_tinfo_decl (type);
   mark_used (ti_decl);
   tree ptype = build_pointer_type (type);
index 19279e3..43f854c 100644 (file)
@@ -3678,15 +3678,13 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
     body = integer_zero_node;
 
   /* Outermost wrapper: If pointer is null, punt.  */
-  tree cond
-    = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, base,
-                      fold_convert (TREE_TYPE (base), nullptr_node));
+  tree cond = build2_loc (input_location, NE_EXPR, boolean_type_node, base,
+                         fold_convert (TREE_TYPE (base), nullptr_node));
   /* This is a compiler generated comparison, don't emit
      e.g. -Wnonnull-compare warning for it.  */
-  if (TREE_CODE (cond) == NE_EXPR)
-    TREE_NO_WARNING (cond) = 1;
-  body = fold_build3_loc (input_location, COND_EXPR, void_type_node,
-                         cond, body, integer_zero_node);
+  TREE_NO_WARNING (cond) = 1;
+  body = build3_loc (input_location, COND_EXPR, void_type_node,
+                    cond, body, integer_zero_node);
   body = build1 (NOP_EXPR, void_type_node, body);
 
   if (controller)
@@ -4523,9 +4521,8 @@ build_delete (tree otype, tree addr, special_function_kind auto_delete,
        {
          /* Handle deleting a null pointer.  */
          warning_sentinel s (warn_address);
-         ifexp = fold (cp_build_binary_op (input_location,
-                                           NE_EXPR, addr, nullptr_node,
-                                           complain));
+         ifexp = cp_build_binary_op (input_location, NE_EXPR, addr,
+                                     nullptr_node, complain);
          if (ifexp == error_mark_node)
            return error_mark_node;
          /* This is a compiler generated comparison, don't emit
index 4ba14fc..e5cfd9a 100644 (file)
@@ -1,3 +1,10 @@
+2016-02-24  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/69922
+       * g++.dg/warn/Wnonnull-compare-6.C: New test.
+       * g++.dg/warn/Wnonnull-compare-7.C: New test.
+       * g++.dg/ubsan/pr69922.C: New test.
+
 2016-02-24  Marek Polacek  <polacek@redhat.com>
 
        PR c/69819
diff --git a/gcc/testsuite/g++.dg/ubsan/pr69922.C b/gcc/testsuite/g++.dg/ubsan/pr69922.C
new file mode 100644 (file)
index 0000000..0392750
--- /dev/null
@@ -0,0 +1,18 @@
+// PR c++/69922
+// { dg-do compile }
+// { dg-options "-fsanitize=vptr -Wnonnull-compare" }
+
+struct S { virtual ~S (); };
+struct T : S { T *bar (); T *baz (); T *q; bool b; };
+
+T *
+T::bar ()
+{
+  return static_cast<T*>(reinterpret_cast<S*>(this));  // { dg-bogus "nonnull argument" }
+}
+
+T *
+T::baz ()
+{
+  return static_cast<T*>(reinterpret_cast<S*>(b ? this : q));  // { dg-bogus "nonnull argument" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull-compare-6.C b/gcc/testsuite/g++.dg/warn/Wnonnull-compare-6.C
new file mode 100644 (file)
index 0000000..d327df9
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/69922
+// { dg-do compile }
+// { dg-options "-Wnonnull-compare" }
+
+struct T { virtual ~T (); };
+struct S { virtual ~S (); T *f (bool); };
+struct U : S, T {};
+
+T *
+S::f (bool b)
+{
+  return b ? static_cast<U *> (this) : (U *) 0;        // { dg-bogus "nonnull argument" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull-compare-7.C b/gcc/testsuite/g++.dg/warn/Wnonnull-compare-7.C
new file mode 100644 (file)
index 0000000..6c19a43
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/69922
+// { dg-do compile }
+// { dg-options "-Wnonnull-compare" }
+
+struct S { virtual ~S (); };
+struct T { virtual ~T (); };
+bool b, c;
+S *p;
+T *q, *r;
+
+S::~S ()
+{
+  delete (b ? this : p);               // { dg-bogus "nonnull argument" }
+}
+
+T::~T ()
+{
+  delete (b ? (c ? this : q) : r);     // { dg-bogus "nonnull argument" }
+}