https://gcc.gnu.org/g:e0140b308723211c08944cc583490da108269736

commit e0140b308723211c08944cc583490da108269736
Author: Alexandre Oliva <ol...@adacore.com>
Date:   Thu Jul 17 17:54:00 2025 -0300

    [hardbool] implement OP=, ++ and --, volatile and atomics
    
    hardbools didn't behave quite like bools when incremented,
    decremented, or otherwise modified using their previous value, as in
    += et al.  Fix that.
    
    Also fix some checking errors that come up when using qualified base
    types, and implement sane semantics for increments and decrements of
    volatile hardbools.
    
    
    for  gcc/c-family/ChangeLog
    
            * c-attribs.cc (handle_hardbool_attribute): Create distinct
            enumeration types, with structural equality.  Handle
            base type qualifiers.
    
    for  gcc/c/ChangeLog
    
            * c-tree.h (C_BOOLEAN_TYPE_P): Cover hardbools as well.
            * c-typeck.cc (convert_lvalue_to_rvalue): New overload and
            wrapper.
            (build_atomic_assign, build_modify_expr): Use it.
            (build_asm_expr, handle_omp-array_sections_1): Simplify with
            it.
            (build_unary_op): Handle hardbools.
    
    for  gcc/testsuite/ChangeLog
    
            * gcc.dg/torture/hardbool-ai.c: New.
            * gcc.dg/torture/hardbool-vi.c: New.
            * gcc.dg/torture/hardbool.c: Handle NO_BITFIELDS.
            (add1, preinc, postinc, sub1, predec, postdec): New.
            (main): Exercise them.

Diff:
---
 gcc/c-family/c-attribs.cc                  | 13 +++--
 gcc/c/c-tree.h                             |  3 +-
 gcc/c/c-typeck.cc                          | 83 ++++++++++++++++++++++++------
 gcc/testsuite/gcc.dg/torture/hardbool-ai.c |  7 +++
 gcc/testsuite/gcc.dg/torture/hardbool-vi.c |  5 ++
 gcc/testsuite/gcc.dg/torture/hardbool.c    | 68 +++++++++++++++++++++++-
 6 files changed, 159 insertions(+), 20 deletions(-)

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 1f4a0df12051..e7500ca2beb4 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -1128,11 +1128,12 @@ handle_hardbool_attribute (tree *node, tree name, tree 
args,
     }
 
   tree orig = *node;
-  *node = build_duplicate_type (orig);
+  tree unqual = build_qualified_type (orig, TYPE_UNQUALIFIED);
+  *node = build_distinct_type_copy (unqual);
 
   TREE_SET_CODE (*node, ENUMERAL_TYPE);
   ENUM_UNDERLYING_TYPE (*node) = orig;
-  TYPE_CANONICAL (*node) = TYPE_CANONICAL (orig);
+  SET_TYPE_STRUCTURAL_EQUALITY (*node);
 
   tree false_value;
   if (args)
@@ -1191,7 +1192,13 @@ handle_hardbool_attribute (tree *node, tree name, tree 
args,
 
   gcc_checking_assert (!TYPE_CACHED_VALUES_P (*node));
   TYPE_VALUES (*node) = values;
-  TYPE_NAME (*node) = orig;
+  TYPE_NAME (*node) = unqual;
+
+  if (TYPE_QUALS (orig) != TYPE_QUALS (*node))
+    {
+      *node = build_qualified_type (*node, TYPE_QUALS (orig));
+      TYPE_NAME (*node) = orig;
+    }
 
   return NULL_TREE;
 }
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 364f51df58c9..daf79f722760 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -163,7 +163,8 @@ along with GCC; see the file COPYING3.  If not see
   (TREE_CODE (TYPE) == BOOLEAN_TYPE                                    \
    || (TREE_CODE (TYPE) == ENUMERAL_TYPE                               \
        && ENUM_UNDERLYING_TYPE (TYPE) != NULL_TREE                     \
-       && TREE_CODE (ENUM_UNDERLYING_TYPE (TYPE)) == BOOLEAN_TYPE))
+       && (TREE_CODE (ENUM_UNDERLYING_TYPE (TYPE)) == BOOLEAN_TYPE     \
+          || c_hardbool_type_attr (TYPE))))
 
 /* Record parser information about an expression that is irrelevant
    for code generation alongside a tree representing its value.  */
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index e022e61c6b19..f6fa288b6ab2 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -2648,6 +2648,20 @@ convert_lvalue_to_rvalue (location_t loc, struct c_expr 
exp,
   return exp;
 }
 
