aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@yorick.cygnus.com>1997-11-15 08:36:38 +0000
committerJason Merrill <jason@gcc.gnu.org>1997-11-15 03:36:38 -0500
commitda4768fe2e67468b4e4b321f07aa0c57836654b6 (patch)
treeaa307cb343792fb4339282298c362fcbc97b48dc
parentdf4791b95d453db88e1db9ffb9315b6fa00d69f6 (diff)
downloadgcc-da4768fe2e67468b4e4b321f07aa0c57836654b6.zip
gcc-da4768fe2e67468b4e4b321f07aa0c57836654b6.tar.gz
gcc-da4768fe2e67468b4e4b321f07aa0c57836654b6.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog12
-rw-r--r--gcc/cp/call.c141
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/decl2.c11
-rw-r--r--gcc/cp/init.c76
5 files changed, 187 insertions, 55 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a94f587..0349d52 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c0fdef1..ed40a07 100644
--- a/gcc/cp/call.c
+++ b/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;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b931a5c..47b9fe6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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));
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index dfe31c2..9ee0287 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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;
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index c1df1d9..c5604e1 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -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.