Update to 4.8.2.
[platform/upstream/gcc48.git] / gcc / tree-eh.c
index 2da170d..973782b 100644 (file)
@@ -1,6 +1,5 @@
 /* Exception handling semantics and decomposition for trees.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 2003-2013 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -28,16 +27,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "except.h"
 #include "pointer-set.h"
 #include "tree-flow.h"
-#include "tree-dump.h"
 #include "tree-inline.h"
-#include "tree-iterator.h"
 #include "tree-pass.h"
-#include "timevar.h"
 #include "langhooks.h"
 #include "ggc.h"
 #include "diagnostic-core.h"
 #include "gimple.h"
 #include "target.h"
+#include "cfgloop.h"
 
 /* In some instances a tree and a gimple need to be stored in a same table,
    i.e. in hash tables. This is a structure to do this. */
@@ -323,6 +320,7 @@ static bitmap eh_region_may_contain_throw_map;
 struct goto_queue_node
 {
   treemple stmt;
+  location_t location;
   gimple_seq repl_stmt;
   gimple cont_stmt;
   int index;
@@ -379,7 +377,7 @@ struct leh_tf_state
   struct pointer_map_t *goto_queue_map;
 
   /* The set of unique labels seen as entries in the goto queue.  */
-  VEC(tree,heap) *dest_array;
+  vec<tree> dest_array;
 
   /* A label to be added at the end of the completed transformed
      sequence.  It will be set if may_fallthru was true *at one time*,
@@ -405,7 +403,7 @@ static gimple_seq lower_eh_must_not_throw (struct leh_state *, gimple);
 
 #define LARGE_GOTO_QUEUE 20
 
-static void lower_eh_constructs_1 (struct leh_state *state, gimple_seq seq);
+static void lower_eh_constructs_1 (struct leh_state *state, gimple_seq *seq);
 
 static gimple_seq
 find_goto_replacement (struct leh_tf_state *tf, treemple stmt)
@@ -480,7 +478,7 @@ replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf,
 /* The real work of replace_goto_queue.  Returns with TSI updated to
    point to the next statement.  */
 
-static void replace_goto_queue_stmt_list (gimple_seq, struct leh_tf_state *);
+static void replace_goto_queue_stmt_list (gimple_seq *, struct leh_tf_state *);
 
 static void
 replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf,
@@ -510,18 +508,18 @@ replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf,
       break;
 
     case GIMPLE_TRY:
-      replace_goto_queue_stmt_list (gimple_try_eval (stmt), tf);
-      replace_goto_queue_stmt_list (gimple_try_cleanup (stmt), tf);
+      replace_goto_queue_stmt_list (gimple_try_eval_ptr (stmt), tf);
+      replace_goto_queue_stmt_list (gimple_try_cleanup_ptr (stmt), tf);
       break;
     case GIMPLE_CATCH:
-      replace_goto_queue_stmt_list (gimple_catch_handler (stmt), tf);
+      replace_goto_queue_stmt_list (gimple_catch_handler_ptr (stmt), tf);
       break;
     case GIMPLE_EH_FILTER:
-      replace_goto_queue_stmt_list (gimple_eh_filter_failure (stmt), tf);
+      replace_goto_queue_stmt_list (gimple_eh_filter_failure_ptr (stmt), tf);
       break;
     case GIMPLE_EH_ELSE:
-      replace_goto_queue_stmt_list (gimple_eh_else_n_body (stmt), tf);
-      replace_goto_queue_stmt_list (gimple_eh_else_e_body (stmt), tf);
+      replace_goto_queue_stmt_list (gimple_eh_else_n_body_ptr (stmt), tf);
+      replace_goto_queue_stmt_list (gimple_eh_else_e_body_ptr (stmt), tf);
       break;
 
     default:
@@ -535,9 +533,9 @@ replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf,
 /* A subroutine of replace_goto_queue.  Handles GIMPLE_SEQ.  */
 
 static void
-replace_goto_queue_stmt_list (gimple_seq seq, struct leh_tf_state *tf)
+replace_goto_queue_stmt_list (gimple_seq *seq, struct leh_tf_state *tf)
 {
-  gimple_stmt_iterator gsi = gsi_start (seq);
+  gimple_stmt_iterator gsi = gsi_start (*seq);
 
   while (!gsi_end_p (gsi))
     replace_goto_queue_1 (gsi_stmt (gsi), tf, &gsi);
@@ -550,8 +548,8 @@ replace_goto_queue (struct leh_tf_state *tf)
 {
   if (tf->goto_queue_active == 0)
     return;
-  replace_goto_queue_stmt_list (tf->top_p_seq, tf);
-  replace_goto_queue_stmt_list (eh_seq, tf);
+  replace_goto_queue_stmt_list (&tf->top_p_seq, tf);
+  replace_goto_queue_stmt_list (&eh_seq, tf);
 }
 
 /* Add a new record to the goto queue contained in TF. NEW_STMT is the
@@ -562,7 +560,8 @@ static void
 record_in_goto_queue (struct leh_tf_state *tf,
                       treemple new_stmt,
                       int index,
-                      bool is_label)
+                      bool is_label,
+                     location_t location)
 {
   size_t active, size;
   struct goto_queue_node *q;
@@ -585,6 +584,7 @@ record_in_goto_queue (struct leh_tf_state *tf,
   memset (q, 0, sizeof (*q));
   q->stmt = new_stmt;
   q->index = index;
+  q->location = location;
   q->is_label = is_label;
 }
 
@@ -592,7 +592,8 @@ record_in_goto_queue (struct leh_tf_state *tf,
    TF is not null.  */
 
 static void
-record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label)
+record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label,
+                           location_t location)
 {
   int index;
   treemple temp, new_stmt;
@@ -611,27 +612,27 @@ record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label)
   if (!outside_finally_tree (temp, tf->try_finally_expr))
     return;
 
