diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b9eb71fbc3a..d71be0a5bc7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4201,6 +4201,18 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define VEC_INIT_EXPR_VALUE_INIT(NODE) \
   TREE_LANG_FLAG_1 (VEC_INIT_EXPR_CHECK (NODE))
 
+/* If T is a VEC_INIT_EXPR, return it, possibly stripping a TARGET_EXPR
+   wrapper.  Otherwise, return null.  */
+inline tree
+get_vec_init_expr (tree t)
+{
+  if (t && TREE_CODE (t) == TARGET_EXPR)
+    t = TARGET_EXPR_INITIAL (t);
+  if (t && TREE_CODE (t) == VEC_INIT_EXPR)
+    return t;
+  return NULL_TREE;
+}
+
 /* The condition under which this MUST_NOT_THROW_EXPR actually blocks
    exceptions.  NULL_TREE means 'true'.  */
 #define MUST_NOT_THROW_COND(NODE) \
@@ -5361,6 +5373,21 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    && TARGET_EXPR_INITIAL (NODE)				\
    && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (NODE))))
 
+/* True if T is a TARGET_EXPR for which we'll need to replace_decl to use it as
+   an initializer.  */
+inline bool
+target_expr_needs_replace (tree t)
+{
+  if (!t || TREE_CODE (t) != TARGET_EXPR)
+    return false;
+  tree init = TARGET_EXPR_INITIAL (t);
+  if (!init || !VOID_TYPE_P (TREE_TYPE (init)))
+    return false;
+  while (TREE_CODE (init) == COMPOUND_EXPR)
+    init = TREE_OPERAND (init, 1);
+  return TREE_CODE (init) != AGGR_INIT_EXPR;
+}
+
 /* True if EXPR expresses direct-initialization of a TYPE.  */
 #define DIRECT_INIT_EXPR_P(TYPE,EXPR)					\
   (TREE_CODE (EXPR) == TARGET_EXPR && TREE_LANG_FLAG_2 (EXPR)		\
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index d1c653c5fda..d7323fb5c09 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -249,8 +249,7 @@ cp_gimplify_init_expr (tree *expr_p)
   if (TREE_CODE (from) == TARGET_EXPR)
     if (tree init = TARGET_EXPR_INITIAL (from))
       {
-	if (VOID_TYPE_P (TREE_TYPE (init))
-	    && TREE_CODE (init) != AGGR_INIT_EXPR)
+	if (target_expr_needs_replace (from))
 	  {
 	    /* If this was changed by cp_genericize_target_expr, we need to
 	       walk into it to replace uses of the slot.  */
@@ -950,14 +949,23 @@ struct cp_genericize_data
 
 /* Perform any pre-gimplification folding of C++ front end trees to
    GENERIC.
-   Note:  The folding of none-omp cases is something to move into
+   Note:  The folding of non-omp cases is something to move into
      the middle-end.  As for now we have most foldings only on GENERIC
      in fold-const, we need to perform this before transformation to
      GIMPLE-form.  */
 
-static tree
-cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
+struct cp_fold_data
 {
+  hash_set<tree> pset;
+  bool genericize; // called from cp_fold_function?
+
+  cp_fold_data (bool g): genericize (g) {}
+};
+
+static tree
+cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
+{
+  cp_fold_data *data = (cp_fold_data*)data_;
   tree stmt = *stmt_p;
   enum tree_code code = TREE_CODE (stmt);
 
@@ -967,7 +975,7 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
       if (TREE_CODE (PTRMEM_CST_MEMBER (stmt)) == FUNCTION_DECL
 	  && DECL_IMMEDIATE_FUNCTION_P (PTRMEM_CST_MEMBER (stmt)))
 	{
-	  if (!((hash_set<tree> *) data)->add (stmt))
+	  if (!data->pset.add (stmt))
 	    error_at (PTRMEM_CST_LOCATION (stmt),
 		      "taking address of an immediate function %qD",
 		      PTRMEM_CST_MEMBER (stmt));
@@ -1001,7 +1009,7 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
 
   *stmt_p = stmt = cp_fold (*stmt_p);
 
-  if (((hash_set<tree> *) data)->add (stmt))
+  if (data->pset.add (stmt))
     {
       /* Don't walk subtrees of stmts we've already walked once, otherwise
 	 we can have exponential complexity with e.g. lots of nested
@@ -1075,12 +1083,17 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
 	}
       break;
 
+      /* These are only for genericize time; they're here rather than in
+	 cp_genericize to avoid problems with the invisible reference
+	 transition.  */
     case INIT_EXPR:
-      cp_genericize_init_expr (stmt_p);
+      if (data->genericize)
+	cp_genericize_init_expr (stmt_p);
       break;
 
     case TARGET_EXPR:
-      cp_genericize_target_expr (stmt_p);
+      if (data->genericize)
+	cp_genericize_target_expr (stmt_p);
       break;
 
     default:
@@ -1096,8 +1109,8 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
 void
 cp_fold_function (tree fndecl)
 {
-  hash_set<tree> pset;
-  cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, &pset, NULL);
+  cp_fold_data data (/*genericize*/true);
+  cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, &data, NULL);
 }
 
 /* Turn SPACESHIP_EXPR EXPR into GENERIC.  */
@@ -2358,8 +2371,8 @@ cp_fully_fold_init (tree x)
   if (processing_template_decl)
     return x;
   x = cp_fully_fold (x);
-  hash_set<tree> pset;
-  cp_walk_tree (&x, cp_fold_r, &pset, NULL);
+  cp_fold_data data (/*genericize*/false);
+  cp_walk_tree (&x, cp_fold_r, &data, NULL);
   return x;
 }
 
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 1f047831b6d..fcb255f1ac7 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4368,8 +4368,8 @@ build_vec_init (tree base, tree maxindex, tree init,
       && from_array != 2)
     init = TARGET_EXPR_INITIAL (init);
 
-  if (init && TREE_CODE (init) == VEC_INIT_EXPR)
-    init = VEC_INIT_EXPR_INIT (init);
+  if (tree vi = get_vec_init_expr (init))
+    init = VEC_INIT_EXPR_INIT (vi);
 
   bool direct_init = false;
   if (from_array && init && BRACE_ENCLOSED_INITIALIZER_P (init)
@@ -4581,10 +4581,14 @@ build_vec_init (tree base, tree maxindex, tree init,
 
 	  num_initialized_elts++;
 
+	  /* We need to see sub-array TARGET_EXPR before cp_fold_r so we can
+	     handle cleanup flags properly.  */
+	  gcc_checking_assert (!target_expr_needs_replace (elt));
+
 	  if (digested)
 	    one_init = build2 (INIT_EXPR, type, baseref, elt);
-	  else if (TREE_CODE (elt) == VEC_INIT_EXPR)
-	    one_init = expand_vec_init_expr (baseref, elt, complain, flags);
+	  else if (tree vi = get_vec_init_expr (elt))
+	    one_init = expand_vec_init_expr (baseref, vi, complain, flags);
 	  else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
 	    one_init = build_aggr_init (baseref, elt, 0, complain);
 	  else
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 2d8f2c551c0..6e9be713c51 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -785,8 +785,8 @@ build_vec_init_elt (tree type, tree init, tsubst_flags_t complain)
 tree
 build_vec_init_expr (tree type, tree init, tsubst_flags_t complain)
 {
-  if (init && TREE_CODE (init) == VEC_INIT_EXPR)
-    return init;
+  if (tree vi = get_vec_init_expr (init))
+    return vi;
 
   tree elt_init;
   if (init && TREE_CODE (init) == CONSTRUCTOR
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index f439dd54866..4015bd53257 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -548,6 +548,10 @@ split_nonconstant_init_1 (tree dest, tree init, bool last,
 
 	  bool elt_last = last && idx == CONSTRUCTOR_NELTS (init) - 1;
 
+	  /* We need to see sub-array TARGET_EXPR before cp_fold_r so we can
+	     handle cleanup flags properly.  */
+	  gcc_checking_assert (!target_expr_needs_replace (value));
+
 	  if (TREE_CODE (value) == CONSTRUCTOR)
 	    {
 	      if (!split_nonconstant_init_1 (sub, value, elt_last, flags)
@@ -574,9 +578,9 @@ split_nonconstant_init_1 (tree dest, tree init, bool last,
 		  num_split_elts++;
 		}
 	    }
-	  else if (TREE_CODE (value) == VEC_INIT_EXPR)
+	  else if (tree vi = get_vec_init_expr (value))
 	    {
-	      add_stmt (expand_vec_init_expr (sub, value, tf_warning_or_error,
+	      add_stmt (expand_vec_init_expr (sub, vi, tf_warning_or_error,
 					      flags));
 
 	      /* Mark element for removal.  */
@@ -1925,6 +1929,7 @@ process_init_constructor (tree type, tree init, int nested, int flags,
 	 initializer-clause until later so we can use a loop.  */
       TREE_TYPE (init) = init_list_type_node;
       init = build_vec_init_expr (type, init, complain);
+      init = get_target_expr (init);
     }
   return init;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array14.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array14.C
new file mode 100644
index 00000000000..baa4afc91fd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array14.C
@@ -0,0 +1,12 @@
+// PR c++/104300
+// { dg-do compile { target c++11 } }
+
+struct ss {
+  char r;
+  ss();
+};
+struct a {
+  ss e[6];
+};
+a vv;
+void ff() { vv = {}; }
