https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93018

--- Comment #3 from John Drouhard <john at drouhard dot dev> ---
I don't think this is a matter of object lifetime. Passing -fnolifetime-dse or
-flifetime-dse=1 does not change the generated assembly here at all.

As a user of the functions baz1 and baz2, I would expect the returned object to
have identical object representations. Bar's default constructor as well as its
user-defined constructor with the null_t argument should produce identical
objects here. Even if the copy constructor is used to copy from a temporary
object during the return from baz1/baz2, union class types' default copy
constructors copy the object representations (as if memmove is used), so we
should still be seeing a zero-initialized "foo" member.

The assembly generated with -O2, for reference:

    baz1(long long):
        xorl    %eax, %eax
        movl    $0, %edx
        testq   %rdi, %rdi
        cmovg   %rdi, %rdx
        setg    %al
        ret
    baz2(long long):
        xorl    %eax, %eax
        testq   %rdi, %rdi
        jle     .L7
        movb    $1, %al
        movq    %rdi, %rdx
    .L7:
        ret

%rax is the bool member of bar, %rdx is the union member. baz2 is simply not
storing anything in %rdx, so the caller receives an uninitialized value
(instead of zero-initialization) for the union "foo" member.

If I write the following program:

int main() {
    Bar obj = baz2(0);
    printf("%08x\n", *((long long*)&obj.foo));
    return 0;
}

Random garbage is printed out. If I change it to use baz1 instead, 0 is
correctly printed. If I change the optimization level to -O3, 0 is correctly
printed. If I change the implementation of baz2(long long) to unconditionally
return the null sentinel object, 0 is correctly printed. "obj" is also
definitely still alive at this point in the program, so object lifetime is not
the problem.

It seems to only be uninitialized when using the converting constructor in the
return statement, using -O2 optimization, and there is another path in the
function that returns an object where the active union member is not the empty
struct and is initialized.

Reply via email to