https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68470
Mikhail Maltsev <miyuki at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |miyuki at gcc dot gnu.org Component|middle-end |ipa --- Comment #3 from Mikhail Maltsev <miyuki at gcc dot gnu.org> --- A bit simplified testcase: void deallocate(void *); void *a; struct C { virtual void m_fn1(); }; struct D { C *m_fn2() { if (a) __builtin_abort(); } }; D getd(); struct vec_int { int _M_start; ~vec_int() { if (_M_start) deallocate(&_M_start); } }; vec_int *b; struct I { virtual void m_fn3(); }; void I::m_fn3() { if (a) getd().m_fn2()->m_fn1(); b->~vec_int(); } $ cc1plus -O2 test.cc - ICE after fnsplit $ cc1plus -O2 test.cc -fno-checking - ICE in IPA-ICF (like in the original bug report) $ cc1plus -O2 test.cc -fno-devirtualize - OK $ cc1plus -O2 test.cc --param partial-inlining-entry-probability=0 - OK ISTM, this is some IPA-related issue: D::m_fn2 and vec_int::~vec_int are inlined into I::m_fn3. D::m_fn2 (D::operator-> in previous comments) does not return any value (undefined behavior), so gimple_fold_call devirtualizes getd().m_fn2()->m_fn1() into __builtin_unreachable during fwprop1. fnsplit then tries to split I::m_fn3. This is how the function looks before fnsplit: ;; Function virtual void I::m_fn3() (_ZN1I5m_fn3Ev, funcdef_no=4, decl_uid=2299, cgraph_uid=4, symbol_order=6) virtual void I::m_fn3() (struct I * const this) { struct C * D.2356; void * a.0_3; void * a.2_5; struct vec_int * b.1_12; int _14; int * _15; <bb 2>: a.0_3 = a; if (a.0_3 != 0B) goto <bb 3>; else goto <bb 6>; <bb 3>: getd (); a.2_5 = a; if (a.2_5 != 0B) goto <bb 4>; else goto <bb 5>; <bb 4>: __builtin_abort (); <bb 5>: __builtin_unreachable (); <bb 6>: b.1_12 = b; _14 = b.1_12->_M_start; if (_14 != 0) goto <bb 7>; else goto <bb 8>; <bb 7>: _15 = &b.1_12->_M_start; deallocate (_15); <bb 8>: MEM[(struct &)b.1_12] ={v} {CLOBBER}; return; } The splitting pass tries to do this: Splitting function at: Split point at BB 6 header time: 19646 header size: 10 split time: 2491 split size: 6 bbs: 6, 7 SSA names to pass: Introduced new external node (void __builtin_unreachable()/18). ICE probably happens in this part: virtual void I::m_fn3() (struct I * const this) { struct C * D.2356; void * a.0_3; void * a.2_5; <bb 2>: a.0_3 = a; if (a.0_3 != 0B) goto <bb 3>; else goto <bb 6>; <bb 3>: getd (); a.2_5 = a; if (a.2_5 != 0B) goto <bb 4>; else goto <bb 5>; <bb 4>: __builtin_abort (); <bb 5>: __builtin_unreachable (); <bb 6>: I::_ZN1I5m_fn3Ev.part.1 (); MEM[(struct &)_12] ={v} {CLOBBER}; return; }