OSDN Git Service

* gcc.dg/titype-1.c: Enable TImode on __SPU__.
[pf3gnuchains/gcc-fork.git] / gcc / tree-eh.c
index 56b1b94..270d76d 100644 (file)
@@ -1,5 +1,5 @@
 /* Exception handling semantics and decomposition for trees.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -23,11 +23,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "rtl.h"
-#include "tm_p.h"
 #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"
@@ -36,7 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "timevar.h"
 #include "langhooks.h"
 #include "ggc.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "gimple.h"
 #include "target.h"
 
@@ -97,7 +96,7 @@ add_stmt_to_eh_lp_fn (struct function *ifun, gimple t, int num)
 
   gcc_assert (num != 0);
 
-  n = GGC_NEW (struct throw_stmt_node);
+  n = ggc_alloc_throw_stmt_node ();
   n->stmt = t;
   n->lp_nr = num;
 
@@ -203,21 +202,6 @@ lookup_stmt_eh_lp (gimple t)
   return lookup_stmt_eh_lp_fn (cfun, t);
 }
 
-/* Likewise, but reference a tree expression instead.  */
-
-int
-lookup_expr_eh_lp (tree t)
-{
-  if (cfun && cfun->eh->throw_stmt_table && t && EXPR_P (t))
-    {
-      tree_ann_common_t ann = tree_common_ann (t);
-      if (ann)
-       return ann->lp_nr;
-    }
-  return 0;
-}
-
-
 /* First pass of EH node decomposition.  Build up a tree of GIMPLE_TRY_FINALLY
    nodes and LABEL_DECL nodes.  We will use this during the second phase to
    determine if a goto leaves the body of a TRY_FINALLY_EXPR node.  */
@@ -334,13 +318,13 @@ outside_finally_tree (treemple start, gimple target)
    The eh region creation is straight-forward, but frobbing all the gotos
    and such into shape isn't.  */
 
-/* The sequence into which we record all EH stuff.  This will be 
+/* The sequence into which we record all EH stuff.  This will be
    placed at the end of the function when we're all done.  */
 static gimple_seq eh_seq;
 
 /* Record whether an EH region contains something that can throw,
    indexed by EH region number.  */
-static bitmap eh_region_may_contain_throw;
+static bitmap eh_region_may_contain_throw_map;
 
 /* The GOTO_QUEUE is is an array of GIMPLE_GOTO and GIMPLE_RETURN
    statements that are seen to escape this GIMPLE_TRY_FINALLY node.
@@ -578,6 +562,7 @@ 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);
 }
 
 /* Add a new record to the goto queue contained in TF. NEW_STMT is the
@@ -658,7 +643,6 @@ record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label)
      labels. */
   new_stmt = stmt;
   record_in_goto_queue (tf, new_stmt, index, true);
-
 }
 
 /* For any GIMPLE_GOTO or GIMPLE_RETURN, decide whether it leaves a try_finally
@@ -863,15 +847,23 @@ emit_eh_dispatch (gimple_seq *seq, eh_region region)
 static void
 note_eh_region_may_contain_throw (eh_region region)
 {
-  while (!bitmap_bit_p (eh_region_may_contain_throw, region->index))
+  while (bitmap_set_bit (eh_region_may_contain_throw_map, region->index))
     {
-      bitmap_set_bit (eh_region_may_contain_throw, region->index);
       region = region->outer;
       if (region == NULL)
        break;
     }
 }
 
+/* Check if REGION has been marked as containing a throw.  If REGION is
+   NULL, this predicate is false.  */
+
+static inline bool
+eh_region_may_contain_throw (eh_region r)
+{
+  return r && bitmap_bit_p (eh_region_may_contain_throw_map, r->index);
+}
+
 /* We want to transform
        try { body; } catch { stuff; }
    to
@@ -958,12 +950,12 @@ lower_try_finally_fallthru_label (struct leh_tf_state *tf)
   return label;
 }
 
-/* A subroutine of lower_try_finally.  If lang_protect_cleanup_actions
-   returns non-null, then the language requires that the exception path out
-   of a try_finally be treated specially.  To wit: the code within the
-   finally block may not itself throw an exception.  We have two choices here.
-   First we can duplicate the finally block and wrap it in a must_not_throw
-   region.  Second, we can generate code like
+/* 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
+   the finally block may not itself throw an exception.  We have two choices
+   here. First we can duplicate the finally block and wrap it in a
+   must_not_throw region.  Second, we can generate code like
 
        try {
          finally_block;
@@ -990,9 +982,9 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
   gimple x;
 
   /* First check for nothing to do.  */
