Compound literal and designated initializer warning from GCC but not Clang
Asked Answered
C

2

17

Compiling with gcc -std=c99 -Wextra this piece of code:

#include <stdio.h>

struct T {
    int a;
    int *b;
    int c;
};

int main(void)
{
    struct T t = {.b = ((int []){1, 1})};

    printf("%d\n", t.b[1]);
    return 0;
}

Is giving me a warning:

demo.c:11:12: warning: missing initializer for field ‘c’ of ‘struct T’ [-Wmissing-field-initializers]
     struct T t = {.b = ((int []){1, 1})};
            ^
demo.c:6:9: note: ‘c’ declared here
     int c;
         ^

But designated initializers are supposed to initialize to zero the rest of the members even if they are ommited.

Why the warning? (clang compiles the same piece of code without warnings)

gcc version 6.3.0 20170516 (Debian 6.3.0-18) 
clang version 3.8.1-24 (tags/RELEASE_381/final)
Crew answered 3/3, 2018 at 6:53 Comment(16)
I do get the warning you see from GCC 7.3.0. It is curious that there isn't a warning for a at the same time. That inconsistency points to a bug. For reporting it to the GCC team, you can lose the header and the printf() and make it a general function rather than main so that your preprocessed code is minimal. I compiled with -std=c11, too, rather than -std=c99.Singlet
@JonathanLeffler, yes, no warning for a, and also there is no warning if the compound literal is applied to the last member of a structCrew
Points to mention in the bug report.Singlet
No-one spotted it before — that's all. Note that the parentheses around the compound literal are not needed. The compound literal seems to be a part of the bug; using struct T t = {.b = &t.a }; doesn't generate the warning, for example. A one-element array (compound literal) is sufficient, too. It also seems to be "only the element after the one initialized with the compound literal". Add int d; after c and there's no complaint about d. (Add more integers before or after, and it is still just the one element after the compound literal that gets the complaint.)Singlet
@JonathanLeffler.: Well it always complains for the last desig initializer if there is member after it. And if the last desig initializer has nothing after it - it won't complain. For example: struct T { int a; int *b; int c; int *e; /* int f; */ }; and struct T t = {.b = ((int []){1, 1}), .e=((int []){2,3})}; this won't. But remove the comment it will about e not about b anymore.Cyr
I adapted the code in the question to: struct T { int a; int *b; int c; }; struct T foo(int bar); struct T foo(int bar) { struct T t = {.b = (int[]){1}}; t.c = bar; return t; } which can be preprocessed without doing more than adding for #line directives (except that the line is left out). Which makes a close to minimal reproduction. I compile with gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -c diw71.c ('diw' — designated initializers warning; choose your own name).Singlet
@JonathanLeffler.: So what is the general procedure after bug being raised? Also curious (I am quite sure there is someone) if there is someone from gcc team here!. (S)he might give a better overview over this.Cyr
Follow the rules at the GCC site on How to report bugs — one of which is that you're required to submit the preprocessed source, so minimizing the headers required to produce the problem minimizes the size of the bug report. Think MCVE on steroids!Singlet
@JonathanLeffler, thanks, I'll report this to gccCrew
@KeineLust.: Hope you can post in comment the bug number raised so that we can follow the discussion.Cyr
@coderredoc, Jonathan: gcc.gnu.org/bugzilla/show_bug.cgi?id=84685Crew
@KeineLust.: Awesome. All the very best.Cyr
So do we think it should or shouldn't warn? After all there are missing initializers (not all of the fields are given initializers) , and that is the entire purpose of this warning flagBorough
@M. M even if that is the purpose of the flag, the rest of the members should be initialized automatically so there is no need of emitting a warning, isn't it?Crew
My code is affected by this annoying bug too. Note though that you can suppress the warnings on a per file basis with #pragma GCC diagnostic ignored "-Wmissing-field-initializers" as a (temporary) workaround.Hebraize
See also this GCC bug gcc.gnu.org/bugzilla/show_bug.cgi?id=82283Hussey
F
2

It looks like a gcc "consistency bug", here is the relevant code snippet in gcc/c/c-typeck.c

 7436   /* Warn when some struct elements are implicitly initialized to zero.  */
 7437   if (warn_missing_field_initializers
 7438       && constructor_type
 7439       && TREE_CODE (constructor_type) == RECORD_TYPE
 7440       && constructor_unfilled_fields)
 7441     {
 7442         bool constructor_zeroinit =
 7443          (vec_safe_length (constructor_elements) == 1
 7444           && integer_zerop ((*constructor_elements)[0].value));
 7445
 7446         /* Do not warn for flexible array members or zero-length arrays.  */
 7447         while (constructor_unfilled_fields
 7448                && (!DECL_SIZE (constructor_unfilled_fields)
 7449                    || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
 7450           constructor_unfilled_fields = DECL_CHAIN (constructor_unfilled_fields);
 7451
 7452         if (constructor_unfilled_fields
 7453             /* Do not warn if this level of the initializer uses member
 7454                designators; it is likely to be deliberate.  */
 7455             && !constructor_designated
 7456             /* Do not warn about initializing with ` = {0}'.  */
 7457             && !constructor_zeroinit)
 7458           {
 7459             if (warning_at (input_location, OPT_Wmissing_field_initializers,
 7460                             "missing initializer for field %qD of %qT",
 7461                             constructor_unfilled_fields,
 7462                             constructor_type))
 7463               inform (DECL_SOURCE_LOCATION (constructor_unfilled_fields),
 7464                       "%qD declared here", constructor_unfilled_fields);
 7465           }
 7466     }

The intent of the code appears to be to warn if any attribute constructor has an unfilled-field. The fact that you are not getting a warning on element 'a' is likely the "consistency bug" here.

If -Wextra is intended to turn on the missing initializers warning, then it has. The question is, should the "missing initializers warning" exclude omitted attributes? It seems that gcc and clang disagree about this - and it might be fine for them to?

This may not be the answer you are looking for .. but hope it helps with your understanding of the situation. :). GCC team has a consistency bug, but their code's intent seems to be warn in these cases, whereas clang, empirically, will not.

Fluviatile answered 11/2, 2020 at 15:39 Comment(0)
R
0

Why the warning?

Because -Wmissing-field-initializers is set by -Wextra and you set the latter in the gcc call.

-Wextra is picky, and -Wmissing-field-initializers is not even element of -Wall.

Omitting just some field initializers but not all is a source of error. In an array / struct with has some hundreds elements and you are just initializing some of them, then it's almost impossible for a human to grasp that by just looking at the code.

Rab answered 31/1, 2020 at 11:24 Comment(3)
This warning is simply broken in gcc, see -Wmissing-field-initializer when using designated initializers. As you can see, not omitting any initializer can still get the warning to trigger. That was 5 years ago but gcc trunk exhibits the same bugs still.Barter
I cannot confirm this. Changing the line to struct T t = {.b = ((int []){1, 1}), .c = 1 }; so that c is also initialized, the warning goes away.Rab
Still, the warning is fickle and not to be trusted. Lots of false positives.Barter

© 2022 - 2024 — McMap. All rights reserved.