c++: fix missing lifetime extension [PR119383]
Since r15-8011 cp_build_indirect_ref_1 won't do the *&TARGET_EXPR -> TARGET_EXPR folding not to change its value category. That fix seems correct but it made us stop extending the lifetime in this testcase, causing a wrong-code issue -- extend_ref_init_temps_1 did not see through the extra *& because it doesn't use a tree walk. This patch reverts r15-8011 and instead handles the problem in build_over_call by calling force_lvalue in the is_really_empty_class case as well as in the general case. PR c++/119383 gcc/cp/ChangeLog: * call.cc (build_over_call): Use force_lvalue to ensure op= returns an lvalue. * cp-tree.h (force_lvalue): Declare. * cvt.cc (force_lvalue): New. * typeck.cc (cp_build_indirect_ref_1): Revert r15-8011. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/temp-extend3.C: New test. Reviewed-by: Jason Merrill <jason@redhat.com>
This commit is contained in:
parent
182d891e13
commit
e9803f10c9
5 changed files with 55 additions and 10 deletions
|
@ -10828,10 +10828,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
|
|||
if (is_really_empty_class (type, /*ignore_vptr*/true))
|
||||
{
|
||||
/* Avoid copying empty classes, but ensure op= returns an lvalue even
|
||||
if the object argument isn't one. This isn't needed in other cases
|
||||
since MODIFY_EXPR is always considered an lvalue. */
|
||||
to = cp_build_addr_expr (to, tf_none);
|
||||
to = cp_build_indirect_ref (input_location, to, RO_ARROW, complain);
|
||||
if the object argument isn't one. */
|
||||
to = force_lvalue (to, complain);
|
||||
val = build2 (COMPOUND_EXPR, type, arg, to);
|
||||
suppress_warning (val, OPT_Wunused);
|
||||
}
|
||||
|
@ -10852,6 +10850,9 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
|
|||
tree array_type, alias_set;
|
||||
|
||||
arg2 = TYPE_SIZE_UNIT (as_base);
|
||||
/* Ensure op= returns an lvalue even if the object argument isn't
|
||||
one. */
|
||||
to = force_lvalue (to, complain);
|
||||
to = cp_stabilize_reference (to);
|
||||
arg0 = cp_build_addr_expr (to, complain);
|
||||
|
||||
|
|
|
@ -7079,6 +7079,7 @@ extern tree convert_to_reference (tree, tree, int, int, tree,
|
|||
tsubst_flags_t);
|
||||
extern tree convert_from_reference (tree);
|
||||
extern tree force_rvalue (tree, tsubst_flags_t);
|
||||
extern tree force_lvalue (tree, tsubst_flags_t);
|
||||
extern tree ocp_convert (tree, tree, int, int,
|
||||
tsubst_flags_t);
|
||||
extern tree cp_convert (tree, tree, tsubst_flags_t);
|
||||
|
|
|
@ -575,6 +575,19 @@ force_rvalue (tree expr, tsubst_flags_t complain)
|
|||
return expr;
|
||||
}
|
||||
|
||||
/* Force EXPR to be an lvalue, if it isn't already. */
|
||||
|
||||
tree
|
||||
force_lvalue (tree expr, tsubst_flags_t complain)
|
||||
{
|
||||
if (!lvalue_p (expr))
|
||||
{
|
||||
expr = cp_build_addr_expr (expr, complain);
|
||||
expr = cp_build_indirect_ref (input_location, expr, RO_ARROW, complain);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
/* If EXPR and ORIG are INTEGER_CSTs, return a version of EXPR that has
|
||||
TREE_OVERFLOW set only if it is set in ORIG. Otherwise, return EXPR
|
||||
|
|
|
@ -3870,13 +3870,11 @@ cp_build_indirect_ref_1 (location_t loc, tree ptr, ref_operator errorstring,
|
|||
return error_mark_node;
|
||||
}
|
||||
else if (do_fold && TREE_CODE (pointer) == ADDR_EXPR
|
||||
&& same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0)))
|
||||
/* Don't let this change the value category. '*&TARGET_EXPR'
|
||||
is an lvalue, but folding it into 'TARGET_EXPR' would turn
|
||||
it into a prvalue of class type. */
|
||||
&& lvalue_p (TREE_OPERAND (pointer, 0)))
|
||||
&& same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
|
||||
/* The POINTER was something like `&x'. We simplify `*&x' to
|
||||
`x'. */
|
||||
`x'. This can change the value category: '*&TARGET_EXPR'
|
||||
is an lvalue and folding it into 'TARGET_EXPR' turns it into
|
||||
a prvalue of class type. */
|
||||
return TREE_OPERAND (pointer, 0);
|
||||
else
|
||||
{
|
||||
|
|
32
gcc/testsuite/g++.dg/cpp0x/temp-extend3.C
Normal file
32
gcc/testsuite/g++.dg/cpp0x/temp-extend3.C
Normal file
|
@ -0,0 +1,32 @@
|
|||
// PR c++/119383
|
||||
// { dg-do run { target c++11 } }
|
||||
|
||||
int g;
|
||||
|
||||
struct base {
|
||||
virtual base *clone() const = 0;
|
||||
~base() { }
|
||||
};
|
||||
|
||||
struct impl : virtual base {
|
||||
base *clone() const { return new impl; } // #1
|
||||
impl() { ++g; }
|
||||
~impl() { --g; }
|
||||
};
|
||||
|
||||
const base *
|
||||
make_a_clone ()
|
||||
{
|
||||
const base &base = impl{}; // #2
|
||||
return base.clone();
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
make_a_clone ();
|
||||
// impl::impl() is called twice (#1 and #2), impl::~impl() once,
|
||||
// at the end of make_a_clone.
|
||||
if (g != 1)
|
||||
__builtin_abort ();
|
||||
}
|
Loading…
Add table
Reference in a new issue