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:
parent
8dc1dc7975
commit
e2df21bfc6
5 changed files with 140 additions and 1 deletions
|
@ -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.
|
||||
|
||||
|
|
|
@ -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))))
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
64
gcc/testsuite/g++.dg/cpp0x/initlist-lifetime2.C
Normal file
64
gcc/testsuite/g++.dg/cpp0x/initlist-lifetime2.C
Normal 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;
|
||||
}
|
23
gcc/testsuite/g++.dg/init/lifetime2.C
Normal file
23
gcc/testsuite/g++.dg/init/lifetime2.C
Normal 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;
|
||||
}
|
Loading…
Add table
Reference in a new issue