aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2000-12-15 11:36:00 -0500
committerJason Merrill <jason@gcc.gnu.org>2000-12-15 11:36:00 -0500
commit967900711fa76f74c368bb49c4d78f8485e0cade (patch)
tree87be15c6f6d845e4752baddab8c1fb21ccb8c50c /gcc
parent8d42565b847d588e6c04e9c3cd5a3157859e2c6a (diff)
downloadgcc-967900711fa76f74c368bb49c4d78f8485e0cade.zip
gcc-967900711fa76f74c368bb49c4d78f8485e0cade.tar.gz
gcc-967900711fa76f74c368bb49c4d78f8485e0cade.tar.bz2
* init.c (build_new_1): Reorganize. Now with 100% fewer SAVE_EXPRs!
From-SVN: r38292
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog2
-rw-r--r--gcc/cp/init.c263
2 files changed, 121 insertions, 144 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index d92e24e..a59a835 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,7 @@
2000-12-15 Jason Merrill <jason@redhat.com>
+ * init.c (build_new_1): Reorganize. Now with 100% fewer SAVE_EXPRs!
+
* init.c (build_new_1): Don't strip quals from type.
* decl.c (pushdecl): Don't check for linkage on a non-decl.
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 7a2ce18..023c834 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2236,9 +2236,10 @@ build_new_1 (exp)
tree exp;
{
tree placement, init;
- tree type, true_type, size, rval;
+ tree type, true_type, size, rval, t;
tree nelts = NULL_TREE;
- tree alloc_expr, alloc_node = NULL_TREE;
+ tree alloc_call, alloc_expr, alloc_node;
+ tree cookie_expr, init_expr;
int has_array = 0;
enum tree_code code;
int use_cookie, nothrow, check_new;
@@ -2280,11 +2281,9 @@ build_new_1 (exp)
if (!complete_type_or_else (true_type, exp))
return error_mark_node;
+ size = size_in_bytes (true_type);
if (has_array)
- size = fold (cp_build_binary_op (MULT_EXPR, size_in_bytes (true_type),
- nelts));
- else
- size = size_in_bytes (type);
+ size = fold (cp_build_binary_op (MULT_EXPR, size, nelts));
if (TREE_CODE (true_type) == VOID_TYPE)
{
@@ -2299,8 +2298,9 @@ build_new_1 (exp)
new. */
if (!globally_qualified_p
&& IS_AGGR_TYPE (true_type)
- && ((!has_array && TYPE_HAS_NEW_OPERATOR (true_type))
- || (has_array && TYPE_HAS_ARRAY_NEW_OPERATOR (true_type))))
+ && (has_array
+ ? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
+ : TYPE_HAS_NEW_OPERATOR (true_type)))
use_global_new = 0;
else
use_global_new = 1;
@@ -2330,9 +2330,6 @@ build_new_1 (exp)
size = size_binop (PLUS_EXPR, size, cookie_size);
}
- if (has_array && init && pedantic)
- cp_pedwarn ("initialization in array new");
-
/* Allocate the object. */
if (! placement && TYPE_FOR_JAVA (true_type))
@@ -2346,11 +2343,10 @@ build_new_1 (exp)
if (alloc_decl == NULL_TREE)
fatal("call to Java constructor, while `%s' undefined", alloc_name);
class_addr = build1 (ADDR_EXPR, jclass_node, class_decl);
- rval = build_function_call (alloc_decl,
- tree_cons (NULL_TREE, class_addr,
- build_tree_list (NULL_TREE,
- class_size)));
- rval = cp_convert (build_pointer_type (true_type), rval);
+ alloc_call = (build_function_call
+ (alloc_decl,
+ tree_cons (NULL_TREE, class_addr,
+ build_tree_list (NULL_TREE, class_size))));
}
else
{
@@ -2361,19 +2357,21 @@ build_new_1 (exp)
fnname = ansi_opname (code);
if (use_global_new)
- rval = (build_new_function_call
- (lookup_function_nonclass (fnname, args),
- args));
+ alloc_call = (build_new_function_call
+ (lookup_function_nonclass (fnname, args),
+ args));
else
- rval = build_method_call (build_dummy_object (true_type),
- fnname, args, NULL_TREE,
- LOOKUP_NORMAL);
- rval = cp_convert (build_pointer_type (true_type), rval);
+ alloc_call = build_method_call (build_dummy_object (true_type),
+ fnname, args, NULL_TREE,
+ LOOKUP_NORMAL);
}
- if (rval == error_mark_node)
+ if (alloc_call == error_mark_node)
return error_mark_node;
+ if (alloc_call == NULL_TREE)
+ abort ();
+
/* 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_,
@@ -2384,74 +2382,56 @@ build_new_1 (exp)
So check for a null exception spec on the op new we just called. */
- nothrow = 0;
- if (rval)
- {
- /* The CALL_EXPR. */
- tree t = TREE_OPERAND (rval, 0);
- /* The function. */
- t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
- nothrow = TYPE_NOTHROW_P (TREE_TYPE (t));
- }
+ /* The ADDR_EXPR. */
+ t = TREE_OPERAND (alloc_call, 0);
+ /* The function. */
+ t = TREE_OPERAND (t, 0);
+ nothrow = TYPE_NOTHROW_P (TREE_TYPE (t));
check_new = (flag_check_new || nothrow) && ! use_java_new;
- if ((check_new || flag_exceptions) && rval)
- {
- alloc_expr = get_target_expr (rval);
- alloc_node = rval = TREE_OPERAND (alloc_expr, 0);
- }
- else
- alloc_expr = NULL_TREE;
+ alloc_expr = alloc_call;
+
+ if (use_cookie)
+ /* Adjust so we're pointing to the start of the object. */
+ alloc_expr = build (PLUS_EXPR, TREE_TYPE (alloc_expr),
+ alloc_expr, cookie_size);
+ alloc_expr = convert (build_pointer_type (type), alloc_expr);
+
+ /* Now save the allocation expression so we only evaluate it once. */
+ alloc_expr = get_target_expr (alloc_expr);
+ alloc_node = TREE_OPERAND (alloc_expr, 0);
- /* if rval is NULL_TREE I don't have to allocate it, but are we
- totally sure we have some extra bytes in that case for the
- cookies? And how does that interact with the code below? (mrs) */
- /* Finish up some magic for new'ed arrays */
- if (use_cookie && rval != NULL_TREE)
+ /* Now initialize the cookie. */
+ if (use_cookie)
{
- tree cookie, exp1;
- rval = convert (string_type_node, rval); /* for ptr arithmetic */
- rval = save_expr (cp_build_binary_op (PLUS_EXPR, rval, cookie_size));
+ tree cookie;
+
/* Store the number of bytes allocated so that we can know how
many elements to destroy later. */
if (flag_new_abi)
{
/* Under the new ABI, we use the last sizeof (size_t) bytes
to store the number of elements. */
- cookie = build_indirect_ref (build (MINUS_EXPR,
- build_pointer_type (sizetype),
- rval,
- size_in_bytes (sizetype)),
- NULL_PTR);
- exp1 = build (MODIFY_EXPR, void_type_node, cookie, nelts);
+ cookie = build (MINUS_EXPR, build_pointer_type (sizetype),
+ alloc_node, size_in_bytes (sizetype));
+ cookie = build_indirect_ref (cookie, NULL_PTR);
}
else
{
- cookie
- = build_indirect_ref (build (MINUS_EXPR,
- build_pointer_type (BI_header_type),
- rval, cookie_size), NULL_PTR);
- exp1 = build (MODIFY_EXPR, void_type_node,
- build_component_ref (cookie, nelts_identifier,
- NULL_TREE, 0),
- nelts);
+ cookie = build (MINUS_EXPR, build_pointer_type (BI_header_type),
+ alloc_node, cookie_size);
+ cookie = build_indirect_ref (cookie, NULL_PTR);
+ cookie = build_component_ref (cookie, nelts_identifier,
+ NULL_TREE, 0);
}
-
- /* Build `(cookie = nelts, rval)' and use that as the complete
- expression. */
- rval = cp_convert (build_pointer_type (true_type), rval);
- rval = build_compound_expr
- (tree_cons (NULL_TREE, exp1,
- build_tree_list (NULL_TREE, rval)));
+ cookie_expr = build (MODIFY_EXPR, void_type_node, cookie, nelts);
+ TREE_SIDE_EFFECTS (cookie_expr) = 1;
}
+ else
+ cookie_expr = NULL_TREE;
- if (rval == error_mark_node)
- return error_mark_node;
-
- /* Don't call any constructors or do any initialization. */
- if (init == void_type_node)
- goto done;
-
+ /* Now initialize the allocated object. */
+ init_expr = NULL_TREE;
if (TYPE_NEEDS_CONSTRUCTING (type) || init)
{
if (! TYPE_NEEDS_CONSTRUCTING (type)
@@ -2462,11 +2442,7 @@ build_new_1 (exp)
tree deref;
tree deref_type;
- /* At present RVAL is a temporary variable, created to hold
- the value from the call to `operator new'. We transform
- it to (*RVAL = INIT, RVAL). */
- rval = save_expr (rval);
- deref = build_indirect_ref (rval, NULL_PTR);
+ deref = build_indirect_ref (alloc_node, NULL_PTR);
/* Even for something like `new const int (10)' we must
allow the expression to be non-const while we do the
@@ -2480,54 +2456,48 @@ build_new_1 (exp)
TREE_READONLY (deref) = 0;
if (TREE_CHAIN (init) != NULL_TREE)
- pedwarn ("initializer list being treated as compound expression");
+ pedwarn
+ ("initializer list being treated as compound expression");
else if (TREE_CODE (init) == CONSTRUCTOR)
{
- pedwarn ("initializer list appears where operand should be used");
+ pedwarn
+ ("initializer list appears where operand should be used");
init = TREE_OPERAND (init, 1);
}
init = build_compound_expr (init);
init = convert_for_initialization (deref, type, init, LOOKUP_NORMAL,
"new", NULL_TREE, 0);
- rval = build (COMPOUND_EXPR, TREE_TYPE (rval),
- build_modify_expr (deref, NOP_EXPR, init),
- rval);
- TREE_NO_UNUSED_WARNING (rval) = 1;
- TREE_SIDE_EFFECTS (rval) = 1;
+ init_expr = build_modify_expr (deref, NOP_EXPR, init);
}
else if (! has_array)
{
- tree newrval;
/* Constructors are never virtual. If it has an initialization, we
need to complain if we aren't allowed to use the ctor that took
that argument. */
int flags = LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_COMPLAIN;
- rval = save_expr (rval);
- newrval = rval;
-
- if (newrval && TREE_CODE (TREE_TYPE (newrval)) == POINTER_TYPE)
- newrval = build_indirect_ref (newrval, NULL_PTR);
-
- newrval = build_method_call (newrval,
- complete_ctor_identifier,
- init, TYPE_BINFO (true_type), flags);
-
- if (newrval == NULL_TREE || newrval == error_mark_node)
- return error_mark_node;
+ init_expr = build_indirect_ref (alloc_node, NULL_PTR);
- newrval = build (COMPOUND_EXPR, TREE_TYPE (rval), newrval, rval);
- rval = newrval;
- TREE_HAS_CONSTRUCTOR (rval) = 1;
+ init_expr = build_method_call (init_expr,
+ complete_ctor_identifier,
+ init, TYPE_BINFO (true_type), flags);
}
else
- rval = (build_vec_init
- (NULL_TREE,
- save_expr (rval),
- cp_build_binary_op (MINUS_EXPR, nelts, integer_one_node),
- init,
- /*from_array=*/0));
+ {
+ if (init && pedantic)
+ cp_pedwarn ("initialization in array new");
+
+ init_expr = convert (build_pointer_type (true_type), alloc_node);
+ init_expr = (build_vec_init
+ (NULL_TREE, init_expr,
+ cp_build_binary_op (MINUS_EXPR, nelts,
+ integer_one_node),
+ init, /*from_array=*/0));
+ }
+
+ if (init_expr == error_mark_node)
+ return error_mark_node;
/* If any part of the object initialization terminates by throwing an
exception and a suitable deallocation function can be found, the
@@ -2537,10 +2507,10 @@ build_new_1 (exp)
unambiguous matching deallocation function can be found,
propagating the exception does not cause the object's memory to be
freed. */
- if (flag_exceptions && alloc_expr && ! use_java_new)
+ if (flag_exceptions && ! use_java_new)
{
enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
- tree cleanup, fn = NULL_TREE;
+ tree cleanup;
int flags = (LOOKUP_NORMAL
| (globally_qualified_p * LOOKUP_GLOBAL));
@@ -2549,21 +2519,31 @@ build_new_1 (exp)
functions that we use for finding allocation functions. */
flags |= LOOKUP_SPECULATIVELY;
- /* We expect alloc_expr to look like a TARGET_EXPR around
- a NOP_EXPR around the CALL_EXPR we want. */
- fn = TREE_OPERAND (alloc_expr, 1);
- fn = TREE_OPERAND (fn, 0);
-
- cleanup = build_op_delete_call (dcode, alloc_node, size, flags, fn);
+ cleanup = build_op_delete_call (dcode, alloc_node, size, flags,
+ alloc_call);
/* Ack! First we allocate the memory. Then we set our sentry
variable to true, and expand a cleanup that deletes the memory
- if sentry is true. Then we run the constructor and store the
- returned pointer in buf. Then we clear sentry and return buf. */
+ if sentry is true. Then we run the constructor, and finally
+ clear the sentry.
+
+ It would be nice to be able to handle this without the sentry
+ variable, perhaps with a TRY_CATCH_EXPR, but this doesn't
+ work. We allocate the space first, so if there are any
+ temporaries with cleanups in the constructor args we need this
+ EH region to extend until end of full-expression to preserve
+ nesting.
+
+ If the backend had some mechanism so that we could force the
+ allocation to be expanded after all the other args to the
+ constructor, that would fix the nesting problem and we could
+ do away with this complexity. But that would complicate other
+ things; in particular, it would make it difficult to bail out
+ if the allocation function returns null. */
if (cleanup)
{
- tree end, sentry, begin, buf, t = TREE_TYPE (rval);
+ tree end, sentry, begin;
begin = get_target_expr (boolean_true_node);
sentry = TREE_OPERAND (begin, 0);
@@ -2572,46 +2552,41 @@ build_new_1 (exp)
= build (COND_EXPR, void_type_node, sentry,
cleanup, void_zero_node);
- rval = get_target_expr (rval);
-
end = build (MODIFY_EXPR, TREE_TYPE (sentry),
sentry, boolean_false_node);
- buf = TREE_OPERAND (rval, 0);
-
- rval = build (COMPOUND_EXPR, t, begin,
- build (COMPOUND_EXPR, t, rval,
- build (COMPOUND_EXPR, t, end, buf)));
+ init_expr
+ = build (COMPOUND_EXPR, void_type_node, begin,
+ build (COMPOUND_EXPR, void_type_node, init_expr,
+ end));
}
}
}
else if (CP_TYPE_CONST_P (true_type))
cp_error ("uninitialized const in `new' of `%#T'", true_type);
- done:
+ /* Now build up the return value in reverse order. */
- if (alloc_expr && rval == alloc_node)
- {
- rval = TREE_OPERAND (alloc_expr, 1);
- alloc_expr = NULL_TREE;
- }
+ rval = alloc_node;
+
+ if (init_expr)
+ rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval);
+ if (cookie_expr)
+ rval = build (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
- if (check_new && alloc_expr)
+ if (rval == alloc_node)
+ /* If we didn't modify anything, strip the TARGET_EXPR and return the
+ (adjusted) call. */
+ return TREE_OPERAND (alloc_expr, 1);
+
+ if (check_new)
{
- /* Did we modify the storage? */
tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node,
integer_zero_node);
rval = build_conditional_expr (ifexp, rval, alloc_node);
}
- if (alloc_expr)
- rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
-
- if (rval && TREE_TYPE (rval) != build_pointer_type (type))
- {
- /* The type of new int [3][3] is not int *, but int [3] * */
- rval = build_c_cast (build_pointer_type (type), rval);
- }
+ rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
return rval;
}