Index: tree-eh.c
===================================================================
--- tree-eh.c	(revision 183716)
+++ tree-eh.c	(working copy)
@@ -1990,6 +1990,44 @@ lower_eh_constructs_2 (struct leh_state
 	}
       break;
 
+    case GIMPLE_ASM:
+      /* Similar to normal LHS handling above, replace outputs
+         with new temporaries.  */
+      if (stmt_could_throw_p (stmt)
+	  && gimple_code (stmt) == GIMPLE_ASM)
+	{
+	  unsigned noutputs;
+	  unsigned i;
+
+	  noutputs = gimple_asm_noutputs (stmt);
+	  for (i = 0; i < noutputs; i++)
+	    {
+	      tree link, op;
+	      link = gimple_asm_output_op (stmt, i);
+	      op = TREE_VALUE (link);
+	      if (!tree_could_throw_p (op)
+		  && is_gimple_reg_type (TREE_TYPE (op)))
+		{
+		  tree tmp = create_tmp_var (TREE_TYPE (op), NULL);
+		  gimple s = gimple_build_assign (op, tmp);
+		  gimple_set_location (s, gimple_location (stmt));
+		  gimple_set_block (s, gimple_block (stmt));
+		  TREE_VALUE (link) = tmp;
+		  if (TREE_CODE (TREE_TYPE (tmp)) == COMPLEX_TYPE
+		      || TREE_CODE (TREE_TYPE (tmp)) == VECTOR_TYPE)
+		    DECL_GIMPLE_REG_P (tmp) = 1;
+		  gsi_insert_after (gsi, s, GSI_SAME_STMT);
+		}
+	    }
+	}
+      /* Look for things that can throw exceptions, and record them.  */
+      if (state->cur_region && stmt_could_throw_p (stmt))
+	{
+	  record_stmt_eh_region (state->cur_region, stmt);
+	  note_eh_region_may_contain_throw (state->cur_region);
+	}
+      break;
+
     case GIMPLE_COND:
     case GIMPLE_GOTO:
     case GIMPLE_RETURN:
@@ -2639,6 +2677,8 @@ stmt_could_throw_p (gimple stmt)
       return stmt_could_throw_1_p (stmt);
 
     case GIMPLE_ASM:
+      if (gimple_asm_can_throw_p (stmt))
+	return true;
       if (!cfun->can_throw_non_call_exceptions)
         return false;
       return gimple_asm_volatile_p (stmt);
