Hi!

As mentioned in the PR, if gimple_purge_dead_eh_edges is ever called
after ehcleanup2 pass (or in its after todos as in the testcase below),
nothing removes the unreachable EH regions and we crash either in
cleanup_dead_labels_eh or, if we ignore those there, later on during
emitting of exception info.

We could run remove_unreachable_handlers unconditionally again shortly
before expansion, but that needs a walk of all stmts, so this
patch chooses to do it only if it sees some landing pads got removed.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2011-11-23  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/50682
        * tree-eh.c (maybe_remove_unreachable_handlers): New function.
        * tree-flow.h (maybe_remove_unreachable_handlers): New prototype.
        * tree-optimize.c (execute_cleanup_cfg_post_optimizing): Call it.

        * g++.dg/opt/pr50682.C: New test.

--- gcc/tree-eh.c.jj    2011-11-08 23:35:12.000000000 +0100
+++ gcc/tree-eh.c       2011-11-23 17:32:10.726659121 +0100
@@ -3473,6 +3473,29 @@ remove_unreachable_handlers (void)
 #endif
 }
 
+/* Remove unreachable handlers if any landing pads have been removed after
+   last ehcleanup pass (due to gimple_purge_dead_eh_edges).  */
+
+void
+maybe_remove_unreachable_handlers (void)
+{
+  eh_landing_pad lp;
+  int i;
+
+  if (cfun->eh == NULL)
+    return;
+              
+  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+    if (lp && lp->post_landing_pad)
+      {
+       if (label_to_block (lp->post_landing_pad) == NULL)
+         {
+           remove_unreachable_handlers ();
+           return;
+         }
+      }
+}
+
 /* Remove regions that do not have landing pads.  This assumes
    that remove_unreachable_handlers has already been run, and
    that we've just manipulated the landing pads since then.  */
--- gcc/tree-flow.h.jj  2011-11-08 23:35:12.000000000 +0100
+++ gcc/tree-flow.h     2011-11-23 17:33:27.211192957 +0100
@@ -789,6 +789,7 @@ extern bool maybe_duplicate_eh_stmt_fn (
 extern bool maybe_duplicate_eh_stmt (gimple, gimple);
 extern bool verify_eh_edges (gimple);
 extern bool verify_eh_dispatch_edge (gimple);
+extern void maybe_remove_unreachable_handlers (void);
 
 /* In tree-ssa-pre.c  */
 struct pre_expr_d;
--- gcc/tree-optimize.c.jj      2011-08-18 08:36:01.000000000 +0200
+++ gcc/tree-optimize.c 2011-11-23 17:34:12.661916087 +0100
@@ -159,6 +159,7 @@ static unsigned int
 execute_cleanup_cfg_post_optimizing (void)
 {
   cleanup_tree_cfg ();
+  maybe_remove_unreachable_handlers ();
   cleanup_dead_labels ();
   group_case_labels ();
   if ((flag_compare_debug_opt || flag_compare_debug)
--- gcc/testsuite/g++.dg/opt/pr50682.C.jj       2011-11-23 17:40:01.352786764 
+0100
+++ gcc/testsuite/g++.dg/opt/pr50682.C  2011-11-23 17:39:20.000000000 +0100
@@ -0,0 +1,39 @@
+// PR tree-optimization/50682
+// { dg-do compile }
+// { dg-options "-O2 -fnon-call-exceptions -ftracer -fno-tree-ccp 
-fno-tree-copy-prop -fno-tree-dce" }
+
+void foo () __attribute__ ((__noreturn__));
+int baz ();
+
+const int &
+bar (const int &x, const int &y)
+{
+  if (x >= y)
+    return y;
+  return x;
+}
+
+int a, b;
+
+struct S
+{
+  ~S ();
+  bool m ()
+  {
+    int l = bar (a, b);
+    int r = baz ();
+    if (r)
+        r = l;
+      return r;
+  }
+};
+
+void
+test ()
+{
+  S s;
+  if (!s.m ())
+    foo ();
+  if (!s.m ())
+    foo ();
+}

        Jakub

Reply via email to