call.c (build_new_op): Fix copy error.
* call.c (build_new_op): Fix copy error. (build_op_new_call): New fn. (build_op_delete_call): New fn. * cp-tree.h: Declare them. * init.c (build_new): Use them. Support placement delete. (build_x_delete): Use build_op_delete_call. (build_delete): Likewise. * decl2.c (delete_sanity): Likewise. (coerce_delete_type): Don't complain about placement delete. Support placement delete. From-SVN: r16501
This commit is contained in:
parent
df4791b95d
commit
da4768fe2e
@ -1,3 +1,15 @@
|
||||
Sat Nov 15 00:30:51 1997 Jason Merrill <jason@yorick.cygnus.com>
|
||||
|
||||
* call.c (build_new_op): Fix copy error.
|
||||
(build_op_new_call): New fn.
|
||||
(build_op_delete_call): New fn.
|
||||
* cp-tree.h: Declare them.
|
||||
* init.c (build_new): Use them. Support placement delete.
|
||||
(build_x_delete): Use build_op_delete_call.
|
||||
(build_delete): Likewise.
|
||||
* decl2.c (delete_sanity): Likewise.
|
||||
(coerce_delete_type): Don't complain about placement delete.
|
||||
|
||||
Thu Nov 13 01:52:36 1997 Jason Merrill <jason@yorick.cygnus.com>
|
||||
|
||||
* call.c (build_new_function_call): Remove unused 'obj' parm.
|
||||
|
141
gcc/cp/call.c
141
gcc/cp/call.c
@ -4861,8 +4861,8 @@ build_new_op (code, flags, arg1, arg2, arg3)
|
||||
templates = scratch_tree_cons (NULL_TREE, fn, templates);
|
||||
candidates
|
||||
= add_template_candidate (candidates, fn, NULL_TREE,
|
||||
this_arglist, TREE_TYPE
|
||||
(fnname), LOOKUP_NORMAL);
|
||||
this_arglist, TREE_TYPE (fnname),
|
||||
flags);
|
||||
}
|
||||
else
|
||||
candidates = add_function_candidate
|
||||
@ -5071,6 +5071,143 @@ builtin:
|
||||
}
|
||||
}
|
||||
|
||||
/* Build up a call to operator new. This has to be handled differently
|
||||
from other operators in the way lookup is handled; first members are
|
||||
considered, then globals. CODE is either NEW_EXPR or VEC_NEW_EXPR.
|
||||
TYPE is the type to be created. ARGS are any new-placement args.
|
||||
FLAGS are the usual overloading flags. */
|
||||
|
||||
tree
|
||||
build_op_new_call (code, type, args, flags)
|
||||
enum tree_code code;
|
||||
tree type, args;
|
||||
int flags;
|
||||
{
|
||||
tree fnname = ansi_opname[code];
|
||||
|
||||
if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL)
|
||||
&& (TYPE_GETS_NEW (type) & (1 << (code == VEC_NEW_EXPR))))
|
||||
{
|
||||
tree dummy = build1 (NOP_EXPR, build_pointer_type (type),
|
||||
error_mark_node);
|
||||
dummy = build_indirect_ref (dummy, "new");
|
||||
return build_method_call (dummy, fnname, args, NULL_TREE, flags);
|
||||
}
|
||||
else
|
||||
return build_new_function_call (lookup_name_nonclass (fnname), args);
|
||||
}
|
||||
|
||||
/* Build a call to operator delete. This has to be handled very specially,
|
||||
because the restrictions on what signatures match are different from all
|
||||
other call instances. For a normal delete, only a delete taking (void *)
|
||||
or (void *, size_t) is accepted. For a placement delete, only an exact
|
||||
match with the placement new is accepted.
|
||||
|
||||
CODE is either DELETE_EXPR or VEC_DELETE_EXPR.
|
||||
ADDR is the pointer to be deleted. For placement delete, it is also
|
||||
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. */
|
||||
|
||||
tree
|
||||
build_op_delete_call (code, addr, size, flags)
|
||||
enum tree_code code;
|
||||
tree addr, size;
|
||||
int flags;
|
||||
{
|
||||
tree fn, fns, fnname, fntype, argtypes, args, type;
|
||||
int placement;
|
||||
|
||||
if (addr == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
type = TREE_TYPE (TREE_TYPE (addr));
|
||||
fnname = ansi_opname[code];
|
||||
|
||||
if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL))
|
||||
/* Here we make assumptions about how instantiate_type works. This comes
|
||||
out as a simple TREE_LIST, so it looks like overloaded globals to
|
||||
instantiate_type; this works out fine. If something changes we
|
||||
might have to build this up like build_offset_ref does. */
|
||||
fns = lookup_fnfields (TYPE_BINFO (type), fnname, 0);
|
||||
else
|
||||
fns = NULL_TREE;
|
||||
|
||||
if (fns == NULL_TREE)
|
||||
fns = lookup_name_nonclass (fnname);
|
||||
|
||||
/* We can recognize a placement delete because of LOOKUP_SPECULATIVELY;
|
||||
if we are doing placement delete we do nothing if we don't find a
|
||||
matching op delete. */
|
||||
placement = !!(flags & LOOKUP_SPECULATIVELY);
|
||||
if (placement)
|
||||
{
|
||||
/* If placement, we are coming from build_new, and we know that addr
|
||||
is the allocation expression, so extract the info we need from it.
|
||||
Obviously, if the build_new process changes this may have to
|
||||
change as well. */
|
||||
/* The SAVE_EXPR. */
|
||||
tree t = TREE_OPERAND (addr, 0);
|
||||
/* The CALL_EXPR. */
|
||||
t = TREE_OPERAND (t, 0);
|
||||
/* The function. */
|
||||
argtypes = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
|
||||
/* The second parm type. */
|
||||
argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (argtypes)));
|
||||
/* The second argument. */
|
||||
args = TREE_CHAIN (TREE_OPERAND (t, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* First try it without the size argument. */
|
||||
argtypes = void_list_node;
|
||||
args = NULL_TREE;
|
||||
}
|
||||
|
||||
argtypes = tree_cons (NULL_TREE, ptr_type_node, argtypes);
|
||||
fntype = build_function_type (void_type_node, argtypes);
|
||||
|
||||
/* Strip const and volatile from addr. */
|
||||
if (type != TYPE_MAIN_VARIANT (type))
|
||||
addr = cp_convert (build_pointer_type (TYPE_MAIN_VARIANT (type)), addr);
|
||||
|
||||
/* instantiate_type will always return a plain function; pretend it's
|
||||
overloaded. */
|
||||
if (TREE_CODE (fns) == FUNCTION_DECL)
|
||||
fns = scratch_tree_cons (NULL_TREE, fns, NULL_TREE);
|
||||
|
||||
fn = instantiate_type (fntype, fns, 0);
|
||||
|
||||
if (fn != error_mark_node)
|
||||
{
|
||||
if (TREE_PURPOSE (fns))
|
||||
/* TREE_PURPOSE is only set for lists of member functions. */
|
||||
enforce_access (TREE_PURPOSE (fns), fn);
|
||||
return build_function_call (fn, expr_tree_cons (NULL_TREE, addr, args));
|
||||
}
|
||||
|
||||
if (placement)
|
||||
return NULL_TREE;
|
||||
|
||||
/* Normal delete; now try to find a match including the size argument. */
|
||||
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, 0);
|
||||
|
||||
if (fn != error_mark_node)
|
||||
return build_function_call
|
||||
(fn, expr_tree_cons (NULL_TREE, addr,
|
||||
build_expr_list (NULL_TREE, size)));
|
||||
|
||||
cp_error ("no suitable operator delete for `%T'", type);
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* If the current scope isn't allowed to access FUNCTION along
|
||||
BASETYPE_PATH, give an error. */
|
||||
|
||||
static void
|
||||
enforce_access (basetype_path, function)
|
||||
tree basetype_path, function;
|
||||
|
@ -1957,6 +1957,8 @@ extern tree type_decays_to PROTO((tree));
|
||||
extern tree build_user_type_conversion PROTO((tree, tree, int));
|
||||
extern tree build_new_function_call PROTO((tree, tree));
|
||||
extern tree build_new_op PROTO((enum tree_code, int, tree, tree, tree));
|
||||
extern tree build_op_new_call PROTO((enum tree_code, tree, tree, int));
|
||||
extern tree build_op_delete_call PROTO((enum tree_code, tree, tree, int));
|
||||
extern int can_convert PROTO((tree, tree));
|
||||
extern int can_convert_arg PROTO((tree, tree, tree));
|
||||
|
||||
|
@ -1310,8 +1310,8 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
|
||||
{
|
||||
/* Only do access checking here; we'll be calling op delete
|
||||
from the destructor. */
|
||||
tree tmp = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, t,
|
||||
size_zero_node, NULL_TREE);
|
||||
tree tmp = build_op_delete_call (DELETE_EXPR, t,
|
||||
size_zero_node, LOOKUP_NORMAL);
|
||||
if (tmp == error_mark_node)
|
||||
return error_mark_node;
|
||||
}
|
||||
@ -2403,6 +2403,7 @@ coerce_delete_type (type)
|
||||
|| TREE_VALUE (arg_types) != ptr_type_node)
|
||||
e2 = 1, error ("`operator delete' takes type `void *' as first parameter");
|
||||
|
||||
#if 0
|
||||
if (arg_types
|
||||
&& TREE_CHAIN (arg_types)
|
||||
&& TREE_CHAIN (arg_types) != void_list_node)
|
||||
@ -2434,8 +2435,12 @@ coerce_delete_type (type)
|
||||
arg_types = tree_cons (NULL_TREE, ptr_type_node, TREE_CHAIN (arg_types));
|
||||
}
|
||||
else e3 |= e1;
|
||||
#endif
|
||||
|
||||
if (e3)
|
||||
if (e2)
|
||||
arg_types = tree_cons (NULL_TREE, ptr_type_node,
|
||||
arg_types ? TREE_CHAIN (arg_types): NULL_TREE);
|
||||
if (e2 || e1)
|
||||
type = build_function_type (void_type_node, arg_types);
|
||||
|
||||
return type;
|
||||
|
@ -2493,18 +2493,9 @@ build_new (placement, decl, init, use_global_new)
|
||||
}
|
||||
|
||||
/* Allocate the object. */
|
||||
if (! use_global_new && TYPE_LANG_SPECIFIC (true_type)
|
||||
&& (TYPE_GETS_NEW (true_type) & (1 << has_array)))
|
||||
rval = build_opfncall (code, LOOKUP_NORMAL,
|
||||
build_pointer_type (true_type), size, placement);
|
||||
else if (placement)
|
||||
{
|
||||
rval = build_opfncall (code, LOOKUP_GLOBAL|LOOKUP_COMPLAIN,
|
||||
ptr_type_node, size, placement);
|
||||
rval = cp_convert (build_pointer_type (true_type), rval);
|
||||
}
|
||||
else if (! has_array && flag_this_is_variable > 0
|
||||
&& TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
|
||||
|
||||
if (! has_array && ! placement && flag_this_is_variable > 0
|
||||
&& TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
|
||||
{
|
||||
if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST)
|
||||
rval = NULL_TREE;
|
||||
@ -2516,10 +2507,10 @@ build_new (placement, decl, init, use_global_new)
|
||||
}
|
||||
else
|
||||
{
|
||||
rval = build_builtin_call (build_pointer_type (true_type),
|
||||
has_array ? BIVN : BIN,
|
||||
build_expr_list (NULL_TREE, size));
|
||||
TREE_CALLS_NEW (rval) = 1;
|
||||
rval = build_op_new_call
|
||||
(code, true_type, expr_tree_cons (NULL_TREE, size, placement),
|
||||
LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL));
|
||||
rval = cp_convert (build_pointer_type (true_type), rval);
|
||||
}
|
||||
|
||||
if (flag_exceptions && rval)
|
||||
@ -2719,27 +2710,27 @@ build_new (placement, decl, init, use_global_new)
|
||||
an exception and the new-expression does not contain a
|
||||
new-placement, then the deallocation function is called to free
|
||||
the memory in which the object was being constructed. */
|
||||
/* FIXME: handle placement delete. */
|
||||
if (flag_exceptions && ! placement)
|
||||
if (flag_exceptions && alloc_expr)
|
||||
{
|
||||
tree cleanup = alloc_expr;
|
||||
enum tree_code dcode = has_array? VEC_DELETE_EXPR : DELETE_EXPR;
|
||||
tree cleanup, args = NULL_TREE;
|
||||
int flags = LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL);
|
||||
|
||||
/* All cleanups must last longer than normal. */
|
||||
int yes = suspend_momentary ();
|
||||
|
||||
if (! use_global_new && TYPE_LANG_SPECIFIC (true_type)
|
||||
&& (TYPE_GETS_DELETE (true_type) & (1 << has_array)))
|
||||
cleanup = build_opfncall (has_array? VEC_DELETE_EXPR : DELETE_EXPR,
|
||||
LOOKUP_NORMAL, cleanup, size, NULL_TREE);
|
||||
else
|
||||
cleanup = build_builtin_call
|
||||
(void_type_node, has_array ? BIVD : BID,
|
||||
build_expr_list (NULL_TREE, cleanup));
|
||||
if (placement)
|
||||
flags |= LOOKUP_SPECULATIVELY;
|
||||
|
||||
cleanup = build_op_delete_call (dcode, alloc_expr, size, flags);
|
||||
|
||||
resume_momentary (yes);
|
||||
|
||||
rval = build (TRY_CATCH_EXPR, TREE_TYPE (rval), rval, cleanup);
|
||||
rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
|
||||
|
||||
if (cleanup)
|
||||
{
|
||||
rval = build (TRY_CATCH_EXPR, TREE_TYPE (rval), rval, cleanup);
|
||||
rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (TYPE_READONLY (true_type))
|
||||
@ -3196,16 +3187,10 @@ build_x_delete (type, addr, which_delete, virtual_size)
|
||||
{
|
||||
int use_global_delete = which_delete & 1;
|
||||
int use_vec_delete = !!(which_delete & 2);
|
||||
tree rval;
|
||||
enum tree_code code = use_vec_delete ? VEC_DELETE_EXPR : DELETE_EXPR;
|
||||
int flags = LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL);
|
||||
|
||||
if (! use_global_delete && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
|
||||
&& (TYPE_GETS_DELETE (TREE_TYPE (type)) & (1 << use_vec_delete)))
|
||||
rval = build_opfncall (code, LOOKUP_NORMAL, addr, virtual_size, NULL_TREE);
|
||||
else
|
||||
rval = build_builtin_call (void_type_node, use_vec_delete ? BIVD : BID,
|
||||
build_expr_list (NULL_TREE, addr));
|
||||
return rval;
|
||||
return build_op_delete_call (code, addr, virtual_size, flags);
|
||||
}
|
||||
|
||||
/* Generate a call to a destructor. TYPE is the type to cast ADDR to.
|
||||
@ -3302,18 +3287,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
|
||||
if (auto_delete == integer_zero_node)
|
||||
return void_zero_node;
|
||||
|
||||
/* Pass the size of the object down to the operator delete() in
|
||||
addition to the ADDR. */
|
||||
if (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
|
||||
{
|
||||
tree virtual_size = c_sizeof_nowarn (type);
|
||||
return build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
|
||||
virtual_size, NULL_TREE);
|
||||
}
|
||||
|
||||
/* Call the builtin operator delete. */
|
||||
return build_builtin_call (void_type_node, BID,
|
||||
build_expr_list (NULL_TREE, addr));
|
||||
return build_op_delete_call
|
||||
(DELETE_EXPR, addr, c_sizeof_nowarn (type),
|
||||
LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL));
|
||||
}
|
||||
|
||||
/* Below, we will reverse the order in which these calls are made.
|
||||
|
Loading…
Reference in New Issue
Block a user