| /* PR 101832: |
| GCC extension accepts the case when a struct with a C99 flexible array |
| member is embedded into another struct (possibly recursively). |
| __builtin_object_size will treat such struct as flexible size. |
| However, when a structure with non-C99 flexible array member, i.e, trailing |
| [0], [1], or [4], is embedded into anther struct, the stucture will not |
| be treated as flexible size. */ |
| /* { dg-do run } */ |
| /* { dg-options "-O2" } */ |
| |
| #include "builtin-object-size-common.h" |
| |
| #define expect(p, _v) do { \ |
| size_t v = _v; \ |
| if (p == v) \ |
| __builtin_printf ("ok: %s == %zd\n", #p, p); \ |
| else {\ |
| __builtin_printf ("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ |
| FAIL (); \ |
| } \ |
| } while (0); |
| |
| |
| struct A { |
| int n; |
| char data[]; |
| }; |
| |
| struct B { |
| int m; |
| struct A a; |
| }; |
| |
| struct C { |
| int q; |
| struct B b; |
| }; |
| |
| struct A0 { |
| int n; |
| char data[0]; |
| }; |
| |
| struct B0 { |
| int m; |
| struct A0 a; |
| }; |
| |
| struct C0 { |
| int q; |
| struct B0 b; |
| }; |
| |
| struct A1 { |
| int n; |
| char data[1]; |
| }; |
| |
| struct B1 { |
| int m; |
| struct A1 a; |
| }; |
| |
| struct C1 { |
| int q; |
| struct B1 b; |
| }; |
| |
| struct An { |
| int n; |
| char data[8]; |
| }; |
| |
| struct Bn { |
| int m; |
| struct An a; |
| }; |
| |
| struct Cn { |
| int q; |
| struct Bn b; |
| }; |
| |
| volatile void *magic1, *magic2; |
| |
| int main (int argc, char *argv[]) |
| { |
| struct B *outer; |
| struct C *outest; |
| |
| /* Make sure optimization can't find some other object size. */ |
| outer = (void *)magic1; |
| outest = (void *)magic2; |
| |
| expect (__builtin_object_size (&outer->a, 1), -1); |
| expect (__builtin_object_size (&outest->b, 1), -1); |
| expect (__builtin_object_size (&outest->b.a, 1), -1); |
| |
| struct B0 *outer0; |
| struct C0 *outest0; |
| |
| /* Make sure optimization can't find some other object size. */ |
| outer0 = (void *)magic1; |
| outest0 = (void *)magic2; |
| |
| expect (__builtin_object_size (&outer0->a, 1), sizeof (outer0->a)); |
| expect (__builtin_object_size (&outest0->b, 1), sizeof (outest0->b)); |
| expect (__builtin_object_size (&outest0->b.a, 1), sizeof (outest0->b.a)); |
| |
| struct B1 *outer1; |
| struct C1 *outest1; |
| |
| /* Make sure optimization can't find some other object size. */ |
| outer1 = (void *)magic1; |
| outest1 = (void *)magic2; |
| |
| expect (__builtin_object_size (&outer1->a, 1), sizeof (outer1->a)); |
| expect (__builtin_object_size (&outest1->b, 1), sizeof (outest1->b)); |
| expect (__builtin_object_size (&outest1->b.a, 1), sizeof (outest1->b.a)); |
| |
| struct Bn *outern; |
| struct Cn *outestn; |
| |
| /* Make sure optimization can't find some other object size. */ |
| outern = (void *)magic1; |
| outestn = (void *)magic2; |
| |
| expect (__builtin_object_size (&outern->a, 1), sizeof (outern->a)); |
| expect (__builtin_object_size (&outestn->b, 1), sizeof (outestn->b)); |
| expect (__builtin_object_size (&outestn->b.a, 1), sizeof (outestn->b.a)); |
| |
| DONE (); |
| return 0; |
| } |