diff options
author | Andrew Pinski <andrew.pinski@oss.qualcomm.com> | 2025-08-20 15:34:15 -0700 |
---|---|---|
committer | Andrew Pinski <andrew.pinski@oss.qualcomm.com> | 2025-08-21 11:35:52 -0700 |
commit | 8b41e021ba4ad8db6a6cbd512c8c42277909c402 (patch) | |
tree | d897cbb81abf7997c8c0635b8e14d63c68fb6bfe | |
parent | 70f33ad677e6350a724b56d4cb766480ed8367fc (diff) | |
download | gcc-8b41e021ba4ad8db6a6cbd512c8c42277909c402.zip gcc-8b41e021ba4ad8db6a6cbd512c8c42277909c402.tar.gz gcc-8b41e021ba4ad8db6a6cbd512c8c42277909c402.tar.bz2 |
c: Add folding of nullptr_t in some cases [PR121478]
The middle-end does not fully understand NULLPTR_TYPE. So it
gets confused a lot of the time when dealing with it.
This adds the folding that is similarly done in the C++ front-end already.
In some cases it should produce slightly better code as there is no
reason to load from a nullptr_t variable as it is always NULL.
The following is handled:
nullptr_v ==/!= nullptr_v -> true/false
(ptr)nullptr_v -> (ptr)0, nullptr_v
f(nullptr_v) -> f ((nullptr, nullptr_v))
The last one is for conversion inside ... .
Bootstrapped and tested on x86_64-linux-gnu.
PR c/121478
gcc/c/ChangeLog:
* c-fold.cc (c_fully_fold_internal): Fold nullptr_t ==/!= nullptr_t.
* c-typeck.cc (convert_arguments): Handle conversion from nullptr_t
for varargs.
(convert_for_assignment): Handle conversions from nullptr_t to
pointer type specially.
gcc/testsuite/ChangeLog:
* gcc.dg/torture/pr121478-1.c: New test.
Signed-off-by: Andrew Pinski <andrew.pinski@oss.qualcomm.com>
-rw-r--r-- | gcc/c/c-fold.cc | 20 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/pr121478-1.c | 32 |
3 files changed, 58 insertions, 3 deletions
diff --git a/gcc/c/c-fold.cc b/gcc/c/c-fold.cc index d54ab3c..3f6e4b46 100644 --- a/gcc/c/c-fold.cc +++ b/gcc/c/c-fold.cc @@ -369,7 +369,25 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, || TREE_CODE (op1) != INTEGER_CST)) goto out; - if (op0 != orig_op0 || op1 != orig_op1 || in_init) + if (TREE_CODE_CLASS (code) == tcc_comparison + && TREE_CODE (TREE_TYPE (op0)) == NULLPTR_TYPE + && TREE_CODE (TREE_TYPE (op1)) == NULLPTR_TYPE) + { + switch (code) + { + case EQ_EXPR: + ret = constant_boolean_node (true, TREE_TYPE (expr)); + break; + case NE_EXPR: + ret = constant_boolean_node (false, TREE_TYPE (expr)); + break; + default: + gcc_unreachable (); + } + ret = omit_two_operands_loc (loc, TREE_TYPE (expr), ret, + op0, op1); + } + else if (op0 != orig_op0 || op1 != orig_op1 || in_init) ret = in_init ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1) : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 3c6f7d9..6a08fcd 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -4679,6 +4679,9 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree fntype, val, valtype, npc, rname, parmnum, argnum, excess_precision, 0); } + /* A NULLPTR type is just a nullptr always. */ + else if (TREE_CODE (TREE_TYPE (val)) == NULLPTR_TYPE) + parmval = omit_one_operand_loc (ploc, TREE_TYPE (val), nullptr_node, val); else if (promote_float_arg) { if (type_generic) @@ -8983,11 +8986,13 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, && coder == INTEGER_TYPE) warning_at (location, OPT_Wzero_as_null_pointer_constant, "zero as null pointer constant"); - + /* A NULLPTR type is just a nullptr always. */ + if (coder == NULLPTR_TYPE) + return omit_one_operand_loc (expr_loc, type, nullptr_node, rhs); /* 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. */ - if (!null_pointer_constant && coder != NULLPTR_TYPE) + else if (!null_pointer_constant) switch (errtype) { case ic_argpass: diff --git a/gcc/testsuite/gcc.dg/torture/pr121478-1.c b/gcc/testsuite/gcc.dg/torture/pr121478-1.c new file mode 100644 index 0000000..1dda01c --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr121478-1.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-std=gnu23" } */ + +#include <stddef.h> +#include <stdlib.h> +typedef struct { + int data[5]; + nullptr_t np; +} container_t; +void process_array(int *arr, size_t len, nullptr_t nullp) { + for (size_t i = 0; i < len; ++i) { + switch (arr[i] % 4) { + case 1: + if (nullp == nullptr) { + arr[i] *= -1; + [[fallthrough]]; + } + case 2: + arr[i] = abs(arr[i]); + break; + default: + arr[i] = 0; + } + } +} +int main(void) { + container_t c = { + .data = { -3, 1, 4, 2, 7 }, + .np = nullptr + }; + process_array(c.data, 5, c.np); +} |