public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] warn for more impossible null pointer tests
@ 2021-09-01  2:08 Martin Sebor
  2021-09-01 17:35 ` Jeff Law
  2021-09-01 19:21 ` Jason Merrill
  0 siblings, 2 replies; 24+ messages in thread
From: Martin Sebor @ 2021-09-01  2:08 UTC (permalink / raw)
  To: gcc-patches, Jason Merrill, Joseph S. Myers

[-- Attachment #1: Type: text/plain, Size: 2925 bytes --]

A Coverity run recently uncovered a latent bug in GCC that GCC should
be able to detect itself: comparing the address of a declared object
for equality to null, similar to:

   int f (void)
   {
     int a[2][2];
     return &a == 0;
   }

GCC issues -Waddress for this code, but the bug Coverity found was
actually closer to the following:

   int f (void)
   {
     int a[2][2];
     return a[0] == 0;
   }

where the hapless author (yours truly) meant to compare the value
of a[0][0] (as in r12-3268).

This variant is not diagnosed even though the bug in it is the same
and I'd expect more likely to occur in practice.  (&a[0] == 0 isn't
diagnosed either, though that's a less likely mistake to make).

The attached patch enhances -Waddress to detect this variant along
with a number of other similar instances of the problem, including
comparing the address of array members to null.

Besides these, the patch also issues -Waddress for null equality
tests of pointer-plus expressions such as in:

   int g (int i)
   {
     return a[0] + i == 0;
   }

and in C++ more instances of pointers to members.

Testing on x86_64-linux, besides a few benign issues in GCC sources
a regression test, run shows a failure in gcc.dg/Waddress.c.  That's
a test added after GCC for some reason stopped warning for one of
the basic cases that other tools warn about (comparing an array to
null).  I suspect the change was unintentional because GCC still
warns for other very similar expressions.  The reporter who also
submitted the test in pr36299 argued that the warning wasn't
helpful because tests for arrays sometimes come from macros, and
the test was committed after it was noted that GCC no longer warned
for the reporter's simple case.  While it's certainly true that
the warning can be triggered by the null equality tests in macros
(the patch exposed two such instances in GCC) they are easy to
avoid (the patch adds a an additional escape hatch).  At the same
time, as is evident from the Coverity bug report and from the two
issues the enhancement exposes in the FORTRAN front end (even if
benign), issuing the warning in these cases does help find bugs
or mistaken assumptions.  With that, I've changed the test to
expect the restored -Waddress warning instead.

Testing with Glibc exposed a couple of harmless comparisons of
arrays a large macro in vfprintf-internal.c.  I'll submit a fix
to avoid the -Waddress instances if/when this enhancement is
approved.

Testing with Binutils/GDB also turned up a couple of pointless
comparison of arrays to null and a couple of uses in macros that
can be trivially suppressed.

Martin

PS Clang issues a warning for some of the same null pointer tests
the patch diagnoses, including gcc.dg/Waddress.c, except under at
least three different options: some under -Wpointer-bool-conversion,
others under -Wtautological-pointer-compare, and others still under
-Wtautological-compare.


[-- Attachment #2: gcc-102103.diff --]
[-- Type: text/x-patch, Size: 24702 bytes --]

Enhance -Waddress to detect more suspicious expressions.

Resolves:
PR c/102103 - missing warning comparing array address to null


gcc/ChangeLog:

	* doc/invoke.texi (-Waddress): Update.

gcc/c-family/ChangeLog:

	* c-common.c (decl_with_nonnull_addr_p): Handle members.

gcc/c/ChangeLog:

	* c-typeck.c (maybe_warn_for_null_address): New function.
	(build_binary_op): Call it.

gcc/cp/ChangeLog:

	* typeck.c (warn_for_null_address): Enhance.
	(cp_build_binary_op): Call it also for member pointers.

gcc/fortran/ChangeLog:

	* gcc/fortran/array.c: Remove an unnecessary test.
	* gcc/fortran/trans-array.c: Same.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/constexpr-array-ptr10.C: Suppress a valid warning.
	* g++.dg/warn/Wreturn-local-addr-6.C: Correct a cast.
	* gcc.dg/Waddress.c: Expect a warning.
	* c-c++-common/Waddress-3.c: New test.
	* c-c++-common/Waddress-4.c: New test.
	* g++.dg/warn/Waddress-5.C: New test.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 017e41537ac..ca3544bd066 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -3393,14 +3393,16 @@ c_wrap_maybe_const (tree expr, bool non_const)
   return expr;
 }
 
-/* Return whether EXPR is a declaration whose address can never be
-   NULL.  */
+/* Return whether EXPR is a declaration whose address can never be NULL.
+   The address of the first struct member could be NULL only if it were
+   accessed through a NULL pointer, and such an access would be invalid.  */
 
 bool
 decl_with_nonnull_addr_p (const_tree expr)
 {
   return (DECL_P (expr)
-	  && (TREE_CODE (expr) == PARM_DECL
+	  && (TREE_CODE (expr) == FIELD_DECL
+	      || TREE_CODE (expr) == PARM_DECL
 	      || TREE_CODE (expr) == LABEL_DECL
 	      || !DECL_WEAK (expr)));
 }
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index d9f26d67bd3..d6aa4fe9263 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -11541,6 +11541,78 @@ build_vec_cmp (tree_code code, tree type,
   return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
 }
 
+/* Possibly warn about an address of OP never being NULL in a comparison
+   operation CODE involving null.  */
+
+static void
+maybe_warn_for_null_address (location_t loc, tree op, tree_code code)
+{
+  if (!warn_address || warning_suppressed_p (op, OPT_Waddress))
+    return;
+
+  if (TREE_CODE (op) == NOP_EXPR)
+    {
+      /* Allow a cast to void* to suppress the warning.  */
+      tree type = TREE_TYPE (TREE_TYPE (op));
+      if (VOID_TYPE_P (type))
+	return;
+      op = TREE_OPERAND (op, 0);
+    }
+
+  if (TREE_CODE (op) == POINTER_PLUS_EXPR)
+    {
+      /* Allow a cast to void* to suppress the warning.  */
+      tree type = TREE_TYPE (TREE_TYPE (op));
+      if (VOID_TYPE_P (type))
+	return;
+
+      /* Adding any value to a null pointer, including zero, is undefined
+	 in C.  This includes the expression &p[0] where p is the null
+	 pointer, although &p[0] will have been folded to p by this point
+	 and so not diagnosed.  */
+      if (code == EQ_EXPR)
+	warning_at (loc, OPT_Waddress,
+		    "the comparison will always evaluate as %<false%> "
+		    "for the pointer operand in %qE must not be NULL",
+		    op);
+      else
+	warning_at (loc, OPT_Waddress,
+		    "the comparison will always evaluate as %<true%> "
+		    "for the pointer operand in %qE must not be NULL",
+		    op);
+
+      return;
+    }
+
+  if (TREE_CODE (op) != ADDR_EXPR)
+    return;
+
+  op = TREE_OPERAND (op, 0);
+  while (TREE_CODE (op) == ARRAY_REF
+	 || TREE_CODE (op) == COMPONENT_REF)
+    {
+      unsigned opno = TREE_CODE (op) == COMPONENT_REF;
+      op = TREE_OPERAND (op, opno);
+    }
+
+  if (!decl_with_nonnull_addr_p (op)
+      || from_macro_expansion_at (loc))
+    return;
+
+  if (code == EQ_EXPR)
+    warning_at (loc, OPT_Waddress,
+		"the comparison will always evaluate as %<false%> "
+		"for the address of %qD will never be NULL",
+		op);
+  else
+    warning_at (loc, OPT_Waddress,
+		"the comparison will always evaluate as %<true%> "
+		"for the address of %qD will never be NULL",
+		op);
+
+  inform (DECL_SOURCE_LOCATION (op), "%qD declared here", op);
+}
+
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    LOCATION is the operator's location.
@@ -12176,44 +12248,12 @@ build_binary_op (location_t location, enum tree_code code,
 	short_compare = 1;
       else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
 	{
-	  if (TREE_CODE (op0) == ADDR_EXPR
-	      && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0))
-	      && !from_macro_expansion_at (location))
-	    {
-	      if (code == EQ_EXPR)
-		warning_at (location,
-			    OPT_Waddress,
-			    "the comparison will always evaluate as %<false%> "
-			    "for the address of %qD will never be NULL",
-			    TREE_OPERAND (op0, 0));
-	      else
-		warning_at (location,
-			    OPT_Waddress,
-			    "the comparison will always evaluate as %<true%> "
-			    "for the address of %qD will never be NULL",
-			    TREE_OPERAND (op0, 0));
-	    }
+	  maybe_warn_for_null_address (location, op0, code);
 	  result_type = type0;
 	}
       else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
 	{
-	  if (TREE_CODE (op1) == ADDR_EXPR
-	      && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0))
-	      && !from_macro_expansion_at (location))
-	    {
-	      if (code == EQ_EXPR)
-		warning_at (location,
-			    OPT_Waddress,
-			    "the comparison will always evaluate as %<false%> "
-			    "for the address of %qD will never be NULL",
-			    TREE_OPERAND (op1, 0));
-	      else
-		warning_at (location,
-			    OPT_Waddress,
-			    "the comparison will always evaluate as %<true%> "
-			    "for the address of %qD will never be NULL",
-			    TREE_OPERAND (op1, 0));
-	    }
+	  maybe_warn_for_null_address (location, op1, code);
 	  result_type = type1;
 	}
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a46c6d2340d..50ee43a2ebe 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4617,28 +4617,76 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
   if (!warn_address
       || (complain & tf_warning) == 0
       || c_inhibit_evaluation_warnings != 0
-      || warning_suppressed_p (op, OPT_Waddress))
+      || warning_suppressed_p (op, OPT_Waddress)
+      || processing_template_decl != 0)
     return;
 
   tree cop = fold_for_warn (op);
 
