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.

Reply via email to