/* Handle initialization things in C++.
- Copyright (C) 1987, 89, 92-98, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-98, 1999, 2000 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
#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;
-
-static void expand_aggr_vbase_init_1 PROTO((tree, tree, tree, tree));
-static void expand_aggr_vbase_init 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 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 int member_init_ok_or_else PROTO((tree, tree, const char *));
-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;
+#include "ggc.h"
+
+static void expand_aggr_vbase_init_1 PARAMS ((tree, tree, tree, tree));
+static void construct_virtual_bases PARAMS ((tree, tree, tree, tree, tree));
+static void expand_aggr_init_1 PARAMS ((tree, tree, tree, tree, int));
+static void expand_default_init PARAMS ((tree, tree, tree, tree, int));
+static tree build_vec_delete_1 PARAMS ((tree, tree, tree, tree, int));
+static void perform_member_init PARAMS ((tree, tree, tree, int));
+static void sort_base_init PARAMS ((tree, tree *, tree *));
+static tree build_builtin_delete_call PARAMS ((tree));
+static int member_init_ok_or_else PARAMS ((tree, tree, const char *));
+static void expand_virtual_init PARAMS ((tree, tree));
+static tree sort_member_init PARAMS ((tree));
+static tree initializing_context PARAMS ((tree));
+static tree build_java_class_ref PARAMS ((tree));
+static void expand_cleanup_for_base PARAMS ((tree, tree));
+static tree get_temp_regvar PARAMS ((tree, tree));
+static tree dfs_initialize_vtbl_ptrs PARAMS ((tree, void *));
/* 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);
+ BI_header_type = make_aggr_type (RECORD_TYPE);
+ 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
- virtual function table pointers, except those that come from
- virtual base classes. Initialize binfo's vtable pointer, if
- INIT_SELF is true. CAN_ELIDE is true when we know that all virtual
- function table pointers in all bases have been initialized already,
- probably because their constructors have just be run. ADDR is the
- pointer to the object whos vtables we are going to initialize.
+/* Called from initialize_vtbl_ptrs via dfs_walk. */
+
+static tree
+dfs_initialize_vtbl_ptrs (binfo, data)
+ tree binfo;
+ void *data;
+{
+ if (!BINFO_PRIMARY_MARKED_P (binfo)
+ && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+ {
+ tree base_ptr = TREE_VALUE ((tree) data);
+
+ if (TREE_VIA_VIRTUAL (binfo))
+ base_ptr = convert_pointer_to_vbase (BINFO_TYPE (binfo),
+ base_ptr);
+ else
+ base_ptr
+ = build_vbase_path (PLUS_EXPR,
+ build_pointer_type (BINFO_TYPE (binfo)),
+ base_ptr,
+ binfo,
+ /*nonnull=*/1);
- REAL_BINFO is usually the same as BINFO, except when addr is not of
- pointer to the type of the real derived type that we want to
- initialize for. This is the case when addr is a pointer to a sub
- object of a complete object, and we only want to do part of the
- complete object's initialization of vtable pointers. This is done
- for all virtual table pointers in virtual base classes. REAL_BINFO
- is used to find the BINFO_VTABLE that we initialize with. BINFO is
- used for conversions of addr to subobjects.
+ expand_virtual_init (binfo, base_ptr);
+ }
- BINFO_TYPE (real_binfo) must be BINFO_TYPE (binfo).
+ SET_BINFO_MARKED (binfo);
+
+ return NULL_TREE;
+}
- Relies upon binfo being inside TYPE_BINFO (TREE_TYPE (TREE_TYPE
- (addr))). */
+/* Initialize all the vtable pointers for the hierarchy dominated by
+ TYPE. */
void
-expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
- tree real_binfo, binfo, addr;
- int init_self, can_elide;
+initialize_vtbl_ptrs (type, addr)
+ tree type;
+ tree addr;
{
- tree real_binfos = BINFO_BASETYPES (real_binfo);
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = real_binfos ? TREE_VEC_LENGTH (real_binfos) : 0;
-
- for (i = 0; i < n_baselinks; i++)
- {
- tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable
- = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
- if (! TREE_VIA_VIRTUAL (real_base_binfo))
- expand_direct_vtbls_init (real_base_binfo, base_binfo,
- is_not_base_vtable, can_elide, addr);
- }
-#if 0
- /* Before turning this on, make sure it is correct. */
- if (can_elide && ! BINFO_MODIFIED (binfo))
- return;
-#endif
- /* Should we use something besides CLASSTYPE_VFIELDS? */
- if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (real_binfo)))
- {
- tree base_ptr = convert_pointer_to_real (binfo, addr);
- expand_virtual_init (real_binfo, base_ptr);
- }
+ tree list = build_tree_list (type, addr);
+
+ /* Walk through the hierarchy, initializing the vptr in each base
+ class. We do these in pre-order because under the new ABI we
+ can't find the virtual bases for a class until we've initialized
+ the vtbl for that class. */
+ dfs_walk_real (TYPE_BINFO (type), dfs_initialize_vtbl_ptrs,
+ NULL, dfs_unmarked_real_bases_queue_p, list);
+ dfs_walk (TYPE_BINFO (type), dfs_unmark,
+ dfs_marked_real_bases_queue_p, type);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (type))
+ expand_indirect_vtbls_init (TYPE_BINFO (type), addr);
}
+
\f
/* 348 - 351 */
/* Subroutine of emit_base_init. */
tree decl;
tree type = TREE_TYPE (member);
- expand_start_target_temps ();
-
decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
+ if (decl == error_mark_node)
+ return;
+
/* Deal with this here, as we will get confused if we try to call the
assignment op for an anonymous union. This can happen in a
synthesized copy constructor. */
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)))
/* Since `init' is already a TREE_LIST on the current_member_init_list,
only build it into one if we aren't already a list. */
if (init != NULL_TREE && TREE_CODE (init) != TREE_LIST)
- init = build_expr_list (NULL_TREE, init);
+ init = build_tree_list (NULL_TREE, init);
if (explicit
&& TREE_CODE (type) == ARRAY_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
{
{
/* default-initialization. */
if (AGGREGATE_TYPE_P (type))
- init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
- else if (TREE_CODE (type) == REFERENCE_TYPE)
{
- cp_error ("default-initialization of `%#D', which has reference type",
- member);
- init = error_mark_node;
+ /* This is a default initialization of an aggregate,
+ but not one of non-POD class type. We cleverly
+ notice that the initialization rules in such a
+ case are the same as for initialization with an
+ empty brace-initialization list. We don't want
+ to call build_modify_expr as that will go looking
+ for constructors and such. */
+ tree e = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+ TREE_SIDE_EFFECTS (e) = 1;
+ 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",
+ member);
else
init = integer_zero_node;
}
init = TREE_VALUE (init);
}
- /* We only build this with a null init if we got it from the
- current_member_init_list. */
- if (init || explicit)
- {
- expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
- }
+ if (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);
}
}
this constructor is the top-level constructor called. */
if (TREE_VIA_VIRTUAL (binfo))
{
- tree v = CLASSTYPE_VBASECLASSES (t);
- while (BINFO_TYPE (v) != BINFO_TYPE (binfo))
- v = TREE_CHAIN (v);
-
+ tree v = BINFO_FOR_VBASE (BINFO_TYPE (binfo), t);
vbases = tree_cons (v, TREE_VALUE (x), vbases);
continue;
}
Note that emit_base_init does *not* initialize virtual base
classes. That is done specially, elsewhere. */
-extern tree base_init_expr, rtl_expr_chain;
-
-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))
{
tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
-
- expand_start_cond (first_arg, 0);
- expand_aggr_vbase_init (t_binfo, current_class_ref, current_class_ptr,
- vbase_init_list, first_arg);
- expand_end_cond ();
+ construct_virtual_bases (t, current_class_ref, current_class_ptr,
+ vbase_init_list, first_arg);
}
/* Now, perform initialization of non-virtual base classes. */
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);
rbase_init_list = TREE_CHAIN (rbase_init_list);
}
- /* Initialize all the virtual function table fields that
- do come from virtual base classes. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (t))
- expand_indirect_vtbls_init (t_binfo, current_class_ref, current_class_ptr);
-
- /* Initialize all the virtual function table fields that
- do not come from virtual base classes. */
- expand_direct_vtbls_init (t_binfo, t_binfo, 1, 1, current_class_ptr);
+ /* Initialize the vtable pointers for the class. */
+ initialize_vtbl_ptrs (t, current_class_ptr);
for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member))
{
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
- an assignment to `this'. */
+ an assignment to `this'. Called only when such an assignment
+ is actually noted. */
void
check_base_init (t)
tree vtbl, vtbl_ptr;
tree vtype, vtype_binfo;
- /* This code is crusty. Should be simple, like:
- vtbl = BINFO_VTABLE (binfo);
- */
- vtype = DECL_CONTEXT (CLASSTYPE_VFIELD (type));
+ /* Compute the location of the vtable. */
+ 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));
- assemble_external (vtbl);
- TREE_USED (vtbl) = 1;
- vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
+ vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo));
+
+ if (TREE_CODE (vtbl) == VAR_DECL)
+ {
+ assemble_external (vtbl);
+ TREE_USED (vtbl) = 1;
+ vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
+ }
+ else
+ /* Under the new ABI, secondary vtables are stored with the
+ primary vtable. So, the BINFO_VTABLE may be an expression for
+ computing the secondary vtable, rather than the secondary
+ vtable itself. */
+ my_friendly_assert (merge_primary_and_secondary_vtables_p (),
+ 20000220);
+
+ /* Under the new ABI, we need to point into the middle of the
+ vtable. */
+ if (vbase_offsets_in_vtable_p ())
+ vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
+ size_extra_vtbl_entries (binfo));
+
+ /* Compute the location of the vtpr. */
decl = convert_pointer_to_real (vtype_binfo, decl);
vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL_PTR), vtype);
if (vtbl_ptr == error_mark_node)
return;
- /* Have to convert VTBL since array sizes may be different. */
+ /* Assign the vtable to the vptr. */
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,
- build_expr_list (NULL_TREE, integer_zero_node)));
+ build_tree_list (NULL_TREE, integer_zero_node)));
if (flag)
expr = fold (build (COND_EXPR, void_type_node,
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 ();
}
-/* Initialize this object's virtual base class pointers. This must be
- done only at the top-level of the object being constructed.
-
- INIT_LIST is list of initialization for constructor to perform. */
+/* Construct the virtual base-classes of THIS_REF (whose address is
+ THIS_PTR). The object has the indicated TYPE. The construction
+ actually takes place only if FLAG is non-zero. INIT_LIST is list
+ of initializations for constructors to perform. */
static void
-expand_aggr_vbase_init (binfo, exp, addr, init_list, flag)
- tree binfo;
- tree exp;
- tree addr;
+construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
+ tree type;
+ tree this_ref;
+ tree this_ptr;
tree init_list;
tree flag;
{
- tree type = BINFO_TYPE (binfo);
+ tree vbases;
- if (TYPE_USES_VIRTUAL_BASECLASSES (type))
+ /* 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. */
+ if (!vbase_offsets_in_vtable_p ())
{
- tree result = init_vbase_pointers (type, addr);
- tree vbases;
+ tree if_stmt;
+ tree result;
+ 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));
-
- for (vbases = CLASSTYPE_VBASECLASSES (type); vbases;
- vbases = TREE_CHAIN (vbases))
- {
- tree tmp = purpose_member (vbases, result);
- expand_aggr_vbase_init_1 (vbases, exp,
- TREE_OPERAND (TREE_VALUE (tmp), 0),
- init_list);
- expand_cleanup_for_base (vbases, flag);
- }
+ 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 inner_if_stmt;
+ tree compound_stmt;
+ tree exp;
+
+ /* 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
+ period during which the cleanups must occur) begin from the time
+ the construction is complete to the end of the function. If we
+ create a conditional block in which to initialize the
+ base-classes, then the cleanup region for the virtual base begins
+ inside a block, and ends outside of that block. This situation
+ confuses the sjlj exception-handling code. Therefore, we do not
+ create a single conditional block, but one for each
+ initialization. (That way the cleanup regions always begin
+ 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. */
+ inner_if_stmt = begin_if_stmt ();
+ finish_if_stmt_cond (flag, inner_if_stmt);
+ compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
+
+ /* Compute the location of the virtual base. If we're
+ constructing virtual bases, then we must be the most derived
+ class. Therefore, we don't have to look up the virtual base;
+ we already know where it is. */
+ exp = build (PLUS_EXPR,
+ TREE_TYPE (this_ptr),
+ this_ptr,
+ BINFO_OFFSET (vbases));
+ exp = build1 (NOP_EXPR,
+ build_pointer_type (BINFO_TYPE (vbases)),
+ exp);
+
+ expand_aggr_vbase_init_1 (vbases, this_ref, exp, init_list);
+ finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+ finish_then_clause (inner_if_stmt);
+ finish_if_stmt ();
+
+ expand_cleanup_for_base (vbases, flag);
}
}
&& ! current_template_parms
&& ! vec_binfo_member (basetype,
TYPE_BINFO_BASETYPES (type))
- && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
+ && ! BINFO_FOR_VBASE (basetype, type))
{
if (IDENTIFIER_CLASS_VALUE (name))
goto try_member;
}
}
+/* 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.
If `init' is a CONSTRUCTOR, then we emit a warning message,
explaining that such initializations are invalid.
- ALIAS_THIS is nonzero iff we are initializing something which is
- essentially an alias for current_class_ref. In this case, the base
- constructor may move it on us, and we must keep track of such
- deviations.
-
If INIT resolves to a CALL_EXPR which happens to return
something of the type we are looking for, then we know
that we can safely use that call to perform the
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
to run a new constructor; and catching an exception, where we
have already built up the constructor call so we could wrap it
in an exception region. */;
+ else if (TREE_CODE (init) == CONSTRUCTOR)
+ /* A brace-enclosed initializer has whatever type is
+ required. There's no need to convert it. */
+ ;
else
init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
else
init = build (INIT_EXPR, TREE_TYPE (exp), exp, init);
TREE_SIDE_EFFECTS (init) = 1;
- expand_expr_stmt (init);
+ finish_expr_stmt (init);
return;
}
init = TREE_VALUE (parms);
}
else
- parms = build_expr_list (NULL_TREE, init);
+ parms = build_tree_list (NULL_TREE, init);
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
from TRUE_EXP. In constructors, we don't know anything about
the value being initialized.
- ALIAS_THIS serves the same purpose it serves for expand_aggr_init.
-
FLAGS is just passes to `build_method_call'. See that function for
its description. */
&& 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;
}
else
return NULL_TREE;
}
-
+
\f
/* This code could just as well go in `class.c', but is placed here for
modularity. */
/* The code in instantiate_type which will process this
expects to encounter OVERLOADs, not raw functions. */
t = ovl_cons (t, NULL_TREE);
-
+
return build (OFFSET_REF,
unknown_type_node,
decl,
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);
}
if (BASELINK_P (member))
{
- cp_pedwarn ("assuming & on overloaded member function");
+ if (! flag_ms_extensions)
+ cp_pedwarn ("assuming & on overloaded member function");
return build_unary_op (ADDR_EXPR, exp, 0);
}
if (TREE_CODE (TREE_TYPE (member)) == METHOD_TYPE)
{
- cp_pedwarn ("assuming & on `%E'", member);
+ if (! flag_ms_extensions)
+ cp_pedwarn ("assuming & on `%E'", member);
return build_unary_op (ADDR_EXPR, exp, 0);
}
basetype = DECL_CONTEXT (member);
base = current_class_ptr;
-
+
if (get_base_distance (basetype, TREE_TYPE (TREE_TYPE (base)), 0, &basetype_path) < 0)
{
error_not_base_type (basetype, TREE_TYPE (TREE_TYPE (base)));
basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member)));
addr = convert_pointer_to (basetype, addr);
member = cp_convert (ptrdiff_type_node, member);
-
+
/* Pointer to data members are offset by one, so that a null
pointer with a real value of 0 is distinguishable from an
offset of the first member of a structure. */
{
mark_used (global_delete_fndecl);
return build_call (global_delete_fndecl,
- void_type_node, build_expr_list (NULL_TREE, addr));
+ void_type_node, build_tree_list (NULL_TREE, addr));
}
\f
/* Generate a C++ "new" expression. DECL is either a TREE_LIST
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)
{
if (processing_template_decl)
{
if (has_array)
- t = min_tree_cons (min_tree_cons (NULL_TREE, type, NULL_TREE),
- build_min_nt (ARRAY_REF, NULL_TREE, nelts),
- NULL_TREE);
+ t = tree_cons (tree_cons (NULL_TREE, type, NULL_TREE),
+ build_min_nt (ARRAY_REF, NULL_TREE, nelts),
+ NULL_TREE);
else
t = type;
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_obstacks_nochange ();
- end_temporary_allocation ();
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;
}
return error_mark_node;
}
- if (TYPE_LANG_SPECIFIC (true_type)
- && CLASSTYPE_ABSTRACT_VIRTUALS (true_type))
- {
- abstract_virtuals_error (NULL_TREE, true_type);
- return error_mark_node;
- }
+ if (abstract_virtuals_error (NULL_TREE, true_type))
+ return error_mark_node;
- if (TYPE_LANG_SPECIFIC (true_type) && IS_SIGNATURE (true_type))
- {
- signature_error (NULL_TREE, true_type);
- return error_mark_node;
- }
-
/* When we allocate an array, and the corresponding deallocation
function takes a second argument of type size_t, and that's the
"usual deallocation function", we allocate some extra space at
&& 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,
- build_expr_list (NULL_TREE, rval)));
+ (tree_cons (NULL_TREE, exp1,
+ build_tree_list (NULL_TREE, rval)));
}
if (rval == error_mark_node)
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 = NULL_TREE;
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
+ 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
- expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0);
+ {
+ 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
{
passed_auto_delete = auto_delete;
expr = build_method_call
- (ref, dtor_identifier, build_expr_list (NULL_TREE, passed_auto_delete),
+ (ref, dtor_identifier, build_tree_list (NULL_TREE, passed_auto_delete),
NULL_TREE, flags);
if (do_delete)
cond = NULL_TREE;
if (cond)
- exprstmt = build_expr_list (NULL_TREE, cond);
+ exprstmt = build_tree_list (NULL_TREE, cond);
if (base_binfo
&& ! TREE_VIA_VIRTUAL (base_binfo)
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);
+ build_tree_list (NULL_TREE, this_auto_delete));
+ exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
/* Take care of the remaining baseclasses. */
expr = build_scoped_method_call
(ref, base_binfo, dtor_identifier,
- build_expr_list (NULL_TREE, integer_zero_node));
+ build_tree_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);
}