diff mbox series

[v3] c: add Wzero-as-null-pointer-constant [PR117059]

Message ID d26e4fe5d3820846b0fc0e6f35c93a003d5ae788.camel@tugraz.at
State New
Headers show
Series [v3] c: add Wzero-as-null-pointer-constant [PR117059] | expand

Commit Message

Martin Uecker Nov. 11, 2024, 6:04 p.m. UTC
This patch enables the Wzero-as-null-pointer-constant for C.
The third version adds more tests. 


Bootstrapped and regression tested on x86_64.


commit 3afa3065be59374389daebfb32490fb93ad63d88
Author: Martin Uecker <uecker@tugraz.at>
Date:   Sat Nov 9 10:48:52 2024 +0100

    c: add Wzero-as-null-pointer-constant [PR117059]
    
    Add warnings for the use of zero as a null pointer constant to the C FE.
    
            PR c/117059
    
    gcc/c-family/ChangeLog:
            * c.opt (Wzero-as-null-pointer-constant): Enable for C and ObjC.
    
    gcc/c/ChangeLog:
            * c-typeck.cc (parse_build_binary_op): Add warning.
            (build_conditional_expr): Add warning.
            (convert_for_assignment): Add warning.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/Wzero-as-null-pointer-constant.c: New test.
    
    Suggested-by: Alejandro Colomar <alx@kernel.org>
    Acked-by: Alejandro Colomar <alx@kernel.org>
    Reviewed-by: Joseph Myers <josmyers@redhat.com>

Comments

Joseph Myers Nov. 11, 2024, 6:13 p.m. UTC | #1
On Mon, 11 Nov 2024, Martin Uecker wrote:

> This patch enables the Wzero-as-null-pointer-constant for C.
> The third version adds more tests. 

The various tests for boolean operations should also test those for 
pointers that are *not* null pointers (to verify that the implicit 0 being 
compared against isn't being diagnosed as if it were an integer 0 null 
pointer constant).
diff mbox series

Patch

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 9b9f5e744f6..b4e967ce000 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1632,7 +1632,7 @@  C ObjC C++ ObjC++ Var(warn_xor_used_as_pow) Warning Init(1)
 Warn about xor operators where it appears the user meant exponentiation.
 
 Wzero-as-null-pointer-constant
-C++ ObjC++ Var(warn_zero_as_null_pointer_constant) Warning
+C ObjC C++ ObjC++ Var(warn_zero_as_null_pointer_constant) Warning
 Warn when a literal '0' is used as null pointer.
 
 Wzero-length-bounds
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 201d75d2e9c..ced58c2be84 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -4600,6 +4600,25 @@  parser_build_binary_op (location_t location, enum tree_code code,
 		"comparison with string literal results in unspecified "
 		"behavior");
 
+  if (warn_zero_as_null_pointer_constant
+      && c_inhibit_evaluation_warnings == 0
+      && TREE_CODE_CLASS (code) == tcc_comparison)
+    {
+      if ((TREE_CODE (type1) == POINTER_TYPE
+	   || TREE_CODE (type1) == NULLPTR_TYPE)
+	  && TREE_CODE (type2) == INTEGER_TYPE
+	  && null_pointer_constant_p (arg2.value))
+	warning_at (arg2.get_location(), OPT_Wzero_as_null_pointer_constant,
+		    "zero as null pointer constant");
+
+      if ((TREE_CODE (type2) == POINTER_TYPE
+	   || TREE_CODE (type2) == NULLPTR_TYPE)
+	  && TREE_CODE (type1) == INTEGER_TYPE
+	  && null_pointer_constant_p (arg1.value))
+	warning_at (arg1.get_location(), OPT_Wzero_as_null_pointer_constant,
+		    "zero as null pointer constant");
+    }
+
   if (warn_array_compare
       && TREE_CODE_CLASS (code) == tcc_comparison
       && TREE_CODE (type1) == ARRAY_TYPE
@@ -5965,6 +5984,20 @@  build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
 		    t1, t2);
     }
 
+  if (warn_zero_as_null_pointer_constant
+      && c_inhibit_evaluation_warnings == 0)
+    {
+      if ((code1 == POINTER_TYPE || code1 == NULLPTR_TYPE)
+	  && code2 == INTEGER_TYPE && null_pointer_constant_p (orig_op2))
+	warning_at (op2_loc, OPT_Wzero_as_null_pointer_constant,
+		    "zero as null pointer constant");
+
+      if ((code2 == POINTER_TYPE || code2 == NULLPTR_TYPE)
+	  && code1 == INTEGER_TYPE && null_pointer_constant_p (orig_op1))
+	warning_at (op1_loc, OPT_Wzero_as_null_pointer_constant,
+		    "zero as null pointer constant");
+    }
+
   /* Quickly detect the usual case where op1 and op2 have the same type
      after promotion.  */
   if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
