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

--- Comment #4 from Vadim Zeitlin <vz-gcc at zeitlins dot org> ---
Sorry, I've somehow forgot to provide the example, but here it is in its most
minimal form:

namespace {
    struct AnonB {
        virtual bool foo() const = 0;
        virtual ~AnonB() {}
    };
}

struct RealB {
    virtual bool foo() const = 0;
    virtual ~RealB() {}
};

AnonB* create()
{
    struct D : RealB {
        virtual bool foo() const { return true; }
    };

    return reinterpret_cast<AnonB*>(new D);
}

int main() {
    return create()->foo(); // please ignore the memory leak here
}

Compiling this without optimizations "works", while with -O2 or -O3 the program
terminates due to a pure virtual function call and the code looks just like
this:

(gdb) disassemble
Dump of assembler code for function main():
=> 0x0000000000400670 <+0>:     mov    edi,0x8
   0x0000000000400675 <+5>:     sub    rsp,0x8
   0x0000000000400679 <+9>:     call   0x400660 <_Znwm@plt>
   0x000000000040067e <+14>:    mov    QWORD PTR [rax],0x4008b0
   0x0000000000400685 <+21>:    mov    rdi,rax
   0x0000000000400688 <+24>:    call   0x400650 <__cxa_pure_virtual@plt>
End of assembler dump.

Again, I understand that the program invokes undefined behaviour and the
compiler is perfectly in its right to do what it does. But in practice casts
such as above are always required when using COM with its QueryInterface() and
it would be nice if the compiler could warn about this devirtualization because
it can never be intentional, AFAICS.

Also notice that giving the namespace a name (and replacing AnonB with
NS::AnonB) also prevents the devirtualization from happening.

Finally, I've tested this with (the originally reported) 4.9, 5.5, 6.4 and 7.2
and the behaviour is almost the same for all of them, but 7.2 does give this
warning

puredevirt.cpp: In function β€˜int main()’:
puredevirt.cpp:24:25: warning: β€˜<anonymous>’ is used uninitialized in this
function [-Wuninitialized]
     return create()->foo();
            ~~~~~~~~~~~~~^~

I guess this already partially addresses my request because at least there is a
warning, but its wording is not especially clear. Looking at the disassembly

(gdb) disassemble
Dump of assembler code for function main:
=> 0x0000555555554600 <+0>:     sub    rsp,0x8
   0x0000555555554604 <+4>:     mov    edi,0x8
   0x0000555555554609 <+9>:     call   0x5555555545e0 <_Znwm@plt>
   0x000055555555460e <+14>:    call   0x5555555545d0 <__cxa_pure_virtual@plt>
End of assembler dump.

it becomes clear that it's the object on which foo() is called which is not
initialized (i.e. it doesn't even bother loading its address before calling
__cxa_pure_virtual, which makes sense), but it's not really obvious from just
the error message.

Reply via email to