diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 56e6d661537..e204182da97 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -465,6 +465,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       OVL_USING_P (in OVERLOAD)
       IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR)
       BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK)
+      BIND_EXPR_VEC_DTOR (in BIND_EXPR)
    2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE)
       ICS_THIS_FLAG (in _CONV)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -712,6 +713,10 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
 #define BIND_EXPR_TRY_BLOCK(NODE) \
   TREE_LANG_FLAG_0 (BIND_EXPR_CHECK (NODE))
 
+/* This BIND_EXPR is from build_vec_delete_1.  */
+#define BIND_EXPR_VEC_DTOR(NODE) \
+  TREE_LANG_FLAG_1 (BIND_EXPR_CHECK (NODE))
+
 /* Used to mark the block around the member initializers and cleanups.  */
 #define BIND_EXPR_BODY_BLOCK(NODE) \
   TREE_LANG_FLAG_3 (BIND_EXPR_CHECK (NODE))
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b16a4f9ed34..5fe341e0b75 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -7451,11 +7451,24 @@ wrap_cleanups_r (tree *stmt_p, int *walk_subtrees, void *data)
    they are run on the normal path, but not if they are run on the
    exceptional path.  We implement this by telling
    honor_protect_cleanup_actions to strip the variable cleanup from the
-   exceptional path.  */
+   exceptional path.
+
+   Another approach could be to make the variable cleanup region enclose
+   initialization, but depend on a flag to indicate that the variable is
+   initialized; that's effectively what we do for arrays.  But the current
+   approach works fine for non-arrays, and has no code overhead in the usual
+   case where the temporary destructors are noexcept.  */
 
 static void
 wrap_temporary_cleanups (tree init, tree guard)
 {
+  if (TREE_CODE (guard) == BIND_EXPR)
+    {
+      /* An array cleanup region already encloses any temporary cleanups,
+	 don't wrap it around them again.  */
+      gcc_checking_assert (BIND_EXPR_VEC_DTOR (guard));
+      return;
+    }
   cp_walk_tree_without_duplicates (&init, wrap_cleanups_r, (void *)guard);
 }
 
@@ -7518,8 +7531,8 @@ initialize_local_var (tree decl, tree init)
 
 	  /* If we're only initializing a single object, guard the
 	     destructors of any temporaries used in its initializer with
-	     its destructor.  But arrays are handled in build_vec_init.  */
-	  if (cleanup && TREE_CODE (type) != ARRAY_TYPE)
+	     its destructor.  */
+	  if (cleanup)
 	    wrap_temporary_cleanups (init, cleanup);
 
 	  gcc_assert (building_stmt_list_p ());
@@ -8367,7 +8380,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
   if (cleanups)
     {
       for (tree t : *cleanups)
-	push_cleanup (decl, t, false);
+	{
+	  push_cleanup (decl, t, false);
+	  /* As in initialize_local_var.  */
+	  wrap_temporary_cleanups (init, t);
+	}
       release_tree_vector (cleanups);
     }
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index df63e618394..bfe4ad464bf 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -4092,6 +4092,7 @@ build_vec_delete_1 (location_t loc, tree base, tree maxindex, tree type,
   tbase_init = build_stmt (loc, DECL_EXPR, tbase);
   controller = build3 (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (controller) = 1;
+  BIND_EXPR_VEC_DTOR (controller) = true;
 
   body = build1 (EXIT_EXPR, void_type_node,
 		 build2 (EQ_EXPR, boolean_type_node, tbase,
diff --git a/gcc/testsuite/g++.dg/eh/ref-temp1.C b/gcc/testsuite/g++.dg/eh/ref-temp1.C
new file mode 100644
index 00000000000..2df1a4937b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/ref-temp1.C
@@ -0,0 +1,51 @@
+// PR c++/53868
+// { dg-do run { target c++11 } }
+
+#if __cplusplus > 201100L
+#define THROWING noexcept(false)
+#else
+#define THROWING
+#endif
+
+extern "C" int printf(const char *, ...);
+extern "C" void abort();
+
+struct SubobjectInA {
+   SubobjectInA();
+   ~SubobjectInA();
+};
+
+int a;
+struct A : SubobjectInA {
+   A() = delete;
+   A(const A &) = delete;
+  A(A &&) = delete;
+   A(int);
+   ~A();
+};
+
+#ifdef DEBUG
+#define TRACE_FUNC( ... ) \
+{   printf("%s\n", __PRETTY_FUNCTION__); __VA_ARGS__   }
+#else
+#define TRACE_FUNC( ... ) \
+{   __VA_ARGS__   }
+#endif
+
+struct Q {
+   Q() : q(0)  TRACE_FUNC()
+   ~Q() THROWING;
+   int q;
+};
+
+int main() {
+   try { const A &a = Q().q; }
+   catch (...) { if (!a) return 0; }
+   abort();
+}
+
+SubobjectInA::SubobjectInA()  TRACE_FUNC()
+SubobjectInA::~SubobjectInA()  TRACE_FUNC()
+A::A(int)  TRACE_FUNC(++a;)
+A::~A()  TRACE_FUNC(--a;)
+Q::~Q() THROWING TRACE_FUNC( throw 0; )
diff --git a/gcc/testsuite/g++.dg/eh/ref-temp2.C b/gcc/testsuite/g++.dg/eh/ref-temp2.C
new file mode 100644
index 00000000000..0c718962d49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/ref-temp2.C
@@ -0,0 +1,15 @@
+// { dg-do run { target c++11 } }
+
+struct B { B() {} ~B() noexcept(false) { throw 42; } };
+int a;
+struct A { A() { ++a; }; A(B) { ++a; } ~A() { --a; } };
+
+using Arr = A[3];
+
+int main()
+{
+  try {
+    auto&& ref = Arr{B()};
+  } catch (...) { }
+  return a;
+}
