/* Handle initialization things in C++.
- Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-98, 1999 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"
-
-extern void compiler_error ();
-
-/* In C++, structures with well-defined constructors are initialized by
- those constructors, unasked. CURRENT_BASE_INIT_LIST
- holds a list of stmts for a BASE_INIT term in the grammar.
- This list has one element for each base class which must be
- initialized. The list elements are [basename, init], with
- type basetype. This allows the possibly anachronistic form
- (assuming d : a, b, c) "d (int a) : c(a+5), b (a-4), a (a+3)"
- where each successive term can be handed down the constructor
- line. Perhaps this was not intended. */
-tree current_base_init_list, current_member_init_list;
+#include "ggc.h"
static void expand_aggr_vbase_init_1 PROTO((tree, tree, tree, tree));
-static void expand_aggr_vbase_init PROTO((tree, tree, tree, tree));
-static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int,
- int));
-static void expand_default_init PROTO((tree, tree, tree, tree, int,
- int));
-static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, tree,
- int));
+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, 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 tree build_array_eh_cleanup PROTO((tree, tree, tree));
-static int member_init_ok_or_else PROTO((tree, tree, char *));
+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 build_partial_cleanup_for PROTO((tree));
static tree initializing_context PROTO((tree));
-
-/* Cache the identifier nodes for the magic field of a new cookie. */
-static tree nc_nelts_field_id;
-
-static tree minus_one;
+static tree build_java_class_ref PROTO((tree));
+static void expand_cleanup_for_base PROTO((tree, tree));
+static tree get_temp_regvar PROTO((tree, tree));
/* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */
{
tree fields[1];
- minus_one = build_int_2 (-1, -1);
+ minus_one_node = build_int_2 (-1, -1);
/* Define the structure that holds header information for
arrays allocated via operator new. */
BI_header_type = make_lang_type (RECORD_TYPE);
- nc_nelts_field_id = get_identifier ("nelts");
- fields[0] = build_lang_field_decl (FIELD_DECL, nc_nelts_field_id, sizetype);
+ nelts_identifier = get_identifier ("nelts");
+ fields[0] = build_lang_decl (FIELD_DECL, nelts_identifier, sizetype);
+
+ /* Use the biggest alignment supported by the target to prevent operator
+ new from returning misaligned pointers. */
+ TYPE_ALIGN (BI_header_type) = BIGGEST_ALIGNMENT;
finish_builtin_type (BI_header_type, "__new_cookie", fields,
- 0, double_type_node);
+ 0, BI_header_type);
BI_header_size = size_in_bytes (BI_header_type);
+
+ ggc_add_tree_root (&BI_header_type, 1);
+ ggc_add_tree_root (&BI_header_size, 1);
}
/* Subroutine of emit_base_init. For BINFO, initialize all the
tree decl;
tree type = TREE_TYPE (member);
- expand_start_target_temps ();
+ decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
- if (TYPE_NEEDS_CONSTRUCTING (type)
- || (init && TYPE_HAS_CONSTRUCTOR (type)))
+ /* 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));
+ 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);
- decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
-
if (explicit
&& TREE_CODE (type) == ARRAY_TYPE
&& init != NULL_TREE
&& 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, 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)
- {
- decl = build_component_ref (current_class_ref, name, NULL_TREE,
- 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);
}
}
continue;
name = TREE_PURPOSE (x);
-#if 0
- /* This happens in templates, since the IDENTIFIER is replaced
- with the COMPONENT_REF in tsubst_expr. */
- field = (TREE_CODE (name) == COMPONENT_REF
- ? TREE_OPERAND (name, 1) : IDENTIFIER_CLASS_VALUE (name));
-#else
- /* Let's find out when this happens. */
- my_friendly_assert (TREE_CODE (name) != COMPONENT_REF, 348);
- field = IDENTIFIER_CLASS_VALUE (name);
-#endif
+ if (TREE_CODE (name) == IDENTIFIER_NODE)
+ field = IDENTIFIER_CLASS_VALUE (name);
+ else
+ {
+ my_friendly_assert (TREE_CODE (name) == FIELD_DECL, 348);
+ field = name;
+ }
/* If one member shadows another, get the outermost one. */
if (TREE_CODE (field) == TREE_LIST)
*vbase_ptr = vbases;
}
-/* Perform partial cleanups for a base for exception handling. */
-
-static tree
-build_partial_cleanup_for (binfo)
- tree binfo;
-{
- return build_scoped_method_call
- (current_class_ref, binfo, dtor_identifier,
- build_expr_list (NULL_TREE, integer_zero_node));
-}
-
/* Perform whatever initializations have yet to be done on the base
class of the class variable. These actions are in the global
variable CURRENT_BASE_INIT_LIST. Such an action could be
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);
- 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 (TREE_VIA_VIRTUAL (base_binfo))
continue;
-#if 0 /* Once unsharing happens soon enough. */
- my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo, 999);
-#else
- BINFO_INHERITANCE_CHAIN (base_binfo) = t_binfo;
-#endif
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo,
+ 999);
if (TREE_PURPOSE (rbase_init_list))
init = TREE_VALUE (rbase_init_list);
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,
- BINFO_OFFSET_ZEROP (base_binfo), LOOKUP_NORMAL);
-
- expand_end_target_temps ();
- free_temp_slots ();
- }
-
- if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
- {
- tree expr;
-
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
- expr = build_partial_cleanup_for (base_binfo);
- pop_obstacks ();
- add_partial_entry (expr);
+ LOOKUP_NORMAL);
}
+ expand_cleanup_for_base (base_binfo, NULL_TREE);
rbase_init_list = TREE_CHAIN (rbase_init_list);
}
init = TREE_VALUE (mem_init_list);
from_init_list = 1;
-#if 0
- if (TREE_CODE (name) == COMPONENT_REF)
- name = DECL_NAME (TREE_OPERAND (name, 1));
-#else
- /* Also see if it's ever a COMPONENT_REF here. If it is, we
- need to do `expand_assignment (name, init, 0, 0);' and
- a continue. */
- my_friendly_assert (TREE_CODE (name) != COMPONENT_REF, 349);
-#endif
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE
+ || TREE_CODE (name) == FIELD_DECL, 349);
}
else
{
{
name = TREE_PURPOSE (mem_init_list);
init = TREE_VALUE (mem_init_list);
- /* XXX: this may need the COMPONENT_REF operand 0 check if
- it turns out we actually get them. */
- field = IDENTIFIER_CLASS_VALUE (name);
+
+ if (TREE_CODE (name) == IDENTIFIER_NODE)
+ field = IDENTIFIER_CLASS_VALUE (name);
+ else
+ field = name;
/* If one member shadows another, get the outermost one. */
if (TREE_CODE (field) == TREE_LIST)
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)
/* This code is crusty. Should be simple, like:
vtbl = BINFO_VTABLE (binfo);
*/
- vtype = DECL_CONTEXT (CLASSTYPE_VFIELD (type));
+ vtype = DECL_CONTEXT (TYPE_VFIELD (type));
vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0);
- vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)), binfo));
+ vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo));
assemble_external (vtbl);
TREE_USED (vtbl) = 1;
vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
/* Have to convert VTBL since array sizes may be different. */
vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
- expand_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
+ finish_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
+}
+
+/* If an exception is thrown in a constructor, those base classes already
+ constructed must be destroyed. This function creates the cleanup
+ for BINFO, which has just been constructed. If FLAG is non-NULL,
+ it is a DECL which is non-zero when this base needs to be
+ destroyed. */
+
+static void
+expand_cleanup_for_base (binfo, flag)
+ tree binfo;
+ tree flag;
+{
+ tree expr;
+
+ if (!TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo)))
+ return;
+
+ /* Call the destructor. */
+ expr = (build_scoped_method_call
+ (current_class_ref, binfo, dtor_identifier,
+ build_expr_list (NULL_TREE, integer_zero_node)));
+ if (flag)
+ expr = fold (build (COND_EXPR, void_type_node,
+ truthvalue_conversion (flag),
+ expr, integer_zero_node));
+
+ 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, 0, LOOKUP_COMPLAIN);
-
- expand_end_target_temps ();
- free_temp_slots ();
+ expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
}
-/* 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 initialization for constructor to perform. */
static void
-expand_aggr_vbase_init (binfo, exp, addr, init_list)
- 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);
-
- if (TYPE_USES_VIRTUAL_BASECLASSES (type))
- {
- tree result = init_vbase_pointers (type, addr);
- tree vbases;
-
- 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);
- }
+ tree vbases;
+ tree result;
+ tree if_stmt;
+
+ /* If there are no virtual baseclasses, we shouldn't even be here. */
+ my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621);
+
+ /* First set the pointers in our object that tell us where to find
+ our virtual baseclasses. */
+ 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;
+
+ /* 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);
+ expand_aggr_vbase_init_1 (vbases, this_ref,
+ TREE_OPERAND (TREE_VALUE (tmp), 0),
+ 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);
}
}
/* Anonymous union members can be initialized in the first enclosing
non-anonymous union context. */
- while (t && ANON_UNION_TYPE_P (t))
+ while (t && ANON_AGGR_TYPE_P (t))
t = TYPE_CONTEXT (t);
return t;
}
member_init_ok_or_else (field, type, member_name)
tree field;
tree type;
- char *member_name;
+ const char *member_name;
{
if (field == error_mark_node)
return 0;
if (name && TREE_CODE (name) == TYPE_DECL)
{
- basetype = TREE_TYPE (name);
+ basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
name = DECL_NAME (name);
}
}
}
+/* We are about to generate some complex initialization code.
+ Conceptually, it is all a single expression. However, we may want
+ to include conditionals, loops, and other such statement-level
+ constructs. Therefore, we build the initialization code inside a
+ statement-expression. This function starts such an expression.
+ STMT_EXPR_P and COMPOUND_STMT_P are filled in by this function;
+ pass them back to finish_init_stmts when the expression is
+ complete. */
+
+void
+begin_init_stmts (stmt_expr_p, compound_stmt_p)
+ tree *stmt_expr_p;
+ tree *compound_stmt_p;
+{
+ *stmt_expr_p = begin_stmt_expr ();
+ *compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
+}
+
+/* Finish out the statement-expression begun by the previous call to
+ begin_init_stmts. Returns the statement-expression itself. */
+
+tree
+finish_init_stmts (stmt_expr, compound_stmt)
+ tree stmt_expr;
+ tree compound_stmt;
+{
+ finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+ stmt_expr = finish_stmt_expr (stmt_expr);
+
+ /* To avoid spurious warnings about unused values, we set
+ TREE_USED. */
+ if (stmt_expr)
+ TREE_USED (stmt_expr) = 1;
+
+ return stmt_expr;
+}
+
/* This is like `expand_member_init', only it stores one aggregate
value into another.
A constructor or a conversion operator may have to be used to
perform the initialization, but not both, as it would be ambiguous. */
-void
-expand_aggr_init (exp, init, alias_this, flags)
+tree
+build_aggr_init (exp, init, flags)
tree exp, init;
- int alias_this;
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;
/* Must arrange to initialize each element of EXP
from elements of INIT. */
tree itype = init ? TREE_TYPE (init) : NULL_TREE;
- if (TYPE_READONLY (TREE_TYPE (type)) || TYPE_VOLATILE (TREE_TYPE (type)))
+ if (CP_TYPE_QUALS (type) != TYPE_UNQUALIFIED)
{
TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
if (init)
}
*/
error ("bad array initializer");
- return;
+ return error_mark_node;
}
- expand_vec_init (exp, exp, array_type_nelts (type), init,
- init && comptypes (TREE_TYPE (init), TREE_TYPE (exp), 1));
+ 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, alias_this, LOOKUP_NORMAL|flags);
+ 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
-expand_default_init (binfo, true_exp, exp, init, alias_this, flags)
+expand_default_init (binfo, true_exp, exp, init, flags)
tree binfo;
tree true_exp, exp;
tree init;
- int alias_this;
int flags;
{
tree type = TREE_TYPE (exp);
if (true_exp != exp)
abort ();
- /* We special-case TARGET_EXPRs here to avoid an error about
- private copy constructors for temporaries bound to reference vars.
- If the TARGET_EXPR represents a call to a function that has
- permission to create such objects, a reference can bind directly
- to the return value. An object variable must be initialized
- via the copy constructor, even if the call is elided. */
- if (! (TREE_CODE (exp) == VAR_DECL && DECL_ARTIFICIAL (exp)
- && TREE_CODE (init) == TARGET_EXPR && TREE_TYPE (init) == type))
+ if (flags & DIRECT_BIND)
+ /* Do nothing. We hit this in two cases: Reference initialization,
+ where we aren't initializing a real variable, so we don't want
+ 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);
if (TREE_CODE (init) == TRY_CATCH_EXPR)
else
init = build (INIT_EXPR, TREE_TYPE (exp), exp, init);
TREE_SIDE_EFFECTS (init) = 1;
- expand_expr_stmt (init);
+ finish_expr_stmt (init);
return;
}
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
if (true_exp == exp)
- parms = expr_tree_cons (NULL_TREE, integer_one_node, parms);
+ parms = tree_cons (NULL_TREE, integer_one_node, parms);
else
- parms = expr_tree_cons (NULL_TREE, integer_zero_node, parms);
+ parms = tree_cons (NULL_TREE, integer_zero_node, parms);
flags |= LOOKUP_HAS_IN_CHARGE;
}
rval = build_method_call (exp, ctor_identifier,
parms, binfo, flags);
if (TREE_SIDE_EFFECTS (rval))
- expand_expr_stmt (rval);
+ finish_expr_stmt (rval);
}
/* This function is responsible for initializing EXP with INIT
its description. */
static void
-expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
+expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
tree binfo;
tree true_exp, exp;
tree init;
- int alias_this;
int flags;
{
tree type = TREE_TYPE (exp);
&& 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;
}
/* We know that expand_default_init can handle everything we want
at this point. */
- expand_default_init (binfo, true_exp, exp, init, alias_this, flags);
+ expand_default_init (binfo, true_exp, exp, init, flags);
}
/* Report an error if NAME is not the name of a user-defined,
tree t;
tree method_name;
int dtor = 0;
- int dont_use_this = 0;
tree basetype_path, decl;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR
{
/* 'name' already refers to the decls from the namespace, since we
hit do_identifier for template_ids. */
- my_friendly_assert (is_overloaded_fn (TREE_OPERAND (name, 0)), 980519);
+ method_name = TREE_OPERAND (name, 0);
+ /* FIXME: Since we don't do independent names right yet, the
+ name might also be a LOOKUP_EXPR. Once we resolve this to a
+ real decl earlier, this can go. This may happen during
+ tsubst'ing. */
+ if (TREE_CODE (method_name) == LOOKUP_EXPR)
+ {
+ method_name = lookup_namespace_name
+ (type, TREE_OPERAND (method_name, 0));
+ TREE_OPERAND (name, 0) = method_name;
+ }
+ my_friendly_assert (is_overloaded_fn (method_name), 980519);
return build_x_function_call (name, parmlist, current_class_ref);
}
return build_x_function_call (lookup_namespace_name (type, name),
parmlist, current_class_ref);
- if (TREE_CODE (name) != TEMPLATE_ID_EXPR)
- method_name = name;
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+ {
+ method_name = TREE_OPERAND (name, 0);
+ if (TREE_CODE (method_name) == COMPONENT_REF)
+ method_name = TREE_OPERAND (method_name, 1);
+ if (is_overloaded_fn (method_name))
+ method_name = DECL_NAME (OVL_CURRENT (method_name));
+ TREE_OPERAND (name, 0) = method_name;
+ }
else
- method_name = TREE_OPERAND (name, 0);
+ method_name = name;
if (TREE_CODE (method_name) == BIT_NOT_EXPR)
{
return error_mark_node;
}
- /* No object? Then just fake one up, and let build_method_call
- figure out what to do. */
- if (current_class_type == 0
- || get_base_distance (type, current_class_type, 0, &basetype_path) == -1)
- dont_use_this = 1;
+ decl = maybe_dummy_object (type, &basetype_path);
- if (dont_use_this)
- {
- basetype_path = TYPE_BINFO (type);
- decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
- }
- else if (current_class_ptr == 0)
- {
- dont_use_this = 1;
- decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
- }
- else
+ /* Convert 'this' to the specified type to disambiguate conversion
+ to the function's context. Apparently Standard C++ says that we
+ shouldn't do this. */
+ if (decl == current_class_ref
+ && ! pedantic
+ && ACCESSIBLY_UNIQUELY_DERIVED_P (type, current_class_type))
{
tree olddecl = current_class_ptr;
tree oldtype = TREE_TYPE (TREE_TYPE (olddecl));
if (oldtype != type)
{
- tree newtype = build_type_variant (type, TYPE_READONLY (oldtype),
- TYPE_VOLATILE (oldtype));
+ tree newtype = build_qualified_type (type, TYPE_QUALS (oldtype));
decl = convert_force (build_pointer_type (newtype), olddecl, 0);
+ decl = build_indirect_ref (decl, NULL_PTR);
}
- else
- decl = olddecl;
}
- decl = build_indirect_ref (decl, NULL_PTR);
-
if (method_name == constructor_name (type)
|| method_name == constructor_name_full (type))
return build_functional_cast (type, parmlist);
- if ((t = lookup_fnfields (basetype_path, method_name, 0)))
+ if (lookup_fnfields (basetype_path, method_name, 0))
return build_method_call (decl,
TREE_CODE (name) == TEMPLATE_ID_EXPR
? name : method_name,
return error_mark_node;
if (TREE_CODE (t) == FIELD_DECL)
{
- if (dont_use_this)
+ if (is_dummy_object (decl))
{
cp_error ("invalid use of non-static field `%D'", t);
return error_mark_node;
build_offset_ref (type, name)
tree type, name;
{
- tree decl, fnfields, fields, t = error_mark_node;
+ tree decl, t = error_mark_node;
+ tree member;
tree basebinfo = NULL_TREE;
tree orig_name = name;
name = ctor_identifier;
#endif
- if (TYPE_SIZE (complete_type (type)) == 0)
+ if (TYPE_SIZE (complete_type (type)) == 0
+ && !TYPE_BEING_DEFINED (type))
{
- if (type == current_class_type)
- t = IDENTIFIER_CLASS_VALUE (name);
- else
- t = NULL_TREE;
- if (t == 0)
- {
- cp_error ("incomplete type `%T' does not have member `%D'", type,
- name);
- return error_mark_node;
- }
- if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == VAR_DECL
- || TREE_CODE (t) == CONST_DECL)
- {
- mark_used (t);
- return t;
- }
- if (TREE_CODE (t) == FIELD_DECL)
- sorry ("use of member in incomplete aggregate type");
- else if (TREE_CODE (t) == FUNCTION_DECL)
- sorry ("use of member function in incomplete aggregate type");
- else
- my_friendly_abort (52);
+ cp_error ("incomplete type `%T' does not have member `%D'", type,
+ name);
return error_mark_node;
}
- if (current_class_type == 0
- || get_base_distance (type, current_class_type, 0, &basebinfo) == -1)
- {
- basebinfo = TYPE_BINFO (type);
- decl = build1 (NOP_EXPR, type, error_mark_node);
- }
- else if (current_class_ptr == 0)
- decl = build1 (NOP_EXPR, type, error_mark_node);
- else
- decl = current_class_ref;
+ decl = maybe_dummy_object (type, &basebinfo);
- fnfields = lookup_fnfields (basebinfo, name, 1);
- fields = lookup_field (basebinfo, name, 0, 0);
+ member = lookup_member (basebinfo, name, 1, 0);
- if (fields == error_mark_node || fnfields == error_mark_node)
+ if (member == error_mark_node)
return error_mark_node;
/* A lot of this logic is now handled in lookup_field and
lookup_fnfield. */
- if (fnfields)
+ if (member && BASELINK_P (member))
{
- extern int flag_save_memoized_contexts;
-
/* Go from the TREE_BASELINK to the member function info. */
+ tree fnfields = member;
t = TREE_VALUE (fnfields);
if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
t = ovl_cons (t, NULL_TREE);
return build (OFFSET_REF,
- build_offset_type (type, unknown_type_node),
+ unknown_type_node,
decl,
build (TEMPLATE_ID_EXPR,
TREE_TYPE (t),
if (!really_overloaded_fn (t))
{
- tree access;
-
/* Get rid of a potential OVERLOAD around it */
t = OVL_CURRENT (t);
/* unique functions are handled easily. */
basebinfo = TREE_PURPOSE (fnfields);
- access = compute_access (basebinfo, t);
- if (access == access_protected_node)
- {
- cp_error_at ("member function `%#D' is protected", t);
- error ("in this context");
- return error_mark_node;
- }
- if (access == access_private_node)
- {
- cp_error_at ("member function `%#D' is private", t);
- error ("in this context");
- return error_mark_node;
- }
+ if (!enforce_access (basebinfo, t))
+ return error_mark_node;
mark_used (t);
+ if (DECL_STATIC_FUNCTION_P (t))
+ return t;
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 (either for memoization
- or 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)
- && ((flag_save_memoized_contexts && toplevel_bindings_p ())
- || ! allocation_temporary_p ()))
- fnfields = copy_list (fnfields);
-
- t = build_tree_list (error_mark_node, fnfields);
- TREE_TYPE (t) = build_offset_type (type, unknown_type_node);
- return t;
+ TREE_TYPE (fnfields) = unknown_type_node;
+ return build (OFFSET_REF, unknown_type_node, decl, fnfields);
}
- /* Now that we know we are looking for a field, see if we
- have access to that field. Lookup_field will give us the
- error message. */
-
- t = lookup_field (basebinfo, name, 1, 0);
-
- if (t == error_mark_node)
- return error_mark_node;
+ t = member;
if (t == NULL_TREE)
{
return convert_from_reference (t);
}
- if (TREE_CODE (t) == FIELD_DECL && DECL_BIT_FIELD (t))
+ if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t))
{
cp_error ("illegal pointer to bit field `%D'", t);
return error_mark_node;
tree member;
tree basetype, addr;
- if (TREE_CODE (exp) == TREE_LIST)
- {
- cp_pedwarn ("assuming & on overloaded member function");
- return build_unary_op (ADDR_EXPR, exp, 0);
- }
-
if (TREE_CODE (exp) == OFFSET_REF)
{
member = TREE_OPERAND (exp, 1);
base = current_class_ref;
}
+ if (BASELINK_P (member))
+ {
+ 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)
+ {
+ if (! flag_ms_extensions)
+ cp_pedwarn ("assuming & on `%E'", member);
+ return build_unary_op (ADDR_EXPR, exp, 0);
+ }
+
if ((TREE_CODE (member) == VAR_DECL
- && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member)))
- || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (member)) == METHOD_TYPE)
+ && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member))
+ && ! TYPE_PTRMEM_P (TREE_TYPE (member)))
+ || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE)
{
/* These were static members. */
if (mark_addressable (member) == 0)
/* The first case is really just a reference to a member of `this'. */
if (TREE_CODE (member) == FIELD_DECL
- && (base == current_class_ref
- || (TREE_CODE (base) == NOP_EXPR
- && TREE_OPERAND (base, 0) == error_mark_node)))
+ && (base == current_class_ref || is_dummy_object (base)))
{
- tree basetype_path, access;
+ tree basetype_path;
+ tree expr;
if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
basetype = TYPE_OFFSET_BASETYPE (type);
}
/* Kludge: we need to use basetype_path now, because
convert_pointer_to will bash it. */
- access = compute_access (basetype_path, member);
+ enforce_access (basetype_path, member);
addr = convert_pointer_to (basetype, base);
- if (access == access_public_node)
- return build (COMPONENT_REF, TREE_TYPE (member),
- build_indirect_ref (addr, NULL_PTR), member);
- if (access == access_protected_node)
- {
- cp_error_at ("member `%D' is protected", member);
- error ("in this context");
- return error_mark_node;
- }
- if (access == access_private_node)
- {
- cp_error_at ("member `%D' is private", member);
- error ("in this context");
- return error_mark_node;
- }
- my_friendly_abort (55);
+
+ /* Even in the case of illegal access, we form the
+ COMPONENT_REF; that will allow better error recovery than
+ just feeding back error_mark_node. */
+ expr = build (COMPONENT_REF, TREE_TYPE (member),
+ build_indirect_ref (addr, NULL_PTR), member);
+ return convert_from_reference (expr);
}
/* Ensure that we have an object. */
- if (TREE_CODE (base) == NOP_EXPR
- && TREE_OPERAND (base, 0) == error_mark_node)
+ if (is_dummy_object (base))
addr = error_mark_node;
else
- {
- /* If this is a reference to a member function, then return the
- address of the member function (which may involve going
- through the object's vtable), otherwise, return an expression
- for the dereferenced pointer-to-member construct. */
- addr = build_unary_op (ADDR_EXPR, base, 0);
- }
+ /* If this is a reference to a member function, then return the
+ address of the member function (which may involve going
+ through the object's vtable), otherwise, return an expression
+ for the dereferenced pointer-to-member construct. */
+ addr = build_unary_op (ADDR_EXPR, base, 0);
- if (TREE_CODE (TREE_TYPE (member)) == OFFSET_TYPE)
+ if (TYPE_PTRMEM_P (TREE_TYPE (member)))
{
if (addr == error_mark_node)
{
return error_mark_node;
}
- basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (member));
+ basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member)));
addr = convert_pointer_to (basetype, addr);
- member = cp_convert (ptrdiff_type_node,
- build_unary_op (ADDR_EXPR, member, 0));
+ 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. */
member = build_binary_op (MINUS_EXPR, member,
- cp_convert (ptrdiff_type_node, integer_one_node),
- 0);
+ cp_convert (ptrdiff_type_node, integer_one_node));
return build1 (INDIRECT_REF, type,
build (PLUS_EXPR, build_pointer_type (type),
tree decl;
{
if (! TREE_THIS_VOLATILE (decl)
-#if 0
- /* These may be necessary for C, but they break C++. */
- ! TREE_PUBLIC (decl)
- /* Don't change a variable array bound or initial value to a constant
- in a place where a variable is invalid. */
- && ! pedantic
-#endif /* 0 */
- && DECL_INITIAL (decl) != 0
+ && DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node
/* This is invalid if initial value is not constant.
If it has either a function call, a memory reference,
or a variable, then re-evaluating it could give different results. */
&& TREE_CONSTANT (DECL_INITIAL (decl))
/* Check for cases where this is sub-optimal, even though valid. */
- && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR
-#if 0
- /* We must allow this to work outside of functions so that
- static constants can be used for array sizes. */
- && current_function_decl != 0
- && DECL_MODE (decl) != BLKmode
-#endif
- )
+ && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR)
return DECL_INITIAL (decl);
return decl;
}
build_builtin_delete_call (addr)
tree addr;
{
- tree BID = get_first_fn
- (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) DELETE_EXPR]));
-
- return build_call (BID, void_type_node, build_expr_list (NULL_TREE, addr));
+ mark_used (global_delete_fndecl);
+ return build_call (global_delete_fndecl,
+ void_type_node, build_expr_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;
}
else
{
+ int flags = pedantic ? WANT_INT : (WANT_INT | WANT_ENUM);
+ if (build_expr_type_conversion (flags, this_nelts, 0)
+ == NULL_TREE)
+ pedwarn ("size in array new must have integral type");
+
this_nelts = save_expr (cp_convert (sizetype, this_nelts));
absdcl = TREE_OPERAND (absdcl, 0);
if (this_nelts == integer_zero_node)
nelts = integer_zero_node;
}
else
- nelts = build_binary_op (MULT_EXPR, nelts, this_nelts, 1);
+ nelts = build_binary_op (MULT_EXPR, nelts, this_nelts);
}
}
else
type = groktypename (decl);
if (! type || type == error_mark_node)
- {
- immediate_size_expand = old_immediate_size_expand;
- return error_mark_node;
- }
-
- if (current_function_decl
- && DECL_CONSTRUCTOR_P (current_function_decl))
- {
- pending_sizes = get_pending_sizes ();
- immediate_size_expand = old_immediate_size_expand;
- }
+ return error_mark_node;
}
else if (TREE_CODE (decl) == IDENTIFIER_NODE)
{
rval = build (NEW_EXPR, build_pointer_type (type), placement, t, init);
NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
TREE_SIDE_EFFECTS (rval) = 1;
+ rval = build_new_1 (rval);
+ if (rval == error_mark_node)
+ return error_mark_node;
/* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain. */
rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval);
TREE_NO_UNUSED_WARNING (rval) = 1;
- if (pending_sizes)
- rval = build_compound_expr (chainon (pending_sizes,
- build_expr_list (NULL_TREE, rval)));
-
return rval;
}
+/* Given a Java class, return a decl for the corresponding java.lang.Class. */
+
+static tree
+build_java_class_ref (type)
+ tree type;
+{
+ tree name, class_decl;
+ static tree CL_prefix = NULL_TREE;
+ if (CL_prefix == NULL_TREE)
+ CL_prefix = get_identifier("_CL_");
+ if (jclass_node == NULL_TREE)
+ {
+ jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier("jclass"));
+ if (jclass_node == NULL_TREE)
+ fatal("call to Java constructor, while `jclass' undefined");
+ jclass_node = TREE_TYPE (jclass_node);
+ }
+ name = build_overload_with_type (CL_prefix, type);
+ class_decl = IDENTIFIER_GLOBAL_VALUE (name);
+ if (class_decl == NULL_TREE)
+ {
+ class_decl = build_decl (VAR_DECL, name, TREE_TYPE (jclass_node));
+ TREE_STATIC (class_decl) = 1;
+ DECL_EXTERNAL (class_decl) = 1;
+ TREE_PUBLIC (class_decl) = 1;
+ DECL_ARTIFICIAL (class_decl) = 1;
+ DECL_IGNORED_P (class_decl) = 1;
+ pushdecl_top_level (class_decl);
+ make_decl_rtl (class_decl, NULL_PTR, 1);
+ }
+ return class_decl;
+}
+
/* Called from cplus_expand_expr when expanding a NEW_EXPR. The return
value is immediately handed to expand_expr. */
enum tree_code code = NEW_EXPR;
int use_cookie, nothrow, check_new;
int use_global_new;
+ int use_java_new = 0;
placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1);
}
true_type = type;
- if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
+ if (CP_TYPE_QUALS (type))
type = TYPE_MAIN_VARIANT (type);
/* If our base type is an array, then make sure we know how many elements
while (TREE_CODE (true_type) == ARRAY_TYPE)
{
tree this_nelts = array_type_nelts_top (true_type);
- nelts = build_binary_op (MULT_EXPR, nelts, this_nelts, 1);
+ nelts = build_binary_op (MULT_EXPR, nelts, this_nelts);
true_type = TREE_TYPE (true_type);
}
- if (!complete_type_or_else (true_type))
+ if (!complete_type_or_else (true_type, exp))
return error_mark_node;
if (has_array)
size = fold (build_binary_op (MULT_EXPR, size_in_bytes (true_type),
- nelts, 1));
+ nelts));
else
size = size_in_bytes (type);
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
+ the beginning of the array to store the size of the array.
-#if 1
- /* Get a little extra space to store a couple of things before the new'ed
- array, if this isn't the default placement new. */
+ Well, that's what we should do. For backwards compatibility, we
+ have to do this whenever there's a two-argument array-delete
+ operator.
+ FIXME: For -fnew-abi, we don't have to maintain backwards
+ compatibility and we should fix this. */
use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type)
&& ! (placement && ! TREE_CHAIN (placement)
&& TREE_TYPE (TREE_VALUE (placement)) == ptr_type_node));
-#else
- /* Get a little extra space to store a couple of things before the new'ed
- array, if this is either non-placement new or new (nothrow). */
-
- use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type)
- && (! placement || nothrow));
-#endif
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;
- }
+ if (! placement && TYPE_FOR_JAVA (true_type))
+ {
+ tree class_addr, alloc_decl;
+ tree class_decl = build_java_class_ref (true_type);
+ tree class_size = size_in_bytes (true_type);
+ static char alloc_name[] = "_Jv_AllocObject";
+ use_java_new = 1;
+ alloc_decl = IDENTIFIER_GLOBAL_VALUE (get_identifier (alloc_name));
+ if (alloc_decl == NULL_TREE)
+ fatal("call to Java constructor, while `%s' undefined", alloc_name);
+ class_addr = build1 (ADDR_EXPR, jclass_node, class_decl);
+ rval = build_function_call (alloc_decl,
+ tree_cons (NULL_TREE, class_addr,
+ build_tree_list (NULL_TREE,
+ class_size)));
+ rval = cp_convert (build_pointer_type (true_type), rval);
}
else
{
- int susp;
-
- 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-
tree t = TREE_OPERAND (rval, 0);
/* The function. */
t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
- t = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (t));
-
- if (t && TREE_VALUE (t) == NULL_TREE)
- nothrow = 1;
+ nothrow = TYPE_NOTHROW_P (TREE_TYPE (t));
}
- check_new = flag_check_new || nothrow;
+ check_new = (flag_check_new || nothrow) && ! use_java_new;
if ((check_new || flag_exceptions) && rval)
{
tree extra = BI_header_size;
tree cookie, exp1;
rval = convert (string_type_node, rval); /* for ptr arithmetic */
- rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra, 1));
+ rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra));
/* Store header info. */
cookie = build_indirect_ref (build (MINUS_EXPR,
build_pointer_type (BI_header_type),
rval, extra), NULL_PTR);
exp1 = build (MODIFY_EXPR, void_type_node,
- build_component_ref (cookie, nc_nelts_field_id,
+ build_component_ref (cookie, nelts_identifier,
NULL_TREE, 0),
nelts);
- TREE_SIDE_EFFECTS (exp1) = 1;
rval = cp_convert (build_pointer_type (true_type), rval);
rval = build_compound_expr
- (expr_tree_cons (NULL_TREE, exp1,
+ (tree_cons (NULL_TREE, exp1,
build_expr_list (NULL_TREE, rval)));
}
if (! TYPE_NEEDS_CONSTRUCTING (type)
&& ! IS_AGGR_TYPE (type) && ! has_array)
{
- /* New 2.0 interpretation: `new int (10)' means
- allocate an int, and initialize it with 10. */
+ /* We are processing something like `new int (10)', which
+ means allocate an int, and initialize it with 10. */
tree deref;
+ tree deref_type;
+ /* At present RVAL is a temporary variable, created to hold
+ the value from the call to `operator new'. We transform
+ it to (*RVAL = INIT, RVAL). */
rval = save_expr (rval);
deref = build_indirect_ref (rval, NULL_PTR);
+
+ /* Even for something like `new const int (10)' we must
+ allow the expression to be non-const while we do the
+ initialization. */
+ deref_type = TREE_TYPE (deref);
+ if (CP_TYPE_CONST_P (deref_type))
+ TREE_TYPE (deref)
+ = cp_build_qualified_type (deref_type,
+ CP_TYPE_QUALS (deref_type)
+ & ~TYPE_QUAL_CONST);
TREE_READONLY (deref) = 0;
if (TREE_CHAIN (init) != NULL_TREE)
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;
}
+ if (use_java_new)
+ rval = save_expr (rval);
newrval = rval;
if (newrval && TREE_CODE (TREE_TYPE (newrval)) == POINTER_TYPE)
if (newrval == NULL_TREE || newrval == error_mark_node)
return error_mark_node;
+ /* Java constructors compiled by jc1 do not return this. */
+ if (use_java_new)
+ newrval = build (COMPOUND_EXPR, TREE_TYPE (newrval),
+ newrval, rval);
rval = newrval;
TREE_HAS_CONSTRUCTOR (rval) = 1;
}
else
- rval = build (VEC_INIT_EXPR, TREE_TYPE (rval),
- save_expr (rval), init, nelts);
-
- /* If any part of the object initialization terminates by throwing
- an exception and the new-expression does not contain a
- new-placement, then the deallocation function is called to free
- the memory in which the object was being constructed. */
- if (flag_exceptions && alloc_expr)
+ 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
+ deallocation function is called to free the memory in which the
+ object was being constructed, after which the exception continues
+ to propagate in the context of the new-expression. If no
+ unambiguous matching deallocation function can be found,
+ propagating the exception does not cause the object's memory to be
+ freed. */
+ if (flag_exceptions && alloc_expr && ! use_java_new)
{
enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
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. */
+ flags |= LOOKUP_SPECULATIVELY;
- if (placement)
- {
- flags |= LOOKUP_SPECULATIVELY;
-
- /* We expect alloc_expr to look like a TARGET_EXPR around
- a NOP_EXPR around the CALL_EXPR we want. */
- fn = TREE_OPERAND (alloc_expr, 1);
- fn = TREE_OPERAND (fn, 0);
- }
-
- /* Copy size to the saveable obstack. */
- size = copy_node (size);
+ /* We expect alloc_expr to look like a TARGET_EXPR around
+ a NOP_EXPR around the CALL_EXPR we want. */
+ fn = TREE_OPERAND (alloc_expr, 1);
+ fn = TREE_OPERAND (fn, 0);
cleanup = build_op_delete_call (dcode, alloc_node, size, flags, fn);
- 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
if (cleanup)
{
-#if 0
- /* Disable this until flow is fixed so that it doesn't
- think the initialization of sentry is a dead write. */
tree end, sentry, begin, buf, t = TREE_TYPE (rval);
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);
rval = build (COMPOUND_EXPR, t, begin,
build (COMPOUND_EXPR, t, rval,
build (COMPOUND_EXPR, t, end, buf)));
-#else
- /* FIXME: this is a workaround for a crash due to overlapping
- exception regions. Cleanups shouldn't really happen here. */
- rval = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (rval), rval);
-
- rval = build (TRY_CATCH_EXPR, TREE_TYPE (rval), rval, cleanup);
- rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
-#endif
}
}
}
- else if (TYPE_READONLY (true_type))
+ else if (CP_TYPE_CONST_P (true_type))
cp_error ("uninitialized const in `new' of `%#T'", true_type);
done:
{
/* Did we modify the storage? */
tree ifexp = build_binary_op (NE_EXPR, alloc_node,
- integer_zero_node, 1);
+ integer_zero_node);
rval = build_conditional_expr (ifexp, rval, alloc_node);
}
}
\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,
- 1));
- /* 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 (ptype, 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:
/* If the delete flag is one, or anything else with the low bit set,
delete the storage. */
- if (auto_delete_vec == integer_zero_node
- || auto_delete_vec == integer_two_node)
+ if (auto_delete_vec == integer_zero_node)
deallocate_expr = integer_zero_node;
else
{
base_tbd = cp_convert (ptype,
build_binary_op (MINUS_EXPR,
cp_convert (string_type_node, base),
- BI_header_size,
- 1));
+ BI_header_size));
/* True size with header. */
virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
}
- deallocate_expr = build_x_delete (ptype, base_tbd,
+ 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);
}
-/* Build a tree to cleanup partially built arrays.
- BASE is that starting address of the array.
- COUNT is the count of objects that have been built, that need destroying.
- TYPE is the type of elements in the array. */
+tree
+create_temporary_var (type)
+ tree type;
+{
+ 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;
+
+ return decl;
+}
+
+/* Create a new temporary variable of the indicated TYPE, initialized
+ to INIT.
+
+ 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
-build_array_eh_cleanup (base, count, type)
- tree base, count, type;
+get_temp_regvar (type, init)
+ tree type, init;
{
- tree expr = build_vec_delete_1 (base, count, type, integer_two_node,
- integer_zero_node, 0);
- return expr;
+ tree decl;
+
+ 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 iterator, base2 = NULL_TREE;
- tree type = TREE_TYPE (TREE_TYPE (base));
+ tree base2 = NULL_TREE;
tree size;
+ tree itype = NULL_TREE;
+ tree iterator;
+ /* The type of an element in the array. */
+ tree type;
+ /* The type of a pointer to an element in the array. */
+ tree ptype;
+ tree stmt_expr;
+ tree compound_stmt;
+ int destroy_temps;
+ tree try_block = NULL_TREE;
+ tree try_body;
+ int num_initialized_elts = 0;
maxindex = cp_convert (ptrdiff_type_node, maxindex);
if (maxindex == error_mark_node)
return error_mark_node;
- if (current_function_decl == NULL_TREE)
- {
- rval = make_tree_vec (3);
- TREE_VEC_ELT (rval, 0) = base;
- TREE_VEC_ELT (rval, 1) = maxindex;
- TREE_VEC_ELT (rval, 2) = init;
- return rval;
- }
-
+ type = TREE_TYPE (TREE_TYPE (base));
+ ptype = build_pointer_type (type);
size = size_in_bytes (type);
- /* Set to zero in case size is <= 0. Optimizer will delete this if
- it is not needed. */
- rval = get_temp_regvar (build_pointer_type (type),
- cp_convert (build_pointer_type (type), null_pointer_node));
- base = default_conversion (base);
- base = cp_convert (build_pointer_type (type), base);
- expand_assignment (rval, base, 0, 0);
- base = get_temp_regvar (build_pointer_type (type), base);
-
- if (init != NULL_TREE
- && TREE_CODE (init) == CONSTRUCTOR
- && (! decl || TREE_TYPE (init) == TREE_TYPE (decl)))
- {
- /* Initialization of array from {...}. */
- tree elts = CONSTRUCTOR_ELTS (init);
- tree baseref = build1 (INDIRECT_REF, type, base);
- tree baseinc = build (PLUS_EXPR, build_pointer_type (type), base, size);
- int host_i = TREE_INT_CST_LOW (maxindex);
-
- if (IS_AGGR_TYPE (type))
- {
- while (elts)
- {
- host_i -= 1;
- expand_aggr_init (baseref, TREE_VALUE (elts), 0, 0);
-
- expand_assignment (base, baseinc, 0, 0);
- elts = TREE_CHAIN (elts);
- }
- /* Initialize any elements by default if possible. */
- if (host_i >= 0)
- {
- if (TYPE_NEEDS_CONSTRUCTING (type) == 0)
- {
- if (obey_regdecls)
- use_variable (DECL_RTL (base));
- goto done_init;
- }
+ /* 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. */
+ 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))))
+ {
+ /* Do non-default initialization resulting from brace-enclosed
+ initializers. */
+
+ tree elts;
+ 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)
+ finish_expr_stmt (build_aggr_init (baseref, elt, 0));
+ else
+ finish_expr_stmt (build_modify_expr (baseref, NOP_EXPR,
+ elt));
- iterator = get_temp_regvar (ptrdiff_type_node,
- build_int_2 (host_i, 0));
- init = NULL_TREE;
- goto init_by_default;
- }
+ finish_expr_stmt (build_modify_expr
+ (base,
+ NOP_EXPR,
+ build (PLUS_EXPR, build_pointer_type (type),
+ base, size)));
+ finish_expr_stmt (build_modify_expr
+ (iterator,
+ NOP_EXPR,
+ build (MINUS_EXPR, ptrdiff_type_node,
+ iterator, integer_one_node)));
}
- else
- while (elts)
- {
- expand_assignment (baseref, TREE_VALUE (elts), 0, 0);
- expand_assignment (base, baseinc, 0, 0);
- elts = TREE_CHAIN (elts);
- }
-
- if (obey_regdecls)
- use_variable (DECL_RTL (base));
+ /* Clear out INIT so that we don't get confused below. */
+ init = NULL_TREE;
}
- else
+ else if (from_array)
{
- tree itype;
-
- iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
-
- init_by_default:
- itype = NULL_TREE;
-
- /* If initializing one array from another,
- initialize element by element. */
- if (from_array)
+ /* If initializing one array from another, initialize element by
+ element. We rely upon the below calls the do argument
+ checking. */
+ if (decl == NULL_TREE)
{
- /* We rely upon the below calls the do argument checking */
- if (decl == NULL_TREE)
- {
- sorry ("initialization of array from dissimilar array type");
- return error_mark_node;
- }
- if (init)
- {
- base2 = default_conversion (init);
- itype = TREE_TYPE (base2);
- base2 = get_temp_regvar (itype, base2);
- itype = TREE_TYPE (itype);
- }
- else if (TYPE_LANG_SPECIFIC (type)
- && TYPE_NEEDS_CONSTRUCTING (type)
- && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
- {
- error ("initializer ends prematurely");
- return error_mark_node;
- }
+ sorry ("initialization of array from dissimilar array type");
+ return error_mark_node;
}
+ if (init)
+ {
+ base2 = default_conversion (init);
+ itype = TREE_TYPE (base2);
+ base2 = get_temp_regvar (itype, base2);
+ itype = TREE_TYPE (itype);
+ }
+ else if (TYPE_LANG_SPECIFIC (type)
+ && TYPE_NEEDS_CONSTRUCTING (type)
+ && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+ {
+ error ("initializer ends prematurely");
+ return error_mark_node;
+ }
+ }
- expand_start_cond (build (GE_EXPR, boolean_type_node,
- iterator, integer_zero_node), 0);
- if (TYPE_NEEDS_DESTRUCTOR (type))
- expand_eh_region_start ();
- expand_start_loop_continue_elsewhere (1);
-
- /* The initialization of each array element is a full-expression. */
- expand_start_target_temps ();
+ /* Now, default-initialize any remaining elements. We don't need to
+ do that if a) the type does not need constructing, or b) we've
+ already initialized all the elements.
+
+ We do need to keep going if we're copying an array. */
+
+ if (from_array
+ || (TYPE_NEEDS_CONSTRUCTING (type)
+ && !(TREE_CODE (maxindex) == INTEGER_CST
+ && num_initialized_elts == TREE_INT_CST_LOW (maxindex) + 1)))
+ {
+ /* If the ITERATOR is equal to -1, then we don't have to loop;
+ we've already initialized all the elements. */
+ 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. */
+ 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, 0);
+ elt_init = build_aggr_init (to, from, 0);
else if (from)
- expand_assignment (to, from, 0, 0);
+ elt_init = build_modify_expr (to, NOP_EXPR, from);
else
my_friendly_abort (57);
}
{
if (init != 0)
sorry ("cannot initialize multi-dimensional array with initializer");
- expand_vec_init (decl, build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), base),
- array_type_nelts (type), 0, 0);
+ elt_init = (build_vec_init
+ (decl,
+ build1 (NOP_EXPR,
+ build_pointer_type (TREE_TYPE (type)),
+ base),
+ array_type_nelts (type), 0, 0));
}
else
- expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0, 0);
-
- expand_assignment (base,
- build (PLUS_EXPR, build_pointer_type (type), base, size),
- 0, 0);
- if (base2)
- expand_assignment (base2,
- build (PLUS_EXPR, build_pointer_type (type), base2, size), 0, 0);
-
- /* 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)
+ 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 ())
{
- use_variable (DECL_RTL (base));
- if (base2)
- use_variable (DECL_RTL (base2));
+ finish_expr_stmt (elt_init);
+ expand_end_target_temps ();
}
- expand_end_loop ();
- if (TYPE_NEEDS_DESTRUCTOR (type) && flag_exceptions)
+ else
{
- /* 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 ();
- {
- tree e1, 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);
-
- e1 = build_array_eh_cleanup
- (rval,
- build_binary_op (MINUS_EXPR, maxindex, iterator, 1),
- type);
- expand_expr (e1, 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 ();
+ stmts_are_full_exprs_p = 1;
+ finish_expr_stmt (elt_init);
+ stmts_are_full_exprs_p = 0;
}
- expand_end_cond ();
- if (obey_regdecls)
- use_variable (DECL_RTL (iterator));
- }
- done_init:
- if (obey_regdecls)
- use_variable (DECL_RTL (rval));
- return rval;
+ finish_expr_stmt (build_modify_expr
+ (base,
+ NOP_EXPR,
+ build (PLUS_EXPR, build_pointer_type (type),
+ base, size)));
+ if (base2)
+ finish_expr_stmt (build_modify_expr
+ (base2,
+ NOP_EXPR,
+ build (PLUS_EXPR, build_pointer_type (type),
+ base2, size)));
+
+ 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);
+
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
+ }
+
+ /* Make sure to cleanup any partially constructed elements. */
+ if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
+ {
+ 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);
+ }
+
+ /* 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.
This does not call any destructors. */
tree
-build_x_delete (type, addr, which_delete, virtual_size)
- tree type, addr;
+build_x_delete (addr, which_delete, virtual_size)
+ tree addr;
int which_delete;
tree virtual_size;
{
if (TREE_CODE (type) == POINTER_TYPE)
{
type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
- if (!complete_type_or_else (type))
+ if (type != void_type_node && !complete_type_or_else (type, addr))
return error_mark_node;
if (TREE_CODE (type) == ARRAY_TYPE)
goto handle_array;
return error_mark_node;
}
return build_vec_delete (addr, array_type_nelts (type),
- auto_delete, integer_two_node,
- use_global_delete);
+ auto_delete, use_global_delete);
}
else
{
ifexp = integer_one_node;
else
/* Handle deleting a null pointer. */
- ifexp = fold (build_binary_op (NE_EXPR, addr, integer_zero_node, 1));
+ ifexp = fold (build_binary_op (NE_EXPR, addr, integer_zero_node));
if (ifexp != integer_one_node)
expr = build (COND_EXPR, void_type_node,
tree parent_auto_delete = auto_delete;
tree cond;
+ /* Set this again before we call anything, as we might get called
+ recursively. */
+ TYPE_HAS_DESTRUCTOR (type) = 1;
+
/* If we have member delete or vbases, we call delete in
finish_function. */
if (auto_delete == integer_zero_node)
expr = build_scoped_method_call
(ref, base_binfo, dtor_identifier,
build_expr_list (NULL_TREE, this_auto_delete));
- exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
+ exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
/* Take care of the remaining baseclasses. */
(ref, base_binfo, dtor_identifier,
build_expr_list (NULL_TREE, integer_zero_node));
- exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
+ exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
tree this_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0);
tree this_type = TREE_TYPE (member);
expr = build_delete (this_type, this_member, integer_two_node, flags, 0);
- exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
+ exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
}
{
tree this_addr = convert_force (build_pointer_type (BINFO_TYPE (vbases)),
addr, 0);
- result = expr_tree_cons (NULL_TREE,
+ result = tree_cons (NULL_TREE,
build_delete (TREE_TYPE (this_addr), this_addr,
integer_zero_node,
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
BASE is the expression that should yield the store to be deleted.
This function expands (or synthesizes) these calls itself.
AUTO_DELETE_VEC says whether the container (vector) should be deallocated.
- AUTO_DELETE say whether each item in the container should be deallocated.
This also calls delete for virtual baseclasses of elements of the vector.
be worth bothering.) */
tree
-build_vec_delete (base, maxindex, auto_delete_vec, auto_delete,
- use_global_delete)
+build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete)
tree base, maxindex;
- tree auto_delete_vec, auto_delete;
+ tree auto_delete_vec;
int use_global_delete;
{
tree type;
tree cookie_addr = build (MINUS_EXPR, build_pointer_type (BI_header_type),
base, BI_header_size);
tree cookie = build_indirect_ref (cookie_addr, NULL_PTR);
- maxindex = build_component_ref (cookie, nc_nelts_field_id, NULL_TREE, 0);
+ maxindex = build_component_ref (cookie, nelts_identifier, NULL_TREE, 0);
do
type = TREE_TYPE (type);
while (TREE_CODE (type) == ARRAY_TYPE);
return error_mark_node;
}
- return build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
+ return build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
use_global_delete);
}