Hi Richard,
here is another version. This now just ignores the size for all trailing arrays which I think is the right thing to do. It also modifies the lto hashing which also seems to work (but needs more testing and I haven't added tests to the patch yet). I also added back the missing comparison for the field offset. Instead of checking for flexible arrays members, for the exceptions I now simply use RECORD_OR_UNION_TYPE_P. The alternative would be to add the bit, but this would then be for any nested trailing array - not FAM. But I am not entirely sure adding the bit is worth it, as checking for structures seems to be good enough - maybe for "verify_type" we could then spend more time and check recursively for a trailing array. Before I continue with this, what do you think? Comments and tests still need some improvements. Martin Fix type compatibility for types with flexible array member [PR113688,PR114014,PR117724] verify_type checks the compatibility of TYPE_CANONICAL using gimple_canonical_types_compatible_p. But it is stricter than what the C standard requires and therefor inconsistent with how TYPE_CANONICAL is set in the C FE. Here, the logic is changed to ignore the array size when one is the last element of a structure or union. To not get errors because of an inconsistent number of members, zero-sized arrays are not ignored anymore when checking the fields of a struct (which is stricter than what was done before). Finally, exceptions are added that allow the TYPE_MODE of a type with an array as last member to differ from another compatible type. PR c/113688 PR c/114014 PR c/117724 gcc/ChangeLog: * tree.cc (gimple_canonical_types_compatible_p): Revise logic for types with array as last member. (verify_type): Add exceptions. gcc/lto/ChangeLog: * lto-common.cc (hash_canonical_type): Add exceptions. gcc/testsuite/ChangeLog: * gcc.dg/pr113688.c: New test. * gcc.dg/pr114014.c: New test. * gcc.dg/pr117724.c: New test. diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc index 86a309f92b4..f65a9d1c7b6 100644 --- a/gcc/lto/lto-common.cc +++ b/gcc/lto/lto-common.cc @@ -254,7 +254,8 @@ hash_canonical_type (tree type) checked. */ code = tree_code_for_canonical_type_merging (TREE_CODE (type)); hstate.add_int (code); - hstate.add_int (TYPE_MODE (type)); + if (!RECORD_OR_UNION_TYPE_P (type)) + hstate.add_int (TYPE_MODE (type)); /* Incorporate common features of numerical types. */ if (INTEGRAL_TYPE_P (type) @@ -332,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..ab783f4f85d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr114014.c @@ -0,0 +1,14 @@ +/* PR c/114014 + * { dg-do compile } + * { dg-options "-std=c23 -g" } */ + +struct r { + int a; + char b[]; +}; +struct r { + int a; + char b[0]; +}; /* { dg-error "redefinition" } */ + + 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 125f38b1cfa..30e3b4531a1 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -13907,8 +13907,12 @@ gimple_canonical_types_compatible_p (const_tree t1, const_tree t2, || TREE_CODE (t1) == NULLPTR_TYPE) return true; - /* Can't be the same type if they have different mode. */ - if (TYPE_MODE (t1) != TYPE_MODE (t2)) + /* Can't be compatible types if they have different mode. We allow + mismatching modes for structures or unions because they could end + with flexible array member. */ + if (!RECORD_OR_UNION_TYPE_P (t1) + && !RECORD_OR_UNION_TYPE_P (t2) + && (TYPE_MODE (t1) != TYPE_MODE (t2))) return false; /* Non-aggregate types can be handled cheaply. */ @@ -13959,7 +13963,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) @@ -14053,23 +14057,35 @@ 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. */ - while (f1 && (TREE_CODE (f1) != FIELD_DECL - || (DECL_SIZE (f1) - && integer_zerop (DECL_SIZE (f1))))) + /* Skip non-fields. We used to skip zero-sized fields, but not + allow them only at the end. */ + while (f1 && (TREE_CODE (f1) != FIELD_DECL)) f1 = TREE_CHAIN (f1); - while (f2 && (TREE_CODE (f2) != FIELD_DECL - || (DECL_SIZE (f2) - && integer_zerop (DECL_SIZE (f2))))) + while (f2 && (TREE_CODE (f2) != FIELD_DECL)) f2 = TREE_CHAIN (f2); if (!f1 || !f2) break; + + tree t1 = TREE_TYPE (f1); + tree t2 = TREE_TYPE (f2); + + /* Special case for array members at the end. */ + if (TREE_CHAIN (f1) == NULL_TREE + && TREE_CHAIN (f2) == NULL_TREE + && TREE_CODE (t1) == ARRAY_TYPE + && TREE_CODE (t2) == ARRAY_TYPE + && TYPE_REVERSE_STORAGE_ORDER (t1) == TYPE_REVERSE_STORAGE_ORDER (t2) + && TYPE_NONALIASED_COMPONENT (t1) == TYPE_NONALIASED_COMPONENT (t2) + && gimple_compare_field_offset (f1, f2) + && gimple_canonical_types_compatible_p + (TREE_TYPE (t1), TREE_TYPE (t2), + trust_type_canonical)) + ; /* The fields must have the same name, offset and type. */ - if (DECL_NONADDRESSABLE_P (f1) != DECL_NONADDRESSABLE_P (f2) + else 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; } @@ -14213,6 +14229,10 @@ verify_type (const_tree t) } if (COMPLETE_TYPE_P (t) && TYPE_CANONICAL (t) + /* We allow a mismatch for structure or union because of + flexible array members. */ + && !RECORD_OR_UNION_TYPE_P (t) + && !RECORD_OR_UNION_TYPE_P (TYPE_CANONICAL (t)) && TYPE_MODE (t) != TYPE_MODE (TYPE_CANONICAL (t))) { error ("%<TYPE_MODE%> of %<TYPE_CANONICAL%> is not compatible");