Index: varasm.c
===================================================================
--- varasm.c	(revision 183716)
+++ varasm.c	(working copy)
@@ -834,9 +834,10 @@ set_user_assembler_name (tree decl, cons
 
 /* Decode an `asm' spec for a declaration as a register name.
    Return the register number, or -1 if nothing specified,
-   or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
+   or -2 if the ASMSPEC is not `cc', `memory' or `throw' and is not recognized,
    or -3 if ASMSPEC is `cc' and is not recognized,
-   or -4 if ASMSPEC is `memory' and is not recognized.
+   or -4 if ASMSPEC is `memory' and is not recognized,
+   or -5 if ASMSPEC is `throw' and is not recognized.
    Accept an exact spelling or a decimal number.
    Prefixes such as % are optional.  */
 
@@ -902,6 +903,9 @@ decode_reg_name_and_count (const char *a
       }
 #endif /* ADDITIONAL_REGISTER_NAMES */
 
+      if (!strcmp (asmspec, "throw"))
+	return -5;
+
       if (!strcmp (asmspec, "memory"))
 	return -4;
 
Index: rtl.h
===================================================================
--- rtl.h	(revision 183716)
+++ rtl.h	(working copy)
@@ -266,7 +266,8 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"
      1 in a CALL_INSN if it is a sibling call.
      1 in a SET that is for a return.
      In a CODE_LABEL, part of the two-bit alternate entry field.
-     1 in a CONCAT is VAL_EXPR_IS_COPIED in var-tracking.c.  */
+     1 in a CONCAT is VAL_EXPR_IS_COPIED in var-tracking.c.
+     1 in an ASM_OPERANDS is ASM_OPERANDS_THROW_P.  */
   unsigned int jump : 1;
   /* In a CODE_LABEL, part of the two-bit alternate entry field.
      1 in a MEM if it cannot trap.
@@ -1317,6 +1318,8 @@ do {									\
 #define ASM_OPERANDS_LABEL_LENGTH(RTX) XCVECLEN (RTX, 5, ASM_OPERANDS)
 #define ASM_OPERANDS_LABEL(RTX, N) XCVECEXP (RTX, 5, N, ASM_OPERANDS)
 #define ASM_OPERANDS_SOURCE_LOCATION(RTX) XCUINT (RTX, 6, ASM_OPERANDS)
+#define ASM_OPERANDS_THROW_P(RTX) \
+  (RTL_FLAG_CHECK1("ASM_OPERANDS_THROW_P", (RTX), ASM_OPERANDS)->jump)
 #define ASM_INPUT_SOURCE_LOCATION(RTX) XCUINT (RTX, 1, ASM_INPUT)
 
 /* 1 if RTX is a mem that is statically allocated in read-only memory.  */
Index: gimple.c
===================================================================
--- gimple.c	(revision 183716)
+++ gimple.c	(working copy)
@@ -5513,4 +5513,21 @@ gimple_asm_clobbers_memory_p (const_gimp
 
   return false;
 }
+
+/* Return true if the GIMPLE_ASM STMT can throw.  */
+
+bool
+gimple_asm_can_throw_p (const_gimple stmt)
+{
+  unsigned i;
+
+  for (i = 0; i < gimple_asm_nclobbers (stmt); i++)
+    {
+      tree op = gimple_asm_clobber_op (stmt, i);
+      if (strcmp (TREE_STRING_POINTER (TREE_VALUE (op)), "throw") == 0)
+	return true;
+    }
+
+  return false;
+}
 #include "gt-gimple.h"
Index: gimple.h
===================================================================
--- gimple.h	(revision 183716)
+++ gimple.h	(working copy)
@@ -1030,6 +1030,7 @@ extern bool walk_stmt_load_store_ops (gi
 extern bool gimple_ior_addresses_taken (bitmap, gimple);
 extern bool gimple_call_builtin_p (gimple, enum built_in_function);
 extern bool gimple_asm_clobbers_memory_p (const_gimple);
+extern bool gimple_asm_can_throw_p (const_gimple);
 
 /* In gimplify.c  */
 extern tree create_tmp_var_raw (tree, const char *);
Index: tree-cfg.c
===================================================================
--- tree-cfg.c	(revision 183716)
+++ tree-cfg.c	(working copy)
@@ -580,6 +580,8 @@ make_edges (void)
 
 	    case GIMPLE_ASM:
 	      make_gimple_asm_edges (bb);
+	      if (is_ctrl_altering_stmt (last))
+		make_eh_edges (last);
 	      fallthru = true;
 	      break;
 
Index: stmt.c
===================================================================
--- stmt.c	(revision 183716)
+++ stmt.c	(working copy)
@@ -657,6 +657,7 @@ expand_asm_operands (tree string, tree o
   enum machine_mode *inout_mode = XALLOCAVEC (enum machine_mode, noutputs);
   const char **constraints = XALLOCAVEC (const char *, noutputs + ninputs);
   int old_generating_concat_p = generating_concat_p;
+  bool throw_p = false;
 
   /* An ASM with no outputs needs to be treated as volatile, for now.  */
   if (noutputs == 0)
@@ -696,6 +697,11 @@ expand_asm_operands (tree string, tree o
       i = decode_reg_name_and_count (regname, &nregs);
       if (i == -4)
 	++nclobbers;
+      else if (i == -5)
+	{
+	  throw_p = true;
+	  vol = 1;
+	}
       else if (i == -2)
 	error ("unknown register name %qs in %<asm%>", regname);
 
@@ -872,6 +878,7 @@ expand_asm_operands (tree string, tree o
 			       labelvec, locus);
 
   MEM_VOLATILE_P (body) = vol;
+  ASM_OPERANDS_THROW_P (body) = throw_p;
 
   /* Eval the inputs and put them into ARGVEC.
      Put their constraints into ASM_INPUTs and store in CONSTRAINTS.  */
@@ -1028,6 +1035,7 @@ expand_asm_operands (tree string, tree o
 			    i, argvec, constraintvec, labelvec, locus));
 
 	  MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
+	  ASM_OPERANDS_THROW_P (SET_SRC (XVECEXP (body, 0, i))) = throw_p;
 	}
 
       /* If there are no outputs (but there are some clobbers)
Index: except.c
===================================================================
--- except.c	(revision 183716)
+++ except.c	(working copy)
@@ -1622,12 +1622,16 @@ make_reg_eh_region_note_nothrow_nononloc
 bool
 insn_could_throw_p (const_rtx insn)
 {
+  rtx tmp;
   if (!flag_exceptions)
     return false;
   if (CALL_P (insn))
     return true;
   if (INSN_P (insn) && cfun->can_throw_non_call_exceptions)
     return may_trap_p (PATTERN (insn));
+  if (INSN_P (insn)
+      && (tmp = extract_asm_operands (PATTERN (insn))) != NULL)
+    return ASM_OPERANDS_THROW_P (tmp);
   return false;
 }
 
Index: cfgbuild.c
===================================================================
--- cfgbuild.c	(revision 183716)
+++ cfgbuild.c	(working copy)
@@ -82,6 +82,7 @@ inside_basic_block_p (const_rtx insn)
 bool
 control_flow_insn_p (const_rtx insn)
 {
+  rtx tmp;
   switch (GET_CODE (insn))
     {
     case NOTE:
@@ -112,6 +113,8 @@ control_flow_insn_p (const_rtx insn)
       if (GET_CODE (PATTERN (insn)) == TRAP_IF
 	  && XEXP (PATTERN (insn), 0) == const1_rtx)
 	return true;
+      if ((tmp = extract_asm_operands (PATTERN (insn))) != NULL)
+	return can_throw_internal (insn);
       if (!cfun->can_throw_non_call_exceptions)
 	return false;
       break;
@@ -364,6 +367,8 @@ make_edges (basic_block min, basic_block
 		}
 	    }
 	}
+      else if (code == INSN && extract_asm_operands (PATTERN (insn)))
+	rtl_make_eh_edge (edge_cache, bb, insn);
 
       /* Find out if we can drop through to the next block.  */
       insn = NEXT_INSN (insn);
Index: testsuite/g++.dg/eh/pr52770.C
===================================================================
--- testsuite/g++.dg/eh/pr52770.C	(revision 0)
+++ testsuite/g++.dg/eh/pr52770.C	(revision 0)
@@ -0,0 +1,16 @@
+// PR c++/52770
+// { dg-do compile }
+// { dg-final { scan-assembler "EHB" } }
+// { dg-options "-O2" }
+int f (void)
+{
+  int x, y;
+  x = 1;
+  y = 2;
+  try {
+    __asm__ ("" : "=r"(x), "=r"(y) : : "throw");
+  } catch (...) {
+    return 2+x+y;
+  }
+  return x+y;
+}
