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.pin...@oss.qualcomm.com>
---
 gcc/c/c-fold.cc                           | 20 +++++++++++++-
 gcc/c/c-typeck.cc                         |  9 +++++--
 gcc/testsuite/gcc.dg/torture/pr121478-1.c | 32 +++++++++++++++++++++++
 3 files changed, 58 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr121478-1.c

diff --git a/gcc/c/c-fold.cc b/gcc/c/c-fold.cc
index d54ab3cf479..3f6e4b469b9 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 3c6f7d996e9..6a08fcd396a 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 00000000000..1dda01c6241
--- /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);
+}
-- 
2.43.0

Reply via email to