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();
+   }
+ }

Reply via email to