This is an archive of the discontinued LLVM Phabricator instance.

[clang] Report missing designated initializers in C++
ClosedPublic

Authored by Fznamznon on Aug 14 2023, 7:50 AM.

Details

Summary

Prior to this change clang didn't emit missing-field-initializers
warning for designated initializers. The comments say that it is done to
match gcc behavior. However, gcc behaves so only for C. For C++ warnings
are emitted.

Fixes https://github.com/llvm/llvm-project/issues/56628

Diff Detail

Event Timeline

Fznamznon created this revision.Aug 14 2023, 7:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 14 2023, 7:50 AM
Fznamznon requested review of this revision.Aug 14 2023, 7:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 14 2023, 7:50 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

Thank you for working on this! The changes should come with a release note.

I think the diagnostic is triggered a bit to aggressively in the case where there is an invalid initializer for a field -- we'll claim there is no initializer in that case, but that effectively duplicates the diagnostics without adding anything actionable for the user to do (once they fix the initialization, both diagnostics go away). Can we silence the diagnostic in these cases?

clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
64

This second warning seems wrong, there is an initializer for a, it's just not a valid one.

72–79

This warning is quite wrong, there's a whole pile of initializers for x. :-)

228

I also think this one is wrong.

Fznamznon updated this revision to Diff 551051.Aug 17 2023, 2:11 AM

Add a release note, apply feedback:

  • Do not report invalid initializers as missing
  • Fix wrong warning if record has bitfields
Fznamznon marked 3 inline comments as done.Aug 17 2023, 2:13 AM

Thank you for working on this! The changes should come with a release note.

Thanks for feedback, I added a release note.

Can we silence the diagnostic in these cases?

And this is done.

Tangentially related: Now that we have this InitializedFields set, would it be easy to add a warning for double-initialization of fields (that would also trigger in C)?

Tangentially related: Now that we have this InitializedFields set, would it be easy to add a warning for double-initialization of fields (that would also trigger in C)?

Isn't a warning like this already in place - https://godbolt.org/z/E1dGsY3ze ? Or you meant something else?

Tangentially related: Now that we have this InitializedFields set, would it be easy to add a warning for double-initialization of fields (that would also trigger in C)?

Isn't a warning like this already in place - https://godbolt.org/z/E1dGsY3ze ? Or you meant something else?

Yes, thanks. Someone else was asking for this feature a while back but looks like they didn't notice it already exists.

This revision is now accepted and ready to land.Aug 18 2023, 5:49 AM
Fznamznon updated this revision to Diff 551924.Aug 21 2023, 1:04 AM

Rebase to maybe pass precommit

The failure is unrelated, since the patch doesn't touch modules and I've seen the test failing for other patches as well.

This revision was landed with ongoing or failed builds.Aug 21 2023, 2:07 AM
This revision was automatically updated to reflect the committed changes.

is there any way to suppress this for a specific field? (I believe) I'm seeing user code where a field is intentionally not being initialized

is there any way to suppress this for a specific field? (I believe) I'm seeing user code where a field is intentionally not being initialized

Hmmm, so they're wanting to rely on the implicit initialization (http://eel.is/c++draft/dcl.init#aggr-5)? It seems a bit odd to pass -Wmissing-field-initializers and then rely on implicit initialization of fields, so some more details might be helpful.

ah I thought this was in -Wall but it's not

the struct is

struct Foo {
  const void* buffer;
  uint32_t capacity;
  uint32_t reserved;
};

where reserved isn't explicitly initialized. that seems like reasonable code, but I suppose we can just explicitly initialize reserved here

ah I thought this was in -Wall but it's not

the struct is

struct Foo {
  const void* buffer;
  uint32_t capacity;
  uint32_t reserved;
};

where reserved isn't explicitly initialized. that seems like reasonable code, but I suppose we can just explicitly initialize reserved here

