re PR c++/26714 (violation of [class.temporary]/5)

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

From-SVN: r181002
This commit is contained in:
Jason Merrill 2011-11-04 23:28:14 -04:00 committed by Jason Merrill
parent 8dc1dc7975
commit e2df21bfc6
5 changed files with 140 additions and 1 deletions

View file

@ -1,5 +1,9 @@
2011-11-04 Jason Merrill <jason@redhat.com>
PR c++/26714
* init.c (perform_member_init): Strip TARGET_EXPR around NSDMI.
Do temporary lifetime extension.
PR c++/48370
* decl.c (cp_finish_decl): Run cleanups in the right order.

View file

@ -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 constructors 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))))
{

View file

@ -1,5 +1,9 @@
2011-11-04 Jason Merrill <jason@redhat.com>
PR c++/26714
* g++.dg/init/lifetime2.C: New.
* g++.dg/cpp0x/initlist-lifetime2.C: New.
PR c++/48370
* g++.dg/init/lifetime1.C: Test cleanup order.

View file

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

View file

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