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>
|
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
|
PR c++/48370
|
||||||
* decl.c (cp_finish_decl): Run cleanups in the right order.
|
* 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,
|
tf_warning_or_error, member, /*function_p=*/false,
|
||||||
/*integral_constant_expression_p=*/false));
|
/*integral_constant_expression_p=*/false));
|
||||||
else
|
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
|
/* 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);
|
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)
|
else if (type_build_ctor_call (type)
|
||||||
|| (init && CLASS_TYPE_P (strip_array_types (type))))
|
|| (init && CLASS_TYPE_P (strip_array_types (type))))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
2011-11-04 Jason Merrill <jason@redhat.com>
|
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
|
PR c++/48370
|
||||||
* g++.dg/init/lifetime1.C: Test cleanup order.
|
* 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