@@ -8396,6 +8429,11 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	       || coder == NULLPTR_TYPE
 	       || coder == BITINT_TYPE))
     {
+      if (null_pointer_constant && c_inhibit_evaluation_warnings == 0
+	  && coder == INTEGER_TYPE)
+	warning_at (location, OPT_Wzero_as_null_pointer_constant,
+		    "zero as null pointer constant");
+
       /* An explicit constant 0 or type nullptr_t can convert to a pointer,
 	 or one that results from arithmetic, even including a cast to
 	 integer type.  */
diff --git a/gcc/testsuite/gcc.dg/Wzero-as-null-pointer-constant.c b/gcc/testsuite/gcc.dg/Wzero-as-null-pointer-constant.c
new file mode 100644
index 00000000000..54cee704311
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wzero-as-null-pointer-constant.c
@@ -0,0 +1,90 @@ 
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -Wzero-as-null-pointer-constant" } */
+
+#define NULL (void*)0
+
+void foo(void*);
+void baz(bool);
+
+void bar()
+{
+	foo(0);				/* { dg-warning "zero as null pointer constant" } */
+	foo(NULL);
+	foo(nullptr);
+
+	int a = 0;
+
+	bool b = 0;
+	bool c = (void*)0;
+	bool d = NULL;
+	bool e = nullptr;
+
+	bool f = (bool)0;
+	bool g = (bool)(void*)0;
+	bool h = (bool)NULL;
+	bool i = (bool)nullptr;
+
+	baz(0);
+	baz((void*)0);
+	baz(NULL);
+	baz(nullptr);
+	baz((bool)0);
+	baz((bool)(void*)0);
+	baz((bool)NULL);
+	baz((bool)nullptr);
+
+	void *p = 0;			/* { dg-warning "zero as null pointer constant" } */
+	void *r = NULL;
+	void *t = nullptr;
+	void *o = { };
+	void *q = { 0 };		/* { dg-warning "zero as null pointer constant" } */
+	void *s = { NULL };
+	void *u = { nullptr };
+	struct { void *q; } x = { 0 };	/* { dg-warning "zero as null pointer constant" } */
+	struct { void *q; } y = { NULL };
+	struct { void *q; } z = { nullptr };
+	struct { int a; void *b; } n = { 0 };
+	struct { int a; int b; void *c; } m = { 0, 0 };
+
+	1 ? 0 : 0;
+	1 ? i : 0;
+	1 ? 0 : p;			/* { dg-warning "zero as null pointer constant" } */
+	1 ? p : 0;			/* { dg-warning "zero as null pointer constant" } */
+	1 ? 0 : NULL;			/* { dg-warning "zero as null pointer constant" } */
+	1 ? NULL : 0;			/* { dg-warning "zero as null pointer constant" } */
+
+	0 ? 0 : 1;
+	(void*)0 ? 0 : 1;
+	NULL ? 0 : 1;
+	nullptr ? 0 : 1;
+
+	if (0 == 0);
+	if (i == 0);
+	if (p == 0);			/* { dg-warning "zero as null pointer constant" } */
+	if (0 == p);			/* { dg-warning "zero as null pointer constant" } */
+	if (NULL == 0);			/* { dg-warning "zero as null pointer constant" } */
+	if (0 == NULL);			/* { dg-warning "zero as null pointer constant" } */
+	if (0 == (void*)0);		/* { dg-warning "zero as null pointer constant" } */
+	if (0 == nullptr);		/* { dg-warning "zero as null pointer constant" } */
+	if (nullptr == 0);		/* { dg-warning "zero as null pointer constant" } */
+
+	if (0 != 0);
+	if (i != 0);
+	if (p != 0);			/* { dg-warning "zero as null pointer constant" } */
+	if (0 != p);			/* { dg-warning "zero as null pointer constant" } */
+	if (NULL != 0);			/* { dg-warning "zero as null pointer constant" } */
+	if (0 != NULL);			/* { dg-warning "zero as null pointer constant" } */
+	if (0 != (void*)0);		/* { dg-warning "zero as null pointer constant" } */
+	if (0 != nullptr);		/* { dg-warning "zero as null pointer constant" } */
+	if (nullptr != 0);		/* { dg-warning "zero as null pointer constant" } */
+
+	if (0);
+	if (NULL);
+	if ((void*)0);
+	if (nullptr);
+	if (!0);
+	if (!NULL);
+	if (!(void*)0);
+	if (!nullptr);
+}
+