From 3d525fce70fa0ffa0b22af6e213643e1ceca5ab5 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Mon, 18 Nov 2024 22:24:48 +0000 Subject: [PATCH] c: Allow bool and enum null pointer constants [PR112556] 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. --- gcc/c/c-typeck.cc | 2 + .../gcc.dg/c11-null-pointer-constant-1.c | 55 ++++++++ .../gcc.dg/c23-null-pointer-constant-1.c | 120 ++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/c11-null-pointer-constant-1.c create mode 100644 gcc/testsuite/gcc.dg/c23-null-pointer-constant-1.c diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 26ee0ebf91f..a701dd090fb 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 00000000000..f463a1a59da --- /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 00000000000..71b66cc35d6 --- /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 +}