-  if (TREE_CODE (cop) == ADDR_EXPR
-      && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
-      && !warning_suppressed_p (cop, OPT_Waddress))
-    warning_at (location, OPT_Waddress, "the address of %qD will never "
-		"be NULL", TREE_OPERAND (cop, 0));
+  if (TREE_CODE (op) == PTRMEM_CST)
+    {
+      /* The address of a nonstatic data member is never null.  */
+      warning_at (location, OPT_Waddress,
+		  "the address %qE will never be NULL",
+		  op);
+      return;
+    }
+
+  if (TREE_CODE (cop) == NOP_EXPR)
+    {
+      /* Allow a cast to void* to suppress the warning.  */
+      tree type = TREE_TYPE (TREE_TYPE (cop));
+      if (VOID_TYPE_P (type))
+	return;
+      STRIP_NOPS (cop);
+    }
+
+  bool warned = false;
+  if (TREE_CODE (cop) == ADDR_EXPR)
+    {
+      cop = TREE_OPERAND (cop, 0);
+      while (TREE_CODE (cop) == ARRAY_REF
+	     || TREE_CODE (cop) == COMPONENT_REF)
+	{
+	  unsigned opno = TREE_CODE (cop) == COMPONENT_REF;
+	  cop = TREE_OPERAND (cop, opno);
+	}
+
+      if (decl_with_nonnull_addr_p (cop)
+	  && !warning_suppressed_p (cop, OPT_Waddress))
+	warned = warning_at (location, OPT_Waddress,
+			     "the address of %qD will never be NULL", cop);
+    }
+  else if (TREE_CODE (cop) == POINTER_PLUS_EXPR)
+    {
+      /* Same as above, allow a cast to void* to suppress the warning.  */
+      tree type = TREE_TYPE (TREE_TYPE (cop));
+      if (VOID_TYPE_P (type))
+	return;
+
+      /* Adding zero to the null pointer is well-defined in C++.  When
+	 the offset is unknown (i.e., not a constant) warn anyway since
+	 it's less likely that the pointer operand is null than not.  */
+      tree off = TREE_OPERAND (cop, 1);
+      if (!integer_zerop (off))
+	warning_at (location, OPT_Waddress, "comparing the result of pointer "
+		    "addition %qE and NULL", cop);
+      return;
+    }
 
   if (CONVERT_EXPR_P (op)
       && TYPE_REF_P (TREE_TYPE (TREE_OPERAND (op, 0))))
     {
-      tree inner_op = op;
-      STRIP_NOPS (inner_op);
+      STRIP_NOPS (op);
 
-      if (DECL_P (inner_op))
-	warning_at (location, OPT_Waddress,
-		    "the compiler can assume that the address of "
-		    "%qD will never be NULL", inner_op);
+      if (DECL_P (op))
+	warned = warning_at (location, OPT_Waddress,
+			     "the compiler can assume that the address of "
+			     "%qD will never be NULL", op);
     }
