This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++] PATCH to avoid reevaluation of new placement args
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 17 Nov 2003 14:37:16 -0500
- Subject: [C++] PATCH to avoid reevaluation of new placement args
While looking at PR 11266, I noticed that any side-effects in a new
placement argument are evaluated again if we call placement delete. The
standard is not entirely clear on this point, but I think this is wrong,
and the EDG compiler agrees with me.
Tested x86_64-pc-linux-gnu, applied to trunk. Test in
g++.dg/init/placement2.C.
2003-11-17 Jason Merrill <jason@redhat.com>
* init.c (build_new_1): Preevaluate placement args.
* call.c (build_op_delete_call): Don't expose placement args to
overload resolution.
*** call.c.~1~ 2003-11-17 11:51:48.000000000 -0500
--- call.c 2003-11-17 13:22:09.000000000 -0500
*************** build_op_delete_call (enum tree_code cod
*** 3824,3833 ****
/* Find the allocation function that is being called. */
call_expr = placement;
- /* Sometimes we have a COMPOUND_EXPR, rather than a simple
- CALL_EXPR. */
- while (TREE_CODE (call_expr) == COMPOUND_EXPR)
- call_expr = TREE_OPERAND (call_expr, 1);
/* Extract the function. */
alloc_fn = get_callee_fndecl (call_expr);
my_friendly_assert (alloc_fn != NULL_TREE, 20020327);
--- 3824,3829 ----
*************** build_op_delete_call (enum tree_code cod
*** 3910,3916 ****
args = tree_cons (NULL_TREE, addr,
build_tree_list (NULL_TREE, size));
! return build_function_call (fn, args);
}
/* If we are doing placement delete we do nothing if we don't find a
--- 3906,3920 ----
args = tree_cons (NULL_TREE, addr,
build_tree_list (NULL_TREE, size));
! if (placement)
! {
! /* The placement args might not be suitable for overload
! resolution at this point, so build the call directly. */
! mark_used (fn);
! return build_cxx_call (fn, args, args);
! }
! else
! return build_function_call (fn, args);
}
/* If we are doing placement delete we do nothing if we don't find a
*** init.c.~1~ 2003-11-03 16:39:12.000000000 -0500
--- init.c 2003-11-17 13:24:07.000000000 -0500
*************** build_new_1 (tree exp)
*** 2060,2072 ****
if (alloc_call == error_mark_node)
return error_mark_node;
! /* The ALLOC_CALL should be a CALL_EXPR -- or a COMPOUND_EXPR whose
! right-hand-side is ultimately a CALL_EXPR -- and the first
! operand should be the address of a known FUNCTION_DECL. */
! t = alloc_call;
! while (TREE_CODE (t) == COMPOUND_EXPR)
! t = TREE_OPERAND (t, 1);
! alloc_fn = get_callee_fndecl (t);
my_friendly_assert (alloc_fn != NULL_TREE, 20020325);
/* Now, check to see if this function is actually a placement
--- 2060,2081 ----
if (alloc_call == error_mark_node)
return error_mark_node;
! /* In the simple case, we can stop now. */
! pointer_type = build_pointer_type (type);
! if (!cookie_size && !is_initialized)
! return build_nop (pointer_type, alloc_call);
!
! /* 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. */
! while (TREE_CODE (alloc_call) == COMPOUND_EXPR)
! alloc_call = TREE_OPERAND (alloc_call, 1);
! alloc_fn = get_callee_fndecl (alloc_call);
my_friendly_assert (alloc_fn != NULL_TREE, 20020325);
/* Now, check to see if this function is actually a placement
*************** build_new_1 (tree exp)
*** 2083,2088 ****
--- 2092,2118 ----
= (type_num_arguments (TREE_TYPE (alloc_fn)) > 1
|| varargs_function_p (alloc_fn));
+ /* Preevaluate the placement args so that we don't reevaluate them for a
+ placement delete. */
+ if (placement_allocation_fn_p)
+ {
+ tree inits = NULL_TREE;
+ t = TREE_CHAIN (TREE_OPERAND (alloc_call, 1));
+ for (; t; t = TREE_CHAIN (t))
+ if (TREE_SIDE_EFFECTS (TREE_VALUE (t)))
+ {
+ tree init;
+ TREE_VALUE (t) = stabilize_expr (TREE_VALUE (t), &init);
+ if (inits)
+ inits = build (COMPOUND_EXPR, void_type_node, inits, init);
+ else
+ inits = init;
+ }
+ if (inits)
+ alloc_expr = build (COMPOUND_EXPR, TREE_TYPE (alloc_expr), inits,
+ alloc_expr);
+ }
+
/* unless an allocation function is declared with an empty excep-
tion-specification (_except.spec_), throw(), it indicates failure to
allocate storage by throwing a bad_alloc exception (clause _except_,
*************** build_new_1 (tree exp)
*** 2096,2113 ****
nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
check_new = (flag_check_new || nothrow) && ! use_java_new;
- /* In the simple case, we can stop now. */
- pointer_type = build_pointer_type (type);
- if (!cookie_size && !is_initialized)
- return build_nop (pointer_type, alloc_call);
-
- /* 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);
-
if (cookie_size)
{
tree cookie;
--- 2126,2131 ----