-  if (! tf->dest_array)
+  if (! tf->dest_array.exists ())
     {
-      tf->dest_array = VEC_alloc (tree, heap, 10);
-      VEC_quick_push (tree, tf->dest_array, label);
+      tf->dest_array.create (10);
+      tf->dest_array.quick_push (label);
       index = 0;
     }
   else
     {
-      int n = VEC_length (tree, tf->dest_array);
+      int n = tf->dest_array.length ();
       for (index = 0; index < n; ++index)
-        if (VEC_index (tree, tf->dest_array, index) == label)
+        if (tf->dest_array[index] == label)
           break;
       if (index == n)
-        VEC_safe_push (tree, heap, tf->dest_array, label);
+        tf->dest_array.safe_push (label);
     }
 
   /* In the case of a GOTO we want to record the destination label,
      since with a GIMPLE_COND we have an easy access to the then/else
      labels. */
   new_stmt = stmt;
-  record_in_goto_queue (tf, new_stmt, index, true);
+  record_in_goto_queue (tf, new_stmt, index, true, location);
 }
 
 /* For any GIMPLE_GOTO or GIMPLE_RETURN, decide whether it leaves a try_finally
@@ -651,19 +652,22 @@ maybe_record_in_goto_queue (struct leh_state *state, gimple stmt)
     {
     case GIMPLE_COND:
       new_stmt.tp = gimple_op_ptr (stmt, 2);
-      record_in_goto_queue_label (tf, new_stmt, gimple_cond_true_label (stmt));
+      record_in_goto_queue_label (tf, new_stmt, gimple_cond_true_label (stmt),
+                                 EXPR_LOCATION (*new_stmt.tp));
       new_stmt.tp = gimple_op_ptr (stmt, 3);
-      record_in_goto_queue_label (tf, new_stmt, gimple_cond_false_label (stmt));
+      record_in_goto_queue_label (tf, new_stmt, gimple_cond_false_label (stmt),
+                                 EXPR_LOCATION (*new_stmt.tp));
       break;
     case GIMPLE_GOTO:
       new_stmt.g = stmt;
-      record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt));
+      record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt),
+                                 gimple_location (stmt));
       break;
 
     case GIMPLE_RETURN:
       tf->may_return = true;
       new_stmt.g = stmt;
-      record_in_goto_queue (tf, new_stmt, -1, false);
+      record_in_goto_queue (tf, new_stmt, -1, false, gimple_location (stmt));
       break;
 
     default:
@@ -730,13 +734,11 @@ do_return_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod)
 
   q->cont_stmt = q->stmt.g;
 
-  if (!q->repl_stmt)
-    q->repl_stmt = gimple_seq_alloc ();
-
   if (mod)
     gimple_seq_add_seq (&q->repl_stmt, mod);
 
   x = gimple_build_goto (finlab);
+  gimple_set_location (x, q->location);
   gimple_seq_add_stmt (&q->repl_stmt, x);
 }
 
@@ -749,15 +751,14 @@ do_goto_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod,
   gimple x;
 
   gcc_assert (q->is_label);
-  if (!q->repl_stmt)
-    q->repl_stmt = gimple_seq_alloc ();
 
-  q->cont_stmt = gimple_build_goto (VEC_index (tree, tf->dest_array, q->index));
+  q->cont_stmt = gimple_build_goto (tf->dest_array[q->index]);
 
   if (mod)
     gimple_seq_add_seq (&q->repl_stmt, mod);
 
   x = gimple_build_goto (finlab);
+  gimple_set_location (x, q->location);
   gimple_seq_add_stmt (&q->repl_stmt, x);
 }
 
@@ -857,6 +858,7 @@ frob_into_branch_around (gimple tp, eh_region region, tree over)
       if (!over)
        over = create_artificial_label (loc);
       x = gimple_build_goto (over);
+      gimple_set_location (x, loc);
       gimple_seq_add_stmt (&cleanup, x);
     }
   gimple_seq_add_seq (&eh_seq, cleanup);
@@ -873,13 +875,26 @@ frob_into_branch_around (gimple tp, eh_region region, tree over)
    Make sure to record all new labels found.  */
 
 static gimple_seq
-lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state)
+lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state,
+                            location_t loc)
 {
   gimple region = NULL;
   gimple_seq new_seq;
+  gimple_stmt_iterator gsi;
 
   new_seq = copy_gimple_seq_and_replace_locals (seq);
 
+  for (gsi = gsi_start (new_seq); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple stmt = gsi_stmt (gsi);
+      if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
+       {
+         tree block = gimple_block (stmt);
+         gimple_set_location (stmt, loc);
+         gimple_set_block (stmt, block);
+       }
+    }
+
   if (outer_state->tf)
     region = outer_state->tf->try_finally_expr;
   collect_finally_tree_1 (new_seq, region);
@@ -974,7 +989,8 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
       gimple_try_set_cleanup (tf->top_p, gimple_eh_else_n_body (eh_else));
     }
   else if (this_state)
-    finally = lower_try_finally_dup_block (finally, outer_state);
+    finally = lower_try_finally_dup_block (finally, outer_state,
+       gimple_location (tf->try_finally_expr));
   finally_may_fallthru = gimple_seq_may_fallthru (finally);
 
   /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP
