commit 30ed5835a92df18afef71802b5fa95899ceca227
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Nov 4 14:59:20 2011 -0400

    	PR c++/26714
    	* init.c (perform_member_init): Strip TARGET_EXPR around NSDMI.
    	Do temporary lifetime extension.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 3881275..ca4f590 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -507,7 +507,15 @@ perform_member_init (tree member, tree init)
 		 tf_warning_or_error, member, /*function_p=*/false,
 		 /*integral_constant_expression_p=*/false));
       else
-	init = break_out_target_exprs (DECL_INITIAL (member));
+	{
+	  init = DECL_INITIAL (member);
+	  /* Strip redundant TARGET_EXPR so we don't need to remap it, and
+	     so the aggregate init code below will see a CONSTRUCTOR.  */
+	  if (init && TREE_CODE (init) == TARGET_EXPR
+	      && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (init))))
+	    init = TARGET_EXPR_INITIAL (init);
+	  init = break_out_target_exprs (init);
+	}
     }
 
   /* Effective C++ rule 12 requires that all data members be
@@ -565,6 +573,42 @@ perform_member_init (tree member, tree init)
 	  finish_expr_stmt (init);
 	}
     }
+  else if (init
+	   && (TREE_CODE (type) == REFERENCE_TYPE
+	       /* Pre-digested NSDMI.  */
+	       || (((TREE_CODE (init) == CONSTRUCTOR
+		     && TREE_TYPE (init) == type)
+		    /* { } mem-initializer.  */
+		    || (TREE_CODE (init) == TREE_LIST
+			&& TREE_CODE (TREE_VALUE (init)) == CONSTRUCTOR
+			&& CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init))))
+		   && (CP_AGGREGATE_TYPE_P (type)
+		       || is_std_init_list (type)))))
+    {
+      /* With references and list-initialization, we need to deal with
+	 extending temporary lifetimes.  12.2p5: "A temporary bound to a
+	 reference member in a constructor’s ctor-initializer (12.6.2)
+	 persists until the constructor exits."  */
+      unsigned i; tree t;
+      VEC(tree,gc) *cleanups = make_tree_vector ();
+      if (TREE_CODE (init) == TREE_LIST)
+	init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
+						tf_warning_or_error);
+      if (TREE_TYPE (init) != type)
+	init = digest_init (type, init, tf_warning_or_error);
+      if (init == error_mark_node)
+	return;
+      /* Use 'this' as the decl, as it has the lifetime we want.  */
+      init = extend_ref_init_temps (current_class_ptr, init, &cleanups);
+      if (TREE_CODE (type) == ARRAY_TYPE
+	  && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)))
+	init = build_vec_init_expr (type, init, tf_warning_or_error);
+      init = build2 (INIT_EXPR, type, decl, init);
+      finish_expr_stmt (init);
+      FOR_EACH_VEC_ELT (tree, cleanups, i, t)
+	push_cleanup (decl, t, false);
+      release_tree_vector (cleanups);
+    }
   else if (type_build_ctor_call (type)
 	   || (init && CLASS_TYPE_P (strip_array_types (type))))
     {
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime2.C
new file mode 100644
index 0000000..16ae1ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime2.C
@@ -0,0 +1,64 @@
+// Test that we properly extend the lifetime of the initializer_list
+// array even if the initializer_list is a subobject.
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+#include <initializer_list>
+
+extern "C" void abort();
+bool ok;
+
+bool do_throw;
+
+struct A {
+  A(int) { if (do_throw) throw 42; }
+  ~A() { if (!ok) abort(); }
+};
+
+typedef std::initializer_list<A> AL;
+typedef std::initializer_list<AL> AL2;
+typedef std::initializer_list<AL2> AL3;
+
+struct B {
+  AL al;
+  const AL& alr;
+};
+
+struct A2
+{
+  const A& a1;
+  const A& a2;
+};
+
+struct C {
+  AL ar[2];
+  B b;
+  AL3 al3;
+  A2 a2;
+  A2 a2r[2];
+  C():
+    ar{{1,2},{3,4}},
+    b{{5,6},{7,8}},
+    al3{{{1},{2},{3}}},
+    a2{1,2},
+    a2r{{1,2},{3,4}}
+  { ok = true; }
+};
+
+struct D {
+  AL ar[2] = {{1,2},{3,4}};
+  B b = {{5,6},{7,8}};
+  AL3 al3 = {{{1},{2},{3}}};
+  A2 a2 = {1,2};
+  A2 a2r[2] = {{1,2},{3,4}};
+  D() { ok = true; }
+};
+
+int main(int argc, const char** argv)
+{
+  do_throw = (argc > 1);	// always false, but optimizer can't tell
+  ok = false;
+  C c;
+  ok = false;
+  D d;
+}
diff --git a/gcc/testsuite/g++.dg/init/lifetime2.C b/gcc/testsuite/g++.dg/init/lifetime2.C
new file mode 100644
index 0000000..293bd69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/lifetime2.C
@@ -0,0 +1,23 @@
+// PR c++/26714
+// { dg-do run }
+
+extern "C" void abort();
+
+bool ok = false;
+struct A
+{
+  A() { }
+  ~A() { if (!ok) abort(); }
+};
+
+struct B
+{
+  const A &a1;
+  const A &a2;
+  B() : a1(A()),a2(A()) { ok = true; }
+};
+
+int main()
+{
+  B b;
+}
