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.