diff mbox

PR middle-end/16351 NULL dereference warnings

Message ID CAESRpQAh2eESu2MdE8E+PHjkWE0OBxDhdqqyEhfGTzYHs8X9NA@mail.gmail.com
State New
Headers show

Commit Message

Manuel López-Ibáñez July 22, 2015, 3:52 p.m. UTC
I took the patch in
https://gcc.gnu.org/ml/gcc-patches/2014-01/msg01715.html and removed
the Wnull-attribute part, since most of it can be done from the FE as
shown in https://gcc.gnu.org/ml/gcc-patches/2015-07/msg01857.html  and
also to make the patch smaller and easier to review.

I also fixed the comments by Florian here:
https://gcc.gnu.org/ml/gcc-patches/2014-02/msg00149.html and added
more tests from the PR and its duplicates (one xfailed, I'll open a
new PR about it).

Futher cleanups may be possible (infer_nonnull_range_by_attribute
checks flag_delete_null_pointer_checks, which seems weird to me but it
matches the existing behavior of infer_nonnull_range).

I added this to Wall to get as much testing as possible, we can always
move it to Wextra or disable it by default just before the release if
it turns out to be too noisy.

Boostrapped and regression tested on x86_64-linux-gnu.

OK?

gcc/ChangeLog:

2015-07-22  Manuel López-Ibáñez  <manu@gcc.gnu.org>
        Jeff Law  <law@redhat.com>

    PR c/16351
    * doc/invoke.texi (Wnull-dereference): New.
    * tree-vrp.c (infer_value_range): Update call to infer_nonnull_range.
    * gimple-ssa-isolate-paths.c (find_implicit_erroneous_behaviour):
    Warn for potential NULL dereferences.
    (find_explicit_erroneous_behaviour): Warn for NULL dereferences.
    * ubsan.c (instrument_nonnull_arg): Call
    infer_nonnull_range_by_attribute.
    (instrument_nonnull_return): Likewise.
    * common.opt (Wnull-dereference); New.
    * gimple.c (infer_nonnull_range): Remove bool arguments.
    (infer_nonnull_range_by_dereference): New.
    (infer_nonnull_range_by_attribute): New.
    * gimple.h: Update declarations.

gcc/testsuite/ChangeLog:

2015-07-22  Manuel López-Ibáñez  <manu@gcc.gnu.org>
        Jeff Law  <law@redhat.com>

    PR c/16351
    * gcc.dg/tree-ssa/isolate-2.c: Close comment.
    * gcc.dg/tree-ssa/isolate-4.c: Likewise.
    * gcc.dg/tree-ssa/wnull-dereference.c: New test.
    * gcc.dg/tree-ssa/isolate-1.c: Test warnings with -Wnull-dereference.
    * gcc.dg/tree-ssa/isolate-3.c: Likewise.
    * gcc.dg/tree-ssa/isolate-5.c: Likewise.
    * c-c++-common/wnonnull-1.c: New test.
diff mbox

Patch

Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c	(revision 225868)
+++ gcc/tree-vrp.c	(working copy)
@@ -4936,11 +4936,11 @@  infer_value_range (gimple stmt, tree op,
 	  break;
       if (e == NULL)
 	return false;
     }
 
-  if (infer_nonnull_range (stmt, op, true, true))
+  if (infer_nonnull_range (stmt, op))
     {
       *val_p = build_int_cst (TREE_TYPE (op), 0);
       *comp_code_p = NE_EXPR;
       return true;
     }
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 225868)
+++ gcc/doc/invoke.texi	(working copy)
@@ -258,10 +258,11 @@  Objective-C and Objective-C++ Dialects}.
 -Wframe-larger-than=@var{len} -Wno-free-nonheap-object -Wjump-misses-init @gol
 -Wignored-qualifiers  -Wincompatible-pointer-types @gol
 -Wimplicit  -Wimplicit-function-declaration  -Wimplicit-int @gol
 -Winit-self  -Winline  -Wno-int-conversion @gol
 -Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol
