* 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
+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
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. */
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:
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);
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)
{
/* 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
+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
--- /dev/null
+// 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" }
+}
--- /dev/null
+// 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" }
+}
--- /dev/null
+// 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" }
+}