diff options
author | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
commit | c9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch) | |
tree | 086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/cp/init.c | |
parent | 2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff) | |
download | FreeBSD-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.c | 3146 |
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); } |