Hi! If the nothrow pass (which is GIMPLE, not IPA pass) determines that the current function can't throw externally, it marks it nothrow. But it fails to adjust self-recursive calls, which might change because of that from possibly throwing to not being able to throw, so we need to cleanup the EH region, purge dead eh edges and adjust CFG if needed.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-04-13 Jakub Jelinek <ja...@redhat.com> PR c++/70641 * ipa-pure-const.c (pass_nothrow::execute): Call maybe_clean_eh_stmt on all recursive call stmts. Return TODO_cleanup_cfg if any dead eh edges have been purged. * g++.dg/opt/pr70641.C: New test. --- gcc/ipa-pure-const.c.jj 2016-04-13 15:53:01.051799840 +0200 +++ gcc/ipa-pure-const.c 2016-04-13 16:03:10.715556547 +0200 @@ -1956,10 +1956,28 @@ pass_nothrow::execute (function *) } node->set_nothrow_flag (true); + + bool cfg_changed = false; + if (self_recursive_p (node)) + FOR_EACH_BB_FN (this_block, cfun) + for (gimple_stmt_iterator gsi = gsi_start_bb (this_block); + !gsi_end_p (gsi); + gsi_next (&gsi)) + if (is_gimple_call (gsi_stmt (gsi))) + { + gimple *g = gsi_stmt (gsi); + tree callee_t = gimple_call_fndecl (g); + if (callee_t + && recursive_call_p (current_function_decl, callee_t) + && maybe_clean_eh_stmt (g) + && gimple_purge_dead_eh_edges (gimple_bb (g))) + cfg_changed = true; + } + if (dump_file) fprintf (dump_file, "Function found to be nothrow: %s\n", current_function_name ()); - return 0; + return cfg_changed ? TODO_cleanup_cfg : 0; } } // anon namespace --- gcc/testsuite/g++.dg/opt/pr70641.C.jj 2016-04-13 16:01:16.381102468 +0200 +++ gcc/testsuite/g++.dg/opt/pr70641.C 2016-04-13 16:01:16.381102468 +0200 @@ -0,0 +1,10 @@ +// PR c++/70641 +// { dg-do compile } +// { dg-options "-O2" } + +void +foo () +{ + try { foo (); } + catch (...) { __builtin_abort (); } +} Jakub