diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 728e272975664ebbc20b6c6617647df0e60e800d..fa89805ba9fbd53b703a3f589e425e4851a43416 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2009-09-28  Richard Henderson  <rth@redhat.com>
+
+	* except.h (struct eh_region_d): Add use_cxa_end_cleanup.
+	* except.c (gen_eh_region): Set it.
+	(duplicate_eh_regions_1): Copy it.
+	* tree-eh.c (lower_resx): Use it to determine which function
+	to call to resume.
+
+	* langhooks.h (struct lang_hooks): Add eh_use_cxa_end_cleanup.
+	* langhooks-def.h (LANG_HOOKS_EH_USE_CXA_END_CLEANUP): New.
+	* builtins.def (BUILT_IN_CXA_END_CLEANUP): New.
+	* tree.c (build_common_builtin_nodes): Remove parameter.  Build
+	BUILT_IN_CXA_END_CLEANUP if necessary.
+
+	* c-common.c (c_define_builtins): Update call to
+	build_common_builtin_nodes.
+
 2009-09-28  Andrew Pinski  <andrew_pinski@playstation.sony.com>
 
 	* spu.c (get_branch_target): Return NULL for ASM_OPERANDS patterns.
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index b0112a15162f78ca7d950b8e40c3e8397e1283e2..8e4c061c04bc443bdf0e4664532727dc287cd340 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,8 @@
+2009-09-28  Richard Henderson  <rth@redhat.com>
+
+	* gcc-interface/utils.c (gnat_install_builtins): Update call to
+	build_common_builtin_nodes.
+
 2009-09-26  Eric Botcazou  <ebotcazou@adacore.com>
 
 	* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Array_Type>: Filter out
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index abc0b7b557ce085edc33c014b39686fa0bc0411c..7acb2ce2de4ec8343c887eb4890cbe06dc6f20f3 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -5662,7 +5662,7 @@ gnat_install_builtins (void)
      know about internal specificities and control attributes accordingly, for
      instance __builtin_alloca vs no-throw and -fstack-check.  We will ignore
      the generic definition from builtins.def.  */
-  build_common_builtin_nodes (false);
+  build_common_builtin_nodes ();
 
   /* Now, install the target specific builtins, such as the AltiVec family on
      ppc, and the common set as exposed by builtins.def.  */
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 00287c7548a1e3d758378c927924f165a86928f3..785eefb0b74f32a8b53b8ac27a9710cece4e2a8f 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -761,6 +761,7 @@ DEF_BUILTIN (BUILT_IN_EMUTLS_REGISTER_COMMON,
 
 /* Exception support.  */
 DEF_BUILTIN_STUB (BUILT_IN_UNWIND_RESUME, "__builtin_unwind_resume")
+DEF_BUILTIN_STUB (BUILT_IN_CXA_END_CLEANUP, "__builtin_cxa_end_cleanup")
 DEF_BUILTIN_STUB (BUILT_IN_EH_POINTER, "__builtin_eh_pointer")
 DEF_BUILTIN_STUB (BUILT_IN_EH_FILTER, "__builtin_eh_filter")
 DEF_BUILTIN_STUB (BUILT_IN_EH_COPY_VALUES, "__builtin_eh_copy_values")
diff --git a/gcc/c-common.c b/gcc/c-common.c
index a9e12864010d17754f913e8e327a11603ed577d1..baa3d35c27f59ba471e764f4d5bde9baf5277fd9 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -4574,7 +4574,7 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node)
 
   targetm.init_builtins ();
 
-  build_common_builtin_nodes (c_dialect_cxx ());
+  build_common_builtin_nodes ();
 
   if (flag_mudflap)
     mudflap_init ();
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5949b24ec8afee00b8528d33dbb5c7b25197fa1f..de0a97fd48240cf5f8bc6d23d62f5c75566d5cc9 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,7 @@
+2009-09-28  Richard Henderson  <rth@redhat.com>
+
+	* cp-objcp-common.h (LANG_HOOKS_EH_USE_CXA_END_CLEANUP): New.
+
 2009-09-24  Jakub Jelinek  <jakub@redhat.com>
 
 	* method.c (make_thunk, make_alias_for): Don't set
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 818540c219471fe94369ce11e11f58855176ef5e..8f0cdc324e4af51c9b0ff8ee46fa2f42f724cbde 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -142,4 +142,7 @@ extern bool cp_function_decl_explicit_p (tree decl);
 #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE
 #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference
 
