OSDN Git Service

* lib/gcc-simulate-thread.exp (simulate-thread): Improve error message.
[pf3gnuchains/gcc-fork.git] / gcc / tree-eh.c
index 66fee8e..440ac0f 100644 (file)
@@ -1,5 +1,5 @@
 /* Exception handling semantics and decomposition for trees.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -54,26 +54,6 @@ using_eh_for_cleanups (void)
 
 /* Misc functions used in this file.  */
 
-/* Compare and hash for any structure which begins with a canonical
-   pointer.  Assumes all pointers are interchangeable, which is sort
-   of already assumed by gcc elsewhere IIRC.  */
-
-static int
-struct_ptr_eq (const void *a, const void *b)
-{
-  const void * const * x = (const void * const *) a;
-  const void * const * y = (const void * const *) b;
-  return *x == *y;
-}
-
-static hashval_t
-struct_ptr_hash (const void *a)
-{
-  const void * const * x = (const void * const *) a;
-  return (size_t)*x >> 4;
-}
-
-
 /* Remember and lookup EH landing pad data for arbitrary statements.
    Really this means any statement that could_throw_p.  We could
    stuff this information into the stmt_ann data structure, but:
@@ -284,6 +264,11 @@ collect_finally_tree (gimple stmt, gimple region)
       collect_finally_tree_1 (gimple_eh_filter_failure (stmt), region);
       break;
 
+    case GIMPLE_EH_ELSE:
+      collect_finally_tree_1 (gimple_eh_else_n_body (stmt), region);
+      collect_finally_tree_1 (gimple_eh_else_e_body (stmt), region);
+      break;
+
     default:
       /* A type, a decl, or some kind of statement that we're not
         interested in.  Don't walk them.  */
