call.c (build_over_call): Check unsafe_copy_elision_p even for trivial constructors.
authorJason Merrill <jason@redhat.com>
Fri, 22 Jul 2016 03:45:30 +0000 (23:45 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 22 Jul 2016 03:45:30 +0000 (23:45 -0400)
* 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
gcc/cp/call.c
gcc/cp/method.c
gcc/testsuite/g++.dg/torture/tail-padding1.C [new file with mode: 0644]

index 0ba456c76e5256487c216a5aaba0a16e43b641ea..3d3e85fdc48a19d2ad25fcac15864533d44623d1 100644 (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
index f929fb2042d86e1a873c6760effd0d11dc7d442d..d917d9afed4612ecc399d266b10c6d674b8f1e6f 100644 (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,
index cd8faaf483f67cabc724820042a2e1058ed11f63..63aa53ea9cdc9e30fd31427117067bc7a5722bc1 100644 (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
     {
diff --git a/gcc/testsuite/g++.dg/torture/tail-padding1.C b/gcc/testsuite/g++.dg/torture/tail-padding1.C
new file mode 100644 (file)
index 0000000..43e26ad
--- /dev/null
@@ -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 ();
+}