+#undef LANG_HOOKS_EH_USE_CXA_END_CLEANUP
+#define LANG_HOOKS_EH_USE_CXA_END_CLEANUP true
+
 #endif /* GCC_CP_OBJCP_COMMON */
diff --git a/gcc/except.c b/gcc/except.c
index c916a18089b9c56f68eeb5b246aa975de906f1dd..bb26bf4dc6f6f7db781825a77046f6a09bc27e5e 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -369,6 +369,10 @@ gen_eh_region (enum eh_region_type type, eh_region outer)
   new_eh->index = VEC_length (eh_region, cfun->eh->region_array);
   VEC_safe_push (eh_region, gc, cfun->eh->region_array, new_eh);
 
+  /* Copy the language's notion of whether to use __cxa_end_cleanup.  */
+  if (targetm.arm_eabi_unwinder && lang_hooks.eh_use_cxa_end_cleanup)
+    new_eh->use_cxa_end_cleanup = true;
+
   return new_eh;
 }
 
@@ -573,6 +577,9 @@ duplicate_eh_regions_1 (struct duplicate_eh_regions_data *data,
       EH_LANDING_PAD_NR (new_lp->post_landing_pad) = new_lp->index;
     }
 
+  /* Make sure to preserve the original use of __cxa_end_cleanup.  */
+  new_r->use_cxa_end_cleanup = old_r->use_cxa_end_cleanup;
+
   for (old_r = old_r->inner; old_r ; old_r = old_r->next_peer)
     duplicate_eh_regions_1 (data, old_r, new_r);
 }
diff --git a/gcc/except.h b/gcc/except.h
index 3e9a39cbb5f1fd8b960ba2225c2316c4b7de6e98..f1dbf90c2a991fe7e623d7883d9e101f8734aea4 100644
--- a/gcc/except.h
+++ b/gcc/except.h
@@ -171,6 +171,10 @@ struct GTY(()) eh_region_d
      Each region gets its own psuedos so that if there are nested exceptions
      we do not overwrite the values of the first exception.  */
   rtx exc_ptr_reg, filter_reg;
+
+  /* True if this region should use __cxa_end_cleanup instead
+     of _Unwind_Resume.  */
+  bool use_cxa_end_cleanup;
 };
 
 typedef struct eh_landing_pad_d *eh_landing_pad;
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index e7826e000081a80e7d173cd9042c373b7e7c6464..ab55bd8931d38975a4f78ef935376e097281a86c 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,8 @@
+2009-09-28  Richard Henderson  <rth@redhat.com>
+
+	* f95-lang.c (gfc_init_builtin_functions): Update call to
+	build_common_builtin_nodes.
+
 2009-09-25  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
 	* simplify.c (gfc_simplify_acos, gfc_simplify_acosh,
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index a21044c64ae48a0de059ef79a5a6dd846a3c5bd3..5d2846c8890ac84aff89fa2ad9347250c70ec203 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -1131,7 +1131,7 @@ gfc_init_builtin_functions (void)
 		      BUILT_IN_EMUTLS_REGISTER_COMMON,
 		      "__emutls_register_common", false);
 
-  build_common_builtin_nodes (false);
+  build_common_builtin_nodes ();
   targetm.init_builtins ();
 }
 
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index 6c58a99b4c171869a6d7cd3cc23c95c6397d9117..5a9f1d6e010c94592f0849d2bf24fe5a87597d6c 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,3 +1,9 @@
+2009-09-28  Richard Henderson  <rth@redhat.com>
+
+	* builtins.c (initialize_builtins): Update call to
+	build_common_builtin_nodes.
+	* lang.c (LANG_HOOKS_EH_USE_CXA_END_CLEANUP): New.
+
 2009-09-14  Richard Henderson  <rth@redhat.com>
 
 	* builtins.c (initialize_builtins): Update call to
