v3 Patch: * adds documentation * fixes formatting * minor code cleanup
Currently the behaviour of Wmissing-field-initializers is inconsistent between C and C++. The C warning assumes that missing designated initializers are deliberate, and does not warn. The C++ warning does warn for missing designated initializers. This patch changes the behaviour of Wmissing-field-initializers to universally not warn about missing designated initializers, and adds a new warning for specifically for missing designated initializers. NOTE TO MAINTAINERS: This is my first gcc contribution, so I don't have git write access. Successfully tested on x86_64-pc-linux-gnu. PR c/39589 gcc/c-family/ChangeLog: * c.opt (Wmissing-designated-initializers): New option. * c.opt.urls: (Wmissing-designated-initializers): New option. gcc/c/ChangeLog: * c-typeck.cc (pop_init_level): Generate warning for missing designated initializers rather than always ignore. gcc/ChangeLog: * common.opt.urls: (Wmissing-designated-initializers): New option. * doc/invoke.texi: (Wmissing-designated-initializers): New option. gcc/cp/ChangeLog: * typeck2.cc (process_init_constructor_record): Add check if missing initializer is designated, warn as appropriate. gcc/testsuite/ChangeLog: * g++.dg/diagnostic/base.C: Change flags. * gcc.dg/20011021-1.c: Fix test, missing designated initializers can generate a warning now. * gcc.dg/missing-field-init-1.c: Change flags. * gcc.dg/pr60784.c: Change flags. * g++.dg/warn/missing-designated-initializers-1.C: New test. * g++.dg/warn/missing-designated-initializers-2.C: New test. * gcc.dg/missing-designated-initializers-1.c: New test. * gcc.dg/missing-designated-initializers-2.c: New test. --- gcc/c-family/c.opt | 4 + gcc/c-family/c.opt.urls | 3 + gcc/c/c-typeck.cc | 52 ++++----- gcc/common.opt.urls | 2 +- gcc/cp/typeck2.cc | 100 +++++++++--------- gcc/doc/invoke.texi | 40 ++++++- gcc/testsuite/g++.dg/diagnostic/base.C | 4 +- .../warn/missing-designated-initializers-1.C | 12 +++ .../warn/missing-designated-initializers-2.C | 12 +++ gcc/testsuite/gcc.dg/20011021-1.c | 17 ++- .../missing-designated-initializers-1.c | 14 +++ .../missing-designated-initializers-2.c | 14 +++ gcc/testsuite/gcc.dg/missing-field-init-1.c | 2 +- gcc/testsuite/gcc.dg/pr60784.c | 2 +- 14 files changed, 184 insertions(+), 94 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/missing-designated-initializers-1.C create mode 100644 gcc/testsuite/g++.dg/warn/missing-designated-initializers-2.C create mode 100644 gcc/testsuite/gcc.dg/missing-designated-initializers-1.c create mode 100644 gcc/testsuite/gcc.dg/missing-designated-initializers-2.c diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 15698dc65bb..746adc8aaad 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1030,6 +1030,10 @@ Wmissing-field-initializers C ObjC C++ ObjC++ Var(warn_missing_field_initializers) Warning EnabledBy(Wextra) Warn about missing fields in struct initializers. +Wmissing-designated-initializers +C ObjC C++ ObjC++ Var(warn_missing_designated_initializers) Warning EnabledBy(Wextra) +Warn about missing designated initializers in struct initializers. + Wmissing-format-attribute C ObjC C++ ObjC++ Warning Alias(Wsuggest-attribute=format) ; diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls index fd7ffd38d53..88772cd113f 100644 --- a/gcc/c-family/c.opt.urls +++ b/gcc/c-family/c.opt.urls @@ -553,6 +553,9 @@ UrlSuffix(gcc/Warning-Options.html#index-Wmissing-declarations) Wmissing-field-initializers UrlSuffix(gcc/Warning-Options.html#index-Wmissing-field-initializers) +Wmissing-designated-initializers +UrlSuffix(gcc/Warning-Options.html#index-Wmissing-designated-initializers) + Wmissing-format-attribute UrlSuffix(gcc/Warning-Options.html#index-Wmissing-format-attribute) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index dbb688cabaa..37cc95f4a37 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -10150,31 +10150,33 @@ pop_init_level (location_t loc, int implicit, } /* Warn when some struct elements are implicitly initialized to zero. */ - 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); - - 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) - { - 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); - } + if ((warn_missing_field_initializers || + warn_missing_designated_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); + + if (constructor_unfilled_fields + /* Do not warn about initializing with { 0 } or with { }. */ + && !constructor_zeroinit) { + if (!constructor_designated) { + 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 (warning_at(input_location, OPT_Wmissing_designated_initializers, + "missing designated initializer for field %qD of %qT", + constructor_unfilled_fields, constructor_type)) + inform(DECL_SOURCE_LOCATION(constructor_unfilled_fields), + "%qD declared here", constructor_unfilled_fields); + } + } } /* Pad out the end of the structure. */ diff --git a/gcc/common.opt.urls b/gcc/common.opt.urls index 79c322bed2b..f7950d834c4 100644 --- a/gcc/common.opt.urls +++ b/gcc/common.opt.urls @@ -48,7 +48,7 @@ T UrlSuffix(gcc/Link-Options.html#index-T) ; skipping UrlSuffix for 'W' due to multiple URLs: -; duplicate: 'gcc/Incompatibilities.html#index-W-3' +; duplicate: 'gcc/Incompatibilities.html#index-W-4' ; duplicate: 'gcc/Warning-Options.html#index-W' Waggregate-return diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 381f198d0fe..9fcd8b932c8 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -1848,59 +1848,59 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, TARGET_EXPR_ELIDING_P (next) = false; /* Warn when some struct elements are implicitly initialized. */ - if ((complain & tf_warning) - && !cp_unevaluated_operand - && !EMPTY_CONSTRUCTOR_P (init)) - warning (OPT_Wmissing_field_initializers, - "missing initializer for member %qD", field); - } - else - { - if (TYPE_REF_P (fldtype)) - { - if (complain & tf_error) - error ("member %qD is uninitialized reference", field); - else - return PICFLAG_ERRONEOUS; - } - else if (CLASSTYPE_REF_FIELDS_NEED_INIT (fldtype)) - { - if (complain & tf_error) - error ("member %qD with uninitialized reference fields", field); - else - return PICFLAG_ERRONEOUS; - } - /* Do nothing for flexible array members since they need not have any - elements. Don't worry about 'skipped' because a flexarray has to - be the last field. */ - else if (TREE_CODE (fldtype) == ARRAY_TYPE && !TYPE_DOMAIN (fldtype)) - continue; + if ((complain & tf_warning) && !cp_unevaluated_operand && + !EMPTY_CONSTRUCTOR_P(init)) { + if (CONSTRUCTOR_IS_DESIGNATED_INIT(init)) + warning(OPT_Wmissing_designated_initializers, + "missing designated initializer for member %qD", field); + else + warning(OPT_Wmissing_field_initializers, + "missing initializer for member %qD", field); + } + } else { + if (TYPE_REF_P(fldtype)) { + if (complain & tf_error) + error("member %qD is uninitialized reference", field); + else + return PICFLAG_ERRONEOUS; + } else if (CLASSTYPE_REF_FIELDS_NEED_INIT(fldtype)) { + if (complain & tf_error) + error("member %qD with uninitialized reference fields", field); + else + return PICFLAG_ERRONEOUS; + } + /* Do nothing for flexible array members since they need not have any + elements. Don't worry about 'skipped' because a flexarray has to + be the last field. */ + else if (TREE_CODE(fldtype) == ARRAY_TYPE && !TYPE_DOMAIN(fldtype)) + continue; /* Warn when some struct elements are implicitly initialized to zero. */ - if ((complain & tf_warning) - && !cp_unevaluated_operand - && !EMPTY_CONSTRUCTOR_P (init) - && !is_really_empty_class (fldtype, /*ignore_vptr*/false)) - warning (OPT_Wmissing_field_initializers, - "missing initializer for member %qD", field); - - if (!zero_init_p (fldtype) || skipped < 0) - { - if (TYPE_REF_P (fldtype)) - next = build_zero_cst (fldtype); - else - next = build_zero_init (fldtype, /*nelts=*/NULL_TREE, - /*static_storage_p=*/false); - } - else - { - /* The default zero-initialization is fine for us; don't - add anything to the CONSTRUCTOR. */ - skipped = 1; - continue; - } - } + if ((complain & tf_warning) && !cp_unevaluated_operand && + !EMPTY_CONSTRUCTOR_P(init) && + !is_really_empty_class(fldtype, /*ignore_vptr*/ false)) { + if (CONSTRUCTOR_IS_DESIGNATED_INIT(init)) + warning(OPT_Wmissing_designated_initializers, + "missing designated initializer for member %qD", field); + else + warning(OPT_Wmissing_field_initializers, + "missing initializer for member %qD", field); + } + + if (!zero_init_p(fldtype) || skipped < 0) { + if (TYPE_REF_P(fldtype)) + next = build_zero_cst(fldtype); + else + next = build_zero_init(fldtype, /*nelts=*/NULL_TREE, + /*static_storage_p=*/false); + } else { + /* The default zero-initialization is fine for us; don't + add anything to the CONSTRUCTOR. */ + skipped = 1; + continue; + } + } /* We can't actually elide the temporary when initializing a potentially-overlapping field from a function that returns by diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 0a7a81b2067..406ea24fb3b 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -393,9 +393,10 @@ 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-include-dirs -Wmissing-noreturn -Wno-missing-profile --Wno-multichar -Wmultistatement-macros -Wnonnull -Wnonnull-compare +-Wmissing-field-initializers -Wmissing-designated-initializers +-Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn +-Wno-missing-profile -Wno-multichar -Wmultistatement-macros +-Wnonnull -Wnonnull-compare -Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} -Wnull-dereference -Wno-odr -Wopenacc-parallelism @@ -6463,6 +6464,7 @@ name is still supported, but the newer name is more descriptive.) -Wimplicit-fallthrough=3 -Wmaybe-uninitialized -Wmissing-field-initializers +-Wmissing-designated-initializers -Wmissing-parameter-name @r{(C/ObjC only)} -Wmissing-parameter-type @r{(C/ObjC only)} -Wold-style-declaration @r{(C/ObjC only)} @@ -10248,8 +10250,7 @@ struct s @{ int f, g, h; @}; struct s x = @{ 3, 4 @}; @end smallexample -@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 +This option does not warn about missing designated initializers, so the following modification does not trigger a warning: @smallexample @@ -10257,6 +10258,9 @@ struct s @{ int f, g, h; @}; struct s x = @{ .f = 3, .g = 4 @}; @end smallexample +Use @option{-Wmissing-designated-initializers} to detect missing designated +initializers. + In C this option does not warn about the universal zero initializer @samp{@{ 0 @}}: @@ -10276,6 +10280,32 @@ s x = @{ @}; 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-designated-initializers +@opindex Wno-missing-designated-initializers +@opindex W +@opindex Wextra +@opindex Wno-extra +@item -Wmissing-designated-initializers +Warn if a structure's designated initializer is missing some fields. 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 @}; +@end smallexample + +This option does not warn about missing fields for undesignated initializers, +so the following modification does not trigger a warning: + +@smallexample +struct s @{ int f, g, h; @}; +struct s x = @{ 3, 4 @}; +@end smallexample + +Use @option{-Wmissing-field-initializers} to detect missing undesignated initializers. + + @opindex Wmissing-requires @opindex Wno-missing-requires @item -Wno-missing-requires diff --git a/gcc/testsuite/g++.dg/diagnostic/base.C b/gcc/testsuite/g++.dg/diagnostic/base.C index 1540414072e..9e9abc2729a 100644 --- a/gcc/testsuite/g++.dg/diagnostic/base.C +++ b/gcc/testsuite/g++.dg/diagnostic/base.C @@ -1,6 +1,6 @@ // PR c++/110745 // { dg-do compile { target c++17 } } -// { dg-options "-Wmissing-field-initializers" } +// { dg-options "-Wmissing-designated-initializers" } struct B { int i; }; struct D : B { @@ -11,6 +11,6 @@ struct D : B { int main () { - D d = {.x=1, .y=2}; // { dg-warning "missing initializer for member .D::B." } + D d = {.x = 1, .y = 2}; // { dg-warning "missing designated initializer for member .D::B." } (void)d; } diff --git a/gcc/testsuite/g++.dg/warn/missing-designated-initializers-1.C b/gcc/testsuite/g++.dg/warn/missing-designated-initializers-1.C new file mode 100644 index 00000000000..8f3fa200aaf --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/missing-designated-initializers-1.C @@ -0,0 +1,12 @@ +/* PR c/39589 */ +/* { dg-do compile } */ +/* { dg-options "-Wextra -Wmissing-designated-initializers" } */ + +struct s { int a, b, c; }; +struct s s1 = { .a = 1, .b = 2, .c = 3 }; +struct s s2 = { .a = 1, .b = 2 }; /* { dg-warning "missing designated initializer" } */ +struct s s3 = { .a = 1 }; /* { dg-warning "missing designated initializer" } */ + +struct s s6[] = { { .a = 1, .b = 2, .c = 3 }, { .a = 4 } }; /* { dg-warning "missing designated initializer" } */ +struct s s7[] = { { .a = 1 }, { .a = 2, .b = 3, .c = 4 } }; /* { dg-warning "missing designated initializer" } */ +struct s s8[] = { { 1, 2, 3 }, { .a = 4 } }; /* { dg-warning "missing designated initializer" } */ diff --git a/gcc/testsuite/g++.dg/warn/missing-designated-initializers-2.C b/gcc/testsuite/g++.dg/warn/missing-designated-initializers-2.C new file mode 100644 index 00000000000..2398a6b0dc1 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/missing-designated-initializers-2.C @@ -0,0 +1,12 @@ +/* PR c/39589 */ +/* { dg-do compile } */ +/* { dg-options "-Wextra -Wno-missing-designated-initializers" } */ + +struct s { int a, b, c; }; +struct s s1 = { .a = 1, .b = 2, .c = 3 }; +struct s s2 = { .a = 1, .b = 2 }; /* { dg-bogus "missing designated initializer" } */ +struct s s3 = { .a = 1 }; /* { dg-bogus "missing designated initializer" } */ + +struct s s6[] = { { .a = 1, .b = 2, .c = 3 }, { .a = 4 } }; /* { dg-bogus "missing designated initializer" } */ +struct s s7[] = { { .a = 1 }, { .a = 2, .b = 3, .c = 4 } }; /* { dg-bogus "missing designated initializer" } */ +struct s s8[] = { { 1, 2, 3 }, { .a = 4 } }; /* { dg-bogus "missing designated initializer" } */ diff --git a/gcc/testsuite/gcc.dg/20011021-1.c b/gcc/testsuite/gcc.dg/20011021-1.c index 2d567a75381..d9b26e3c48a 100644 --- a/gcc/testsuite/gcc.dg/20011021-1.c +++ b/gcc/testsuite/gcc.dg/20011021-1.c @@ -29,17 +29,16 @@ struct multilevel struct t T0 = { 1 }; /* { dg-warning "missing init" } */ -struct t T1 = { .a = 1 }; /* { dg-bogus "(missing|near) init" } */ +struct t T1 = {.a = 1}; /* { dg-warning "missing designated initializer" } */ union u U0 = { 1 }; /* { dg-warning "initialization of union" } */ union u U1 = { .i = 1 }; /* { dg-bogus "initialization of union" } */ -struct multilevel M = -{ - 12, - { .b = 3 }, /* { dg-bogus "missing init" } */ - { 4 }, /* { dg-warning "initialization of union" } */ - { .n = 9 }, /* { dg-bogus "initialization of union" } */ - /* "string here" */ -}; /* { dg-warning "missing init" } */ +struct multilevel M = { + 12, + {.b = 3}, /* { dg-warning "missing designated initializer" } */ + {4}, /* { dg-warning "initialization of union" } */ + {.n = 9}, /* { dg-bogus "initialization of union" } */ + /* "string here" */ +}; /* { dg-warning "missing init" } */ /* { dg-message "declared here" "near init" { target *-*-* } multilevel_f } */ diff --git a/gcc/testsuite/gcc.dg/missing-designated-initializers-1.c b/gcc/testsuite/gcc.dg/missing-designated-initializers-1.c new file mode 100644 index 00000000000..aef953978df --- /dev/null +++ b/gcc/testsuite/gcc.dg/missing-designated-initializers-1.c @@ -0,0 +1,14 @@ +/* PR c/39589 */ +/* { dg-do compile } */ +/* { dg-options "-Wextra -Wmissing-designated-initializers" } */ + +struct s { int a, b, c; }; +struct s s1 = { .a = 1, .b = 2, .c = 3 }; +struct s s2 = { .a = 1, .b = 2 }; /* { dg-warning "missing designated initializer" } */ +struct s s3 = { .a = 1 }; /* { dg-warning "missing designated initializer" } */ +struct s s4 = { .a = 1, 2 }; /* { dg-warning "missing designated initializer" } */ +struct s s5 = { .a = 1, 2, 3 }; /* { dg-bogus "missing designated initializer" } */ + +struct s s6[] = { { .a = 1, .b = 2, .c = 3 }, { .a = 4 } }; /* { dg-warning "missing designated initializer" } */ +struct s s7[] = { { .a = 1 }, { .a = 2, .b = 3, .c = 4 } }; /* { dg-warning "missing designated initializer" } */ +struct s s8[] = { { 1, 2, 3 }, { .a = 4 } }; /* { dg-warning "missing designated initializer" } */ diff --git a/gcc/testsuite/gcc.dg/missing-designated-initializers-2.c b/gcc/testsuite/gcc.dg/missing-designated-initializers-2.c new file mode 100644 index 00000000000..f17fbd6c0e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/missing-designated-initializers-2.c @@ -0,0 +1,14 @@ +/* PR c/39589 */ +/* { dg-do compile } */ +/* { dg-options "-Wextra -Wno-missing-designated-initializers" } */ + +struct s { int a, b, c; }; +struct s s1 = { .a = 1, .b = 2, .c = 3 }; +struct s s2 = { .a = 1, .b = 2 }; /* { dg-bogus "missing designated initializer" } */ +struct s s3 = { .a = 1 }; /* { dg-bogus "missing designated initializer" } */ +struct s s4 = { .a = 1, 2 }; /* { dg-bogus "missing designated initializer" } */ +struct s s5 = { .a = 1, 2, 3 }; /* { dg-bogus "missing designated initializer" } */ + +struct s s6[] = { { .a = 1, .b = 2, .c = 3 }, { .a = 4 } }; /* { dg-bogus "missing designated initializer" } */ +struct s s7[] = { { .a = 1 }, { .a = 2, .b = 3, .c = 4 } }; /* { dg-bogus "missing designated initializer" } */ +struct s s8[] = { { 1, 2, 3 }, { .a = 4 } }; /* { dg-bogus "missing designated initializer" } */ diff --git a/gcc/testsuite/gcc.dg/missing-field-init-1.c b/gcc/testsuite/gcc.dg/missing-field-init-1.c index 5f32b021f0a..cd43fcc4f06 100644 --- a/gcc/testsuite/gcc.dg/missing-field-init-1.c +++ b/gcc/testsuite/gcc.dg/missing-field-init-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-Wextra -Wno-missing-field-initializers -std=c99" } */ +/* { dg-options "-Wextra -Wno-missing-field-initializers -Wno-missing-designated-initializers -std=c99" } */ struct s { int a, b, c; }; struct s s1 = { 1, 2, 3 }; diff --git a/gcc/testsuite/gcc.dg/pr60784.c b/gcc/testsuite/gcc.dg/pr60784.c index 82b512f7c2e..60532831f4f 100644 --- a/gcc/testsuite/gcc.dg/pr60784.c +++ b/gcc/testsuite/gcc.dg/pr60784.c @@ -1,6 +1,6 @@ /* PR c/60784 */ /* { dg-do compile } */ -/* { dg-options "-Wextra -std=c99" } */ +/* { dg-options "-Wextra -Wno-missing-designated-initializers -std=c99" } */ struct A { int i, j; }; struct B { struct A a; } b1 = { .a.i = 1, .a.j = 1 }; -- 2.39.5