Bug 96868 - C++20 designated initializer erroneous warnings
Summary: C++20 designated initializer erroneous warnings
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
: 107434 (view as bug list)
Depends on:
Blocks:
 
Reported: 2020-08-31 12:57 UTC by Matt Godbolt
Modified: 2024-04-08 04:21 UTC (History)
10 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matt Godbolt 2020-08-31 12:57:39 UTC
The following code, with -Wall -Wextra, GCC 10.x or trunk, -std=c++20:

```
struct MyObj {
    MyObj();
};

struct Test {
    int a{};
    MyObj obj;
};

Test t() {
    Test t{.a = 1};

    return t;
}

```

Creates a warning:

```
<source>: In function 'Test t()':

<source>:11:18: warning: missing initializer for member 'Test::obj' [-Wmissing-field-initializers]
   11 |     Test t{.a = 1};
      |                  ^
```

The "obj" is not missing initialization: the generated code correctly calls MyObj::MyObj().

clang issues no diagnostic on the same code (even with -Weverything).

May be a duplicate of bug #82283 or bug #84685, but those have far more complex-looking initialiser lists.

CE link: https://godbolt.org/z/b75P6r
Comment 1 Marek Polacek 2020-09-01 01:11:37 UTC
I think the warning is correct, Test::obj here is initialized from {}, but that's not what the user might intend.
Comment 2 Matt Godbolt 2020-09-01 02:47:03 UTC
Thanks: I was confused (as I think will many folks be). The examples for designated initialisers in C++20 on cppreference cite this behaviour as being useful^. Of course I understand it can be misused, and this indeed a non-default warning. Thanks for taking the time to reply!

--matt

^: https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers
Comment 3 Jonathan Wakely 2021-11-22 09:35:55 UTC
(In reply to Matt Godbolt from comment #2)
> Thanks: I was confused (as I think will many folks be).

Approximately everybody is confused by -Wmissing-field-initializers which is why people probably shouldn't use it.

It specifically says the **initializer** is missing, not that initialization is missing. But everybody thinks it's telling them the member is uninitialized.

The manual is at least clear:

> the following code causes such a warning, because "x.h" is implicitly zero

Unfortunately it also says:

> This option does not warn about designated initializers

which might be true for C, but not C++. Should it be true for C++?
Comment 4 Pavel Sergeev 2022-02-10 21:15:32 UTC
(In reply to Jonathan Wakely from comment #3)
> (In reply to Matt Godbolt from comment #2)
> > Thanks: I was confused (as I think will many folks be).
> 
> Approximately everybody is confused by -Wmissing-field-initializers which is
> why people probably shouldn't use it.
> 
> It specifically says the **initializer** is missing, not that initialization
> is missing. But everybody thinks it's telling them the member is
> uninitialized.
> 
> The manual is at least clear:
> 
> > the following code causes such a warning, because "x.h" is implicitly zero
> 
> Unfortunately it also says:
> 
> > This option does not warn about designated initializers
> 
> which might be true for C, but not C++. Should it be true for C++?

Do you see any reasons why it shouldn't?
Comment 5 Andrew Pinski 2022-10-27 14:51:14 UTC
*** Bug 107434 has been marked as a duplicate of this bug. ***
Comment 6 Paweł Bylica 2022-10-29 12:27:49 UTC
The workaround is 

MyObj obj = {};

which at least suggests some inconsistency in the compiler internals.

For me this warning should be disabled in C++ when designated initializers are used and all other fields are value initialized.
Comment 7 Marek Polacek 2023-06-08 18:00:12 UTC
A similar test.  I'm not sure how we want -Wm-f-i to behave here.

#include <optional>

struct A {
	int a;
	std::optional<int> b;
};

int main()
{
    auto x = A {
        .a = 123 // warns
    };
}
Comment 8 GCC Commits 2023-06-09 14:23:04 UTC
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:0f8f1dee851c23bce19977b2531cf69b4da9f88f

commit r14-1657-g0f8f1dee851c23bce19977b2531cf69b4da9f88f
Author: Marek Polacek <polacek@redhat.com>
Date:   Thu Jun 8 13:52:11 2023 -0400

    doc: Clarification for -Wmissing-field-initializers
    
    The manual is incorrect in saying that the option does not warn
    about designated initializers, which it does in C++.  Whether the
    divergence in behavior is desirable is another thing, but let's
    at least make the manual match the reality.
    
            PR c/39589
            PR c++/96868
    
    gcc/ChangeLog:
    
            * doc/invoke.texi: Clarify that -Wmissing-field-initializers doesn't
            warn about designated initializers in C only.
Comment 9 Roland McGrath 2023-08-21 17:44:37 UTC
IMHO there's a good case to be made for never warning for designated initializers, even for fields that have uninitialized default-construction.
When using a designated initializer, `= {.a=value}` doesn't leave any field `b` uninitialized, it initializes it as `= {}` would, i.e. safely zero for base types, etc.  When I write `= {.a=value}` that default-or-zero-initialization of the other fields is exactly what I intended, and I know well that omitted fields in an initializer are different from leaving the fields uninitialized.

Clearly opinions on this vary.  It seems like it merits having separable option configuration: `-Wmissing-field-initializers`, `-Wmissing-designated-field-initializers`. If that flexibility is available, then it's of less concern what the default state with just `-Wmissing-field-initializers` or `-Wextra` is.

The separate question remains whether "missing initializer" vs "missing (explicit) initialization" should also be distinguished differently in the available warning states than what we have today.  I don't have much opinion about that one as long as there's a way for me to say that:
```
struct s { int a, b; };
s foo = {.a=1};
```
is acceptable without warning in C++, even if it requires a different option state than to accept:
```
struct s { int a; int b = 0; };
s foo = {.a=1};
```