+-Wnull-dereference @gol
 -Winvalid-pch -Wlarger-than=@var{len}  -Wunsafe-loop-optimizations @gol
 -Wlogical-op -Wlogical-not-parentheses -Wlong-long @gol
 -Wmain -Wmaybe-uninitialized -Wmemset-transposed-args @gol
 -Wmisleading-indentation -Wmissing-braces @gol
 -Wmissing-field-initializers -Wmissing-include-dirs @gol
@@ -4130,10 +4133,20 @@  All the above @option{-Wunused} options 
 
 In order to get a warning about an unused function parameter, you must
 either specify @option{-Wextra -Wunused} (note that @option{-Wall} implies
 @option{-Wunused}), or separately specify @option{-Wunused-parameter}.
 
+@item -Wnull-dereference
+@opindex Wnull-dereference
+@opindex Wno-null-dereference
+Warn if the compiler detects paths which trigger erroneous or
+undefined behaviour due to dereferencing a NULL pointer.  This option
+is only active when @option{-fdelete-null-pointer-checks} is active,
+which is enabled by optimizations in most targets.  The precision of
+the warnings depends on the optimization options used.  This option is
+enabled by @option{-Wall}.
+
 @item -Wuninitialized
 @opindex Wuninitialized
 @opindex Wno-uninitialized
 Warn if an automatic variable is used without first being initialized
 or if a variable may be clobbered by a @code{setjmp} call. In C++,
Index: gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c	(revision 225868)
+++ gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c	(working copy)
@@ -33,10 +33,10 @@  bar (void)
    returns non-null attribute to isolate a path where NULL flows into
    a return statement.  We test this twice, once where the NULL flows
    from a PHI, the second with an explicit return 0 in the IL.
 
    We also verify that after isolation phi-cprop simplifies the
-   return statement so that it returns &z directly.
+   return statement so that it returns &z directly. */
 /* { dg-final { scan-tree-dump-times "__builtin_trap" 2 "isolate-paths"} } */
 /* { dg-final { scan-tree-dump-times "return &z;" 1 "phicprop1"} } */
 
 
Index: gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c	(revision 225868)
+++ gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c	(working copy)
@@ -22,10 +22,10 @@  bar (void)
 /* We testing that the path isolation code can take advantage of the
    returns non-null attribute to isolate a path where NULL flows into
    a return statement.
 
    We also verify that after isolation phi-cprop simplifies the
-   return statement so that it returns &z directly.
+   return statement so that it returns &z directly. */
 /* { dg-final { scan-tree-dump-times "__builtin_trap" 2 "isolate-paths"} } */
 /* { dg-final { scan-tree-dump-times "foo .&z.;" 1 "phicprop1"} } */
 
 
Index: gcc/testsuite/gcc.dg/tree-ssa/wnull-dereference.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/wnull-dereference.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/wnull-dereference.c	(revision 0)
@@ -0,0 +1,80 @@ 
+/* { dg-do compile } */ 
+/* PR c/16531 */
+/* { dg-options "-O2 -fdelete-null-pointer-checks -Wnull-dereference" } */
+/* { dg-skip-if "" keeps_null_pointer_checks } */
+
+#ifndef __cplusplus
+#define NULL (void *)0
+#else
+#define NULL nullptr
+#endif
+
+struct t
+{
+  int bar;
+};
+
+struct t2
+{
+  struct t *s;
+};
+
+void test1 ()
+{
+  struct t *s = NULL;
+  s->bar = 1;  /* { dg-warning "null" } */
+}
+
+void test2 (struct t *s)
+{
+  if (s == NULL && s->bar > 2)  /* { dg-warning "null" } */
+    return;
+
+  s->bar = 3;
+}
+
+void test3 (struct t *s)
+{
+  if (s != NULL || s->bar > 2)  /* { dg-warning "null" } */
+    return;
+
+  s->bar = 3;  /* { dg-warning "null" } */
+}
+
+void test4 (struct t *s)
+{
+  if (s != NULL && s->bar > 2)  /* { dg-bogus "null" } */
+    return;
+}
+
+void test5 (struct t *s)
+{
+  if (s == NULL || s->bar > 2)  /* { dg-bogus "null" } */
+    return;
+
+}
+
+void test6 (struct t2 *s)
+{
+  if (s->s == 0 && s->s->bar == 0)  /* { dg-warning "null" "null" { xfail *-*-* } } */
+    return;
+}
+
+int test7 (struct t *s)
+{
+  s = 0;
+  return s->bar;  /* { dg-warning "null" } */
+}
+
+int test8 ()
+{
+  return ((struct t *)0)->bar;  /* { dg-warning "null" } */
+}
+
+void test9 (struct t **s)
+{
+  if (s == 0)
+    *s = 0;  /* { dg-warning "null" } */
+}
+
+
Index: gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c	(revision 225868)
+++ gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c	(working copy)
@@ -1,8 +1,7 @@ 
-
 /* { dg-do compile } */ 
