The second part now only contains the changes for array size.
I added back a special case for this instead of having the 'ignore_size' flag (which I would nevertheless assume might be needed in the future when matching pointer types). In this version, I added an exception to the special case to ignore the case were both are zero-sized arrays, because this seems to be the only case were the new code would otherwise be stricter than the old code. I also replaced/fixed one test where I accidentally included a similar test for another closely related bug involving VLA types. Bootstrapped and regression tested on x86_64. 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. --- 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 | 38 ++++++++++++++++++++++++++------- 6 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr113688.c create mode 100644 gcc/testsuite/gcc.dg/pr114014.c create mode 100644 gcc/testsuite/gcc.dg/pr114713.c create mode 100644 gcc/testsuite/gcc.dg/pr117724.c diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc index 94050209912..f65a9d1c7b6 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 00000000000..8dee8c86f1b --- /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 00000000000..1531ffab1b7 --- /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 00000000000..1f0ad39c433 --- /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 00000000000..d631daeb644 --- /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 1391af6bd4c..9803d16805c 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -13838,7 +13838,6 @@ type_with_interoperable_signedness (const_tree type) that have TYPE_CANONICAL defined and assume them equivalent. This is useful only for LTO because only in these cases TYPE_CANONICAL equivalence correspond to one defined by gimple_canonical_types_compatible_p. */ - bool gimple_canonical_types_compatible_p (const_tree t1, const_tree t2, bool trust_type_canonical) @@ -13969,7 +13968,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 +14062,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; } -- 2.39.5