From da4768fe2e67468b4e4b321f07aa0c57836654b6 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 15 Nov 1997 08:36:38 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 12 ++++ gcc/cp/call.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++- gcc/cp/cp-tree.h | 2 + gcc/cp/decl2.c | 11 +++- gcc/cp/init.c | 76 +++++++++---------------- 5 files changed, 187 insertions(+), 55 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a94f58714b3..0349d52a92e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +Sat Nov 15 00:30:51 1997 Jason Merrill + + * 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 * call.c (build_new_function_call): Remove unused 'obj' parm. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c0fdef1d762..ed40a073452 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 b931a5cd21b..47b9fe6062e 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 dfe31c29923..9ee0287c954 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 c1df1d978f5..c5604e14681 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. -- 2.30.2