PR c++/71913 - missing copy elision with new.
authorJason Merrill <jason@redhat.com>
Fri, 22 Jul 2016 03:45:37 +0000 (23:45 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 22 Jul 2016 03:45:37 +0000 (23:45 -0400)
* call.c (unsafe_copy_elision_p): It's OK to elide when
initializing an unknown object.

From-SVN: r238621

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/g++.dg/init/elide5.C [new file with mode: 0644]

index 3d3e85fdc48a19d2ad25fcac15864533d44623d1..b196d54937d8cc17eac5db55a5e9cdf6683ee1ce 100644 (file)
@@ -1,5 +1,9 @@
 2016-07-21  Jason Merrill  <jason@redhat.com>
 
+       PR c++/71913
+       * call.c (unsafe_copy_elision_p): It's OK to elide when
+       initializing an unknown object.
+
        * 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
index d917d9afed4612ecc399d266b10c6d674b8f1e6f..061e7084d37fc27b01f8e046bc8d3b7703460688 100644 (file)
@@ -7275,10 +7275,11 @@ unsafe_copy_elision_p (tree target, tree exp)
   if (TREE_CODE (exp) != TARGET_EXPR)
     return false;
   tree type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
-  if (type == CLASSTYPE_AS_BASE (type))
+  /* It's safe to elide the copy for a class with no tail padding.  */
+  if (tree_int_cst_equal (TYPE_SIZE (type), CLASSTYPE_SIZE (type)))
     return false;
-  if (!is_base_field_ref (target)
-      && resolves_to_fixed_type_p (target, NULL))
+  /* It's safe to elide the copy if we aren't initializing a base object.  */
+  if (!is_base_field_ref (target))
     return false;
   tree init = TARGET_EXPR_INITIAL (exp);
   /* build_compound_expr pushes COMPOUND_EXPR inside TARGET_EXPR.  */
diff --git a/gcc/testsuite/g++.dg/init/elide5.C b/gcc/testsuite/g++.dg/init/elide5.C
new file mode 100644 (file)
index 0000000..0a9978c
--- /dev/null
@@ -0,0 +1,27 @@
+// PR c++/71913
+// { dg-do link { target c++11 } }
+
+void* operator new(unsigned long, void* p) { return p; }
+
+struct IndirectReturn {
+  IndirectReturn() {}
+  // Undefined so we get a link error if the indirect return value is copied
+  IndirectReturn(const IndirectReturn&);
+  IndirectReturn& operator=(const IndirectReturn&) = delete;
+  ~IndirectReturn() {}
+};
+
+IndirectReturn foo() { return IndirectReturn(); }
+
+void bar(void* ptr) {
+  new (ptr) IndirectReturn(foo());
+}
+
+alignas (alignof (IndirectReturn))
+unsigned char c[sizeof(IndirectReturn)];
+
+int main()
+{
+  bar(c);
+}
+