/* 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 "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;
-
-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 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);
+
+ expand_virtual_init (binfo, base_ptr);
+ }
- 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.
+ SET_BINFO_MARKED (binfo);
- BINFO_TYPE (real_binfo) must be BINFO_TYPE (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
{
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);
}
}
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;
-
-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);
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
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 ();
}
/* 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 initialization for constructor to perform. */
+ of initializations for constructors to perform. */
static void
construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
tree flag;
{
tree vbases;
- tree result;
/* 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);
- result = init_vbase_pointers (type, this_ptr);
- if (result)
- expand_expr_stmt (build_compound_expr (result));
- expand_end_cond ();
+ if (!vbase_offsets_in_vtable_p ())
+ {
+ 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)
+ 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;
+ 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
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);
- expand_aggr_vbase_init_1 (vbases, this_ref,
- TREE_OPERAND (TREE_VALUE (tmp), 0),
- init_list);
- expand_end_cond ();
+ 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
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;
}
&& 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);
}