@@ -534,6 +519,10 @@ replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf,
     case GIMPLE_EH_FILTER:
       replace_goto_queue_stmt_list (gimple_eh_filter_failure (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);
+      break;
 
     default:
       /* These won't have gotos in them.  */
@@ -711,66 +700,35 @@ verify_norecord_switch_expr (struct leh_state *state, gimple switch_expr)
 #define verify_norecord_switch_expr(state, switch_expr)
 #endif
 
-/* Redirect a RETURN_EXPR pointed to by STMT_P to FINLAB.  Place in CONT_P
-   whatever is needed to finish the return.  If MOD is non-null, insert it
-   before the new branch.  RETURN_VALUE_P is a cache containing a temporary
-   variable to be used in manipulating the value returned from the function.  */
+/* Redirect a RETURN_EXPR pointed to by Q to FINLAB.  If MOD is
+   non-null, insert it before the new branch.  */
 
 static void
-do_return_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod,
-                      tree *return_value_p)
+do_return_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod)
 {
-  tree ret_expr;
   gimple x;
 
-  /* In the case of a return, the queue node must be a gimple statement. */
+  /* In the case of a return, the queue node must be a gimple statement.  */
   gcc_assert (!q->is_label);
 
-  ret_expr = gimple_return_retval (q->stmt.g);
-
-  if (ret_expr)
-    {
-      if (!*return_value_p)
-        *return_value_p = ret_expr;
-      else
-        gcc_assert (*return_value_p == ret_expr);
-      q->cont_stmt = q->stmt.g;
-      /* The nasty part about redirecting the return value is that the
-        return value itself is to be computed before the FINALLY block
-        is executed.  e.g.
-
-               int x;
-               int foo (void)
-               {
-                 x = 0;
-                 try {
-                   return x;
-                 } finally {
-                   x++;
-                 }
-               }
-
-         should return 0, not 1.  Arrange for this to happen by copying
-         computed the return value into a local temporary.  This also
-         allows us to redirect multiple return statements through the
-         same destination block; whether this is a net win or not really
-         depends, I guess, but it does make generation of the switch in
-         lower_try_finally_switch easier.  */
+  /* Note that the return value may have already been computed, e.g.,
 
-      if (TREE_CODE (ret_expr) == RESULT_DECL)
+       int x;
+       int foo (void)
        {
-         if (!*return_value_p)
-           *return_value_p = ret_expr;
-         else
-           gcc_assert (*return_value_p == ret_expr);
-         q->cont_stmt = q->stmt.g;
+         x = 0;
+         try {
+           return x;
+         } finally {
+           x++;
+         }
        }
-      else
-         gcc_unreachable ();
-    }
-  else
-      /* If we don't return a value, all return statements are the same.  */
-      q->cont_stmt = q->stmt.g;
+
+     should return 0, not 1.  We don't have to do anything to make
+     this happens because the return value has been placed in the
+     RESULT_DECL already.  */
+
+  q->cont_stmt = q->stmt.g;
 
   if (!q->repl_stmt)
     q->repl_stmt = gimple_seq_alloc ();
@@ -849,6 +807,8 @@ note_eh_region_may_contain_throw (eh_region region)
 {
   while (bitmap_set_bit (eh_region_may_contain_throw_map, region->index))
     {
+      if (region->type == ERT_MUST_NOT_THROW)
+       break;
       region = region->outer;
       if (region == NULL)
        break;
@@ -950,6 +910,21 @@ lower_try_finally_fallthru_label (struct leh_tf_state *tf)
   return label;
 }
 
+/* A subroutine of lower_try_finally.  If FINALLY consits of a
+   GIMPLE_EH_ELSE node, return it.  */
+
+static inline gimple
+get_eh_else (gimple_seq finally)
+{
+  gimple x = gimple_seq_first_stmt (finally);
+  if (gimple_code (x) == GIMPLE_EH_ELSE)
+    {
+      gcc_assert (gimple_seq_singleton_p (finally));
+      return x;
+    }
+  return NULL;
+}
+
 /* A subroutine of lower_try_finally.  If the eh_protect_cleanup_actions
    langhook returns non-null, then the language requires that the exception
    path out of a try_finally be treated specially.  To wit: the code within
@@ -979,7 +954,7 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
   gimple_stmt_iterator gsi;
   bool finally_may_fallthru;
   gimple_seq finally;
-  gimple x;
+  gimple x, eh_else;
 
   /* First check for nothing to do.  */
   if (lang_hooks.eh_protect_cleanup_actions == NULL)
@@ -989,12 +964,18 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
     return;
 
   finally = gimple_try_cleanup (tf->top_p);
-  finally_may_fallthru = gimple_seq_may_fallthru (finally);
+  eh_else = get_eh_else (finally);
 
   /* Duplicate the FINALLY block.  Only need to do this for try-finally,
-     and not for cleanups.  */
-  if (this_state)
+     and not for cleanups.  If we've got an EH_ELSE, extract it now.  */
+  if (eh_else)
+    {
+      finally = gimple_eh_else_e_body (eh_else);
+      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_may_fallthru = gimple_seq_may_fallthru (finally);
 
   /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP
      set, the handler of the TRY_CATCH_EXPR is another cleanup which ought
@@ -1039,8 +1020,8 @@ static void
 lower_try_finally_nofallthru (struct leh_state *state,
                              struct leh_tf_state *tf)
 {
-  tree lab, return_val;
-  gimple x;
+  tree lab;
+  gimple x, eh_else;
   gimple_seq finally;
   struct goto_queue_node *q, *qe;
 
@@ -1053,26 +1034,45 @@ lower_try_finally_nofallthru (struct leh_state *state,
   x = gimple_build_label (lab);
   gimple_seq_add_stmt (&tf->top_p_seq, x);
 
-  return_val = NULL;
   q = tf->goto_queue;
   qe = q + tf->goto_queue_active;
   for (; q < qe; ++q)
     if (q->index < 0)
-      do_return_redirection (q, lab, NULL, &return_val);
+      do_return_redirection (q, lab, NULL);
     else
       do_goto_redirection (q, lab, NULL, tf);
 
   replace_goto_queue (tf);
 
-  lower_eh_constructs_1 (state, finally);
-  gimple_seq_add_seq (&tf->top_p_seq, finally);
+  /* Emit the finally block into the stream.  Lower EH_ELSE at this time.  */
+  eh_else = get_eh_else (finally);
+  if (eh_else)
+    {
+      finally = gimple_eh_else_n_body (eh_else);
+      lower_eh_constructs_1 (state, finally);
+      gimple_seq_add_seq (&tf->top_p_seq, finally);
 
-  if (tf->may_throw)
+      if (tf->may_throw)
+       {
+         finally = gimple_eh_else_e_body (eh_else);
+         lower_eh_constructs_1 (state, finally);
+
+         emit_post_landing_pad (&eh_seq, tf->region);
+         gimple_seq_add_seq (&eh_seq, finally);
+       }
+    }
+  else
     {
-      emit_post_landing_pad (&eh_seq, tf->region);
+      lower_eh_constructs_1 (state, finally);
+      gimple_seq_add_seq (&tf->top_p_seq, finally);
 
-      x = gimple_build_goto (lab);
-      gimple_seq_add_stmt (&eh_seq, x);
+      if (tf->may_throw)
+       {
+         emit_post_landing_pad (&eh_seq, tf->region);
+
+         x = gimple_build_goto (lab);
+         gimple_seq_add_stmt (&eh_seq, x);
+       }
     }
 }
 
@@ -1092,6 +1092,18 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
   finally = gimple_try_cleanup (tf->top_p);
   tf->top_p_seq = gimple_try_eval (tf->top_p);
 
+  /* Since there's only one destination, and the destination edge can only
+     either be EH or non-EH, that implies that all of our incoming edges
+     are of the same type.  Therefore we can lower EH_ELSE immediately.  */
+  x = get_eh_else (finally);
+  if (x)
+    {
+      if (tf->may_throw)
+       finally = gimple_eh_else_e_body (x);
+      else
+       finally = gimple_eh_else_n_body (x);
+    }
+
   lower_eh_constructs_1 (state, finally);
 
   if (tf->may_throw)
@@ -1124,9 +1136,8 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
   if (tf->may_return)
     {
       /* Reachable by return expressions only.  Redirect them.  */
-      tree return_val = NULL;
       for (; q < qe; ++q)
-       do_return_redirection (q, finally_label, NULL, &return_val);
+       do_return_redirection (q, finally_label, NULL);
       replace_goto_queue (tf);
     }
   else
@@ -1163,11 +1174,18 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
   gimple_seq finally;
   gimple_seq new_stmt;
   gimple_seq seq;
-  gimple x;
+  gimple x, eh_else;
   tree tmp;
   location_t tf_loc = gimple_location (tf->try_finally_expr);
 
   finally = gimple_try_cleanup (tf->top_p);
+
+  /* Notice EH_ELSE, and simplify some of the remaining code
+     by considering FINALLY to be the normal return path only.  */
+  eh_else = get_eh_else (finally);
+  if (eh_else)
+    finally = gimple_eh_else_n_body (eh_else);
+
   tf->top_p_seq = gimple_try_eval (tf->top_p);
   new_stmt = NULL;
 
@@ -1184,7 +1202,12 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
 
   if (tf->may_throw)
     {
-      seq = lower_try_finally_dup_block (finally, state);
+      /* We don't need to copy the EH path of EH_ELSE,
+        since it is only emitted once.  */
+      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);
 
       emit_post_landing_pad (&eh_seq, tf->region);
@@ -1195,7 +1218,6 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
   if (tf->goto_queue)
     {
       struct goto_queue_node *q, *qe;
-      tree return_val = NULL;
       int return_index, index;
       struct labels_s
       {
@@ -1228,7 +1250,7 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
            = create_artificial_label (tf_loc);
 
          if (index == return_index)
-           do_return_redirection (q, lab, NULL, &return_val);
+           do_return_redirection (q, lab, NULL);
          else
            do_goto_redirection (q, lab, NULL, tf);
 
@@ -1255,7 +1277,7 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
          lab = labels[index].label;
 
          if (index == return_index)
-           do_return_redirection (q, lab, NULL, &return_val);
+           do_return_redirection (q, lab, NULL);
          else
            do_goto_redirection (q, lab, NULL, tf);
        }
@@ -1278,14 +1300,13 @@ static void
 lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
 {
   struct goto_queue_node *q, *qe;
-  tree return_val = NULL;
   tree finally_tmp, finally_label;
   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;
-  gimple x;
+  gimple x, eh_else;
   tree tmp;
   gimple switch_stmt;
   gimple_seq finally;
@@ -1296,9 +1317,10 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   location_t finally_loc;
 
   switch_body = gimple_seq_alloc ();
+  finally = gimple_try_cleanup (tf->top_p);
+  eh_else = get_eh_else (finally);
 
   /* Mash the TRY block to the head of the chain.  */
-  finally = gimple_try_cleanup (tf->top_p);
   tf->top_p_seq = gimple_try_eval (tf->top_p);
 
   /* The location of the finally is either the last stmt in the finally
@@ -1314,7 +1336,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   nlabels = VEC_length (tree, tf->dest_array);
   return_index = nlabels;
   eh_index = return_index + tf->may_return;
-  fallthru_index = eh_index + tf->may_throw;
+  fallthru_index = eh_index + (tf->may_throw && !eh_else);
   ndests = fallthru_index + tf->may_fallthru;
 
   finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
@@ -1334,12 +1356,13 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   if (tf->may_fallthru)
     {
       x = gimple_build_assign (finally_tmp,
-                              build_int_cst (NULL, fallthru_index));
+                              build_int_cst (integer_type_node,
+                                             fallthru_index));
       gimple_seq_add_stmt (&tf->top_p_seq, x);
 
-      last_case = build3 (CASE_LABEL_EXPR, void_type_node,
-                         build_int_cst (NULL, fallthru_index),
-                         NULL, create_artificial_label (tf_loc));
+      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);
       last_case_index++;
 
@@ -1351,20 +1374,36 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       gimple_seq_add_stmt (&switch_body, x);
     }
 
-  if (tf->may_throw)
+  /* For EH_ELSE, emit the exception path (plus resx) now, then
+     subsequently we only need consider the normal path.  */
+  if (eh_else)
+    {
+      if (tf->may_throw)
+       {
+         finally = gimple_eh_else_e_body (eh_else);
+         lower_eh_constructs_1 (state, finally);
+
+         emit_post_landing_pad (&eh_seq, tf->region);
+         gimple_seq_add_seq (&eh_seq, finally);
+         emit_resx (&eh_seq, tf->region);
+       }
+
+      finally = gimple_eh_else_n_body (eh_else);
+    }
+  else if (tf->may_throw)
     {
       emit_post_landing_pad (&eh_seq, tf->region);
 
       x = gimple_build_assign (finally_tmp,
-                              build_int_cst (NULL, eh_index));
+                              build_int_cst (integer_type_node, eh_index));
       gimple_seq_add_stmt (&eh_seq, x);
 
       x = gimple_build_goto (finally_label);
       gimple_seq_add_stmt (&eh_seq, x);
 
-      last_case = build3 (CASE_LABEL_EXPR, void_type_node,
-                         build_int_cst (NULL, eh_index),
-                         NULL, create_artificial_label (tf_loc));
+      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);
       last_case_index++;
 
@@ -1395,15 +1434,16 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       if (q->index < 0)
        {
          x = gimple_build_assign (finally_tmp,
-                                  build_int_cst (NULL, return_index));
+                                  build_int_cst (integer_type_node,
+                                                 return_index));
          gimple_seq_add_stmt (&mod, x);
-         do_return_redirection (q, finally_label, mod, &return_val);
+         do_return_redirection (q, finally_label, mod);
          switch_id = return_index;
        }
       else
        {
          x = gimple_build_assign (finally_tmp,
-                                  build_int_cst (NULL, q->index));
+                                  build_int_cst (integer_type_node, q->index));
          gimple_seq_add_stmt (&mod, x);
          do_goto_redirection (q, finally_label, mod, tf);
          switch_id = q->index;
@@ -1415,13 +1455,11 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
         {
           tree case_lab;
           void **slot;
-          case_lab = build3 (CASE_LABEL_EXPR, void_type_node,
-                             build_int_cst (NULL, switch_id),
-                            NULL, NULL);
+         tmp = build_int_cst (integer_type_node, switch_id);
+          case_lab = build_case_label (tmp, NULL,
+                                      create_artificial_label (tf_loc));
           /* We store the cont_stmt in the pointer map, so that we can recover
-             it in the loop below.  We don't create the new label while
-             walking the goto_queue because pointers don't offer a stable
-             order.  */
+             it in the loop below.  */
           if (!cont_map)
             cont_map = pointer_map_create ();
           slot = pointer_map_insert (cont_map, case_lab);
@@ -1431,7 +1469,6 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
     }
   for (j = last_case_index; j < last_case_index + nlabels; j++)
     {
-      tree label;
       gimple cont_stmt;
       void **slot;
 
@@ -1441,15 +1478,10 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       gcc_assert (cont_map);
 
       slot = pointer_map_contains (cont_map, last_case);
-      /* As the comment above suggests, CASE_LABEL (last_case) was just a
-         placeholder, it does not store an actual label, yet. */
       gcc_assert (slot);
       cont_stmt = *(gimple *) slot;
 
-      label = create_artificial_label (tf_loc);
-      CASE_LABEL (last_case) = label;
-
-      x = gimple_build_label (label);
+      x = gimple_build_label (CASE_LABEL (last_case));
       gimple_seq_add_stmt (&switch_body, x);
       gimple_seq_add_stmt (&switch_body, cont_stmt);
       maybe_record_in_goto_queue (state, cont_stmt);
@@ -1491,12 +1523,22 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
    the estimate of the size of the switch machinery we'd have to add.  */
 
 static bool
-decide_copy_try_finally (int ndests, gimple_seq finally)
+decide_copy_try_finally (int ndests, bool may_throw, gimple_seq finally)
 {
   int f_estimate, sw_estimate;
+  gimple eh_else;
+
+  /* If there's an EH_ELSE involved, the exception path is separate
+     and really doesn't come into play for this computation.  */
+  eh_else = get_eh_else (finally);
+  if (eh_else)
+    {
+      ndests -= may_throw;
+      finally = gimple_eh_else_n_body (eh_else);
+    }
 
   if (!optimize)
-    return false;
+    return ndests == 1;
 
   /* Finally estimate N times, plus N gotos.  */
   f_estimate = count_insns_seq (finally, &eni_size_weights);
@@ -1602,7 +1644,8 @@ lower_try_finally (struct leh_state *state, gimple tp)
   /* We can easily special-case redirection to a single destination.  */
   else if (ndests == 1)
     lower_try_finally_onedest (state, &this_tf);
-  else if (decide_copy_try_finally (ndests, gimple_try_cleanup (tp)))
+  else if (decide_copy_try_finally (ndests, this_tf.may_throw,
+                                   gimple_try_cleanup (tp)))
     lower_try_finally_copy (state, &this_tf);
   else
     lower_try_finally_switch (state, &this_tf);
@@ -1617,8 +1660,7 @@ lower_try_finally (struct leh_state *state, gimple tp)
     }
 
   VEC_free (tree, heap, this_tf.dest_array);
-  if (this_tf.goto_queue)
-    free (this_tf.goto_queue);
+  free (this_tf.goto_queue);
   if (this_tf.goto_queue_map)
     pointer_map_destroy (this_tf.goto_queue_map);
 
@@ -1870,7 +1912,8 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
                 this zero argument with the current catch region number.  */
              if (state->ehp_region)
                {
-                 tree nr = build_int_cst (NULL, state->ehp_region->index);
+                 tree nr = build_int_cst (integer_type_node,
+                                          state->ehp_region->index);
                  gimple_call_set_arg (stmt, 0, nr);
                }
              else
@@ -1967,6 +2010,9 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
                case GIMPLE_EH_MUST_NOT_THROW:
                    replace = lower_eh_must_not_throw (state, stmt);
                    break;
+               case GIMPLE_EH_ELSE:
+                   /* This code is only valid with GIMPLE_TRY_FINALLY.  */
+                   gcc_unreachable ();
                default:
                    replace = lower_cleanup (state, stmt);
                    break;
@@ -1981,6 +2027,10 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
       /* Return since we don't want gsi_next () */
       return;
 
+    case GIMPLE_EH_ELSE:
+      /* We should be eliminating this in lower_try_finally et al.  */
+      gcc_unreachable ();
+
     default:
       /* A type, a decl, or some kind of statement that we're not
         interested in.  Don't walk them.  */
@@ -2056,7 +2106,7 @@ struct gimple_opt_pass pass_lower_eh =
   PROP_gimple_leh,                     /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func                       /* todo_flags_finish */
+  0                                    /* todo_flags_finish */
  }
 };
 \f
@@ -2334,6 +2384,11 @@ operation_could_trap_helper_p (enum tree_code op,
        return true;
       return false;
 
+    case COMPLEX_EXPR:
+    case CONSTRUCTOR:
+      /* Constructing an object cannot trap.  */
+      return false;
+
     default:
       /* Any floating arithmetic may trap.  */
       if (fp_operation && flag_trapping_math)
@@ -2448,8 +2503,42 @@ tree_could_trap_p (tree expr)
     case CALL_EXPR:
       t = get_callee_fndecl (expr);
       /* Assume that calls to weak functions may trap.  */
-      if (!t || !DECL_P (t) || DECL_WEAK (t))
+      if (!t || !DECL_P (t))
        return true;
+      if (DECL_WEAK (t))
+       return tree_could_trap_p (t);
+      return false;
+
+    case FUNCTION_DECL:
+      /* Assume that accesses to weak functions may trap, unless we know
+        they are certainly defined in current TU or in some other
+        LTO partition.  */
+      if (DECL_WEAK (expr))
+       {
+         struct cgraph_node *node;
+         if (!DECL_EXTERNAL (expr))
+           return false;
+         node = cgraph_function_node (cgraph_get_node (expr), NULL);
+         if (node && node->in_other_partition)
+           return false;
+         return true;
+       }
+      return false;
+
+    case VAR_DECL:
+      /* Assume that accesses to weak vars may trap, unless we know
+        they are certainly defined in current TU or in some other
+        LTO partition.  */
+      if (DECL_WEAK (expr))
+       {
+         struct varpool_node *node;
+         if (!DECL_EXTERNAL (expr))
+           return false;
+         node = varpool_variable_node (varpool_get_node (expr), NULL);
+         if (node && node->in_other_partition)
+           return false;
+         return true;
+       }
       return false;
 
     default:
@@ -2477,7 +2566,13 @@ stmt_could_throw_1_p (gimple stmt)
       || TREE_CODE_CLASS (code) == tcc_unary
       || TREE_CODE_CLASS (code) == tcc_binary)
     {
-      t = gimple_expr_type (stmt);
+      if (is_gimple_assign (stmt)
+         && TREE_CODE_CLASS (code) == tcc_comparison)
+       t = TREE_TYPE (gimple_assign_rhs1 (stmt));
+      else if (gimple_code (stmt) == GIMPLE_COND)
+       t = TREE_TYPE (gimple_cond_lhs (stmt));
+      else
+       t = gimple_expr_type (stmt);
       fp_operation = FLOAT_TYPE_P (t);
       if (fp_operation)
        {
@@ -2738,7 +2833,7 @@ same_handler_p (gimple_seq oneh, gimple_seq twoh)
       || gimple_call_lhs (twos)
       || gimple_call_chain (ones)
       || gimple_call_chain (twos)
-      || !operand_equal_p (gimple_call_fn (ones), gimple_call_fn (twos), 0)
+      || !gimple_call_same_target_p (ones, twos)
       || gimple_call_num_args (ones) != gimple_call_num_args (twos))
     return false;
 
@@ -2826,6 +2921,10 @@ refactor_eh_r (gimple_seq seq)
          case GIMPLE_EH_FILTER:
            refactor_eh_r (gimple_eh_filter_failure (one));
            break;
+         case GIMPLE_EH_ELSE:
+           refactor_eh_r (gimple_eh_else_n_body (one));
+           refactor_eh_r (gimple_eh_else_e_body (one));
+           break;
          default:
            break;
          }
@@ -2864,7 +2963,7 @@ struct gimple_opt_pass pass_refactor_eh =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func                       /* todo_flags_finish */
+  0                                    /* todo_flags_finish */
  }
 };
 \f
@@ -2899,7 +2998,7 @@ lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map)
 
         Resolve this by expanding the resx node to an abort.  */
 
-      fn = implicit_built_in_decls[BUILT_IN_TRAP];
+      fn = builtin_decl_implicit (BUILT_IN_TRAP);
       x = gimple_build_call (fn, 0);
       gsi_insert_before (&gsi, x, GSI_SAME_STMT);
 
@@ -2954,10 +3053,10 @@ lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map)
       else
        {
          edge_iterator ei;
-         tree dst_nr = build_int_cst (NULL, dst_r->index);
+         tree dst_nr = build_int_cst (integer_type_node, dst_r->index);
 
-         fn = implicit_built_in_decls[BUILT_IN_EH_COPY_VALUES];
-         src_nr = build_int_cst (NULL, src_r->index);
+         fn = builtin_decl_implicit (BUILT_IN_EH_COPY_VALUES);
+         src_nr = build_int_cst (integer_type_node, src_r->index);
          x = gimple_build_call (fn, 2, dst_nr, src_nr);
          gsi_insert_before (&gsi, x, GSI_SAME_STMT);
 
@@ -2991,21 +3090,21 @@ lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map)
         with no arguments for C++ and Java.  Check for that.  */
       if (src_r->use_cxa_end_cleanup)
        {
-         fn = implicit_built_in_decls[BUILT_IN_CXA_END_CLEANUP];
+         fn = builtin_decl_implicit (BUILT_IN_CXA_END_CLEANUP);
          x = gimple_build_call (fn, 0);
          gsi_insert_before (&gsi, x, GSI_SAME_STMT);
        }
       else
        {
-         fn = implicit_built_in_decls[BUILT_IN_EH_POINTER];
-         src_nr = build_int_cst (NULL, src_r->index);
+         fn = builtin_decl_implicit (BUILT_IN_EH_POINTER);
+         src_nr = build_int_cst (integer_type_node, src_r->index);
          x = gimple_build_call (fn, 1, src_nr);
          var = create_tmp_var (ptr_type_node, NULL);
          var = make_ssa_name (var, x);
          gimple_call_set_lhs (x, var);
          gsi_insert_before (&gsi, x, GSI_SAME_STMT);
 
-         fn = implicit_built_in_decls[BUILT_IN_UNWIND_RESUME];
+         fn = builtin_decl_implicit (BUILT_IN_UNWIND_RESUME);
          x = gimple_build_call (fn, 1, var);
          gsi_insert_before (&gsi, x, GSI_SAME_STMT);
        }
