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
>
>

Reply via email to