+2001-05-21 Mark Mitchell <mark@codesourcery.com>
+
+ * call.c (build_op_delete_call): Ignore exception-specifications
+ when looking for matching delete operators.
+ * init.c (build_new_1): Compute whether or not the allocation
+ function used is a placement allocation function or not, and
+ communicate this information to build_op_delete_call.
+
2001-05-21 Jason Merrill <jason_merrill@redhat.com>
* class.c (build_vtable_entry_ref): Lose vtbl parm. Fix for new abi.
used to determine what the corresponding new looked like.
SIZE is the size of the memory block to be deleted.
FLAGS are the usual overloading flags.
- PLACEMENT is the corresponding placement new call, or 0. */
+ PLACEMENT is the corresponding placement new call, or NULL_TREE. */
tree
build_op_delete_call (code, addr, size, flags, placement)
argtypes = tree_cons (NULL_TREE, ptr_type_node,
tree_cons (NULL_TREE, sizetype,
void_list_node));
-
fntype = build_function_type (void_type_node, argtypes);
- fn = instantiate_type (fntype, fns, itf_no_attributes);
- if (fn != error_mark_node)
+ /* Go through the `operator delete' functions looking for one
+ with a matching type. */
+ for (fn = BASELINK_P (fns) ? TREE_VALUE (fns) : fns;
+ fn;
+ fn = OVL_NEXT (fn))
{
- /* Member functions. */
- if (BASELINK_P (fns))
- enforce_access (type, fn);
-
- if (pass == 0)
- args = tree_cons (NULL_TREE, addr, args);
- else
- args = tree_cons (NULL_TREE, addr,
- build_tree_list (NULL_TREE, size));
- return build_function_call (fn, args);
+ tree t;
+
+ /* Exception specifications on the `delete' operator do not
+ matter. */
+ t = build_exception_variant (TREE_TYPE (OVL_CURRENT (fn)),
+ NULL_TREE);
+ /* We also don't compare attributes. We're really just
+ trying to check the types of the first two parameters. */
+ if (comptypes (t, fntype, COMPARE_NO_ATTRIBUTES))
+ break;
}
+
+ /* If we found a match, we're done. */
+ if (fn)
+ break;
+ }
+
+ /* If we have a matching function, call it. */
+ if (fn)
+ {
+ /* Make sure we have the actual function, and not an
+ OVERLOAD. */
+ fn = OVL_CURRENT (fn);
+
+ /* If the FN is a member function, make sure that it is
+ accessible. */
+ if (DECL_CLASS_SCOPE_P (fn))
+ enforce_access (type, fn);
+
+ if (pass == 0)
+ args = tree_cons (NULL_TREE, addr, args);
+ else
+ 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
beginning of the storage allocated for an array-new expression in
order to store the number of elements. */
tree cookie_size = NULL_TREE;
+ /* True if the function we are calling is a placement allocation
+ function. */
+ bool placement_allocation_fn_p;
placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1);
if (alloc_call == error_mark_node)
return error_mark_node;
- if (alloc_call == NULL_TREE)
- abort ();
+ /* The ALLOC_CALL should be a CALL_EXPR, and the first operand
+ should be the address of a known FUNCTION_DECL. */
+ my_friendly_assert (TREE_CODE (alloc_call) == CALL_EXPR, 20000521);
+ t = TREE_OPERAND (alloc_call, 0);
+ my_friendly_assert (TREE_CODE (t) == ADDR_EXPR, 20000521);
+ t = TREE_OPERAND (t, 0);
+ my_friendly_assert (TREE_CODE (t) == FUNCTION_DECL, 20000521);
+ /* Now, check to see if this function is actually a placement
+ allocation function. This can happen even when PLACEMENT is NULL
+ because we might have something like:
+
+ struct S { void* operator new (size_t, int i = 0); };
+
+ A call to `new S' will get this allocation function, even though
+ there is no explicit placement argument. If there is more than
+ one argument, or there are variable arguments, then this is a
+ placement allocation function. */
+ placement_allocation_fn_p
+ = (type_num_arguments (TREE_TYPE (t)) > 1 || varargs_function_p (t));
/* unless an allocation function is declared with an empty excep-
tion-specification (_except.spec_), throw(), it indicates failure to
flags |= LOOKUP_SPECULATIVELY;
cleanup = build_op_delete_call (dcode, alloc_node, size, flags,
- alloc_call);
+ (placement_allocation_fn_p
+ ? alloc_call : NULL_TREE));
/* Ack! First we allocate the memory. Then we set our sentry
variable to true, and expand a cleanup that deletes the memory
--- /dev/null
+// Origin: philip_martin@ntlworld.com
+
+#include <new>
+
+extern "C" void abort();
+
+bool new_flag = false;
+bool delete_flag = false;
+
+struct X {
+ X()
+ {
+ throw 1;
+ }
+ void* operator new ( std::size_t n ) throw ( std::bad_alloc )
+ {
+ new_flag = true;
+ return ::operator new( n );
+ }
+ void operator delete( void* p, std::size_t n ) throw()
+ {
+ delete_flag = true;
+ ::operator delete( p );
+ }
+};
+
+int
+main()
+{
+ try
+ {
+ X* x = new X; // gcc 3.0 fails to call operator delete when X::X throws
+ }
+ catch ( ... )
+ {
+ }
+ if ( ! new_flag || ! delete_flag )
+ ::abort();
+}