@@ -1049,13 +1065,13 @@ lower_try_finally_nofallthru (struct leh_state *state,
   if (eh_else)
     {
       finally = gimple_eh_else_n_body (eh_else);
-      lower_eh_constructs_1 (state, finally);
+      lower_eh_constructs_1 (state, &finally);
       gimple_seq_add_seq (&tf->top_p_seq, finally);
 
       if (tf->may_throw)
        {
          finally = gimple_eh_else_e_body (eh_else);
-         lower_eh_constructs_1 (state, finally);
+         lower_eh_constructs_1 (state, &finally);
 
          emit_post_landing_pad (&eh_seq, tf->region);
          gimple_seq_add_seq (&eh_seq, finally);
@@ -1063,7 +1079,7 @@ lower_try_finally_nofallthru (struct leh_state *state,
     }
   else
     {
-      lower_eh_constructs_1 (state, finally);
+      lower_eh_constructs_1 (state, &finally);
       gimple_seq_add_seq (&tf->top_p_seq, finally);
 
       if (tf->may_throw)
@@ -1071,6 +1087,7 @@ lower_try_finally_nofallthru (struct leh_state *state,
          emit_post_landing_pad (&eh_seq, tf->region);
 
          x = gimple_build_goto (lab);
+         gimple_set_location (x, gimple_location (tf->try_finally_expr));
          gimple_seq_add_stmt (&eh_seq, x);
        }
     }
@@ -1086,6 +1103,7 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
   struct goto_queue_node *q, *qe;
   gimple x;
   gimple_seq finally;
+  gimple_stmt_iterator gsi;
   tree finally_label;
   location_t loc = gimple_location (tf->try_finally_expr);
 
@@ -1104,7 +1122,18 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
        finally = gimple_eh_else_n_body (x);
     }
 
-  lower_eh_constructs_1 (state, finally);
+  lower_eh_constructs_1 (state, &finally);
+
+  for (gsi = gsi_start (finally); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple stmt = gsi_stmt (gsi);
+      if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
+       {
+         tree block = gimple_block (stmt);
+         gimple_set_location (stmt, gimple_location (tf->try_finally_expr));
+         gimple_set_block (stmt, block);
+       }
+    }
 
   if (tf->may_throw)
     {
@@ -1147,7 +1176,7 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
        do_goto_redirection (q, finally_label, NULL, tf);
       replace_goto_queue (tf);
 
-      if (VEC_index (tree, tf->dest_array, 0) == tf->fallthru_label)
+      if (tf->dest_array[0] == tf->fallthru_label)
        {
          /* Reachable by goto to fallthru label only.  Redirect it
             to the new label (already created, sadly), and do not
@@ -1191,12 +1220,13 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
 
   if (tf->may_fallthru)
     {
-      seq = lower_try_finally_dup_block (finally, state);
-      lower_eh_constructs_1 (state, seq);
+      seq = lower_try_finally_dup_block (finally, state, tf_loc);
+      lower_eh_constructs_1 (state, &seq);
       gimple_seq_add_seq (&new_stmt, seq);
 
       tmp = lower_try_finally_fallthru_label (tf);
       x = gimple_build_goto (tmp);
+      gimple_set_location (x, tf_loc);
       gimple_seq_add_stmt (&new_stmt, x);
     }
 
@@ -1207,8 +1237,8 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
       if (eh_else)
        seq = gimple_eh_else_e_body (eh_else);
       else
-       seq = lower_try_finally_dup_block (finally, state);
-      lower_eh_constructs_1 (state, seq);
+       seq = lower_try_finally_dup_block (finally, state, tf_loc);
+      lower_eh_constructs_1 (state, &seq);
 
       emit_post_landing_pad (&eh_seq, tf->region);
       gimple_seq_add_seq (&eh_seq, seq);
@@ -1225,7 +1255,7 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
        tree label;
       } *labels;
 
-      return_index = VEC_length (tree, tf->dest_array);
+      return_index = tf->dest_array.length ();
       labels = XCNEWVEC (struct labels_s, return_index + 1);
 
       q = tf->goto_queue;
@@ -1257,8 +1287,8 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
          x = gimple_build_label (lab);
           gimple_seq_add_stmt (&new_stmt, x);
 
-         seq = lower_try_finally_dup_block (finally, state);
-         lower_eh_constructs_1 (state, seq);
+         seq = lower_try_finally_dup_block (finally, state, q->location);
+         lower_eh_constructs_1 (state, &seq);
           gimple_seq_add_seq (&new_stmt, seq);
 
           gimple_seq_add_stmt (&new_stmt, q->cont_stmt);
@@ -1304,8 +1334,8 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   int return_index, eh_index, fallthru_index;
   int nlabels, ndests, j, last_case_index;
   tree last_case;
-  VEC (tree,heap) *case_label_vec;
-  gimple_seq switch_body;
+  vec<tree> case_label_vec;
+  gimple_seq switch_body = NULL;
   gimple x, eh_else;
   tree tmp;
   gimple switch_stmt;
@@ -1316,7 +1346,6 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   /* The location of the finally block.  */
   location_t finally_loc;
 
-  switch_body = gimple_seq_alloc ();
   finally = gimple_try_cleanup (tf->top_p);
   eh_else = get_eh_else (finally);
 
@@ -1329,10 +1358,10 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   finally_loc = x ? gimple_location (x) : tf_loc;
 
   /* Lower the finally block itself.  */
-  lower_eh_constructs_1 (state, finally);
+  lower_eh_constructs_1 (state, &finally);
 
   /* Prepare for switch statement generation.  */
-  nlabels = VEC_length (tree, tf->dest_array);
+  nlabels = tf->dest_array.length ();
   return_index = nlabels;
   eh_index = return_index + tf->may_return;
   fallthru_index = eh_index + (tf->may_throw && !eh_else);
@@ -1341,16 +1370,16 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
   finally_label = create_artificial_label (finally_loc);
 
-  /* We use VEC_quick_push on case_label_vec throughout this function,
+  /* We use vec::quick_push on case_label_vec throughout this function,
      since we know the size in advance and allocate precisely as muce
      space as needed.  */
-  case_label_vec = VEC_alloc (tree, heap, ndests);
+  case_label_vec.create (ndests);
   last_case = NULL;
   last_case_index = 0;
 
   /* Begin inserting code for getting to the finally block.  Things
      are done in this order to correspond to the sequence the code is
-     layed out.  */
+     laid out.  */
 
   if (tf->may_fallthru)
     {
@@ -1362,7 +1391,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       tmp = build_int_cst (integer_type_node, fallthru_index);
       last_case = build_case_label (tmp, NULL,
                                    create_artificial_label (tf_loc));
-      VEC_quick_push (tree, case_label_vec, last_case);
+      case_label_vec.quick_push (last_case);
       last_case_index++;
 
       x = gimple_build_label (CASE_LABEL (last_case));
@@ -1370,6 +1399,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
 
       tmp = lower_try_finally_fallthru_label (tf);
       x = gimple_build_goto (tmp);
+      gimple_set_location (x, tf_loc);
       gimple_seq_add_stmt (&switch_body, x);
     }
 
@@ -1380,7 +1410,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       if (tf->may_throw)
        {
          finally = gimple_eh_else_e_body (eh_else);
-         lower_eh_constructs_1 (state, finally);
+         lower_eh_constructs_1 (state, &finally);
 
          emit_post_landing_pad (&eh_seq, tf->region);
          gimple_seq_add_seq (&eh_seq, finally);
@@ -1398,12 +1428,13 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       gimple_seq_add_stmt (&eh_seq, x);
 
       x = gimple_build_goto (finally_label);
+      gimple_set_location (x, tf_loc);
       gimple_seq_add_stmt (&eh_seq, x);
 
       tmp = build_int_cst (integer_type_node, eh_index);
       last_case = build_case_label (tmp, NULL,
                                    create_artificial_label (tf_loc));
-      VEC_quick_push (tree, case_label_vec, last_case);
+      case_label_vec.quick_push (last_case);
       last_case_index++;
 
       x = gimple_build_label (CASE_LABEL (last_case));
@@ -1424,12 +1455,10 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
      entrance through a particular edge. */
   for (; q < qe; ++q)
     {
-      gimple_seq mod;
+      gimple_seq mod = NULL;
       int switch_id;
       unsigned int case_index;
 
-      mod = gimple_seq_alloc ();
-
       if (q->index < 0)
        {
          x = gimple_build_assign (finally_tmp,
@@ -1449,8 +1478,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
        }
 
       case_index = j + q->index;
-      if (VEC_length (tree, case_label_vec) <= case_index
-          || !VEC_index (tree, case_label_vec, case_index))
+      if (case_label_vec.length () <= case_index || !case_label_vec[case_index])
         {
           tree case_lab;
           void **slot;
@@ -1463,7 +1491,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
             cont_map = pointer_map_create ();
           slot = pointer_map_insert (cont_map, case_lab);
           *slot = q->cont_stmt;
-          VEC_quick_push (tree, case_label_vec, case_lab);
+          case_label_vec.quick_push (case_lab);
         }
     }
   for (j = last_case_index; j < last_case_index + nlabels; j++)
@@ -1471,7 +1499,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       gimple cont_stmt;
       void **slot;
 
-      last_case = VEC_index (tree, case_label_vec, j);
+      last_case = case_label_vec[j];
 
       gcc_assert (last_case);
       gcc_assert (cont_map);
@@ -1497,8 +1525,8 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
 
   /* Build the switch statement, setting last_case to be the default
      label.  */
-  switch_stmt = gimple_build_switch_vec (finally_tmp, last_case,
-                                         case_label_vec);
+  switch_stmt = gimple_build_switch (finally_tmp, last_case,
+                                    case_label_vec);
   gimple_set_location (switch_stmt, finally_loc);
 
   /* Need to link SWITCH_STMT after running replace_goto_queue
@@ -1621,7 +1649,7 @@ lower_try_finally (struct leh_state *state, gimple tp)
   old_eh_seq = eh_seq;
   eh_seq = NULL;
 
-  lower_eh_constructs_1 (&this_state, gimple_try_eval(tp));
+  lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
 
   /* Determine if the try block is escaped through the bottom.  */
   this_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp));
@@ -1636,7 +1664,7 @@ lower_try_finally (struct leh_state *state, gimple tp)
      how many destinations are reached by the finally block.  Use this to
      determine how we process the finally block itself.  */
 
-  ndests = VEC_length (tree, this_tf.dest_array);
+  ndests = this_tf.dest_array.length ();
   ndests += this_tf.may_fallthru;
   ndests += this_tf.may_return;
   ndests += this_tf.may_throw;
@@ -1671,7 +1699,7 @@ lower_try_finally (struct leh_state *state, gimple tp)
       gimple_seq_add_stmt (&this_tf.top_p_seq, x);
     }
 
-  VEC_free (tree, heap, this_tf.dest_array);
+  this_tf.dest_array.release ();
   free (this_tf.goto_queue);
   if (this_tf.goto_queue_map)
     pointer_map_destroy (this_tf.goto_queue_map);
@@ -1704,7 +1732,7 @@ lower_catch (struct leh_state *state, gimple tp)
   struct leh_state this_state = *state;
   gimple_stmt_iterator gsi;
   tree out_label;
-  gimple_seq new_seq;
+  gimple_seq new_seq, cleanup;
   gimple x;
   location_t try_catch_loc = gimple_location (tp);
 
@@ -1714,7 +1742,7 @@ lower_catch (struct leh_state *state, gimple tp)
       this_state.cur_region = try_region;
     }
 
-  lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
+  lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
 
   if (!eh_region_may_contain_throw (try_region))
     return gimple_try_eval (tp);
@@ -1727,7 +1755,8 @@ lower_catch (struct leh_state *state, gimple tp)
   this_state.ehp_region = try_region;
 
   out_label = NULL;
-  for (gsi = gsi_start (gimple_try_cleanup (tp));
+  cleanup = gimple_try_cleanup (tp);
+  for (gsi = gsi_start (cleanup);
        !gsi_end_p (gsi);
        gsi_next (&gsi))
     {
@@ -1739,7 +1768,7 @@ lower_catch (struct leh_state *state, gimple tp)
       c = gen_eh_region_catch (try_region, gimple_catch_types (gcatch));
 
       handler = gimple_catch_handler (gcatch);
-      lower_eh_constructs_1 (&this_state, handler);
+      lower_eh_constructs_1 (&this_state, &handler);
 
       c->label = create_artificial_label (UNKNOWN_LOCATION);
       x = gimple_build_label (c->label);
@@ -1785,7 +1814,7 @@ lower_eh_filter (struct leh_state *state, gimple tp)
       this_state.cur_region = this_region;
     }
 
-  lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
+  lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
 
   if (!eh_region_may_contain_throw (this_region))
     return gimple_try_eval (tp);
@@ -1801,7 +1830,7 @@ lower_eh_filter (struct leh_state *state, gimple tp)
   x = gimple_build_label (this_region->u.allowed.label);
   gimple_seq_add_stmt (&new_seq, x);
 
-  lower_eh_constructs_1 (&this_state, gimple_eh_filter_failure (inner));
+  lower_eh_constructs_1 (&this_state, gimple_eh_filter_failure_ptr (inner));
   gimple_seq_add_seq (&new_seq, gimple_eh_filter_failure (inner));
 
   gimple_try_set_cleanup (tp, new_seq);
@@ -1826,7 +1855,8 @@ lower_eh_must_not_throw (struct leh_state *state, gimple tp)
       this_region = gen_eh_region_must_not_throw (state->cur_region);
       this_region->u.must_not_throw.failure_decl
        = gimple_eh_must_not_throw_fndecl (inner);
-      this_region->u.must_not_throw.failure_loc = gimple_location (tp);
+      this_region->u.must_not_throw.failure_loc
+       = LOCATION_LOCUS (gimple_location (tp));
 
       /* In order to get mangling applied to this decl, we must mark it
         used now.  Otherwise, pass_ipa_free_lang_data won't think it
@@ -1836,7 +1866,7 @@ lower_eh_must_not_throw (struct leh_state *state, gimple tp)
       this_state.cur_region = this_region;
     }
 
-  lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
+  lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
 
   return gimple_try_eval (tp);
 }
@@ -1859,7 +1889,7 @@ lower_cleanup (struct leh_state *state, gimple tp)
       this_state.cur_region = this_region;
     }
 
-  lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
+  lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
 
   if (cleanup_dead || !eh_region_may_contain_throw (this_region))
     return gimple_try_eval (tp);
@@ -1879,7 +1909,7 @@ lower_cleanup (struct leh_state *state, gimple tp)
     {
       /* In this case honor_protect_cleanup_actions had nothing to do,
         and we should process this normally.  */
-      lower_eh_constructs_1 (state, gimple_try_cleanup (tp));
+      lower_eh_constructs_1 (state, gimple_try_cleanup_ptr (tp));
       result = frob_into_branch_around (tp, this_region,
                                         fake_tf.fallthru_label);
     }
@@ -1962,7 +1992,7 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
       /* If the stmt can throw use a new temporary for the assignment
          to a LHS.  This makes sure the old value of the LHS is
         available on the EH edge.  Only do so for statements that
-        potentially fall thru (no noreturn calls e.g.), otherwise
+        potentially fall through (no noreturn calls e.g.), otherwise
         this new assignment might create fake fallthru regions.  */
       if (stmt_could_throw_p (stmt)
          && gimple_has_lhs (stmt)
@@ -2008,7 +2038,7 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
          if (!x)
            {
              replace = gimple_try_eval (stmt);
-             lower_eh_constructs_1 (state, replace);
+             lower_eh_constructs_1 (state, &replace);
            }
          else
            switch (gimple_code (x))
@@ -2055,10 +2085,10 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
 /* A helper to unwrap a gimple_seq and feed stmts to lower_eh_constructs_2. */
 
 static void
-lower_eh_constructs_1 (struct leh_state *state, gimple_seq seq)
+lower_eh_constructs_1 (struct leh_state *state, gimple_seq *pseq)
 {
   gimple_stmt_iterator gsi;
-  for (gsi = gsi_start (seq); !gsi_end_p (gsi);)
+  for (gsi = gsi_start (*pseq); !gsi_end_p (gsi);)
     lower_eh_constructs_2 (state, &gsi);
 }
 
@@ -2077,7 +2107,8 @@ lower_eh_constructs (void)
   memset (&null_state, 0, sizeof (null_state));
 
   collect_finally_tree_1 (bodyp, NULL);
-  lower_eh_constructs_1 (&null_state, bodyp);
+  lower_eh_constructs_1 (&null_state, &bodyp);
+  gimple_set_body (current_function_decl, bodyp);
 
   /* We assume there's a return statement, or something, at the end of
      the function, and thus ploping the EH sequence afterward won't
@@ -2108,6 +2139,7 @@ struct gimple_opt_pass pass_lower_eh =
  {
   GIMPLE_PASS,
   "eh",                                        /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   NULL,                                        /* gate */
   lower_eh_constructs,                 /* execute */
   NULL,                                        /* sub */
@@ -2531,7 +2563,7 @@ tree_could_trap_p (tree expr)
          if (!DECL_EXTERNAL (expr))
            return false;
          node = cgraph_function_node (cgraph_get_node (expr), NULL);
-         if (node && node->in_other_partition)
+         if (node && node->symbol.in_other_partition)
            return false;
          return true;
        }
@@ -2547,7 +2579,7 @@ tree_could_trap_p (tree expr)
          if (!DECL_EXTERNAL (expr))
            return false;
          node = varpool_variable_node (varpool_get_node (expr), NULL);
-         if (node && node->in_other_partition)
+         if (node && node->symbol.in_other_partition)
            return false;
          return true;
        }
@@ -2752,7 +2784,7 @@ maybe_clean_or_replace_eh_stmt (gimple old_stmt, gimple new_stmt)
   return false;
 }
 
