https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69777
Eric Gallager <egallager at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |NEW Resolution|INVALID |--- Known to fail| |4.9.1, 5.5.0, 6.4.0, 7.2.1, | |8.0 --- Comment #5 from Eric Gallager <egallager at gcc dot gnu.org> --- (In reply to Vadim Zeitlin from comment #4) > 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. Reopening; confirmed that the example only prints the -Wuninitialized warning, but I get different disassembly, although that's probably due to target differences. (my gdb doesn't disassemble it properly when optimized, but if I use -save-temps and examine the assembly, I can see that it still contains the call to __cxa_pure_virtual at least)