https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89924
--- Comment #3 from Jan Hubicka <hubicka at gcc dot gnu.org> --- OK, C++ FE can't do that because virtual call is wrapper by foo_virtual_inner. After inlining we see: Determining dynamic type for call: OBJ_TYPE_REF(_5;(struct A)p_2(D)->0) (p_2(D), p_2(D)); Starting walk at: _4 = MEM[(struct A *)p_2(D)]._vptr.A; instance pointer: p_2(D) Outer instance pointer: p_2(D) offset: 0 (bits) vtbl reference: MEM[(struct A *)p_2(D)]._vptr.A No dynamic type change found. Targets of polymorphic call of type 0:struct A token 0 Outer type (dynamic):struct A (or a derived type) offset 0 Speculative outer type:struct Aint (or a derived type) at offset 0 This is partial list; extra targets may be defined in other units. (derived types included) (speculative derived types included) virtual A& Aint::operator+=(const A&)/3 foo_virtual (struct Aint * p) { int (*) () * _4; int (*) () _5; <bb 2> : _4 = MEM[(struct A *)p_2(D)]._vptr.A; _5 = *_4; OBJ_TYPE_REF(_5;(struct A)p_2(D)->0) (p_2(D), p_2(D)); return; } The reason why we do not devirtualize is that only information about Aint is the type of function parameter and we do not believe it implies the type of memory location it points to because there is no read or anything from that pointer before it is casted to struct A* and pointer of a given type does not need to necessarily point to memory location of the same type unless you dereference it. Is it really valid to devirtualize here?