From d3f28910851bee99e959d8841c818417109d0a33 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 21 May 2010 15:32:29 -0400 Subject: [PATCH] tree-eh.c (cleanup_is_dead_in): New. * tree-eh.c (cleanup_is_dead_in): New. (lower_try_finally): Don't generate a dead cleanup region. (lower_cleanup): Likewise. From-SVN: r159682 --- gcc/ChangeLog | 6 ++++++ gcc/doc/implement-cxx.texi | 14 +++++++++++++ gcc/doc/invoke.texi | 13 +++++++----- gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/g++.dg/eh/spec11.C | 12 +++++++++-- gcc/tree-eh.c | 34 +++++++++++++++++++++++++------- 6 files changed, 69 insertions(+), 14 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dcfff779fc1..06529f51a05 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2010-05-21 Jason Merrill + + * tree-eh.c (cleanup_is_dead_in): New. + (lower_try_finally): Don't generate a dead cleanup region. + (lower_cleanup): Likewise. + 2010-05-21 Jakub Jelinek PR debug/44223 diff --git a/gcc/doc/implement-cxx.texi b/gcc/doc/implement-cxx.texi index 9968f592473..1de25361cfc 100644 --- a/gcc/doc/implement-cxx.texi +++ b/gcc/doc/implement-cxx.texi @@ -28,6 +28,7 @@ environment); refer to their documentation for details. @menu * Conditionally-supported behavior:: +* Exception handling:: @end menu @node Conditionally-supported behavior @@ -45,3 +46,16 @@ constructor or destructor can be passed to ... (C++0x 5.2.2).} Such argument passing is not supported. @end itemize + +@node Exception handling +@section Exception handling + +@itemize @bullet +@item +@cite{In the situation where no matching handler is found, it is +implementation-defined whether or not the stack is unwound before +std::terminate() is called (C++98 15.5.1).} + +The stack is not unwound before std::terminate is called. + +@end itemize diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 195cdfb6436..c3e2d37c7e8 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -187,7 +187,7 @@ in the following sections. -fno-implicit-templates @gol -fno-implicit-inline-templates @gol -fno-implement-inlines -fms-extensions @gol --fno-nonansi-builtins -fno-operator-names @gol +-fno-nonansi-builtins -fnothrow-opt -fno-operator-names @gol -fno-optional-diags -fpermissive @gol -fno-pretty-templates @gol -frepo -fno-rtti -fstats -ftemplate-depth=@var{n} @gol @@ -1933,10 +1933,13 @@ ANSI/ISO C@. These include @code{ffs}, @code{alloca}, @code{_exit}, @opindex fnothrow-opt Treat a @code{throw()} exception specification as though it were a @code{noexcept} specification to reduce or eliminate the text size -overhead relative to a function with no exception specification. The -semantic effect is that an exception thrown out of a function with -such an exception specification will result in a call to -@code{terminate} rather than @code{unexpected}. +overhead relative to a function with no exception specification. If +the function has local variables of types with non-trivial +destructors, the exception specification will actually make the +function smaller because the EH cleanups for those variables can be +optimized away. The semantic effect is that an exception thrown out of +a function with such an exception specification will result in a call +to @code{terminate} rather than @code{unexpected}. @item -fno-operator-names @opindex fno-operator-names diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d40fc045d2d..227a77c73a8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2010-05-21 Jason Merrill + + * g++.dg/eh/spec11.C: Test cleanup optimization. + 2010-05-21 Jakub Jelinek PR debug/44223 diff --git a/gcc/testsuite/g++.dg/eh/spec11.C b/gcc/testsuite/g++.dg/eh/spec11.C index 562e366aa2c..4615a640519 100644 --- a/gcc/testsuite/g++.dg/eh/spec11.C +++ b/gcc/testsuite/g++.dg/eh/spec11.C @@ -1,5 +1,8 @@ // Make sure that we force an LSDA for a throw() spec with -fnothrow-opt so -// that the personality routine will call terminate. +// that the personality routine will call terminate. Also check that we +// optimize away the EH cleanup for var because the personality routine +// will call terminate before unwinding: there should not be an EH region +// (i.e. LEHB/LEHE labels) around the call to g(). // { dg-final { scan-assembler-not "_ZSt9terminatev" } } // { dg-final { scan-assembler-not "EHB" } } @@ -7,5 +10,10 @@ // { dg-options "-fnothrow-opt" } +struct A { ~A(); }; void g(); -void f() throw() { g(); } +void f() throw() +{ + A var; + g(); +} diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 2cc03d3b0ee..e5d76c8b8ba 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -1517,6 +1517,20 @@ decide_copy_try_finally (int ndests, gimple_seq finally) return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3; } +/* REG is the enclosing region for a possible cleanup region, or the region + itself. Returns TRUE if such a region would be unreachable. + + Cleanup regions within a must-not-throw region aren't actually reachable + even if there are throwing stmts within them, because the personality + routine will call terminate before unwinding. */ + +static bool +cleanup_is_dead_in (eh_region reg) +{ + while (reg && reg->type == ERT_CLEANUP) + reg = reg->outer; + return (reg && reg->type == ERT_MUST_NOT_THROW); +} /* A subroutine of lower_eh_constructs_1. Lower a GIMPLE_TRY_FINALLY nodes to a sequence of labels and blocks, plus the exception region trees @@ -1537,12 +1551,17 @@ lower_try_finally (struct leh_state *state, gimple tp) this_tf.try_finally_expr = tp; this_tf.top_p = tp; this_tf.outer = state; - if (using_eh_for_cleanups_p) - this_tf.region = gen_eh_region_cleanup (state->cur_region); + if (using_eh_for_cleanups_p && !cleanup_is_dead_in (state->cur_region)) + { + this_tf.region = gen_eh_region_cleanup (state->cur_region); + this_state.cur_region = this_tf.region; + } else - this_tf.region = NULL; + { + this_tf.region = NULL; + this_state.cur_region = state->cur_region; + } - this_state.cur_region = this_tf.region; this_state.ehp_region = state->ehp_region; this_state.tf = &this_tf; @@ -1555,7 +1574,7 @@ lower_try_finally (struct leh_state *state, gimple tp) this_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp)); /* Determine if any exceptions are possible within the try block. */ - if (using_eh_for_cleanups_p) + if (this_tf.region) this_tf.may_throw = eh_region_may_contain_throw (this_tf.region); if (this_tf.may_throw) honor_protect_cleanup_actions (state, &this_state, &this_tf); @@ -1779,8 +1798,9 @@ lower_cleanup (struct leh_state *state, gimple tp) eh_region this_region = NULL; struct leh_tf_state fake_tf; gimple_seq result; + bool cleanup_dead = cleanup_is_dead_in (state->cur_region); - if (flag_exceptions) + if (flag_exceptions && !cleanup_dead) { this_region = gen_eh_region_cleanup (state->cur_region); this_state.cur_region = this_region; @@ -1788,7 +1808,7 @@ lower_cleanup (struct leh_state *state, gimple tp) lower_eh_constructs_1 (&this_state, gimple_try_eval (tp)); - if (!eh_region_may_contain_throw (this_region)) + if (cleanup_dead || !eh_region_may_contain_throw (this_region)) return gimple_try_eval (tp); /* Build enough of a try-finally state so that we can reuse -- 2.30.2