Consider: typedef union { char c; int i; } union_t; struct { struct { int a; long b; } x; int y; } t = { { 0 }, 1 }; struct { struct { union_t a; long b; } x; int y; } u = { { 0 }, 1 }; As expected, I do not get a warning for the first initialization. But with Debian's GCC 6.3.0 20170415 (and previous versions GCC 4.9 and 5), I get a warning for the second one: tst.c:5:56: warning: missing braces around initializer [-Wmissing-braces] struct { struct { union_t a; long b; } x; int y; } u = { { 0 }, 1 }; ^ tst.c:5:56: note: (near initialization for ‘u’) (pthread_rwlock_t from <pthread.h> is such a union type on my machine, so that there's the same problem with this.) It seems that not everything was fixed in PR 53119.
Confirmed, and the placement of the fixit hint looks weird, too: $ /usr/local/bin/gcc -c -Wmissing-braces 80454.c 80454.c:5:56: warning: missing braces around initializer [-Wmissing-braces] struct { struct { union_t a; long b; } x; int y; } u = { { 0 }, 1 }; ^ { } $
Is this really a bug? In the second case we have a union in two nested structs, in the first case just two nested structs. clang also warns: w.c:3:60: warning: suggest braces around initialization of subobject [-Wmissing-braces] struct { struct { union_t a; long b; } x; int y; } u = { { 0 }, 1 }; ^ {} But yes, the fix-it hints looks strange.
The bug is that universal zero initializers are warned about when they are inside of some other initializer, even though we correctly stopped doing that when they appear on their own. In the following example GCC shouldn't warn for the initialization of s2, like it already doesn't for s1 (Clang warns for both, but that's probably a bug in Clang). struct S1 { struct S1i { int i; } s1i; int i; }; #define S1_INIT {0} struct S1 s1 = S1_INIT; struct S2 { struct S1 s1; int i; } s2 = {S1_INIT, 0};
cc-ing diagnostics maintainers
clang no longer warns with their C front-end.
To fix this, we have to somehow propagate the flag constructor_zeroinit up in pop_init_level.