OSDN Git Service

* tree-eh.c (cleanup_is_dead_in): New.
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 21 May 2010 19:32:29 +0000 (19:32 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 21 May 2010 19:32:29 +0000 (19:32 +0000)
(lower_try_finally): Don't generate a dead cleanup region.
(lower_cleanup): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@159682 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/doc/implement-cxx.texi
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/eh/spec11.C
gcc/tree-eh.c

index dcfff77..06529f5 100644 (file)
@@ -1,3 +1,9 @@
+2010-05-21  Jason Merrill  <jason@redhat.com>
+
+       * 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  <jakub@redhat.com>
 
        PR debug/44223
 2010-05-21  Jakub Jelinek  <jakub@redhat.com>
 
        PR debug/44223
index 9968f59..1de2536 100644 (file)
@@ -28,6 +28,7 @@ environment); refer to their documentation for details.
 
 @menu
 * Conditionally-supported behavior::
 
 @menu
 * Conditionally-supported behavior::
+* Exception handling::
 @end menu
 
 @node Conditionally-supported behavior
 @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
 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
index 195cdfb..c3e2d37 100644 (file)
@@ -187,7 +187,7 @@ in the following sections.
 -fno-implicit-templates @gol
 -fno-implicit-inline-templates @gol
 -fno-implement-inlines  -fms-extensions @gol
 -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
 -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
 @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
 
 @item -fno-operator-names
 @opindex fno-operator-names
index d40fc04..227a77c 100644 (file)
@@ -1,3 +1,7 @@
+2010-05-21  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/eh/spec11.C: Test cleanup optimization.
+
 2010-05-21  Jakub Jelinek  <jakub@redhat.com>
 
        PR debug/44223
 2010-05-21  Jakub Jelinek  <jakub@redhat.com>
 
        PR debug/44223
index 562e366..4615a64 100644 (file)
@@ -1,5 +1,8 @@
 // Make sure that we force an LSDA for a throw() spec with -fnothrow-opt so
 // 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" } }
 
 // { dg-final { scan-assembler-not "_ZSt9terminatev" } }
 // { dg-final { scan-assembler-not "EHB" } }
@@ -7,5 +10,10 @@
 
 // { dg-options "-fnothrow-opt" }
 
 
 // { dg-options "-fnothrow-opt" }
 
+struct A { ~A(); };
 void g();
 void g();
-void f() throw() { g(); }
+void f() throw()
+{
+  A var;
+  g();
+}
index 2cc03d3..e5d76c8 100644 (file)
@@ -1517,6 +1517,20 @@ decide_copy_try_finally (int ndests, gimple_seq finally)
     return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3;
 }
 
     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
 
 /* 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;
   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
   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;
 
   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.  */
   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);
     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;
   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;
     {
       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));
 
 
   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
     return gimple_try_eval (tp);
 
   /* Build enough of a try-finally state so that we can reuse