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

commit r15-6170-gd46c7f313b5a30ee04080f249e31e12987d50aa2
Author: Martin Uecker <uec...@tugraz.at>
Date:   Sat Nov 23 08:04:05 2024 +0100

    Fix type compatibility for types with flexible array member 2/2 
[PR113688,PR114713,PR117724]
    
    For checking or computing TYPE_CANONICAL, ignore the array size when it is
    the last element of a structure or union.  To not get errors because of
    an inconsistent number of members, zero-sized arrays which are the last
    element are not ignored anymore when checking the fields of a struct.
    
            PR c/113688
            PR c/114014
            PR c/114713
            PR c/117724
    
    gcc/ChangeLog:
            * tree.cc (gimple_canonical_types_compatible_p): Add exception.
    
    gcc/lto/ChangeLog:
            * lto-common.cc (hash_canonical_type): Add exception.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/pr113688.c: New test.
            * gcc.dg/pr114014.c: New test.
            * gcc.dg/pr114713.c: New test.
            * gcc.dg/pr117724.c: New test.

Diff:
---
 gcc/lto/lto-common.cc           |  6 +++++-
 gcc/testsuite/gcc.dg/pr113688.c |  8 ++++++++
 gcc/testsuite/gcc.dg/pr114014.c | 14 ++++++++++++++
 gcc/testsuite/gcc.dg/pr114713.c | 35 +++++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr117724.c | 16 ++++++++++++++++
 gcc/tree.cc                     | 37 ++++++++++++++++++++++++++++++-------
 6 files changed, 108 insertions(+), 8 deletions(-)

diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc
index 940502099128..f65a9d1c7b6f 100644
--- a/gcc/lto/lto-common.cc
+++ b/gcc/lto/lto-common.cc
@@ -333,7 +333,11 @@ hash_canonical_type (tree type)
            && (! DECL_SIZE (f)
                || ! integer_zerop (DECL_SIZE (f))))
          {
-           iterative_hash_canonical_type (TREE_TYPE (f), hstate);
+           tree t = TREE_TYPE (f);
+           if (!TREE_CHAIN (f)
+               && TREE_CODE (t) == ARRAY_TYPE)
+             t = TREE_TYPE  (t);
+           iterative_hash_canonical_type (t, hstate);
            nf++;
          }
 
diff --git a/gcc/testsuite/gcc.dg/pr113688.c b/gcc/testsuite/gcc.dg/pr113688.c
new file mode 100644
index 000000000000..8dee8c86f1bf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr113688.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-g" } */
+
+struct S{int x,y[1];}*a;
+int main(void){
+       struct S{int x,y[];};
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr114014.c b/gcc/testsuite/gcc.dg/pr114014.c
new file mode 100644
index 000000000000..1531ffab1b75
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114014.c
@@ -0,0 +1,14 @@
+/* PR c/114014
+ * { dg-do compile }
+ * { dg-options "-std=gnu23 -g" } */
+
+struct r {
+  int a;
+  char b[];
+};
+struct r {
+  int a;
+  char b[0];
+};
+
+
diff --git a/gcc/testsuite/gcc.dg/pr114713.c b/gcc/testsuite/gcc.dg/pr114713.c
new file mode 100644
index 000000000000..1f0ad39c433c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114713.c
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+/* { dg-require-effective-target lto } */
+/* { dg-options "-flto -O2" } */
+
+struct foo { int x; char a[]; };
+
+void test_bar(void* b);
+
+__attribute__((noinline))
+int test_foo(struct foo* a, void* b)
+{
+        a->x = 1;
+        test_bar(b);
+        return a->x;
+}
+
+int main()
+{
+        struct foo y;
+
+        if (2 != test_foo(&y, &y))
+                __builtin_abort();
+
+        return 0;
+}
+
+// TU2
+struct foo { int x; char a[0]; };
+
+void test_bar(void* b)
+{
+        struct foo *p = b;
+        p->x = 2;
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr117724.c b/gcc/testsuite/gcc.dg/pr117724.c
new file mode 100644
index 000000000000..d631daeb644d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr117724.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-g" } */
+
+struct {
+  unsigned long len;
+  unsigned long size;
+  char data[];
+};                     /* { dg-warning "unnamed struct" } */
+struct {
+  struct {
+    unsigned long len;
+    unsigned long size;
+    char data[6];
+  };
+};                     /* { dg-warning "unnamed struct" } */
+
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 1391af6bd4c3..322451139162 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -13969,7 +13969,7 @@ gimple_canonical_types_compatible_p (const_tree t1, 
const_tree t2,
     {
     case ARRAY_TYPE:
       /* Array types are the same if the element types are the same and
-        the number of elements are the same.  */
+        minimum and maximum index are the same.  */
       if (!gimple_canonical_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2),
                                                trust_type_canonical)
          || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2)
@@ -14063,23 +14063,46 @@ gimple_canonical_types_compatible_p (const_tree t1, 
const_tree t2,
             f1 || f2;
             f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
          {
-           /* Skip non-fields and zero-sized fields.  */
+           /* Skip non-fields and zero-sized fields, except zero-sized
+              arrays at the end.  */
            while (f1 && (TREE_CODE (f1) != FIELD_DECL
                          || (DECL_SIZE (f1)
-                             && integer_zerop (DECL_SIZE (f1)))))
+                             && integer_zerop (DECL_SIZE (f1))
+                             && (TREE_CHAIN (f1)
+                                 || TREE_CODE (TREE_TYPE (f1))
+                                    != ARRAY_TYPE))))
              f1 = TREE_CHAIN (f1);
            while (f2 && (TREE_CODE (f2) != FIELD_DECL
                          || (DECL_SIZE (f2)
-                             && integer_zerop (DECL_SIZE (f2)))))
+                             && integer_zerop (DECL_SIZE (f2))
+                             && (TREE_CHAIN (f2)
+                                 || TREE_CODE (TREE_TYPE (f2))
+                                    != ARRAY_TYPE))))
              f2 = TREE_CHAIN (f2);
            if (!f1 || !f2)
              break;
-           /* The fields must have the same name, offset and type.  */
+
+           tree t1 = TREE_TYPE (f1);
+           tree t2 = TREE_TYPE (f2);
+
+           /* If the last element are arrays, we only compare the element
+              types.  */
+           if (TREE_CHAIN (f1) == NULL_TREE && TREE_CODE (t1) == ARRAY_TYPE
+               && TREE_CHAIN (f2) == NULL_TREE && TREE_CODE (t2) == ARRAY_TYPE)
+             {
+               /* If both arrays have zero size, this is a match.  */
+               if (DECL_SIZE (f1) && integer_zerop (DECL_SIZE (f1))
+                   && DECL_SIZE (f2) && integer_zerop (DECL_SIZE (f2)))
+                 return true;
+
+               t1 = TREE_TYPE (t1);
+               t2 = TREE_TYPE (t2);
+             }
+
            if (DECL_NONADDRESSABLE_P (f1) != DECL_NONADDRESSABLE_P (f2)
                || !gimple_compare_field_offset (f1, f2)
                || !gimple_canonical_types_compatible_p
-                     (TREE_TYPE (f1), TREE_TYPE (f2),
-                      trust_type_canonical))
+                     (t1, t2, trust_type_canonical))
              return false;
          }

Reply via email to