This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/36633
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 31 Jul 2008 13:37:49 -0400
- Subject: C++ PATCH for c++/36633
When I started looking at 36633, it seemed to have already been fixed;
the optimizers aren't generating the array references anymore for some
reason. But it still seemed odd to me that the compiler is generating
code like
void *vp = operator new[](size);
T *tp = vp + cookie size;
int *cp = tp - cookie size;
*cp = cookie;
Better to avoid the subtraction, and initialize cp directly from vp.
The memory allocated is not all Ts, it's an int followed by some Ts.
The code generated is correct, but there's no need to confuse the
optimizers by going through T* along the way to initializing the cookie.
Since I couldn't reproduce the bug described in the PR, my testcase
looks at the tree dump.
Tested x86_64-pc-linux-gnu, applied to trunk.
2008-07-31 Jason Merrill <jason@redhat.com>
PR c++/36633
* init.c (build_new_1): Don't convert pointer to the data type
until we're actually going to treat it as that type.
Index: cp/init.c
===================================================================
*** cp/init.c (revision 138355)
--- cp/init.c (working copy)
*************** build_new_1 (tree placement, tree type,
*** 2055,2065 ****
return rval;
}
! /* While we're working, use a pointer to the type we've actually
! allocated. Store the result of the call in a variable so that we
! can use it more than once. */
! full_pointer_type = build_pointer_type (full_type);
! alloc_expr = get_target_expr (build_nop (full_pointer_type, alloc_call));
alloc_node = TARGET_EXPR_SLOT (alloc_expr);
/* Strip any COMPOUND_EXPRs from ALLOC_CALL. */
--- 2055,2063 ----
return rval;
}
! /* Store the result of the allocation call in a variable so that we can
! use it more than once. */
! alloc_expr = get_target_expr (alloc_call);
alloc_node = TARGET_EXPR_SLOT (alloc_expr);
/* Strip any COMPOUND_EXPRs from ALLOC_CALL. */
*************** build_new_1 (tree placement, tree type,
*** 2111,2126 ****
tree size_ptr_type;
/* Adjust so we're pointing to the start of the object. */
! data_addr = get_target_expr (build2 (POINTER_PLUS_EXPR, full_pointer_type,
! alloc_node, cookie_size));
/* Store the number of bytes allocated so that we can know how
many elements to destroy later. We use the last sizeof
(size_t) bytes to store the number of elements. */
! cookie_ptr = fold_build1 (NEGATE_EXPR, sizetype, size_in_bytes (sizetype));
size_ptr_type = build_pointer_type (sizetype);
! cookie_ptr = build2 (POINTER_PLUS_EXPR, size_ptr_type,
! fold_convert (size_ptr_type, data_addr), cookie_ptr);
cookie = cp_build_indirect_ref (cookie_ptr, NULL, complain);
cookie_expr = build2 (MODIFY_EXPR, sizetype, cookie, nelts);
--- 2109,2125 ----
tree size_ptr_type;
/* Adjust so we're pointing to the start of the object. */
! data_addr = build2 (POINTER_PLUS_EXPR, TREE_TYPE (alloc_node),
! alloc_node, cookie_size);
/* Store the number of bytes allocated so that we can know how
many elements to destroy later. We use the last sizeof
(size_t) bytes to store the number of elements. */
! cookie_ptr = size_binop (MINUS_EXPR, cookie_size, size_in_bytes (sizetype));
! cookie_ptr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (alloc_node),
! alloc_node, cookie_ptr);
size_ptr_type = build_pointer_type (sizetype);
! cookie_ptr = fold_convert (size_ptr_type, cookie_ptr);
cookie = cp_build_indirect_ref (cookie_ptr, NULL, complain);
cookie_expr = build2 (MODIFY_EXPR, sizetype, cookie, nelts);
*************** build_new_1 (tree placement, tree type,
*** 2134,2144 ****
cookie = cp_build_indirect_ref (cookie_ptr, NULL, complain);
cookie = build2 (MODIFY_EXPR, sizetype, cookie,
! size_in_bytes(elt_type));
cookie_expr = build2 (COMPOUND_EXPR, TREE_TYPE (cookie_expr),
cookie, cookie_expr);
}
- data_addr = TARGET_EXPR_SLOT (data_addr);
}
else
{
--- 2133,2142 ----
cookie = cp_build_indirect_ref (cookie_ptr, NULL, complain);
cookie = build2 (MODIFY_EXPR, sizetype, cookie,
! size_in_bytes (elt_type));
cookie_expr = build2 (COMPOUND_EXPR, TREE_TYPE (cookie_expr),
cookie, cookie_expr);
}
}
else
{
*************** build_new_1 (tree placement, tree type,
*** 2146,2151 ****
--- 2144,2153 ----
data_addr = alloc_node;
}
+ /* Now use a pointer to the type we've actually allocated. */
+ full_pointer_type = build_pointer_type (full_type);
+ data_addr = fold_convert (full_pointer_type, data_addr);
+
/* Now initialize the allocated object. Note that we preevaluate the
initialization expression, apart from the actual constructor call or
assignment--we do this because we want to delay the allocation as long
*************** build_new_1 (tree placement, tree type,
*** 2241,2251 ****
/* The Standard is unclear here, but the right thing to do
is to use the same method for finding deallocation
functions that we use for finding allocation functions. */
! cleanup = build_op_delete_call (dcode, alloc_node, size,
! globally_qualified_p,
! (placement_allocation_fn_p
! ? alloc_call : NULL_TREE),
! alloc_fn);
if (!cleanup)
/* We're done. */;
--- 2243,2255 ----
/* The Standard is unclear here, but the right thing to do
is to use the same method for finding deallocation
functions that we use for finding allocation functions. */
! cleanup = (build_op_delete_call
! (dcode,
! fold_convert (full_pointer_type, alloc_node),
! size,
! globally_qualified_p,
! placement_allocation_fn_p ? alloc_call : NULL_TREE,
! alloc_fn));
if (!cleanup)
/* We're done. */;
*************** build_new_1 (tree placement, tree type,
*** 2300,2306 ****
if (cookie_expr)
rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
! if (rval == alloc_node)
/* If we don't have an initializer or a cookie, strip the TARGET_EXPR
and return the call (which doesn't need to be adjusted). */
rval = TARGET_EXPR_INITIAL (alloc_expr);
--- 2304,2310 ----
if (cookie_expr)
rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
! if (rval == data_addr)
/* If we don't have an initializer or a cookie, strip the TARGET_EXPR
and return the call (which doesn't need to be adjusted). */
rval = TARGET_EXPR_INITIAL (alloc_expr);
Index: testsuite/g++.dg/tree-ssa/new1.C
===================================================================
*** testsuite/g++.dg/tree-ssa/new1.C (revision 0)
--- testsuite/g++.dg/tree-ssa/new1.C (revision 0)
***************
*** 0 ****
--- 1,42 ----
+ // PR c++/36633
+
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -Wall -fdump-tree-forwprop1" } */
+ // No particular reason for choosing forwprop1 dump to look at.
+
+ struct B { ~B() {} };
+ struct D : public B {};
+ //struct D {};
+
+ struct my_deleter
+ {
+ void operator()(D * d)
+ {
+ // delete [] d;
+ }
+ };
+
+ struct smart_ptr
+ {
+ smart_ptr(D * ptr) : p(ptr) { }
+ ~smart_ptr() { d(p); }
+ D * p;
+ my_deleter d;
+ };
+
+ int
+ test01()
+ {
+ smart_ptr p(new D[7]);
+
+ return 0;
+ }
+
+ int main()
+ {
+ test01();
+ return 0;
+ }
+
+ /* { dg-final { scan-tree-dump-not "= .* \\+ -" "forwprop1" } } */
+ /* { dg-final { cleanup-tree-dump "forwprop1" } } */