Bug 39589 - make -Wmissing-field-initializers=2 work with "designated initializers" ?
Summary: make -Wmissing-field-initializers=2 work with "designated initializers" ?
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.5.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic, documentation
Depends on:
Blocks:
 
Reported: 2009-03-30 17:04 UTC by jim
Modified: 2019-11-23 05:54 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 6.2.0
Last reconfirmed: 2015-02-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description jim 2009-03-30 17:04:44 UTC
Compiling this with -Wmissing-field-initializers evokes a warning:

    struct foo { int a; int b; };
    struct foo f = { 1 };

but with "designated initializers" it does not:

    struct foo { int a; int b; };
    struct foo f = { .a = 1 };

That -Wmissing-field-initializers works this way is even documented.

My quandary is that I'd prefer to use the more readable and
maintainable c99 form, especially with long lists of member names:

  foo = {
    .f1 = callback_a,
    .f2 = callback_b,
    .f3 = callback_c,
    ...
    .fn = callback_n,
  };

Then, it's obvious that foo.f23 is initialized to callback_23,
whereas with old-style initializations, I'd have to count,
and if ever I had the misfortune to reorder member names,
and signatures are similar, it'd be easy to miss the error.

However, the old-style initialization has the advantage that
when I add a new member, gcc -Wmissing-field-initializers will
prompt me to add a new initializer.  With the c99-style, there
seems to be no way to evoke a similar prod.

Maybe we can get the best of both worlds?

Paolo Bonzini mentioned that this would be easy to implement,
and that -Wmissing-field-initializers=2 may be the way to do it,
given the precedent of -Wstrict-overflow and -Wstrict-overflow=<N>.
Comment 1 Szikra István 2013-10-22 13:13:55 UTC
I have the same (or similar) problem, and would like to have an option to enable warnings for incomplete structure initialization with designated initializers, where not all fields were explicitly assigned. 

(I know that the omitted fields are going to be 0, but that does not help me much in my embedded project. I would really like a compilation warning for the occasional misses, and not have to use other code analysis tools. Unfortunately splint does not even work for gnu99 code.)

More details, examples can be found here:
http://stackoverflow.com/questions/19430285/how-to-ensure-structures-are-completly-initialized-by-name-in-gcc

Thanks in advance for anyone who can help us out.
Comment 2 Manuel López-Ibáñez 2013-10-23 08:24:08 UTC
(In reply to Szikra István from comment #1)
> I have the same (or similar) problem, and would like to have an option to
> enable warnings for incomplete structure initialization with designated
> initializers, where not all fields were explicitly assigned. 

I don't think GCC devs would be against this in principle if someone provided a sensible patch: http://gcc.gnu.org/contribute.html

The relevant code is at gcc/c/c-typeck.c: pop_init_level

  /* 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)
    {
        bool constructor_zeroinit =
         (vec_safe_length (constructor_elements) == 1
          && integer_zerop ((*constructor_elements)[0].value));

        /* 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}'.  */
            && !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);
          }
    }


Perhaps sinking the !constructor_designated check into the if, and adding an 'else'? Or simply deleting the check and doing:

            if (warning_at (input_location, 
                            !constructor_designated check ? OPT_Wmissing_field_initializers : OPT_Wmissing_field_initializers_2,

where OPT_Wmissing_field_initializers_2 corresponds to a new option Wmissing-field-initializers=2 that needs to be added to c.opt (and documented in doc/invoke.texi).
Comment 3 Manuel López-Ibáñez 2014-10-08 12:22:23 UTC
Also, I would propose to call the warning -Wmissing-designated-initializers better than a number that does not mean much.
Comment 4 Marek Polacek 2015-02-12 14:22:49 UTC
Confirmed.
Comment 5 Jakub Jelinek 2016-04-27 10:58:29 UTC
GCC 6.1 has been released.
Comment 6 Richard Biener 2016-08-22 08:36:55 UTC
GCC 6.2 is being released, adjusting target milestone
Comment 7 Jakub Jelinek 2016-12-21 10:59:13 UTC
GCC 6.3 is being released, adjusting target milestone.
Comment 8 Georg 2017-01-03 11:30:38 UTC
If it helps implementing this legitimate distinction between
use cases, i.e. default initialisation vs. software maintenance,
I'd be happy having to attach a type attribute. For example, 

  struct foo { int a; int b; }
   __attribute__((explicit_initialization));

Or any better name of an attribute.

The attribute could tell the compiler to please use its
knowledge of missing field initialisers, and, less paradoxically,
to warn, actually, when -Wmissing-field-initializers is in effect.
Just as it does when there are no designator in the initialiser list.
For software maintenance this will be a boon.

By analogy, I'd like to illustrate this use case like this:
I don't want the compiler to be silent by force whenever
it notices a missing implementation of a member function/Obj-C
method/Ada prim op just because the programmer had given some other
of these a name---assuming the respective language were to allow
this at all.
Comment 9 Jonathan Wakely 2017-01-03 12:05:07 UTC
I'm unsetting Target Milestone, because if this is changed it should be done on trunk not a release branch.
Comment 10 Manuel López-Ibáñez 2017-01-03 21:56:26 UTC
(In reply to Georg from comment #8)
> If it helps implementing this legitimate distinction between
> use cases, i.e. default initialisation vs. software maintenance,
> I'd be happy having to attach a type attribute. For example, 

This seems more complicated than extending -Wm-f-i or adding a new option. I think the current behavior is historical and does not make sense nowadays. If the patch reviewers complain that the behavior of -Wm-f-i should not change, then just add a new option or a numeric level to -Wm-f-i, whatever reviewers prefer (see point 10 in https://gcc.gnu.org/wiki/Community).

The reason this has not been implemented in 8 years is not any a priori rejection, but simply nobody has had the time or the motivation to submit a patch:

https://gcc.gnu.org/wiki/GettingStarted#Basics:_Contributing_to_GCC_in_10_easy_steps
Comment 11 Matthijs Kooijman 2019-11-22 18:48:56 UTC
It seems this was actually implemented at some point (at least for C++, maybe that was the case all along already), though the manual page was not updated to reflect this. Taking the example from the manual (which is documented to *not* cause this warning):

matthijs@grubby:~$ cat foo.cpp 
struct s { int f, g, h; };
struct s x = { .f = 3, .g = 4 };
matthijs@grubby:~$ gcc foo.cpp -c  -Wall -Wextra
foo.cpp:2:31: warning: missing initializer for member ‘s::h’ [-Wmissing-field-initializers]
 struct s x = { .f = 3, .g = 4 };
                               ^
However, this seems to be the case only for C++, if I rename to foo.c, no warning is emitted.


I actually came here looking for a way to *disable* this warning for designated initializers on a specific struct. I was hoping to use a struct with designated initializers as an elegant way to specify configuration with optional fields (e.g. by lettin any unspecified fields be initialized to 0 and fill in a default value for them). However, when any caller that omits a field to get the default value is pestered with a warning, that approach does not really work well. On the other hand, disabling the warning completely with a commandline option or pragma seems heavy-handed, since I do consider this a useful warning in many other cases.
Comment 12 Eric Gallager 2019-11-23 05:54:43 UTC
(In reply to Matthijs Kooijman from comment #11)
> It seems this was actually implemented at some point (at least for C++,
> maybe that was the case all along already), though the manual page was not
> updated to reflect this. 

Sounds like a documentation issue, too, then; adding that keyword...