]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c: Add support for byte arrays in C2Y
authorMartin Uecker <uecker@tugraz.at>
Sun, 23 Jun 2024 21:14:33 +0000 (23:14 +0200)
committerMartin Uecker <uecker@gcc.gnu.org>
Fri, 2 Aug 2024 08:56:12 +0000 (10:56 +0200)
To get correct aliasing behavior requires that structures and unions
that contain a byte array, i.e. an array of non-atomic character
type (N3254), are marked with TYPE_TYPELESS_STORAGE.  This change
affects also earlier language modes.

gcc/c/
* c-decl.cc (grokdeclarator, finish_struct): Set and
propagate TYPE_TYPELESS_STORAGE.

gcc/testsuite/
* gcc.dg/c2y-byte-alias-1.c: New test.
* gcc.dg/c2y-byte-alias-2.c: New test.
* gcc.dg/c2y-byte-alias-3.c: New test.

gcc/c/c-decl.cc
gcc/testsuite/gcc.dg/c2y-byte-alias-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2y-byte-alias-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2y-byte-alias-3.c [new file with mode: 0644]

index 97f1d346835edf5805d6a65e1edee70e556616d4..8cef8f2c28958085c6db378ac47dcd6867575c71 100644 (file)
@@ -7502,12 +7502,18 @@ grokdeclarator (const struct c_declarator *declarator,
               modify the shared type, so we gcc_assert (itype)
               below.  */
              {
+               /* Identify typeless storage as introduced in C2Y
+                  and supported also in earlier language modes.  */
+               bool typeless = (char_type_p (type)
+                                && !(type_quals & TYPE_QUAL_ATOMIC))
+                               || (AGGREGATE_TYPE_P (type)
+                                   && TYPE_TYPELESS_STORAGE (type));
+
                addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals);
                if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type))
                  type = build_qualified_type (type,
                                               ENCODE_QUAL_ADDR_SPACE (as));
-
-               type = build_array_type (type, itype);
+               type = build_array_type (type, itype, typeless);
              }
 
            if (type != error_mark_node)
@@ -9659,6 +9665,10 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
       if (DECL_NAME (x)
          || RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
        saw_named_field = true;
+
+      if (AGGREGATE_TYPE_P (TREE_TYPE (x))
+         && TYPE_TYPELESS_STORAGE (TREE_TYPE (x)))
+       TYPE_TYPELESS_STORAGE (t) = true;
     }
 
   detect_field_duplicates (fieldlist);
@@ -9859,6 +9869,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
       TYPE_FIELDS (x) = TYPE_FIELDS (t);
       TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
       TYPE_TRANSPARENT_AGGR (x) = TYPE_TRANSPARENT_AGGR (t);
+      TYPE_TYPELESS_STORAGE (x) = TYPE_TYPELESS_STORAGE (t);
       C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t);
       C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
       C_TYPE_FIELDS_NON_CONSTEXPR (x) = C_TYPE_FIELDS_NON_CONSTEXPR (t);
diff --git a/gcc/testsuite/gcc.dg/c2y-byte-alias-1.c b/gcc/testsuite/gcc.dg/c2y-byte-alias-1.c
new file mode 100644 (file)
index 0000000..30bc2c0
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -O2" } */
+
+struct f { _Alignas(int) char buf[sizeof(int)]; };
+struct f2 { struct f x; };
+union g { _Alignas(int) char buf[sizeof(int)]; };
+
+[[gnu::noinline]]
+int foo(struct f *p, int *q)
+{
+       *q = 1;
+       *p = (struct f){ };
+       return *q;
+}
+
+[[gnu::noinline]]
+int foo2(struct f2 *p, int *q)
+{
+       *q = 1;
+       *p = (struct f2){ };
+       return *q;
+}
+
+[[gnu::noinline]]
+int bar(union g *p, int *q)
+{
+       *q = 1;
+       *p = (union g){ };
+       return *q;
+}
+
+
+int main()
+{
+       struct f p;
+       if (0 != foo(&p, (void*)&p.buf))
+               __builtin_abort();
+
+       struct f2 p2;
+       if (0 != foo2(&p2, (void*)&p2.x.buf))
+               __builtin_abort();
+
+       union g q;
+       if (0 != bar(&q, (void*)&q.buf))
+               __builtin_abort();
+}
diff --git a/gcc/testsuite/gcc.dg/c2y-byte-alias-2.c b/gcc/testsuite/gcc.dg/c2y-byte-alias-2.c
new file mode 100644 (file)
index 0000000..9bd2d18
--- /dev/null
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -O2" } */
+
+struct f2 {
+       struct f {
+               _Alignas(int) char buf[sizeof(int)];
+       } x[2];
+       int i;
+};
+
+[[gnu::noinline]]
+int foo2(struct f2 *p, int *q)
+{
+       *q = 1;
+       *p = (struct f2){ };
+       return *q;
+}
+
+struct g2 {
+       union g {
+               _Alignas(int) char buf[sizeof(int)];
+       } x[2];
+       int i;
+};
+
+[[gnu::noinline]]
+int bar2(struct g2 *p, int *q)
+{
+       *q = 1;
+       *p = (struct g2){ };
+       return *q;
+}
+
+int main()
+{
+       struct f2 p2;
+       if (0 != foo2(&p2, (void*)&p2.x[0].buf))
+               __builtin_abort();
+
+       struct g2 q2;
+       if (0 != bar2(&q2, (void*)&q2.x[0].buf))
+               __builtin_abort();
+}
diff --git a/gcc/testsuite/gcc.dg/c2y-byte-alias-3.c b/gcc/testsuite/gcc.dg/c2y-byte-alias-3.c
new file mode 100644 (file)
index 0000000..f88eab2
--- /dev/null
@@ -0,0 +1,47 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -O2" } */
+
+struct f { _Alignas(int) typeof(volatile char) buf[sizeof(int)]; };
+struct f2 { struct f x; };
+union g { _Alignas(int) volatile char buf[sizeof(int)]; };
+
+
+[[gnu::noinline]]
+int foo(struct f *p, int *q)
+{
+       *q = 1;
+       *p = (struct f){ };
+       return *q;
+}
+
+[[gnu::noinline]]
+int foo2(struct f2 *p, int *q)
+{
+       *q = 1;
+       *p = (struct f2){ };
+       return *q;
+}
+
+[[gnu::noinline]]
+int bar(union g *p, int *q)
+{
+       *q = 1;
+       *p = (union g){ };
+       return *q;
+}
+
+
+int main()
+{
+       struct f p;
+       if (0 != foo(&p, (void*)&p.buf))
+               __builtin_abort();
+
+       struct f2 p2;
+       if (0 != foo2(&p2, (void*)&p2.x.buf))
+               __builtin_abort();
+
+       union g q;
+       if (0 != bar(&q, (void*)&q.buf))
+               __builtin_abort();
+}