call.c (build_over_call): Check unsafe_copy_elision_p even for trivial constructors.

* call.c (build_over_call): Check unsafe_copy_elision_p even for
	trivial constructors.
	* method.c (do_build_copy_constructor): Don't copy tail padding
	even in a trivial constructor.

From-SVN: r238620
This commit is contained in:
Jason Merrill 2016-07-21 23:45:30 -04:00 committed by Jason Merrill
parent 4114e6b1fe
commit d5ec842cde
4 changed files with 55 additions and 10 deletions

View File

@ -1,3 +1,10 @@
2016-07-21 Jason Merrill <jason@redhat.com>
* call.c (build_over_call): Check unsafe_copy_elision_p even for
trivial constructors.
* method.c (do_build_copy_constructor): Don't copy tail padding
even in a trivial constructor.
2016-07-21 Jakub Jelinek <jakub@redhat.com>
PR c++/71728

View File

@ -7271,6 +7271,9 @@ is_base_field_ref (tree t)
static bool
unsafe_copy_elision_p (tree target, tree exp)
{
/* Copy elision only happens with a TARGET_EXPR. */
if (TREE_CODE (exp) != TARGET_EXPR)
return false;
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
if (type == CLASSTYPE_AS_BASE (type))
return false;
@ -7726,9 +7729,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
else if (trivial)
return force_target_expr (DECL_CONTEXT (fn), arg, complain);
}
else if (trivial
|| (TREE_CODE (arg) == TARGET_EXPR
&& !unsafe_copy_elision_p (fa, arg)))
else if ((trivial || TREE_CODE (arg) == TARGET_EXPR)
&& !unsafe_copy_elision_p (fa, arg))
{
tree to = cp_stabilize_reference (cp_build_indirect_ref (fa,
RO_NULL,

View File

@ -542,14 +542,32 @@ do_build_copy_constructor (tree fndecl)
if (!inh)
parm = convert_from_reference (parm);
if (trivial
&& is_empty_class (current_class_type))
/* Don't copy the padding byte; it might not have been allocated
if *this is a base subobject. */;
else if (trivial)
if (trivial)
{
tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm);
finish_expr_stmt (t);
if (is_empty_class (current_class_type))
/* Don't copy the padding byte; it might not have been allocated
if *this is a base subobject. */;
else if (tree_int_cst_equal (TYPE_SIZE (current_class_type),
CLASSTYPE_SIZE (current_class_type)))
{
tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm);
finish_expr_stmt (t);
}
else
{
/* We must only copy the non-tail padding parts. */
tree base_size = CLASSTYPE_SIZE_UNIT (current_class_type);
base_size = size_binop (MINUS_EXPR, base_size, size_int (1));
tree array_type = build_array_type (unsigned_char_type_node,
build_index_type (base_size));
tree alias_set = build_int_cst (TREE_TYPE (current_class_ptr), 0);
tree lhs = build2 (MEM_REF, array_type,
current_class_ptr, alias_set);
tree rhs = build2 (MEM_REF, array_type,
TREE_OPERAND (parm, 0), alias_set);
tree t = build2 (INIT_EXPR, void_type_node, lhs, rhs);
finish_expr_stmt (t);
}
}
else
{

View File

@ -0,0 +1,18 @@
// Test that initializing a non-POD base with a trivial copy ctor doesn't
// clobber tail padding.
// { dg-do run }
struct X { ~X() {} int n; char d; };
struct Y { Y(); char c[3]; };
struct Z : X, virtual Y { Z(); };
X f() { X nrvo; __builtin_memset(&nrvo, 0, sizeof(X)); return nrvo; }
Z::Z() : Y(), X(f()) {}
Y::Y() { c[0] = 1; }
int main() {
Z z;
if (z.c[0] != 1)
__builtin_abort ();
}