Thank you for sharing the use case, that's actually a rather interesting one! Leaving the identifier reserved off the field would trigger a -Wmissing-declarations diagnostic (which is on by default). You can leave the field named and use an in-class initializer for it and that should silence the diagnostic. But I kind of wonder if we want to special case fields named reserved or similar (wReserved, reserved2, etc)?

phosek added a subscriber: phosek.Aug 21 2023, 10:55 AM

Note that there's an ongoing discussion on the GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96868 whether -Wmissing-field-initializers should apply to both C and C++ or just C.

ah I thought this was in -Wall but it's not

the struct is

struct Foo {
  const void* buffer;
  uint32_t capacity;
  uint32_t reserved;
};

where reserved isn't explicitly initialized. that seems like reasonable code, but I suppose we can just explicitly initialize reserved here

FWIW, if this is the specific piece of code that led me to this conversation, that declaration is in a header which at least in theory is supposed to remain compatible with C. It's inside extern "C" { ... } even. We can't add explicit initialize reserved and keep the definition C comaptible.

Note that there's an ongoing discussion on the GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96868 whether -Wmissing-field-initializers should apply to both C and C++ or just C.

Thank you for posting this! I'm with @jwakely on this: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96868#c3 -- the warning is for people who want to be told they've not explicitly specified all of the initializers, it is not for telling you "this hasn't been initialized". I think the desire makes as much sense in C++ as it does in C, but this is more of a style warning than a correctness warning.

ah I thought this was in -Wall but it's not

the struct is

struct Foo {
  const void* buffer;
  uint32_t capacity;
  uint32_t reserved;
};

where reserved isn't explicitly initialized. that seems like reasonable code, but I suppose we can just explicitly initialize reserved here

FWIW, if this is the specific piece of code that led me to this conversation, that declaration is in a header which at least in theory is supposed to remain compatible with C. It's inside extern "C" { ... } even. We can't add explicit initialize reserved and keep the definition C comaptible.

Ouch, yeah, that does make it a challenge. But why is -Wmissing-field-initializers enabled in the first place for the code? It seems like there are fields you *don't* want explicit initialization for, so perhaps the answer is to disable the diagnostic for those types?

Note that there's an ongoing discussion on the GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96868 whether -Wmissing-field-initializers should apply to both C and C++ or just C.

Thank you for posting this! I'm with @jwakely on this: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96868#c3 -- the warning is for people who want to be told they've not explicitly specified all of the initializers, it is not for telling you "this hasn't been initialized". I think the desire makes as much sense in C++ as it does in C, but this is more of a style warning than a correctness warning.

ah I thought this was in -Wall but it's not

the struct is

struct Foo {
  const void* buffer;
  uint32_t capacity;
  uint32_t reserved;
};

where reserved isn't explicitly initialized. that seems like reasonable code, but I suppose we can just explicitly initialize reserved here

FWIW, if this is the specific piece of code that led me to this conversation, that declaration is in a header which at least in theory is supposed to remain compatible with C. It's inside extern "C" { ... } even. We can't add explicit initialize reserved and keep the definition C comaptible.

Ouch, yeah, that does make it a challenge. But why is -Wmissing-field-initializers enabled in the first place for the code? It seems like there are fields you *don't* want explicit initialization for, so perhaps the answer is to disable the diagnostic for those types?

It's an unfortunate configuration. We saw this in Chrome where some projects were manually setting -Wmissing-field-initializers, but when building for Fuchsia, some Fuchsia system headers had this code. We can just suppress this for all Fuchsia builds, I think that's fine.

rsmith added a subscriber: rsmith.Oct 26 2023, 2:51 PM

This change has introduced a false positive for anonymous union members:

struct A {
    int m;
    union { int n = 0; };
};

A a = A{.m = 0};

now produces a false positive warning saying that the anonymous union member in A is uninitialized.

This change has introduced a false positive for anonymous union members:

struct A {
    int m;
    union { int n = 0; };
};

A a = A{.m = 0};

now produces a false positive warning saying that the anonymous union member in A is uninitialized.

Thanks! I've created https://github.com/llvm/llvm-project/issues/70444 and will figure something to fix this asap.