+
+  if (warned && DECL_P (op))
+    inform (DECL_SOURCE_LOCATION (op), "%qD declared here", op);
 }
 
 /* Warn about [expr.arith.conv]/2: If one operand is of enumeration type and
@@ -5428,6 +5476,8 @@ cp_build_binary_op (const op_location_t &location,
 	      op1 = cp_convert (TREE_TYPE (op0), op1, complain);
 	    }
 	  result_type = TREE_TYPE (op0);
+
+	  warn_for_null_address (location, orig_op0, complain);
 	}
       else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (orig_op0))
 	return cp_build_binary_op (location, code, op1, op0, complain);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index b83bd902cec..9ffc7f2a2b4 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8547,17 +8547,40 @@ by @option{-Wall}.
 @item -Waddress
 @opindex Waddress
 @opindex Wno-address
-Warn about suspicious uses of memory addresses. These include using
-the address of a function in a conditional expression, such as
-@code{void func(void); if (func)}, and comparisons against the memory
-address of a string literal, such as @code{if (x == "abc")}.  Such
-uses typically indicate a programmer error: the address of a function
-always evaluates to true, so their use in a conditional usually
-indicate that the programmer forgot the parentheses in a function
-call; and comparisons against string literals result in unspecified
-behavior and are not portable in C, so they usually indicate that the
-programmer intended to use @code{strcmp}.  This warning is enabled by
-@option{-Wall}.
+Warn about suspicious uses of address expressions. These include comparing
+the address of a function or a declared object to the null pointer constant
+such as in
+@smallexample
+void f (void);
+void g (void)
+@{
+  if (!func)   // warning: expression evaluates to false
+    abort ();
+@}
+@end smallexample
+comparisons of a pointer to a string literal, such as in
+@smallexample
+void f (const char *x)
+@{
+  if (x == "abc")   // warning: expression evaluates to false
+    puts ("equal");
+@}
+@end smallexample
+and tests of the results of pointer addition or subtraction for equality
+to null, such as in
+@smallexample
+void f (const int *p, int i)
+@{
+  return p + i == NULL;
+@}
+@end smallexample
+Such uses typically indicate a programmer error: the address of most
+functions and objects necessarily evaluates to true (the exception are
+weak symbols), so their use in a conditional might indicate missing
+parentheses in a function call or a missing dereference in an array
+expression.  Comparisons against string literals result in unspecified
+behavior and are not portable, and suggest the intent was to call
+@code{strcmp}.  @option{-Waddress} warning is enabled by @option{-Wall}.
 
 @item -Wno-address-of-packed-member
 @opindex Waddress-of-packed-member
diff --git a/gcc/fortran/array.c b/gcc/fortran/array.c
index b858bada18a..341290f91b8 100644
--- a/gcc/fortran/array.c
+++ b/gcc/fortran/array.c
@@ -2578,7 +2578,7 @@ gfc_array_dimen_size (gfc_expr *array, int dimen, mpz_t *result)
 	    }
 	}
 
-      if (array->shape && array->shape[dimen])
+      if (array->shape)
 	{
 	  mpz_init_set (*result, array->shape[dimen]);
 	  return true;
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 0d013defdbb..5147509fbe7 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -5104,7 +5104,6 @@ set_loop_bounds (gfc_loopinfo *loop)
 
 	  if (info->shape)
 	    {
-	      gcc_assert (info->shape[dim]);
 	      /* The frontend has worked out the size for us.  */
 	      if (!loopspec[n]
 		  || !specinfo->shape
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 31d4bf4e5d0..fa6b81e806f 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -3685,8 +3685,8 @@ write_types (outf_p output_header, type_p structures,
 	output_mangled_typename (output_header, s);
 	oprintf (output_header, "(X) do { \\\n");
 	oprintf (output_header,
-		 "  if (X != NULL) gt_%sx_%s (X);\\\n", wtd->prefix,
-		 s_id_for_tag);
+		 "  if ((void *)(X) != NULL) gt_%sx_%s (X);\\\n",
+		 wtd->prefix, s_id_for_tag);
 	oprintf (output_header, "  } while (0)\n");
 
 	for (opt = s->u.s.opt; opt; opt = opt->next)
diff --git a/gcc/poly-int.h b/gcc/poly-int.h
index f47f9e436a8..94e7b701f64 100644
--- a/gcc/poly-int.h
+++ b/gcc/poly-int.h
@@ -324,10 +324,10 @@ struct poly_result<T1, T2, 2>
    routine can take the address of RES rather than the address of
    a temporary.
 
-   The dummy comparison against a null C * is just a way of checking
+   The dummy self-comparison against C * is just a way of checking
    that C gives the right type.  */
 #define POLY_SET_COEFF(C, RES, I, VALUE) \
-  ((void) (&(RES).coeffs[0] == (C *) 0), \
+  ((void) (&(RES).coeffs[0] == (C *) (void *) &(RES).coeffs[0]), \
    wi::int_traits<C>::precision_type == wi::FLEXIBLE_PRECISION \
    ? (void) ((RES).coeffs[I] = VALUE) \
    : (void) ((RES).coeffs[I].~C (), new (&(RES).coeffs[I]) C (VALUE)))
diff --git a/gcc/testsuite/c-c++-common/Waddress-3.c b/gcc/testsuite/c-c++-common/Waddress-3.c
new file mode 100644
index 00000000000..2390f6722b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Waddress-3.c
@@ -0,0 +1,226 @@
+/* PR c/102103 - missing warning comparing array address to null
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+struct S { void *p, *a1[2], *a2[2][2]; } s, *p;
+
+extern void *a1[2], *a2[2][2], *ax[];
+
+int x;
+
+void test_array_eq_0 (int i)
+{
+  // Verify that a cast to void* suppresses the warning.
+  if ((void *)a1 == 0)
+    ++x;
+
+  if (a1 == 0)          // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a1)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a1[0] == 0)
+    ++x;
+
+  if (0 == (void *)&a1[0])
+    ++x;
+
+  if (0 == &a1[0])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a1[i] == 0)
+    ++x;
+
+  if (0 == (void *)&a1[i])
+    ++x;
+
+  if (0 == &a1[i])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2 == 0)          // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a2)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2[0] == 0)       // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a1[0])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2[i] == 0)       // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a2[i])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2[0][0] == 0)
+    ++x;
+
+  if (0 == &a2[0][0])   // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&ax == 0)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &ax)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&ax[0] == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == ax[0])
+    ++x;
+}
+
+
+void test_array_neq_0 (int i)
+{
+  // Verify that a cast to void* suppresses the warning.
+  if ((void *)a1)
+    ++x;
+
+  if (a1)               // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&a1 != 0)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a1[0])
+    ++x;
+
+  if (&a1[0] != 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a1[i])
+    ++x;
+
+  if (&a1[i] != 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2)               // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&a2 != 0)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2[0])            // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&a1[0] != 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2[i])            // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&a2[i] != 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2[0][0])
+    ++x;
+
+  if (&a2[0][0] != 0)   // { dg-warning "-Waddress" }
+    ++x;
+}
+
+
+void test_member_array_eq_0 (int i)
+{
+  // Verify that a cast to void* suppresses the warning.
+  if ((void *)s.a1 == 0)
+    ++x;
+
+  if (s.a1 == 0)        // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a1)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a1[0] == 0)
+    ++x;
+
+  if (0 == &a1[0])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a1[i] == 0)
+    ++x;
+
+  if (0 == &a1[i])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a2 == 0)        // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a2)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a2[0] == 0)     // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a1[0])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a2[i] == 0)     // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a2[i])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a2[0][0] == 0)
+    ++x;
+
+  if (0 == &a2[0][0]) // { dg-warning "-Waddress" }
+    ++x;
+}
+
+
+void test_member_array_neq_0 (int i)
+{
+  // Verify that a cast to void* suppresses the warning.
+  if ((void *)s.a1)
+    ++x;
+
+  if (s.a1)             // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&s.a1 != 0)       // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a1[0])
+    ++x;
+
+  if (&s.a1[0] != 0)    // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a1[i])
+    ++x;
+
+  if (&s.a1[i] != 0)    // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a2)             // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&s.a2 != 0)       // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a2[0])          // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&s.a1[0] != 0)    // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a2[i])          // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&s.a2[i] != 0)    // { dg-warning "-Waddress" }
+    ++x;
+
+  if (s.a2[0][0])
+    ++x;
+
+  if (&s.a2[0][0] != 0) // { dg-warning "-Waddress" }
+    ++x;
+}
diff --git a/gcc/testsuite/c-c++-common/Waddress-4.c b/gcc/testsuite/c-c++-common/Waddress-4.c
new file mode 100644
index 00000000000..6aa94f4c375
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Waddress-4.c
@@ -0,0 +1,109 @@
+/* PR c/102103 - missing warning comparing array address to null
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+extern char *ax[], *a2[][2];
+
+extern int x;
+
+void test_ax_plus_eq_0 (int i)
+{
+  // Verify that a cast to void* suppresses the warning.
+  if ((void *)(ax + 0) == 0)
+    ++x;
+
+  if (ax + 0 == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&ax[0] == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (ax - 1 == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &ax[-1])     // { dg-warning "-Waddress" }
+    ++x;
+
+  if ((void *)(&ax[0] + 2) == 0)
+    ++x;
+
+  if (&ax[0] + 2 == 0)  // { dg-warning "-Waddress" }
+    ++x;
+
+  if (ax + 3 == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &ax[-4])     // { dg-warning "-Waddress" }
+    ++x;
+
+  if (ax - i == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&ax[i] == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &ax[1] + i)  // { dg-warning "-Waddress" }
+    ++x;
+}
+
+void test_a2_plus_eq_0 (int i)
+{
+  // Verify that a cast to void* suppresses the warning.
+  if ((void *)(a2 + 0) == 0)
+    ++x;
+
+  if (a2 + 0 == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&a2[0] == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2 - 1 == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a2[-1])     // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2 + 2 == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &a2[-2])     // { dg-warning "-Waddress" }
+    ++x;
+
+  if (a2 - i == 0)      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&a2[i] == 0)      // { dg-warning "-Waddress" }
+    ++x;
+}
+
+
+void test_p_plus_eq_0 (int *p, int i)
+{
+  /* P + 0 and equivalently &P[0] are folded to p before the warning
+     has a chance to trigger.  */
+
+  if (p + 0 == 0)       // { dg-warning "-Waddress" "pr??????" { xfail *-*-*} }
+    ++x;
+
+  if (&p[0] == 0)       // { dg-warning "-Waddress" "pr??????" { xfail *-*-*} }
+    ++x;
+
+  if (p - 1 == 0)       // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &p[-1])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (p + 2 == 0)       // { dg-warning "-Waddress" }
+    ++x;
+
+  if (0 == &p[-2])      // { dg-warning "-Waddress" }
+    ++x;
+
+  if (p - i == 0)       // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&p[i] == 0)       // { dg-warning "-Waddress" }
+    ++x;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
index 5224bb14234..63295230d51 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
@@ -85,8 +85,11 @@ extern __attribute__ ((weak)) int i;
 constexpr int *p1 = &i + 1;
 
 #pragma GCC diagnostic push
+// Suppress warning: ordered comparison of pointer with integer zero.
 #pragma GCC diagnostic ignored "-Wextra"
-// Suppress warning: ordered comparison of pointer with integer zero
+// Also suppress -Waddress for comparisons of constant addresses to
+// to null.
+#pragma GCC diagnostic ignored "-Waddress"
 
 constexpr bool b0  = p1;        // { dg-error "not a constant expression" }
 constexpr bool b1  = p1 == 0;   // { dg-error "not a constant expression" }
diff --git a/gcc/testsuite/g++.dg/warn/Waddress-5.C b/gcc/testsuite/g++.dg/warn/Waddress-5.C
new file mode 100644
index 00000000000..5278cda2fab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Waddress-5.C
@@ -0,0 +1,75 @@
+/* PR c/102103 - missing warning comparing array address to null
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+struct A
+{
+  void f ();
+  virtual void vf ();
+  virtual void pvf () = 0;
+
+  void sf ();
+
+  int *p;
+  int a[2];
+};
+
+int x;
+
+void warn_memptr ()
+{
+  // Exercise warnings for addresses of nonstatic member functions.
+  if (&A::f == 0)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&A::vf)             // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&A::pvf != 0)       // { dg-warning "-Waddress" }
+    ++x;
+
+  // Exercise warnings for addresses of static member functions.
+  if (&A::sf == 0)        // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&A::sf)             // { dg-warning "-Waddress" }
+    ++x;
+
+  // Exercise warnings for addresses of nonstatic data members.
+  if (&A::p == 0)         // { dg-warning "-Waddress" }
+    ++x;
+
+  if (&A::a == 0)         // { dg-warning "-Waddress" }
+    ++x;
+}
+
+
+// Verify that no warnings are issued for an uninstantiated template.
+
+template <int>
+struct B
+{
+  // This is why.
+  struct F { void* operator& () const { return 0; } } f;
+};
+
+template <int N>
+void nowarn_template ()
+{
+  if (&B<N>::f == 0)
+    ++x;
+
+  /* Like in the case above, the address-of operator could be a member
+     of B<N>::vf that returns zero.  */
+  if (&B<N>::vf)
+    ++x;
+
+  if (&B<N>::pvf != 0)
+    ++x;
+
+  if (&B<N>::p == 0)
+    ++x;
+
+  if (&B<N>::a == 0)
+    ++x;
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C
index bfe14457547..fae8b7e766f 100644
--- a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C
+++ b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-6.C
@@ -9,7 +9,7 @@ const intptr_t&
 return_addr_label_as_intref (void)
 {
  label:
-  if ((const intptr_t*)&&label == 0)
+  if ((const intptr_t)&&label == 0)
     __builtin_exit (1);
 
   return *(const intptr_t*)&&label;   // { dg-warning "\\\[-Wreturn-local-addr]" } */
@@ -19,7 +19,7 @@ const intptr_t&
 return_addr_local_as_intref (void)
 {
   int a[1];
-  if ((const intptr_t*)a == 0)
+  if ((const intptr_t)a == 0)
     __builtin_exit (1);
 
   return (const intptr_t&)a;   // { dg-warning "\\\[-Wreturn-local-addr]" } */
diff --git a/gcc/testsuite/gcc.dg/Waddress.c b/gcc/testsuite/gcc.dg/Waddress.c
index 146b1a932df..b26e7b1f329 100644
--- a/gcc/testsuite/gcc.dg/Waddress.c
+++ b/gcc/testsuite/gcc.dg/Waddress.c
@@ -6,5 +6,5 @@ int
 foo(void)
 {
   char a[1];
-  return a == 0;
+  return a == 0;    // { dg-warning "-Waddress" }
 }

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2021-10-01 17:58 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-01  2:08 [PATCH] warn for more impossible null pointer tests Martin Sebor
2021-09-01 17:35 ` Jeff Law
2021-09-01 18:57   ` Koning, Paul
2021-09-01 19:08     ` Jeff Law
2021-09-01 19:28       ` Koning, Paul
2021-09-01 19:35         ` Iain Sandoe
2021-09-01 19:58           ` Andreas Schwab
2021-09-01 20:36           ` Koning, Paul
2021-09-01 19:21 ` Jason Merrill
2021-09-01 20:33   ` Martin Sebor
2021-09-01 21:39     ` Jason Merrill
2021-09-01 22:27       ` Martin Sebor
2021-09-02 13:43         ` Jason Merrill
2021-09-02 14:39           ` Martin Sebor
2021-09-02 23:53             ` [PATCH] warn for more impossible null pointer tests [PR102103] Martin Sebor
2021-09-08 20:06               ` Jason Merrill
2021-09-17 16:02                 ` Martin Sebor
2021-09-21 21:40                   ` Jason Merrill
2021-09-22  0:34                     ` Martin Sebor
2021-09-22 20:12                       ` Jason Merrill
2021-09-24 14:31                       ` PING " Martin Sebor
2021-09-30 16:14                         ` PING #2 " Martin Sebor
2021-09-30 19:35                           ` Joseph Myers
2021-10-01 17:58                             ` Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).