re PR middle-end/42859 (ICE in verify_flow_info)
authorAndrey Belevantsev <abel@ispras.ru>
Wed, 10 Mar 2010 11:08:48 +0000 (14:08 +0300)
committerAndrey Belevantsev <abel@gcc.gnu.org>
Wed, 10 Mar 2010 11:08:48 +0000 (14:08 +0300)
    PR middle-end/42859

    * tree-eh.c: Include pointer-set.h.
    (lower_eh_dispatch): Filter out duplicate case labels and
    remove the unneeded edge when the label is unused.  Return
    true when some edges are removed.
    (execute_lower_eh_dispatch): When any lowering resulted in
    removing an edge, also delete unreachable blocks.

    * g++.dg/eh/pr42859.C: New test.

From-SVN: r157337

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/eh/pr42859.C [new file with mode: 0644]
gcc/tree-eh.c

index ae224caf4c4186200d16836a509e0dc474bbc96e..32e2eab6bcf489956c24c023a3ab6676154f051a 100644 (file)
@@ -1,3 +1,13 @@
+2010-03-10  Andrey Belevantsev  <abel@ispras.ru>
+
+       PR middle-end/42859
+       * tree-eh.c: Include pointer-set.h.
+       (lower_eh_dispatch): Filter out duplicate case labels and
+       remove the unneeded edge when the label is unused.  Return
+       true when some edges are removed.
+       (execute_lower_eh_dispatch): When any lowering resulted in
+       removing an edge, also delete unreachable blocks.
+
 2010-03-10  Jakub Jelinek  <jakub@redhat.com>
 
        PR bootstrap/43287
index 6f3709339880a6d912680f93ff00db00b54c7f2a..bf4ccf7fe0608162bad4e335196e56a5283e7a02 100644 (file)
@@ -1,3 +1,8 @@
+2010-03-10  Andrey Belevantsev  <abel@ispras.ru>
+
+       PR middle-end/42859
+       * g++.dg/eh/pr42859.C: New test.
+
 2010-03-09  Jakub Jelinek  <jakub@redhat.com>
 
        PR debug/43299
diff --git a/gcc/testsuite/g++.dg/eh/pr42859.C b/gcc/testsuite/g++.dg/eh/pr42859.C
new file mode 100644 (file)
index 0000000..a9f1473
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile }
+
+void start (void);
+void
+ptw32_terminate (void)
+{
+  try
+  {
+    try
+    {
+      start ();
+    }
+    catch (int)
+    {
+    }
+    catch (int)
+    {
+    }
+  }
+  catch (int)
+  {
+  }
+}
index 2cb334ff0d491c63b4e3a6efa978d0cb60702f2f..5ae47f0c10fa88836d682570f76b84d9b4757782 100644 (file)
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "function.h"
 #include "except.h"
+#include "pointer-set.h"
 #include "tree-flow.h"
 #include "tree-dump.h"
 #include "tree-inline.h"
@@ -3038,9 +3039,10 @@ struct gimple_opt_pass pass_lower_resx =
 };
 
 
-/* At the end of inlining, we can lower EH_DISPATCH.  */
+/* At the end of inlining, we can lower EH_DISPATCH.  Return true when 
+   we have found some duplicate labels and removed some edges.  */
 
-static void
+static bool
 lower_eh_dispatch (basic_block src, gimple stmt)
 {
   gimple_stmt_iterator gsi;
@@ -3048,6 +3050,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
   eh_region r;
   tree filter, fn;
   gimple x;
+  bool redirected = false;
 
   region_nr = gimple_eh_dispatch_region (stmt);
   r = get_eh_region_from_number (region_nr);
@@ -3063,6 +3066,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
        eh_catch c;
        edge_iterator ei;
        edge e;
+       struct pointer_set_t *seen_values = pointer_set_create ();
 
        /* Collect the labels for a switch.  Zero the post_landing_pad
           field becase we'll no longer have anything keeping these labels
@@ -3071,6 +3075,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
        for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
          {
            tree tp_node, flt_node, lab = c->label;
+           bool have_label = false;
 
            c->label = NULL;
            tp_node = c->type_list;
@@ -3083,14 +3088,29 @@ lower_eh_dispatch (basic_block src, gimple stmt)
              }
            do
              {
-               tree t = build3 (CASE_LABEL_EXPR, void_type_node,
-                                TREE_VALUE (flt_node), NULL, lab);
-               VEC_safe_push (tree, heap, labels, t);
+               /* Filter out duplicate labels that arise when this handler 
+                  is shadowed by an earlier one.  When no labels are 
+                  attached to the handler anymore, we remove 
+                  the corresponding edge and then we delete unreachable 
+                  blocks at the end of this pass.  */
+               if (! pointer_set_contains (seen_values, TREE_VALUE (flt_node)))
+                 {
+                   tree t = build3 (CASE_LABEL_EXPR, void_type_node,
+                                    TREE_VALUE (flt_node), NULL, lab);
+                   VEC_safe_push (tree, heap, labels, t);
+                   pointer_set_insert (seen_values, TREE_VALUE (flt_node));
+                   have_label = true;
+                 }
 
                tp_node = TREE_CHAIN (tp_node);
                flt_node = TREE_CHAIN (flt_node);
              }
            while (tp_node);
+           if (! have_label)
+             {
+               remove_edge (find_edge (src, label_to_block (lab)));
+               redirected = true;
+             }
          }
 
        /* Clean up the edge flags.  */
@@ -3132,6 +3152,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
 
            VEC_free (tree, heap, labels);
          }
+       pointer_set_destroy (seen_values);
       }
       break;
 
@@ -3165,6 +3186,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
 
   /* Replace the EH_DISPATCH with the SWITCH or COND generated above.  */
   gsi_remove (&gsi, true);
+  return redirected;
 }
 
 static unsigned
@@ -3172,6 +3194,7 @@ execute_lower_eh_dispatch (void)
 {
   basic_block bb;
   bool any_rewritten = false;
+  bool redirected = false;
 
   assign_filter_values ();
 
@@ -3180,11 +3203,13 @@ execute_lower_eh_dispatch (void)
       gimple last = last_stmt (bb);
       if (last && gimple_code (last) == GIMPLE_EH_DISPATCH)
        {
-         lower_eh_dispatch (bb, last);
+         redirected |= lower_eh_dispatch (bb, last);
          any_rewritten = true;
        }
     }
 
+  if (redirected)
+    delete_unreachable_blocks ();
   return any_rewritten ? TODO_update_ssa_only_virtuals : 0;
 }