[PATCH] Move the -Wnonnull compare against NULL warning from FEs to early uninit under -Wnonnull-compare (PR c/69835)

Jakub Jelinek jakub@redhat.com
Tue Feb 16 15:29:00 GMT 2016


Hi!

As has been reported today on gcc@, the new -Wnonnull warning addition
warns even about nonnull parameters that were changed (or could be changed)
in the function.  IMHO the nonnull attribute only talks about the value of
the parameter upon entry to the function, if you assign something else
to the argument afterwards and test that for NULL or non-NULL, it is like
any other variable.
But, we don't have the infrastructure to detect this in the FE, so this
patch moves the warning soon after we go into SSA form.
As -Wnonnull is a C/C++/ObjC/ObjC++ only warning, I've added a new
-Wnonnull-compare switch for it too (and enable it for C/C++/ObjC/ObjC++
from -Wall).

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

2016-02-16  Jakub Jelinek  <jakub@redhat.com>

	PR c/69835
	* common.opt (Wnonnull-compare): New warning.
	* doc/invoke.texi (-Wnonnull): Remove text about comparison
	of arguments against NULL.
	(-Wnonnull-compare): Document.
	* tree-ssa-uninit.c (warn_uninitialized_vars): Add warn_nonnull_cmp
	argument, if true, warn about SSA_NAME (D) of nonnull_arg_p
	comparisons against NULL pointers.
	(pass_late_warn_uninitialized::execute): Adjust caller.
	(execute_early_warn_uninitialized): Likewise.
	(gate_early_warn_uninitialized): New function.
	(pass_early_warn_uninitialized::gate): Call it instead of
	gate_warn_uninitialized.
c-family/
	* c.opt (Wnonnull-compare): Enable for -Wall.
c/
	* c-typeck.c (build_binary_op): Revert 2015-09-09 change.
cp/
	* typeck.c (cp_build_binary_op): Revert 2015-09-09 change.
testsuite/
	* c-c++-common/nonnull-1.c: Use -Wnonnull-compare instead of
	-Wnonnull in dg-options.
	* c-c++-common/nonnull-2.c: New test.

--- gcc/common.opt.jj	2016-01-27 19:47:35.000000000 +0100
+++ gcc/common.opt	2016-02-16 11:52:42.641623690 +0100
@@ -616,6 +616,10 @@ Wlarger-than=
 Common RejectNegative Joined UInteger Warning
 -Wlarger-than=<number>	Warn if an object is larger than <number> bytes.
 
+Wnonnull-compare
+Var(warn_nonnull_compare) Warning
+Warn if comparing pointer parameter with nonnull attribute with NULL.
+
 Wnull-dereference
 Common Var(warn_null_dereference) Warning
 Warn if dereferencing a NULL pointer may lead to erroneous or undefined behavior.
--- gcc/doc/invoke.texi.jj	2016-02-08 18:39:16.000000000 +0100
+++ gcc/doc/invoke.texi	2016-02-16 12:31:42.037232875 +0100
@@ -276,7 +276,8 @@ Objective-C and Objective-C++ Dialects}.
 -Wmain -Wmaybe-uninitialized -Wmemset-transposed-args @gol
 -Wmisleading-indentation -Wmissing-braces @gol
 -Wmissing-field-initializers -Wmissing-include-dirs @gol
--Wno-multichar  -Wnonnull  -Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} @gol
+-Wno-multichar -Wnonnull -Wnonnull-compare @gol
+-Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} @gol
 -Wnull-dereference -Wodr  -Wno-overflow  -Wopenmp-simd  @gol
 -Woverride-init-side-effects -Woverlength-strings @gol
 -Wpacked  -Wpacked-bitfield-compat  -Wpadded @gol