@@ -3070,7 +3169,7 @@ struct gimple_opt_pass pass_lower_resx =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_verify_flow    /* todo_flags_finish */
+  TODO_verify_flow                     /* todo_flags_finish */
  }
 };
 
@@ -3131,8 +3230,8 @@ lower_eh_dispatch (basic_block src, gimple stmt)
                   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);
+                   tree t = build_case_label (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;
@@ -3171,16 +3270,16 @@ lower_eh_dispatch (basic_block src, gimple stmt)
          }
        else
          {
-           fn = implicit_built_in_decls[BUILT_IN_EH_FILTER];
-           x = gimple_build_call (fn, 1, build_int_cst (NULL, region_nr));
+           fn = builtin_decl_implicit (BUILT_IN_EH_FILTER);
+           x = gimple_build_call (fn, 1, build_int_cst (integer_type_node,
+                                                        region_nr));
            filter = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
            filter = make_ssa_name (filter, x);
            gimple_call_set_lhs (x, filter);
            gsi_insert_before (&gsi, x, GSI_SAME_STMT);
 
            /* Turn the default label into a default case.  */
-           default_label = build3 (CASE_LABEL_EXPR, void_type_node,
-                                   NULL, NULL, default_label);
+           default_label = build_case_label (NULL, NULL, default_label);
            sort_case_labels (labels);
 
            x = gimple_build_switch_vec (filter, default_label, labels);
@@ -3197,8 +3296,9 @@ lower_eh_dispatch (basic_block src, gimple stmt)
        edge b_e = BRANCH_EDGE (src);
        edge f_e = FALLTHRU_EDGE (src);
 
-       fn = implicit_built_in_decls[BUILT_IN_EH_FILTER];
-       x = gimple_build_call (fn, 1, build_int_cst (NULL, region_nr));
+       fn = builtin_decl_implicit (BUILT_IN_EH_FILTER);
+       x = gimple_build_call (fn, 1, build_int_cst (integer_type_node,
+                                                    region_nr));
        filter = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
        filter = make_ssa_name (filter, x);
        gimple_call_set_lhs (x, filter);
@@ -3270,7 +3370,7 @@ struct gimple_opt_pass pass_lower_eh_dispatch =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_verify_flow    /* todo_flags_finish */
+  TODO_verify_flow                     /* todo_flags_finish */
  }
 };
 \f
