#include "system.h"
#include "tree.h"
#include "rtl.h"
-#include "function.h"
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
#include "except.h"
#include "expr.h"
#include "toplev.h"
-
-/* In C++, structures with well-defined constructors are initialized by
- those constructors, unasked. CURRENT_BASE_INIT_LIST
- holds a list of stmts for a BASE_INIT term in the grammar.
- This list has one element for each base class which must be
- initialized. The list elements are [basename, init], with
- type basetype. This allows the possibly anachronistic form
- (assuming d : a, b, c) "d (int a) : c(a+5), b (a-4), a (a+3)"
- where each successive term can be handed down the constructor
- line. Perhaps this was not intended. */
-tree current_base_init_list, current_member_init_list;
+#include "ggc.h"
static void expand_aggr_vbase_init_1 PROTO((tree, tree, tree, tree));
static void construct_virtual_bases PROTO((tree, tree, tree, tree, tree));
static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int));
static void expand_default_init PROTO((tree, tree, tree, tree, int));
-static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, tree,
- int));
+static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, int));
static void perform_member_init PROTO((tree, tree, tree, int));
static void sort_base_init PROTO((tree, tree *, tree *));
static tree build_builtin_delete_call PROTO((tree));
static void expand_virtual_init PROTO((tree, tree));
static tree sort_member_init PROTO((tree));
static tree initializing_context PROTO((tree));
-static void expand_vec_init_try_block PROTO((tree));
-static void expand_vec_init_catch_clause PROTO((tree, tree, tree, tree));
static tree build_java_class_ref PROTO((tree));
static void expand_cleanup_for_base PROTO((tree, tree));
-
-/* Cache the identifier nodes for the magic field of a new cookie. */
-static tree nc_nelts_field_id;
-
-static tree minus_one;
+static tree get_temp_regvar PROTO((tree, tree));
/* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */
{
tree fields[1];
- minus_one = build_int_2 (-1, -1);
+ minus_one_node = build_int_2 (-1, -1);
/* Define the structure that holds header information for
arrays allocated via operator new. */
BI_header_type = make_lang_type (RECORD_TYPE);
- nc_nelts_field_id = get_identifier ("nelts");
- fields[0] = build_lang_field_decl (FIELD_DECL, nc_nelts_field_id, sizetype);
+ nelts_identifier = get_identifier ("nelts");
+ fields[0] = build_lang_decl (FIELD_DECL, nelts_identifier, sizetype);
+
+ /* Use the biggest alignment supported by the target to prevent operator
+ new from returning misaligned pointers. */
+ TYPE_ALIGN (BI_header_type) = BIGGEST_ALIGNMENT;
finish_builtin_type (BI_header_type, "__new_cookie", fields,
- 0, double_type_node);
+ 0, BI_header_type);
BI_header_size = size_in_bytes (BI_header_type);
+
+ ggc_add_tree_root (&BI_header_type, 1);
+ ggc_add_tree_root (&BI_header_size, 1);
}
/* Subroutine of emit_base_init. For BINFO, initialize all the
tree decl;
tree type = TREE_TYPE (member);
- expand_start_target_temps ();
-
decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
/* Deal with this here, as we will get confused if we try to call the
if (ANON_AGGR_TYPE_P (type))
{
init = build (INIT_EXPR, type, decl, TREE_VALUE (init));
- TREE_SIDE_EFFECTS (init) = 1;
- expand_expr_stmt (init);
+ finish_expr_stmt (init);
}
else if (TYPE_NEEDS_CONSTRUCTING (type)
|| (init && TYPE_HAS_CONSTRUCTOR (type)))
&& TREE_CODE (TREE_TYPE (TREE_VALUE (init))) == ARRAY_TYPE)
{
/* Initialization of one array from another. */
- expand_vec_init (TREE_OPERAND (decl, 1), decl,
- array_type_nelts (type), TREE_VALUE (init), 1);
+ finish_expr_stmt
+ (build_vec_init (TREE_OPERAND (decl, 1), decl,
+ array_type_nelts (type), TREE_VALUE (init), 1));
}
else
- expand_aggr_init (decl, init, 0);
+ finish_expr_stmt (build_aggr_init (decl, init, 0));
}
else
{
for constructors and such. */
tree e = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (e) = 1;
- expand_expr_stmt (build (INIT_EXPR, type, decl, e));
+ finish_expr_stmt (build (INIT_EXPR, type, decl, e));
}
else if (TREE_CODE (type) == REFERENCE_TYPE)
cp_error ("default-initialization of `%#D', which has reference type",
}
if (init)
- expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
+ finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
- expand_end_target_temps ();
- free_temp_slots ();
-
if (TYPE_NEEDS_DESTRUCTOR (type))
{
tree expr;
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
expr = build_component_ref (current_class_ref, name, NULL_TREE,
explicit);
expr = build_delete (type, expr, integer_zero_node,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
if (expr != error_mark_node)
- add_partial_entry (expr);
-
- pop_obstacks ();
+ finish_subobject (expr);
}
}
Note that emit_base_init does *not* initialize virtual base
classes. That is done specially, elsewhere. */
-extern tree base_init_expr;
-
-void
-emit_base_init (t, immediately)
+tree
+emit_base_init (t)
tree t;
- int immediately;
{
tree member;
tree mem_init_list;
tree t_binfo = TYPE_BINFO (t);
tree binfos = BINFO_BASETYPES (t_binfo);
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- tree expr = NULL_TREE;
-
- if (! immediately)
- {
- int momentary;
- do_pending_stack_adjust ();
- /* Make the RTL_EXPR node temporary, not momentary,
- so that rtl_expr_chain doesn't become garbage. */
- momentary = suspend_momentary ();
- expr = make_node (RTL_EXPR);
- resume_momentary (momentary);
- start_sequence_for_rtl_expr (expr);
- }
-
- if (write_symbols == NO_DEBUG)
- /* As a matter of principle, `start_sequence' should do this. */
- emit_note (0, -1);
- else
- /* Always emit a line number note so we can step into constructors. */
- emit_line_note_force (DECL_SOURCE_FILE (current_function_decl),
- DECL_SOURCE_LINE (current_function_decl));
+ tree stmt_expr;
+ tree compound_stmt;
mem_init_list = sort_member_init (t);
current_member_init_list = NULL_TREE;
sort_base_init (t, &rbase_init_list, &vbase_init_list);
current_base_init_list = NULL_TREE;
+ begin_init_stmts (&stmt_expr, &compound_stmt);
+
/* First, initialize the virtual base classes, if we are
constructing the most-derived object. */
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
if (init != void_list_node)
{
- expand_start_target_temps ();
-
member = convert_pointer_to_real (base_binfo, current_class_ptr);
expand_aggr_init_1 (base_binfo, NULL_TREE,
build_indirect_ref (member, NULL_PTR), init,
LOOKUP_NORMAL);
-
- expand_end_target_temps ();
- free_temp_slots ();
}
expand_cleanup_for_base (base_binfo, NULL_TREE);
cp_error ("field `%D' not in immediate context", field);
}
-#if 0
- /* It turns out if you have an anonymous union in the
- class, a member from it can end up not being on the
- list of fields (rather, the type is), and therefore
- won't be seen by the for loop above. */
-
- /* The code in this for loop is derived from a general loop
- which had this check in it. Theoretically, we've hit
- every initialization for the list of members in T, so
- we shouldn't have anything but these left in this list. */
- my_friendly_assert (DECL_FIELD_CONTEXT (field) != t, 351);
-#endif
-
perform_member_init (field, name, init, 1);
}
mem_init_list = TREE_CHAIN (mem_init_list);
}
- if (! immediately)
- {
- do_pending_stack_adjust ();
- my_friendly_assert (base_init_expr == 0, 207);
- base_init_expr = expr;
- TREE_TYPE (expr) = void_type_node;
- RTL_EXPR_RTL (expr) = const0_rtx;
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- rtl_expr_chain = tree_cons (NULL_TREE, expr, rtl_expr_chain);
- end_sequence ();
- TREE_SIDE_EFFECTS (expr) = 1;
- }
-
/* All the implicit try blocks we built up will be zapped
when we come to a real binding contour boundary. */
+ return finish_init_stmts (stmt_expr, compound_stmt);
}
/* Check that all fields are properly initialized after
/* This code is crusty. Should be simple, like:
vtbl = BINFO_VTABLE (binfo);
*/
- vtype = DECL_CONTEXT (CLASSTYPE_VFIELD (type));
+ vtype = DECL_CONTEXT (TYPE_VFIELD (type));
vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0);
- vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)), binfo));
+ vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo));
assemble_external (vtbl);
TREE_USED (vtbl) = 1;
vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
/* Have to convert VTBL since array sizes may be different. */
vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
- expand_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
+ finish_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
}
/* If an exception is thrown in a constructor, those base classes already
if (!TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo)))
return;
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
/* Call the destructor. */
expr = (build_scoped_method_call
(current_class_ref, binfo, dtor_identifier,
truthvalue_conversion (flag),
expr, integer_zero_node));
- pop_obstacks ();
- add_partial_entry (expr);
+ finish_subobject (expr);
}
/* Subroutine of `expand_aggr_vbase_init'.
tree init = purpose_member (binfo, init_list);
tree ref = build_indirect_ref (addr, NULL_PTR);
- expand_start_target_temps ();
-
if (init)
init = TREE_VALUE (init);
/* Call constructors, but don't set up vtables. */
expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
-
- expand_end_target_temps ();
- free_temp_slots ();
}
/* Construct the virtual base-classes of THIS_REF (whose address is
{
tree vbases;
tree result;
+ tree if_stmt;
/* If there are no virtual baseclasses, we shouldn't even be here. */
my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621);
/* First set the pointers in our object that tell us where to find
our virtual baseclasses. */
- expand_start_cond (flag, 0);
+ if_stmt = begin_if_stmt ();
+ finish_if_stmt_cond (flag, if_stmt);
result = init_vbase_pointers (type, this_ptr);
if (result)
- expand_expr_stmt (build_compound_expr (result));
- expand_end_cond ();
+ finish_expr_stmt (build_compound_expr (result));
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
/* Now, run through the baseclasses, initializing each. */
for (vbases = CLASSTYPE_VBASECLASSES (type); vbases;
vbases = TREE_CHAIN (vbases))
{
tree tmp = purpose_member (vbases, result);
-
+ tree inner_if_stmt;
+ tree compound_stmt;
+
/* If there are virtual base classes with destructors, we need to
emit cleanups to destroy them if an exception is thrown during
the construction process. These exception regions (i.e., the
in the outer block.) We trust the back-end to figure out
that the FLAG will not change across initializations, and
avoid doing multiple tests. */
- expand_start_cond (flag, 0);
+ inner_if_stmt = begin_if_stmt ();
+ finish_if_stmt_cond (flag, inner_if_stmt);
+ compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
expand_aggr_vbase_init_1 (vbases, this_ref,
TREE_OPERAND (TREE_VALUE (tmp), 0),
init_list);
- expand_end_cond ();
+ finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+ finish_then_clause (inner_if_stmt);
+ finish_if_stmt ();
expand_cleanup_for_base (vbases, flag);
}
}
}
+/* We are about to generate some complex initialization code.
+ Conceptually, it is all a single expression. However, we may want
+ to include conditionals, loops, and other such statement-level
+ constructs. Therefore, we build the initialization code inside a
+ statement-expression. This function starts such an expression.
+ STMT_EXPR_P and COMPOUND_STMT_P are filled in by this function;
+ pass them back to finish_init_stmts when the expression is
+ complete. */
+
+void
+begin_init_stmts (stmt_expr_p, compound_stmt_p)
+ tree *stmt_expr_p;
+ tree *compound_stmt_p;
+{
+ *stmt_expr_p = begin_stmt_expr ();
+ *compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
+}
+
+/* Finish out the statement-expression begun by the previous call to
+ begin_init_stmts. Returns the statement-expression itself. */
+
+tree
+finish_init_stmts (stmt_expr, compound_stmt)
+ tree stmt_expr;
+ tree compound_stmt;
+{
+ finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+ stmt_expr = finish_stmt_expr (stmt_expr);
+
+ /* To avoid spurious warnings about unused values, we set
+ TREE_USED. */
+ if (stmt_expr)
+ TREE_USED (stmt_expr) = 1;
+
+ return stmt_expr;
+}
+
/* This is like `expand_member_init', only it stores one aggregate
value into another.
A constructor or a conversion operator may have to be used to
perform the initialization, but not both, as it would be ambiguous. */
-void
-expand_aggr_init (exp, init, flags)
+tree
+build_aggr_init (exp, init, flags)
tree exp, init;
int flags;
{
+ tree stmt_expr;
+ tree compound_stmt;
+ int destroy_temps;
tree type = TREE_TYPE (exp);
int was_const = TREE_READONLY (exp);
int was_volatile = TREE_THIS_VOLATILE (exp);
if (init == error_mark_node)
- return;
+ return error_mark_node;
TREE_READONLY (exp) = 0;
TREE_THIS_VOLATILE (exp) = 0;
}
*/
error ("bad array initializer");
- return;
+ return error_mark_node;
}
- expand_vec_init (exp, exp, array_type_nelts (type), init,
- init && same_type_p (TREE_TYPE (init),
- TREE_TYPE (exp)));
+ stmt_expr = build_vec_init (exp, exp, array_type_nelts (type), init,
+ init && same_type_p (TREE_TYPE (init),
+ TREE_TYPE (exp)));
TREE_READONLY (exp) = was_const;
TREE_THIS_VOLATILE (exp) = was_volatile;
TREE_TYPE (exp) = type;
if (init)
TREE_TYPE (init) = itype;
- return;
+ return stmt_expr;
}
if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
/* just know that we've seen something for this node */
TREE_USED (exp) = 1;
-#if 0
- /* If initializing from a GNU C CONSTRUCTOR, consider the elts in the
- constructor as parameters to an implicit GNU C++ constructor. */
- if (init && TREE_CODE (init) == CONSTRUCTOR
- && TYPE_HAS_CONSTRUCTOR (type)
- && TREE_TYPE (init) == type)
- init = CONSTRUCTOR_ELTS (init);
-#endif
-
TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
+ begin_init_stmts (&stmt_expr, &compound_stmt);
+ destroy_temps = stmts_are_full_exprs_p;
+ stmts_are_full_exprs_p = 0;
expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
init, LOOKUP_NORMAL|flags);
+ stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
+ stmts_are_full_exprs_p = destroy_temps;
TREE_TYPE (exp) = type;
TREE_READONLY (exp) = was_const;
TREE_THIS_VOLATILE (exp) = was_volatile;
+
+ return stmt_expr;
}
static void
else
init = build (INIT_EXPR, TREE_TYPE (exp), exp, init);
TREE_SIDE_EFFECTS (init) = 1;
- expand_expr_stmt (init);
+ finish_expr_stmt (init);
return;
}
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
if (true_exp == exp)
- parms = expr_tree_cons (NULL_TREE, integer_one_node, parms);
+ parms = tree_cons (NULL_TREE, integer_one_node, parms);
else
- parms = expr_tree_cons (NULL_TREE, integer_zero_node, parms);
+ parms = tree_cons (NULL_TREE, integer_zero_node, parms);
flags |= LOOKUP_HAS_IN_CHARGE;
}
rval = build_method_call (exp, ctor_identifier,
parms, binfo, flags);
if (TREE_SIDE_EFFECTS (rval))
- expand_expr_stmt (rval);
+ finish_expr_stmt (rval);
}
/* This function is responsible for initializing EXP with INIT
&& TREE_CODE (init) == CONSTRUCTOR
&& TREE_HAS_CONSTRUCTOR (init))
{
- tree t = store_init_value (exp, init);
- if (!t)
+ /* If store_init_value returns NULL_TREE, the INIT has been
+ record in the DECL_INITIAL for EXP. That means there's
+ nothing more we have to do. */
+ if (!store_init_value (exp, init))
{
- expand_decl_init (exp);
- return;
+ if (!building_stmt_tree ())
+ expand_decl_init (exp);
}
- t = build (INIT_EXPR, type, exp, init);
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr_stmt (t);
+ else
+ finish_expr_stmt (build (INIT_EXPR, type, exp, init));
return;
}
return build (OFFSET_REF, TREE_TYPE (t), decl, t);
}
- /* FNFIELDS is most likely allocated on the search_obstack,
- which will go away after this class scope. If we need
- to save this value for later (i.e. for use as an initializer
- for a static variable), then do so here.
-
- ??? The smart thing to do for the case of saving initializers
- is to resolve them before we're done with this scope. */
- if (!TREE_PERMANENT (fnfields)
- && ! allocation_temporary_p ())
- fnfields = copy_list (fnfields);
-
TREE_TYPE (fnfields) = unknown_type_node;
return build (OFFSET_REF, unknown_type_node, decl, fnfields);
}
tree nelts = NULL_TREE, t;
int has_array = 0;
- tree pending_sizes = NULL_TREE;
-
if (decl == error_mark_node)
return error_mark_node;
{
tree absdcl = TREE_VALUE (decl);
tree last_absdcl = NULL_TREE;
- int old_immediate_size_expand = 0;
if (current_function_decl
&& DECL_CONSTRUCTOR_P (current_function_decl))
- {
- old_immediate_size_expand = immediate_size_expand;
- immediate_size_expand = 0;
- }
+ my_friendly_assert (immediate_size_expand == 0, 19990926);
nelts = integer_one_node;
type = groktypename (decl);
if (! type || type == error_mark_node)
- {
- immediate_size_expand = old_immediate_size_expand;
- return error_mark_node;
- }
-
- if (current_function_decl
- && DECL_CONSTRUCTOR_P (current_function_decl))
- {
- pending_sizes = get_pending_sizes ();
- immediate_size_expand = old_immediate_size_expand;
- }
+ return error_mark_node;
}
else if (TREE_CODE (decl) == IDENTIFIER_NODE)
{
rval = build (NEW_EXPR, build_pointer_type (type), placement, t, init);
NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
TREE_SIDE_EFFECTS (rval) = 1;
+ rval = build_new_1 (rval);
+ if (rval == error_mark_node)
+ return error_mark_node;
/* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain. */
rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval);
TREE_NO_UNUSED_WARNING (rval) = 1;
- if (pending_sizes)
- rval = build_compound_expr (chainon (pending_sizes,
- build_expr_list (NULL_TREE, rval)));
-
return rval;
}
-/* If non-NULL, a POINTER_TYPE equivalent to (java::lang::Class*). */
-
-static tree jclass_node = NULL_TREE;
-
/* Given a Java class, return a decl for the corresponding java.lang.Class. */
static tree
class_decl = IDENTIFIER_GLOBAL_VALUE (name);
if (class_decl == NULL_TREE)
{
- push_permanent_obstack ();
class_decl = build_decl (VAR_DECL, name, TREE_TYPE (jclass_node));
TREE_STATIC (class_decl) = 1;
DECL_EXTERNAL (class_decl) = 1;
DECL_IGNORED_P (class_decl) = 1;
pushdecl_top_level (class_decl);
make_decl_rtl (class_decl, NULL_PTR, 1);
- pop_obstacks ();
}
return class_decl;
}
&& TREE_TYPE (TREE_VALUE (placement)) == ptr_type_node));
if (use_cookie)
- {
- tree extra = BI_header_size;
-
- size = size_binop (PLUS_EXPR, size, extra);
- }
+ size = size_binop (PLUS_EXPR, size, BI_header_size);
if (has_array)
{
/* Allocate the object. */
- 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;
- else
- {
- error ("constructors take parameter lists");
- return error_mark_node;
- }
- }
- else if (! placement && TYPE_FOR_JAVA (true_type))
+ if (! placement && TYPE_FOR_JAVA (true_type))
{
tree class_addr, alloc_decl;
tree class_decl = build_java_class_ref (true_type);
}
else
{
- int susp = 0;
-
- if (flag_exceptions)
- /* We will use RVAL when generating an exception handler for
- this new-expression, so we must save it. */
- susp = suspend_momentary ();
-
rval = build_op_new_call
- (code, true_type, expr_tree_cons (NULL_TREE, size, placement),
+ (code, true_type, 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)
- resume_momentary (susp);
}
/* unless an allocation function is declared with an empty excep-
build_pointer_type (BI_header_type),
rval, extra), NULL_PTR);
exp1 = build (MODIFY_EXPR, void_type_node,
- build_component_ref (cookie, nc_nelts_field_id,
+ build_component_ref (cookie, nelts_identifier,
NULL_TREE, 0),
nelts);
- TREE_SIDE_EFFECTS (exp1) = 1;
rval = cp_convert (build_pointer_type (true_type), rval);
rval = build_compound_expr
- (expr_tree_cons (NULL_TREE, exp1,
+ (tree_cons (NULL_TREE, exp1,
build_expr_list (NULL_TREE, rval)));
}
if (rval && TYPE_USES_VIRTUAL_BASECLASSES (true_type))
{
- init = expr_tree_cons (NULL_TREE, integer_one_node, init);
+ init = tree_cons (NULL_TREE, integer_one_node, init);
flags |= LOOKUP_HAS_IN_CHARGE;
}
TREE_HAS_CONSTRUCTOR (rval) = 1;
}
else
- rval = build (VEC_INIT_EXPR, TREE_TYPE (rval),
- save_expr (rval), init, nelts);
+ rval = (build_vec_init
+ (NULL_TREE,
+ save_expr (rval),
+ build_binary_op (MINUS_EXPR, nelts, integer_one_node),
+ init,
+ /*from_array=*/0));
/* If any part of the object initialization terminates by throwing an
exception and a suitable deallocation function can be found, the
tree cleanup, fn = NULL_TREE;
int flags = LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL);
- /* All cleanups must last longer than normal. */
- int yes = suspend_momentary ();
-
/* The Standard is unclear here, but the right thing to do
is to use the same method for finding deallocation
functions that we use for finding allocation functions. */
fn = TREE_OPERAND (alloc_expr, 1);
fn = TREE_OPERAND (fn, 0);
- /* Copy size to the saveable obstack. */
- size = mapcar (size, permanent_p);
-
cleanup = build_op_delete_call (dcode, alloc_node, size, flags, fn);
- resume_momentary (yes);
-
/* 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
begin = get_target_expr (boolean_true_node);
sentry = TREE_OPERAND (begin, 0);
- yes = suspend_momentary ();
TREE_OPERAND (begin, 2)
= build (COND_EXPR, void_type_node, sentry,
cleanup, void_zero_node);
- resume_momentary (yes);
rval = get_target_expr (rval);
end = build (MODIFY_EXPR, TREE_TYPE (sentry),
sentry, boolean_false_node);
- TREE_SIDE_EFFECTS (end) = 1;
buf = TREE_OPERAND (rval, 0);
}
\f
static tree
-build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
- use_global_delete)
+build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
tree base, maxindex, type;
- tree auto_delete_vec, auto_delete;
+ tree auto_delete_vec;
int use_global_delete;
{
tree virtual_size;
/* The below is short by BI_header_size */
virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex));
- tbase = build_decl (VAR_DECL, NULL_TREE, ptype);
+ tbase = create_temporary_var (ptype);
tbase_init = build_modify_expr (tbase, NOP_EXPR,
fold (build (PLUS_EXPR, ptype,
base,
controller = build (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (controller) = 1;
- if (auto_delete != integer_zero_node
- && auto_delete != integer_two_node)
- {
- tree base_tbd = cp_convert (ptype,
- build_binary_op (MINUS_EXPR,
- cp_convert (ptr_type_node, base),
- BI_header_size));
- /* This is the real size */
- virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
- body = build_expr_list (NULL_TREE,
- build_x_delete (base_tbd,
- 2 | use_global_delete,
- virtual_size));
- body = build (COND_EXPR, void_type_node,
- build (BIT_AND_EXPR, integer_type_node,
- auto_delete, integer_one_node),
- body, integer_zero_node);
- }
- else
- body = NULL_TREE;
+ body = NULL_TREE;
- body = expr_tree_cons (NULL_TREE,
- build_delete (ptype, tbase, auto_delete,
+ body = tree_cons (NULL_TREE,
+ build_delete (ptype, tbase, integer_two_node,
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1),
body);
- body = expr_tree_cons (NULL_TREE,
+ body = tree_cons (NULL_TREE,
build_modify_expr (tbase, NOP_EXPR, build (MINUS_EXPR, ptype, tbase, size_exp)),
body);
- body = expr_tree_cons (NULL_TREE,
+ body = tree_cons (NULL_TREE,
build (EXIT_EXPR, void_type_node,
build (EQ_EXPR, boolean_type_node, base, tbase)),
body);
loop = build (LOOP_EXPR, void_type_node, build_compound_expr (body));
- loop = expr_tree_cons (NULL_TREE, tbase_init,
- expr_tree_cons (NULL_TREE, loop, NULL_TREE));
+ loop = tree_cons (NULL_TREE, tbase_init,
+ tree_cons (NULL_TREE, loop, NULL_TREE));
loop = build_compound_expr (loop);
no_destructor:
deallocate_expr = build_x_delete (base_tbd,
2 | use_global_delete,
virtual_size);
- if (auto_delete_vec != integer_one_node)
- deallocate_expr = build (COND_EXPR, void_type_node,
- build (BIT_AND_EXPR, integer_type_node,
- auto_delete_vec, integer_one_node),
- deallocate_expr, integer_zero_node);
+ deallocate_expr = fold (build (COND_EXPR, void_type_node,
+ fold (build (BIT_AND_EXPR,
+ integer_type_node,
+ auto_delete_vec,
+ integer_one_node)),
+ deallocate_expr, integer_zero_node));
}
if (loop && deallocate_expr != integer_zero_node)
{
- body = expr_tree_cons (NULL_TREE, loop,
- expr_tree_cons (NULL_TREE, deallocate_expr, NULL_TREE));
+ body = tree_cons (NULL_TREE, loop,
+ tree_cons (NULL_TREE, deallocate_expr, NULL_TREE));
body = build_compound_expr (body);
}
else
body = loop;
/* Outermost wrapper: If pointer is null, punt. */
- body = build (COND_EXPR, void_type_node,
- build (NE_EXPR, boolean_type_node, base, integer_zero_node),
- body, integer_zero_node);
+ body = fold (build (COND_EXPR, void_type_node,
+ fold (build (NE_EXPR, boolean_type_node, base,
+ integer_zero_node)),
+ body, integer_zero_node));
body = build1 (NOP_EXPR, void_type_node, body);
if (controller)
return cp_convert (void_type_node, body);
}
-/* Protect the vector initialization with a try-block so that we can
- destroy the first few elements if constructing a later element
- causes an exception to be thrown. TYPE is the type of the array
- elements. */
-
-static void
-expand_vec_init_try_block (type)
+tree
+create_temporary_var (type)
tree type;
{
- if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions)
- return;
-
- /* The code we generate looks like:
-
- try {
- // Initialize the vector.
- } catch (...) {
- // Destory the elements that need destroying.
- throw;
- }
-
- Here we're just beginning the `try'. */
+ tree decl;
+
+ decl = build_decl (VAR_DECL, NULL_TREE, type);
+ TREE_USED (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_SOURCE_FILE (decl) = input_filename;
+ DECL_SOURCE_LINE (decl) = lineno;
+ DECL_IGNORED_P (decl) = 1;
+ DECL_CONTEXT (decl) = current_function_decl;
- expand_eh_region_start ();
+ return decl;
}
-/* Add code to destroy the array elements constructed so far if the
- construction of some element in the array causes an exception to be
- thrown. RVAL is the address of the last element in the array.
- TYPE is the type of the array elements. MAXINDEX is the maximum
- allowable index into the array. ITERATOR is an integer variable
- indicating how many elements remain to be constructed. */
+/* Create a new temporary variable of the indicated TYPE, initialized
+ to INIT.
-static void
-expand_vec_init_catch_clause (rval, type, maxindex, iterator)
- tree rval;
- tree type;
- tree maxindex;
- tree iterator;
+ It is not entered into current_binding_level, because that breaks
+ things when it comes time to do final cleanups (which take place
+ "outside" the binding contour of the function). */
+
+static tree
+get_temp_regvar (type, init)
+ tree type, init;
{
- tree e;
- tree cleanup;
+ tree decl;
- if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions)
- return;
-
- /* We have to ensure that this can live to the cleanup expansion
- time, since we know it is only ever needed once, generate code
- now. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
- cleanup = make_node (RTL_EXPR);
- TREE_TYPE (cleanup) = void_type_node;
- RTL_EXPR_RTL (cleanup) = const0_rtx;
- TREE_SIDE_EFFECTS (cleanup) = 1;
- do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (cleanup);
-
- e = build_vec_delete_1 (rval,
- build_binary_op (MINUS_EXPR, maxindex,
- iterator),
- type,
- /*auto_delete_vec=*/integer_zero_node,
- /*auto_delete=*/integer_zero_node,
- /*use_global_delete=*/0);
- expand_expr (e, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- do_pending_stack_adjust ();
- RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
- end_sequence ();
- cleanup = protect_with_terminate (cleanup);
- expand_eh_region_end (cleanup);
- pop_obstacks ();
+ decl = create_temporary_var (type);
+ if (building_stmt_tree ())
+ add_decl_stmt (decl);
+ if (!building_stmt_tree ())
+ DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
+ finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
+
+ return decl;
}
-/* `expand_vec_init' performs initialization of a vector of aggregate
- types.
+/* `build_vec_init' returns tree structure that performs
+ initialization of a vector of aggregate types.
DECL is passed only for error reporting, and provides line number
and source file name information.
- BASE is the space where the vector will be.
+ BASE is the space where the vector will be. For a vector of Ts,
+ the type of BASE is `T*'.
MAXINDEX is the maximum index of the array (one less than the
number of elements).
INIT is the (possibly NULL) initializer.
but use assignment instead of initialization. */
tree
-expand_vec_init (decl, base, maxindex, init, from_array)
+build_vec_init (decl, base, maxindex, init, from_array)
tree decl, base, maxindex, init;
int from_array;
{
tree rval;
tree base2 = NULL_TREE;
- tree type = TREE_TYPE (TREE_TYPE (base));
tree size;
tree itype = NULL_TREE;
tree iterator;
+ /* The type of an element in the array. */
+ tree type;
+ /* The type of a pointer to an element in the array. */
+ tree ptype;
+ tree stmt_expr;
+ tree compound_stmt;
+ int destroy_temps;
+ tree try_block = NULL_TREE;
+ tree try_body;
int num_initialized_elts = 0;
maxindex = cp_convert (ptrdiff_type_node, maxindex);
if (maxindex == error_mark_node)
return error_mark_node;
- if (current_function_decl == NULL_TREE)
- {
- rval = make_tree_vec (3);
- TREE_VEC_ELT (rval, 0) = base;
- TREE_VEC_ELT (rval, 1) = maxindex;
- TREE_VEC_ELT (rval, 2) = init;
- return rval;
- }
-
+ type = TREE_TYPE (TREE_TYPE (base));
+ ptype = build_pointer_type (type);
size = size_in_bytes (type);
- base = default_conversion (base);
- base = cp_convert (build_pointer_type (type), base);
- rval = get_temp_regvar (build_pointer_type (type), base);
- base = get_temp_regvar (build_pointer_type (type), base);
+ /* The code we are generating looks like:
+
+ T* t1 = (T*) base;
+ T* rval = base;
+ ptrdiff_t iterator = maxindex;
+ try {
+ ... initializations from CONSTRUCTOR ...
+ if (iterator != -1) {
+ do {
+ ... initialize *base ...
+ ++base;
+ } while (--iterator != -1);
+ }
+ } catch (...) {
+ ... destroy elements that were constructed ...
+ }
+
+ We can omit the try and catch blocks if we know that the
+ initialization will never throw an exception, or if the array
+ elements do not have destructors. If we have a CONSTRUCTOR to
+ give us initialization information, we emit code to initialize
+ each of the elements before the loop in the try block, and then
+ iterate over fewer elements. We can omit the loop completely if
+ the elements of the array do not have constructors.
+
+ We actually wrap the entire body of the above in a STMT_EXPR, for
+ tidiness.
+
+ When copying from array to another, when the array elements have
+ only trivial copy constructors, we should use __builtin_memcpy
+ rather than generating a loop. That way, we could take advantage
+ of whatever cleverness the back-end has for dealing with copies
+ of blocks of memory. */
+
+ begin_init_stmts (&stmt_expr, &compound_stmt);
+ destroy_temps = stmts_are_full_exprs_p;
+ stmts_are_full_exprs_p = 0;
+ rval = get_temp_regvar (ptype,
+ cp_convert (ptype, default_conversion (base)));
+ base = get_temp_regvar (ptype, rval);
iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
/* Protect the entire array initialization so that we can destroy
the partially constructed array if an exception is thrown. */
- expand_vec_init_try_block (type);
+ if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
+ {
+ try_block = begin_try_block ();
+ try_body = begin_compound_stmt (/*has_no_scope=*/1);
+ }
if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR
&& (!decl || same_type_p (TREE_TYPE (init), TREE_TYPE (decl))))
initializers. */
tree elts;
- tree baseref = build1 (INDIRECT_REF, type, base);
-
from_array = 0;
for (elts = CONSTRUCTOR_ELTS (init); elts; elts = TREE_CHAIN (elts))
{
tree elt = TREE_VALUE (elts);
+ tree baseref = build1 (INDIRECT_REF, type, base);
num_initialized_elts++;
if (IS_AGGR_TYPE (type) || TREE_CODE (type) == ARRAY_TYPE)
- expand_aggr_init (baseref, elt, 0);
+ finish_expr_stmt (build_aggr_init (baseref, elt, 0));
else
- expand_assignment (baseref, elt, 0, 0);
+ finish_expr_stmt (build_modify_expr (baseref, NOP_EXPR,
+ elt));
- expand_assignment (base,
+ finish_expr_stmt (build_modify_expr
+ (base,
+ NOP_EXPR,
build (PLUS_EXPR, build_pointer_type (type),
- base, size),
- 0, 0);
- expand_assignment (iterator,
+ base, size)));
+ finish_expr_stmt (build_modify_expr
+ (iterator,
+ NOP_EXPR,
build (MINUS_EXPR, ptrdiff_type_node,
- iterator, integer_one_node),
- 0, 0);
+ iterator, integer_one_node)));
}
/* Clear out INIT so that we don't get confused below. */
init = NULL_TREE;
-
- if (obey_regdecls)
- use_variable (DECL_RTL (base));
}
else if (from_array)
{
{
/* If the ITERATOR is equal to -1, then we don't have to loop;
we've already initialized all the elements. */
- expand_start_cond (build (NE_EXPR, boolean_type_node,
- iterator, minus_one),
- 0);
+ tree if_stmt;
+ tree do_stmt;
+ tree do_body;
+ tree elt_init;
+
+ if_stmt = begin_if_stmt ();
+ finish_if_stmt_cond (build (NE_EXPR, boolean_type_node,
+ iterator, minus_one_node),
+ if_stmt);
/* Otherwise, loop through the elements. */
- expand_start_loop_continue_elsewhere (1);
-
- /* The initialization of each array element is a full-expression. */
- expand_start_target_temps ();
+ do_stmt = begin_do_stmt ();
+ do_body = begin_compound_stmt (/*has_no_scope=*/1);
+
+ /* When we're not building a statement-tree, things are a little
+ complicated. If, when we recursively call build_aggr_init,
+ an expression containing a TARGET_EXPR is expanded, then it
+ may get a cleanup. Then, the result of that expression is
+ passed to finish_expr_stmt, which will call
+ expand_start_target_temps/expand_end_target_temps. However,
+ the latter call will not cause the cleanup to run because
+ that block will still be on the block stack. So, we call
+ expand_start_target_temps here manually; the corresponding
+ call to expand_end_target_temps below will cause the cleanup
+ to be performed. */
+ if (!building_stmt_tree ())
+ expand_start_target_temps ();
if (from_array)
{
from = NULL_TREE;
if (from_array == 2)
- expand_expr_stmt (build_modify_expr (to, NOP_EXPR, from));
+ elt_init = build_modify_expr (to, NOP_EXPR, from);
else if (TYPE_NEEDS_CONSTRUCTING (type))
- expand_aggr_init (to, from, 0);
+ elt_init = build_aggr_init (to, from, 0);
else if (from)
- expand_assignment (to, from, 0, 0);
+ elt_init = build_modify_expr (to, NOP_EXPR, from);
else
my_friendly_abort (57);
}
{
if (init != 0)
sorry ("cannot initialize multi-dimensional array with initializer");
- expand_vec_init (decl,
- build1 (NOP_EXPR,
- build_pointer_type (TREE_TYPE
- (type)),
- base),
- array_type_nelts (type), 0, 0);
+ elt_init = (build_vec_init
+ (decl,
+ build1 (NOP_EXPR,
+ build_pointer_type (TREE_TYPE (type)),
+ base),
+ array_type_nelts (type), 0, 0));
}
else
- expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0);
+ elt_init = build_aggr_init (build1 (INDIRECT_REF, type, base),
+ init, 0);
+
+ /* The initialization of each array element is a
+ full-expression. */
+ if (!building_stmt_tree ())
+ {
+ finish_expr_stmt (elt_init);
+ expand_end_target_temps ();
+ }
+ else
+ {
+ stmts_are_full_exprs_p = 1;
+ finish_expr_stmt (elt_init);
+ stmts_are_full_exprs_p = 0;
+ }
- expand_assignment (base,
+ finish_expr_stmt (build_modify_expr
+ (base,
+ NOP_EXPR,
build (PLUS_EXPR, build_pointer_type (type),
- base, size), 0, 0);
+ base, size)));
if (base2)
- expand_assignment (base2,
+ finish_expr_stmt (build_modify_expr
+ (base2,
+ NOP_EXPR,
build (PLUS_EXPR, build_pointer_type (type),
- base2, size), 0, 0);
+ base2, size)));
- /* Cleanup any temporaries needed for the initial value. */
- expand_end_target_temps ();
-
- expand_loop_continue_here ();
- expand_exit_loop_if_false (0, build (NE_EXPR, boolean_type_node,
- build (PREDECREMENT_EXPR,
- ptrdiff_type_node,
- iterator,
- integer_one_node),
- minus_one));
-
- if (obey_regdecls)
- {
- use_variable (DECL_RTL (base));
- if (base2)
- use_variable (DECL_RTL (base2));
- }
+ finish_compound_stmt (/*has_no_scope=*/1, do_body);
+ finish_do_body (do_stmt);
+ finish_do_stmt (build (NE_EXPR, boolean_type_node,
+ build (PREDECREMENT_EXPR,
+ ptrdiff_type_node,
+ iterator,
+ integer_one_node),
+ minus_one_node),
+ do_stmt);
- expand_end_loop ();
- expand_end_cond ();
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
}
/* Make sure to cleanup any partially constructed elements. */
- expand_vec_init_catch_clause (rval, type, maxindex, iterator);
-
- if (obey_regdecls)
+ if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
{
- use_variable (DECL_RTL (iterator));
- use_variable (DECL_RTL (rval));
+ tree e;
+
+ finish_compound_stmt (/*has_no_scope=*/1, try_body);
+ finish_cleanup_try_block (try_block);
+ e = build_vec_delete_1 (rval,
+ build_binary_op (MINUS_EXPR, maxindex,
+ iterator),
+ type,
+ /*auto_delete_vec=*/integer_zero_node,
+ /*use_global_delete=*/0);
+ finish_cleanup (e, try_block);
}
- return rval;
+ /* The value of the array initialization is the address of the
+ first element in the array. */
+ finish_expr_stmt (rval);
+
+ stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
+ stmts_are_full_exprs_p = destroy_temps;
+ return stmt_expr;
}
/* Free up storage of type TYPE, at address ADDR.
return error_mark_node;
}
return build_vec_delete (addr, array_type_nelts (type),
- auto_delete, integer_zero_node,
- use_global_delete);
+ auto_delete, use_global_delete);
}
else
{
expr = build_scoped_method_call
(ref, base_binfo, dtor_identifier,
build_expr_list (NULL_TREE, this_auto_delete));
- exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
+ exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
/* Take care of the remaining baseclasses. */
(ref, base_binfo, dtor_identifier,
build_expr_list (NULL_TREE, integer_zero_node));
- exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
+ exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
tree this_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0);
tree this_type = TREE_TYPE (member);
expr = build_delete (this_type, this_member, integer_two_node, flags, 0);
- exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
+ exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
}
{
tree this_addr = convert_force (build_pointer_type (BINFO_TYPE (vbases)),
addr, 0);
- result = expr_tree_cons (NULL_TREE,
+ result = tree_cons (NULL_TREE,
build_delete (TREE_TYPE (this_addr), this_addr,
integer_zero_node,
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
BASE is the expression that should yield the store to be deleted.
This function expands (or synthesizes) these calls itself.
AUTO_DELETE_VEC says whether the container (vector) should be deallocated.
- AUTO_DELETE say whether each item in the container should be deallocated.
This also calls delete for virtual baseclasses of elements of the vector.
be worth bothering.) */
tree
-build_vec_delete (base, maxindex, auto_delete_vec, auto_delete,
- use_global_delete)
+build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete)
tree base, maxindex;
- tree auto_delete_vec, auto_delete;
+ tree auto_delete_vec;
int use_global_delete;
{
tree type;
tree cookie_addr = build (MINUS_EXPR, build_pointer_type (BI_header_type),
base, BI_header_size);
tree cookie = build_indirect_ref (cookie_addr, NULL_PTR);
- maxindex = build_component_ref (cookie, nc_nelts_field_id, NULL_TREE, 0);
+ maxindex = build_component_ref (cookie, nelts_identifier, NULL_TREE, 0);
do
type = TREE_TYPE (type);
while (TREE_CODE (type) == ARRAY_TYPE);
return error_mark_node;
}
- return build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
+ return build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
use_global_delete);
}