+/* Wrapper for the overload above, same arguments but for tree rather than
+   c_expr.  This is important for hardbools to decay to bools.  */
+
+static inline tree
+convert_lvalue_to_rvalue (location_t loc, tree val,
+                         bool convert_p, bool read_p, bool for_init = false)
+{
+  struct c_expr expr;
+  memset (&expr, 0, sizeof (expr));
+  expr.value = val;
+  expr = convert_lvalue_to_rvalue (loc, expr, convert_p, read_p, for_init);
+  return expr.value;
+}
+
 /* EXP is an expression of integer type.  Apply the integer promotions
    to it and return the promoted value.  */
 
@@ -5271,7 +5285,9 @@ cas_loop:
   /* newval = old + val;  */
   if (rhs_type != rhs_semantic_type)
     val = build1 (EXCESS_PRECISION_EXPR, nonatomic_rhs_semantic_type, val);
-  rhs = build_binary_op (loc, modifycode, old, val, true);
+  rhs = build_binary_op (loc, modifycode,
+                        convert_lvalue_to_rvalue (loc, old, true, true),
+                        val, true);
   if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
     {
       tree eptype = TREE_TYPE (rhs);
@@ -5727,7 +5743,48 @@ build_unary_op (location_t location, enum tree_code 
code, tree xarg,
            goto return_build_unary_op;
          }
 
-       if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg)))
+       tree true_res;
+       if (c_hardbool_type_attr (TREE_TYPE (arg), NULL, &true_res))
+         {
+           tree larg = stabilize_reference (arg);
+           tree sarg = save_expr (larg);
+           switch (code)
+             {
+             case PREINCREMENT_EXPR:
+               val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, true_res);
+               val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), sarg, val);
+               break;
+             case POSTINCREMENT_EXPR:
+               val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, true_res);
+               val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), val, sarg);
+               val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), sarg, val);
+               break;
+             case PREDECREMENT_EXPR:
+               {
+                 tree rarg = convert_lvalue_to_rvalue (location, sarg,
+                                                       true, true);
+                 rarg = invert_truthvalue_loc (location, rarg);
+                 rarg = convert (TREE_TYPE (sarg), rarg);
+                 val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, rarg);
+               }
+               break;
+             case POSTDECREMENT_EXPR:
+               {
+                 tree rarg = convert_lvalue_to_rvalue (location, sarg,
+                                                       true, true);
+                 rarg = invert_truthvalue_loc (location, rarg);
+                 tree iarg = convert (TREE_TYPE (larg), rarg);
+                 val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, iarg);
+                 val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), val, sarg);
+                 val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), sarg, val);
+               }
+               break;
+             default:
+               gcc_unreachable ();
+             }
+           TREE_SIDE_EFFECTS (val) = 1;
+         }
+       else if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg)))
          val = boolean_increment (code, arg);
        else
          val = build2 (code, TREE_TYPE (arg), arg, inc);
@@ -7335,8 +7392,10 @@ build_modify_expr (location_t location, tree lhs, tree 
lhs_origtype,
                clear_decl_read = true;
            }
 
-         newrhs = build_binary_op (location,
-                                   modifycode, lhs, newrhs, true);
+         newrhs = build_binary_op (location, modifycode,
+                                   convert_lvalue_to_rvalue (location, lhs,
+                                                             true, true),
+                                   newrhs, true);
          if (clear_decl_read)
            DECL_READ_P (lhs) = 0;
 
