middle-end: Reject flexible array members in __builtin_clear_padding [PR97943]
authorJakub Jelinek <jakub@redhat.com>
Wed, 25 Nov 2020 09:37:58 +0000 (10:37 +0100)
committerJakub Jelinek <jakub@redhat.com>
Wed, 25 Nov 2020 09:37:58 +0000 (10:37 +0100)
As mentioned in the PR, we currently ICE on flexible array members in
structs and unions during __builtin_clear_padding processing.

Jason said in the PR he'd prefer an error in these cases over forcefully
handling it as [0] arrays (everything is padding then) or consider the
arrays to have as many whole elements as would fit into the tail padding.

So, this patch implements that.

2020-11-25  Jakub Jelinek  <jakub@redhat.com>

PR middle-end/97943
* gimple-fold.c (clear_padding_union, clear_padding_type): Error on and
ignore flexible array member fields.  Ignore fields with
error_mark_node type.

* c-c++-common/builtin-clear-padding-2.c: New test.
* c-c++-common/builtin-clear-padding-3.c: New test.
* g++.dg/ext/builtin-clear-padding-1.C: New test.
* gcc.dg/builtin-clear-padding-2.c: New test.

gcc/gimple-fold.c
gcc/testsuite/c-c++-common/builtin-clear-padding-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/builtin-clear-padding-3.c [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/builtin-clear-padding-1.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtin-clear-padding-2.c [new file with mode: 0644]

index 905c0a0..1f0a609 100644 (file)
@@ -4329,6 +4329,17 @@ clear_padding_union (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
   for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     if (TREE_CODE (field) == FIELD_DECL)
       {
+       if (DECL_SIZE_UNIT (field) == NULL_TREE)
+         {
+           if (TREE_TYPE (field) == error_mark_node)
+             continue;
+           gcc_assert (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+                       && !COMPLETE_TYPE_P (TREE_TYPE (field)));
+           error_at (buf->loc, "flexible array member %qD does not have "
+                               "well defined padding bits for %qs",
+                     field, "__builtin_clear_padding");
+           continue;
+         }
        HOST_WIDE_INT fldsz = tree_to_shwi (DECL_SIZE_UNIT (field));
        gcc_assert (union_buf->size == 0);
        union_buf->off = start_off;
@@ -4446,11 +4457,12 @@ clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
       for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
        if (TREE_CODE (field) == FIELD_DECL)
          {
+           tree ftype = TREE_TYPE (field);
            if (DECL_BIT_FIELD (field))
              {
                if (DECL_NAME (field) == NULL_TREE)
                  continue;
-               HOST_WIDE_INT fldsz = TYPE_PRECISION (TREE_TYPE (field));
+               HOST_WIDE_INT fldsz = TYPE_PRECISION (ftype);
                if (fldsz == 0)
                  continue;
                HOST_WIDE_INT pos = int_byte_position (field);
@@ -4513,6 +4525,16 @@ clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
                      }
                  }
              }
+           else if (DECL_SIZE_UNIT (field) == NULL_TREE)
+             {
+               if (ftype == error_mark_node)
+                 continue;
+               gcc_assert (TREE_CODE (ftype) == ARRAY_TYPE
+                           && !COMPLETE_TYPE_P (ftype));
+               error_at (buf->loc, "flexible array member %qD does not have "
+                                   "well defined padding bits for %qs",
+                         field, "__builtin_clear_padding");
+             }
            else
              {
                HOST_WIDE_INT pos = int_byte_position (field);
diff --git a/gcc/testsuite/c-c++-common/builtin-clear-padding-2.c b/gcc/testsuite/c-c++-common/builtin-clear-padding-2.c
new file mode 100644 (file)
index 0000000..67c03c8
--- /dev/null
@@ -0,0 +1,17 @@
+/* PR middle-end/97943 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct S { int a; char b[] __attribute__((aligned (2 * sizeof (int)))); };
+struct T { int a; struct S b; };
+union U { int a; struct S b; };
+struct V { int a; union U b; };
+
+void
+foo (struct S *s, struct T *t, union U *u, struct V *v)
+{
+  __builtin_clear_padding (s); /* { dg-error "flexible array member '(S::)?b' does not have well defined padding bits for '__builtin_clear_padding'" } */
+  __builtin_clear_padding (t); /* { dg-error "flexible array member '(S::)?b' does not have well defined padding bits for '__builtin_clear_padding'" } */
+  __builtin_clear_padding (u); /* { dg-error "flexible array member '(S::)?b' does not have well defined padding bits for '__builtin_clear_padding'" } */
+  __builtin_clear_padding (v); /* { dg-error "flexible array member '(S::)?b' does not have well defined padding bits for '__builtin_clear_padding'" } */
+}
diff --git a/gcc/testsuite/c-c++-common/builtin-clear-padding-3.c b/gcc/testsuite/c-c++-common/builtin-clear-padding-3.c
new file mode 100644 (file)
index 0000000..d16cc6a
--- /dev/null
@@ -0,0 +1,15 @@
+/* PR middle-end/97943 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+union U { int a; char b[] __attribute__((aligned (2 * sizeof (int)))); };      /* { dg-error "flexible array member in union" } */
+struct V { int a; union U b; };
+struct W { int a; union U b; int c; };
+
+void
+foo (union U *u, struct V *v, struct W *w)
+{
+  __builtin_clear_padding (u);
+  __builtin_clear_padding (v);
+  __builtin_clear_padding (w);
+}
diff --git a/gcc/testsuite/g++.dg/ext/builtin-clear-padding-1.C b/gcc/testsuite/g++.dg/ext/builtin-clear-padding-1.C
new file mode 100644 (file)
index 0000000..d188186
--- /dev/null
@@ -0,0 +1,15 @@
+// PR middle-end/97943
+// { dg-do compile }
+// { dg-options "" }
+
+struct S { int a; char b[] __attribute__((aligned (2 * sizeof (int)))); }; // { dg-error "flexible array member 'S::b' not at end of 'struct \[TV]'" }
+struct T { int a; struct S b; int c; };        // { dg-message "next member 'int T::c' declared here|in the definition of 'struct T'" }
+union U { int a; struct S b; };
+struct V { int a; union U b; int : 15; int c; };       // { dg-message "next member 'int V::c' declared here|in the definition of 'struct V'" }
+
+void
+foo (struct T *t, struct V *v)
+{
+  __builtin_clear_padding (t); // { dg-error "flexible array member 'S::b' does not have well defined padding bits for '__builtin_clear_padding'" }
+  __builtin_clear_padding (v); // { dg-error "flexible array member 'S::b' does not have well defined padding bits for '__builtin_clear_padding'" }
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-clear-padding-2.c b/gcc/testsuite/gcc.dg/builtin-clear-padding-2.c
new file mode 100644 (file)
index 0000000..641d47d
--- /dev/null
@@ -0,0 +1,15 @@
+/* PR middle-end/97943 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct S { int a; char b[] __attribute__((aligned (2 * sizeof (int)))); };
+struct T { int a; struct S b; int c; };
+union U { int a; struct S b; };
+struct V { int a; union U b; int : 15; int c; };
+
+void
+foo (struct T *t, struct V *v)
+{
+  __builtin_clear_padding (t); /* { dg-error "flexible array member 'b' does not have well defined padding bits for '__builtin_clear_padding'" } */
+  __builtin_clear_padding (v); /* { dg-error "flexible array member 'b' does not have well defined padding bits for '__builtin_clear_padding'" } */
+}