https://gcc.gnu.org/bugzilla/show_bug.cgi?id=19808
--- Comment #39 from Richard Biener <rguenth at gcc dot gnu.org> --- (In reply to Jason Merrill from comment #38) > (In reply to Jonathan Wakely from comment #37) > > If you add a > > Y y{}; > > GCC warns about the Y constructor. > > We don't warn about the implicit X constructor because we don't clobber the > object at the beginning of an implicit constructor, because > value-initialization zero-initializes the object before calling the implicit > constructor, and we mustn't clobber that initialization (bug 68006). The > middle end relies on the clobber to know what's uninitialized, so we don't > get the warning here. > > It would be appropriate to give a maybe-uninitialized warning here, though. > I don't know how complicated it would be to do that using the existing > mechanisms. These case are difficult because they involve exported globals which GCC thinks are always initialized. For the testcase only the initializer of x prevails, the constructor of y is discarded before we run the warning machinery. The initializer of x prevails in __static_initialization_and_destruction_0 like _1 = x.x2; x.x1 = _1; which has the aforementioned issue. So for a proper testcase we need calls to the constructors (where we should warn in?) and the constructors prevail. Adding Y y{}; makes Y::Y prevail and as you said we warn about it. IL: Y::Y (struct Y * const this) { int _1; <bb 2> : MEM[(struct &)this_3(D)] ={v} {CLOBBER}; _1 = this_3(D)->y2; this_3(D)->y1 = _1; this_3(D)->y2 = 0; return; so - how do I make X::X used and thus prevail? It looks like it doesn't really exist and the C++ FE even for void foo() { X x{}; } just outputs ;; Function void foo() (null) ;; enabled by -tree-original { struct X x = {.x2=0}; <<cleanup_point struct X x = {.x2=0};>>; <<cleanup_point <<< Unknown tree: expr_stmt x.x1 = x.x2 >>>>>; } which ends up as foo () { struct X x; try { x = {}; _1 = x.x2; x.x1 = _1; } finally { x = {CLOBBER}; } } so there is no uninitialized use. OK, doing void foo() { X x; } shows X::X (struct X * const this) { _1 = this->x2; this->x1 = _1; this->x2 = 0; } foo () { struct X x; try { X::X (&x); } finally { x = {CLOBBER}; } } warning would need inlining of the constructor which only happens after the early warning pass, the late one isn't run at -O0 and with optimization everything of course vanishes.