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