-  if (lang_protect_cleanup_actions == NULL)
+  if (lang_hooks.eh_protect_cleanup_actions == NULL)
     return;
-  protect_cleanup_actions = lang_protect_cleanup_actions ();
+  protect_cleanup_actions = lang_hooks.eh_protect_cleanup_actions ();
   if (protect_cleanup_actions == NULL)
     return;
 
@@ -1524,6 +1516,20 @@ decide_copy_try_finally (int ndests, gimple_seq finally)
     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
@@ -1536,6 +1542,7 @@ lower_try_finally (struct leh_state *state, gimple tp)
   struct leh_tf_state this_tf;
   struct leh_state this_state;
   int ndests;
+  gimple_seq old_eh_seq;
 
   /* Process the try block.  */
 
@@ -1543,24 +1550,31 @@ lower_try_finally (struct leh_state *state, gimple tp)
   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
-    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;
 
+  old_eh_seq = eh_seq;
+  eh_seq = NULL;
+
   lower_eh_constructs_1 (&this_state, gimple_try_eval(tp));
 
   /* Determine if the try block is escaped through the bottom.  */
   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)
-    this_tf.may_throw = bitmap_bit_p (eh_region_may_contain_throw,
-                                     this_tf.region->index);
+  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);
 
@@ -1608,6 +1622,20 @@ lower_try_finally (struct leh_state *state, gimple tp)
   if (this_tf.goto_queue_map)
     pointer_map_destroy (this_tf.goto_queue_map);
 
+  /* If there was an old (aka outer) eh_seq, append the current eh_seq.
+     If there was no old eh_seq, then the append is trivially already done.  */
+  if (old_eh_seq)
+    {
+      if (eh_seq == NULL)
+       eh_seq = old_eh_seq;
+      else
+       {
+         gimple_seq new_eh_seq = eh_seq;
+         eh_seq = old_eh_seq;
+         gimple_seq_add_seq(&eh_seq, new_eh_seq);
+       }
+    }
+
   return this_tf.top_p_seq;
 }
 
@@ -1618,22 +1646,23 @@ lower_try_finally (struct leh_state *state, gimple tp)
 static gimple_seq
 lower_catch (struct leh_state *state, gimple tp)
 {
-  eh_region try_region;
-  struct leh_state this_state;
+  eh_region try_region = NULL;
+  struct leh_state this_state = *state;
   gimple_stmt_iterator gsi;
   tree out_label;
   gimple_seq new_seq;
   gimple x;
   location_t try_catch_loc = gimple_location (tp);
 
-  try_region = gen_eh_region_try (state->cur_region);
-
-  this_state = *state;
-  this_state.cur_region = try_region;
+  if (flag_exceptions)
+    {
+      try_region = gen_eh_region_try (state->cur_region);
+      this_state.cur_region = try_region;
+    }
 
   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
 
-  if (!bitmap_bit_p (eh_region_may_contain_throw, try_region->index))
+  if (!eh_region_may_contain_throw (try_region))
     return gimple_try_eval (tp);
 
   new_seq = NULL;
@@ -1672,6 +1701,8 @@ lower_catch (struct leh_state *state, gimple tp)
          x = gimple_build_goto (out_label);
          gimple_seq_add_stmt (&new_seq, x);
        }