-/* Given a statement OLD_STMT in OLD_FUN and a duplicate statment NEW_STMT
+/* Given a statement OLD_STMT in OLD_FUN and a duplicate statement NEW_STMT
    in NEW_FUN, copy the EH table data from OLD_STMT to NEW_STMT.  The MAP
    operand is the return value of duplicate_eh_regions.  */
 
@@ -2778,7 +2810,7 @@ maybe_duplicate_eh_stmt_fn (struct function *new_fun, gimple new_stmt,
     {
       eh_landing_pad old_lp, new_lp;
 
-      old_lp = VEC_index (eh_landing_pad, old_fun->eh->lp_array, old_lp_nr);
+      old_lp = (*old_fun->eh->lp_array)[old_lp_nr];
       slot = pointer_map_contains (map, old_lp);
       new_lp = (eh_landing_pad) *slot;
       new_lp_nr = new_lp->index;
@@ -2787,7 +2819,7 @@ maybe_duplicate_eh_stmt_fn (struct function *new_fun, gimple new_stmt,
     {
       eh_region old_r, new_r;
 
-      old_r = VEC_index (eh_region, old_fun->eh->region_array, -old_lp_nr);
+      old_r = (*old_fun->eh->region_array)[-old_lp_nr];
       slot = pointer_map_contains (map, old_r);
       new_r = (eh_region) *slot;
       new_lp_nr = -new_r->index;
@@ -2872,8 +2904,10 @@ optimize_double_finally (gimple one, gimple two)
 {
   gimple oneh;
   gimple_stmt_iterator gsi;
+  gimple_seq cleanup;
 
-  gsi = gsi_start (gimple_try_cleanup (one));
+  cleanup = gimple_try_cleanup (one);
+  gsi = gsi_start (cleanup);
   if (!gsi_one_before_end_p (gsi))
     return;
 
@@ -2965,6 +2999,7 @@ struct gimple_opt_pass pass_refactor_eh =
  {
   GIMPLE_PASS,
   "ehopt",                             /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   gate_refactor_eh,                    /* gate */
   refactor_eh,                         /* execute */
   NULL,                                        /* sub */
@@ -3040,6 +3075,8 @@ lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map)
              gimple_stmt_iterator gsi2;
 
              new_bb = create_empty_bb (bb);
+             if (current_loops)
+               add_bb_to_loop (new_bb, bb->loop_father);
              lab = gimple_block_label (new_bb);
              gsi2 = gsi_start_bb (new_bb);
 
@@ -3171,6 +3208,7 @@ struct gimple_opt_pass pass_lower_resx =
  {
   GIMPLE_PASS,
   "resx",                              /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   gate_lower_resx,                     /* gate */
   execute_lower_resx,                  /* execute */
   NULL,                                        /* sub */
@@ -3254,22 +3292,18 @@ sink_clobbers (basic_block bb)
   for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
     {
       gimple stmt = gsi_stmt (gsi);
-      tree vdef;
       if (is_gimple_debug (stmt))
        continue;
       if (gimple_code (stmt) == GIMPLE_LABEL)
        break;
       unlink_stmt_vdef (stmt);
       gsi_remove (&gsi, false);
-      vdef = gimple_vdef (stmt);
-      if (vdef && TREE_CODE (vdef) == SSA_NAME)
-       {
-         vdef = SSA_NAME_VAR (vdef);
-         mark_sym_for_renaming (vdef);
-         gimple_set_vdef (stmt, vdef);
-         gimple_set_vuse (stmt, vdef);
-       }
-      release_defs (stmt);
+      /* Trigger the operand scanner to cause renaming for virtual
+         operands for this statement.
+        ???  Given the simple structure of this code manually
+        figuring out the reaching definition should not be too hard.  */
+      if (gimple_vuse (stmt))
+       gimple_set_vuse (stmt, NULL_TREE);
       gsi_insert_before (&dgsi, stmt, GSI_SAME_STMT);
     }
 
@@ -3298,7 +3332,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
     {
     case ERT_TRY:
       {
-       VEC (tree, heap) *labels = NULL;
+       vec<tree> labels = vNULL;
        tree default_label = NULL;
        eh_catch c;
        edge_iterator ei;
@@ -3307,7 +3341,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
 
        /* Collect the labels for a switch.  Zero the post_landing_pad
           field becase we'll no longer have anything keeping these labels
-          in existance and the optimizer will be free to merge these
+          in existence and the optimizer will be free to merge these
           blocks at will.  */
        for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
          {
@@ -3334,7 +3368,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
                  {
                    tree t = build_case_label (TREE_VALUE (flt_node),
                                               NULL, lab);
-                   VEC_safe_push (tree, heap, labels, t);
+                   labels.safe_push (t);
                    pointer_set_insert (seen_values, TREE_VALUE (flt_node));
                    have_label = true;
                  }
@@ -3365,7 +3399,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
 
        /* Don't generate a switch if there's only a default case.
           This is common in the form of try { A; } catch (...) { B; }.  */
-       if (labels == NULL)
+       if (!labels.exists ())
          {
            e = single_succ_edge (src);
            e->flags |= EDGE_FALLTHRU;
@@ -3384,10 +3418,10 @@ lower_eh_dispatch (basic_block src, gimple stmt)
            default_label = build_case_label (NULL, NULL, default_label);
            sort_case_labels (labels);
 
-           x = gimple_build_switch_vec (filter, default_label, labels);
+           x = gimple_build_switch (filter, default_label, labels);
            gsi_insert_before (&gsi, x, GSI_SAME_STMT);
 
-           VEC_free (tree, heap, labels);
+           labels.release ();
          }
        pointer_set_destroy (seen_values);
       }
@@ -3471,6 +3505,7 @@ struct gimple_opt_pass pass_lower_eh_dispatch =
  {
   GIMPLE_PASS,
   "ehdisp",                            /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   gate_lower_eh_dispatch,              /* gate */
   execute_lower_eh_dispatch,           /* execute */
   NULL,                                        /* sub */
@@ -3485,23 +3520,37 @@ struct gimple_opt_pass pass_lower_eh_dispatch =
  }
 };
 \f
-/* Walk statements, see what regions are really referenced and remove
-   those that are unused.  */
+/* Walk statements, see what regions and, optionally, landing pads
+   are really referenced.
+   
+   Returns in R_REACHABLEP an sbitmap with bits set for reachable regions,
+   and in LP_REACHABLE an sbitmap with bits set for reachable landing pads.
+
+   Passing NULL for LP_REACHABLE is valid, in this case only reachable
+   regions are marked.
+
+   The caller is responsible for freeing the returned sbitmaps.  */
 
 static void
-remove_unreachable_handlers (void)
+mark_reachable_handlers (sbitmap *r_reachablep, sbitmap *lp_reachablep)
 {
   sbitmap r_reachable, lp_reachable;
-  eh_region region;
-  eh_landing_pad lp;
   basic_block bb;
-  int lp_nr, r_nr;
+  bool mark_landing_pads = (lp_reachablep != NULL);
+  gcc_checking_assert (r_reachablep != NULL);
 
-  r_reachable = sbitmap_alloc (VEC_length (eh_region, cfun->eh->region_array));
-  lp_reachable
-    = sbitmap_alloc (VEC_length (eh_landing_pad, cfun->eh->lp_array));
-  sbitmap_zero (r_reachable);
-  sbitmap_zero (lp_reachable);
+  r_reachable = sbitmap_alloc (cfun->eh->region_array->length ());
+  bitmap_clear (r_reachable);
+  *r_reachablep = r_reachable;
+
+  if (mark_landing_pads)
+    {
+      lp_reachable = sbitmap_alloc (cfun->eh->lp_array->length ());
+      bitmap_clear (lp_reachable);
+      *lp_reachablep = lp_reachable;
+    }
+  else
+    lp_reachable = NULL;
 
   FOR_EACH_BB (bb)
     {
@@ -3510,62 +3559,82 @@ remove_unreachable_handlers (void)
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
          gimple stmt = gsi_stmt (gsi);
-         lp_nr = lookup_stmt_eh_lp (stmt);
-
-         /* Negative LP numbers are MUST_NOT_THROW regions which
-            are not considered BB enders.  */
-         if (lp_nr < 0)
-           SET_BIT (r_reachable, -lp_nr);
 
-         /* Positive LP numbers are real landing pads, are are BB enders.  */
-         else if (lp_nr > 0)
+         if (mark_landing_pads)
            {
-             gcc_assert (gsi_one_before_end_p (gsi));
-             region = get_eh_region_from_lp_number (lp_nr);
-             SET_BIT (r_reachable, region->index);
-             SET_BIT (lp_reachable, lp_nr);
+             int lp_nr = lookup_stmt_eh_lp (stmt);
+
+             /* Negative LP numbers are MUST_NOT_THROW regions which
+                are not considered BB enders.  */
+             if (lp_nr < 0)
+               bitmap_set_bit (r_reachable, -lp_nr);
+
+             /* Positive LP numbers are real landing pads, and BB enders.  */
+             else if (lp_nr > 0)
+               {
+                 gcc_assert (gsi_one_before_end_p (gsi));
+                 eh_region region = get_eh_region_from_lp_number (lp_nr);
+                 bitmap_set_bit (r_reachable, region->index);
+                 bitmap_set_bit (lp_reachable, lp_nr);
+               }
            }
 
          /* Avoid removing regions referenced from RESX/EH_DISPATCH.  */
          switch (gimple_code (stmt))
            {
            case GIMPLE_RESX:
-             SET_BIT (r_reachable, gimple_resx_region (stmt));
+             bitmap_set_bit (r_reachable, gimple_resx_region (stmt));
              break;
            case GIMPLE_EH_DISPATCH:
-             SET_BIT (r_reachable, gimple_eh_dispatch_region (stmt));
+             bitmap_set_bit (r_reachable, gimple_eh_dispatch_region (stmt));
              break;
            default:
              break;
            }
        }
     }
+}
+
+/* Remove unreachable handlers and unreachable landing pads.  */
+
+static void
+remove_unreachable_handlers (void)
+{
+  sbitmap r_reachable, lp_reachable;
+  eh_region region;
+  eh_landing_pad lp;
+  unsigned i;
+
+  mark_reachable_handlers (&r_reachable, &lp_reachable);
 
   if (dump_file)
     {
       fprintf (dump_file, "Before removal of unreachable regions:\n");
       dump_eh_tree (dump_file, cfun);
       fprintf (dump_file, "Reachable regions: ");
-      dump_sbitmap_file (dump_file, r_reachable);
+      dump_bitmap_file (dump_file, r_reachable);
       fprintf (dump_file, "Reachable landing pads: ");
-      dump_sbitmap_file (dump_file, lp_reachable);
+      dump_bitmap_file (dump_file, lp_reachable);
     }
 
-  for (r_nr = 1;
-       VEC_iterate (eh_region, cfun->eh->region_array, r_nr, region); ++r_nr)
-    if (region && !TEST_BIT (r_reachable, r_nr))
-      {
-       if (dump_file)
-         fprintf (dump_file, "Removing unreachable region %d\n", r_nr);
-       remove_eh_handler (region);
-      }
+  if (dump_file)
+    {
+      FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
+       if (region && !bitmap_bit_p (r_reachable, region->index))
+         fprintf (dump_file,
+                  "Removing unreachable region %d\n",
+                  region->index);
+    }
+
+  remove_unreachable_eh_regions (r_reachable);
 
-  for (lp_nr = 1;
-       VEC_iterate (eh_landing_pad, cfun->eh->lp_array, lp_nr, lp); ++lp_nr)
-    if (lp && !TEST_BIT (lp_reachable, lp_nr))
+  FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp)
+    if (lp && !bitmap_bit_p (lp_reachable, lp->index))
       {
        if (dump_file)
-         fprintf (dump_file, "Removing unreachable landing pad %d\n", lp_nr);
+         fprintf (dump_file,
+                  "Removing unreachable landing pad %d\n",
+                  lp->index);
        remove_eh_landing_pad (lp);
       }
 
@@ -3591,12 +3660,12 @@ void
 maybe_remove_unreachable_handlers (void)
 {
   eh_landing_pad lp;
-  int i;
+  unsigned i;
 
   if (cfun->eh == NULL)
     return;
-              
-  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+           
+  FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp)
     if (lp && lp->post_landing_pad)
       {
        if (label_to_block (lp->post_landing_pad) == NULL)
@@ -3609,45 +3678,38 @@ maybe_remove_unreachable_handlers (void)
 
 /* 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.  */
+   that we've just manipulated the landing pads since then.
+
+   Preserve regions with landing pads and regions that prevent
+   exceptions from propagating further, even if these regions
+   are not reachable.  */
 
 static void
 remove_unreachable_handlers_no_lp (void)
 {
-  eh_region r;
-  int i;
+  eh_region region;
   sbitmap r_reachable;
-  basic_block bb;
+  unsigned i;
 
-  r_reachable = sbitmap_alloc (VEC_length (eh_region, cfun->eh->region_array));
-  sbitmap_zero (r_reachable);
+  mark_reachable_handlers (&r_reachable, /*lp_reachablep=*/NULL);
 
-  FOR_EACH_BB (bb)
+  FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
     {
-      gimple stmt = last_stmt (bb);
-      if (stmt)
-       /* Avoid removing regions referenced from RESX/EH_DISPATCH.  */
-       switch (gimple_code (stmt))
-         {
-         case GIMPLE_RESX:
-           SET_BIT (r_reachable, gimple_resx_region (stmt));
-           break;
-         case GIMPLE_EH_DISPATCH:
-           SET_BIT (r_reachable, gimple_eh_dispatch_region (stmt));
-           break;
-         default:
-           break;
-         }
+      if (! region)
+       continue;
+
+      if (region->landing_pads != NULL
+         || region->type == ERT_MUST_NOT_THROW)
+       bitmap_set_bit (r_reachable, region->index);
+
+      if (dump_file
+         && !bitmap_bit_p (r_reachable, region->index))
+       fprintf (dump_file,
+                "Removing unreachable region %d\n",
+                region->index);
     }
 
-  for (i = 1; VEC_iterate (eh_region, cfun->eh->region_array, i, r); ++i)
-    if (r && r->landing_pads == NULL && r->type != ERT_MUST_NOT_THROW
-       && !TEST_BIT (r_reachable, i))
-      {
-       if (dump_file)
-         fprintf (dump_file, "Removing unreachable region %d\n", i);
-       remove_eh_handler (r);
-      }
+  remove_unreachable_eh_regions (r_reachable);
 
   sbitmap_free (r_reachable);
 }
@@ -3766,7 +3828,7 @@ unsplit_all_eh (void)
   eh_landing_pad lp;
   int i;
 
-  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+  for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
     if (lp)
       changed |= unsplit_eh (lp);
 
@@ -3865,7 +3927,7 @@ cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb,
        }
       /* If we didn't find the PHI, but it's a VOP, remember to rename
         it later, assuming all other tests succeed.  */
-      else if (!is_gimple_reg (nresult))
+      else if (virtual_operand_p (nresult))
        bitmap_set_bit (rename_virts, SSA_NAME_VERSION (nresult));
       /* If we didn't find the PHI, and it's a real variable, we know
         from the fact that OLD_BB is tree_empty_eh_handler_p that the
@@ -3912,6 +3974,21 @@ cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb,
   for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)); )
     if (e->flags & EDGE_EH)
       {
+       /* ???  CFG manipluation routines do not try to update loop
+          form on edge redirection.  Do so manually here for now.  */
+       /* If we redirect a loop entry or latch edge that will either create
+          a multiple entry loop or rotate the loop.  If the loops merge
+          we may have created a loop with multiple latches.
+          All of this isn't easily fixed thus cancel the affected loop
+          and mark the other loop as possibly having multiple latches.  */
+       if (current_loops
+           && e->dest == e->dest->loop_father->header)
+         {
+           e->dest->loop_father->header = NULL;
+           e->dest->loop_father->latch = NULL;
+           new_bb->loop_father->latch = NULL;
+           loops_state_set (LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
+         }
        redirect_eh_edge_1 (e, new_bb, change_region);
        redirect_edge_succ (e, new_bb);
        flush_pending_stmts (e);
@@ -3951,7 +4028,7 @@ cleanup_empty_eh_move_lp (basic_block bb, edge e_out,
 
   /* Delete the RESX that was matched within the empty handler block.  */
   gsi = gsi_last_bb (bb);
-  mark_virtual_ops_for_renaming (gsi_stmt (gsi));
+  unlink_stmt_vdef (gsi_stmt (gsi));
   gsi_remove (&gsi, true);
 
   /* Clean up E_OUT for the fallthru.  */
@@ -4201,7 +4278,7 @@ cleanup_all_empty_eh (void)
   eh_landing_pad lp;
   int i;
 
-  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+  for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
     if (lp)
       changed |= cleanup_empty_eh (lp);
 
@@ -4279,6 +4356,7 @@ struct gimple_opt_pass pass_cleanup_eh = {
   {
    GIMPLE_PASS,
    "ehcleanup",                        /* name */
+   OPTGROUP_NONE,               /* optinfo_flags */
    gate_cleanup_eh,            /* gate */
    execute_cleanup_eh,         /* execute */
    NULL,                       /* sub */