If one mixes a struct with FAM and one with zero size at the end, then TBAA considers them incompatible for aliasing purposes when using LTO. One could decide that those are incompatible types, but this would break code that mixes both, e.g. during a transition time to standard FAMs. Also affects old versions of GCC. https://godbolt.org/z/xodMK9sqE 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; }
[] and [0] are not the same. Note the C and C++ frontends encode [0] (or did encode) differently. See tree.cc:gimple_canonical_types_compatible_p I agree that from a QOI perspective [] and [0] should be compatible. Note [0] can have many "equivalent" domains, [3:2], [0:-1], [1:0], etc. but the current code has /* Array types are the same if the element types are the same and the number of elements are the same. */ ... /* The minimum/maximum values have to be the same. */ if ((min1 == min2 || (min1 && min2 which is somewhat contradicting comments. See also layout_type which says, when computing TYPE_SIZE of an array: /* ??? We have no way to distinguish a null-sized array from an array spanning the whole sizetype range, so we arbitrarily decide that [0, -1] is the only valid representation. */ if (integer_zerop (length) && TREE_OVERFLOW (length) && integer_zerop (lb)) length = size_zero_node; revealing that the constraints on TYPE_DOMAIN are not very well specified.
Also note that people might find it reasonable to access struct { int n; int a[4]; } a = { 4, }; via struct X { int n; int a[] } *p; The fortran frontend goes some lengths to make this work for array descriptors statically allocated by accessing the storage always via the type with the flexible array member. But that also relies on GCC middle-end semantics, accessing an automatic variable with a declared type via a not compatible type, thus changing its effective type. The only valid C way is to resort to dynamic (stack) allocation.
The master branch has been updated by Martin Uecker <uecker@gcc.gnu.org>: https://gcc.gnu.org/g:d46c7f313b5a30ee04080f249e31e12987d50aa2 commit r15-6170-gd46c7f313b5a30ee04080f249e31e12987d50aa2 Author: Martin Uecker <uecker@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.
Fixed on trunk.
The releases/gcc-14 branch has been updated by Martin Uecker <uecker@gcc.gnu.org>: https://gcc.gnu.org/g:73549be0a3c819b2ab78e0e973f5b4d41b9f4a2d commit r14-11478-g73549be0a3c819b2ab78e0e973f5b4d41b9f4a2d Author: Martin Uecker <uecker@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. (cherry picked from commit d46c7f313b5a30ee04080f249e31e12987d50aa2)
The releases/gcc-14 branch has been updated by Eric Botcazou <ebotcazou@gcc.gnu.org>: https://gcc.gnu.org/g:5457388f58262bee41ae1d744ff6f3da34119e2d commit r14-11611-g5457388f58262bee41ae1d744ff6f3da34119e2d Author: Eric Botcazou <ebotcazou@adacore.com> Date: Mon Apr 14 23:35:43 2025 +0200 Revert very recent backport of changes to the type system The backport of the change made for PR c/113688 onto the 14 branch a couple of weeks ago has seriously broken the LTO compiler for the Ada language on the 14 branch, because it changes the GCC type system for the sake of C in a way that is not compatible with simple discriminated types in Ada. To be more precise, useless_type_conversion_p now returns true for some (view-) conversions that are needed by the rest of the compiler. gcc/ PR lto/119792 Revert Backported from master: 2024-12-12 Martin Uecker <uecker@tugraz.at> PR c/113688 PR c/114014 PR c/114713 PR c/117724 * tree.cc (gimple_canonical_types_compatible_p): Add exception. (verify_type): Add exception. gcc/lto/ PR lto/119792 Revert Backported from master: 2024-12-12 Martin Uecker <uecker@tugraz.at> * lto-common.cc (hash_canonical_type): Add exception. gcc/testsuite/ * gcc.dg/pr113688.c: Delete. * gcc.dg/pr114014.c: Likewise. * gcc.dg/pr114713.c: Likewise. * gcc.dg/pr117724.c: Likewise