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