@@ -12725,11 +12784,9 @@ build_asm_expr (location_t loc, tree string, tree 
outputs, tree inputs,
            }
          else
            {
-             struct c_expr expr;
-             memset (&expr, 0, sizeof (expr));
-             expr.value = input;
-             expr = convert_lvalue_to_rvalue (loc, expr, true, false);
-             input = c_fully_fold (expr.value, false, NULL);
+             input = c_fully_fold (convert_lvalue_to_rvalue (loc, input,
+                                                             true, false),
+                                   false, NULL);
 
              if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input)))
                {
@@ -15349,12 +15406,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> 
&types,
          /* If the array section is pointer based and the pointer
             itself is _Atomic qualified, we need to atomically load
             the pointer.  */
-         c_expr expr;
-         memset (&expr, 0, sizeof (expr));
-         expr.value = ret;
-         expr = convert_lvalue_to_rvalue (OMP_CLAUSE_LOCATION (c),
-                                          expr, false, false);
-         ret = expr.value;
+         ret = convert_lvalue_to_rvalue (OMP_CLAUSE_LOCATION (c),
+                                         ret, false, false);
        }
       return ret;
     }
diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-ai.c 
b/gcc/testsuite/gcc.dg/torture/hardbool-ai.c
new file mode 100644
index 000000000000..97569a6de6da
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/hardbool-ai.c
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+
+#define basetype _Atomic int
+
+#define NO_BITFIELDS 1
+
+#include "hardbool.c"
diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-vi.c 
b/gcc/testsuite/gcc.dg/torture/hardbool-vi.c
new file mode 100644
index 000000000000..898d395c5c52
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/hardbool-vi.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+
+#define basetype volatile int
+
+#include "hardbool.c"
diff --git a/gcc/testsuite/gcc.dg/torture/hardbool.c 
b/gcc/testsuite/gcc.dg/torture/hardbool.c
index 01684952a2a9..ed0c5988d2be 100644
--- a/gcc/testsuite/gcc.dg/torture/hardbool.c
+++ b/gcc/testsuite/gcc.dg/torture/hardbool.c
@@ -21,8 +21,12 @@ typedef unsigned char __attribute__ ((__hardbool__ (1, 0))) 
zbool;
 
 struct hs {
   hbool a[2];
+#ifndef NO_BITFIELDS
   hbool x:2;
   hbool y:5;
+#else
+  hbool x, y;
+#endif
   zbool z:1;
 };
 
@@ -57,6 +61,30 @@ int ghs(hbool s) {
 
 int t = (hbool)2;
 
+hbool add1(hbool *s) {
+  return *s += 1;
+}
+
+hbool preinc(hbool *s) {
+  return ++*s;
+}
+
+hbool postinc(hbool *s) {
+  return (*s)++;
+}
+
+hbool sub1(hbool *s) {
+  return *s -= 1;
+}
+
+hbool predec(hbool *s) {
+  return --*s;
+}
+
+hbool postdec(hbool *s) {
+  return (*s)--;
+}
+
 void check_pfalse (hbool *p)
 {
   assert (!*p);
@@ -114,5 +142,43 @@ int main () {
   check_vtrue (h2 (2));
   check_vtrue (h2 (1));
   check_vfalse (h2 (0));
-}
 
+  hbool v;
+  v = 0;
+  check_vtrue (add1 (&v));
+  assert (v);
+  v = 0;
+  check_vtrue (preinc (&v));
+  assert (v);
+  v = 0;
+  check_vfalse (postinc (&v));
+  assert (v);
+  v = 0;
+  check_vtrue (sub1 (&v));
+  assert (v);
+  v = 0;
+  check_vtrue (predec (&v));
+  assert (v);
+  v = 0;
+  check_vfalse (postdec (&v));
+  assert (v);
+  
+  v = 1;
+  check_vtrue (add1 (&v));
+  assert (v);
+  v = 1;
+  check_vtrue (preinc (&v));
+  assert (v);
+  v = 1;
+  check_vtrue (postinc (&v));
+  assert (v);
+  v = 1;
+  check_vfalse (sub1 (&v));
+  assert (!v);
+  v = 1;
+  check_vfalse (predec (&v));
+  assert (!v);
+  v = 1;
+  check_vtrue (postdec (&v));
+  assert (!v);
+}

Reply via email to