Patchwork C++ PATCH for c++/26714 (lifetime of temps in mem-initializers for reference members)

login
register
mail settings
Submitter Jason Merrill
Date Nov. 5, 2011, 3:24 a.m.
Message ID <4EB4AC8A.1070607@redhat.com>
Download mbox | patch
Permalink /patch/123816/
State New
Headers show

Comments

Jason Merrill - Nov. 5, 2011, 3:24 a.m.
After my previous patch for 48370 which adds extend_ref_init_temps, it 
is straightforward to fix this issue as well by extending ref init 
mem-initializers to match the lifetime of 'this'.

Tested x86_64-pc-linux-gnu, applying to trunk.
IainS - Nov. 5, 2011, 2:32 p.m.
On 5 Nov 2011, at 03:24, Jason Merrill wrote:

> After my previous patch for 48370 which adds extend_ref_init_temps,  
> it is straightforward to fix this issue as well by extending ref  
> init mem-initializers to match the lifetime of 'this'.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.
> 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.

either this or the previous patch has broken (or exposed a problem  
which has broken)  bootstrap on i686-darwin9  with:

libtool: compile:  /GCC/gcc-4-7-trunk-build/./gcc/xgcc -shared-libgcc - 
B/GCC/gcc-4-7-trunk-build/./gcc -nostdinc++ -L/GCC/gcc-4-7-trunk-build/ 
i686-apple-darwin9/x86_64/libstdc++-v3/src -L/GCC/gcc-4-7-trunk-build/ 
i686-apple-darwin9/x86_64/libstdc++-v3/src/.libs -B/GCC/gcc-4-7- 
install/i686-apple-darwin9/bin/ -B/GCC/gcc-4-7-install/i686-apple- 
darwin9/lib/ -isystem /GCC/gcc-4-7-install/i686-apple-darwin9/include - 
isystem /GCC/gcc-4-7-install/i686-apple-darwin9/sys-include -m64 -I/ 
GCC/gcc-4-7-trunk-build/i686-apple-darwin9/x86_64/libstdc++-v3/include/ 
i686-apple-darwin9 -I/GCC/gcc-4-7-trunk-build/i686-apple-darwin9/ 
x86_64/libstdc++-v3/include -I/GCC/gcc-live-trunk/libstdc++-v3/libsupc+ 
+ -fno-implicit-templates -Wall -Wextra -Wwrite-strings -Wcast-qual - 
fdiagnostics-show-location=once -fvisibility-inlines-hidden -ffunction- 
sections -fdata-sections -frandom-seed=functexcept.lo -g -O2 -m64 - 
std=gnu++0x -c /GCC/gcc-live-trunk/libstdc++-v3/src/functexcept.cc  - 
fno-common -DPIC -o .libs/functexcept.o
In file included from /GCC/gcc-4-7-trunk-build/i686-apple-darwin9/ 
x86_64/libstdc++-v3/include/future:41:0,
                  from /GCC/gcc-live-trunk/libstdc++-v3/src/ 
functexcept.cc:32:
/GCC/gcc-4-7-trunk-build/i686-apple-darwin9/x86_64/libstdc++-v3/ 
include/thread:195:46: internal compiler error: Segmentation fault
Please submit a full bug report,

gdb:

GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096
Compiler executable checksum: d5643d919cac033598d9277e144abbda

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0xa5a5a5a5
0x00443fca in build_stmt (loc=6644384, code=CLEANUP_STMT) at /GCC/gcc- 
live-trunk/gcc/c-family/c-semantics.c:124
124           if (t && !TYPE_P (t))
(gdb) bt
#0  0x00443fca in build_stmt (loc=6644384, code=CLEANUP_STMT) at /GCC/ 
gcc-live-trunk/gcc/c-family/c-semantics.c:124
#1  0x002da1f3 in push_cleanup (decl=0x2d36280, cleanup=0xa5a5a5a5,  
eh_only=0 '\0') at /GCC/gcc-live-trunk/gcc/cp/semantics.c:488
#2  0x00069fad in cp_finish_decl (decl=0x2d36280, init=0x428167b8,  
init_const_expr_p=0 '\0', asmspec_tree=0x0, flags=11) at /GCC/gcc-live- 
trunk/gcc/cp/decl.c:6320
#3  0x00223127 in cp_parser_init_declarator (parser=0x42827188,  
decl_specifiers=0xbfffe81c, checks=0x0,  
function_definition_allowed_p=1 '\001', member_p=0 '\0',  
declares_class_or_enum=0, function_definition_p=0xbfffe817 "",  
maybe_range_for_decl=0x0) at /GCC/gcc-live-trunk/gcc/cp/parser.c:15462
#4  0x00219e28 in cp_parser_simple_declaration (parser=0x42827188,  
function_definition_allowed_p=1 '\001', maybe_range_for_decl=0x0) at / 
GCC/gcc-live-trunk/gcc/cp/parser.c:10301
#5  0x00219c70 in cp_parser_block_declaration (parser=0x42827188,  
statement_p=0 '\0') at /GCC/gcc-live-trunk/gcc/cp/parser.c:10187
#6  0x00219a68 in cp_parser_declaration (parser=0x42827188) at /GCC/ 
gcc-live-trunk/gcc/cp/parser.c:10092
#7  0x002196dd in cp_parser_declaration_seq_opt (parser=0x42827188)  
at /GCC/gcc-live-trunk/gcc/cp/parser.c:9978
#8  0x00221c85 in cp_parser_namespace_body (parser=0x42827188) at /GCC/ 
gcc-live-trunk/gcc/cp/parser.c:14633
#9  0x00221c3b in cp_parser_namespace_definition (parser=0x42827188)  
at /GCC/gcc-live-trunk/gcc/cp/parser.c:14614
#10 0x002199b7 in cp_parser_declaration (parser=0x42827188) at /GCC/ 
gcc-live-trunk/gcc/cp/parser.c:10076
#11 0x002196dd in cp_parser_declaration_seq_opt (parser=0x42827188)  
at /GCC/gcc-live-trunk/gcc/cp/parser.c:9978
#12 0x0020c287 in cp_parser_translation_unit (parser=0x42827188) at / 
GCC/gcc-live-trunk/gcc/cp/parser.c:3739
#13 0x002416dc in c_parse_file () at /GCC/gcc-live-trunk/gcc/cp/ 
parser.c:26714
#14 0x0042edb3 in c_common_parse_file () at /GCC/gcc-live-trunk/gcc/c- 
family/c-opts.c:1122
#15 0x00e2a954 in compile_file () at /GCC/gcc-live-trunk/gcc/toplev.c: 
565
#16 0x00e2d634 in do_compile () at /GCC/gcc-live-trunk/gcc/toplev.c:1930
#17 0x00e2d81d in toplev_main (argc=57, argv=0xbfffebe4) at /GCC/gcc- 
live-trunk/gcc/toplev.c:2006
#18 0x00458618 in main (argc=57, argv=0xbfffebe4) at /GCC/gcc-live- 
trunk/gcc/main.c:36

cheers
Iain
Jason Merrill - Nov. 5, 2011, 9:30 p.m.
On 11/05/2011 10:32 AM, Iain Sandoe wrote:
> either this or the previous patch has broken (or exposed a problem which
> has broken) bootstrap on i686-darwin9 with:

I've mostly reverted the previous patch, does that fix bootstrap for 
you?  I don't understand yet what the problem is.

Jason
IainS - Nov. 5, 2011, 9:32 p.m.
On 5 Nov 2011, at 21:30, Jason Merrill wrote:

> On 11/05/2011 10:32 AM, Iain Sandoe wrote:
>> either this or the previous patch has broken (or exposed a problem  
>> which
>> has broken) bootstrap on i686-darwin9 with:
>
> I've mostly reverted the previous patch, does that fix bootstrap for  
> you?  I don't understand yet what the problem is.

I'll set it running now...  try to report back today...
looks like a GTY kinda issue from the pattern showing in the gdb output/

thanks,
Iain
IainS - Nov. 5, 2011, 9:53 p.m.
On 5 Nov 2011, at 21:32, Iain Sandoe wrote:

> On 5 Nov 2011, at 21:30, Jason Merrill wrote:
>
>> On 11/05/2011 10:32 AM, Iain Sandoe wrote:
>>> either this or the previous patch has broken (or exposed a problem  
>>> which
>>> has broken) bootstrap on i686-darwin9 with:
>>
>> I've mostly reverted the previous patch, does that fix bootstrap  
>> for you?  I don't understand yet what the problem is.
>
> I'll set it running now...  try to report back today...

we're on stage2 - so looking good.

> looks like a GTY kinda issue from the pattern showing in the gdb  
> output/

two more data points -
1) doesn't fail on either powerpc-darwin9 or x86-64-darwin10.
2) doesn't fail if compiled "-save-temps"

.. makes one think that it's sensitive to the headers used
cheers
Iain

Patch

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;
+}