diff --git a/gcc/java/builtins.c b/gcc/java/builtins.c
index a05ff53ceb99c93e8922d37809584817e76541f7..6e4815beeab2755e9e7a4b2b5bb95741c0e9bebe 100644
--- a/gcc/java/builtins.c
+++ b/gcc/java/builtins.c
@@ -584,7 +584,7 @@ initialize_builtins (void)
 		  build_function_type_list (ptr_type_node, int_type_node, NULL_TREE),
 		  "__builtin_return_address", BUILTIN_NOTHROW);
 
-  build_common_builtin_nodes (true);
+  build_common_builtin_nodes ();
 }
 
 /* If the call matches a builtin, return the
diff --git a/gcc/java/lang.c b/gcc/java/lang.c
index 504d0295bf044afde9f1326eb1b900bdbf5ac76a..f1d8f44ce86d30bece4262647f6c2049ebfc6e22 100644
--- a/gcc/java/lang.c
+++ b/gcc/java/lang.c
@@ -164,6 +164,9 @@ struct GTY(()) language_function {
 #undef LANG_HOOKS_EH_PERSONALITY
 #define LANG_HOOKS_EH_PERSONALITY java_eh_personality
 
+#undef LANG_HOOKS_EH_USE_CXA_END_CLEANUP
+#define LANG_HOOKS_EH_USE_CXA_END_CLEANUP  true
+
 /* Each front end provides its own.  */
 struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
 
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index fa078adaa9a862ae294db7e87682f0ecd83ac62a..40a4de93d6d34ec2c2bc903b528080657387f01f 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -110,6 +110,7 @@ extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *,
 #define LANG_HOOKS_INIT_TS		lhd_do_nothing
 #define LANG_HOOKS_EH_PERSONALITY	lhd_gcc_personality
 #define LANG_HOOKS_EH_RUNTIME_TYPE	lhd_pass_through_t
+#define LANG_HOOKS_EH_USE_CXA_END_CLEANUP	false
 
 /* Attribute hooks.  */
 #define LANG_HOOKS_ATTRIBUTE_TABLE		NULL
@@ -283,6 +284,7 @@ extern tree lhd_make_node (enum tree_code);
   LANG_HOOKS_EXPR_TO_DECL, \
   LANG_HOOKS_EH_PERSONALITY, \
   LANG_HOOKS_EH_RUNTIME_TYPE, \
+  LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
 }
 
 #endif /* GCC_LANG_HOOKS_DEF_H */
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index ab640403df7185754e32b60214a9c4e2ad483a82..b133ea0576311330b4a9150ff69850b5fcadbb15 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -430,6 +430,10 @@ struct lang_hooks
   /* Map a type to a runtime object to match type.  */
   tree (*eh_runtime_type) (tree);
 
+  /* True if this language uses __cxa_end_cleanup when the ARM EABI
+     is enabled.  */
+  bool eh_use_cxa_end_cleanup;
+
   /* Whenever you add entries here, make sure you adjust langhooks-def.h
      and langhooks.c accordingly.  */
 };
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 70c009d6bb2b7ecf58cdd7cbc88a2ad6126b75ad..0f5931e0b75ee8aec7152698b0bb760500f1624b 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -2949,21 +2949,16 @@ lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map)
 	 up the call chain.  We resolve this by generating a call to the
 	 _Unwind_Resume library function.  */
 
-      /* ??? The ARM EABI redefines _Unwind_Resume as __cxa_end_cleanup
+      /* The ARM EABI redefines _Unwind_Resume as __cxa_end_cleanup
 	 with no arguments for C++ and Java.  Check for that.  */
-      switch (targetm.arm_eabi_unwinder)
+      if (src_r->use_cxa_end_cleanup)
+	{
+	  fn = implicit_built_in_decls[BUILT_IN_CXA_END_CLEANUP];
+	  x = gimple_build_call (fn, 0);
+	  gsi_insert_before (&gsi, x, GSI_SAME_STMT);
+	}
+      else
 	{
-	default:
-	  fn = implicit_built_in_decls[BUILT_IN_UNWIND_RESUME];
-	  if (TYPE_ARG_TYPES (TREE_TYPE (fn)) == void_list_node)
-	    {
-	      x = gimple_build_call (fn, 0);
-	      gsi_insert_before (&gsi, x, GSI_SAME_STMT);
-	      break;
-	    }
-	  /* FALLTHRU */
-
-	case 0:
 	  fn = implicit_built_in_decls[BUILT_IN_EH_POINTER];
 	  src_nr = build_int_cst (NULL, src_r->index);
 	  x = gimple_build_call (fn, 1, src_nr);
@@ -2975,7 +2970,6 @@ lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map)
 	  fn = implicit_built_in_decls[BUILT_IN_UNWIND_RESUME];
 	  x = gimple_build_call (fn, 1, var);
 	  gsi_insert_before (&gsi, x, GSI_SAME_STMT);
