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; }