From d5ec842cde69dedaf9a447d7d7a00735c9b4da40 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 21 Jul 2016 23:45:30 -0400 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 7 +++++ gcc/cp/call.c | 8 +++-- gcc/cp/method.c | 32 +++++++++++++++----- gcc/testsuite/g++.dg/torture/tail-padding1.C | 18 +++++++++++ 4 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/tail-padding1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0ba456c76e5..3d3e85fdc48 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2016-07-21 Jason Merrill + + * 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 PR c++/71728 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f929fb2042d..d917d9afed4 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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, diff --git a/gcc/cp/method.c b/gcc/cp/method.c index cd8faaf483f..63aa53ea9cd 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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 { diff --git a/gcc/testsuite/g++.dg/torture/tail-padding1.C b/gcc/testsuite/g++.dg/torture/tail-padding1.C new file mode 100644 index 00000000000..43e26adacea --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/tail-padding1.C @@ -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 (); +} -- 2.30.2