This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Fix placement new if operator new has 2nd argument REFERENCE_TYPE (PR c++/34862)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Jason Merrill <jason at redhat dot com>, Mark Mitchell <mark at codesourcery dot com>, Ian Lance Taylor <iant at google dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Tue, 29 Jan 2008 08:06:01 -0500
- Subject: [C++ PATCH] Fix placement new if operator new has 2nd argument REFERENCE_TYPE (PR c++/34862)
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
If placement new is passed a POINTER, the C++ optimizes and passes
instead a TARGET_EXPR on which it applies CHANGE_DYNAMIC_TYPE_EXPR,
otherwise (placement new with more than one argument, or non-pointer),
asm volatile barrier is used. If operator new has second argument
a reference to a pointer, this means either silent miscompilation
(when placement_expr used to be initialized with get_temp_regvar)
or incorrect error (since my PR33025 fix when get_target_expr is
used instead). So for this optimization we need to know if
the placement pointer will be passed through reference or not.
Unfortunately overload resolution already needs arguments in place
and modifies them and performing it twice, once with original
placement argument, once with target_expr risks duplicate
diagnostics. The following patch performs overload resolution
with the original placement argument and if it is not a reference,
will modify the CALL_EXPR arguments.
Ok for trunk?
2008-01-29 Jakub Jelinek <jakub@redhat.com>
PR c++/34862
* init.c (build_new_1): Don't create placement_expr before
constructing alloc_call. Verify that the pointer is passed by
value to operator new.
* g++.dg/init/new27.C: New test.
--- gcc/cp/init.c.jj 2008-01-23 00:35:57.000000000 +0100
+++ gcc/cp/init.c 2008-01-29 13:58:05.000000000 +0100
@@ -1653,7 +1653,7 @@ build_new_1 (tree placement, tree type,
beginning of the storage allocated for an array-new expression in
order to store the number of elements. */
tree cookie_size = NULL_TREE;
- tree placement_expr;
+ tree placement_expr = NULL_TREE;
/* True if the function we are calling is a placement allocation
function. */
bool placement_allocation_fn_p;
@@ -1745,19 +1745,6 @@ build_new_1 (tree placement, tree type,
alloc_fn = NULL_TREE;
- /* If PLACEMENT is a simple pointer type, then copy it into
- PLACEMENT_EXPR. */
- if (processing_template_decl
- || placement == NULL_TREE
- || TREE_CHAIN (placement) != NULL_TREE
- || TREE_CODE (TREE_TYPE (TREE_VALUE (placement))) != POINTER_TYPE)
- placement_expr = NULL_TREE;
- else
- {
- placement_expr = get_target_expr (TREE_VALUE (placement));
- placement = tree_cons (NULL_TREE, placement_expr, NULL_TREE);
- }
-
/* Allocate the object. */
if (! placement && TYPE_FOR_JAVA (elt_type))
{
@@ -1852,6 +1839,28 @@ build_new_1 (tree placement, tree type,
gcc_assert (alloc_fn != NULL_TREE);
+ /* If PLACEMENT is a simple pointer type and is not passed by reference,
+ then copy it into PLACEMENT_EXPR. */
+ if (!processing_template_decl
+ && placement != NULL_TREE
+ && TREE_CHAIN (placement) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (TREE_VALUE (placement))) == POINTER_TYPE
+ && TREE_CODE (alloc_call) == CALL_EXPR
+ && call_expr_nargs (alloc_call) == 2
+ && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 0))) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 1))) == POINTER_TYPE)
+ {
+ tree placement_arg = CALL_EXPR_ARG (alloc_call, 1);
+
+ if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg)))
+ || VOID_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg))))
+ {
+ placement_expr = get_target_expr (TREE_VALUE (placement));
+ CALL_EXPR_ARG (alloc_call, 1)
+ = convert (TREE_TYPE (placement_arg), placement_expr);
+ }
+ }
+
/* In the simple case, we can stop now. */
pointer_type = build_pointer_type (type);
if (!cookie_size && !is_initialized)
--- gcc/testsuite/g++.dg/init/new27.C.jj 2008-01-29 13:06:21.000000000 +0100
+++ gcc/testsuite/g++.dg/init/new27.C 2008-01-29 13:05:42.000000000 +0100
@@ -0,0 +1,40 @@
+// PR c++/34862
+// { dg-do run }
+// { dg-options "-O2" }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" void abort ();
+
+struct T
+{
+ void *operator new (size_t, char *&);
+ T () { i[0] = 1; i[1] = 2; }
+ int i[2];
+};
+
+void *
+T::operator new (size_t size, char *&p)
+{
+ void *o = (void *) p;
+ p += size;
+ return o;
+}
+
+T *
+f (char *&x)
+{
+ return new (x) T ();
+}
+
+char buf[10 * sizeof (T)] __attribute__((aligned (__alignof (T))));
+
+int
+main ()
+{
+ char *p = buf;
+ T *t = f (p);
+ if (p != buf + sizeof (T))
+ abort ();
+ if (t->i[0] != 1 || t->i[1] != 2)
+ abort ();
+}
Jakub