Hi! If TREE_BINFO has BV_VCALL_INDEX set, this needs to be dynamically adjusted, but none of the callers are prepared to handle that. Thus, this patch makes devirtualization give up in those cases.
Bootstrapped/regtested on x86_64-linux and i686-linux, trunk and 4.6. On the trunk the testcase ICEs before and after the patch in some new callgraph checking (added today or so, Honza?), on the branch it works just fine. Ok for trunk/4.6? 2011-04-18 Jakub Jelinek <ja...@redhat.com> PR middle-end/48661 * gimple-fold.c (gimple_get_virt_method_for_binfo): Return NULL if TREE_TYPE (v) is non-NULL. * gimple-fold.c (gimple_get_virt_method_for_binfo): Renamed from gimple_get_virt_mehtod_for_binfo. * gimple.h (gimple_get_virt_method_for_binfo): Likewise. * ipa-cp.c (ipcp_process_devirtualization_opportunities): Adjust callers. * ipa-prop.c (try_make_edge_direct_virtual_call): Likewise. * g++.dg/torture/pr48661.C: New test. --- gcc/gimple-fold.c.jj 2011-03-14 14:12:15.000000000 +0100 +++ gcc/gimple-fold.c 2011-04-18 18:35:22.000000000 +0200 @@ -1374,7 +1374,7 @@ gimple_fold_builtin (gimple stmt) is a thunk (other than a this adjustment which is dealt with by DELTA). */ tree -gimple_get_virt_mehtod_for_binfo (HOST_WIDE_INT token, tree known_binfo, +gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo, tree *delta, bool refuse_thunks) { HOST_WIDE_INT i; @@ -1393,6 +1393,10 @@ gimple_get_virt_mehtod_for_binfo (HOST_W v = TREE_CHAIN (v); } + /* If BV_VCALL_INDEX is non-NULL, give up. */ + if (TREE_TYPE (v)) + return NULL_TREE; + fndecl = TREE_VALUE (v); node = cgraph_get_node_or_alias (fndecl); if (refuse_thunks --- gcc/gimple.h.jj 2011-03-14 14:12:15.000000000 +0100 +++ gcc/gimple.h 2011-04-18 18:35:40.000000000 +0200 @@ -892,7 +892,7 @@ unsigned get_gimple_rhs_num_ops (enum tr gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL); const char *gimple_decl_printable_name (tree, int); bool gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace); -tree gimple_get_virt_mehtod_for_binfo (HOST_WIDE_INT, tree, tree *, bool); +tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree, tree *, bool); void gimple_adjust_this_by_delta (gimple_stmt_iterator *, tree); /* Returns true iff T is a valid GIMPLE statement. */ extern bool is_gimple_stmt (tree); --- gcc/ipa-cp.c.jj 2011-04-13 12:39:28.000000000 +0200 +++ gcc/ipa-cp.c 2011-04-18 18:36:11.000000000 +0200 @@ -1242,7 +1242,7 @@ ipcp_process_devirtualization_opportunit { tree binfo = VEC_index (tree, info->params[param_index].types, j); tree d; - tree t = gimple_get_virt_mehtod_for_binfo (token, binfo, &d, true); + tree t = gimple_get_virt_method_for_binfo (token, binfo, &d, true); if (!t) { --- gcc/ipa-prop.c.jj 2011-04-13 12:39:28.000000000 +0200 +++ gcc/ipa-prop.c 2011-04-18 18:36:30.000000000 +0200 @@ -1730,7 +1730,7 @@ try_make_edge_direct_virtual_call (struc type = ie->indirect_info->otr_type; binfo = get_binfo_at_offset (binfo, ie->indirect_info->anc_offset, type); if (binfo) - target = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta, true); + target = gimple_get_virt_method_for_binfo (token, binfo, &delta, true); else return NULL; --- gcc/testsuite/g++.dg/torture/pr48661.C.jj 2011-04-18 18:50:49.000000000 +0200 +++ gcc/testsuite/g++.dg/torture/pr48661.C 2011-04-18 18:50:11.000000000 +0200 @@ -0,0 +1,77 @@ +// PR middle-end/48661 +// { dg-do run } + +extern "C" void abort (); + +__attribute__((noinline)) +double +foo (double x, double y) +{ + asm volatile ("" : : : "memory"); + return x + y; +} + +__attribute__((noinline, noclone)) +void +bar (int x) +{ + if (x != 123) + abort (); +} + +struct A +{ + double a1, a2; +}; + +struct B +{ + virtual int m () const = 0 ; +}; + +struct C +{ + virtual ~C () {} +}; + +struct D : virtual public B, public C +{ + explicit D (const A &x) : d(123) { foo (x.a2, x.a1); } + int m () const { return d; } + int d; +}; + +struct E +{ + E () : d(0) {} + virtual void n (const B &x) { d = x.m (); x.m (); x.m (); } + int d; +}; + +void +test () +{ + A a; + a.a1 = 0; + a.a2 = 1; + E p; + D q (a); + const B &b = q; + bar (b.m ()); + p.n (b); + bar (p.d); +} + +void +baz () +{ + A a; + D p2 (a); +} + +int +main () +{ + test (); + return 0; +} Jakub