@@ -3537,6 +3538,7 @@ Options} and @ref{Objective-C and Object
 -Wmissing-braces @r{(only for C/ObjC)} @gol
 -Wnarrowing @r{(only for C++)}  @gol
 -Wnonnull  @gol
+-Wnonnull-compare  @gol
 -Wopenmp-simd @gol
 -Wparentheses  @gol
 -Wpointer-sign  @gol
@@ -3795,12 +3797,18 @@ formats that may yield only a two-digit
 Warn about passing a null pointer for arguments marked as
 requiring a non-null value by the @code{nonnull} function attribute.
 
-Also warns when comparing an argument marked with the @code{nonnull}
-function attribute against null inside the function.
-
 @option{-Wnonnull} is included in @option{-Wall} and @option{-Wformat}.  It
 can be disabled with the @option{-Wno-nonnull} option.
 
+@item -Wnonnull-compare
+@opindex Wnonnull-compare
+@opindex Wno-nonnull-compare
+Warn when comparing an argument marked with the @code{nonnull}
+function attribute against null inside the function.
+
+@option{-Wnonnull-compare} is included in @option{-Wall}.  It
+can be disabled with the @option{-Wno-nonnull-compare} option.
+
 @item -Wnull-dereference
 @opindex Wnull-dereference
 @opindex Wno-null-dereference
--- gcc/tree-ssa-uninit.c.jj	2016-01-13 13:28:41.000000000 +0100
+++ gcc/tree-ssa-uninit.c	2016-02-16 12:50:30.390619823 +0100
@@ -171,7 +171,8 @@ warn_uninit (enum opt_code wc, tree t, t
 }
 
 static unsigned int
-warn_uninitialized_vars (bool warn_possibly_uninitialized)
+warn_uninitialized_vars (bool warn_possibly_uninitialized,
+			 bool warn_nonnull_cmp)
 {
   gimple_stmt_iterator gsi;
   basic_block bb;
@@ -190,6 +191,60 @@ warn_uninitialized_vars (bool warn_possi
 	  if (is_gimple_debug (stmt))
 	    continue;
 
+	  if (warn_nonnull_cmp)
+	    {
+	      tree op0 = NULL_TREE, op1 = NULL_TREE;
+	      location_t loc = gimple_location (stmt);
+	      if (gimple_code (stmt) == GIMPLE_COND)
+		switch (gimple_cond_code (stmt))
+		  {
+		  case EQ_EXPR:
+		  case NE_EXPR:
+		    op0 = gimple_cond_lhs (stmt);
+		    op1 = gimple_cond_rhs (stmt);
+		    break;
+		  default:
+		    break;
+		  }
+	      else if (is_gimple_assign (stmt))
+		switch (gimple_assign_rhs_code (stmt))
+		  {
+		  case EQ_EXPR:
+		  case NE_EXPR:
+		    op0 = gimple_assign_rhs1 (stmt);
+		    op1 = gimple_assign_rhs2 (stmt);
+		    break;
+		  case COND_EXPR:
+		    switch (TREE_CODE (gimple_assign_rhs1 (stmt)))
+		      {
+		      case EQ_EXPR:
+		      case NE_EXPR:
+			op1 = gimple_assign_rhs1 (stmt);
+			loc = EXPR_LOC_OR_LOC (op1, loc);
+			op0 = TREE_OPERAND (op1, 0);
+			op1 = TREE_OPERAND (op1, 1);
+			break;
+		      default:
+			break;
+		      }
+		    break;
+		  default:
+		    break;
+		  }
+	      if (op0
+		  && TREE_CODE (op0) == SSA_NAME
+		  && SSA_NAME_IS_DEFAULT_DEF (op0)
+		  && TREE_CODE (SSA_NAME_VAR (op0)) == PARM_DECL
+		  && (POINTER_TYPE_P (TREE_TYPE (op0))
+		      || TREE_CODE (TREE_TYPE (op0)) == OFFSET_TYPE)
+		  && nonnull_arg_p (SSA_NAME_VAR (op0))
+		  && (POINTER_TYPE_P (TREE_TYPE (op0))
+		      ? integer_zerop (op1) : integer_minus_onep (op1)))
+		warning_at (gimple_location (stmt), OPT_Wnonnull_compare,
+			    "nonnull argument %qD compared to NULL",
+			    SSA_NAME_VAR (op0));
+	    }
+
 	  /* We only do data flow with SSA_NAMEs, so that's all we
 	     can warn about.  */
 	  FOR_EACH_SSA_USE_OPERAND (use_p, stmt, op_iter, SSA_OP_USE)
@@ -2416,7 +2471,7 @@ pass_late_warn_uninitialized::execute (f
   /* Re-do the plain uninitialized variable check, as optimization may have
      straightened control flow.  Do this first so that we don't accidentally
      get a "may be" warning when we'd have seen an "is" warning later.  */
-  warn_uninitialized_vars (/*warn_possibly_uninitialized=*/1);
+  warn_uninitialized_vars (/*warn_possibly_uninitialized=*/true, false);
 
   timevar_push (TV_TREE_UNINIT);
 
@@ -2478,6 +2533,14 @@ make_pass_late_warn_uninitialized (gcc::
 }
 
 
+static bool
+gate_early_warn_uninitialized (void)
+{
+  return (warn_uninitialized
+	  || warn_maybe_uninitialized
+	  || warn_nonnull_compare);
+}
+
 static unsigned int
 execute_early_warn_uninitialized (void)
 {
@@ -2488,7 +2551,8 @@ execute_early_warn_uninitialized (void)
      optimization we need to warn here about "may be uninitialized".  */
   calculate_dominance_info (CDI_POST_DOMINATORS);
 
-  warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize);
+  warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize,
+			   warn_nonnull_compare);
 
   /* Post-dominator information can not be reliably updated. Free it
      after the use.  */
@@ -2521,7 +2585,7 @@ public:
   {}
 
   /* opt_pass methods: */
-  virtual bool gate (function *) { return gate_warn_uninitialized (); }
+  virtual bool gate (function *) { return gate_early_warn_uninitialized (); }
   virtual unsigned int execute (function *)
     {
       return execute_early_warn_uninitialized ();
--- gcc/c-family/c.opt.jj	2016-02-08 18:39:17.000000000 +0100
+++ gcc/c-family/c.opt	2016-02-16 12:30:00.299641823 +0100
@@ -677,6 +677,10 @@ Wnonnull
 C ObjC C++ ObjC++ LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ;
 
+Wnonnull-compare
+C ObjC C++ ObjC++ LangEnabledBy(C ObjC C++ ObjC++,Wall)
+;
+
 Wnormalized
 C ObjC C++ ObjC++ Warning Alias(Wnormalized=,nfc,none)
 ;
--- gcc/c/c-typeck.c.jj	2016-02-12 10:23:50.000000000 +0100
+++ gcc/c/c-typeck.c	2016-02-16 11:40:08.474048701 +0100
@@ -11086,11 +11086,6 @@ build_binary_op (location_t location, en
 	short_compare = 1;
       else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
 	{
-	  if (warn_nonnull
-	      && TREE_CODE (op0) == PARM_DECL && nonnull_arg_p (op0))
-	    warning_at (location, OPT_Wnonnull,
-			"nonnull argument %qD compared to NULL", op0);
-
 	  if (TREE_CODE (op0) == ADDR_EXPR
 	      && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
 	    {
@@ -11111,11 +11106,6 @@ build_binary_op (location_t location, en
 	}
       else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
 	{
-	  if (warn_nonnull
-	      && TREE_CODE (op1) == PARM_DECL && nonnull_arg_p (op1))
-	    warning_at (location, OPT_Wnonnull,
-			"nonnull argument %qD compared to NULL", op1);
-
 	  if (TREE_CODE (op1) == ADDR_EXPR
 	      && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
 	    {
--- gcc/cp/typeck.c.jj	2016-02-12 10:23:50.000000000 +0100
+++ gcc/cp/typeck.c	2016-02-16 11:40:37.783643278 +0100
@@ -4514,11 +4514,6 @@ cp_build_binary_op (location_t location,
 	       || (code0 == POINTER_TYPE
 		   && TYPE_PTR_P (type1) && integer_zerop (op1)))
 	{
-	  if (warn_nonnull
-	      && TREE_CODE (op0) == PARM_DECL && nonnull_arg_p (op0))
-	    warning_at (location, OPT_Wnonnull,
-			"nonnull argument %qD compared to NULL", op0);
-
 	  if (TYPE_PTR_P (type1))
 	    result_type = composite_pointer_type (type0, type1, op0, op1,
 						  CPO_COMPARISON, complain);
@@ -4558,11 +4553,6 @@ cp_build_binary_op (location_t location,
 	       || (code1 == POINTER_TYPE
 		   && TYPE_PTR_P (type0) && integer_zerop (op0)))
 	{
-	  if (warn_nonnull
-	      && TREE_CODE (op1) == PARM_DECL && nonnull_arg_p (op1))
-	    warning_at (location, OPT_Wnonnull,
-			"nonnull argument %qD compared to NULL", op1);
-
 	  if (TYPE_PTR_P (type0))
 	    result_type = composite_pointer_type (type0, type1, op0, op1,
 						  CPO_COMPARISON, complain);
--- gcc/testsuite/c-c++-common/nonnull-1.c.jj	2015-10-11 19:11:06.000000000 +0200
+++ gcc/testsuite/c-c++-common/nonnull-1.c	2016-02-16 12:38:53.917256278 +0100
@@ -1,7 +1,7 @@
 /* Test for the bad usage of "nonnull" function attribute parms.  */
 /*  */
 /* { dg-do compile } */
-/* { dg-options "-Wnonnull" } */
+/* { dg-options "-Wnonnull-compare" } */
 
 #include <stddef.h>
 #include <stdlib.h>
--- gcc/testsuite/c-c++-common/nonnull-2.c.jj	2016-02-16 12:52:17.149142596 +0100
+++ gcc/testsuite/c-c++-common/nonnull-2.c	2016-02-16 12:56:29.904645198 +0100
@@ -0,0 +1,26 @@
+/* Test for the bad usage of "nonnull" function attribute parms.  */
+/* { dg-do compile } */
+/* { dg-options "-Wnonnull-compare" } */
+
+void bar (char **);
+
+__attribute__((nonnull (1, 3))) int
+foo (char *cp1, char *cp2, char *cp3, char *cp4)
+{
+  if (cp1 == (char *) 0) /* { dg-warning "nonnull argument" "cp1 compared to NULL" } */
+    return 1;
+
+  cp1 = cp2;
+  if (cp1 == (char *) 0) /* { dg-bogus "nonnull argument" } */
+    return 2;
+
+  if (!cp4)	   /* { dg-bogus "nonnull argument" } */
+    return 3;
+
+  char **p = &cp3;
+  bar (p);
+  if (cp3 == (char *) 0) /* { dg-bogus "nonnull argument" } */
+    return 4;
+
+  return 5;
+}

	Jakub



More information about the Gcc-patches mailing list