-/* { dg-options "-O2 -fdump-tree-isolate-paths -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fdump-tree-isolate-paths -fdelete-null-pointer-checks -Wnull-dereference" } */
 /* { dg-skip-if "" keeps_null_pointer_checks } */
 
 
 struct demangle_component
 {
@@ -37,12 +36,12 @@  d_make_empty (struct d_info *di)
 struct demangle_component *
 d_type (struct d_info *di)
 {
    struct demangle_component *ret;
    ret = d_make_empty (di);
-   ret->type = 42;
-   ret->zzz = -1;
+   ret->type = 42;		/* { dg-warning "null pointer dereference" } */
+   ret->zzz = -1;		/* { dg-warning "null pointer dereference" } */
    return ret;
 }
 
 /* We're testing three aspects of isolation here.  First that isolation
    occurs, second that if we have two null dereferences in a block that
@@ -51,10 +50,5 @@  d_type (struct d_info *di)
    and finally that we set the RHS of the store to zero.  */
 /* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
 /* { dg-final { scan-tree-dump-times "->type = 42" 1 "isolate-paths"} } */
 /* { dg-final { scan-tree-dump-times "->type ={v} 0" 1 "isolate-paths"} } */
 /* { dg-final { scan-tree-dump-times "->zzz" 1 "isolate-paths"} } */
-
-
-
-
-
Index: gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c	(revision 225868)
+++ gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c	(working copy)
@@ -1,7 +1,7 @@ 
 /* { dg-do compile } */ 
-/* { dg-options "-O2 -fdump-tree-isolate-paths -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fdump-tree-isolate-paths -fdelete-null-pointer-checks -Wnull-dereference" } */
 /* { dg-skip-if "" keeps_null_pointer_checks } */
 
 
 typedef __SIZE_TYPE__ size_t;
 extern void *memset (void *__s, int __c, size_t __n)
@@ -27,11 +27,11 @@  typedef struct VEC_rtx_gc
 
 static __inline__ void
 VEC_rtx_gc_safe_grow (VEC_rtx_gc ** vec_, int size_, const char *file_,
                       unsigned line_, const char *function_)
 {
-  ((*vec_) ? &(*vec_)->base : 0)->num = size_;
+  ((*vec_) ? &(*vec_)->base : 0)->num = size_; /* { dg-warning "null pointer dereference" } */
 } 
 
 static __inline__ void
 VEC_rtx_gc_safe_grow_cleared (VEC_rtx_gc ** vec_, int size_,
                               const char *file_, unsigned line_,
Index: gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c	(revision 225868)
+++ gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c	(working copy)
@@ -1,7 +1,7 @@ 
 /* { dg-do compile } */ 
-/* { dg-options "-O2 -fdelete-null-pointer-checks -fdump-tree-isolate-paths -fdump-tree-optimized" } */
+/* { dg-options "-O2 -fdelete-null-pointer-checks -fdump-tree-isolate-paths -fdump-tree-optimized -Wnull-dereference" } */
 /* { dg-skip-if "" keeps_null_pointer_checks } */
 
 struct demangle_component
 {
 
@@ -34,12 +34,12 @@  d_make_empty (struct d_info *di)
 struct demangle_component *
 d_type (struct d_info *di)
 {
    struct demangle_component *ret;
    ret = d_make_empty (di);
-   foo (ret->type);
-   bar (ret->zzz);
+   foo (ret->type); /* { dg-warning "null pointer dereference" } */
+   bar (ret->zzz); /* { dg-warning "null pointer dereference" } */
    return ret;
 }
 
 /* We're testing two aspects of isolation here.  First that isolation
    occurs, second that if we have two null dereferences in a block that
Index: gcc/testsuite/c-c++-common/wnonnull-1.c
===================================================================
--- gcc/testsuite/c-c++-common/wnonnull-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/wnonnull-1.c	(revision 0)
@@ -0,0 +1,42 @@ 
+/* { dg-do compile } */ 
+/* { dg-options "-Wnonnull" } */
+
+
+extern void foo(void *) __attribute__ ((__nonnull__ (1)));
+
+int z;
+int y;
+
+void
+com (int a)
+{
+  foo (a == 42 ? &z  : (void *) 0); /* { dg-warning "null" } */
+}
+
+void
+bar (void)
+{
+  foo ((void *)0); /* { dg-warning "null" } */
+}
+
+int * foo_r(int a) __attribute__((returns_nonnull));
+int * bar_r(void) __attribute__((returns_nonnull));
+
+int *
+foo_r(int a)
+{
+  switch (a)
+    {
+      case 0:
+        return &z;
+      default:
+        return (int *)0; /* { dg-warning "null" } */
+    }
+}
+
+int *
+bar_r (void)
+{
+  return 0;		/* { dg-warning "null" } */
+}
+
Index: gcc/gimple-ssa-isolate-paths.c
===================================================================
--- gcc/gimple-ssa-isolate-paths.c	(revision 225868)
+++ gcc/gimple-ssa-isolate-paths.c	(working copy)
@@ -329,15 +329,33 @@  find_implicit_erroneous_behaviour (void)
 		     in other blocks would require more complex path
 		     isolation code.   */
 		  if (gimple_bb (use_stmt) != bb)
 		    continue;
 
-		  if (infer_nonnull_range (use_stmt, lhs,
-					   flag_isolate_erroneous_paths_dereference,
-					   flag_isolate_erroneous_paths_attribute))
+		  bool by_dereference 
+		    = infer_nonnull_range_by_dereference (use_stmt, lhs);
 
+		  if (by_dereference 
+		      || infer_nonnull_range_by_attribute (use_stmt, lhs))
 		    {
+		      location_t loc = gimple_location (use_stmt)
+			? gimple_location (use_stmt)
+			: gimple_phi_arg_location (phi, i);
+
+		      if (by_dereference)
+			{
+			  warning_at (loc, OPT_Wnull_dereference,
+				      "potential null pointer dereference");
+			  if (!flag_isolate_erroneous_paths_dereference)
+			    continue;
+			}
+		      else 
+			{
+			  if (!flag_isolate_erroneous_paths_attribute)
+			    continue;
+			}
+
 		      duplicate = isolate_path (bb, duplicate, e,
 						use_stmt, lhs, false);
 
 		      /* When we remove an incoming edge, we need to
 			 reprocess the Ith element.  */
@@ -379,17 +397,33 @@  find_explicit_erroneous_behaviour (void)
 	 because of jump threading and constant propagation.  */
       for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
 	{
 	  gimple stmt = gsi_stmt (si);
 
-	  /* By passing null_pointer_node, we can use infer_nonnull_range
-	     to detect explicit NULL pointer dereferences and other uses
-	     where a non-NULL value is required.  */
-	  if (infer_nonnull_range (stmt, null_pointer_node,
-				   flag_isolate_erroneous_paths_dereference,
-				   flag_isolate_erroneous_paths_attribute))
+	  /* By passing null_pointer_node, we can use the
+	     infer_nonnull_range functions to detect explicit NULL
+	     pointer dereferences and other uses where a non-NULL
+	     value is required.  */
+	  
+	  bool by_dereference
+	    = infer_nonnull_range_by_dereference (stmt, null_pointer_node);
+	  if (by_dereference
+	      || infer_nonnull_range_by_attribute (stmt, null_pointer_node))
 	    {
+	      if (by_dereference)
+		{
+		  warning_at (gimple_location (stmt), OPT_Wnull_dereference,
+			      "null pointer dereference");
+		  if (!flag_isolate_erroneous_paths_dereference)
+		    continue;
+		}
+	      else
+		{
+		  if (!flag_isolate_erroneous_paths_attribute)
+		    continue;
+		}
+
 	      insert_trap_and_remove_trailing_statements (&si,
 							  null_pointer_node);
 
 	      /* And finally, remove all outgoing edges from BB.  */
 	      edge e;
@@ -532,11 +566,12 @@  public:
   virtual bool gate (function *)
     {
       /* If we do not have a suitable builtin function for the trap statement,
 	 then do not perform the optimization.  */
       return (flag_isolate_erroneous_paths_dereference != 0
-	      || flag_isolate_erroneous_paths_attribute != 0);
+	      || flag_isolate_erroneous_paths_attribute != 0
+	      || warn_null_dereference);
     }
 
   virtual unsigned int execute (function *)
     {
       return gimple_ssa_isolate_erroneous_paths ();
Index: gcc/ubsan.c
===================================================================
--- gcc/ubsan.c	(revision 225868)
+++ gcc/ubsan.c	(working copy)
@@ -1613,11 +1613,11 @@  instrument_nonnull_arg (gimple_stmt_iter
   loc[1] = UNKNOWN_LOCATION;
   for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++)
     {
       tree arg = gimple_call_arg (stmt, i);
       if (POINTER_TYPE_P (TREE_TYPE (arg))
-	  && infer_nonnull_range (stmt, arg, false, true))
+	  && infer_nonnull_range_by_attribute (stmt, arg))
 	{
 	  gimple g;
 	  if (!is_gimple_val (arg))
 	    {
 	      g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
@@ -1678,11 +1678,11 @@  instrument_nonnull_return (gimple_stmt_i
   loc[0] = gimple_location (stmt);
   loc[1] = UNKNOWN_LOCATION;
   if (arg
       && POINTER_TYPE_P (TREE_TYPE (arg))
       && is_gimple_val (arg)
-      && infer_nonnull_range (stmt, arg, false, true))
+      && infer_nonnull_range_by_attribute (stmt, arg))
     {
       basic_block then_bb, fallthru_bb;
       *gsi = create_cond_insert_point (gsi, true, false, true,
 				       &then_bb, &fallthru_bb);
       gimple g = gimple_build_cond (EQ_EXPR, arg,
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 225868)
+++ gcc/common.opt	(working copy)
@@ -590,10 +590,15 @@  Common RejectNegative Joined Warning Und
 
 Wlarger-than=
 Common RejectNegative Joined UInteger Warning
 -Wlarger-than=<number>	Warn if an object is larger than <number> bytes
 
+Wnull-dereference
+Common Var(warn_null_dereference) Warning EnabledBy(Wall)
+Warn if the compiler detects paths which trigger erroneous or undefined
+behaviour due to dereferencing a NULL pointer.
+
 Wunsafe-loop-optimizations
 Common Var(warn_unsafe_loop_optimizations) Warning
 Warn if the loop cannot be optimized due to nontrivial assumptions.
 
 Wmissing-noreturn
Index: gcc/gimple.c
===================================================================
--- gcc/gimple.c	(revision 225868)
+++ gcc/gimple.c	(working copy)
@@ -2616,35 +2616,52 @@  check_loadstore (gimple, tree op, tree, 
       && operand_equal_p (TREE_OPERAND (op, 0), (tree)data, 0))
     return true;
   return false;
 }
 
-/* If OP can be inferred to be non-NULL after STMT executes, return true.
 
-   DEREFERENCE is TRUE if we can use a pointer dereference to infer a
-   non-NULL range, FALSE otherwise.
-
-   ATTRIBUTE is TRUE if we can use attributes to infer a non-NULL range
-   for function arguments and return values.  FALSE otherwise.  */
+/* Return true if OP can be inferred to be non-NULL after STMT executes,
+   either by using a pointer dereference or attributes.  */
+bool
+infer_nonnull_range (gimple stmt, tree op)
+{
+  return infer_nonnull_range_by_dereference (stmt, op)
+    || infer_nonnull_range_by_attribute (stmt, op);
+}
 
+/* Return true if OP can be inferred to be non-NULL after STMT
+   executes by using a pointer dereference.  */
 bool
-infer_nonnull_range (gimple stmt, tree op, bool dereference, bool attribute)
+infer_nonnull_range_by_dereference (gimple stmt, tree op)
 {
   /* We can only assume that a pointer dereference will yield
      non-NULL if -fdelete-null-pointer-checks is enabled.  */
   if (!flag_delete_null_pointer_checks
       || !POINTER_TYPE_P (TREE_TYPE (op))
       || gimple_code (stmt) == GIMPLE_ASM)
     return false;
 
-  if (dereference
-      && walk_stmt_load_store_ops (stmt, (void *)op,
-				   check_loadstore, check_loadstore))
+  if (walk_stmt_load_store_ops (stmt, (void *)op,
+				check_loadstore, check_loadstore))
     return true;
 
-  if (attribute
-      && is_gimple_call (stmt) && !gimple_call_internal_p (stmt))
+  return false;
+}
+
+/* Return true if OP can be inferred to be a non-NULL after STMT
+   executes by using attributes.  */
+bool
+infer_nonnull_range_by_attribute (gimple stmt, tree op)
+{
+  /* We can only assume that a pointer dereference will yield
+     non-NULL if -fdelete-null-pointer-checks is enabled.  */
+  if (!flag_delete_null_pointer_checks
+      || !POINTER_TYPE_P (TREE_TYPE (op))
+      || gimple_code (stmt) == GIMPLE_ASM)
+    return false;
+
+  if (is_gimple_call (stmt) && !gimple_call_internal_p (stmt))
     {
       tree fntype = gimple_call_fntype (stmt);
       tree attrs = TYPE_ATTRIBUTES (fntype);
       for (; attrs; attrs = TREE_CHAIN (attrs))
 	{
@@ -2679,17 +2696,16 @@  infer_nonnull_range (gimple stmt, tree o
 	}
     }
 
   /* If this function is marked as returning non-null, then we can
      infer OP is non-null if it is used in the return statement.  */
-  if (attribute)
-    if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
-      if (gimple_return_retval (return_stmt)
-	  && operand_equal_p (gimple_return_retval (return_stmt), op, 0)
-	  && lookup_attribute ("returns_nonnull",
-			       TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
-	return true;
+  if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
+    if (gimple_return_retval (return_stmt)
+	&& operand_equal_p (gimple_return_retval (return_stmt), op, 0)
+	&& lookup_attribute ("returns_nonnull",
+			     TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
+      return true;
 
   return false;
 }
 
 /* Compare two case labels.  Because the front end should already have
Index: gcc/gimple.h
===================================================================
--- gcc/gimple.h	(revision 225868)
+++ gcc/gimple.h	(working copy)
@@ -1399,11 +1399,13 @@  extern bool gimple_call_builtin_p (const
 extern bool gimple_call_builtin_p (const_gimple, enum built_in_class);
 extern bool gimple_call_builtin_p (const_gimple, enum built_in_function);
 extern bool gimple_asm_clobbers_memory_p (const gasm *);
 extern void dump_decl_set (FILE *, bitmap);
 extern bool nonfreeing_call_p (gimple);
-extern bool infer_nonnull_range (gimple, tree, bool, bool);
+extern bool infer_nonnull_range (gimple, tree);
+extern bool infer_nonnull_range_by_dereference (gimple, tree);
+extern bool infer_nonnull_range_by_attribute (gimple, tree);
 extern void sort_case_labels (vec<tree>);
 extern void preprocess_case_label_vec_for_gimple (vec<tree>, tree, tree *);
 extern void gimple_seq_set_location (gimple_seq, location_t);
 extern void gimple_seq_discard (gimple_seq);
 extern void maybe_remove_unused_call_args (struct function *, gimple);