Hi!

As -Wnonnull -> -Wnonnull-compare warning has been moved from FE
to after going into SSA form, we have a problem because
delete ptr;
in C++ may introduce a comparison on its own, and on that artificial
comparison can complain about comparison of nonnull argument with NULL.

The following patch fixes this by setting TREE_NO_WARNING on it, making sure
it propagates up to the warn_nonnull_compare pass and not warning if it is
set.

While for "this" (after stripping nops) perhaps already the C++ FE could
optimize and assume this is always non-NULL (i.e. not generate the
comparison at all), in other cases, even if the arg is nonnull_arg_p, it
can't assume that, for the exact same reasons why the warning had to be
moved into the middle-end.  Because we can have:
__attribute__((nonnull)) void
foo (S *p, S *q, int a)
{
  if (a == 1)
    delete p; // here if (p != NULL) could be optimized away, but the
              // FE doesn't know that
  else if (a == 2)
    {
      bar (&q); // q could have changed here.
      delete q; // so, eventhough nonnull_arg_p (q), we have to if (q != NULL)
    }
  else if (a == 3)
    {
      p = baz (); // p value has changed, thus we need to test
      delete p;   // if (p != NULL) here.
    }
}
In any case, as the source doesn't contain comparison of p != NULL in the a
== 1 case, we don't want to warn.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-02-17  Jakub Jelinek  <ja...@redhat.com>

        PR c++/69850
        * gimplify.c (gimplify_cond_expr): Call gimple_set_no_warning
        on the cond_stmt from TREE_NO_WARNING on COND_EXPR_COND.
        * gimple-ssa-nonnull-compare.c (do_warn_nonnull_compare): Don't
        warn on gimple_no_warning_p statements.

        * init.c (build_delete): Set TREE_NO_WARNING on ifexp.

        * g++.dg/warn/Wnonnull-compare-1.C: New test.

--- gcc/gimplify.c.jj   2016-02-16 21:42:57.000000000 +0100
+++ gcc/gimplify.c      2016-02-17 14:01:45.789728763 +0100
@@ -3219,6 +3219,7 @@ gimplify_cond_expr (tree *expr_p, gimple
                                 &arm2);
   cond_stmt = gimple_build_cond (pred_code, arm1, arm2, label_true,
                                 label_false);
+  gimple_set_no_warning (cond_stmt, TREE_NO_WARNING (COND_EXPR_COND (expr)));
   gimplify_seq_add_stmt (&seq, cond_stmt);
   gimple_stmt_iterator gsi = gsi_last (seq);
   maybe_fold_stmt (&gsi);
--- gcc/gimple-ssa-nonnull-compare.c.jj 2016-02-16 21:46:02.000000000 +0100
+++ gcc/gimple-ssa-nonnull-compare.c    2016-02-17 13:51:52.933996279 +0100
@@ -96,7 +96,8 @@ do_warn_nonnull_compare (function *fun,
          }
       if (op
          && (POINTER_TYPE_P (TREE_TYPE (arg))
-             ? integer_zerop (op) : integer_minus_onep (op)))
+             ? integer_zerop (op) : integer_minus_onep (op))
+         && !gimple_no_warning_p (stmt))
        warning_at (loc, OPT_Wnonnull_compare,
                    "nonnull argument %qD compared to NULL", arg);
     }
--- gcc/cp/init.c.jj    2016-02-15 23:04:42.000000000 +0100
+++ gcc/cp/init.c       2016-02-17 13:54:32.597769729 +0100
@@ -4525,6 +4525,10 @@ build_delete (tree otype, tree addr, spe
                                            complain));
          if (ifexp == error_mark_node)
            return error_mark_node;
+         /* This is a compiler generated comparison, don't emit
+            e.g. -Wnonnull-compare warning for it.  */
+         else if (TREE_CODE (ifexp) == NE_EXPR)
+           TREE_NO_WARNING (ifexp) = 1;
        }
 
       if (ifexp != integer_one_node)
--- gcc/testsuite/g++.dg/warn/Wnonnull-compare-1.C.jj   2016-02-17 
14:04:51.644136979 +0100
+++ gcc/testsuite/g++.dg/warn/Wnonnull-compare-1.C      2016-02-17 
14:04:24.000000000 +0100
@@ -0,0 +1,9 @@
+// PR c++/69850
+// { dg-do compile }
+// { dg-options "-Wall" }
+
+struct C
+{
+  ~C () { delete this; }       // { dg-bogus "nonnull argument" }
+};
+C c;

        Jakub

Reply via email to