There is -fdelete-dead-exceptions now and we're tracking nothrow and const/pure bits separately and I do remember that const or pure does _not_ imply nothrow.
Now, in the light of the PR100382 fix which added a stmt_unremovable_because_of_non_call_eh_p guard to DSEs "DCE" I wondered how -fdelete-dead-exceptions applies to calls and whether stmt_unremovable_because_of_non_call_eh_p doing return (fun->can_throw_non_call_exceptions && !fun->can_delete_dead_exceptions && stmt_could_throw_p (fun, stmt)); really should conditionalize itself on fun->can_throw_non_call_exceptions. In fact DCE happily elides pure function calls that throw without a LHS (probably a consistency bug). The following testcase shows this: int x, y; int __attribute__((pure,noinline)) foo () { if (x) throw; return y; } int main() { int a[2]; x = 1; try { int res = foo (); a[0] = res; } catch (...) { return 0; } return 1; } note that if you wrap foo () into another noinline wrap_foo () { foo (); return 1; } function then we need to make sure to not DCE this call either even though it only throws externally. Now the question is whether this testcase is valid (it should not abort). The documentation of 'pure' must be read as that 'pure' is not valid for 'foo' since throwing an exception is obviously an observable effect on the state of the program (in particular for the testcase at hand). But for example IPA pure const does not cause us to infer nothrow on pure declared functions and the C++ program extern int __attribute__((pure)) foo(); int bar() { try { return foo (); } catch (...) { return -1; } } is compiled with full EH in place. (clang elides all of it, btw) The set of changes below do not succeed in it passing but at least the throwing call prevails but somehow EH info is hosed and you'll get > ./pr100382.exe terminate called without an active exception Aborted (core dumped) So - what is it? Are pure functions allowed to throw or not? 2021-05-03 Richard Biener <rguent...@suse.de> * calls.c (expand_call): Preserve possibly throwing calls. * cfgexpand.c (expand_call_stmt): When a call can throw signal RTL expansion there are side-effects. * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Simplify. * tree-ssa-dse.c (pass_dse::execute): Preserve exceptions unless -fdelete-dead-exceptions. * g++.dg/tree-ssa/pr100382.C: New testcase. --- gcc/calls.c | 1 + gcc/cfgexpand.c | 5 ++++- gcc/testsuite/g++.dg/tree-ssa/pr100382.C | 25 ++++++++++++++++++++++++ gcc/tree-ssa-dce.c | 21 +++----------------- gcc/tree-ssa-dse.c | 3 ++- 5 files changed, 35 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr100382.C diff --git a/gcc/calls.c b/gcc/calls.c index 883d08ba5f2..f3da1839dc5 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -3808,6 +3808,7 @@ expand_call (tree exp, rtx target, int ignore) side-effects. */ if ((flags & (ECF_CONST | ECF_PURE)) && (!(flags & ECF_LOOPING_CONST_OR_PURE)) + && (flags & ECF_NOTHROW) && (ignore || target == const0_rtx || TYPE_MODE (rettype) == VOIDmode)) { diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index a6b48d3e48f..556a0b22ed6 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -2795,7 +2795,10 @@ expand_call_stmt (gcall *stmt) CALL_EXPR_ARG (exp, i) = arg; } - if (gimple_has_side_effects (stmt)) + if (gimple_has_side_effects (stmt) + /* ??? Downstream in expand_expr_real_1 we assume that expressions + w/o side-effects do not throw so work around this here. */ + || stmt_could_throw_p (cfun, stmt)) TREE_SIDE_EFFECTS (exp) = 1; if (gimple_call_nothrow_p (stmt)) diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr100382.C b/gcc/testsuite/g++.dg/tree-ssa/pr100382.C new file mode 100644 index 00000000000..b9948d3034a --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr100382.C @@ -0,0 +1,25 @@ +// { dg-do run } +// { dg-options "-O2" } + +int x, y; +int __attribute__((pure,noinline)) foo () { if (x) throw; return y; } + +int __attribute__((noinline)) bar() +{ + int a[2]; + x = 1; + try { + int res = foo (); + a[0] = res; + } catch (...) { + return 0; + } + return 1; +} + +int main() +{ + if (bar ()) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index 096cfc8721d..ff0389af36f 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -250,14 +250,6 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)) return; - /* Most, but not all function calls are required. Function calls that - produce no result and have no side effects (i.e. const pure - functions) are unnecessary. */ - if (gimple_has_side_effects (stmt)) - { - mark_stmt_necessary (stmt, true); - return; - } /* IFN_GOACC_LOOP calls are necessary in that they are used to represent parameter (i.e. step, bound) of a lowered OpenACC partitioned loop. But this kind of partitioned loop might not @@ -269,8 +261,6 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) mark_stmt_necessary (stmt, true); return; } - if (!gimple_call_lhs (stmt)) - return; break; } @@ -312,19 +302,14 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) /* If the statement has volatile operands, it needs to be preserved. Same for statements that can alter control flow in unpredictable ways. */ - if (gimple_has_volatile_ops (stmt) || is_ctrl_altering_stmt (stmt)) - { - mark_stmt_necessary (stmt, true); - return; - } - - if (stmt_may_clobber_global_p (stmt)) + if (gimple_has_side_effects (stmt) || is_ctrl_altering_stmt (stmt)) { mark_stmt_necessary (stmt, true); return; } - if (gimple_vdef (stmt) && keep_all_vdefs_p ()) + if ((gimple_vdef (stmt) && keep_all_vdefs_p ()) + || stmt_may_clobber_global_p (stmt)) { mark_stmt_necessary (stmt, true); return; diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c index dfa6d314727..386667b9f7f 100644 --- a/gcc/tree-ssa-dse.c +++ b/gcc/tree-ssa-dse.c @@ -1219,7 +1219,8 @@ pass_dse::execute (function *fun) dead SSA defs. */ if (has_zero_uses (DEF_FROM_PTR (def_p)) && !gimple_has_side_effects (stmt) - && !stmt_unremovable_because_of_non_call_eh_p (cfun, stmt)) + && (!stmt_could_throw_p (fun, stmt) + || fun->can_delete_dead_exceptions)) { if (dump_file && (dump_flags & TDF_DETAILS)) { -- 2.26.2