aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Pinski <andrew.pinski@oss.qualcomm.com>2025-08-20 15:34:15 -0700
committerAndrew Pinski <andrew.pinski@oss.qualcomm.com>2025-08-21 11:35:52 -0700
commit8b41e021ba4ad8db6a6cbd512c8c42277909c402 (patch)
treed897cbb81abf7997c8c0635b8e14d63c68fb6bfe
parent70f33ad677e6350a724b56d4cb766480ed8367fc (diff)
downloadgcc-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.cc20
-rw-r--r--gcc/c/c-typeck.cc9
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr121478-1.c32
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);
+}