http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59226
--- Comment #7 from Jan Hubicka <hubicka at gcc dot gnu.org> --- This testcase manifest the other virtual inehritance problem. Here it is algorithm of get_binfo_at_offset that first walks fields of a structure and if it finds corresponding field at given offset, it walks bases of structure to dive recursively into. I am speaking of testcase in #1 Here get_binfo_at_offset is called on binfo of class D looking for class A at offset 0. The binfo of class D itself is one nested in E. The inheritance tree looks as follows: A B v/v\ / (v marks virtual inheritance) C D \ / E ipa-devirt does not expect get_binfo_at_offset to fail since it knows D derives A. Now get_binfo_at_offset looks into memory layout of type D. <record_type 0x7ffff76b17e0 D addressable tree_2 needs-constructing type_5 BLK size <integer_cst 0x7ffff753e140 type <integer_type 0x7ffff753c150 bitsizetype> constant 128> unit size <integer_cst 0x7ffff753e160 type <integer_type 0x7ffff753c0a8 sizetype> constant 16> align 64 symtab 0 alias set -1 canonical type 0x7ffff76b17e0 fields <field_decl 0x7ffff769eed8 D.2255 type <record_type 0x7ffff76a87e0 B addressable tree_2 needs-constructing type_5 BLK size <integer_cst 0x7ffff753e0c0 constant 64> unit size <integer_cst 0x7ffff753e0e0 constant 8> align 64 symtab 0 alias set -1 canonical type 0x7ffff76a87e0 fields <field_decl 0x7ffff769e4c0 _vptr.B> context <translation_unit_decl 0x7ffff7546170 D.1> full-name "struct B" needs-constructor X() X(constX&) this=(X&) n_parents=0 use_template=0 interface-unknown pointer_to_this <pointer_type 0x7ffff76a8a80> chain <type_decl 0x7ffff7693ac8 B>> ignored decl_6 BLK file /home/jan/t.C line 13 col 8 size <integer_cst 0x7ffff753e0c0 64> unit size <integer_cst 0x7ffff753e0e0 8> align 64 offset_align 128 offset <integer_cst 0x7ffff753e100 constant 0> bit offset <integer_cst 0x7ffff753e180 constant 0> context <record_type 0x7ffff76b17e0 D> chain <type_decl 0x7ffff76b3170 D type <record_type 0x7ffff76b1888 D> nonlocal decl_4 VOID file /home/jan/t.C line 14 col 1 align 1 context <record_type 0x7ffff76b17e0 D> result <record_type 0x7ffff76b17e0 D> chain <field_decl 0x7ffff76b4098 D.2257>>> context <translation_unit_decl 0x7ffff7546170 D.1> full-name "struct D" needs-constructor X() X(constX&) this=(X&) n_parents=2 use_template=0 interface-unknown pointer_to_this <pointer_type 0x7ffff76b1a80> chain <type_decl 0x7ffff76b30b8 D>> and here it finds B that is a wrong turn and gives up after looking into B. Now if it looked further (gdb) p debug_tree (fld->common.chain->common.chain) <field_decl 0x7ffff76b4098 D.2257 type <record_type 0x7ffff76a8000 A addressable tree_2 needs-constructing type_5 BLK size <integer_cst 0x7ffff753e0c0 constant 64> unit size <integer_cst 0x7ffff753e0e0 constant 8> align 64 symtab 0 alias set -1 canonical type 0x7ffff76a8000 fields <field_decl 0x7ffff769e1c8 _vptr.A type <pointer_type 0x7ffff768ec78> unsigned virtual DI file /home/jan/t.C line 1 col 8 size <integer_cst 0x7ffff753e0c0 64> unit size <integer_cst 0x7ffff753e0e0 8> align 64 offset_align 128 offset <integer_cst 0x7ffff753e100 constant 0> bit offset <integer_cst 0x7ffff753e180 constant 0> context <record_type 0x7ffff76a8000 A> chain <type_decl 0x7ffff7693958 A>> context <translation_unit_decl 0x7ffff7546170 D.1> full-name "struct A" needs-constructor X() X(constX&) this=(X&) n_parents=0 use_template=0 interface-unknown pointer_to_this <pointer_type 0x7ffff76a82a0> chain <type_decl 0x7ffff76938a0 A>> ignored decl_6 BLK file /home/jan/t.C line 13 col 8 size <integer_cst 0x7ffff753e0c0 64> unit size <integer_cst 0x7ffff753e0e0 8> align 64 offset_align 128 offset <integer_cst 0x7ffff753e100 0> bit offset <integer_cst 0x7ffff753e0c0 64> context <record_type 0x7ffff76b17e0 D>> $20 = void here it would find A, but this time at offset 64. So perhaps we are looking for A at wrong offset? Or are we taking wrong vtable? type_binfo is D since it is last on the walk down to A with virtual table attached. Maybe it is because all references to A in D go via C's vtable and we are safe to give up. Or do we need to compensate for offsets here like this? Index: ipa-devirt.c =================================================================== --- ipa-devirt.c (revision 205941) +++ ipa-devirt.c (working copy) @@ -646,8 +646,11 @@ if (types_same_for_odr (type, outer_type)) { - tree inner_binfo = get_binfo_at_offset (type_binfo, - offset, otr_type); + tree inner_binfo = get_binfo_at_offset + (type_binfo, offset + + (tree_to_uhwi (BINFO_OFFSET (type_binfo)) + - tree_to_uhwi (BINFO_OFFSET (binfo))) + * BITS_PER_UNIT, otr_type); /* For types in anonymous namespace first check if the respective vtable is alive. If not, we know the type can't be called. */ if (!flag_ltrans && anonymous) (in single inheritance case this is not needed, since every binfo with non-zero offset must have vtable attached). Other option would be to simply return NULL when inner_binfo is NULL with a comment that this is virtual multiple inheritance case where vtable was already taken care on at different branch of recursion. Jason, what do you think? Markus, I do not have my usual firefox testing setup until christmas. Would be nice to know if the proposed patch works on anything else than this testcase.