aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/call.c14
-rw-r--r--gcc/cp/init.c56
-rw-r--r--gcc/testsuite/g++.dg/init/placement2.C19
4 files changed, 71 insertions, 24 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5a5dc78..e143dea 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+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.
+
2003-11-16 Jason Merrill <jason@redhat.com>
* Make-lang.in (c++.tags): Create TAGS.sub files in each directory
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 07622ab..354eb8b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3824,10 +3824,6 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
/* 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);
@@ -3910,7 +3906,15 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
args = tree_cons (NULL_TREE, addr,
build_tree_list (NULL_TREE, size));
- return build_function_call (fn, args);
+ 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
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 7352153..332c518 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2060,13 +2060,22 @@ build_new_1 (tree exp)
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);
+ /* 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
@@ -2083,6 +2092,27 @@ build_new_1 (tree exp)
= (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_,
@@ -2096,18 +2126,6 @@ build_new_1 (tree exp)
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;
diff --git a/gcc/testsuite/g++.dg/init/placement2.C b/gcc/testsuite/g++.dg/init/placement2.C
new file mode 100644
index 0000000..bca7415
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/placement2.C
@@ -0,0 +1,19 @@
+// { dg-do run }
+
+void* operator new (unsigned int sz, void*) { return operator new (sz); }
+void operator delete (void* p, void*) { operator delete (p); }
+
+struct A { A() { throw 1; } };
+
+int c;
+void *f() { ++c; return 0; }
+
+int main()
+{
+ try
+ {
+ new (f()) A;
+ }
+ catch (...) {}
+ return c != 1;
+}