@@ -3294,7 +3394,7 @@ remove_unreachable_handlers (void)
 
   FOR_EACH_BB (bb)
     {
-      gimple_stmt_iterator gsi = gsi_start_bb (bb);
+      gimple_stmt_iterator gsi;
 
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
@@ -3314,6 +3414,19 @@ remove_unreachable_handlers (void)
              SET_BIT (r_reachable, region->index);
              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));
+             break;
+           case GIMPLE_EH_DISPATCH:
+             SET_BIT (r_reachable, gimple_eh_dispatch_region (stmt));
+             break;
+           default:
+             break;
+           }
        }
     }
 
@@ -3547,6 +3660,20 @@ cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb,
       /* If we did find the corresponding PHI, copy those inputs.  */
       if (ophi)
        {
+         /* If NOP is used somewhere else beyond phis in new_bb, give up.  */
+         if (!has_single_use (nop))
+           {
+             imm_use_iterator imm_iter;
+             use_operand_p use_p;
+
+             FOR_EACH_IMM_USE_FAST (use_p, imm_iter, nop)
+               {
+                 if (!gimple_debug_bind_p (USE_STMT (use_p))
+                     && (gimple_code (USE_STMT (use_p)) != GIMPLE_PHI
+                         || gimple_bb (USE_STMT (use_p)) != new_bb))
+                   goto fail;
+               }
+           }
          bitmap_set_bit (ophi_handled, SSA_NAME_VERSION (nop));
          FOR_EACH_EDGE (e, ei, old_bb->preds)
            {
@@ -3665,6 +3792,8 @@ cleanup_empty_eh_unsplit (basic_block bb, edge e_out, eh_landing_pad lp)
 {
   gimple_stmt_iterator gsi;
   tree lab;
+  edge_iterator ei;
+  edge e;
 
   /* We really ought not have totally lost everything following
      a landing pad label.  Given that BB is empty, there had better
@@ -3687,6 +3816,22 @@ cleanup_empty_eh_unsplit (basic_block bb, edge e_out, eh_landing_pad lp)
        return false;
     }
 
+  /* The destination block must not be a regular successor for any
+     of the preds of the landing pad.  Thus, avoid turning
+        <..>
+        |  \ EH
+        |  <..>
+        |  /
+       <..>
+     into
+        <..>
+       |  | EH
+       <..>
+     which CFG verification would choke on.  See PR45172.  */
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    if (find_edge (e->src, e_out->dest))
+      return false;
+
   /* Attempt to move the PHIs into the successor block.  */
   if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out, false))
     {
@@ -3701,6 +3846,42 @@ cleanup_empty_eh_unsplit (basic_block bb, edge e_out, eh_landing_pad lp)
   return false;
 }
 
+/* Return true if edge E_FIRST is part of an empty infinite loop
+   or leads to such a loop through a series of single successor
+   empty bbs.  */
+
+static bool
+infinite_empty_loop_p (edge e_first)
+{
+  bool inf_loop = false;
+  edge e;
+
+  if (e_first->dest == e_first->src)
+    return true;
+
+  e_first->src->aux = (void *) 1;
+  for (e = e_first; single_succ_p (e->dest); e = single_succ_edge (e->dest))
+    {
+      gimple_stmt_iterator gsi;
+      if (e->dest->aux)
+       {
+         inf_loop = true;
+         break;
+       }
+      e->dest->aux = (void *) 1;
+      gsi = gsi_after_labels (e->dest);
+      if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
+       gsi_next_nondebug (&gsi);
+      if (!gsi_end_p (gsi))
+       break;
+    }
+  e_first->src->aux = NULL;
+  for (e = e_first; e->dest->aux; e = single_succ_edge (e->dest))
+    e->dest->aux = NULL;
+
+  return inf_loop;
+}
+
 /* Examine the block associated with LP to determine if it's an empty
    handler for its EH region.  If so, attempt to redirect EH edges to
    an outer region.  Return true the CFG was updated in any way.  This
@@ -3738,10 +3919,23 @@ cleanup_empty_eh (eh_landing_pad lp)
 
   /* If the block is totally empty, look for more unsplitting cases.  */
   if (gsi_end_p (gsi))
-    return cleanup_empty_eh_unsplit (bb, e_out, lp);
+    {
+      /* For the degenerate case of an infinite loop bail out.  */
+      if (infinite_empty_loop_p (e_out))
+       return false;
 
-  /* The block should consist only of a single RESX statement.  */
+      return cleanup_empty_eh_unsplit (bb, e_out, lp);
+    }
+
+  /* The block should consist only of a single RESX statement, modulo a
+     preceding call to __builtin_stack_restore if there is no outgoing
+     edge, since the call can be eliminated in this case.  */
   resx = gsi_stmt (gsi);
+  if (!e_out && gimple_call_builtin_p (resx, BUILT_IN_STACK_RESTORE))
+    {
+      gsi_next (&gsi);
+      resx = gsi_stmt (gsi);
+    }
   if (!is_gimple_resx (resx))
     return false;
   gcc_assert (gsi_one_before_end_p (gsi));
@@ -3926,7 +4120,7 @@ struct gimple_opt_pass pass_cleanup_eh = {
    0,                          /* properties_provided */
    0,                          /* properties_destroyed */
    0,                          /* todo_flags_start */
-   TODO_dump_func              /* todo_flags_finish */
+   0                           /* todo_flags_finish */
    }
 };
 \f