As reported in bug 112556, GCC wrongly rejects conversion of null
pointer constants with bool or enum type to pointers in
convert_for_assignment (assignment, initialization, argument passing,
return).  Fix the code there to allow BOOLEAN_TYPE and ENUMERAL_TYPE;
it already allowed INTEGER_TYPE and BITINT_TYPE.

This bug (together with -std=gnu23 meaning false has type bool rather
than int) has in turn resulted in people thinking they need to fix
code using false as a null pointer constant for C23 compatibility.
While such a usage is certainly questionable, it has nothing to do
with C23 compatibility and the right place for warnings about such
usage is -Wzero-as-null-pointer-constant.  I think it would be
appropriate to extend -Wzero-as-null-pointer-constant to cover
BOOLEAN_TYPE, ENUMERAL_TYPE and BITINT_TYPE (in all the various
contexts in which that option generates warnings), though this patch
doesn't do anything about that option.

Bootstrapped with no regressions for x86-64-pc-linux-gnu.

        PR c/112556

gcc/c/
        * c-typeck.cc (convert_for_assignment): Allow conversion of
        ENUMERAL_TYPE and BOOLEAN_TYPE null pointer constants to pointers.

gcc/testsuite/
        * gcc.dg/c11-null-pointer-constant-1.c,
        gcc.dg/c23-null-pointer-constant-1.c: New tests.

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 26ee0ebf91f0..a701dd090fb8 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -8457,6 +8457,8 @@ convert_for_assignment (location_t location, location_t 
expr_loc, tree type,
     }
   else if (codel == POINTER_TYPE
           && (coder == INTEGER_TYPE
+              || coder == ENUMERAL_TYPE
+              || coder == BOOLEAN_TYPE
               || coder == NULLPTR_TYPE
               || coder == BITINT_TYPE))
     {
diff --git a/gcc/testsuite/gcc.dg/c11-null-pointer-constant-1.c 
b/gcc/testsuite/gcc.dg/c11-null-pointer-constant-1.c
new file mode 100644
index 000000000000..f463a1a59da3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-null-pointer-constant-1.c
@@ -0,0 +1,55 @@
+/* Test zero with different types as null pointer constant: bug 112556.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors -Wno-pointer-compare" } */
+
+enum e { ZERO };
+
+void *p1 = 0;
+void *p2 = 0LL;
+void *p3 = (char) 0;
+void *p4 = 0UL;
+void *p5 = (_Bool) 0;
+void *p6 = (enum e) ZERO;
+
+void f (void *);
+
+void *
+g (void)
+{
+  p1 = 0;
+  p2 = 0LL;
+  p3 = (char) 0;
+  p4 = 0UL;
+  p5 = (_Bool) 0;
+  p6 = (enum e) ZERO;
+  f (0);
+  f (0ULL);
+  f (0L);
+  f ((char) 0);
+  f ((_Bool) 0);
+  f ((enum e) ZERO);
+  (1 ? p1 : 0);
+  (1 ? p1 : 0L);
+  (1 ? p1 : 0ULL);
+  (1 ? p1 : (char) 0);
+  (1 ? p1 : (_Bool) 0);
+  (1 ? p1 : (enum e) 0);
+  p1 == 0;
+  p1 == 0LL;
+  p1 == 0U;
+  p1 == (char) 0;
+  p1 == (_Bool) 0;
+  p1 == (enum e) 0;
+  p1 != 0;
+  p1 != 0LL;
+  p1 != 0U;
+  p1 != (char) 0;
+  p1 != (_Bool) 0;
+  p1 != (enum e) 0;
+  return 0;
+  return 0UL;
+  return 0LL;
+  return (char) 0;
+  return (_Bool) 0;
+  return (enum e) 0;
+}
diff --git a/gcc/testsuite/gcc.dg/c23-null-pointer-constant-1.c 
b/gcc/testsuite/gcc.dg/c23-null-pointer-constant-1.c
new file mode 100644
index 000000000000..71b66cc35d6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-null-pointer-constant-1.c
@@ -0,0 +1,120 @@
+/* Test zero with different types as null pointer constant: bug 112556.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -Wno-pointer-compare" } */
+
+enum e { ZERO };
+enum e2 : bool { BZERO };
+enum e3 : long { LZERO };
+
+void *p1 = 0;
+void *p2 = 0LL;
+void *p3 = (char) 0;
+void *p4 = 0UL;
+void *p5 = (bool) 0;
+void *p6 = (enum e) ZERO;
+void *p7 = false;
+void *p8 = BZERO;
+void *p9 = (enum e2) 0;
+void *p10 = LZERO;
+void *p11 = (enum e3) 0;
+#ifdef __BITINT_MAXWIDTH__
+void *p12 = 0wb;
+void *p13 = 0uwb;
+#endif
+
+void f (void *);
+
+void *
+g (void)
+{
+  p1 = 0;
+  p2 = 0LL;
+  p3 = (char) 0;
+  p4 = 0UL;
+  p5 = (bool) 0;
+  p6 = (enum e) ZERO;
+  p7 = false;
+  p8 = BZERO;
+  p9 = (enum e2) 0;
+  p10 = LZERO;
+  p11 = (enum e3) 0;
+#ifdef __BITINT_MAXWIDTH__
+  p12 = 0wb;
+  p13 = 0uwb;
+#endif
+  f (0);
+  f (0ULL);
+  f (0L);
+  f ((char) 0);
+  f ((bool) 0);
+  f ((enum e) ZERO);
+  f (false);
+  f (BZERO);
+  f ((enum e2) 0);
+  f (LZERO);
+  f ((enum e3) 0);
+#ifdef __BITINT_MAXWIDTH__
+  f (0wb);
+  f (0uwb);
+#endif
+  (1 ? p1 : 0);
+  (1 ? p1 : 0L);
+  (1 ? p1 : 0ULL);
+  (1 ? p1 : (char) 0);
+  (1 ? p1 : (bool) 0);
+  (1 ? p1 : (enum e) 0);
+  (1 ? p1 : false);
+  (1 ? p1 : BZERO);
+  (1 ? p1 : (enum e2) 0);
+  (1 ? p1 : LZERO);
+  (1 ? p1 : (enum e3) 0);
+#ifdef __BITINT_MAXWIDTH__
+  (1 ? p1 : 0wb);
+  (1 ? p1 : 0uwb);
+#endif
+  p1 == 0;
+  p1 == 0LL;
+  p1 == 0U;
+  p1 == (char) 0;
+  p1 == (bool) 0;
+  p1 == (enum e) 0;
+  p1 == false;
+  p1 == BZERO;
+  p1 == (enum e2) 0;
+  p1 == LZERO;
+  p1 == (enum e3) 0;
+#ifdef __BITINT_MAXWIDTH__
+  p1 == 0wb;
+  p1 == 0uwb;
+#endif
+  p1 != 0;
+  p1 != 0LL;
+  p1 != 0U;
+  p1 != (char) 0;
+  p1 != (bool) 0;
+  p1 != (enum e) 0;
+  p1 != false;
+  p1 != BZERO;
+  p1 != (enum e2) 0;
+  p1 != LZERO;
+  p1 != (enum e3) 0;
+#ifdef __BITINT_MAXWIDTH__
+  p1 != 0wb;
+  p1 != 0uwb;
+#endif
+  return 0;
+  return 0UL;
+  return 0LL;
+  return (char) 0;
+  return (bool) 0;
+  return (enum e) 0;
+  return false;
+  return BZERO;
+  return (enum e2) 0;
+  return LZERO;
+  return (enum e3) 0;
+#ifdef __BITINT_MAXWIDTH__
+  return 0wb;
+  return 0uwb;
+#endif
+}

-- 
Joseph S. Myers
josmy...@redhat.com

Reply via email to