+      if (!c->type_list)
+       break;
     }
 
   gimple_try_set_cleanup (tp, new_seq);
@@ -1686,21 +1717,23 @@ lower_catch (struct leh_state *state, gimple tp)
 static gimple_seq
 lower_eh_filter (struct leh_state *state, gimple tp)
 {
-  struct leh_state this_state;
-  eh_region this_region;
+  struct leh_state this_state = *state;
+  eh_region this_region = NULL;
   gimple inner, x;
   gimple_seq new_seq;
 
   inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
 
-  this_region = gen_eh_region_allowed (state->cur_region,
-                                      gimple_eh_filter_types (inner));
-  this_state = *state;
-  this_state.cur_region = this_region;
+  if (flag_exceptions)
+    {
+      this_region = gen_eh_region_allowed (state->cur_region,
+                                          gimple_eh_filter_types (inner));
+      this_state.cur_region = this_region;
+    }
 
   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
 
-  if (!bitmap_bit_p (eh_region_may_contain_throw, this_region->index))
+  if (!eh_region_may_contain_throw (this_region))
     return gimple_try_eval (tp);
 
   new_seq = NULL;
@@ -1729,24 +1762,25 @@ lower_eh_filter (struct leh_state *state, gimple tp)
 static gimple_seq
 lower_eh_must_not_throw (struct leh_state *state, gimple tp)
 {
-  struct leh_state this_state;
-  eh_region this_region;
-  gimple inner;
+  struct leh_state this_state = *state;
 
-  inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
+  if (flag_exceptions)
+    {
+      gimple inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
+      eh_region this_region;
 
-  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 = 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);
 
-  /* 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
-     needs to happen.  */
-  TREE_USED (this_region->u.must_not_throw.failure_decl) = 1;
+      /* 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
+        needs to happen.  */
+      TREE_USED (this_region->u.must_not_throw.failure_decl) = 1;
 
-  this_state = *state;
-  this_state.cur_region = this_region;
+      this_state.cur_region = this_region;
+    }
 
   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
 
@@ -1759,26 +1793,21 @@ lower_eh_must_not_throw (struct leh_state *state, gimple tp)
 static gimple_seq
 lower_cleanup (struct leh_state *state, gimple tp)
 {
-  struct leh_state this_state;
-  eh_region this_region;
+  struct leh_state this_state = *state;
+  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 not using eh, then exception-only cleanups are no-ops.  */
-  if (!flag_exceptions)
+  if (flag_exceptions && !cleanup_dead)
     {
-      result = gimple_try_eval (tp);
-      lower_eh_constructs_1 (state, result);
-      return result;
+      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 = *state;
-  this_state.cur_region = this_region;
-
   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
 
-  if (!bitmap_bit_p (eh_region_may_contain_throw, this_region->index))
+  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
@@ -1847,7 +1876,7 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
              else
                {
                  /* The user has dome something silly.  Remove it.  */
-                 rhs = build_int_cst (ptr_type_node, 0);
+                 rhs = null_pointer_node;
                  goto do_replace;
                }
              break;
@@ -1877,9 +1906,12 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
     case GIMPLE_ASSIGN:
       /* 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.  */
+        available on the EH edge.  Only do so for statements that
+        potentially fall thru (no noreturn calls e.g.), otherwise
+        this new assignment might create fake fallthru regions.  */
       if (stmt_could_throw_p (stmt)
          && gimple_has_lhs (stmt)
+         && gimple_stmt_may_fallthru (stmt)
          && !tree_could_throw_p (gimple_get_lhs (stmt))
          && is_gimple_reg_type (TREE_TYPE (gimple_get_lhs (stmt))))
        {
@@ -1979,7 +2011,7 @@ lower_eh_constructs (void)
     return 0;
 
   finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free);
-  eh_region_may_contain_throw = BITMAP_ALLOC (NULL);
+  eh_region_may_contain_throw_map = BITMAP_ALLOC (NULL);
   memset (&null_state, 0, sizeof (null_state));
 
   collect_finally_tree_1 (bodyp, NULL);
@@ -1996,7 +2028,7 @@ lower_eh_constructs (void)
   gcc_assert (bodyp == gimple_body (current_function_decl));
 
   htab_delete (finally_tree);
-  BITMAP_FREE (eh_region_may_contain_throw);
+  BITMAP_FREE (eh_region_may_contain_throw_map);
   eh_seq = NULL;
 
   /* If this function needs a language specific EH personality routine
@@ -2127,7 +2159,7 @@ redirect_eh_edge_1 (edge edge_in, basic_block new_bb, bool change_region)
     {
       new_lp = get_eh_landing_pad_from_number (new_lp_nr);
       gcc_assert (new_lp);
-      
+
       /* Unless CHANGE_REGION is true, the new and old landing pad
         had better be associated with the same EH region.  */
       gcc_assert (change_region || new_lp->region == old_lp->region);
@@ -2302,6 +2334,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)
@@ -2372,11 +2409,10 @@ tree_could_trap_p (tree expr)
   switch (code)
     {
     case TARGET_MEM_REF:
-      /* For TARGET_MEM_REFs use the information based on the original
-        reference.  */
-      expr = TMR_ORIGINAL (expr);
-      code = TREE_CODE (expr);
-      goto restart;
+      if (TREE_CODE (TMR_BASE (expr)) == ADDR_EXPR
+         && !TMR_INDEX (expr) && !TMR_INDEX2 (expr))
+       return false;
+      return !TREE_THIS_NOTRAP (expr);
 
     case COMPONENT_REF:
     case REALPART_EXPR:
@@ -2404,9 +2440,11 @@ tree_could_trap_p (tree expr)
        return false;
       return !in_array_bounds_p (expr);
 
+    case MEM_REF:
+      if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR)
+       return false;
+      /* Fallthru.  */
     case INDIRECT_REF:
-    case ALIGN_INDIRECT_REF:
-    case MISALIGNED_INDIRECT_REF:
       return !TREE_THIS_NOTRAP (expr);
 
     case ASM_EXPR:
@@ -2493,12 +2531,12 @@ stmt_could_throw_p (gimple stmt)
 
     case GIMPLE_ASSIGN:
     case GIMPLE_COND:
-      if (!flag_non_call_exceptions)
+      if (!cfun->can_throw_non_call_exceptions)
         return false;
       return stmt_could_throw_1_p (stmt);
 
     case GIMPLE_ASM:
-      if (!flag_non_call_exceptions)
+      if (!cfun->can_throw_non_call_exceptions)
         return false;
       return gimple_asm_volatile_p (stmt);
 
@@ -2517,7 +2555,7 @@ tree_could_throw_p (tree t)
     return false;
   if (TREE_CODE (t) == MODIFY_EXPR)
     {
-      if (flag_non_call_exceptions
+      if (cfun->can_throw_non_call_exceptions
           && tree_could_trap_p (TREE_OPERAND (t, 0)))
         return true;
       t = TREE_OPERAND (t, 1);
@@ -2527,7 +2565,7 @@ tree_could_throw_p (tree t)
     t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == CALL_EXPR)
     return (call_expr_flags (t) & ECF_NOTHROW) == 0;
-  if (flag_non_call_exceptions)
+  if (cfun->can_throw_non_call_exceptions)
     return tree_could_trap_p (t);
   return false;
 }
@@ -3042,9 +3080,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;
@@ -3052,6 +3091,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);
@@ -3067,6 +3107,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
@@ -3075,6 +3116,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;
@@ -3087,14 +3129,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.  */
@@ -3136,6 +3193,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
 
            VEC_free (tree, heap, labels);
          }
