This fixes PR54824, an ICE in loop structure verification, by avoiding the situation of a BB with no successor and no control statement (such as a noreturn call). This situation leads RTL expansions call to find_many_sub_basic_blocks to connect such block to the "next" block, in this testcase forming a loop which verification rightfully complains about.
My fix is to simply connect such blocks to themselves during execute_fixup_cfg (the place we deal with suddenly appearing noreturn attributes vs. vanishing noreturn properties which is what we have here). Another possibility would be to insert __builtin_unreachable () calls, but I suppose instead of falling through to a random BB at runtime endless looping is nicer. We could also insert __builtin_trap (). As the situation only appears when inlining such a function a place to fix it up would be the inliner as well. Comments? Should find_many_sub_basic_blocks really do what it does here? Or is the CFG in fact "invalid" (but we don't check that in verification)? Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Thanks, Richard. 2012-10-24 Richard Biener <rguent...@suse.de> PR middle-end/54824 * tree-optimize.c (execute_fixup_cfg): Connect blocks with no successor to themselves. * gcc.dg/torture/pr54824.c: New testcase. Index: gcc/tree-optimize.c =================================================================== *** gcc/tree-optimize.c (revision 192760) --- gcc/tree-optimize.c (working copy) *************** execute_fixup_cfg (void) *** 180,185 **** --- 180,199 ---- FOR_EACH_EDGE (e, ei, bb->succs) e->count = (e->count * count_scale + REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE; + + /* If we have a basic-block with no successors that does not + end with a control statement or a noreturn call connect it + to itself. This situation can occur when inlining a noreturn + call that does in fact return. */ + if (EDGE_COUNT (bb->succs) == 0) + { + gimple stmt = last_stmt (bb); + if (!stmt + || (!is_ctrl_stmt (stmt) + && (!is_gimple_call (stmt) + || (gimple_call_flags (stmt) & ECF_NORETURN) == 0))) + make_edge (bb, bb, EDGE_FALLTHRU); + } } if (count_scale != REG_BR_PROB_BASE) compute_function_frequency (); Index: gcc/testsuite/gcc.dg/torture/pr54824.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr54824.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr54824.c (working copy) *************** *** 0 **** --- 1,16 ---- + /* { dg-do compile } */ + /* { dg-options "-w" } */ + + void __attribute__((noreturn)) bar(void) + { + } + + void foo(int i, char *p, char *q) + { + while (*p++) { + if (i) + p++; + if (!*q++) + bar(); + } + }