Polite ping on this On Sat, Mar 7, 2026, 14:33 S. Alex Wilson <[email protected]> wrote:
> Hello! First contribution. Full disclosure, it's AI assisted with > human-in-the-loop. The tests and documentation are fully human generated. > Based on the initial work done by Peter Frost here > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39589#c14 - out-of-order and > last-element-missing designated initializers needed particular handling. > Bootstrapped and tested with 'check' on an '--enable-languages=all' build. > > Can someone help review and help commit, please? > The PR is unassigned, and will need closing if the commit goes through. > > Thank you! > Alex > > ======================================================================== > > This patch implements the feature request at PR c/39589: > > -Wmissing-field-initializers=2 added to enable warnings when field > initializers are missing when designated initializers are in use > in C. Chaining designators together like ={.a.b.c = 5} still > ignores missing elements due to the additional complexity > required to implement. > > -Wmissing-field-initializers is the same as the newly-added > -Wmissing-field-initializers=1 which is the existing behavior. > > 2026-03-07 S. Alex Wilson <[email protected]> > > gcc/c/ChangeLog: > PR c/39589 > * c-typeck.cc (pop_init_level): Warn when designated field > initializers are used when option is set. > > gcc/cp/ChangeLog: > PR c/39589 > * typeck2.cc (process_init_constructor_record) Use updated > warning variable. > > gcc/c-family/ChangeLog: > PR c/39589 > * c.opt: Variable option for Wmissing-field-initializers. > > gcc/doc/ChangeLog: > PR c/39589 > * invoke.texi: Update documentation for new > Wmissing-field-initializers=2 option, note that no number is > same as =1 is same as old behavior. > > gcc/testsuite/ChangeLog: > PR c/39589 > * gcc.dg/Wmissing-field-initializers-6.c: Test suite to enforce > behaviors for =2. > * g++.dg/warn/Wmissing-field-initializers-4.C: Enforce no change > for =2 for test cases in Wmissing-field-initializers-1.C. > * g++.dg/warn/Wmissing-field-initializers-5.C: Enforce no change > for =2 for test cases in Wmissing-field-initializers-2.C. > * g++.dg/warn/Wmissing-field-initializers-6.C: Enforce no change > for =2 for test cases in Wmissing-field-initializers-3.C. > > Signed-off-by: S. Alex Wilson <[email protected]> > --- > gcc/c-family/c.opt | 6 +- > gcc/c/c-typeck.cc | 121 ++++- > gcc/cp/typeck2.cc | 4 +- > gcc/doc/invoke.texi | 71 ++- > .../warn/Wmissing-field-initializers-4.C | 34 ++ > .../warn/Wmissing-field-initializers-5.C | 47 ++ > .../warn/Wmissing-field-initializers-6.C | 50 ++ > .../gcc.dg/Wmissing-field-initializers-6.c | 433 ++++++++++++++++++ > 8 files changed, 731 insertions(+), 35 deletions(-) > create mode 100644 > gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-4.C > create mode 100644 > gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-5.C > create mode 100644 > gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-6.C > create mode 100644 gcc/testsuite/gcc.dg/Wmissing-field-initializers-6.c > > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt > index 3d96a73ecee..832976f2571 100644 > --- a/gcc/c-family/c.opt > +++ b/gcc/c-family/c.opt > @@ -1058,7 +1058,11 @@ C ObjC C++ ObjC++ Var(warn_missing_declarations) > Warning > Warn about global functions without previous declarations. > > Wmissing-field-initializers > -C ObjC C++ ObjC++ Var(warn_missing_field_initializers) Warning > EnabledBy(Wextra) > +C ObjC C++ ObjC++ Warning Alias(Wmissing-field-initializers=, 1, 0) > +Warn about missing fields in struct initializers. > + > +Wmissing-field-initializers= > +C ObjC C++ ObjC++ Joined RejectNegative UInteger IntegerRange(0, 2) > Var(warn_missing_field_initializers) Warning LangEnabledBy(C ObjC C++ > ObjC++,Wextra,1,0) > Warn about missing fields in struct initializers. > > Wmissing-format-attribute > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc > index 051773a0cd4..e6844a448ff 100644 > --- a/gcc/c/c-typeck.cc > +++ b/gcc/c/c-typeck.cc > @@ -10319,6 +10319,20 @@ static tree constructor_decl; > /* Nonzero if there were any member designators in this initializer. */ > static int constructor_designated; > > +/* Nonzero if a member designator was used at THIS nesting level. > + Unlike constructor_designated, which is inherited from the enclosing > + level via push_init_level (constructor_designated = p->designated), > + this flag is reset to 0 at each push_init_level and only set to 1 > + when set_designator fires at the current level. > + > + This matters for zeroinit: both ".child = { 0 }" (bare zeroinit > + inside a designated parent) and "{ .a = 0 }" (explicit designator > + with a zero value) have constructor_zeroinit == 1 and > + constructor_designated == 1. But only the latter should warn about > + missing fields at level 2+; the former is an intentional {0} idiom. > + constructor_explicitly_designated distinguishes the two cases. */ > +static int constructor_explicitly_designated; > + > /* Nesting depth of designator list. */ > static int designator_depth; > > @@ -10358,6 +10372,8 @@ struct constructor_stack > char outer; > char incremental; > char designated; > + char explicitly_designated; > + char had_chained_push; > bool zero_padding_bits; > bool braced_scalar; > int designator_depth; > @@ -10398,6 +10414,7 @@ struct initializer_stack > char require_constant_elements; > char require_constexpr_value; > char designated; > + char explicitly_designated; > rich_location *missing_brace_richloc; > }; > > @@ -10426,10 +10443,12 @@ start_init (tree decl, tree asmspec_tree > ATTRIBUTE_UNUSED, > p->next = initializer_stack; > p->missing_brace_richloc = richloc; > p->designated = constructor_designated; > + p->explicitly_designated = constructor_explicitly_designated; > initializer_stack = p; > > constructor_decl = decl; > constructor_designated = 0; > + constructor_explicitly_designated = 0; > > require_constant_value = init_require_constant; > require_constexpr_value = init_require_constexpr; > @@ -10485,6 +10504,7 @@ finish_init (void) > require_constexpr_value = p->require_constexpr_value; > constructor_stack = p->constructor_stack; > constructor_designated = p->designated; > + constructor_explicitly_designated = p->explicitly_designated; > constructor_range_stack = p->constructor_range_stack; > constructor_elements = p->elements; > spelling = p->spelling; > @@ -10531,10 +10551,12 @@ really_start_incremental_init (tree type) > p->replacement_value.original_code = ERROR_MARK; > p->replacement_value.original_type = NULL; > p->implicit = 0; > + p->had_chained_push = 0; > p->range_stack = 0; > p->outer = 0; > p->incremental = constructor_incremental; > p->designated = constructor_designated; > + p->explicitly_designated = constructor_explicitly_designated; > p->zero_padding_bits = constructor_zero_padding_bits; > p->braced_scalar = constructor_braced_scalar; > p->designator_depth = designator_depth; > @@ -10550,6 +10572,7 @@ really_start_incremental_init (tree type) > constructor_type = type; > constructor_incremental = 1; > constructor_designated = 0; > + constructor_explicitly_designated = 0; > constructor_zero_padding_bits = false; > constructor_zeroinit = 1; > constructor_braced_scalar = false; > @@ -10666,6 +10689,12 @@ push_init_level (location_t loc, int implicit, > value = find_init_member (constructor_index, braced_init_obstack); > } > > + /* If this level is entered via a chained designator (implicit==2), > + mark the parent frame so that it is also exempt from missing-field > + warnings. The parent frame is the current top of > constructor_stack. */ > + if (implicit == 2 && constructor_stack) > + constructor_stack->had_chained_push = 1; > + > p = XNEW (struct constructor_stack); > p->type = constructor_type; > p->fields = constructor_fields; > @@ -10685,9 +10714,11 @@ push_init_level (location_t loc, int implicit, > p->replacement_value.original_code = ERROR_MARK; > p->replacement_value.original_type = NULL; > p->implicit = implicit; > + p->had_chained_push = 0; > p->outer = 0; > p->incremental = constructor_incremental; > p->designated = constructor_designated; > + p->explicitly_designated = constructor_explicitly_designated; > p->zero_padding_bits = constructor_zero_padding_bits; > p->braced_scalar = constructor_braced_scalar; > p->designator_depth = designator_depth; > @@ -10704,6 +10735,9 @@ push_init_level (location_t loc, int implicit, > /* If the upper initializer is designated, then mark this as > designated too to prevent bogus warnings. */ > constructor_designated = p->designated; > + /* Reset explicitly_designated: no designators have been used at this > + new level yet. It will be set to 1 if/when set_designator fires > here. */ > + constructor_explicitly_designated = 0; > /* If the upper initializer has padding bits zeroed, that includes > all nested initializers as well. */ > constructor_zero_padding_bits = p->zero_padding_bits; > @@ -10952,27 +10986,76 @@ pop_init_level (location_t loc, int implicit, > if (warn_missing_field_initializers > && constructor_type > && TREE_CODE (constructor_type) == RECORD_TYPE > - && constructor_unfilled_fields) > - { > - /* Do not warn for flexible array members or zero-length arrays. > */ > - while (constructor_unfilled_fields > - && (!DECL_SIZE (constructor_unfilled_fields) > - || integer_zerop (DECL_SIZE > (constructor_unfilled_fields)))) > - constructor_unfilled_fields = DECL_CHAIN > (constructor_unfilled_fields); > + /* Don't warn for levels entered via chained designators like > + ".a.b = 1". */ > + && p->implicit != 2 > + && !p->had_chained_push > + /* Warn for {.outer = {.inner2 = 0}} (inner1 skipped), don't warn > for > + ={0}. */ > + && (!constructor_zeroinit > + || (constructor_explicitly_designated > + && warn_missing_field_initializers > 1))) > + { > + if (constructor_unfilled_fields) > + { > + /* Do not warn for flexible array members or zero-length > arrays. */ > + while (constructor_unfilled_fields > + && (!DECL_SIZE (constructor_unfilled_fields) > + || integer_zerop ( > + DECL_SIZE (constructor_unfilled_fields)))) > + constructor_unfilled_fields > + = DECL_CHAIN (constructor_unfilled_fields); > > - if (constructor_unfilled_fields > /* Do not warn if this level of the initializer uses member > - designators; it is likely to be deliberate. */ > - && !constructor_designated > - /* Do not warn about initializing with { 0 } or with { }. */ > - && !constructor_zeroinit) > + designators if -Wmissing-field-initializers <= 1; > + it is likely to be deliberate. */ > + if (constructor_unfilled_fields > + && (!constructor_designated > + || warn_missing_field_initializers > 1)) > + { > + if (warning_at (input_location, > + OPT_Wmissing_field_initializers_, > + "missing initializer for field %qD of %qT", > + constructor_unfilled_fields, > + constructor_type)) > + inform (DECL_SOURCE_LOCATION > (constructor_unfilled_fields), > + "%qD declared here", constructor_unfilled_fields); > + } > + } > + else if (constructor_designated && warn_missing_field_initializers > > 1) > { > - if (warning_at (input_location, > OPT_Wmissing_field_initializers, > - "missing initializer for field %qD of %qT", > - constructor_unfilled_fields, > - constructor_type)) > - inform (DECL_SOURCE_LOCATION (constructor_unfilled_fields), > - "%qD declared here", constructor_unfilled_fields); > + /* Handle out-of-order skipped designated initializers by > scanning > + all of the fields. The unfilled_fields is nullptr when the > + last field is missing when designated field initializers are > + used or when out-of-order designated initializers initialize > + all but one member. */ > + > + for (tree field = TYPE_FIELDS (constructor_type); > + field; field = DECL_CHAIN (field)) > + { > + bool field_initialized = false; > + for (unsigned int i = 0; > + i < vec_safe_length (constructor_elements); ++i) > + { > + if ((*constructor_elements)[i].index == field) > + { > + field_initialized = true; > + break; > + } > + } > + > + if (!field_initialized) > + { > + if (warning_at (input_location, > + OPT_Wmissing_field_initializers_, > + "missing initializer for field %qD of > %qT", > + field, > + constructor_type)) > + inform (DECL_SOURCE_LOCATION (field), > + "%qD declared here", field); > + break; > + } > + } > } > } > > @@ -11055,6 +11138,7 @@ pop_init_level (location_t loc, int implicit, > constructor_erroneous = p->erroneous; > constructor_incremental = p->incremental; > constructor_designated = p->designated; > + constructor_explicitly_designated = p->explicitly_designated; > constructor_zero_padding_bits = p->zero_padding_bits; > constructor_braced_scalar = p->braced_scalar; > designator_depth = p->designator_depth; > @@ -11110,6 +11194,7 @@ set_designator (location_t loc, bool array, > last_init_list_comma), > true, braced_init_obstack); > constructor_designated = 1; > + constructor_explicitly_designated = 1; > return false; > } > > diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc > index 664dd0990bf..7220bd33a80 100644 > --- a/gcc/cp/typeck2.cc > +++ b/gcc/cp/typeck2.cc > @@ -1948,7 +1948,7 @@ process_init_constructor_record (tree type, tree > init, int nested, int flags, > if ((complain & tf_warning) > && !cp_unevaluated_operand > && !EMPTY_CONSTRUCTOR_P (init)) > - warning (OPT_Wmissing_field_initializers, > + warning (OPT_Wmissing_field_initializers_, > "missing initializer for member %qD", field); > } > else > @@ -1979,7 +1979,7 @@ process_init_constructor_record (tree type, tree > init, int nested, int flags, > && !cp_unevaluated_operand > && !EMPTY_CONSTRUCTOR_P (init) > && !is_really_empty_class (fldtype, /*ignore_vptr*/false)) > - warning (OPT_Wmissing_field_initializers, > + warning (OPT_Wmissing_field_initializers_, > "missing initializer for member %qD", field); > > if (!zero_init_p (fldtype) || skipped < 0) > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 6440e7cd369..e5600ce3537 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -421,7 +421,8 @@ Objective-C and Objective-C++ Dialects}. > -Wlong-long -Wno-lto-type-mismatch -Wmain -Wmaybe-uninitialized > -Wmemset-elt-size -Wmemset-transposed-args > -Wmisleading-indentation -Wmissing-attributes -Wmissing-braces > --Wmissing-field-initializers -Wmissing-format-attribute > +-Wmissing-field-initializers -Wmissing-field-initializers=2 > +-Wmissing-format-attribute > -Wmissing-include-dirs -Wmissing-noreturn -Wmusttail-local-addr > -Wmaybe-musttail-local-addr -Wno-missing-profile > -Wno-multichar -Wmultistatement-macros -Wnonnull -Wnonnull-compare > @@ -10883,28 +10884,22 @@ non-prototype declarations; use > @option{-Wmissing-prototypes} to detect > missing prototypes. In C++, no warnings are issued for function > templates, > or for inline functions, or for functions in anonymous namespaces. > > -@opindex Wmissing-field-initializers > @opindex Wno-missing-field-initializers > +@opindex Wmissing-field-initializers > @opindex W > @opindex Wextra > @opindex Wno-extra > +@opindex Wmissing-field-initializers= > @item -Wmissing-field-initializers > -Warn if a structure's initializer has some fields missing. For > -example, the following code causes such a warning, because > -@code{x.h} is implicitly zero: > - > -@smallexample > -struct s @{ int f, g, h; @}; > -struct s x = @{ 3, 4 @}; > -@end smallexample > +@itemx -Wmissing-field-initializers=@var{n} > > -@c It's unclear if this behavior is desirable. See PR39589 and PR96868. > -In C this option does not warn about designated initializers, so the > -following modification does not trigger a warning: > +Warn if a structure's initializer has some fields missing. For example, > +the following code causes such a warning, because @code{x.h} > +is implicitly zero: > > @smallexample > struct s @{ int f, g, h; @}; > -struct s x = @{ .f = 3, .g = 4 @}; > +struct s x = @{ 3, 4 @}; > @end smallexample > > In C this option does not warn about the universal zero initializer > @@ -10923,9 +10918,57 @@ struct s @{ int f, g, h; @}; > s x = @{ @}; > @end smallexample > > +@table @gcctabopt > +@opindex Wmissing-field-initializers > +@opindex Wmissing-field-initializers=1 > +@item -Wmissing-field-initializers=1 > +@itemx -Wmissing-field-initializers > + > +@c It's unclear if this behavior is desirable. See PR96868. > +In C this option does not warn about designated initializers, so the > +following modification does not trigger a warning: > + > +@smallexample > +struct s @{ int f, g, h; @}; > +struct s x = @{ .f = 3, .g = 4 @}; > +@end smallexample > + > This warning is included in @option{-Wextra}. To get other > @option{-Wextra} > warnings without this one, use @option{-Wextra > -Wno-missing-field-initializers}. > > +@opindex Wmissing-field-initializers=2 > +@item -Wmissing-field-initializers=2 > + > +Like @option{-Wmissing-field-initializers=1}, but warns when an element is > +missing when designated initializers are used, so the following code now > +triggers a warning: > + > +@smallexample > +struct s @{ int f, g, h; @}; > +struct s x = @{ .f = 3, .g = 4 @}; > +@end smallexample > + > +Structures containing designated initializers that are chained together do > +not trigger warnings: > + > +@smallexample > +struct child @{ int f, g, h; @}; > +struct parent @{ struct child a; @}; > +/* missing '.a.g', does not warn. */ > +struct parent x = @{ .a.f = 1, .a.h = 3 @}; > +@end smallexample > + > +Nest them using braces instead: > + > +@smallexample > +struct child @{ int f, g, h; @}; > +struct parent @{ struct child a; @}; > +/* Warns. */ > +struct parent x = @{ .a = @{ .f = 1, h = 3 @} @}; > +@end smallexample > + > +@end table > + > @opindex Wmissing-requires > @opindex Wno-missing-requires > @item -Wno-missing-requires > diff --git a/gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-4.C > b/gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-4.C > new file mode 100644 > index 00000000000..69d6bd49790 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-4.C > @@ -0,0 +1,34 @@ > +// PR c++/39589 > +// { dg-do compile { target c++17 } } > +// { dg-options "-Wmissing-field-initializers=2" } > + > +// Unchanged behavior when =2 > + > +struct mystruct1 { > + int a, b; > +}; > + > +struct aux2 { > + aux2(); > +}; > + > +struct mystruct2 { > + aux2 a, b; > +}; > + > +struct aux3 { > + int x; > +}; > + > +struct mystruct3 { > + aux3 a, b; > +}; > + > +mystruct1 obj11 = {}; > +mystruct1 obj12 = {0}; // { dg-warning "missing initializer" } > + > +mystruct2 obj21 = {}; > +mystruct2 obj22 = {aux2()}; // { dg-warning "missing initializer" } > + > +mystruct3 obj31 = {}; > +mystruct3 obj32 = {0}; // { dg-warning "missing initializer" } > diff --git a/gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-5.C > b/gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-5.C > new file mode 100644 > index 00000000000..c6d1cee4bda > --- /dev/null > +++ b/gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-5.C > @@ -0,0 +1,47 @@ > +// PR c++/39589 > +// { dg-do compile { target c++11 } } > +// { dg-options "-Wmissing-field-initializers=2" } > + > +// Unchanged behavior when =2 > + > +namespace std { > + template<typename T> > + T&& declval() noexcept; > + > + template<bool B> > + struct bool_constant { > + static constexpr bool value = B; > + using type = bool_constant; > + }; > + using true_type = bool_constant<true>; > + using false_type = bool_constant<false>; > +}; > + > +template <typename T> > +struct TmpArray > +{ > + T arr[1]; > +}; > + > +template <typename Src, typename Dst, typename = void> > +struct is_non_narrowing_conversion : std::false_type > +{}; > + > +template <typename Src, typename Dst> > +struct is_non_narrowing_conversion< > + Src, Dst, > + decltype(void(TmpArray<Dst>{{ std::declval<Src>() }})) // { dg-bogus > "missing initializer" } > +> : std::true_type > +{}; > + > +struct mystruct > +{ > + int a; > + void * b; > +}; > + > +void test_nok() > +{ > + is_non_narrowing_conversion<int&, mystruct>::type v; > + (void) v; > +} > diff --git a/gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-6.C > b/gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-6.C > new file mode 100644 > index 00000000000..c0d46442734 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/warn/Wmissing-field-initializers-6.C > @@ -0,0 +1,50 @@ > +// PR c++/39589 > +// { dg-do compile { target c++17 } } > +// { dg-options "-Wmissing-field-initializers=2" } > + > +// Unchanged behavior when =2 > + > +struct B { }; > +struct D : B { > + int x; > + int y; > +}; > + > +struct E { > + int x; > + int y; > + B z; > +}; > + > +template<typename> struct X { }; > + > +template<typename T> > +struct F { > + int i; > + int j; > + X<T> x; > +}; > + > +int > +main () > +{ > + D d = {.x=1, .y=2}; // { dg-bogus "missing" } > + (void)d; > + E e = {.x=1, .y=2}; // { dg-bogus "missing" } > + (void)e; > + F<int> f = {.i=1, .j=2 }; // { dg-bogus "missing" } > + (void)f; > +} > + > +template<typename T> > +void fn () > +{ > + F<T> f = {.i=1, .j=2 }; // { dg-bogus "missing" } > + (void)f; > +} > + > +void > +g () > +{ > + fn<int> (); > +} > diff --git a/gcc/testsuite/gcc.dg/Wmissing-field-initializers-6.c > b/gcc/testsuite/gcc.dg/Wmissing-field-initializers-6.c > new file mode 100644 > index 00000000000..323c6f9c0e6 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wmissing-field-initializers-6.c > @@ -0,0 +1,433 @@ > +/* PR c/39589 */ > +/* { dg-do compile } */ > +/* { dg-options "-Wmissing-field-initializers=2" } */ > + > +#define NULL ((void *) 0) > + > +/* simple scenario tests */ > +struct Simple { > + int a; > + int b; > + int c; > +}; > +/* zero ok when warning mode 2 */ > +struct Simple simple01 = { 0 }; > +/* non-designated ok when warning mode 2 */ > +struct Simple simple02 = { 1 }; /* { dg-warning "missing initializer" } */ > +struct Simple simple03 = { 1, 2 }; /* { dg-warning "missing initializer" > } */ > +/* ordering but two are missing */ > +struct Simple simple04 = { .a = 1 }; /* { dg-warning "missing > initializer" } */ > +struct Simple simple05 = { .b = 1 }; /* { dg-warning "missing > initializer" } */ > +struct Simple simple06 = { .c = 1 }; /* { dg-warning "missing > initializer" } */ > +/* ordering but one is missing */ > +struct Simple simple07 = { .c = 1, .b = 1 }; /* { dg-warning "missing > initializer" } */ > +struct Simple simple08 = { .c = 1, .a = 1 }; /* { dg-warning "missing > initializer" } */ > +struct Simple simple09 = { .a = 1, .b = 1 }; /* { dg-warning "missing > initializer" } */ > +struct Simple simple10 = { .b = 1, .a = 1 }; /* { dg-warning "missing > initializer" } */ > +/* zero init but one is missing */ > +struct Simple simple11 = { .a = 0, .b = 0 }; /* { dg-warning "missing > initializer" } */ > +/* ordering, all manually zero ok */ > +struct Simple simple12 = { .a = 0, .b = 0, .c = 0 }; > +struct Simple simple13 = { .c = 0, .a = 0, .b = 0 }; > +struct Simple simple14 = { .b = 0, .a = 0, .c = 0 }; > +/* out-of-order ok */ > +struct Simple simple15 = { .a = 1, .b = 1, .c = 1 }; > +struct Simple simple16 = { .c = 1, .a = 1, .b = 1 }; > +struct Simple simple17 = { .b = 1, .a = 1, .c = 1 }; > +/* out of order, last element in definition = 0 ok */ > +struct Simple simple18 = { .b = 1, .a = 1, .c = 0 }; > + > +/* nested struct tests where last element in parent is a struct */ > +struct Child1 { > + int a1; > + int b1; > +}; > +struct Parent1 { > + int a0; > + struct Child1 child; > +}; > +struct Parent1 parent1_1 = { > + .a0 = 1 > +}; /* { dg-warning "missing initializer for field .child." } */ > +struct Parent1 parent1_2 = { > + .child = { > + .a1 = 1 > + } /* { dg-warning "missing initializer for field .b1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > +struct Parent1 parent1_3 = { > + .child = { > + .b1 = 1 > + } /* { dg-warning "missing initializer for field .a1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > +struct Parent1 parent1_4 = { > + .child = { > + .b1 = 1, > + .a1 = 1 > + } > +}; /* { dg-warning "missing initializer for field .a0." } */ > +/* parent/child ok */ > +struct Parent1 parent1_5 = { .a0 = 1, .child = { .a1 = 1, .b1 = 1 } }; > +struct Parent1 parent1_6 = { .child = { .b1 = 1, .a1 = 1 }, .a0 = 1 }; > +/* parent/child zero-init ok */ > +struct Parent1 parent1_7 = { .child = { .b1 = 0, .a1 = 0 }, .a0 = 1 }; > +struct Parent1 parent1_8 = { .child = { .b1 = 0, .a1 = 0 }, .a0 = 0 }; > + > +/* nested struct tests where last element in parent is not a struct */ > +struct Parent2 { > + struct Child1 child; > + int a0; > +}; > +struct Parent2 parent2_1 = { > + .a0 = 1 > +}; /* { dg-warning "missing initializer for field .child." } */ > +struct Parent2 parent2_2 = { > + .child = { > + .a1 = 1 > + } /* { dg-warning "missing initializer for field .b1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > +struct Parent2 parent2_3 = { > + .child = { > + .b1 = 1 > + } /* { dg-warning "missing initializer for field .a1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > +struct Parent2 parent2_4 = { > + .child = { > + .b1 = 1, > + .a1 = 1 > + } > +}; /* { dg-warning "missing initializer for field .a0." } */ > +/* parent/child ok */ > +struct Parent2 parent2_5 = { .a0 = 1, .child = { .a1 = 1, .b1 = 1 } }; > +struct Parent2 parent2_6 = { .child = { .b1 = 1, .a1 = 1 }, .a0 = 1 }; > +/* parent/child zero-init ok */ > +struct Parent2 parent2_7 = { .child = { .b1 = 0, .a1 = 0 }, .a0 = 1 }; > +struct Parent2 parent2_8 = { .child = { .b1 = 0, .a1 = 0 }, .a0 = 0 }; > + > + > +/* basic consistency tests for consistency with non-designated > initializers*/ > +struct ConsistentLevel2 { > + int a2; > + int b2; > +}; > +struct ConsistentLevel1 { > + struct ConsistentLevel2 level2; > + int a1; > +}; > +struct ConsistentParent1 { > + struct ConsistentLevel1 level1; > + int a0; > +}; > +struct ConsistentParent1 consistent1_1 = { > + { > + { > + 1 > + } /* { dg-warning "missing initializer for field .b2." } */ > + } /* { dg-warning "missing initializer for field .a1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > +struct ConsistentParent1 consistent1_2 = { > + .level1 = { > + .level2 = { > + .a2 = 1 > + } /* { dg-warning "missing initializer for field .b2." } */ > + } /* { dg-warning "missing initializer for field .a1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > + > +/* designated zero init. */ > +struct ConsistentParent1 designated_nested_zero_1 = { > + .level1 = { > + .level2 = { > + .a2 = 0 > + } /* { dg-warning "missing initializer for field .b2." } */ > + } /* { dg-warning "missing initializer for field .a1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > + > +/* designated initializers with a non-designated zero init child. */ > +struct ConsistentParent1 designated_nested_zero_2 = { > + .level1 = { > + .level2 = { > + 0 > + } > + } /* { dg-warning "missing initializer for field .a1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > + > +/* tests for multiple depths, identical siblings */ > +struct Level3 { > + int a3; > + int b3; > + int c3; > +}; > +struct Level2 { > + int a2; > + struct Level3 level3; > +}; > +struct Level1 { > + struct Level2 level2; > + int a1; > +}; > +struct Multi { > + struct Level1 level1_1; > + int a0; > + struct Level1 level1_2; > +}; > + > +/* we're ignoring chained initializers right now. make sure that holds */ > +struct Multi chain_ok = { > + .level1_1.level2.a2 = 1, > + .level1_1.level2.level3.a3 = 1, > + .level1_1.level2.level3.b3 = 1, > + .level1_1.level2.level3.c3 = 1, > + .level1_1.a1 = 1, > + .a0 = 1, > + .level1_2.level2.a2 = 1, > + .level1_2.level2.level3.a3 = 1, > + .level1_2.level2.level3.b3 = 1, > + .level1_2.a1 = 1, /* deliberately out of order */ > + .level1_2.level2.level3.c3 = 1, > +}; > + > +/* we're ignoring chained initializers right now. make sure that holds > + when we skip something in the middle. > + */ > +struct Multi chain_failure_mid = { > + .level1_1.level2.a2 = 1, > + .level1_1.level2.level3.a3 = 1, > + .level1_1.level2.level3.b3 = 1, > + .level1_1.level2.level3.c3 = 1, > + .level1_1.a1 = 1, > + .a0 = 1, > + /* skip a2 */ > + .level1_2.level2.level3.a3 = 1, > + .level1_2.level2.level3.b3 = 1, > + .level1_2.a1 = 1, > + .level1_2.level2.level3.c3 = 1, > +}; > + > +/* we're ignoring chained initializers right now. make sure that holds > + when we skip the bottommost member. */ > +struct Multi chain_failure_bottommost = { > + .level1_2.level2.level3.a3 = 1, > + .level1_1.level2.a2 = 1, > + .level1_1.level2.level3.a3 = 1, > + .level1_1.level2.level3.c3 = 1, > + .level1_1.level2.level3.b3 = 1, > + .level1_1.a1 = 1, > + .a0 = 1, > + .level1_2.level2.level3.b3 = 1, > + .level1_2.a1 = 1, > + .level1_2.level2.a2 = 1, > + /* skip c3 */ > +}; > + > +/* we're ignoring chained initializers right now. make sure that holds > + when we skip something at the top level. */ > +struct Multi chain_failure_topmost = { > + .level1_1.level2.a2 = 1, > + .level1_1.level2.level3.a3 = 1, > + .level1_1.level2.level3.b3 = 1, > + .level1_1.level2.level3.c3 = 1, > + .level1_1.a1 = 1, > + /* skip a0 */ > + .level1_2.level2.a2 = 1, > + .level1_2.level2.level3.a3 = 1, > + .level1_2.level2.level3.b3 = 1, > + .level1_2.level2.level3.c3 = 1, > + .level1_2.a1 = 1, > +}; > + > +/* we're ignoring chained initializers right now. make sure that things > behave > + when we mix initializer types with non-designated initializers. */ > +struct Multi chain_failure_mix1 = { > + .level1_1.level2.a2 = 1, > + .level1_1.level2 = { > + 1, { > + 1, > + 2 > + } /* { dg-warning "missing initializer for field .c3." } */ > + }, > + .level1_1.a1 = 1, > + /* skip a0 */ > + .level1_2.level2.a2 = 1, > + .level1_2.level2.level3.a3 = 1, > + .level1_2.level2.level3.b3 = 1, > + .level1_2.level2.level3.c3 = 1, > + .level1_2.a1 = 1, > +}; > + > +/* we're ignoring chained initializers right now. make sure that things > behave > + when we mix initializer types with non-chained designated > initializers. */ > +struct Multi chain_failure_mix2 = { > + .level1_1.level2.a2 = 1, > + .level1_1.level2 = { > + .a2 = 1, { > + 1, > + 2 > + } /* { dg-warning "missing initializer for field .c3." } */ > + }, > + .level1_1.a1 = 1, > + /* skip a0 */ > + .level1_2.level2.a2 = 1, > + .level1_2.level2.level3.a3 = 1, > + .level1_2.level2.level3.b3 = 1, > + .level1_2.level2.level3.c3 = 1, > + .level1_2.a1 = 1, > +}; > + > +/* we're ignoring chained initializers right now. make sure that things > behave > + when we mix initializer types with non-chained designated > initializers. */ > +struct Multi chain_failure_mix3 = { > + .level1_1.level2.a2 = 1, > + .level1_1.level2 = { > + .level3 = { 1, 2, 3 > + } > + }, /* { dg-warning "missing initializer for field .a2." } */ > + .level1_1.a1 = 1, > + /* skip a0 */ > + .level1_2.level2.a2 = 1, > + .level1_2.level2.level3.a3 = 1, > + .level1_2.level2.level3.b3 = 1, > + .level1_2.level2.level3.c3 = 1, > + .level1_2.a1 = 1, > +}; > + > +struct Multi multi_all_zero = { 0 }; > + > +struct Multi multi01 = { > + .level1_1 = { > + .level2 = { > + .a2 = 1, > + .level3 = { > + .a3 = 1, > + .b3 = 1 > + } /* { dg-warning "missing initializer for field .c3." } */ > + } > + } /* { dg-warning "missing initializer for field .a1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > + > +/* designated nested zero inits still warn when missing */ > +struct Multi multi02 = { > + .level1_1 = { > + .level2 = { > + .a2 = 1, > + .level3 = { > + .a3 = 0, > + .b3 = 0 > + } /* { dg-warning "missing initializer for field .c3." } */ > + } > + } /* { dg-warning "missing initializer for field .a1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > + > +/* designated nested zero inits do not warn when all present */ > +struct Multi multi03 = { > + .level1_1 = { > + .level2 = { > + .a2 = 1, > + .level3 = { > + .a3 = 0, > + .b3 = 0, > + .c3 = 0 > + } > + } > + } /* { dg-warning "missing initializer for field .a1." } */ > +}; /* { dg-warning "missing initializer for field .a0." } */ > + > +/* top level still warns when middle element missing when children are ok > */ > +struct Multi multi04 = { > + .level1_1 = { > + .level2 = { > + .a2 = 1, > + .level3 = { > + .a3 = 1, > + .b3 = 1, > + .c3 = 0 > + } > + }, > + .a1 = 1, > + }, > + .level1_2 = {0} > +}; /* { dg-warning "missing initializer for field .a0." } */ > + > +/* top level warns when final element is struct */ > +struct Multi multi05 = { > + .level1_1 = { > + .level2 = { > + .a2 = 1, > + .level3 = { 1, 2, 3 } /* non-designated inits for good measure */ > + }, > + .a1 = 1, > + }, > + .a0 = 1, > +}; /* { dg-warning "missing initializer for field .level1_2." } */ > + > +/* multiple sublevels zero */ > +struct Multi multi06 = { > + .level1_1 = { > + .level2 = { > + .a2 = 1, > + .level3 = { .a3 = 1, .b3 = 1, .c3 = 1 } > + }, > + .a1 = 1, > + }, > + .a0 = 1, > + .level1_2 = {0} > +}; > + > +/* final element missing in deep designated initializer */ > +struct Multi multi07 = { > + .level1_1 = { > + .level2 = { > + .a2 = 1, > + .level3 = { .a3 = 1, .b3 = 1, .c3 = 1 } > + }, > + .a1 = 1, > + }, > + .a0 = 1, > + .level1_2 = { > + .a1 = 1, > + .level2 = { > + .a2 = 1, > + .level3 = { > + .a3 = 1 > + } /* { dg-warning "missing initializer for field .b3." } */ > + } > + } > +}; > + > +/* non-final element missing in deep designated initializer final child > */ > +struct Multi multi08 = { > + .level1_1 = { > + .level2 = { > + .a2 = 1, > + .level3 = { .a3 = 1, .b3 = 1, .c3 = 1 } > + }, > + .a1 = 1, > + }, > + .a0 = 1, > + .level1_2 = { > + .a1 = 1, > + .level2 = { > + .a2 = 1, > + .level3 = { > + .b3 = 1, > + .c3 = 1 > + } /* { dg-warning "missing initializer for field .a3." } */ > + } > + } > +}; > + > +/* missing multiple final elements in deep designated initializer */ > +struct Multi multi09 = { > + .level1_1 = { > + .level2 = { > + .a2 = 1, > + .level3 = { 1, 2, 3 } > + }, > + .a1 = 1, > + }, > + .a0 = 1, > + .level1_2 = { > + .a1 = 1, > + .level2 = { > + .a2 = 1, > + } /* { dg-warning "missing initializer for field .level3." } */ > + } > +}; > -- > 2.43.0 > >
