Hi, this patch fixes ICE in ipa-devirt that is caused by get_binfo_at_offset reporting NULL for a valid query. This is because how virtual inheritance is represented.
Here we have chain A<-B<-C where A is a virtual base. We look for A within C that is there at offset 64. On this query get_binfo_at_offset walks fields of C and it finds A, it matches it and it looks for BINFO. The catch is that BINFO represents only direct bases and A is not direct base. Conseuqentely it returns NULL. In the past this only prevented us from devirtualizing here, now we ICE, since ipa-devirt depends on fact that it can resolve all possible queries. get_binfo_at_offset needs to make a hop through B. This patch is kind of minimal change needed to get get_binfo_at_offset to look into B: when base is not found, it finds a base that contains A and dives into it. I plan to rewrite the function for next stage1: the walk of fields is already done by ipa-devirt separately, so it really should do only BINFO walk. For that we however need to retire other uses of get_binfo_at_offset that are still used by ipa-devirt. That is on the TODO list to switch it to be basically a propagation engine for ipa-devirt's polymorphic_call_context structures. (basically I want to have one local pass doing non-trivial propagation and one IPA pass propagation across function boundaries, both sharing polymorphic_call_context structure and a lattice operations) Bootstrapped/regtested x86_64-linux, OK with the testcase? struct A { virtual void foo () = 0; void bar () { foo (); } bool a; }; struct B : public virtual A { virtual void foo (); }; struct C : public B { C (); }; void baz () { C c; c.bar (); } PR ipa/59775 * tree.c (get_binfo_at_offset): Look harder for virtual bases. Index: tree.c =================================================================== --- tree.c (revision 206617) +++ tree.c (working copy) @@ -11995,16 +11995,35 @@ get_binfo_at_offset (tree binfo, HOST_WI represented in the binfo for the derived class. */ else if (offset != 0) { - tree base_binfo, found_binfo = NULL_TREE; - for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - if (types_same_for_odr (TREE_TYPE (base_binfo), TREE_TYPE (fld))) - { - found_binfo = base_binfo; - break; - } - if (!found_binfo) - return NULL_TREE; - binfo = found_binfo; + tree base_binfo, binfo2 = binfo; + + /* Find BINFO corresponding to FLD. This is bit harder + by a fact that in virtual inheritance we may need to walk down + the non-virtual inheritance chain. */ + while (true) + { + tree containing_binfo = NULL, found_binfo = NULL; + for (i = 0; BINFO_BASE_ITERATE (binfo2, i, base_binfo); i++) + if (types_same_for_odr (TREE_TYPE (base_binfo), TREE_TYPE (fld))) + { + found_binfo = base_binfo; + break; + } + else + if (BINFO_OFFSET (base_binfo) - BINFO_OFFSET (binfo) < pos + && (!containing_binfo + || (BINFO_OFFSET (containing_binfo) + < BINFO_OFFSET (base_binfo)))) + containing_binfo = base_binfo; + if (found_binfo) + { + binfo = found_binfo; + break; + } + if (!containing_binfo) + return NULL_TREE; + binfo2 = containing_binfo; + } } type = TREE_TYPE (fld);