-	  break;
 	}
 
       gcc_assert (EDGE_COUNT (bb->succs) == 0);
diff --git a/gcc/tree.c b/gcc/tree.c
index 846dd983ea774ccdfeb414e5b31dd3b87c74a091..315df903b30f56d9178ecc48cfb1e73c0f4850a5 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -8890,13 +8890,10 @@ local_define_builtin (const char *name, tree type, enum built_in_function code,
 
 /* Call this function after instantiating all builtins that the language
    front end cares about.  This will build the rest of the builtins that
-   are relied upon by the tree optimizers and the middle-end.
-
-   ENABLE_CXA_END_CLEANUP should be true for C++ and Java, where the ARM
-   EABI requires a slightly different implementation of _Unwind_Resume.  */
+   are relied upon by the tree optimizers and the middle-end.  */
 
 void
-build_common_builtin_nodes (bool enable_cxa_end_cleanup)
+build_common_builtin_nodes (void)
 {
   tree tmp, tmp2, ftype;
 
@@ -9003,23 +9000,23 @@ build_common_builtin_nodes (bool enable_cxa_end_cleanup)
   local_define_builtin ("__builtin_profile_func_exit", ftype,
 			BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit", 0);
 
-  if (enable_cxa_end_cleanup && targetm.arm_eabi_unwinder)
+  /* If there's a possibility that we might use the ARM EABI, build the
+    alternate __cxa_end_cleanup node used to resume from C++ and Java.  */
+  if (targetm.arm_eabi_unwinder)
     {
       ftype = build_function_type (void_type_node, void_list_node);
-      local_define_builtin ("__builtin_unwind_resume", ftype,
-			    BUILT_IN_UNWIND_RESUME,
+      local_define_builtin ("__builtin_cxa_end_cleanup", ftype,
+			    BUILT_IN_CXA_END_CLEANUP,
 			    "__cxa_end_cleanup", ECF_NORETURN);
     }
-  else
-    {
-      tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
-      ftype = build_function_type (void_type_node, tmp);
-      local_define_builtin ("__builtin_unwind_resume", ftype,
-			    BUILT_IN_UNWIND_RESUME,
-			    (USING_SJLJ_EXCEPTIONS
-			     ? "_Unwind_SjLj_Resume" : "_Unwind_Resume"),
-			    ECF_NORETURN);
-    }
+
+  tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+  ftype = build_function_type (void_type_node, tmp);
+  local_define_builtin ("__builtin_unwind_resume", ftype,
+			BUILT_IN_UNWIND_RESUME,
+			(USING_SJLJ_EXCEPTIONS
+			 ? "_Unwind_SjLj_Resume" : "_Unwind_Resume"),
+			ECF_NORETURN);
 
   /* The exception object and filter values from the runtime.  The argument
      must be zero before exception lowering, i.e. from the front end.  After
diff --git a/gcc/tree.h b/gcc/tree.h
index 4f4fd309b6eb563efa9717ca14cc1d916e3d240b..a5a22f456433e50c586551ddba6da9471daae105 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4949,7 +4949,7 @@ extern int real_minus_onep (const_tree);
 extern void init_ttree (void);
 extern void build_common_tree_nodes (bool, bool);
 extern void build_common_tree_nodes_2 (int);
-extern void build_common_builtin_nodes (bool);
+extern void build_common_builtin_nodes (void);
 extern tree build_nonstandard_integer_type (unsigned HOST_WIDE_INT, int);
 extern tree build_range_type (tree, tree, tree);
 extern bool subrange_type_for_debug_p (const_tree, tree *, tree *);