Bug 111771 - Incorrect "is used uninitialized" warning, as if zero-initialization didn't propagate through user-provided default constructors
Summary: Incorrect "is used uninitialized" warning, as if zero-initialization didn't p...
Status: RESOLVED DUPLICATE of bug 108993
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 13.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic, wrong-code
Depends on:
Blocks:
 
Reported: 2023-10-11 14:42 UTC by Egor
Modified: 2023-10-12 16:34 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 13.2.1, 7.5.0
Last reconfirmed: 2023-10-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Egor 2023-10-11 14:42:04 UTC
Here's the code. GCC with `-Wall -O3` warns that `x` is used uninitialized, even though it's zeroed.

    struct A
    {
        A() {}
        int x;
    };

    struct B : A {};

    int main()
    {
        B b = B();
        return b.x;
    }

Since `B` doesn't have a user-provided default constructor, value-initializing it like this performs zero-initialization, which propagates recursively (http://eel.is/c++draft/dcl.dcl#dcl.init.general-6.2) over all members, zeroing everything. Yet GCC incorrectly warns about `x` being uninitialized.
Comment 1 Andrew Pinski 2023-10-11 17:17:10 UTC
Did you miss that the implicit B constructor will just call A's constructor ?
Comment 2 Egor 2023-10-12 05:17:13 UTC
Before calling A's constructor, it will zero `x` anyway.

I was also surprised when I learned this yesterday, but it's what the standard says.

1. `()` performs value-initialization on B: http://eel.is/c++draft/dcl.dcl#dcl.init.general-16.4

2. Since B's ctor is not user-provided, that resolves to zero-initialization followed by default-initialization: http://eel.is/c++draft/dcl.dcl#dcl.init.general-9.1.2

3. Zero-initialization of B propagates to A, then propagates to `x` and zeroes it, regardless of A having a user-provided constructor or not: http://eel.is/c++draft/dcl.dcl#dcl.init.general-6.2

4. Lastly default-initialization of B calls B's constructor and in turn calls A's constructor.
Comment 3 Richard Biener 2023-10-12 07:29:33 UTC
We have

int main ()
{
  int D.2848;

  {
    struct B b;
  
    try
      {
        b.D.2778.x = 0;
        B::B (&b);
        D.2848 = b.D.2778.x;
        return D.2848;

but:

void B::B (struct B * const this)
{
  _1 = &this->D.2778;
  A::A (_1);
}


void A::A (struct A * const this)
{
  *this = {CLOBBER};

so A::A invoked by B::B invalidates the initialized storage.  Maybe a
"different" B::B should have been called (one not invoking A::A?).
Comment 4 Richard Biener 2023-10-12 07:30:02 UTC
-fno-lifetime-dse fixes the issue (and the diagnostic)
Comment 5 Andrew Pinski 2023-10-12 16:34:46 UTC
Dup of bug 108993.

*** This bug has been marked as a duplicate of bug 108993 ***