+       pointer_set_destroy (seen_values);
       }
       break;
 
@@ -3169,6 +3227,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
@@ -3176,6 +3235,7 @@ execute_lower_eh_dispatch (void)
 {
   basic_block bb;
   bool any_rewritten = false;
+  bool redirected = false;
 
   assign_filter_values ();
 
@@ -3184,11 +3244,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;
 }
 
@@ -3287,7 +3349,7 @@ remove_unreachable_handlers (void)
          fprintf (dump_file, "Removing unreachable landing pad %d\n", lp_nr);
        remove_eh_landing_pad (lp);
       }
-    
+
   if (dump_file)
     {
       fprintf (dump_file, "\n\nAfter removal of unreachable regions:\n");
@@ -3354,8 +3416,11 @@ unsplit_eh (eh_landing_pad lp)
   if ((e_in->flags & EDGE_EH) == 0 || (e_out->flags & EDGE_EH) != 0)
     return false;
 
-  /* The block must be empty except for the labels.  */
-  if (!gsi_end_p (gsi_after_labels (bb)))
+  /* The block must be empty except for the labels and debug insns.  */
+  gsi = gsi_after_labels (bb);
+  if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
+    gsi_next_nondebug (&gsi);
+  if (!gsi_end_p (gsi))
     return false;
 
   /* The destination block must not already have a landing pad
@@ -3597,7 +3662,7 @@ cleanup_empty_eh_move_lp (basic_block bb, edge e_out,
 }
 
 /* A subroutine of cleanup_empty_eh.  Handle more complex cases of
-   unsplitting than unsplit_eh was prepared to handle, e.g. when 
+   unsplitting than unsplit_eh was prepared to handle, e.g. when
    multiple incoming edges and phis are involved.  */
 
 static bool
@@ -3605,6 +3670,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
@@ -3627,6 +3694,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))
     {
@@ -3678,7 +3761,13 @@ 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 (e_out->dest == bb)
+       return false;
+
+      return cleanup_empty_eh_unsplit (bb, e_out, lp);
+    }
 
   /* The block should consist only of a single RESX statement.  */
   resx = gsi_stmt (gsi);
