diff --git a/gcc/combine.cc b/gcc/combine.cc
index 53dcac92abc..ba234e3af5f 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -2951,6 +2951,45 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
       return 0;
     }
 
+  /* When i3 transfers to an EH handler we cannot combine if any of the
+     sources are within a must-not-throw region.  Else we can throw away
+     any nothrow, pick a random must-not-throw region or preserve the EH
+     transfer on i3.  Since we want to preserve nothrow notes on calls
+     we have to avoid combining from must-not-throw stmts there as well.
+     This has to be kept in sync with distribute_note.  */
+  if (rtx i3_eh = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
+    {
+      int i3_lp_nr = INTVAL (XEXP (i3_eh, 0));
+      if (i3_lp_nr > 0
+	  || ((i3_lp_nr == 0 || i3_lp_nr == INT_MIN) && CALL_P (i3)))
+	{
+	  rtx eh;
+	  int eh_lp;
+	  if (((eh = find_reg_note (i2, REG_EH_REGION, NULL_RTX))
+	       && (eh_lp = INTVAL (XEXP (eh, 0))) < 0
+	       && eh_lp != INT_MIN)
+	      || (i2
+		  && (eh = find_reg_note (i2, REG_EH_REGION, NULL_RTX))
+		  && (eh_lp = INTVAL (XEXP (eh, 0))) < 0
+		  && eh_lp != INT_MIN)
+	      || (i1
+		  && (eh = find_reg_note (i1, REG_EH_REGION, NULL_RTX))
+		  && (eh_lp = INTVAL (XEXP (eh, 0))) < 0
+		  && eh_lp != INT_MIN)
+	      || (i0
+		  && (eh = find_reg_note (i0, REG_EH_REGION, NULL_RTX))
+		  && (eh_lp = INTVAL (XEXP (eh, 0))) < 0
+		  && eh_lp != INT_MIN))
+	    {
+	      if (dump_file && (dump_flags & TDF_DETAILS))
+		fprintf (dump_file, "Can't combine insn in must-not-throw "
+			 "EH region into i3 which can throws\n");
+	      undo_all ();
+	      return 0;
+	    }
+	}
+    }
+
   /* Record whether i2 and i3 are trivial moves.  */
   i2_was_move = is_just_move (i2);
   i3_was_move = is_just_move (i3);
@@ -14175,23 +14214,56 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
 	  break;
 
 	case REG_EH_REGION:
-	  /* These notes must remain with the call or trapping instruction.  */
-	  if (CALL_P (i3))
-	    place = i3;
-	  else if (i2 && CALL_P (i2))
-	    place = i2;
-	  else
-	    {
-	      gcc_assert (cfun->can_throw_non_call_exceptions);
-	      if (may_trap_p (i3))
-		place = i3;
-	      else if (i2 && may_trap_p (i2))
-		place = i2;
-	      /* ??? Otherwise assume we've combined things such that we
-		 can now prove that the instructions can't trap.  Drop the
-		 note in this case.  */
-	    }
-	  break;
+	  {
+	    /* This handling needs to be kept in sync with the
+	       prerequesite checking in try_combine.  */
+	    int lp_nr = INTVAL (XEXP (note, 0));
+	    /* A REG_EH_REGION note transfering control can only ever come
+	       from i3 and it has to stay there.  */
+	    if (lp_nr > 0)
+	      {
+		gcc_assert (from_insn == i3);
+		if (CALL_P (i3))
+		  place = i3;
+		else
+		  {
+		    gcc_assert (cfun->can_throw_non_call_exceptions);
+		    /* If i3 can still trap preserve the note, otherwise we've
+		       combined things such that we can now prove that the
+		       instructions can't trap.  Drop the note in this case.  */
+		    if (may_trap_p (i3))
+		      place = i3;
+		  }
+	      }
+	    else if (lp_nr == 0 || lp_nr == INT_MIN)
+	      {
+		/* nothrow notes can be dropped but we preserve
+		   those on calls.  */
+		if (from_insn == i3 && CALL_P (i3))
+		  place = i3;
+	      }
+	    else
+	      {
+		/* Distribute must-not-throw notes to all resulting
+		   insns and just pick the first.  */
+		if (!find_reg_note (i3, REG_EH_REGION, NULL_RTX)
+		    && (CALL_P (i3)
+			|| (cfun->can_throw_non_call_exceptions
+			    && may_trap_p (i3))))
+		  place = i3;
+		if (i2
+		    && !find_reg_note (i2, REG_EH_REGION, NULL_RTX)
+		    && cfun->can_throw_non_call_exceptions
+		    && may_trap_p (i2))
+		  {
+		    if (place)
+		      place2 = i2;
+		    else
+		      place = i2;
+		  }
+	      }
+	    break;
+	  }
 
 	case REG_ARGS_SIZE:
 	  /* ??? How to distribute between i3-i1.  Assume i3 contains the
diff --git a/gcc/testsuite/gcc.dg/torture/pr105231.c b/gcc/testsuite/gcc.dg/torture/pr105231.c
new file mode 100644
index 00000000000..50459219c08
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr105231.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target int32plus } */
+/* { dg-require-effective-target dfp } */
+/* { dg-additional-options "-fsanitize-coverage=trace-pc -fnon-call-exceptions --param=max-cse-insns=1 -frounding-math" } */
+/* { dg-additional-options "-mstack-arg-probe" { target x86_64-*-* i?86-*-* } } */
+
+void baz (int *);
+void bar (double, double, _Decimal64);
+
+void
+foo (void)
+{
+  int s __attribute__((cleanup (baz)));
+  bar (0xfffffffffffffffe, 0xebf3fff2fbebaf7f, 0xffffffffffffff);
+}
