aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Uecker <uecker@tugraz.at>2024-11-23 08:04:05 +0100
committerMartin Uecker <uecker@gcc.gnu.org>2024-12-12 13:26:27 +0100
commitd46c7f313b5a30ee04080f249e31e12987d50aa2 (patch)
tree0462ab20decf4595e26f037e03d06643e24e5cbf /gcc
parent1f48225a0ddfaf74a229105343b22f3086c4b8cb (diff)
downloadgcc-d46c7f313b5a30ee04080f249e31e12987d50aa2.zip
gcc-d46c7f313b5a30ee04080f249e31e12987d50aa2.tar.gz
gcc-d46c7f313b5a30ee04080f249e31e12987d50aa2.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/lto/lto-common.cc6
-rw-r--r--gcc/testsuite/gcc.dg/pr113688.c8
-rw-r--r--gcc/testsuite/gcc.dg/pr114014.c14
-rw-r--r--gcc/testsuite/gcc.dg/pr114713.c35
-rw-r--r--gcc/testsuite/gcc.dg/pr117724.c16
-rw-r--r--gcc/tree.cc37
6 files changed, 108 insertions, 8 deletions
diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc
index 940502099..f65a9d1 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 0000000..8dee8c8
--- /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 0000000..1531ffa
--- /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 0000000..1f0ad39
--- /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 0000000..d631dae
--- /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 1391af6..3224511 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;
}