Created attachment 40063 [details] Minimal testcase that shows the (possible) problem. It seems like g++ (any version) doesn't warn when class members are uninitialized when no optimization is enabled (and at -O0). For -O1, -O2, -O3 we correctly get a warning (On the contrary, clang, any version, reports a warning at any optimization level). struct data { int x=w; int w=10; }; int main() { data d; return d.x; } g++ ub.cpp -Wall -Wextra -std=gnu++1z -O0 => no warning g++ ub.cpp -Wall -Wextra -std=gnu++1z -O1 => ub.cpp: In function 'int main()': ub.cpp:4:10: warning: 'd.data::w' is used uninitialized in this function [-Wuninitialized] data d; for -O2, -O3 we get exactly the same warning.
-Wuninitialized requires optimization to handle this case.
(In reply to Richard Biener from comment #1) > -Wuninitialized requires optimization to handle this case. I see thanks. Considering that I found this bug in our unit tests, I'll simply add -O1 in order to avoid in the future this issue in our code.
There might be a dup of this bug already. Linking against the meta-bug about uninit warnings.
Reconfirmed with GCC 11. GCC does issue -Wuninitialized without optimization on an equivalent test case with an explicit ctor. The difference between the two ctors is that B's has a clobber: $ cat pr78391.C && PRED_DUMP=euninit gcc -S -Wall pr78391.C struct A { int x = w; int w = 10; }; int f () { A a; return a.x; } struct B { int x, w; B (): x(w), w (10) { } }; int g () { B b; return b.x; } void A::A (struct A * const this) { int _1; <bb 2> : # VUSE <.MEM_2(D)> <<< no clobber _1 = this_3(D)->w; <<< -Wuninitialized # .MEM_4 = VDEF <.MEM_2(D)> this_3(D)->x = _1; # .MEM_5 = VDEF <.MEM_4> this_3(D)->w = 10; # VUSE <.MEM_5> return; } int f () { struct A a; int D.2439; int _3; <bb 2> : # .MEM_2 = VDEF <.MEM_1(D)> A::A (&a); # VUSE <.MEM_2> _3 = a.x; # .MEM_4 = VDEF <.MEM_2> a ={v} {CLOBBER}; <bb 3> : <L1>: # VUSE <.MEM_4> return _3; } void B::B (struct B * const this) { int _1; <bb 2> : # .MEM_4 = VDEF <.MEM_2(D)> *this_3(D) ={v} {CLOBBER}; <<< clobber here # VUSE <.MEM_4> _1 = this_3(D)->w; <<< -Wuninitialized # .MEM_5 = VDEF <.MEM_4> this_3(D)->x = _1; # .MEM_6 = VDEF <.MEM_5> this_3(D)->w = 10; # VUSE <.MEM_6> return; } pr78391.C: In constructor ‘B::B()’: pr78391.C:9:30: warning: ‘*this.B::w’ is used uninitialized [-Wuninitialized] 9 | struct B { int x, w; B (): x(w), w (10) { } }; | ^ int g () { struct B b; int D.2442; int _3; <bb 2> : # .MEM_2 = VDEF <.MEM_1(D)> B::B (&b); # VUSE <.MEM_2> _3 = b.x; # .MEM_4 = VDEF <.MEM_2> b ={v} {CLOBBER}; <bb 3> : <L1>: # VUSE <.MEM_4> return _3; }
So the missing warning seems like it might be due to a bug in the C++ front end.
In bug 19808 comment #38 Jason explains why the CLOBBER isn't present in the constructor, so that's not a bug. In light of that, I'm not sure the request can be implemented without introducing what are strictly speaking false positives like those Clang suffers from. In the test case below, the global a is implicitly zeroed out first and then its members are explicitly assigned, so there is no uninitialized read. At the same time, I suspect the result of this initialization is probably not going to be what the author intended, and so warning on it regardless might actually be useful (admittedly, issuing -Wuninitialized in this case would be a bit misleading). So with that, -Wuninitialized or -Wmaybe-uninitialized in the middle end could be probably enhanced to detect this pattern of intialization dependencies. Marek submitted a C++ patch for a subset of pr19808 last November but I'm not sure it handled this case. The patch was also not approved as Jason's preference was to detect these things in the middle end. So let me reassign this back to the middle end and try to remember to get to it for GCC 12. $ cat t.C && clang -S t.C struct A { int x = w; int w = 10; }; A a; t.C:1:20: warning: field 'w' is uninitialized when used here [-Wuninitialized] struct A { int x = w; int w = 10; }; ^ t.C:3:3: note: in implicit default constructor for 'A' first required here A a; ^ t.C:1:8: note: during field initialization in the implicit default constructor struct A { int x = w; int w = 10; }; ^ 1 warning generated.
Patch for pr19808: https://gcc.gnu.org/pipermail/gcc-patches/2020-November/559162.html
(In reply to Martin Sebor from comment #7) > Patch for pr19808: > https://gcc.gnu.org/pipermail/gcc-patches/2020-November/559162.html That's fixed now.
This has been improved in GCC 12 but GCC still doesn't diagnose the original test case at -O0. It seems that it should be able to, either in the C++ front end or even in the middle end. I'm not working on this anymore.
GCC 12.1 is being released, retargeting bugs to GCC 12.2.
GCC 12.2 is being released, retargeting bugs to GCC 12.3.
GCC 12.3 is being released, retargeting bugs to GCC 12.4.