This fixes PR57036 which is inlining of a ECF_LEAF function (which cannot perform abnormal control flow into the caller) which in turn has a function call that might abnormally transfer control flow. The fix is to avoid adding _extra_ abnormal edges from such calls to possible receivers in the caller but leave existing abnormal edges in the copied callee in place.
There isn't a way to otherwise honor both always_inline and leaf as we might transform the caller function body in a way that would be invalid if it were allowed to transfer control flow abnormally. It's still valid to have abnormal control flow transfer completely inside a leaf function of course and we may not destroy abnormal edges resulting from that. Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard. 2013-04-23 Richard Biener <rguent...@suse.de> PR middle-end/57036 * tree-inline.c (copy_edges_for_bb): Add can_make_abnormal_goto parameter, only add abnormal goto edges from the copied body if the call could perform abnormal gotos. (copy_cfg_body): Adjust. * gcc.dg/torture/pr57036-1.c: New testcase. * gcc.dg/torture/pr57036-2.c: Likewise. Index: gcc/tree-inline.c =================================================================== *** gcc/tree-inline.c (revision 198190) --- gcc/tree-inline.c (working copy) *************** update_ssa_across_abnormal_edges (basic_ *** 1866,1872 **** debug stmts are left after a statement that must end the basic block. */ static bool ! copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb) { basic_block new_bb = (basic_block) bb->aux; edge_iterator ei; --- 1866,1873 ---- debug stmts are left after a statement that must end the basic block. */ static bool ! copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb, ! bool can_make_abnormal_goto) { basic_block new_bb = (basic_block) bb->aux; edge_iterator ei; *************** copy_edges_for_bb (basic_block bb, gcov_ *** 1921,1927 **** into a COMPONENT_REF which doesn't. If the copy can throw, the original could also throw. */ can_throw = stmt_can_throw_internal (copy_stmt); ! nonlocal_goto = stmt_can_make_abnormal_goto (copy_stmt); if (can_throw || nonlocal_goto) { --- 1922,1932 ---- into a COMPONENT_REF which doesn't. If the copy can throw, the original could also throw. */ can_throw = stmt_can_throw_internal (copy_stmt); ! /* If the call we inline cannot make abnormal goto do not add ! additional abnormal edges but only retain those already present ! in the original function body. */ ! nonlocal_goto ! = can_make_abnormal_goto && stmt_can_make_abnormal_goto (copy_stmt); if (can_throw || nonlocal_goto) { *************** copy_cfg_body (copy_body_data * id, gcov *** 2270,2279 **** last = last_basic_block; /* Now that we've duplicated the blocks, duplicate their edges. */ FOR_ALL_BB_FN (bb, cfun_to_copy) if (!blocks_to_copy || (bb->index > 0 && bitmap_bit_p (blocks_to_copy, bb->index))) ! need_debug_cleanup |= copy_edges_for_bb (bb, count_scale, exit_block_map); if (new_entry) { --- 2275,2287 ---- last = last_basic_block; /* Now that we've duplicated the blocks, duplicate their edges. */ + bool can_make_abormal_goto + = id->gimple_call && stmt_can_make_abnormal_goto (id->gimple_call); FOR_ALL_BB_FN (bb, cfun_to_copy) if (!blocks_to_copy || (bb->index > 0 && bitmap_bit_p (blocks_to_copy, bb->index))) ! need_debug_cleanup |= copy_edges_for_bb (bb, count_scale, exit_block_map, ! can_make_abormal_goto); if (new_entry) { Index: gcc/testsuite/gcc.dg/torture/pr57036-1.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr57036-1.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr57036-1.c (revision 0) *************** *** 0 **** --- 1,16 ---- + /* { dg-do compile } */ + + extern void g (void); + extern __inline __attribute__ ((__always_inline__,__leaf__)) + f () + { + g (); + } + struct __jmp_buf_tag *b; + int jpgDecode_convert (unsigned i) + { + if (i != 0) + f (); + read_buf_open (); + return _setjmp (b); + } Index: gcc/testsuite/gcc.dg/torture/pr57036-2.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr57036-2.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr57036-2.c (revision 0) *************** *** 0 **** --- 1,25 ---- + /* { dg-do compile } */ + + int j_; + int jpgDecode_convert (unsigned i) + { + __label__ label; + int j; + + inline void __attribute__((always_inline,leaf)) f(void) + { + g(); + } + + void __attribute__((noinline)) read_buf_open (void) + { + goto label; + } + + if (i != 0) + f (); + j = j_; + read_buf_open (); + label: + return j; + }