Here the issue was that build_new_1 wants to stabilize any constructor arguments so that the EH region for deleting the allocated memory can be as small as possible. But stabilize_expr was being over-eager, making a copy of a class with trivial constructors, but a non-trivial (and indeed non-callable) destructor. And even if it didn't have a problematic destructor, there's no reason to introduce extra copies of trivially copyable classes. So this patch changes stabilize_expr to only make copies of scalar types and class prvalues.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 21a411247eb5e59895aa54ff9a85e3cf8795a81a
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed May 4 11:15:30 2011 -0400

        PR c++/48873
        * tree.c (stabilize_expr): Don't make gratuitous copies of classes.

diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 0f2f86c..9a6e26d 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -3119,7 +3119,10 @@ stabilize_expr (tree exp, tree* initp)
 
   if (!TREE_SIDE_EFFECTS (exp))
     init_expr = NULL_TREE;
-  else if (!TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp))
+  /* There are no expressions with REFERENCE_TYPE, but there can be call
+     arguments with such a type; just treat it as a pointer.  */
+  else if (TREE_CODE (TREE_TYPE (exp)) == REFERENCE_TYPE
+          || SCALAR_TYPE_P (exp)
           || !lvalue_or_rvalue_with_address_p (exp))
     {
       init_expr = get_target_expr (exp);
diff --git a/gcc/testsuite/g++.dg/init/new32.C 
b/gcc/testsuite/g++.dg/init/new32.C
new file mode 100644
index 0000000..f827857
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/new32.C
@@ -0,0 +1,16 @@
+// PR c++/48873
+
+#include <new>
+
+struct D {
+private:
+  ~D();
+};
+
+template<class T>
+T& create();
+
+void f()
+{
+  D* dp = new (((void*) 0)) D(create<D>()); // #
+}

Reply via email to