summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cp/init.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
committerobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
commitc9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch)
tree086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/cp/init.c
parent2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff)
downloadFreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.zip
FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.tar.gz
Enlist the FreeBSD-CURRENT users as testers of what is to become Gcc 3.1.0.
These bits are taken from the FSF anoncvs repo on 1-Feb-2002 08:20 PST.
Diffstat (limited to 'contrib/gcc/cp/init.c')
-rw-r--r--contrib/gcc/cp/init.c3146
1 files changed, 1523 insertions, 1623 deletions
diff --git a/contrib/gcc/cp/init.c b/contrib/gcc/cp/init.c
index d70fc32..017b894 100644
--- a/contrib/gcc/cp/init.c
+++ b/contrib/gcc/cp/init.c
@@ -1,5 +1,6 @@
/* Handle initialization things in C++.
- Copyright (C) 1987, 89, 92-98, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -25,145 +26,240 @@ Boston, MA 02111-1307, USA. */
#include "system.h"
#include "tree.h"
#include "rtl.h"
+#include "expr.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, tree));
-static int pvbasecount PROTO((tree, int));
-
-/* 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, special_function_kind, int));
+static void perform_member_init PARAMS ((tree, tree, int));
+static void sort_base_init PARAMS ((tree, tree, tree *, tree *));
+static tree build_builtin_delete_call PARAMS ((tree));
+static int member_init_ok_or_else PARAMS ((tree, tree, tree));
+static void expand_virtual_init PARAMS ((tree, tree));
+static tree sort_member_init PARAMS ((tree, tree));
+static tree initializing_context 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 *));
+static tree build_default_init PARAMS ((tree));
+static tree build_new_1 PARAMS ((tree));
+static tree get_cookie_size PARAMS ((tree));
+static tree build_dtor_call PARAMS ((tree, special_function_kind, int));
+static tree build_field_list PARAMS ((tree, tree, int *));
+static tree build_vtbl_address PARAMS ((tree));
/* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */
-static tree BI_header_type, BI_header_size;
+static tree BI_header_type;
void init_init_processing ()
{
tree fields[1];
- minus_one = 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);
+ fields[0] = build_decl (FIELD_DECL, nelts_identifier, sizetype);
+
finish_builtin_type (BI_header_type, "__new_cookie", fields,
0, double_type_node);
- BI_header_size = size_in_bytes (BI_header_type);
+
+ ggc_add_tree_root (&BI_header_type, 1);
+}
+
+/* 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;
+{
+ if (building_stmt_tree ())
+ *stmt_expr_p = begin_stmt_expr ();
+ else
+ *stmt_expr_p = begin_global_stmt_expr ();
+
+ if (building_stmt_tree ())
+ *compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
+ /*
+ else
+ *compound_stmt_p = genrtl_begin_compound_stmt (has_no_scope=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.
+/* Finish out the statement-expression begun by the previous call to
+ begin_init_stmts. Returns the statement-expression itself. */
- 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.
+tree
+finish_init_stmts (stmt_expr, compound_stmt)
+ tree stmt_expr;
+ tree compound_stmt;
- BINFO_TYPE (real_binfo) must be BINFO_TYPE (binfo).
+{
+ if (building_stmt_tree ())
+ finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
+
+ if (building_stmt_tree ())
+ stmt_expr = finish_stmt_expr (stmt_expr);
+ else
+ stmt_expr = finish_global_stmt_expr (stmt_expr);
+
+ /* To avoid spurious warnings about unused values, we set
+ TREE_USED. */
+ if (stmt_expr)
+ TREE_USED (stmt_expr) = 1;
- Relies upon binfo being inside TYPE_BINFO (TREE_TYPE (TREE_TYPE
- (addr))). */
+ return stmt_expr;
+}
+
+/* Constructors */
+
+/* Called from initialize_vtbl_ptrs via dfs_walk. BINFO is the base
+ which we want to initialize the vtable pointer for, DATA is
+ TREE_LIST whose TREE_VALUE is the this ptr expression. */
+
+static tree
+dfs_initialize_vtbl_ptrs (binfo, data)
+ tree binfo;
+ void *data;
+{
+ if ((!BINFO_PRIMARY_P (binfo) || TREE_VIA_VIRTUAL (binfo))
+ && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+ {
+ tree base_ptr = TREE_VALUE ((tree) data);
+
+ base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1);
+
+ expand_virtual_init (binfo, base_ptr);
+ }
+
+ SET_BINFO_MARKED (binfo);
+
+ return NULL_TREE;
+}
+
+/* Initialize all the vtable pointers in the object pointed to by
+ ADDR. */
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 (addr)
+ 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;
+ tree list;
+ tree type;
+
+ type = TREE_TYPE (TREE_TYPE (addr));
+ list = build_tree_list (type, addr);
+
+ /* Walk through the hierarchy, initializing the vptr in each base
+ class. We do these in pre-order because 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);
+}
+
+/* [dcl.init]:
+
+ To default-initialize an object of type T means:
+
+ --if T is a non-POD class type (clause _class_), the default construc-
+ tor for T is called (and the initialization is ill-formed if T has
+ no accessible default constructor);
+
+ --if T is an array type, each element is default-initialized;
+
+ --otherwise, the storage for the object is zero-initialized.
+
+ A program that calls for default-initialization of an entity of refer-
+ ence type is ill-formed. */
- for (i = 0; i < n_baselinks; i++)
+static tree
+build_default_init (type)
+ tree type;
+{
+ tree init = NULL_TREE;
+
+ if (TYPE_NEEDS_CONSTRUCTING (type))
+ /* Other code will handle running the default constructor. We can't do
+ anything with a CONSTRUCTOR for arrays here, as that would imply
+ copy-initialization. */
+ return NULL_TREE;
+ else if (AGGREGATE_TYPE_P (type) && !TYPE_PTRMEMFUNC_P (type))
{
- 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)))
+ /* 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. */
+ init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, NULL_TREE);
+ }
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ /* --if T is a reference type, no initialization is performed. */
+ return NULL_TREE;
+ else
{
- tree base_ptr = convert_pointer_to_real (binfo, addr);
- expand_virtual_init (real_binfo, base_ptr);
+ init = integer_zero_node;
+
+ if (TREE_CODE (type) == ENUMERAL_TYPE)
+ /* We must make enumeral types the right type. */
+ init = fold (build1 (NOP_EXPR, type, init));
}
+
+ init = digest_init (type, init, 0);
+ return init;
}
-
-/* 348 - 351 */
+
/* Subroutine of emit_base_init. */
static void
-perform_member_init (member, name, init, explicit)
- tree member, name, init;
+perform_member_init (member, init, explicit)
+ tree member, init;
int explicit;
{
tree decl;
tree type = TREE_TYPE (member);
- expand_start_target_temps ();
+ decl = build_component_ref (current_class_ref, member, NULL_TREE, explicit);
+
+ if (decl == error_mark_node)
+ return;
- 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))
+ {
+ if (init)
+ {
+ 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,
+ /* Since `init' is already a TREE_LIST on the 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);
+ init = build_tree_list (NULL_TREE, init);
if (explicit
&& TREE_CODE (type) == ARRAY_TYPE
@@ -172,11 +268,10 @@ perform_member_init (member, name, init, explicit)
&& 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 (decl, TREE_VALUE (init), 1));
}
else
- expand_aggr_init (decl, init, 0);
+ finish_expr_stmt (build_aggr_init (decl, init, 0));
}
else
{
@@ -184,21 +279,15 @@ perform_member_init (member, name, init, explicit)
{
if (explicit)
{
- /* 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;
- }
- else
- init = integer_zero_node;
+ init = build_default_init (type);
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ warning
+ ("default-initialization of `%#D', which has reference type",
+ member);
}
/* member traversal: note it leaves init NULL */
- else if (TREE_CODE (TREE_TYPE (member)) == REFERENCE_TYPE)
- cp_pedwarn ("uninitialized reference member `%D'", member);
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ pedwarn ("uninitialized reference member `%D'", member);
}
else if (TREE_CODE (init) == TREE_LIST)
{
@@ -213,138 +302,238 @@ perform_member_init (member, name, init, explicit)
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))
+ if (TYPE_HAS_NONTRIVIAL_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,
+ expr = build_component_ref (current_class_ref, member, NULL_TREE,
explicit);
- expr = build_delete (type, expr, integer_zero_node,
+ expr = build_delete (type, expr, sfk_complete_destructor,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
if (expr != error_mark_node)
- add_partial_entry (expr);
-
- pop_obstacks ();
+ finish_subobject (expr);
}
}
-extern int warn_reorder;
+/* Returns a TREE_LIST containing (as the TREE_PURPOSE of each node) all
+ the FIELD_DECLs on the TYPE_FIELDS list for T, in reverse order. */
-/* Subroutine of emit_member_init. */
-
-static tree
-sort_member_init (t)
+static tree
+build_field_list (t, list, uses_unions_p)
tree t;
+ tree list;
+ int *uses_unions_p;
{
- tree x, member, name, field;
- tree init_list = NULL_TREE;
- int last_pos = 0;
- tree last_field = NULL_TREE;
+ tree fields;
- for (member = TYPE_FIELDS (t); member ; member = TREE_CHAIN (member))
- {
- int pos;
+ /* Note whether or not T is a union. */
+ if (TREE_CODE (t) == UNION_TYPE)
+ *uses_unions_p = 1;
- /* member could be, for example, a CONST_DECL for an enumerated
- tag; we don't want to try to initialize that, since it already
- has a value. */
- if (TREE_CODE (member) != FIELD_DECL || !DECL_NAME (member))
+ for (fields = TYPE_FIELDS (t); fields; fields = TREE_CHAIN (fields))
+ {
+ /* Skip CONST_DECLs for enumeration constants and so forth. */
+ if (TREE_CODE (fields) != FIELD_DECL)
continue;
+
+ /* Keep track of whether or not any fields are unions. */
+ if (TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
+ *uses_unions_p = 1;
+
+ /* For an anonymous struct or union, we must recursively
+ consider the fields of the anonymous type. They can be
+ directly initialized from the constructor. */
+ if (ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
+ {
+ /* Add this field itself. Synthesized copy constructors
+ initialize the entire aggregate. */
+ list = tree_cons (fields, NULL_TREE, list);
+ /* And now add the fields in the anonymous aggregate. */
+ list = build_field_list (TREE_TYPE (fields), list,
+ uses_unions_p);
+ }
+ /* Add this field. */
+ else if (DECL_NAME (fields))
+ list = tree_cons (fields, NULL_TREE, list);
+ }
- for (x = current_member_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos)
+ return list;
+}
+
+/* The MEMBER_INIT_LIST is a TREE_LIST. The TREE_PURPOSE of each list
+ gives a FIELD_DECL in T that needs initialization. The TREE_VALUE
+ gives the initializer, or list of initializer arguments. Sort the
+ MEMBER_INIT_LIST, returning a version that contains the same
+ information but in the order that the fields should actually be
+ initialized. Perform error-checking in the process. */
+
+static tree
+sort_member_init (t, member_init_list)
+ tree t;
+ tree member_init_list;
+{
+ tree init_list;
+ tree last_field;
+ tree init;
+ int uses_unions_p;
+
+ /* Build up a list of the various fields, in sorted order. */
+ init_list = nreverse (build_field_list (t, NULL_TREE, &uses_unions_p));
+
+ /* Go through the explicit initializers, adding them to the
+ INIT_LIST. */
+ last_field = init_list;
+ for (init = member_init_list; init; init = TREE_CHAIN (init))
+ {
+ tree f;
+ tree initialized_field;
+
+ initialized_field = TREE_PURPOSE (init);
+ my_friendly_assert (TREE_CODE (initialized_field) == FIELD_DECL,
+ 20000516);
+
+ /* If the explicit initializers are in sorted order, then the
+ INITIALIZED_FIELD will be for a field following the
+ LAST_FIELD. */
+ for (f = last_field; f; f = TREE_CHAIN (f))
+ if (TREE_PURPOSE (f) == initialized_field)
+ break;
+
+ /* Give a warning, if appropriate. */
+ if (warn_reorder && !f)
{
- /* If we cleared this out, then pay no attention to it. */
- if (TREE_PURPOSE (x) == NULL_TREE)
- 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 one member shadows another, get the outermost one. */
- if (TREE_CODE (field) == TREE_LIST)
- field = TREE_VALUE (field);
-
- if (field == member)
- {
- if (warn_reorder)
- {
- if (pos < last_pos)
- {
- cp_warning_at ("member initializers for `%#D'", last_field);
- cp_warning_at (" and `%#D'", field);
- warning (" will be re-ordered to match declaration order");
- }
- last_pos = pos;
- last_field = field;
- }
+ cp_warning_at ("member initializers for `%#D'",
+ TREE_PURPOSE (last_field));
+ cp_warning_at (" and `%#D'", initialized_field);
+ warning (" will be re-ordered to match declaration order");
+ }
- /* Make sure we won't try to work on this init again. */
- TREE_PURPOSE (x) = NULL_TREE;
- x = build_tree_list (name, TREE_VALUE (x));
- goto got_it;
- }
+ /* Look again, from the beginning of the list. We must find the
+ field on this loop. */
+ if (!f)
+ {
+ f = init_list;
+ while (TREE_PURPOSE (f) != initialized_field)
+ f = TREE_CHAIN (f);
}
- /* If we didn't find MEMBER in the list, create a dummy entry
- so the two lists (INIT_LIST and the list of members) will be
- symmetrical. */
- x = build_tree_list (NULL_TREE, NULL_TREE);
- got_it:
- init_list = chainon (init_list, x);
+ /* If there was already an explicit initializer for this field,
+ issue an error. */
+ if (TREE_TYPE (f))
+ error ("multiple initializations given for member `%D'",
+ initialized_field);
+ else
+ {
+ /* Mark the field as explicitly initialized. */
+ TREE_TYPE (f) = error_mark_node;
+ /* And insert the initializer. */
+ TREE_VALUE (f) = TREE_VALUE (init);
+ }
+
+ /* Remember the location of the last explicitly initialized
+ field. */
+ last_field = f;
}
- /* Initializers for base members go at the end. */
- for (x = current_member_init_list ; x ; x = TREE_CHAIN (x))
+ /* [class.base.init]
+
+ If a ctor-initializer specifies more than one mem-initializer for
+ multiple members of the same union (including members of
+ anonymous unions), the ctor-initializer is ill-formed. */
+ if (uses_unions_p)
{
- name = TREE_PURPOSE (x);
- if (name)
+ last_field = NULL_TREE;
+ for (init = init_list; init; init = TREE_CHAIN (init))
{
- if (purpose_member (name, init_list))
+ tree field;
+ tree field_type;
+ int done;
+
+ /* Skip uninitialized members. */
+ if (!TREE_TYPE (init))
+ continue;
+ /* See if this field is a member of a union, or a member of a
+ structure contained in a union, etc. */
+ field = TREE_PURPOSE (init);
+ for (field_type = DECL_CONTEXT (field);
+ !same_type_p (field_type, t);
+ field_type = TYPE_CONTEXT (field_type))
+ if (TREE_CODE (field_type) == UNION_TYPE)
+ break;
+ /* If this field is not a member of a union, skip it. */
+ if (TREE_CODE (field_type) != UNION_TYPE)
+ continue;
+
+ /* It's only an error if we have two initializers for the same
+ union type. */
+ if (!last_field)
{
- cp_error ("multiple initializations given for member `%D'",
- IDENTIFIER_CLASS_VALUE (name));
+ last_field = field;
continue;
}
+
+ /* See if LAST_FIELD and the field initialized by INIT are
+ members of the same union. If so, there's a problem,
+ unless they're actually members of the same structure
+ which is itself a member of a union. For example, given:
+
+ union { struct { int i; int j; }; };
+
+ initializing both `i' and `j' makes sense. */
+ field_type = DECL_CONTEXT (field);
+ done = 0;
+ do
+ {
+ tree last_field_type;
+
+ last_field_type = DECL_CONTEXT (last_field);
+ while (1)
+ {
+ if (same_type_p (last_field_type, field_type))
+ {
+ if (TREE_CODE (field_type) == UNION_TYPE)
+ error ("initializations for multiple members of `%T'",
+ last_field_type);
+ done = 1;
+ break;
+ }
+
+ if (same_type_p (last_field_type, t))
+ break;
+
+ last_field_type = TYPE_CONTEXT (last_field_type);
+ }
- init_list = chainon (init_list,
- build_tree_list (name, TREE_VALUE (x)));
- TREE_PURPOSE (x) = NULL_TREE;
+ /* If we've reached the outermost class, then we're
+ done. */
+ if (same_type_p (field_type, t))
+ break;
+
+ field_type = TYPE_CONTEXT (field_type);
+ }
+ while (!done);
+
+ last_field = field;
}
}
return init_list;
}
+/* Like sort_member_init, but used for initializers of base classes.
+ *RBASE_PTR is filled in with the initializers for non-virtual bases;
+ vbase_ptr gets the virtual bases. */
+
static void
-sort_base_init (t, rbase_ptr, vbase_ptr)
- tree t, *rbase_ptr, *vbase_ptr;
+sort_base_init (t, base_init_list, rbase_ptr, vbase_ptr)
+ tree t;
+ tree base_init_list;
+ tree *rbase_ptr, *vbase_ptr;
{
tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
@@ -361,71 +550,40 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
tree vbases = NULL_TREE;
/* First walk through and splice out vbase and invalid initializers.
- Also replace names with binfos. */
+ Also replace types with binfos. */
- last = tree_cons (NULL_TREE, NULL_TREE, current_base_init_list);
+ last = tree_cons (NULL_TREE, NULL_TREE, base_init_list);
for (x = TREE_CHAIN (last); x; x = TREE_CHAIN (x))
{
tree basetype = TREE_PURPOSE (x);
- tree binfo = NULL_TREE;
+ tree binfo = (TREE_CODE (basetype) == TREE_VEC
+ ? basetype : binfo_or_else (basetype, t));
+
+ if (binfo == NULL_TREE)
+ /* BASETYPE might be an inaccessible direct base (because it
+ is also an indirect base). */
+ continue;
- if (basetype == NULL_TREE)
+ if (TREE_VIA_VIRTUAL (binfo))
{
- /* Initializer for single base class. Must not
- use multiple inheritance or this is ambiguous. */
- switch (n_baseclasses)
- {
- case 0:
- cp_error ("`%T' does not have a base class to initialize",
- current_class_type);
- return;
- case 1:
- break;
- default:
- cp_error ("unnamed initializer ambiguous for `%T' which uses multiple inheritance",
- current_class_type);
- return;
- }
- binfo = TREE_VEC_ELT (binfos, 0);
+ /* Virtual base classes are special cases. Their
+ initializers are recorded with this constructor, and they
+ are used when this constructor is the top-level
+ constructor called. */
+ tree v = binfo_for_vbase (BINFO_TYPE (binfo), t);
+ vbases = tree_cons (v, TREE_VALUE (x), vbases);
}
- else if (is_aggr_type (basetype, 1))
+ else
{
- binfo = binfo_or_else (basetype, t);
- if (binfo == NULL_TREE)
- continue;
-
- /* Virtual base classes are special cases. Their initializers
- are recorded with this constructor, and they are used when
- 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);
-
- vbases = tree_cons (v, TREE_VALUE (x), vbases);
- continue;
- }
- else
- {
- /* Otherwise, if it is not an immediate base class, complain. */
- for (i = n_baseclasses-1; i >= 0; i--)
- if (BINFO_TYPE (binfo) == BINFO_TYPE (TREE_VEC_ELT (binfos, i)))
- break;
- if (i < 0)
- {
- cp_error ("`%T' is not an immediate base class of `%T'",
- basetype, current_class_type);
- continue;
- }
- }
+ /* Otherwise, it must be an immediate base class. */
+ my_friendly_assert
+ (same_type_p (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo)),
+ t), 20011113);
+
+ TREE_PURPOSE (x) = binfo;
+ TREE_CHAIN (last) = x;
+ last = x;
}
- else
- my_friendly_abort (365);
-
- TREE_PURPOSE (x) = binfo;
- TREE_CHAIN (last) = x;
- last = x;
}
TREE_CHAIN (last) = NULL_TREE;
@@ -433,20 +591,24 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
for (i = 0; i < n_baseclasses; ++i)
{
+ /* The base for which we're currently initializing. */
tree base_binfo = TREE_VEC_ELT (binfos, i);
+ /* The initializer for BASE_BINFO. */
+ tree init;
int pos;
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
- for (x = current_base_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos)
+ /* We haven't found the BASE_BINFO yet. */
+ init = NULL_TREE;
+ /* Loop through all the explicitly initialized bases, looking
+ for an appropriate initializer. */
+ for (x = base_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos)
{
tree binfo = TREE_PURPOSE (x);
- if (binfo == NULL_TREE)
- continue;
-
- if (binfo == base_binfo)
+ if (binfo == base_binfo && !init)
{
if (warn_reorder)
{
@@ -462,169 +624,52 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
/* Make sure we won't try to work on this init again. */
TREE_PURPOSE (x) = NULL_TREE;
- x = build_tree_list (binfo, TREE_VALUE (x));
- goto got_it;
+ init = build_tree_list (binfo, TREE_VALUE (x));
+ }
+ else if (binfo == base_binfo)
+ {
+ error ("base class `%T' already initialized",
+ BINFO_TYPE (binfo));
+ break;
}
}
/* If we didn't find BASE_BINFO in the list, create a dummy entry
so the two lists (RBASES and the list of bases) will be
symmetrical. */
- x = build_tree_list (NULL_TREE, NULL_TREE);
- got_it:
- rbases = chainon (rbases, x);
+ if (!init)
+ init = build_tree_list (NULL_TREE, NULL_TREE);
+ rbases = chainon (rbases, init);
}
*rbase_ptr = rbases;
*vbase_ptr = vbases;
}
-/* Invoke a base-class destructor. REF is the object being destroyed,
- BINFO is the base class, and DTOR_ARG indicates whether the base
- class should invoke delete. */
-
-tree
-build_base_dtor_call (ref, binfo, dtor_arg)
- tree ref, binfo, dtor_arg;
-{
- tree args = NULL_TREE;
- tree vlist = lookup_name (vlist_identifier, 0);
- tree call, decr;
-
- if (TYPE_USES_PVBASES (BINFO_TYPE (binfo)))
- {
- args = expr_tree_cons (NULL_TREE, vlist, args);
- dtor_arg = build (BIT_IOR_EXPR, integer_type_node,
- dtor_arg, build_int_2 (4, 0));
- dtor_arg = fold (dtor_arg);
- }
- args = expr_tree_cons (NULL_TREE, dtor_arg, args);
- call = build_scoped_method_call (ref, binfo, dtor_identifier, args);
-
- if (!TYPE_USES_PVBASES (BINFO_TYPE (binfo)))
- /* For plain inheritance, do not try to adjust __vlist. */
- return call;
-
- /* Now decrement __vlist by the number of slots consumed by the base
- dtor. */
- decr = build_int_2 (pvbasecount (BINFO_TYPE (binfo), 0), 0);
- decr = build_binary_op (MINUS_EXPR, vlist, decr);
- decr = build_modify_expr (vlist, NOP_EXPR, decr);
-
- return build (COMPOUND_EXPR, void_type_node, call, decr);
-}
-
-/* Return the number of vlist entries needed to initialize TYPE,
- depending on whether it is IN_CHARGE. */
-
-static int
-pvbasecount (type, in_charge)
- tree type;
- int in_charge;
-{
- int i;
- int result = 0;
- tree vbase;
-
- for (vbase = (CLASSTYPE_VBASECLASSES (type)); vbase;
- vbase = TREE_CHAIN (vbase))
- {
- result += list_length (CLASSTYPE_VFIELDS (BINFO_TYPE (vbase)));
- if (in_charge)
- result += pvbasecount (BINFO_TYPE (vbase), 0);
- }
-
- for (i=0; i < CLASSTYPE_N_BASECLASSES (type); i++)
- {
- tree base = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i);
- if (TREE_VIA_VIRTUAL (base))
- continue;
- result += pvbasecount (BINFO_TYPE (base), 0);
- }
- return result;
-}
-
-void
-init_vlist (t)
- tree t;
-{
- char *name;
- tree expr;
- tree vlist = lookup_name (vlist_identifier, 0);
-
- name = alloca (strlen (VLIST_NAME_FORMAT)
- + TYPE_ASSEMBLER_NAME_LENGTH (t) + 2);
- sprintf (name, VLIST_NAME_FORMAT, TYPE_ASSEMBLER_NAME_STRING (t));
-
- expr = get_identifier (name);
- expr = lookup_name (expr, 0);
- expr = build1 (ADDR_EXPR, TREE_TYPE (vlist), expr);
- if (DECL_DESTRUCTOR_FOR_PVBASE_P (current_function_decl))
- /* Move to the end of the vlist. */
- expr = build_binary_op (PLUS_EXPR, expr,
- build_int_2 (pvbasecount (t, 1), 0));
- expand_expr_stmt (build_modify_expr (vlist, NOP_EXPR, expr));
-}
-
/* 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
- NULL_TREE, meaning that the user has explicitly called the base
- class constructor with no arguments.
+ class, and non-static data members, of the CURRENT_CLASS_TYPE.
+ These actions are given by the BASE_INIT_LIST and MEM_INIT_LIST,
+ respectively.
If there is a need for a call to a constructor, we must surround
that call with a pushlevel/poplevel pair, since we are technically
- at the PARM level of scope.
-
- Argument IMMEDIATELY, if zero, forces a new sequence to be
- generated to contain these new insns, so it can be emitted later.
- This sequence is saved in the global variable BASE_INIT_EXPR.
- Otherwise, the insns are emitted into the current sequence.
-
- Note that emit_base_init does *not* initialize virtual base
- classes. That is done specially, elsewhere. */
-
-extern tree base_init_expr, rtl_expr_chain;
+ at the PARM level of scope. */
void
-emit_base_init (t, immediately)
- tree t;
- int immediately;
+emit_base_init (mem_init_list, base_init_list)
+ tree mem_init_list;
+ tree base_init_list;
{
tree member;
- tree mem_init_list;
tree rbase_init_list, vbase_init_list;
+ tree t = current_class_type;
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;
- tree vlist = lookup_name (vlist_identifier, 0);
-
- 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));
-
- mem_init_list = sort_member_init (t);
- current_member_init_list = NULL_TREE;
+ int i;
+ int n_baseclasses = BINFO_N_BASETYPES (t_binfo);
- sort_base_init (t, &rbase_init_list, &vbase_init_list);
- current_base_init_list = NULL_TREE;
+ mem_init_list = sort_member_init (t, mem_init_list);
+ sort_base_init (t, base_init_list, &rbase_init_list, &vbase_init_list);
/* First, initialize the virtual base classes, if we are
constructing the most-derived object. */
@@ -652,151 +697,94 @@ emit_base_init (t, immediately)
else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo)))
{
init = NULL_TREE;
- if (extra_warnings && copy_args_p (current_function_decl))
- cp_warning ("base class `%#T' should be explicitly initialized in the copy constructor",
+ if (extra_warnings
+ && DECL_COPY_CONSTRUCTOR_P (current_function_decl))
+ warning ("base class `%#T' should be explicitly initialized in the copy constructor",
BINFO_TYPE (base_binfo));
}
if (init != void_list_node)
{
- expand_start_target_temps ();
-
- member = convert_pointer_to_real (base_binfo, current_class_ptr);
+ member = build_base_path (PLUS_EXPR, current_class_ptr,
+ base_binfo, 1);
expand_aggr_init_1 (base_binfo, NULL_TREE,
- build_indirect_ref (member, NULL_PTR), init,
+ build_indirect_ref (member, NULL), init,
LOOKUP_NORMAL);
-
- expand_end_target_temps ();
- free_temp_slots ();
}
- expand_cleanup_for_base (base_binfo, vlist, NULL_TREE);
+ 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 (current_class_ptr);
- for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member))
+ while (mem_init_list)
{
- tree init, name;
+ tree init;
+ tree member;
int from_init_list;
- /* member could be, for example, a CONST_DECL for an enumerated
- tag; we don't want to try to initialize that, since it already
- has a value. */
- if (TREE_CODE (member) != FIELD_DECL || !DECL_NAME (member))
- continue;
+ member = TREE_PURPOSE (mem_init_list);
/* See if we had a user-specified member initialization. */
- if (TREE_PURPOSE (mem_init_list))
+ if (TREE_TYPE (mem_init_list))
{
- name = TREE_PURPOSE (mem_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
}
else
{
- name = DECL_NAME (member);
init = DECL_INITIAL (member);
-
from_init_list = 0;
/* Effective C++ rule 12. */
if (warn_ecpp && init == NULL_TREE
&& !DECL_ARTIFICIAL (member)
&& TREE_CODE (TREE_TYPE (member)) != ARRAY_TYPE)
- cp_warning ("`%D' should be initialized in the member initialization list", member);
+ warning ("`%D' should be initialized in the member initialization list", member);
}
- perform_member_init (member, name, init, from_init_list);
+ perform_member_init (member, init, from_init_list);
mem_init_list = TREE_CHAIN (mem_init_list);
}
+}
- /* Now initialize any members from our bases. */
- while (mem_init_list)
- {
- tree name, init, field;
-
- if (TREE_PURPOSE (mem_init_list))
- {
- 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 one member shadows another, get the outermost one. */
- if (TREE_CODE (field) == TREE_LIST)
- {
- field = TREE_VALUE (field);
- if (decl_type_context (field) != current_class_type)
- 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
+/* Returns the address of the vtable (i.e., the value that should be
+ assigned to the vptr) for BINFO. */
- perform_member_init (field, name, init, 1);
- }
- mem_init_list = TREE_CHAIN (mem_init_list);
- }
+static tree
+build_vtbl_address (binfo)
+ tree binfo;
+{
+ tree binfo_for = binfo;
+ tree vtbl;
+
+ if (BINFO_VPTR_INDEX (binfo) && TREE_VIA_VIRTUAL (binfo)
+ && BINFO_PRIMARY_P (binfo))
+ /* If this is a virtual primary base, then the vtable we want to store
+ is that for the base this is being used as the primary base of. We
+ can't simply skip the initialization, because we may be expanding the
+ inits of a subobject constructor where the virtual base layout
+ can be different. */
+ while (BINFO_PRIMARY_BASE_OF (binfo_for))
+ binfo_for = BINFO_PRIMARY_BASE_OF (binfo_for);
+
+ /* Figure out what vtable BINFO's vtable is based on, and mark it as
+ used. */
+ vtbl = get_vtbl_decl_for_binfo (binfo_for);
+ assemble_external (vtbl);
+ TREE_USED (vtbl) = 1;
- if (! immediately)
+ /* Now compute the address to use when initializing the vptr. */
+ vtbl = BINFO_VTABLE (binfo_for);
+ if (TREE_CODE (vtbl) == VAR_DECL)
{
- 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;
+ vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
+ TREE_CONSTANT (vtbl) = 1;
}
- /* All the implicit try blocks we built up will be zapped
- when we come to a real binding contour boundary. */
-}
-
-/* Check that all fields are properly initialized after
- an assignment to `this'. */
-
-void
-check_base_init (t)
- tree t;
-{
- tree member;
- for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member))
- if (DECL_NAME (member) && TREE_USED (member))
- cp_error ("field `%D' used before initialized (after assignment to `this')",
- member);
+ return vtbl;
}
/* This code sets up the virtual function tables appropriate for
@@ -809,27 +797,47 @@ static void
expand_virtual_init (binfo, decl)
tree binfo, decl;
{
- tree type = BINFO_TYPE (binfo);
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));
- 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);
- 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. */
+ tree vtt_index;
+
+ /* Compute the initializer for vptr. */
+ vtbl = build_vtbl_address (binfo);
+
+ /* We may get this vptr from a VTT, if this is a subobject
+ constructor or subobject destructor. */
+ vtt_index = BINFO_VPTR_INDEX (binfo);
+ if (vtt_index)
+ {
+ tree vtbl2;
+ tree vtt_parm;
+
+ /* Compute the value to use, when there's a VTT. */
+ vtt_parm = current_vtt_parm;
+ vtbl2 = build (PLUS_EXPR,
+ TREE_TYPE (vtt_parm),
+ vtt_parm,
+ vtt_index);
+ vtbl2 = build1 (INDIRECT_REF, TREE_TYPE (vtbl), vtbl2);
+
+ /* The actual initializer is the VTT value only in the subobject
+ constructor. In maybe_clone_body we'll substitute NULL for
+ the vtt_parm in the case of the non-subobject constructor. */
+ vtbl = build (COND_EXPR,
+ TREE_TYPE (vtbl),
+ build (EQ_EXPR, boolean_type_node,
+ current_in_charge_parm, integer_zero_node),
+ vtbl2,
+ vtbl);
+ }
+
+ /* Compute the location of the vtpr. */
+ vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL),
+ TREE_TYPE (binfo));
+ my_friendly_assert (vtbl_ptr != error_mark_node, 20010730);
+
+ /* 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
@@ -839,39 +847,24 @@ expand_virtual_init (binfo, decl)
destroyed. */
static void
-expand_cleanup_for_base (binfo, vlist, flag)
+expand_cleanup_for_base (binfo, flag)
tree binfo;
- tree vlist;
tree flag;
{
tree expr;
- if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo)))
- {
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
+ if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (binfo)))
+ return;
- /* Call the destructor. */
- expr = build_base_dtor_call (current_class_ref, binfo,
- integer_zero_node);
- if (flag)
- expr = fold (build (COND_EXPR, void_type_node,
- truthvalue_conversion (flag),
- expr, integer_zero_node));
+ /* Call the destructor. */
+ expr = (build_scoped_method_call
+ (current_class_ref, binfo, base_dtor_identifier, NULL_TREE));
+ if (flag)
+ expr = fold (build (COND_EXPR, void_type_node,
+ truthvalue_conversion (flag),
+ expr, integer_zero_node));
- pop_obstacks ();
- add_partial_entry (expr);
- }
-
- if (TYPE_USES_PVBASES (BINFO_TYPE (binfo)))
- {
- /* Increment vlist by number of base's vbase classes. */
- expr = build_int_2 (pvbasecount (BINFO_TYPE (binfo), 0), 0);
- expr = build_binary_op (PLUS_EXPR, vlist, expr);
- expr = build_modify_expr (vlist, NOP_EXPR, expr);
- expand_expr_stmt (expr);
- }
+ finish_subobject (expr);
}
/* Subroutine of `expand_aggr_vbase_init'.
@@ -883,23 +876,18 @@ expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
tree binfo, exp, addr, init_list;
{
tree init = purpose_member (binfo, init_list);
- tree ref = build_indirect_ref (addr, NULL_PTR);
-
- expand_start_target_temps ();
+ tree ref = build_indirect_ref (addr, NULL);
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)
@@ -910,31 +898,19 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
tree flag;
{
tree vbases;
- tree result;
- tree vlist = NULL_TREE;
/* If there are no virtual baseclasses, we shouldn't even be here. */
my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621);
- /* First set the pointers in our object that tell us where to find
- our virtual baseclasses. */
- expand_start_cond (flag, 0);
- if (TYPE_USES_PVBASES (type))
- {
- init_vlist (type);
- vlist = lookup_name (vlist_identifier, 0);
- }
- result = init_vbase_pointers (type, this_ptr);
- if (result)
- expand_expr_stmt (build_compound_expr (result));
- expand_end_cond ();
-
/* 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;
+ tree vbase;
+
/* 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
@@ -949,13 +925,30 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
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. */
+ vbase = TREE_VALUE (vbases);
+ exp = build (PLUS_EXPR,
+ TREE_TYPE (this_ptr),
+ this_ptr,
+ fold (build1 (NOP_EXPR, TREE_TYPE (this_ptr),
+ BINFO_OFFSET (vbase))));
+ exp = build1 (NOP_EXPR,
+ build_pointer_type (BINFO_TYPE (vbase)),
+ exp);
+
+ expand_aggr_vbase_init_1 (vbase, 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, vlist, flag);
+ expand_cleanup_for_base (vbase, flag);
}
}
@@ -969,7 +962,7 @@ initializing_context (field)
/* 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;
}
@@ -985,19 +978,19 @@ static int
member_init_ok_or_else (field, type, member_name)
tree field;
tree type;
- const char *member_name;
+ tree member_name;
{
if (field == error_mark_node)
return 0;
if (field == NULL_TREE || initializing_context (field) != type)
{
- cp_error ("class `%T' does not have any field named `%s'", type,
+ error ("class `%T' does not have any field named `%D'", type,
member_name);
return 0;
}
if (TREE_STATIC (field))
{
- cp_error ("field `%#D' is static; only point of initialization is its declaration",
+ error ("field `%#D' is static; the only point of initialization is its definition",
field);
return 0;
}
@@ -1005,23 +998,18 @@ member_init_ok_or_else (field, type, member_name)
return 1;
}
-/* If NAME is a viable field name for the aggregate DECL,
- and PARMS is a viable parameter list, then expand an _EXPR
- which describes this initialization.
-
- Note that we do not need to chase through the class's base classes
- to look for NAME, because if it's in that list, it will be handled
- by the constructor for that base class.
-
- We do not yet have a fixed-point finder to instantiate types
- being fed to overloaded constructors. If there is a unique
- constructor, then argument types can be got from that one.
+/* EXP is an expression of aggregate type. NAME is an IDENTIFIER_NODE
+ which names a field, or it is a _TYPE node or TYPE_DECL which names
+ a base for that type. INIT is a parameter list for that field's or
+ base's constructor. Check the validity of NAME, and return a
+ TREE_LIST of the base _TYPE or FIELD_DECL and the INIT. EXP is used
+ only to get its type. If NAME is invalid, return NULL_TREE and
+ issue a diagnostic.
- If INIT is non-NULL, then it the initialization should
- be placed in `current_base_init_list', where it will be processed
- by `emit_base_init'. */
+ An old style unnamed direct single base construction is permitted,
+ where NAME is NULL. */
-void
+tree
expand_member_init (exp, name, init)
tree exp, name, init;
{
@@ -1029,109 +1017,75 @@ expand_member_init (exp, name, init)
tree type;
if (exp == NULL_TREE)
- return; /* complain about this later */
+ return NULL_TREE;
type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+ my_friendly_assert (IS_AGGR_TYPE (type), 20011113);
- if (name && TREE_CODE (name) == TYPE_DECL)
- {
- basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
- name = DECL_NAME (name);
- }
-
- if (name == NULL_TREE && IS_AGGR_TYPE (type))
- switch (CLASSTYPE_N_BASECLASSES (type))
- {
- case 0:
- error ("base class initializer specified, but no base class to initialize");
- return;
- case 1:
- basetype = TYPE_BINFO_BASETYPE (type, 0);
- break;
- default:
- error ("initializer for unnamed base class ambiguous");
- cp_error ("(type `%T' uses multiple inheritance)", type);
- return;
+ if (!name)
+ {
+ /* This is an obsolete unnamed base class initializer. The
+ parser will already have warned about its use. */
+ switch (CLASSTYPE_N_BASECLASSES (type))
+ {
+ case 0:
+ error ("unnamed initializer for `%T', which has no base classes",
+ type);
+ return NULL_TREE;
+ case 1:
+ basetype = TYPE_BINFO_BASETYPE (type, 0);
+ break;
+ default:
+ error ("unnamed initializer for `%T', which uses multiple inheritance",
+ type);
+ return NULL_TREE;
}
+ }
+ else if (TYPE_P (name))
+ {
+ basetype = name;
+ name = TYPE_NAME (name);
+ }
+ else if (TREE_CODE (name) == TYPE_DECL)
+ basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
my_friendly_assert (init != NULL_TREE, 0);
- /* The grammar should not allow fields which have names that are
- TYPENAMEs. Therefore, if the field has a non-NULL TREE_TYPE, we
- may assume that this is an attempt to initialize a base class
- member of the current type. Otherwise, it is an attempt to
- initialize a member field. */
-
if (init == void_type_node)
init = NULL_TREE;
- if (name == NULL_TREE || basetype)
+ if (basetype)
{
- tree base_init;
-
- if (name == NULL_TREE)
- {
-#if 0
- if (basetype)
- name = TYPE_IDENTIFIER (basetype);
- else
- {
- error ("no base class to initialize");
- return;
- }
-#endif
- }
- else if (basetype != type
- && ! current_template_parms
- && ! vec_binfo_member (basetype,
- TYPE_BINFO_BASETYPES (type))
- && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
+ if (current_template_parms)
+ ;
+ else if (vec_binfo_member (basetype, TYPE_BINFO_BASETYPES (type)))
+ /* A direct base. */;
+ else if (binfo_for_vbase (basetype, type))
+ /* A virtual base. */;
+ else
{
- if (IDENTIFIER_CLASS_VALUE (name))
- goto try_member;
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
- cp_error ("type `%T' is not an immediate or virtual basetype for `%T'",
- basetype, type);
+ error ("type `%D' is not a direct or virtual base of `%T'",
+ name, type);
else
- cp_error ("type `%T' is not an immediate basetype for `%T'",
- basetype, type);
- return;
- }
-
- if (purpose_member (basetype, current_base_init_list))
- {
- cp_error ("base class `%T' already initialized", basetype);
- return;
- }
-
- if (warn_reorder && current_member_init_list)
- {
- cp_warning ("base initializer for `%T'", basetype);
- warning (" will be re-ordered to precede member initializations");
+ error ("type `%D' is not a direct base of `%T'",
+ name, type);
+ return NULL_TREE;
}
- base_init = build_tree_list (basetype, init);
- current_base_init_list = chainon (current_base_init_list, base_init);
+ init = build_tree_list (basetype, init);
}
else
{
- tree member_init;
-
- try_member:
field = lookup_field (type, name, 1, 0);
- if (! member_init_ok_or_else (field, type, IDENTIFIER_POINTER (name)))
- return;
-
- if (purpose_member (name, current_member_init_list))
- {
- cp_error ("field `%D' already initialized", field);
- return;
- }
+ if (! member_init_ok_or_else (field, type, name))
+ return NULL_TREE;
- member_init = build_tree_list (name, init);
- current_member_init_list = chainon (current_member_init_list, member_init);
+ init = build_tree_list (field, init);
}
+
+ return init;
}
/* This is like `expand_member_init', only it stores one aggregate
@@ -1147,11 +1101,6 @@ expand_member_init (exp, name, init)
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
@@ -1172,17 +1121,20 @@ expand_member_init (exp, name, init)
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;
@@ -1195,13 +1147,8 @@ expand_aggr_init (exp, init, flags)
/* Must arrange to initialize each element of EXP
from elements of INIT. */
tree itype = init ? TREE_TYPE (init) : NULL_TREE;
- if (CP_TYPE_QUALS (type) != TYPE_UNQUALIFIED)
- {
- TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
- if (init)
- TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
- }
- if (init && TREE_TYPE (init) == NULL_TREE)
+
+ if (init && !itype)
{
/* Handle bad initializers like:
class COMPLEX {
@@ -1216,85 +1163,43 @@ expand_aggr_init (exp, init, flags)
}
*/
error ("bad array initializer");
- return;
+ return error_mark_node;
+ }
+ if (cp_type_quals (type) != TYPE_UNQUALIFIED)
+ {
+ TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
+ if (init)
+ TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
}
- 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, 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 ();
+ current_stmt_tree ()->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);
+ current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
TREE_TYPE (exp) = type;
TREE_READONLY (exp) = was_const;
TREE_THIS_VOLATILE (exp) = was_volatile;
-}
-
-static tree
-no_vlist_base_init (rval, exp, init, binfo, flags)
- tree rval, exp, init, binfo;
- int flags;
-{
- tree nrval, func, parms;
-
- /* Obtain the vlist-expecting ctor. */
- func = rval;
- my_friendly_assert (TREE_CODE (func) == CALL_EXPR, 20000131);
- func = TREE_OPERAND (func, 0);
- my_friendly_assert (TREE_CODE (func) == ADDR_EXPR, 20000132);
- func = TREE_OPERAND (func, 0);
- my_friendly_assert (TREE_CODE (func) == FUNCTION_DECL, 20000133);
-
- /* If we have already seen a definition for the wrapped function,
- we don't need to declare it weak. Also, declare_weak will complain
- if we do. */
- if (!TREE_ASM_WRITTEN (func))
- declare_weak (func);
-
- if (init == NULL_TREE
- || (TREE_CODE (init) == TREE_LIST && ! TREE_TYPE (init)))
- {
- parms = init;
- if (parms)
- init = TREE_VALUE (parms);
- }
- else
- parms = build_expr_list (NULL_TREE, init);
-
- flags &= ~LOOKUP_HAS_VLIST;
-
- parms = expr_tree_cons (NULL_TREE, integer_zero_node, parms);
- flags |= LOOKUP_HAS_IN_CHARGE;
-
- nrval = build_method_call (exp, ctor_identifier,
- parms, binfo, flags);
- func = build (NE_EXPR, boolean_type_node,
- func, null_pointer_node);
- nrval = build (COND_EXPR, void_type_node,
- func, rval, nrval);
- return nrval;
-}
+ return stmt_expr;
+}
static void
expand_default_init (binfo, true_exp, exp, init, flags)
@@ -1304,6 +1209,7 @@ expand_default_init (binfo, true_exp, exp, init, flags)
int flags;
{
tree type = TREE_TYPE (exp);
+ tree ctor_name;
/* It fails because there may not be a constructor which takes
its own type as the first (or only parameter), but which does
@@ -1313,8 +1219,6 @@ expand_default_init (binfo, true_exp, exp, init, flags)
out, then look hard. */
tree rval;
tree parms;
- tree vlist = NULL_TREE;
- tree orig_init = init;
if (init && TREE_CODE (init) != TREE_LIST
&& (flags & LOOKUP_ONLYCONVERTING))
@@ -1329,6 +1233,10 @@ expand_default_init (binfo, true_exp, exp, init, flags)
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);
@@ -1342,7 +1250,7 @@ expand_default_init (binfo, true_exp, exp, init, flags)
else
init = build (INIT_EXPR, TREE_TYPE (exp), exp, init);
TREE_SIDE_EFFECTS (init) = 1;
- expand_expr_stmt (init);
+ finish_expr_stmt (init);
return;
}
@@ -1354,40 +1262,21 @@ expand_default_init (binfo, true_exp, exp, init, flags)
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 (TYPE_USES_PVBASES (type))
- {
- /* In compatibility mode, when not calling a base ctor,
- we do not pass the vlist argument. */
- if (true_exp == exp)
- vlist = flag_vtable_thunks_compat? NULL_TREE : vlist_zero_node;
- else
- vlist = lookup_name (vlist_identifier, 0);
-
- if (vlist)
- {
- parms = expr_tree_cons (NULL_TREE, vlist, parms);
- flags |= LOOKUP_HAS_VLIST;
- }
- }
- if (true_exp == exp)
- parms = expr_tree_cons (NULL_TREE, integer_one_node, parms);
- else
- parms = expr_tree_cons (NULL_TREE, integer_zero_node, parms);
- flags |= LOOKUP_HAS_IN_CHARGE;
- }
+ if (true_exp == exp)
+ ctor_name = complete_ctor_identifier;
+ else
+ ctor_name = base_ctor_identifier;
- rval = build_method_call (exp, ctor_identifier,
- parms, binfo, flags);
- if (vlist && true_exp != exp && flag_vtable_thunks_compat)
+ rval = build_method_call (exp, ctor_name, parms, binfo, flags);
+ if (TREE_SIDE_EFFECTS (rval))
{
- rval = no_vlist_base_init (rval, exp, orig_init, binfo, flags);
+ if (building_stmt_tree ())
+ finish_expr_stmt (rval);
+ else
+ genrtl_expr_stmt (rval);
}
- if (TREE_SIDE_EFFECTS (rval))
- expand_expr_stmt (rval);
}
/* This function is responsible for initializing EXP with INIT
@@ -1407,8 +1296,6 @@ expand_default_init (binfo, true_exp, exp, init, flags)
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. */
@@ -1433,15 +1320,16 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
&& 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;
}
@@ -1450,39 +1338,6 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
expand_default_init (binfo, true_exp, exp, init, flags);
}
-/* Report an error if NAME is not the name of a user-defined,
- aggregate type. If OR_ELSE is nonzero, give an error message. */
-
-int
-is_aggr_typedef (name, or_else)
- tree name;
- int or_else;
-{
- tree type;
-
- if (name == error_mark_node)
- return 0;
-
- if (IDENTIFIER_HAS_TYPE_VALUE (name))
- type = IDENTIFIER_TYPE_VALUE (name);
- else
- {
- if (or_else)
- cp_error ("`%T' is not an aggregate typedef", name);
- return 0;
- }
-
- if (! IS_AGGR_TYPE (type)
- && TREE_CODE (type) != TEMPLATE_TYPE_PARM
- && TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
- {
- if (or_else)
- cp_error ("`%T' is not an aggregate type", type);
- return 0;
- }
- return 1;
-}
-
/* Report an error if TYPE is not a user-defined, aggregate type. If
OR_ELSE is nonzero, give an error message. */
@@ -1496,10 +1351,10 @@ is_aggr_type (type, or_else)
if (! IS_AGGR_TYPE (type)
&& TREE_CODE (type) != TEMPLATE_TYPE_PARM
- && TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
+ && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
{
if (or_else)
- cp_error ("`%T' is not an aggregate type", type);
+ error ("`%T' is not an aggregate type", type);
return 0;
}
return 1;
@@ -1522,16 +1377,16 @@ get_aggr_from_typedef (name, or_else)
else
{
if (or_else)
- cp_error ("`%T' fails to be an aggregate typedef", name);
+ error ("`%T' fails to be an aggregate typedef", name);
return NULL_TREE;
}
if (! IS_AGGR_TYPE (type)
&& TREE_CODE (type) != TEMPLATE_TYPE_PARM
- && TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
+ && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
{
if (or_else)
- cp_error ("type `%T' is of non-aggregate type", type);
+ error ("type `%T' is of non-aggregate type", type);
return NULL_TREE;
}
return type;
@@ -1549,7 +1404,7 @@ get_type_value (name)
else
return NULL_TREE;
}
-
+
/* This code could just as well go in `class.c', but is placed here for
modularity. */
@@ -1586,9 +1441,9 @@ build_member_call (type, name, parmlist)
return build_x_function_call (name, parmlist, current_class_ref);
}
- if (type == std_node)
- return build_x_function_call (do_scoped_id (name, 0), parmlist,
- current_class_ref);
+ if (DECL_P (name))
+ name = DECL_NAME (name);
+
if (TREE_CODE (type) == NAMESPACE_DECL)
return build_x_function_call (lookup_namespace_name (type, name),
parmlist, current_class_ref);
@@ -1619,7 +1474,8 @@ build_member_call (type, name, parmlist)
tree ns = lookup_name (type, 0);
if (ns && TREE_CODE (ns) == NAMESPACE_DECL)
{
- return build_x_function_call (build_offset_ref (type, name), parmlist, current_class_ref);
+ return build_x_function_call (build_offset_ref (type, name),
+ parmlist, current_class_ref);
}
}
@@ -1632,7 +1488,7 @@ build_member_call (type, name, parmlist)
if (dtor)
{
- cp_error ("cannot call destructor `%T::~%T' without object", type,
+ error ("cannot call destructor `%T::~%T' without object", type,
method_name);
return error_mark_node;
}
@@ -1652,7 +1508,7 @@ build_member_call (type, name, parmlist)
{
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);
+ decl = build_indirect_ref (decl, NULL);
}
}
@@ -1674,7 +1530,7 @@ build_member_call (type, name, parmlist)
{
if (is_dummy_object (decl))
{
- cp_error ("invalid use of non-static field `%D'", t);
+ error ("invalid use of non-static field `%D'", t);
return error_mark_node;
}
decl = build (COMPONENT_REF, TREE_TYPE (t), decl, t);
@@ -1683,7 +1539,7 @@ build_member_call (type, name, parmlist)
decl = t;
else
{
- cp_error ("invalid use of member `%D'", t);
+ error ("invalid use of member `%D'", t);
return error_mark_node;
}
if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl)))
@@ -1693,7 +1549,7 @@ build_member_call (type, name, parmlist)
}
else
{
- cp_error ("no method `%T::%D'", type, name);
+ error ("no method `%T::%D'", type, name);
return error_mark_node;
}
}
@@ -1721,17 +1577,50 @@ build_offset_ref (type, name)
if (TREE_CODE (name) == TEMPLATE_DECL)
return name;
- if (type == std_node)
- return do_scoped_id (name, 0);
-
if (processing_template_decl || uses_template_parms (type))
return build_min_nt (SCOPE_REF, type, name);
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+ {
+ /* If the NAME is a TEMPLATE_ID_EXPR, we are looking at
+ something like `a.template f<int>' or the like. For the most
+ part, we treat this just like a.f. We do remember, however,
+ the template-id that was used. */
+ name = TREE_OPERAND (orig_name, 0);
+
+ if (DECL_P (name))
+ name = DECL_NAME (name);
+ else
+ {
+ if (TREE_CODE (name) == LOOKUP_EXPR)
+ /* This can happen during tsubst'ing. */
+ name = TREE_OPERAND (name, 0);
+ else
+ {
+ if (TREE_CODE (name) == COMPONENT_REF)
+ name = TREE_OPERAND (name, 1);
+ if (TREE_CODE (name) == OVERLOAD)
+ name = DECL_NAME (OVL_CURRENT (name));
+ }
+ }
+
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 0);
+ }
+
+ if (type == NULL_TREE)
+ return error_mark_node;
+
/* Handle namespace names fully here. */
if (TREE_CODE (type) == NAMESPACE_DECL)
{
t = lookup_namespace_name (type, name);
- if (t != error_mark_node && ! type_unknown_p (t))
+ if (t == error_mark_node)
+ return t;
+ if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
+ /* Reconstruct the TEMPLATE_ID_EXPR. */
+ t = build (TEMPLATE_ID_EXPR, TREE_TYPE (t),
+ t, TREE_OPERAND (orig_name, 1));
+ if (! type_unknown_p (t))
{
mark_used (t);
t = convert_from_reference (t);
@@ -1739,42 +1628,21 @@ build_offset_ref (type, name)
return t;
}
- if (type == NULL_TREE || ! is_aggr_type (type, 1))
+ if (! is_aggr_type (type, 1))
return error_mark_node;
- if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
- {
- /* If the NAME is a TEMPLATE_ID_EXPR, we are looking at
- something like `a.template f<int>' or the like. For the most
- part, we treat this just like a.f. We do remember, however,
- the template-id that was used. */
- name = TREE_OPERAND (orig_name, 0);
-
- if (TREE_CODE (name) == LOOKUP_EXPR)
- /* This can happen during tsubst'ing. */
- name = TREE_OPERAND (name, 0);
-
- my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 0);
- }
-
if (TREE_CODE (name) == BIT_NOT_EXPR)
{
if (! check_dtor_name (type, name))
- cp_error ("qualified type `%T' does not match destructor name `~%T'",
+ error ("qualified type `%T' does not match destructor name `~%T'",
type, TREE_OPERAND (name, 0));
name = dtor_identifier;
}
-#if 0
- /* I think this is wrong, but the draft is unclear. --jason 6/15/98 */
- else if (name == constructor_name_full (type)
- || name == constructor_name (type))
- name = ctor_identifier;
-#endif
- if (TYPE_SIZE (complete_type (type)) == 0
+ if (!COMPLETE_TYPE_P (complete_type (type))
&& !TYPE_BEING_DEFINED (type))
{
- cp_error ("incomplete type `%T' does not have member `%D'", type,
+ error ("incomplete type `%T' does not have member `%D'", type,
name);
return error_mark_node;
}
@@ -1786,8 +1654,7 @@ build_offset_ref (type, name)
if (member == error_mark_node)
return error_mark_node;
- /* A lot of this logic is now handled in lookup_field and
- lookup_fnfield. */
+ /* A lot of this logic is now handled in lookup_member. */
if (member && BASELINK_P (member))
{
/* Go from the TREE_BASELINK to the member function info. */
@@ -1807,14 +1674,14 @@ build_offset_ref (type, name)
/* 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,
- build (TEMPLATE_ID_EXPR,
- TREE_TYPE (t),
- t,
- TREE_OPERAND (orig_name, 1)));
+
+ t = build (TEMPLATE_ID_EXPR, TREE_TYPE (t), t,
+ TREE_OPERAND (orig_name, 1));
+ t = build (OFFSET_REF, unknown_type_node, decl, t);
+
+ PTRMEM_OK_P (t) = 1;
+
+ return t;
}
if (!really_overloaded_fn (t))
@@ -1823,35 +1690,28 @@ build_offset_ref (type, name)
t = OVL_CURRENT (t);
/* unique functions are handled easily. */
- basebinfo = TREE_PURPOSE (fnfields);
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);
+ t = build (OFFSET_REF, TREE_TYPE (t), decl, t);
+ PTRMEM_OK_P (t) = 1;
+ return 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);
+
+ t = build (OFFSET_REF, unknown_type_node, decl, fnfields);
+ PTRMEM_OK_P (t) = 1;
+ return t;
}
t = member;
if (t == NULL_TREE)
{
- cp_error ("`%D' is not a member of type `%T'", name, type);
+ error ("`%D' is not a member of type `%T'", name, type);
return error_mark_node;
}
@@ -1870,19 +1730,21 @@ build_offset_ref (type, name)
if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t))
{
- cp_error ("illegal pointer to bit field `%D'", t);
+ error ("illegal pointer to bit-field `%D'", t);
return error_mark_node;
}
/* static class functions too. */
if (TREE_CODE (t) == FUNCTION_DECL
&& TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
- my_friendly_abort (53);
+ abort ();
/* In member functions, the form `type::name' is no longer
equivalent to `this->type::name', at least not until
resolve_offset_ref. */
- return build (OFFSET_REF, build_offset_type (type, TREE_TYPE (t)), decl, t);
+ t = build (OFFSET_REF, build_offset_type (type, TREE_TYPE (t)), decl, t);
+ PTRMEM_OK_P (t) = 1;
+ return t;
}
/* If a OFFSET_REF made it through to here, then it did
@@ -1915,18 +1777,19 @@ resolve_offset_ref (exp)
base = current_class_ref;
}
- if (BASELINK_P (member))
- {
- cp_pedwarn ("assuming & on overloaded member function");
- return build_unary_op (ADDR_EXPR, exp, 0);
- }
-
+ if (BASELINK_P (member) || TREE_CODE (member) == TEMPLATE_ID_EXPR)
+ 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)
+ /* A single non-static member, make sure we don't allow a
+ pointer-to-member. */
+ exp = ovl_cons (member, NULL_TREE);
+
return build_unary_op (ADDR_EXPR, exp, 0);
}
-
+
if ((TREE_CODE (member) == VAR_DECL
&& ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member))
&& ! TYPE_PTRMEM_P (TREE_TYPE (member)))
@@ -1946,13 +1809,9 @@ resolve_offset_ref (exp)
have been seen as static to be grok'd as non-static. */
if (TREE_CODE (member) == FIELD_DECL && current_class_ref == NULL_TREE)
{
- if (TREE_ADDRESSABLE (member) == 0)
- {
- cp_error_at ("member `%D' is non-static but referenced as a static member",
- member);
- error ("at this point in file");
- TREE_ADDRESSABLE (member) = 1;
- }
+ cp_error_at ("member `%D' is non-static but referenced as a static member",
+ member);
+ error ("at this point in file");
return error_mark_node;
}
@@ -1960,31 +1819,39 @@ resolve_offset_ref (exp)
if (TREE_CODE (member) == FIELD_DECL
&& (base == current_class_ref || is_dummy_object (base)))
{
- tree basetype_path;
tree expr;
+ basetype = DECL_CONTEXT (member);
+
+ /* Try to get to basetype from 'this'; if that doesn't work,
+ nothing will. */
+ base = current_class_ref;
+
+ /* First convert to the intermediate base specified, if appropriate. */
if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
- basetype = TYPE_OFFSET_BASETYPE (type);
- else
- basetype = DECL_CONTEXT (member);
+ base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type));
- base = current_class_ptr;
-
- if (get_base_distance (basetype, TREE_TYPE (TREE_TYPE (base)), 0, &basetype_path) < 0)
+ /* Don't check access on the conversion; we might be after a member
+ promoted by an access- or using-declaration, and we have already
+ checked access for the member itself. */
+ basetype = lookup_base (TREE_TYPE (base), basetype, ba_ignore, NULL);
+ expr = build_base_path (PLUS_EXPR, base, basetype, 1);
+
+ if (expr == error_mark_node)
+ return error_mark_node;
+
+ type = TREE_TYPE (member);
+ if (TREE_CODE (type) != REFERENCE_TYPE)
{
- error_not_base_type (basetype, TREE_TYPE (TREE_TYPE (base)));
- return error_mark_node;
+ int quals = cp_type_quals (type) | cp_type_quals (TREE_TYPE (expr));
+
+ if (DECL_MUTABLE_P (member))
+ quals &= ~TYPE_QUAL_CONST;
+
+ type = cp_build_qualified_type (type, quals);
}
- /* Kludge: we need to use basetype_path now, because
- convert_pointer_to will bash it. */
- enforce_access (basetype_path, member);
- addr = convert_pointer_to (basetype, base);
-
- /* 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);
+
+ expr = build (COMPONENT_REF, type, expr, member);
return convert_from_reference (expr);
}
@@ -2002,40 +1869,38 @@ resolve_offset_ref (exp)
{
if (addr == error_mark_node)
{
- cp_error ("object missing in `%E'", exp);
+ error ("object missing in `%E'", exp);
return error_mark_node;
}
basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member)));
- addr = convert_pointer_to (basetype, addr);
- member = cp_convert (ptrdiff_type_node, member);
+ basetype = lookup_base (TREE_TYPE (TREE_TYPE (addr)),
+ basetype, ba_check, NULL);
+ addr = build_base_path (PLUS_EXPR, addr, basetype, 1);
- /* 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));
+ member = cp_convert (ptrdiff_type_node, member);
- return build1 (INDIRECT_REF, type,
- build (PLUS_EXPR, build_pointer_type (type),
- addr, member));
+ addr = build (PLUS_EXPR, build_pointer_type (type), addr, member);
+ return build_indirect_ref (addr, 0);
}
else if (TYPE_PTRMEMFUNC_P (TREE_TYPE (member)))
{
return get_member_function_from_ptrfunc (&addr, member);
}
- my_friendly_abort (56);
+ abort ();
/* NOTREACHED */
return NULL_TREE;
}
-/* Return either DECL or its known constant value (if it has one). */
+/* If DECL is a `const' declaration, and its value is a known
+ constant, then return that value. */
tree
decl_constant_value (decl)
tree decl;
{
- if (! TREE_THIS_VOLATILE (decl)
+ if (TREE_READONLY_DECL_P (decl)
+ && ! TREE_THIS_VOLATILE (decl)
&& DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node
/* This is invalid if initial value is not constant.
@@ -2057,8 +1922,7 @@ build_builtin_delete_call (addr)
tree addr;
{
mark_used (global_delete_fndecl);
- return build_call (global_delete_fndecl,
- void_type_node, build_expr_list (NULL_TREE, addr));
+ return build_call (global_delete_fndecl, build_tree_list (NULL_TREE, addr));
}
/* Generate a C++ "new" expression. DECL is either a TREE_LIST
@@ -2087,8 +1951,6 @@ build_builtin_delete_call (addr)
PLACEMENT is the `placement' list for user-defined operator new (). */
-extern int flag_check_new;
-
tree
build_new (placement, decl, init, use_global_new)
tree placement;
@@ -2099,8 +1961,6 @@ build_new (placement, decl, init, use_global_new)
tree nelts = NULL_TREE, t;
int has_array = 0;
- tree pending_sizes = NULL_TREE;
-
if (decl == error_mark_node)
return error_mark_node;
@@ -2108,19 +1968,15 @@ build_new (placement, decl, init, use_global_new)
{
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;
if (absdcl && TREE_CODE (absdcl) == CALL_EXPR)
- my_friendly_abort (215);
+ abort ();
while (absdcl && TREE_CODE (absdcl) == INDIRECT_REF)
{
last_absdcl = absdcl;
@@ -2152,8 +2008,8 @@ build_new (placement, decl, init, use_global_new)
}
else
{
- int flags = pedantic ? WANT_INT : (WANT_INT | WANT_ENUM);
- if (build_expr_type_conversion (flags, this_nelts, 0)
+ if (build_expr_type_conversion (WANT_INT | WANT_ENUM,
+ this_nelts, 0)
== NULL_TREE)
pedwarn ("size in array new must have integral type");
@@ -2165,7 +2021,7 @@ build_new (placement, decl, init, use_global_new)
nelts = integer_zero_node;
}
else
- nelts = build_binary_op (MULT_EXPR, nelts, this_nelts);
+ nelts = cp_build_binary_op (MULT_EXPR, nelts, this_nelts);
}
}
else
@@ -2179,17 +2035,7 @@ build_new (placement, decl, init, use_global_new)
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)
{
@@ -2220,9 +2066,9 @@ build_new (placement, decl, init, use_global_new)
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;
@@ -2264,45 +2110,53 @@ build_new (placement, decl, init, use_global_new)
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
+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_");
+ tree name = NULL_TREE, class_decl;
+ static tree CL_suffix = NULL_TREE;
+ if (CL_suffix == NULL_TREE)
+ CL_suffix = get_identifier("class$");
if (jclass_node == NULL_TREE)
{
- jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier("jclass"));
+ jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jclass"));
if (jclass_node == NULL_TREE)
- fatal("call to Java constructor, while `jclass' undefined");
+ fatal_error ("call to Java constructor, while `jclass' undefined");
+
jclass_node = TREE_TYPE (jclass_node);
}
- name = build_overload_with_type (CL_prefix, type);
+
+ /* Mangle the class$ field */
+ {
+ tree field;
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ if (DECL_NAME (field) == CL_suffix)
+ {
+ mangle_decl (field);
+ name = DECL_ASSEMBLER_NAME (field);
+ break;
+ }
+ if (!field)
+ internal_error ("can't find class$");
+ }
+
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;
@@ -2310,62 +2164,103 @@ build_java_class_ref (type)
DECL_ARTIFICIAL (class_decl) = 1;
DECL_IGNORED_P (class_decl) = 1;
pushdecl_top_level (class_decl);
- make_decl_rtl (class_decl, NULL_PTR, 1);
- pop_obstacks ();
+ make_decl_rtl (class_decl, NULL);
}
return class_decl;
}
+/* Returns the size of the cookie to use when allocating an array
+ whose elements have the indicated TYPE. Assumes that it is already
+ known that a cookie is needed. */
+
+static tree
+get_cookie_size (type)
+ tree type;
+{
+ tree cookie_size;
+
+ /* We need to allocate an additional max (sizeof (size_t), alignof
+ (true_type)) bytes. */
+ tree sizetype_size;
+ tree type_align;
+
+ sizetype_size = size_in_bytes (sizetype);
+ type_align = size_int (TYPE_ALIGN_UNIT (type));
+ if (INT_CST_LT_UNSIGNED (type_align, sizetype_size))
+ cookie_size = sizetype_size;
+ else
+ cookie_size = type_align;
+
+ return cookie_size;
+}
+
/* Called from cplus_expand_expr when expanding a NEW_EXPR. The return
value is immediately handed to expand_expr. */
-tree
+static tree
build_new_1 (exp)
tree exp;
{
tree placement, init;
- tree type, true_type, size, rval;
+ tree type, true_type, size, rval, t;
+ tree full_type;
tree nelts = NULL_TREE;
- tree alloc_expr, alloc_node = NULL_TREE;
+ tree alloc_call, alloc_expr, alloc_node;
+ tree cookie_expr, init_expr;
int has_array = 0;
- enum tree_code code = NEW_EXPR;
+ enum tree_code code;
int use_cookie, nothrow, check_new;
+ /* Nonzero if the user wrote `::new' rather than just `new'. */
+ int globally_qualified_p;
+ /* Nonzero if we're going to call a global operator new, rather than
+ a class-specific version. */
int use_global_new;
int use_java_new = 0;
+ /* If non-NULL, the number of extra bytes to allocate at the
+ beginning of the storage allocated for an array-new expression in
+ order to store the number of elements. */
+ tree cookie_size = NULL_TREE;
+ /* True if the function we are calling is a placement allocation
+ function. */
+ bool placement_allocation_fn_p;
placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1);
init = TREE_OPERAND (exp, 2);
- use_global_new = NEW_EXPR_USE_GLOBAL (exp);
+ globally_qualified_p = NEW_EXPR_USE_GLOBAL (exp);
if (TREE_CODE (type) == ARRAY_REF)
{
has_array = 1;
nelts = TREE_OPERAND (type, 1);
type = TREE_OPERAND (type, 0);
+
+ full_type = cp_build_binary_op (MINUS_EXPR, nelts, integer_one_node);
+ full_type = build_index_type (full_type);
+ full_type = build_cplus_array_type (type, full_type);
}
+ else
+ full_type = type;
+
true_type = type;
- if (CP_TYPE_QUALS (type))
- type = TYPE_MAIN_VARIANT (type);
+ code = has_array ? VEC_NEW_EXPR : NEW_EXPR;
/* If our base type is an array, then make sure we know how many elements
it has. */
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);
+ nelts = cp_build_binary_op (MULT_EXPR, nelts, this_nelts);
true_type = TREE_TYPE (true_type);
}
if (!complete_type_or_else (true_type, exp))
return error_mark_node;
+ size = size_in_bytes (true_type);
if (has_array)
- size = fold (build_binary_op (MULT_EXPR, size_in_bytes (true_type),
- nelts));
- else
- size = size_in_bytes (type);
+ size = fold (cp_build_binary_op (MULT_EXPR, size, nelts));
if (TREE_CODE (true_type) == VOID_TYPE)
{
@@ -2373,97 +2268,104 @@ build_new_1 (exp)
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 (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.
-
- Well, that's what we should do. For backwards compatibility, we
- have to do this whenever there's a two-argument array-delete
- operator.
+ if (abstract_virtuals_error (NULL_TREE, true_type))
+ return error_mark_node;
- 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));
+ /* Figure out whether or not we're going to use the global operator
+ new. */
+ if (!globally_qualified_p
+ && IS_AGGR_TYPE (true_type)
+ && (has_array
+ ? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
+ : TYPE_HAS_NEW_OPERATOR (true_type)))
+ use_global_new = 0;
+ else
+ use_global_new = 1;
+
+ /* We only need cookies for arrays containing types for which we
+ need cookies. */
+ if (!has_array || !TYPE_VEC_NEW_USES_COOKIE (true_type))
+ use_cookie = 0;
+ /* When using placement new, users may not realize that they need
+ the extra storage. We require that the operator called be
+ the global placement operator delete[]. */
+ else if (placement && !TREE_CHAIN (placement)
+ && same_type_p (TREE_TYPE (TREE_VALUE (placement)),
+ ptr_type_node))
+ use_cookie = !use_global_new;
+ /* Otherwise, we need the cookie. */
+ else
+ use_cookie = 1;
+ /* Compute the number of extra bytes to allocate, now that we know
+ whether or not we need the cookie. */
if (use_cookie)
{
- tree extra = BI_header_size;
-
- size = size_binop (PLUS_EXPR, size, extra);
- }
-
- if (has_array)
- {
- code = VEC_NEW_EXPR;
-
- if (init && pedantic)
- cp_pedwarn ("initialization in array new");
+ cookie_size = get_cookie_size (true_type);
+ size = size_binop (PLUS_EXPR, size, cookie_size);
}
/* 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);
tree class_size = size_in_bytes (true_type);
- static char alloc_name[] = "_Jv_AllocObject";
+ static const 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);
+ fatal_error ("call to Java constructor with `%s' undefined",
+ alloc_name);
+
class_addr = build1 (ADDR_EXPR, jclass_node, class_decl);
- rval = build_function_call (alloc_decl,
- tree_cons (NULL_TREE, class_addr,
- build_tree_list (NULL_TREE,
- class_size)));
- rval = cp_convert (build_pointer_type (true_type), rval);
+ alloc_call = (build_function_call
+ (alloc_decl,
+ tree_cons (NULL_TREE, class_addr,
+ build_tree_list (NULL_TREE, class_size))));
}
else
{
- 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 ();
+ tree fnname;
+ tree args;
- rval = build_op_new_call
- (code, true_type, expr_tree_cons (NULL_TREE, size, placement),
- LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL));
- rval = cp_convert (build_pointer_type (true_type), rval);
+ args = tree_cons (NULL_TREE, size, placement);
+ fnname = ansi_opname (code);
- if (flag_exceptions)
- resume_momentary (susp);
+ if (use_global_new)
+ alloc_call = (build_new_function_call
+ (lookup_function_nonclass (fnname, args),
+ args));
+ else
+ alloc_call = build_method_call (build_dummy_object (true_type),
+ fnname, args, NULL_TREE,
+ LOOKUP_NORMAL);
}
+ if (alloc_call == error_mark_node)
+ return error_mark_node;
+
+ /* The ALLOC_CALL should be a CALL_EXPR, and the first operand
+ should be the address of a known FUNCTION_DECL. */
+ my_friendly_assert (TREE_CODE (alloc_call) == CALL_EXPR, 20000521);
+ t = TREE_OPERAND (alloc_call, 0);
+ my_friendly_assert (TREE_CODE (t) == ADDR_EXPR, 20000521);
+ t = TREE_OPERAND (t, 0);
+ my_friendly_assert (TREE_CODE (t) == FUNCTION_DECL, 20000521);
+ /* Now, check to see if this function is actually a placement
+ allocation function. This can happen even when PLACEMENT is NULL
+ because we might have something like:
+
+ struct S { void* operator new (size_t, int i = 0); };
+
+ A call to `new S' will get this allocation function, even though
+ there is no explicit placement argument. If there is more than
+ one argument, or there are variable arguments, then this is a
+ placement allocation function. */
+ placement_allocation_fn_p
+ = (type_num_arguments (TREE_TYPE (t)) > 1 || varargs_function_p (t));
+
/* unless an allocation function is declared with an empty excep-
tion-specification (_except.spec_), throw(), it indicates failure to
allocate storage by throwing a bad_alloc exception (clause _except_,
@@ -2474,144 +2376,88 @@ build_new_1 (exp)
So check for a null exception spec on the op new we just called. */
- nothrow = 0;
- if (rval)
- {
- /* The CALL_EXPR. */
- tree t = TREE_OPERAND (rval, 0);
- /* The function. */
- t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
- nothrow = TYPE_NOTHROW_P (TREE_TYPE (t));
- }
+ /* The ADDR_EXPR. */
+ t = TREE_OPERAND (alloc_call, 0);
+ /* The function. */
+ t = TREE_OPERAND (t, 0);
+ nothrow = TYPE_NOTHROW_P (TREE_TYPE (t));
check_new = (flag_check_new || nothrow) && ! use_java_new;
- if ((check_new || flag_exceptions) && rval)
+ alloc_expr = alloc_call;
+
+ if (use_cookie)
+ /* Adjust so we're pointing to the start of the object. */
+ alloc_expr = build (PLUS_EXPR, TREE_TYPE (alloc_expr),
+ alloc_expr, cookie_size);
+
+ /* While we're working, use a pointer to the type we've actually
+ allocated. */
+ alloc_expr = convert (build_pointer_type (full_type), alloc_expr);
+
+ /* Now save the allocation expression so we only evaluate it once. */
+ alloc_expr = get_target_expr (alloc_expr);
+ alloc_node = TREE_OPERAND (alloc_expr, 0);
+
+ /* Now initialize the cookie. */
+ if (use_cookie)
{
- alloc_expr = get_target_expr (rval);
- alloc_node = rval = TREE_OPERAND (alloc_expr, 0);
- }
- else
- alloc_expr = NULL_TREE;
-
- /* if rval is NULL_TREE I don't have to allocate it, but are we totally
- sure we have some extra bytes in that case for the BI_header_size
- cookies? And how does that interact with the code below? (mrs) */
- /* Finish up some magic for new'ed arrays */
- if (use_cookie && rval != NULL_TREE)
- {
- 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));
- /* 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,
- 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 cookie;
- if (rval == error_mark_node)
- return error_mark_node;
+ /* Store the number of bytes allocated so that we can know how
+ many elements to destroy later. We use the last sizeof
+ (size_t) bytes to store the number of elements. */
+ cookie = build (MINUS_EXPR, build_pointer_type (sizetype),
+ alloc_node, size_in_bytes (sizetype));
+ cookie = build_indirect_ref (cookie, NULL);
- /* Don't call any constructors or do any initialization. */
- if (init == void_type_node)
- goto done;
+ cookie_expr = build (MODIFY_EXPR, void_type_node, cookie, nelts);
+ TREE_SIDE_EFFECTS (cookie_expr) = 1;
+ }
+ else
+ cookie_expr = NULL_TREE;
+ /* Now initialize the allocated object. */
+ init_expr = NULL_TREE;
if (TYPE_NEEDS_CONSTRUCTING (type) || init)
{
- if (! TYPE_NEEDS_CONSTRUCTING (type)
- && ! IS_AGGR_TYPE (type) && ! has_array)
+ init_expr = build_indirect_ref (alloc_node, NULL);
+
+ if (init == void_zero_node)
+ init = build_default_init (full_type);
+ else if (init && pedantic && has_array)
+ pedwarn ("ISO C++ forbids initialization in array new");
+
+ if (has_array)
+ init_expr = build_vec_init (init_expr, init, 0);
+ else if (TYPE_NEEDS_CONSTRUCTING (type))
+ init_expr = build_method_call (init_expr,
+ complete_ctor_identifier,
+ init, TYPE_BINFO (true_type),
+ LOOKUP_NORMAL);
+ else
{
/* 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)
- pedwarn ("initializer list being treated as compound expression");
- else if (TREE_CODE (init) == CONSTRUCTOR)
+
+ if (TREE_CODE (init) == TREE_LIST)
{
- pedwarn ("initializer list appears where operand should be used");
- init = TREE_OPERAND (init, 1);
+ if (TREE_CHAIN (init) != NULL_TREE)
+ pedwarn
+ ("initializer list being treated as compound expression");
+ init = build_compound_expr (init);
}
- init = build_compound_expr (init);
-
- init = convert_for_initialization (deref, type, init, LOOKUP_NORMAL,
- "new", NULL_TREE, 0);
- rval = build (COMPOUND_EXPR, TREE_TYPE (rval),
- build_modify_expr (deref, NOP_EXPR, init),
- rval);
- TREE_NO_UNUSED_WARNING (rval) = 1;
- TREE_SIDE_EFFECTS (rval) = 1;
- }
- else if (! has_array)
- {
- tree newrval;
- /* Constructors are never virtual. If it has an initialization, we
- need to complain if we aren't allowed to use the ctor that took
- that argument. */
- int flags = LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_COMPLAIN;
-
- if (rval && TYPE_USES_VIRTUAL_BASECLASSES (true_type))
+ else if (TREE_CODE (init) == CONSTRUCTOR
+ && TREE_TYPE (init) == NULL_TREE)
{
- if (TYPE_USES_PVBASES (true_type)
- && !flag_vtable_thunks_compat)
- {
- init = expr_tree_cons (NULL_TREE, vlist_zero_node, init);
- flags |= LOOKUP_HAS_VLIST;
- }
- init = expr_tree_cons (NULL_TREE, integer_one_node, init);
- flags |= LOOKUP_HAS_IN_CHARGE;
+ pedwarn ("ISO C++ forbids aggregate initializer to new");
+ init = digest_init (type, init, 0);
}
- if (use_java_new)
- rval = save_expr (rval);
- newrval = rval;
-
- if (newrval && TREE_CODE (TREE_TYPE (newrval)) == POINTER_TYPE)
- newrval = build_indirect_ref (newrval, NULL_PTR);
-
- newrval = build_method_call (newrval, ctor_identifier,
- init, TYPE_BINFO (true_type), flags);
-
- 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;
+ init_expr = build_modify_expr (init_expr, INIT_EXPR, init);
}
- else
- rval = build (VEC_INIT_EXPR, TREE_TYPE (rval),
- save_expr (rval), init, nelts);
+
+ if (init_expr == error_mark_node)
+ return error_mark_node;
/* If any part of the object initialization terminates by throwing an
exception and a suitable deallocation function can be found, the
@@ -2621,100 +2467,101 @@ build_new_1 (exp)
unambiguous matching deallocation function can be found,
propagating the exception does not cause the object's memory to be
freed. */
- if (flag_exceptions && alloc_expr && ! use_java_new)
+ if (flag_exceptions && ! use_java_new)
{
enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
- tree cleanup, fn = NULL_TREE;
- int flags = LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL);
+ tree cleanup;
+ int flags = (LOOKUP_NORMAL
+ | (globally_qualified_p * 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 = mapcar (size, permanent_p);
-
- cleanup = build_op_delete_call (dcode, alloc_node, size, flags, fn);
-
- resume_momentary (yes);
+ cleanup = build_op_delete_call (dcode, alloc_node, size, flags,
+ (placement_allocation_fn_p
+ ? alloc_call : NULL_TREE));
/* Ack! First we allocate the memory. Then we set our sentry
variable to true, and expand a cleanup that deletes the memory
- if sentry is true. Then we run the constructor and store the
- returned pointer in buf. Then we clear sentry and return buf. */
+ if sentry is true. Then we run the constructor, and finally
+ clear the sentry.
+
+ It would be nice to be able to handle this without the sentry
+ variable, perhaps with a TRY_CATCH_EXPR, but this doesn't
+ work. We allocate the space first, so if there are any
+ temporaries with cleanups in the constructor args we need this
+ EH region to extend until end of full-expression to preserve
+ nesting.
+
+ If the backend had some mechanism so that we could force the
+ allocation to be expanded after all the other args to the
+ constructor, that would fix the nesting problem and we could
+ do away with this complexity. But that would complicate other
+ things; in particular, it would make it difficult to bail out
+ if the allocation function returns null. */
if (cleanup)
{
- tree end, sentry, begin, buf, t = TREE_TYPE (rval);
+ tree end, sentry, begin;
begin = get_target_expr (boolean_true_node);
sentry = TREE_OPERAND (begin, 0);
- 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)));
+ init_expr
+ = build (COMPOUND_EXPR, void_type_node, begin,
+ build (COMPOUND_EXPR, void_type_node, init_expr,
+ end));
}
}
}
else if (CP_TYPE_CONST_P (true_type))
- cp_error ("uninitialized const in `new' of `%#T'", true_type);
-
- done:
+ error ("uninitialized const in `new' of `%#T'", true_type);
- if (alloc_expr && rval == alloc_node)
- {
- rval = TREE_OPERAND (alloc_expr, 1);
- alloc_expr = NULL_TREE;
- }
+ /* Now build up the return value in reverse order. */
- if (check_new && alloc_expr)
- {
- /* Did we modify the storage? */
- tree ifexp = build_binary_op (NE_EXPR, alloc_node,
- integer_zero_node);
- rval = build_conditional_expr (ifexp, rval, alloc_node);
- }
+ rval = alloc_node;
- if (alloc_expr)
- rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
+ if (init_expr)
+ rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval);
+ if (cookie_expr)
+ rval = build (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
- if (rval && TREE_TYPE (rval) != build_pointer_type (type))
+ if (rval == alloc_node)
+ /* If we didn't modify anything, strip the TARGET_EXPR and return the
+ (adjusted) call. */
+ rval = TREE_OPERAND (alloc_expr, 1);
+ else
{
- /* The type of new int [3][3] is not int *, but int [3] * */
- rval = build_c_cast (build_pointer_type (type), rval);
+ if (check_new)
+ {
+ tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node,
+ integer_zero_node);
+ rval = build_conditional_expr (ifexp, rval, alloc_node);
+ }
+
+ rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
}
+ /* Now strip the outer ARRAY_TYPE, so we return a pointer to the first
+ element. */
+ rval = convert (build_pointer_type (type), rval);
+
return rval;
}
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;
+ special_function_kind auto_delete_vec;
int use_global_delete;
{
tree virtual_size;
@@ -2740,16 +2587,17 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
This is also the containing expression returned by this function. */
tree controller = NULL_TREE;
- if (! IS_AGGR_TYPE (type) || ! TYPE_NEEDS_DESTRUCTOR (type))
+ if (! IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
{
loop = integer_zero_node;
goto no_destructor;
}
- /* The below is short by BI_header_size */
- virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex));
+ /* The below is short by the cookie size. */
+ virtual_size = size_binop (MULT_EXPR, size_exp,
+ convert (sizetype, 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,
@@ -2758,94 +2606,78 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
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, sfk_complete_destructor,
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)
- deallocate_expr = integer_zero_node;
- else
+ deallocate_expr = integer_zero_node;
+ if (auto_delete_vec != sfk_base_destructor)
{
tree base_tbd;
- /* The below is short by BI_header_size */
- virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex));
+ /* The below is short by the cookie size. */
+ virtual_size = size_binop (MULT_EXPR, size_exp,
+ convert (sizetype, maxindex));
if (! TYPE_VEC_NEW_USES_COOKIE (type))
/* no header */
base_tbd = base;
else
{
- base_tbd = cp_convert (ptype,
- build_binary_op (MINUS_EXPR,
- cp_convert (string_type_node, base),
- BI_header_size));
+ tree cookie_size;
+
+ cookie_size = get_cookie_size (type);
+ base_tbd
+ = cp_convert (ptype,
+ cp_build_binary_op (MINUS_EXPR,
+ cp_convert (string_type_node,
+ base),
+ cookie_size));
/* True size with header. */
- virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
+ virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size);
}
- 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);
+
+ if (auto_delete_vec == sfk_deleting_destructor)
+ deallocate_expr = build_x_delete (base_tbd,
+ 2 | use_global_delete,
+ virtual_size);
}
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)
@@ -2857,90 +2689,52 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
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. */
+/* Create an unnamed variable of the indicated TYPE. */
-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 ())
+ SET_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.
- MAXINDEX is the maximum index of the array (one less than the
- number of elements).
+ BASE is a reference to the vector, of ARRAY_TYPE.
INIT is the (possibly NULL) initializer.
FROM_ARRAY is 0 if we should init everything with INIT
@@ -2951,91 +2745,138 @@ expand_vec_init_catch_clause (rval, type, maxindex, iterator)
but use assignment instead of initialization. */
tree
-expand_vec_init (decl, base, maxindex, init, from_array)
- tree decl, base, maxindex, init;
+build_vec_init (base, init, from_array)
+ tree base, 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 the array. */
+ tree atype = TREE_TYPE (base);
+ /* The type of an element in the array. */
+ tree type = TREE_TYPE (atype);
+ /* 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;
+ tree maxindex = array_type_nelts (TREE_TYPE (base));
- maxindex = cp_convert (ptrdiff_type_node, maxindex);
if (maxindex == error_mark_node)
return error_mark_node;
- if (current_function_decl == NULL_TREE)
+ /* For g++.ext/arrnew.C. */
+ if (init && TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == NULL_TREE)
+ init = digest_init (atype, init, 0);
+
+ if (init && !TYPE_NEEDS_CONSTRUCTING (type)
+ && ((TREE_CODE (init) == CONSTRUCTOR
+ /* Don't do this if the CONSTRUCTOR might contain something
+ that might throw and require us to clean up. */
+ && (CONSTRUCTOR_ELTS (init) == NULL_TREE
+ || ! TYPE_HAS_NONTRIVIAL_DESTRUCTOR (target_type (type))))
+ || from_array))
{
- 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;
+ /* Do non-default initialization of POD arrays resulting from
+ brace-enclosed initializers. In this case, digest_init and
+ store_constructor will handle the semantics for us. */
+
+ stmt_expr = build (INIT_EXPR, atype, base, init);
+ TREE_SIDE_EFFECTS (stmt_expr) = 1;
+ return stmt_expr;
}
+ maxindex = cp_convert (ptrdiff_type_node, maxindex);
+ ptype = build_pointer_type (type);
size = size_in_bytes (type);
+ if (TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE)
+ base = cp_convert (ptype, default_conversion (base));
+
+ /* The code we are generating looks like:
- 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);
+ T* t1 = (T*) base;
+ T* rval = t1;
+ ptrdiff_t iterator = maxindex;
+ try {
+ do {
+ ... initialize *t1 ...
+ ++t1;
+ } while (--iterator != -1);
+ } catch (...) {
+ ... destroy elements that were constructed ...
+ }
+ return rval;
+
+ 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. 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 ();
+ current_stmt_tree ()->stmts_are_full_exprs_p = 0;
+ rval = get_temp_regvar (ptype, 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);
+ the partially constructed array if an exception is thrown.
+ But don't do this if we're assigning. */
+ if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+ && from_array != 2)
+ {
+ 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))))
+ if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
{
- /* Do non-default initialization resulting from brace-enclosed
- initializers. */
+ /* Do non-default initialization of non-POD arrays resulting from
+ brace-enclosed 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);
-
- expand_assignment (base,
- build (PLUS_EXPR, build_pointer_type (type),
- base, size),
- 0, 0);
- expand_assignment (iterator,
- build (MINUS_EXPR, ptrdiff_type_node,
- iterator, integer_one_node),
- 0, 0);
+ finish_expr_stmt (build_modify_expr (baseref, NOP_EXPR,
+ elt));
+
+ finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base, 0));
+ finish_expr_stmt (build_unary_op (PREDECREMENT_EXPR, iterator, 0));
}
/* 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 initializing one array from another, initialize element by
element. 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);
@@ -3060,20 +2901,39 @@ expand_vec_init (decl, base, maxindex, init, from_array)
if (from_array
|| (TYPE_NEEDS_CONSTRUCTING (type)
- && !(TREE_CODE (maxindex) == INTEGER_CST
- && num_initialized_elts == TREE_INT_CST_LOW (maxindex) + 1)))
+ && ! (host_integerp (maxindex, 0)
+ && (num_initialized_elts
+ == tree_low_cst (maxindex, 0) + 1))))
{
/* 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, integer_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)
{
@@ -3086,68 +2946,79 @@ expand_vec_init (decl, base, maxindex, init, 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);
+ abort ();
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
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);
+ sorry
+ ("cannot initialize multi-dimensional array with initializer");
+ elt_init = build_vec_init (build1 (INDIRECT_REF, type, base),
+ 0, 0);
}
else
- expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0);
+ elt_init = build_aggr_init (build1 (INDIRECT_REF, type, base),
+ init, 0);
+
+ /* The initialization of each array element is a
+ full-expression, as per core issue 124. */
+ if (!building_stmt_tree ())
+ {
+ genrtl_expr_stmt (elt_init);
+ expand_end_target_temps ();
+ }
+ else
+ {
+ current_stmt_tree ()->stmts_are_full_exprs_p = 1;
+ finish_expr_stmt (elt_init);
+ current_stmt_tree ()->stmts_are_full_exprs_p = 0;
+ }
- expand_assignment (base,
- build (PLUS_EXPR, build_pointer_type (type),
- base, size), 0, 0);
+ finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base, 0));
if (base2)
- expand_assignment (base2,
- build (PLUS_EXPR, build_pointer_type (type),
- base2, size), 0, 0);
+ finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base2, 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)
- {
- 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_unary_op (PREDECREMENT_EXPR, iterator, 0),
+ integer_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_HAS_NONTRIVIAL_DESTRUCTOR (type)
+ && from_array != 2)
{
- 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,
+ cp_build_binary_op (MINUS_EXPR, maxindex,
+ iterator),
+ type,
+ sfk_base_destructor,
+ /*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);
+ current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
+ return stmt_expr;
}
/* Free up storage of type TYPE, at address ADDR.
@@ -3160,7 +3031,7 @@ expand_vec_init (decl, base, maxindex, init, from_array)
things like padding and magic size cookies. It has virtual in it,
because if you have a base pointer and you delete through a virtual
destructor, it should be the size of the dynamic object, not the
- static object, see Free Store 12.5 ANSI C++ WP.
+ static object, see Free Store 12.5 ISO C++.
This does not call any destructors. */
@@ -3178,28 +3049,54 @@ build_x_delete (addr, which_delete, virtual_size)
return build_op_delete_call (code, addr, virtual_size, flags, NULL_TREE);
}
+/* Call the DTOR_KIND destructor for EXP. FLAGS are as for
+ build_delete. */
+
+static tree
+build_dtor_call (exp, dtor_kind, flags)
+ tree exp;
+ special_function_kind dtor_kind;
+ int flags;
+{
+ tree name;
+
+ switch (dtor_kind)
+ {
+ case sfk_complete_destructor:
+ name = complete_dtor_identifier;
+ break;
+
+ case sfk_base_destructor:
+ name = base_dtor_identifier;
+ break;
+
+ case sfk_deleting_destructor:
+ name = deleting_dtor_identifier;
+ break;
+
+ default:
+ abort ();
+ }
+ return build_method_call (exp, name, NULL_TREE, NULL_TREE, flags);
+}
+
/* Generate a call to a destructor. TYPE is the type to cast ADDR to.
ADDR is an expression which yields the store to be destroyed.
- AUTO_DELETE is nonzero if a call to DELETE should be made or not.
- If in the program, (AUTO_DELETE & 2) is non-zero, we tear down the
- virtual baseclasses.
- If in the program, (AUTO_DELETE & 1) is non-zero, then we deallocate.
+ AUTO_DELETE is the name of the destructor to call, i.e., either
+ sfk_complete_destructor, sfk_base_destructor, or
+ sfk_deleting_destructor.
FLAGS is the logical disjunction of zero or more LOOKUP_
- flags. See cp-tree.h for more info.
-
- This function does not delete an object's virtual base classes. */
+ flags. See cp-tree.h for more info. */
tree
build_delete (type, addr, auto_delete, flags, use_global_delete)
tree type, addr;
- tree auto_delete;
+ special_function_kind auto_delete;
int flags;
int use_global_delete;
{
- tree member;
tree expr;
- tree ref;
if (addr == error_mark_node)
return error_mark_node;
@@ -3214,7 +3111,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
if (TREE_CODE (type) == POINTER_TYPE)
{
type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
- if (type != void_type_node && !complete_type_or_else (type, addr))
+ if (!VOID_TYPE_P (type) && !complete_type_or_else (type, addr))
return error_mark_node;
if (TREE_CODE (type) == ARRAY_TYPE)
goto handle_array;
@@ -3228,7 +3125,6 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
/* throw away const and volatile on target type of addr */
addr = convert_force (build_pointer_type (type), addr, 0);
- ref = build_indirect_ref (addr, NULL_PTR);
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
@@ -3241,8 +3137,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
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
{
@@ -3253,19 +3148,14 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
if (TREE_SIDE_EFFECTS (addr))
addr = save_expr (addr);
- if (TREE_CONSTANT (addr))
- addr = convert_pointer_to (type, addr);
- else
- addr = convert_force (build_pointer_type (type), addr, 0);
-
- ref = build_indirect_ref (addr, NULL_PTR);
+ addr = convert_force (build_pointer_type (type), addr, 0);
}
my_friendly_assert (IS_AGGR_TYPE (type), 220);
- if (! TYPE_NEEDS_DESTRUCTOR (type))
+ if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
{
- if (auto_delete == integer_zero_node)
+ if (auto_delete != sfk_deleting_destructor)
return void_zero_node;
return build_op_delete_call
@@ -3273,49 +3163,46 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
NULL_TREE);
}
-
- /* Below, we will reverse the order in which these calls are made.
- If we have a destructor, then that destructor will take care
- of the base classes; otherwise, we must do that here. */
- if (TYPE_HAS_DESTRUCTOR (type))
+ else
{
- tree passed_auto_delete;
tree do_delete = NULL_TREE;
tree ifexp;
- if (use_global_delete)
- {
- tree cond = fold (build (BIT_AND_EXPR, integer_type_node,
- auto_delete, integer_one_node));
- tree call = build_builtin_delete_call (addr);
-
- cond = fold (build (COND_EXPR, void_type_node, cond,
- call, void_zero_node));
- if (cond != void_zero_node)
- do_delete = cond;
+ my_friendly_assert (TYPE_HAS_DESTRUCTOR (type), 20011213);
- passed_auto_delete = fold (build (BIT_AND_EXPR, integer_type_node,
- auto_delete, integer_two_node));
+ /* For `::delete x', we must not use the deleting destructor
+ since then we would not be sure to get the global `operator
+ delete'. */
+ if (use_global_delete && auto_delete == sfk_deleting_destructor)
+ {
+ /* We will use ADDR multiple times so we must save it. */
+ addr = save_expr (addr);
+ /* Delete the object. */
+ do_delete = build_builtin_delete_call (addr);
+ /* Otherwise, treat this like a complete object destructor
+ call. */
+ auto_delete = sfk_complete_destructor;
}
- else
- passed_auto_delete = auto_delete;
-
- /* Maybe pass vlist pointer to destructor. */
- if (TYPE_USES_PVBASES (type))
+ /* If the destructor is non-virtual, there is no deleting
+ variant. Instead, we must explicitly call the appropriate
+ `operator delete' here. */
+ else if (!DECL_VIRTUAL_P (CLASSTYPE_DESTRUCTORS (type))
+ && auto_delete == sfk_deleting_destructor)
{
- /* Pass vlist_zero even if in backwards compatibility mode,
- as the extra argument should not hurt if it is not used. */
- expr = build_expr_list (NULL_TREE, vlist_zero_node);
- flags |= LOOKUP_HAS_VLIST;
+ /* We will use ADDR multiple times so we must save it. */
+ addr = save_expr (addr);
+ /* Build the call. */
+ do_delete = build_op_delete_call (DELETE_EXPR,
+ addr,
+ c_sizeof_nowarn (type),
+ LOOKUP_NORMAL,
+ NULL_TREE);
+ /* Call the complete object destructor. */
+ auto_delete = sfk_complete_destructor;
}
- else
- expr = NULL_TREE;
-
- expr = expr_tree_cons (NULL_TREE, passed_auto_delete, expr);
-
- expr = build_method_call (ref, dtor_identifier, expr,
- NULL_TREE, flags);
+ expr = build_dtor_call (build_indirect_ref (addr, NULL),
+ auto_delete, flags);
if (do_delete)
expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
@@ -3324,7 +3211,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
ifexp = integer_one_node;
else
/* Handle deleting a null pointer. */
- ifexp = fold (build_binary_op (NE_EXPR, addr, integer_zero_node));
+ ifexp = fold (cp_build_binary_op (NE_EXPR, addr, integer_zero_node));
if (ifexp != integer_one_node)
expr = build (COND_EXPR, void_type_node,
@@ -3332,84 +3219,98 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
return expr;
}
- else
- {
- /* We only get here from finish_function for a destructor. */
- tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
- int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- tree base_binfo = n_baseclasses > 0 ? TREE_VEC_ELT (binfos, 0) : NULL_TREE;
- tree exprstmt = NULL_TREE;
- 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)
- cond = NULL_TREE;
- else if (base_binfo == NULL_TREE
- || ! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
- {
- cond = build (COND_EXPR, void_type_node,
- build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_node),
- build_builtin_delete_call (addr),
- void_zero_node);
- }
- else
- cond = NULL_TREE;
+}
- if (cond)
- exprstmt = build_expr_list (NULL_TREE, cond);
+/* At the beginning of a destructor, push cleanups that will call the
+ destructors for our base classes and members.
- if (base_binfo
- && ! TREE_VIA_VIRTUAL (base_binfo)
- && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
- {
- tree this_auto_delete;
+ Called from setup_vtbl_ptr. */
- /* Should the base invoke delete? */
- if (BINFO_OFFSET_ZEROP (base_binfo))
- this_auto_delete = parent_auto_delete;
- else
- this_auto_delete = integer_zero_node;
+void
+push_base_cleanups ()
+{
+ tree binfos;
+ int i, n_baseclasses;
+ tree member;
+ tree expr;
- expr = build_base_dtor_call (ref, base_binfo, this_auto_delete);
- exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
- }
+ /* Run destructors for all virtual baseclasses. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ {
+ tree vbases;
+ tree cond = (condition_conversion
+ (build (BIT_AND_EXPR, integer_type_node,
+ current_in_charge_parm,
+ integer_two_node)));
- /* Take care of the remaining baseclasses. */
- for (i = 1; i < n_baseclasses; i++)
+ vbases = CLASSTYPE_VBASECLASSES (current_class_type);
+ /* The CLASSTYPE_VBASECLASSES list is in initialization
+ order, which is also the right order for pushing cleanups. */
+ for (; vbases;
+ vbases = TREE_CHAIN (vbases))
{
- base_binfo = TREE_VEC_ELT (binfos, i);
- if (! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo))
- || TREE_VIA_VIRTUAL (base_binfo))
- continue;
-
- expr = build_base_dtor_call (ref, base_binfo, integer_zero_node);
-
- exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
- }
+ tree vbase = TREE_VALUE (vbases);
+ tree base_type = BINFO_TYPE (vbase);
- for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
- {
- if (TREE_CODE (member) != FIELD_DECL)
- continue;
- if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (member)))
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (base_type))
{
- 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);
+ tree base_ptr_type = build_pointer_type (base_type);
+ expr = current_class_ptr;
+
+ /* Convert to the basetype here, as we know the layout is
+ fixed. What is more, if we let build_method_call do it,
+ it will use the vtable, which may have been clobbered
+ by the deletion of our primary base. */
+
+ expr = build1 (NOP_EXPR, base_ptr_type, expr);
+ expr = build (PLUS_EXPR, base_ptr_type, expr,
+ BINFO_OFFSET (vbase));
+ expr = build_indirect_ref (expr, NULL);
+ expr = build_method_call (expr, base_dtor_identifier,
+ NULL_TREE, vbase,
+ LOOKUP_NORMAL);
+ expr = build (COND_EXPR, void_type_node, cond,
+ expr, void_zero_node);
+ finish_decl_cleanup (NULL_TREE, expr);
}
}
+ }
+
+ binfos = BINFO_BASETYPES (TYPE_BINFO (current_class_type));
+ n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
- if (exprstmt)
- return build_compound_expr (exprstmt);
- /* Virtual base classes make this function do nothing. */
- return void_zero_node;
+ /* Take care of the remaining baseclasses. */
+ for (i = 0; i < n_baseclasses; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
+ || TREE_VIA_VIRTUAL (base_binfo))
+ continue;
+
+ expr = build_scoped_method_call (current_class_ref, base_binfo,
+ base_dtor_identifier,
+ NULL_TREE);
+
+ finish_decl_cleanup (NULL_TREE, expr);
+ }
+
+ for (member = TYPE_FIELDS (current_class_type); member;
+ member = TREE_CHAIN (member))
+ {
+ if (TREE_CODE (member) != FIELD_DECL)
+ continue;
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
+ {
+ tree this_member = (build_component_ref
+ (current_class_ref, DECL_NAME (member),
+ NULL_TREE, 0));
+ tree this_type = TREE_TYPE (member);
+ expr = build_delete (this_type, this_member,
+ sfk_complete_destructor,
+ LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
+ 0);
+ finish_decl_cleanup (NULL_TREE, expr);
+ }
}
}
@@ -3427,11 +3328,12 @@ build_vbase_delete (type, decl)
while (vbases)
{
- tree this_addr = convert_force (build_pointer_type (BINFO_TYPE (vbases)),
- addr, 0);
- result = expr_tree_cons (NULL_TREE,
+ tree this_addr
+ = convert_force (build_pointer_type (BINFO_TYPE (TREE_VALUE (vbases))),
+ addr, 0);
+ result = tree_cons (NULL_TREE,
build_delete (TREE_TYPE (this_addr), this_addr,
- integer_zero_node,
+ sfk_base_destructor,
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
result);
vbases = TREE_CHAIN (vbases);
@@ -3445,7 +3347,6 @@ build_vbase_delete (type, decl)
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.
@@ -3457,10 +3358,9 @@ build_vbase_delete (type, decl)
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;
+ special_function_kind auto_delete_vec;
int use_global_delete;
{
tree type;
@@ -3479,20 +3379,20 @@ build_vec_delete (base, maxindex, auto_delete_vec, auto_delete,
if (TREE_CODE (type) == POINTER_TYPE)
{
/* Step back one from start of vector, and read dimension. */
- 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);
- do
- type = TREE_TYPE (type);
- while (TREE_CODE (type) == ARRAY_TYPE);
+ tree cookie_addr;
+
+ type = strip_array_types (TREE_TYPE (type));
+ cookie_addr = build (MINUS_EXPR,
+ build_pointer_type (sizetype),
+ base,
+ TYPE_SIZE_UNIT (sizetype));
+ maxindex = build_indirect_ref (cookie_addr, NULL);
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
/* get the total number of things in the array, maxindex is a bad name */
maxindex = array_type_nelts_total (type);
- while (TREE_CODE (type) == ARRAY_TYPE)
- type = TREE_TYPE (type);
+ type = strip_array_types (type);
base = build_unary_op (ADDR_EXPR, base, 1);
}
else
@@ -3502,6 +3402,6 @@ build_vec_delete (base, maxindex, auto_delete_vec, auto_delete,
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);
}
OpenPOWER on IntegriCloud