Added tests with some non-NPC pointers converted to bool.
(BTW: For some reason we allowed 0 == nullptr but not x ? 0 : nullptr in ISO C.) Bootstrapped and regression tested on x86_64. commit 5a29c43cca6fa5f50ad8266c5969a9420ef2488e Author: Martin Uecker <uec...@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/doc/ChangeLog: * invoke.texi (Wzero-as-null-pointer-constant): Adapt description. gcc/testsuite/ChangeLog: * gcc.dg/Wzero-as-null-pointer-constant.c: New test. Suggested-by: Alejandro Colomar <a...@kernel.org> Acked-by: Alejandro Colomar <a...@kernel.org> Reviewed-by: Joseph Myers <josmy...@redhat.com> 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/doc/invoke.texi b/gcc/doc/invoke.texi index 35a72361221..bfd5f4463ce 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -4750,9 +4750,8 @@ Enabled by default with @option{-std=c++20}. Before @opindex Wzero-as-null-pointer-constant @opindex Wno-zero-as-null-pointer-constant -@item -Wzero-as-null-pointer-constant @r{(C++ and Objective-C++ only)} -Warn when a literal @samp{0} is used as null pointer constant. This can -be useful to facilitate the conversion to @code{nullptr} in C++11. +@item -Wzero-as-null-pointer-constant +Warn when a literal @samp{0} is used as null pointer constant. @opindex Waligned-new @opindex Wno-aligned-new 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..b9cfbefe7b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wzero-as-null-pointer-constant.c @@ -0,0 +1,107 @@ +/* { 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); + + if (p); + p ? 0 : 1; + if (!p); + (!p) ? 0 : 1; + + int *v; + if (v); + v ? 1 : 0; + if (!v); + (!v) ? 1 : 0; + + bool j = p; + bool k = (bool)p; + + baz(p); + baz((bool)p); +} +