@@ -3797,7 +3886,7 @@ cleanup_all_empty_eh (void)
 */
 
 static unsigned int
-execute_cleanup_eh (void)
+execute_cleanup_eh_1 (void)
 {
   /* Do this first: unsplit_all_eh and cleanup_all_empty_eh can die
      looking up unreachable landing pads.  */
@@ -3831,6 +3920,21 @@ execute_cleanup_eh (void)
   return 0;
 }
 
+static unsigned int
+execute_cleanup_eh (void)
+{
+  int ret = execute_cleanup_eh_1 ();
+
+  /* If the function no longer needs an EH personality routine
+     clear it.  This exposes cross-language inlining opportunities
+     and avoids references to a never defined personality routine.  */
+  if (DECL_FUNCTION_PERSONALITY (current_function_decl)
+      && function_needs_eh_personality (cfun) != eh_personality_lang)
+    DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE;
+
+  return ret;
+}
+
 static bool
 gate_cleanup_eh (void)
 {
@@ -3858,7 +3962,7 @@ struct gimple_opt_pass pass_cleanup_eh = {
 /* Verify that BB containing STMT as the last statement, has precisely the
    edge that make_eh_edges would create.  */
 
-bool
+DEBUG_FUNCTION bool
 verify_eh_edges (gimple stmt)
 {
   basic_block bb = gimple_bb (stmt);
@@ -3919,7 +4023,7 @@ verify_eh_edges (gimple stmt)
 
 /* Similarly, but handle GIMPLE_EH_DISPATCH specifically.  */
 
-bool
+DEBUG_FUNCTION bool
 verify_eh_dispatch_edge (gimple stmt)
 {
   eh_region r;