--- gcc/cp/init.c 2018/04/24 18:20:20 1.1 +++ gcc/cp/init.c 2018/04/24 18:26:58 1.1.1.2 @@ -1,5 +1,5 @@ /* Handle initialization things in C++. - Copyright (C) 1987, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. + Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GNU CC. @@ -16,7 +16,8 @@ GNU General Public License for more deta You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* High-level class interface. */ @@ -26,6 +27,7 @@ the Free Software Foundation, 675 Mass A #include "rtl.h" #include "cp-tree.h" #include "flags.h" +#include "output.h" #undef NULL #define NULL 0 @@ -108,7 +110,7 @@ void init_init_processing () 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 initiailzation of vtable pointers. This is done + 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. @@ -138,7 +140,7 @@ expand_direct_vtbls_init (real_binfo, bi } #if 0 /* Before turning this on, make sure it is correct. */ - if (can_elide && ! BINFO_MODIFIED (binfo)) + if (can_elide && ! BINFO_MODIFIED (binfo)) return; #endif /* Should we use something besides CLASSTYPE_VFIELDS? */ @@ -152,8 +154,8 @@ expand_direct_vtbls_init (real_binfo, bi /* 348 - 351 */ /* Subroutine of emit_base_init. */ static void -perform_member_init (member, name, init, explicit) - tree member, name, init; +perform_member_init (member, name, init, explicit, protect_list) + tree member, name, init, *protect_list; int explicit; { tree decl; @@ -180,7 +182,7 @@ perform_member_init (member, name, init, array_type_nelts (type), TREE_VALUE (init), 1); } else - expand_aggr_init (decl, init, 0); + expand_aggr_init (decl, init, 0, 0); } else { @@ -218,27 +220,44 @@ perform_member_init (member, name, init, } } expand_cleanups_to (NULL_TREE); - if (flag_handle_exceptions && TYPE_NEEDS_DESTRUCTOR (type)) - cp_warning ("caution, member `%D' may not be destroyed in the presense of an exception during construction", member); + + if (TYPE_NEEDS_DESTRUCTOR (type)) + { + tree expr = build_component_ref (C_C_D, name, 0, explicit); + expr = build_delete (type, expr, integer_zero_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); + + if (expr != error_mark_node) + { + start_protect (); + *protect_list = tree_cons (NULL_TREE, expr, *protect_list); + } + } } +extern int warn_reorder; + /* Subroutine of emit_member_init. */ static tree sort_member_init (t) tree t; { - extern int warn_reorder; tree x, member, name, field, init; tree init_list = NULL_TREE; tree fields_to_unmark = NULL_TREE; - int found; int last_pos = 0; tree last_field; for (member = TYPE_FIELDS (t); member ; member = TREE_CHAIN (member)) { int pos; - found = 0; + + /* 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; + for (x = current_member_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos) { /* If we cleared this out, then pay no attention to it. */ @@ -261,17 +280,9 @@ sort_member_init (t) if (field == member) { - /* See if we already found an initializer for this field. */ - if (found) + if (warn_reorder) { - if (DECL_NAME (field)) - cp_error ("multiple initializations given for member `%D'", - field); - continue; - } - else - { - if (pos < last_pos && warn_reorder) + if (pos < last_pos) { cp_warning_at ("member initializers for `%#D'", last_field); cp_warning_at (" and `%#D'", field); @@ -281,78 +292,193 @@ sort_member_init (t) last_field = field; } - init_list = chainon (init_list, - build_tree_list (name, TREE_VALUE (x))); /* Make sure we won't try to work on this init again. */ TREE_PURPOSE (x) = NULL_TREE; - found = 1; - break; + x = build_tree_list (name, TREE_VALUE (x)); + goto got_it; } } /* 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. */ - if (! found) - init_list = chainon (init_list, build_tree_list (NULL_TREE, NULL_TREE)); + x = build_tree_list (NULL_TREE, NULL_TREE); + got_it: + init_list = chainon (init_list, x); } + /* Initializers for base members go at the end. */ for (x = current_member_init_list ; x ; x = TREE_CHAIN (x)) { - if (TREE_PURPOSE (x)) + name = TREE_PURPOSE (x); + if (name) { - name = TREE_PURPOSE (x); - init = TREE_VALUE (x); - /* 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) + if (purpose_member (name, init_list)) { - field = TREE_VALUE (field); - if (decl_type_context (field) != current_class_type) - cp_error ("field `%D' not in immediate context", field); + cp_error ("multiple initializations given for member `%D'", + IDENTIFIER_CLASS_VALUE (name)); + continue; } + + init_list = chainon (init_list, + build_tree_list (name, TREE_VALUE (x))); + TREE_PURPOSE (x) = NULL_TREE; + } + } -#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. */ + return init_list; +} - /* 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 +static void +sort_base_init (t, rbase_ptr, vbase_ptr) + tree t, *rbase_ptr, *vbase_ptr; +{ + tree binfos = BINFO_BASETYPES (TYPE_BINFO (t)); + int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; + + int i; + tree x; + tree last; + + /* For warn_reorder. */ + int last_pos = 0; + tree last_base = NULL_TREE; - if (TREE_HAS_CONSTRUCTOR (field)) + tree rbases = NULL_TREE; + tree vbases = NULL_TREE; + + /* First walk through and splice out vbase and invalid initializers. + Also replace names with binfos. */ + + last = tree_cons (NULL_TREE, NULL_TREE, current_base_init_list); + for (x = TREE_CHAIN (last); x; x = TREE_CHAIN (x)) + { + tree basename = TREE_PURPOSE (x); + tree binfo; + + if (basename == NULL_TREE) + { + /* Initializer for single base class. Must not + use multiple inheritance or this is ambiguous. */ + switch (n_baseclasses) { - if (DECL_NAME (field)) - error ("multiple initializations given for member `%s'", - IDENTIFIER_POINTER (DECL_NAME (field))); - continue; + 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); + } + else if (is_aggr_typedef (basename, 1)) + { + binfo = binfo_or_else (IDENTIFIER_TYPE_VALUE (basename), t); + if (binfo == NULL_TREE) + continue; - TREE_HAS_CONSTRUCTOR (field) = 1; - fields_to_unmark = tree_cons (NULL_TREE, field, fields_to_unmark); + /* 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); - perform_member_init (field, name, init, 1); - TREE_PURPOSE (x) = NULL_TREE; + 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'", + IDENTIFIER_TYPE_VALUE (basename), + current_class_type); + continue; + } + } } + else + my_friendly_abort (365); + + TREE_PURPOSE (x) = binfo; + TREE_CHAIN (last) = x; + last = x; } + TREE_CHAIN (last) = NULL_TREE; + + /* Now walk through our regular bases and make sure they're initialized. */ - /* Unmark fields which are initialized for the base class. */ - while (fields_to_unmark) + for (i = 0; i < n_baseclasses; ++i) { - TREE_HAS_CONSTRUCTOR (TREE_VALUE (fields_to_unmark)) = 0; - /* XXX is this a memory leak? */ - fields_to_unmark = TREE_CHAIN (fields_to_unmark); + tree base_binfo = TREE_VEC_ELT (binfos, i); + int pos; + + if (TREE_VIA_VIRTUAL (base_binfo)) + continue; + + for (x = current_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 (warn_reorder) + { + if (pos < last_pos) + { + cp_warning_at ("base initializers for `%#T'", last_base); + cp_warning_at (" and `%#T'", BINFO_TYPE (binfo)); + warning (" will be re-ordered to match inheritance order"); + } + last_pos = pos; + last_base = BINFO_TYPE (binfo); + } + + /* 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; + } + } + + /* 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); } - return init_list; + *rbase_ptr = rbases; + *vbase_ptr = vbases; +} + +/* Perform partial cleanups for a base for exception handling. */ +static tree +build_partial_cleanup_for (binfo) + tree binfo; +{ + tree expr = convert_pointer_to_real (binfo, + build_unary_op (ADDR_EXPR, C_C_D, 0)); + + return build_delete (TREE_TYPE (expr), + expr, + integer_zero_node, + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); } /* Perform whatever initializations have yet to be done on the base @@ -367,12 +493,14 @@ sort_member_init (t) 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_INSNS. + 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; + void emit_base_init (t, immediately) tree t; @@ -380,18 +508,26 @@ emit_base_init (t, immediately) { extern tree in_charge_identifier; - tree member, vbases; - tree init_list; - int pass, start; + tree member, x; + tree mem_init_list; + tree rbase_init_list, vbase_init_list; tree t_binfo = TYPE_BINFO (t); tree binfos = BINFO_BASETYPES (t_binfo); int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; - int have_init_list = 0, from_init_list; + tree expr = NULL_TREE; + + my_friendly_assert (protect_list == NULL_TREE, 999); if (! immediately) { + int momentary; do_pending_stack_adjust (); - start_sequence (); + /* 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) @@ -402,285 +538,157 @@ emit_base_init (t, immediately) emit_line_note_force (DECL_SOURCE_FILE (current_function_decl), DECL_SOURCE_LINE (current_function_decl)); - start = ! TYPE_USES_VIRTUAL_BASECLASSES (t); - for (pass = start; pass < 2; pass++) - { - tree vbase_init_list = NULL_TREE; - - for (init_list = current_base_init_list; init_list; - init_list = TREE_CHAIN (init_list)) - { - tree basename = TREE_PURPOSE (init_list); - tree binfo; - tree init = TREE_VALUE (init_list); - - if (basename == NULL_TREE) - { - /* Initializer for single base class. Must not - use multiple inheritance or this is ambiguous. */ - switch (n_baseclasses) - { - case 0: - error ("type `%s' does not have a base class to initialize", - IDENTIFIER_POINTER (current_class_name)); - return; - case 1: - break; - default: - error ("unnamed initializer ambiguous for type `%s' which uses multiple inheritance", IDENTIFIER_POINTER (current_class_name)); - return; - } - binfo = TREE_VEC_ELT (binfos, 0); - } - else if (is_aggr_typedef (basename, 1)) - { - binfo = binfo_or_else (IDENTIFIER_TYPE_VALUE (basename), 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)) - { - /* 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) - { - error ("type `%s' is not an immediate base class of type `%s'", - IDENTIFIER_POINTER (basename), - IDENTIFIER_POINTER (current_class_name)); - continue; - } - } - } - else - continue; + mem_init_list = sort_member_init (t); + current_member_init_list = NULL_TREE; - /* The base initialization list goes up to the first - base class which can actually use it. */ + sort_base_init (t, &rbase_init_list, &vbase_init_list); + current_base_init_list = NULL_TREE; - if (pass == start) - { - char *msgp = (! TYPE_HAS_CONSTRUCTOR (BINFO_TYPE (binfo))) - ? "cannot pass initialization up to class `%s'" : 0; + if (TYPE_USES_VIRTUAL_BASECLASSES (t)) + { + tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl)); - while (! TYPE_HAS_CONSTRUCTOR (BINFO_TYPE (binfo)) - && BINFO_BASETYPES (binfo) != NULL_TREE - && TREE_VEC_LENGTH (BINFO_BASETYPES (binfo)) == 1) - { - /* ?? This should be fixed in RENO by forcing - default constructors to exist. */ - SET_BINFO_BASEINIT_MARKED (binfo); - binfo = BINFO_BASETYPE (binfo, 0); - } + expand_start_cond (first_arg, 0); + expand_aggr_vbase_init (t_binfo, C_C_D, current_class_decl, + vbase_init_list); + expand_end_cond (); + } - /* We used to give an error if this wasn't true, saying that - there's no constructor for the initialization of basename. - This turned out to be incorrect---it should use the - default constructor, since a user could try to initialize - the class in a derived class's base initializer list. */ - if (TYPE_HAS_CONSTRUCTOR (BINFO_TYPE (binfo))) - { - if (msgp) - { - if (pedantic) - error_with_aggr_type (binfo, msgp); - else - msgp = NULL; - } - } + /* Now, perform initialization of non-virtual base classes. */ + for (i = 0; i < n_baseclasses; i++) + { + tree base = current_class_decl; + tree base_binfo = TREE_VEC_ELT (binfos, i); + tree init = void_list_node; - if (BINFO_BASEINIT_MARKED (binfo)) - { - msgp = "class `%s' initializer already specified"; - error (msgp, IDENTIFIER_POINTER (basename)); - } + if (TREE_VIA_VIRTUAL (base_binfo)) + continue; - if (msgp) - continue; +#if 0 /* Once unsharing happens soon enough. */ + my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo); +#else + BINFO_INHERITANCE_CHAIN (base_binfo) = t_binfo; +#endif - SET_BINFO_BASEINIT_MARKED (binfo); - if (TREE_VIA_VIRTUAL (binfo)) - { - vbase_init_list = tree_cons (init, BINFO_TYPE (binfo), - vbase_init_list); - continue; - } - if (pass == 0) - continue; - } - else if (TREE_VIA_VIRTUAL (binfo)) - continue; + if (TREE_PURPOSE (rbase_init_list)) + init = TREE_VALUE (rbase_init_list); + else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo))) + init = NULL_TREE; - member = convert_pointer_to (binfo, current_class_decl); - expand_aggr_init_1 (binfo, 0, + if (init != void_list_node) + { + member = convert_pointer_to_real (base_binfo, current_class_decl); + expand_aggr_init_1 (base_binfo, 0, build_indirect_ref (member, NULL_PTR), init, - BINFO_OFFSET_ZEROP (binfo), LOOKUP_NORMAL); + BINFO_OFFSET_ZEROP (base_binfo), LOOKUP_NORMAL); expand_cleanups_to (NULL_TREE); } - if (pass == 0) + if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo))) { - tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl)); - tree vbases; - - if (DECL_NAME (current_function_decl) == NULL_TREE - && TREE_CHAIN (first_arg) != NULL_TREE) - { - /* If there are virtual baseclasses without initialization - specified, and this is a default X(X&) constructor, - build the initialization list so that each virtual baseclass - of the new object is initialized from the virtual baseclass - of the incoming arg. */ - tree init_arg = build_unary_op (ADDR_EXPR, TREE_CHAIN (first_arg), 0); - for (vbases = CLASSTYPE_VBASECLASSES (t); - vbases; vbases = TREE_CHAIN (vbases)) - { - if (BINFO_BASEINIT_MARKED (vbases) == 0) - { - member = convert_pointer_to (vbases, init_arg); - if (member == init_arg) - member = TREE_CHAIN (first_arg); - else - TREE_TYPE (member) = build_reference_type (BINFO_TYPE (vbases)); - vbase_init_list = tree_cons (convert_from_reference (member), - vbases, vbase_init_list); - SET_BINFO_BASEINIT_MARKED (vbases); - } - } - } - expand_start_cond (first_arg, 0); - expand_aggr_vbase_init (t_binfo, C_C_D, current_class_decl, - vbase_init_list); - expand_end_cond (); + start_protect (); + protect_list = tree_cons (NULL_TREE, + build_partial_cleanup_for (base_binfo), + protect_list); } - } - current_base_init_list = NULL_TREE; - - /* Now, perform default initialization of all base classes which - have not yet been initialized, and unmark baseclasses which - have been initialized. */ - for (i = 0; i < n_baseclasses; i++) - { - tree base = current_class_decl; - tree base_binfo = TREE_VEC_ELT (binfos, i); - - if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo))) - { - if (! TREE_VIA_VIRTUAL (base_binfo) - && ! BINFO_BASEINIT_MARKED (base_binfo)) - { - tree ref; - if (BINFO_OFFSET_ZEROP (base_binfo)) - base = build1 (NOP_EXPR, - TYPE_POINTER_TO (BINFO_TYPE (base_binfo)), - current_class_decl); - else - base = build (PLUS_EXPR, - TYPE_POINTER_TO (BINFO_TYPE (base_binfo)), - current_class_decl, BINFO_OFFSET (base_binfo)); - - ref = build_indirect_ref (base, NULL_PTR); - expand_aggr_init_1 (base_binfo, 0, ref, NULL_TREE, - BINFO_OFFSET_ZEROP (base_binfo), - LOOKUP_NORMAL); - expand_cleanups_to (NULL_TREE); - } - } - CLEAR_BINFO_BASEINIT_MARKED (base_binfo); - - if (! TYPE_USES_VIRTUAL_BASECLASSES (t)) - { - while (! TYPE_HAS_CONSTRUCTOR (BINFO_TYPE (base_binfo)) - && BINFO_BASETYPES (base_binfo) != NULL_TREE - && TREE_VEC_LENGTH (BINFO_BASETYPES (base_binfo)) == 1) - { - /* ?? This should be fixed in RENO by forcing - default constructors to exist. It is needed for symmetry - with code above. */ - base_binfo = BINFO_BASETYPE (base_binfo, 0); - CLEAR_BINFO_BASEINIT_MARKED (base_binfo); - } - } + 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, C_C_D, current_class_decl, 0); - for (vbases = CLASSTYPE_VBASECLASSES (t); vbases; vbases = TREE_CHAIN (vbases)) - CLEAR_BINFO_BASEINIT_MARKED (vbases); /* 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_decl); - if (current_member_init_list) - { - init_list = sort_member_init (t); - have_init_list = 1; - } - for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member)) { tree init, name; - from_init_list = 0; + 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; /* See if we had a user-specified member initialization. */ - if (have_init_list) + if (TREE_PURPOSE (mem_init_list)) { - if (TREE_PURPOSE (init_list)) - { - name = TREE_PURPOSE (init_list); - init = TREE_VALUE (init_list); - from_init_list = 1; - - if (TREE_STATIC (member)) - { - error_with_aggr_type (DECL_FIELD_CONTEXT (member), - "field `%s::%s' is static; only point of initialization is its declaration", - IDENTIFIER_POINTER (TREE_PURPOSE (init_list))); - continue; - } - - /* 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); - } - - init_list = TREE_CHAIN (init_list); + name = TREE_PURPOSE (mem_init_list); + init = TREE_VALUE (mem_init_list); + from_init_list = 1; + + /* 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); } - - if (! from_init_list) + else { - /* 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; - name = DECL_NAME (member); init = DECL_INITIAL (member); + + from_init_list = 0; } - perform_member_init (member, name, init, from_init_list); + perform_member_init (member, name, init, from_init_list, &protect_list); + mem_init_list = TREE_CHAIN (mem_init_list); } - current_member_init_list = NULL_TREE; + /* 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 + + perform_member_init (field, name, init, 1, &protect_list); + } + mem_init_list = TREE_CHAIN (mem_init_list); + } if (! immediately) { - extern rtx base_init_insns; - do_pending_stack_adjust (); - my_friendly_assert (base_init_insns == 0, 207); - base_init_insns = get_insns (); + my_friendly_assert (base_init_expr == 0, 207); + base_init_expr = expr; + TREE_TYPE (expr) = void_type_node; + RTL_EXPR_RTL (expr) = const0_rtx; + RTL_EXPR_SEQUENCE (expr) = get_insns (); + rtl_expr_chain = tree_cons (NULL_TREE, expr, rtl_expr_chain); end_sequence (); + TREE_SIDE_EFFECTS (expr) = 1; } /* All the implicit try blocks we built up will be zapped @@ -719,17 +727,16 @@ expand_virtual_init (binfo, decl) 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)); - if (!flag_vtable_thunks) - assemble_external (vtbl); + assemble_external (vtbl); TREE_USED (vtbl) = 1; - vtbl = build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (vtbl)), vtbl); + 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. */ - vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl); + vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0); expand_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl)); } @@ -740,15 +747,13 @@ static void expand_aggr_vbase_init_1 (binfo, exp, addr, init_list) tree binfo, exp, addr, init_list; { - tree init = value_member (BINFO_TYPE (binfo), init_list); + tree init = purpose_member (binfo, init_list); tree ref = build_indirect_ref (addr, NULL_PTR); if (init) - init = TREE_PURPOSE (init); + init = TREE_VALUE (init); /* Call constructors, but don't set up vtables. */ - expand_aggr_init_1 (binfo, exp, ref, init, 0, - LOOKUP_COMPLAIN|LOOKUP_SPECULATIVELY); + expand_aggr_init_1 (binfo, exp, ref, init, 0, LOOKUP_COMPLAIN); expand_cleanups_to (NULL_TREE); - CLEAR_BINFO_VBASE_INIT_MARKED (binfo); } /* Initialize this object's virtual base class pointers. This must be @@ -772,38 +777,14 @@ expand_aggr_vbase_init (binfo, exp, addr if (result) expand_expr_stmt (build_compound_expr (result)); - /* Mark everything as having an initializer - (either explicit or default). */ - for (vbases = CLASSTYPE_VBASECLASSES (type); - vbases; vbases = TREE_CHAIN (vbases)) - SET_BINFO_VBASE_INIT_MARKED (vbases); - - /* First, initialize baseclasses which could be baseclasses - for other virtual baseclasses. */ - for (vbases = CLASSTYPE_VBASECLASSES (type); - vbases; vbases = TREE_CHAIN (vbases)) - /* Don't initialize twice. */ - if (BINFO_VBASE_INIT_MARKED (vbases)) - { - tree tmp = result; - - while (BINFO_TYPE (vbases) != BINFO_TYPE (TREE_PURPOSE (tmp))) - tmp = TREE_CHAIN (tmp); - expand_aggr_vbase_init_1 (vbases, exp, - TREE_OPERAND (TREE_VALUE (tmp), 0), - init_list); - } - - /* Now initialize the baseclasses which don't have virtual baseclasses. */ - for (; result; result = TREE_CHAIN (result)) - /* Don't initialize twice. */ - if (BINFO_VBASE_INIT_MARKED (TREE_PURPOSE (result))) - { - my_friendly_abort (47); - expand_aggr_vbase_init_1 (TREE_PURPOSE (result), exp, - TREE_OPERAND (TREE_VALUE (result), 0), - init_list); - } + for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; + vbases = TREE_CHAIN (vbases)) + { + tree tmp = purpose_member (vbases, result); + expand_aggr_vbase_init_1 (vbases, exp, + TREE_OPERAND (TREE_VALUE (tmp), 0), + init_list); + } } } @@ -853,16 +834,27 @@ member_init_ok_or_else (field, type, mem if (field == NULL_TREE) { cp_error ("class `%T' does not have any field named `%s'", type, - member_name); + member_name); return 0; } if (DECL_CONTEXT (field) != type && TYPE_NEEDS_CONSTRUCTING (DECL_CONTEXT (field))) { - cp_error ("member `%D' comes from base class needing constructor", + if (current_function_decl && DECL_CONSTRUCTOR_P (current_function_decl)) + cp_error ("initialization of `%D' inside constructor for `%T'", + field, type); + else + cp_error ("member `%D' comes from base class needing constructor", + field); + return 0; + } + if (TREE_STATIC (field)) + { + cp_error ("field `%#D' is static; only point of initialization is its declaration", field); return 0; } + return 1; } @@ -1067,7 +1059,7 @@ expand_member_init (exp, name, init) else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field))) { parm = build_component_ref (exp, name, 0, 0); - expand_aggr_init (parm, NULL_TREE, 0); + expand_aggr_init (parm, NULL_TREE, 0, 0); rval = error_mark_node; } @@ -1083,8 +1075,12 @@ expand_member_init (exp, name, init) INIT comes in two flavors: it is either a value which is to be stored in EXP, or it is a parameter list to go to a constructor, which will operate on EXP. + If INIT is not a parameter list for a constructor, then set + LOOKUP_ONLYCONVERTING. + If FLAGS is LOOKUP_ONLYCONVERTING then it is the = init form of + the initializer, if FLAGS is 0, then it is the (init) form. If `init' is a CONSTRUCTOR, then we emit a warning message, - explaining that such initializations are illegal. + explaining that such initializations are invalid. ALIAS_THIS is nonzero iff we are initializing something which is essentially an alias for C_C_D. In this case, the base constructor @@ -1112,25 +1108,30 @@ expand_member_init (exp, name, init) */ void -expand_aggr_init (exp, init, alias_this) +expand_aggr_init (exp, init, alias_this, flags) tree exp, init; int alias_this; + int flags; { tree type = TREE_TYPE (exp); int was_const = TREE_READONLY (exp); + int was_volatile = TREE_THIS_VOLATILE (exp); if (init == error_mark_node) return; TREE_READONLY (exp) = 0; + TREE_THIS_VOLATILE (exp) = 0; + + if (init && TREE_CODE (init) != TREE_LIST) + flags |= LOOKUP_ONLYCONVERTING; if (TREE_CODE (type) == ARRAY_TYPE) { /* Must arrange to initialize each element of EXP from elements of INIT. */ - int was_const_elts = TYPE_READONLY (TREE_TYPE (type)); tree itype = init ? TREE_TYPE (init) : NULL_TREE; - if (was_const_elts) + if (TYPE_READONLY (TREE_TYPE (type)) || TYPE_VOLATILE (TREE_TYPE (type))) { TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type); if (init) @@ -1156,6 +1157,7 @@ expand_aggr_init (exp, init, alias_this) expand_vec_init (exp, exp, array_type_nelts (type), init, init && comptypes (TREE_TYPE (init), TREE_TYPE (exp), 1)); TREE_READONLY (exp) = was_const; + TREE_THIS_VOLATILE (exp) = was_volatile; TREE_TYPE (exp) = type; if (init) TREE_TYPE (init) = itype; @@ -1174,9 +1176,13 @@ expand_aggr_init (exp, init, alias_this) && TREE_TYPE (init) == type) init = CONSTRUCTOR_ELTS (init); #endif + + TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type); expand_aggr_init_1 (TYPE_BINFO (type), exp, exp, - init, alias_this, LOOKUP_NORMAL); + init, alias_this, LOOKUP_NORMAL|flags); + TREE_TYPE (exp) = type; TREE_READONLY (exp) = was_const; + TREE_THIS_VOLATILE (exp) = was_volatile; } static void @@ -1196,14 +1202,16 @@ expand_default_init (binfo, true_exp, ex out, then look hard. */ tree rval; tree parms; - int xxref_init_possible; - if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST) + if (init == NULL_TREE + || (TREE_CODE (init) == TREE_LIST && ! TREE_TYPE (init))) { parms = init; - if (parms) init = TREE_VALUE (parms); + if (parms) + init = TREE_VALUE (parms); } - else if (TREE_CODE (init) == INDIRECT_REF && TREE_HAS_CONSTRUCTOR (init)) + else if (TREE_CODE (init) == INDIRECT_REF && TREE_HAS_CONSTRUCTOR (init) + && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (init))) { rval = convert_for_initialization (exp, type, init, 0, 0, 0, 0); TREE_USED (rval) = 1; @@ -1213,16 +1221,6 @@ expand_default_init (binfo, true_exp, ex else parms = build_tree_list (NULL_TREE, init); - if (TYPE_HAS_INIT_REF (type) - || init == NULL_TREE - || TREE_CHAIN (parms) != NULL_TREE) - xxref_init_possible = 0; - else - { - xxref_init_possible = LOOKUP_SPECULATIVELY; - flags &= ~LOOKUP_COMPLAIN; - } - if (TYPE_USES_VIRTUAL_BASECLASSES (type)) { if (true_exp == exp) @@ -1232,114 +1230,44 @@ expand_default_init (binfo, true_exp, ex flags |= LOOKUP_HAS_IN_CHARGE; } - rval = build_method_call (exp, constructor_name_full (type), - parms, binfo, flags|xxref_init_possible); - if (rval == NULL_TREE && xxref_init_possible) - { - /* It is an error to implement a default copy constructor if - (see ARM 12.8 for details) ... one case being if another - copy constructor already exists. */ - tree init_type = TREE_TYPE (init); - if (TREE_CODE (init_type) == REFERENCE_TYPE) - init_type = TREE_TYPE (init_type); - if (TYPE_MAIN_VARIANT (init_type) == TYPE_MAIN_VARIANT (type) - || (IS_AGGR_TYPE (init_type) - && UNIQUELY_DERIVED_FROM_P (type, init_type))) - { - if (type == BINFO_TYPE (binfo) - && TYPE_USES_VIRTUAL_BASECLASSES (type)) - { - tree addr = build_unary_op (ADDR_EXPR, exp, 0); - expand_aggr_vbase_init (binfo, exp, addr, NULL_TREE); - - expand_indirect_vtbls_init (binfo, exp, addr, 1); - } - expand_expr_stmt (build_modify_expr (exp, INIT_EXPR, init)); - return; - } - else - rval = build_method_call (exp, constructor_name_full (type), parms, - binfo, flags); - } - - /* Private, protected, or otherwise unavailable. */ - if (rval == error_mark_node && (flags&LOOKUP_COMPLAIN)) - cp_error ("in base initialization for class `%T'", binfo); - /* A valid initialization using constructor. */ - else if (rval != error_mark_node && rval != NULL_TREE) - { - /* p. 222: if the base class assigns to `this', then that - value is used in the derived class. */ - if ((flag_this_is_variable & 1) && alias_this) - { - TREE_TYPE (rval) = TREE_TYPE (current_class_decl); - expand_assignment (current_class_decl, rval, 0, 0); - } - else - expand_expr_stmt (rval); - } - else if (parms && TREE_CHAIN (parms) == NULL_TREE) + if (init && TREE_CHAIN (parms) == NULL_TREE + && TYPE_HAS_TRIVIAL_INIT_REF (type) + && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (init))) { - /* If we are initializing one aggregate value - from another, and though there are constructors, - and none accept the initializer, just do a bitwise - copy. - - The above sounds wrong, ``If a class has any copy - constructor defined, the default copy constructor will - not be generated.'' 12.8 Copying Class Objects (mrs) - - @@ This should reject initializer which a constructor - @@ rejected on access gounds, but there is - @@ no way right now to recognize that case with - @@ just `error_mark_node'. */ - tree itype; - init = TREE_VALUE (parms); - itype = TREE_TYPE (init); - if (TREE_CODE (itype) == REFERENCE_TYPE) - { - init = convert_from_reference (init); - itype = TREE_TYPE (init); - } - itype = TYPE_MAIN_VARIANT (itype); - - /* This is currently how the default X(X&) constructor - is implemented. */ - if (comptypes (TYPE_MAIN_VARIANT (type), itype, 0)) - { -#if 0 - warning ("bitwise copy in initialization of type `%s'", - TYPE_NAME_STRING (type)); -#endif - rval = build (INIT_EXPR, type, exp, init); - expand_expr_stmt (rval); - } - else - { - cp_error ("in base initialization for class `%T',", binfo); - cp_error ("invalid initializer to constructor for type `%T'", type); - return; - } + rval = build (INIT_EXPR, type, exp, init); + TREE_SIDE_EFFECTS (rval) = 1; + expand_expr_stmt (rval); } else { - if (init == NULL_TREE) - my_friendly_assert (parms == NULL_TREE, 210); - if (parms == NULL_TREE && TREE_VIA_VIRTUAL (binfo)) - cp_error ("virtual baseclass `%T' does not have default initializer", binfo); + if (flags & LOOKUP_ONLYCONVERTING) + flags |= LOOKUP_NO_CONVERSION; + rval = build_method_call (exp, constructor_name_full (type), + parms, binfo, flags); + + /* Private, protected, or otherwise unavailable. */ + if (rval == error_mark_node) + { + if (flags & LOOKUP_COMPLAIN) + cp_error ("in base initialization for %sclass `%T'", + TREE_VIA_VIRTUAL (binfo) ? "virtual base " : "", + binfo); + } + else if (rval == NULL_TREE) + my_friendly_abort (361); else { - cp_error ("in base initialization for class `%T',", binfo); - /* This will make an error message for us. */ - build_method_call (exp, constructor_name_full (type), parms, binfo, - (TYPE_USES_VIRTUAL_BASECLASSES (type) - ? LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE - : LOOKUP_NORMAL)); + /* p. 222: if the base class assigns to `this', then that + value is used in the derived class. */ + if ((flag_this_is_variable & 1) && alias_this) + { + TREE_TYPE (rval) = TREE_TYPE (current_class_decl); + expand_assignment (current_class_decl, rval, 0, 0); + } + else + expand_expr_stmt (rval); } - return; } - /* Constructor has been called, but vtables may be for TYPE - rather than for FOR_TYPE. */ } /* This function is responsible for initializing EXP with INIT @@ -1430,9 +1358,6 @@ expand_aggr_init_1 (binfo, true_exp, exp init = build (CALL_EXPR, init_type, TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), 0); TREE_SIDE_EFFECTS (init) = 1; -#if 0 - TREE_RAISES (init) = ?? -#endif if (init_list) TREE_VALUE (init_list) = init; } @@ -1440,7 +1365,7 @@ expand_aggr_init_1 (binfo, true_exp, exp if (init_type == type && TREE_CODE (init) == CALL_EXPR #if 0 - /* It is legal to directly initialize from a CALL_EXPR + /* It is valid to directly initialize from a CALL_EXPR without going through X(X&), apparently. */ && ! TYPE_GETS_INIT_REF (type) #endif @@ -1502,9 +1427,6 @@ expand_aggr_init_1 (binfo, true_exp, exp init = build (CALL_EXPR, build_pointer_type (TREE_TYPE (init)), TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), 0); TREE_SIDE_EFFECTS (init) = 1; -#if 0 - TREE_RAISES (init) = ?? -#endif TREE_VALUE (TREE_OPERAND (init, 1)) = convert_pointer_to (TREE_TYPE (TREE_TYPE (TREE_VALUE (tmp))), arg); @@ -1638,7 +1560,7 @@ expand_recursive_init_1 (binfo, true_exp tree subexp = build_indirect_ref (convert_pointer_to (TREE_VALUE (init_list), addr), NULL_PTR); tree member_base = build (COMPONENT_REF, TREE_TYPE (member), subexp, member); if (IS_AGGR_TYPE (TREE_TYPE (member))) - expand_aggr_init (member_base, DECL_INITIAL (member), 0); + expand_aggr_init (member_base, DECL_INITIAL (member), 0, 0); else if (TREE_CODE (TREE_TYPE (member)) == ARRAY_TYPE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (member))) { @@ -1836,6 +1758,18 @@ build_member_call (cname, name, parmlist if (TREE_CODE (cname) == SCOPE_REF) cname = resolve_scope_to_name (NULL_TREE, cname); + /* This shouldn't be here, and build_member_call shouldn't appear in + parse.y! (mrs) */ + if (cname && get_aggr_from_typedef (cname, 0) == 0 + && TREE_CODE (cname) == IDENTIFIER_NODE) + { + tree ns = lookup_name (cname, 0); + if (ns && TREE_CODE (ns) == NAMESPACE_DECL) + { + return build_x_function_call (build_offset_ref (cname, name), parmlist, current_class_decl); + } + } + if (cname == NULL_TREE || ! (type = get_aggr_from_typedef (cname, 1))) return error_mark_node; @@ -1865,12 +1799,12 @@ build_member_call (cname, name, parmlist if (dont_use_this) { basetype_path = TYPE_BINFO (type); - decl = build1 (NOP_EXPR, TYPE_POINTER_TO (type), error_mark_node); + decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node); } else if (current_class_decl == 0) { dont_use_this = 1; - decl = build1 (NOP_EXPR, TYPE_POINTER_TO (type), error_mark_node); + decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node); } else { @@ -1880,7 +1814,7 @@ build_member_call (cname, name, parmlist { tree newtype = build_type_variant (type, TYPE_READONLY (oldtype), TYPE_VOLATILE (oldtype)); - decl = convert_force (build_pointer_type (newtype), olddecl); + decl = convert_force (build_pointer_type (newtype), olddecl, 0); } else decl = olddecl; @@ -1888,6 +1822,9 @@ build_member_call (cname, name, parmlist decl = build_indirect_ref (decl, NULL_PTR); + if (method_name == constructor_name (type) + || method_name == constructor_name_full (type)) + return build_functional_cast (type, parmlist); if (t = lookup_fnfields (basetype_path, method_name, 0)) return build_method_call (decl, method_name, parmlist, basetype_path, LOOKUP_NORMAL|LOOKUP_NONVIRTUAL); @@ -1944,6 +1881,22 @@ build_offset_ref (cname, name) if (TREE_CODE (cname) == SCOPE_REF) cname = resolve_scope_to_name (NULL_TREE, cname); + /* Handle namespace names fully here. */ + if (TREE_CODE (cname) == IDENTIFIER_NODE + && get_aggr_from_typedef (cname, 0) == 0) + { + tree ns = lookup_name (cname, 0); + tree val; + if (ns && TREE_CODE (ns) == NAMESPACE_DECL) + { + val = lookup_namespace_name (ns, name); + if (val) + return val; + cp_error ("namespace `%D' has no member named `%D'", ns, name); + return error_mark_node; + } + } + if (cname == NULL_TREE || ! is_aggr_typedef (cname, 1)) return error_mark_node; @@ -2083,6 +2036,10 @@ build_offset_ref (cname, name) && ((flag_save_memoized_contexts && global_bindings_p ()) || ! allocation_temporary_p ())) fnfields = copy_list (fnfields); + + for (t = TREE_VALUE (fnfields); t; t = DECL_CHAIN (t)) + assemble_external (t); + t = build_tree_list (error_mark_node, fnfields); TREE_TYPE (t) = build_offset_type (type, unknown_type_node); return t; @@ -2118,6 +2075,12 @@ build_offset_ref (cname, name) return t; } + if (TREE_CODE (t) == FIELD_DECL && DECL_BIT_FIELD (t)) + { + cp_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); @@ -2159,7 +2122,7 @@ get_member_function (exp_addr_ptr, exp, if (UNITS_PER_WORD <= 1) my_friendly_abort (54); - e1 = build (GT_EXPR, integer_type_node, e0, integer_zero_node); + e1 = build (GT_EXPR, boolean_type_node, e0, integer_zero_node); e1 = build_compound_expr (tree_cons (NULL_TREE, exp_addr, build_tree_list (NULL_TREE, e1))); e1 = save_expr (e1); @@ -2242,7 +2205,8 @@ resolve_offset_ref (exp) { if (TREE_ADDRESSABLE (member) == 0) { - cp_error_at ("member `%D' is non-static in static member function context", member); + 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; } @@ -2314,7 +2278,7 @@ resolve_offset_ref (exp) } else if (TYPE_PTRMEMFUNC_P (TREE_TYPE (member))) { - return get_member_function_from_ptrfunc (&addr, base, member); + return get_member_function_from_ptrfunc (&addr, member); } my_friendly_abort (56); /* NOTREACHED */ @@ -2396,7 +2360,13 @@ is_friend (type, supplicant) { tree list = DECL_FRIENDLIST (TYPE_NAME (type)); tree name = DECL_NAME (supplicant); - tree ctype = DECL_CLASS_CONTEXT (supplicant); + tree ctype; + + if (DECL_FUNCTION_MEMBER_P (supplicant)) + ctype = DECL_CLASS_CONTEXT (supplicant); + else + ctype = NULL_TREE; + for (; list ; list = TREE_CHAIN (list)) { if (name == TREE_PURPOSE (list)) @@ -2427,8 +2397,14 @@ is_friend (type, supplicant) } { - tree context = declp ? DECL_CLASS_CONTEXT (supplicant) - : DECL_CONTEXT (TYPE_NAME (supplicant)); + tree context; + + if (! declp) + context = DECL_CONTEXT (TYPE_NAME (supplicant)); + else if (DECL_FUNCTION_MEMBER_P (supplicant)) + context = DECL_CLASS_CONTEXT (supplicant); + else + context = NULL_TREE; if (context) return is_friend (type, context); @@ -2456,9 +2432,9 @@ add_friend (type, decl) { if (decl == TREE_VALUE (friends)) { - cp_pedwarn ("`%D' is already a friend of class `%T'", + cp_warning ("`%D' is already a friend of class `%T'", decl, type); - cp_pedwarn_at ("previous friend declaration of `%D'", + cp_warning_at ("previous friend declaration of `%D'", TREE_VALUE (friends)); return; } @@ -2582,7 +2558,7 @@ make_friend_class (type, friend_type) } if (type == friend_type) { - warning ("class `%s' is implicitly friends with itself", + pedwarn ("class `%s' is implicitly friends with itself", TYPE_NAME_STRING (type)); return; } @@ -2707,7 +2683,6 @@ do_friend (ctype, declarator, decl, parm { /* raw "main", and builtin functions never gets overloaded, but they can become friends. */ - TREE_PUBLIC (decl) = 1; add_friend (current_class_type, decl); DECL_FRIEND_P (decl) = 1; decl = void_type_node; @@ -2868,6 +2843,8 @@ build_builtin_call (type, node, arglist) 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; @@ -2876,6 +2853,7 @@ build_new (placement, decl, init, use_gl { tree type, true_type, size, rval; tree nelts; + tree alloc_expr, alloc_temp; int has_array = 0; enum tree_code code = NEW_EXPR; @@ -2999,6 +2977,12 @@ build_new (placement, decl, init, use_gl type = true_type = TREE_TYPE (type); } + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("new cannot be applied to a function type"); + return error_mark_node; + } + /* When the object being created is an array, the new-expression yields a pointer to the initial element (if any) of the array. For example, both new int and new int[10] return an int*. 5.3.4. */ @@ -3010,11 +2994,8 @@ build_new (placement, decl, init, use_gl } if (TYPE_READONLY (type) || TYPE_VOLATILE (type)) - { - pedwarn ("const and volatile types cannot be created with operator new"); - type = true_type = TYPE_MAIN_VARIANT (type); - } - + type = TYPE_MAIN_VARIANT (type); + /* If our base type is an array, then make sure we know how many elements it has. */ while (TREE_CODE (true_type) == ARRAY_TYPE) @@ -3029,12 +3010,15 @@ build_new (placement, decl, init, use_gl else size = size_in_bytes (type); + if (true_type == void_type_node) + { + error ("invalid type `void' for new"); + return error_mark_node; + } + if (TYPE_SIZE (true_type) == 0) { - if (true_type == void_type_node) - error ("invalid type for new: `void'"); - else - incomplete_type_error (0, true_type); + incomplete_type_error (0, true_type); return error_mark_node; } @@ -3067,15 +3051,15 @@ build_new (placement, decl, init, use_gl if (! use_global_new && TYPE_LANG_SPECIFIC (true_type) && (TYPE_GETS_NEW (true_type) & (1 << has_array))) rval = build_opfncall (code, LOOKUP_NORMAL, - TYPE_POINTER_TO (true_type), size, placement); + build_pointer_type (true_type), size, placement); else if (placement) { rval = build_opfncall (code, LOOKUP_GLOBAL|LOOKUP_COMPLAIN, ptr_type_node, size, placement); - rval = convert (TYPE_POINTER_TO (true_type), rval); + rval = convert (build_pointer_type (true_type), rval); } else if (! has_array && flag_this_is_variable > 0 - && TYPE_HAS_CONSTRUCTOR (true_type) && init != void_type_node) + && TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node) { if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST) rval = NULL_TREE; @@ -3094,9 +3078,9 @@ build_new (placement, decl, init, use_gl /* See comment above as to why this is disabled. */ if (alignment) { - rval = build (PLUS_EXPR, TYPE_POINTER_TO (true_type), rval, + rval = build (PLUS_EXPR, build_pointer_type (true_type), rval, alignment); - rval = build (BIT_AND_EXPR, TYPE_POINTER_TO (true_type), + rval = build (BIT_AND_EXPR, build_pointer_type (true_type), rval, build1 (BIT_NOT_EXPR, integer_type_node, alignment)); } @@ -3104,6 +3088,20 @@ build_new (placement, decl, init, use_gl TREE_CALLS_NEW (rval) = 1; } + if (flag_check_new && rval) + { + /* For array new, we need to make sure that the call to new is + not expanded as part of the RTL_EXPR for the initialization, + so we can't just use save_expr here. */ + + alloc_temp = get_temp_name (TREE_TYPE (rval), 0); + alloc_expr = build (MODIFY_EXPR, TREE_TYPE (rval), alloc_temp, rval); + TREE_SIDE_EFFECTS (alloc_expr) = 1; + rval = alloc_temp; + } + 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) */ @@ -3116,7 +3114,7 @@ build_new (placement, decl, init, use_gl rval = convert (string_type_node, rval); /* lets not add void* and ints */ rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra, 1)); /* Store header info. */ - cookie = build_indirect_ref (build (MINUS_EXPR, TYPE_POINTER_TO (BI_header_type), + 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, 0, 0), @@ -3129,57 +3127,8 @@ build_new (placement, decl, init, use_gl build_tree_list (NULL_TREE, rval))); } - /* We've figured out where the allocation is to go. - If we're not eliding constructors, then if a constructor - is defined, we must go through it. */ - if (!has_array && (rval == NULL_TREE || !flag_elide_constructors) - && TYPE_HAS_CONSTRUCTOR (true_type) && init != void_type_node) - { - 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 a copy constructor might work, set things up so that we can - try that after this. We deliberately don't clear LOOKUP_COMPLAIN - any more, since that would make it impossible to rationally use - the access of a constructor that matches perfectly. */ -#if 0 - if (rval != NULL_TREE) - flags |= LOOKUP_SPECULATIVELY; -#endif - - if (rval && TYPE_USES_VIRTUAL_BASECLASSES (true_type)) - { - init = tree_cons (NULL_TREE, integer_one_node, init); - flags |= LOOKUP_HAS_IN_CHARGE; - } - - { - tree tmp = rval; - - if (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE) - tmp = build_indirect_ref (tmp, NULL_PTR); - - newrval = build_method_call (tmp, constructor_name_full (true_type), - init, NULL_TREE, flags); - } - - if (newrval) - { - rval = newrval; - TREE_HAS_CONSTRUCTOR (rval) = 1; - } - else - rval = error_mark_node; - goto done; - } - if (rval == error_mark_node) return error_mark_node; - rval = save_expr (rval); - TREE_HAS_CONSTRUCTOR (rval) = 1; /* Don't call any constructors or do any initialization. */ if (init == void_type_node) @@ -3187,26 +3136,78 @@ build_new (placement, decl, init, use_gl if (TYPE_NEEDS_CONSTRUCTING (type) || init) { - if (! TYPE_NEEDS_CONSTRUCTING (type) && ! IS_AGGR_TYPE (type)) + if (! TYPE_NEEDS_CONSTRUCTING (type) + && ! IS_AGGR_TYPE (type) && ! has_array) { /* New 2.0 interpretation: `new int (10)' means allocate an int, and initialize it with 10. */ + tree deref; + + rval = save_expr (rval); + deref = build_indirect_ref (rval, NULL_PTR); + TREE_READONLY (deref) = 0; - init = build_c_cast (type, init); + if (TREE_CHAIN (init) != NULL_TREE) + pedwarn ("initializer list being treated as compound expression"); + else if (TREE_CODE (init) == CONSTRUCTOR) + { + pedwarn ("initializer list appears where operand should be used"); + init = TREE_OPERAND (init, 1); + } + 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 (build_indirect_ref (rval, NULL_PTR), - NOP_EXPR, init), + build_modify_expr (deref, NOP_EXPR, init), rval); + TREE_NO_UNUSED_WARNING (rval) = 1; TREE_SIDE_EFFECTS (rval) = 1; TREE_CALLS_NEW (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)) + { + init = tree_cons (NULL_TREE, integer_one_node, init); + flags |= LOOKUP_HAS_IN_CHARGE; + } + + newrval = rval; + + if (newrval && TREE_CODE (TREE_TYPE (newrval)) == POINTER_TYPE) + newrval = build_indirect_ref (newrval, NULL_PTR); + + newrval = build_method_call (newrval, constructor_name_full (true_type), + init, NULL_TREE, flags); + + if (newrval) + { + rval = newrval; + TREE_HAS_CONSTRUCTOR (rval) = 1; + } + else + rval = error_mark_node; + } else if (current_function_decl == NULL_TREE) { extern tree static_aggregates; /* In case of static initialization, SAVE_EXPR is good enough. */ - init = copy_to_permanent (init); + rval = save_expr (rval); rval = copy_to_permanent (rval); + init = copy_to_permanent (init); + init = expand_vec_init (decl, rval, + build_binary_op (MINUS_EXPR, nelts, + integer_one_node, 1), + init, 0); + init = copy_to_permanent (init); static_aggregates = perm_tree_cons (init, rval, static_aggregates); } else @@ -3217,6 +3218,29 @@ build_new (placement, decl, init, use_gl can't easily know the latter, just do it always. */ tree xval = make_node (RTL_EXPR); + /* If we want to check the value of the allocation expression, + and the number of elements in the array is not a constant, we + *must* expand the SAVE_EXPR for nelts in alloc_expr before we + expand it in the actual initialization. So we need to build up + an RTL_EXPR for alloc_expr. Sigh. */ + if (alloc_expr && ! TREE_CONSTANT (nelts)) + { + tree xval = make_node (RTL_EXPR); + rtx rtxval; + TREE_TYPE (xval) = TREE_TYPE (alloc_expr); + do_pending_stack_adjust (); + start_sequence_for_rtl_expr (xval); + emit_note (0, -1); + rtxval = expand_expr (alloc_expr, NULL, VOIDmode, 0); + do_pending_stack_adjust (); + TREE_SIDE_EFFECTS (xval) = 1; + RTL_EXPR_SEQUENCE (xval) = get_insns (); + end_sequence (); + RTL_EXPR_RTL (xval) = rtxval; + TREE_TYPE (xval) = TREE_TYPE (alloc_expr); + alloc_expr = xval; + } + TREE_TYPE (xval) = TREE_TYPE (rval); do_pending_stack_adjust (); start_sequence_for_rtl_expr (xval); @@ -3224,12 +3248,11 @@ build_new (placement, decl, init, use_gl /* As a matter of principle, `start_sequence' should do this. */ emit_note (0, -1); - if (has_array) - rval = expand_vec_init (decl, rval, - build_binary_op (MINUS_EXPR, nelts, integer_one_node, 1), - init, 0); - else - expand_aggr_init (build_indirect_ref (rval, NULL_PTR), init, 0); + rval = save_expr (rval); + rval = expand_vec_init (decl, rval, + build_binary_op (MINUS_EXPR, nelts, + integer_one_node, 1), + init, 0); do_pending_stack_adjust (); @@ -3253,11 +3276,28 @@ build_new (placement, decl, init, use_gl rval = xval; } } + else if (TYPE_READONLY (true_type)) + cp_error ("uninitialized const in `new' of `%#T'", true_type); + done: + + if (alloc_expr) + { + /* Did we modify the storage? */ + if (rval != alloc_temp) + { + tree ifexp = build_binary_op (NE_EXPR, alloc_expr, + integer_zero_node, 1); + rval = build_conditional_expr (ifexp, rval, alloc_temp); + } + else + rval = alloc_expr; + } + if (rval && TREE_TYPE (rval) != build_pointer_type (type)) { /* The type of new int [3][3] is not int *, but int [3] * */ - rval = build_c_cast (build_pointer_type (type), rval); + rval = build_c_cast (build_pointer_type (type), rval, 0); } if (pending_sizes) @@ -3285,6 +3325,174 @@ build_new (placement, decl, init, use_gl return rval; } +static tree +build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete, + use_global_delete) + tree base, maxindex, type; + tree auto_delete_vec, auto_delete; + int use_global_delete; +{ + tree virtual_size; + tree ptype = build_pointer_type (type); + tree size_exp = size_in_bytes (type); + + /* Temporary variables used by the loop. */ + tree tbase, tbase_init; + + /* This is the body of the loop that implements the deletion of a + single element, and moves temp variables to next elements. */ + tree body; + + /* This is the LOOP_EXPR that governs the deletion of the elements. */ + tree loop; + + /* This is the thing that governs what to do after the loop has run. */ + tree deallocate_expr = 0; + + /* This is the BIND_EXPR which holds the outermost iterator of the + loop. It is convenient to set this variable up and test it before + executing any other code in the loop. + This is also the containing expression returned by this function. */ + tree controller = NULL_TREE; + + /* This is the BLOCK to record the symbol binding for debugging. */ + tree block; + + if (! IS_AGGR_TYPE (type) || ! TYPE_NEEDS_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)); + + tbase = build_decl (VAR_DECL, NULL_TREE, ptype); + tbase_init = build_modify_expr (tbase, NOP_EXPR, + fold (build (PLUS_EXPR, ptype, + base, + virtual_size))); + DECL_REGISTER (tbase) = 1; + controller = build (BIND_EXPR, void_type_node, tbase, 0, 0); + TREE_SIDE_EFFECTS (controller) = 1; + block = build_block (tbase, 0, 0, 0, 0); + add_block_current_level (block); + + if (auto_delete != integer_zero_node + && auto_delete != integer_two_node) + { + tree base_tbd = convert (ptype, + build_binary_op (MINUS_EXPR, + convert (ptr_type_node, base), + BI_header_size, + 1)); + /* This is the real size */ + virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size); + body = build_tree_list (NULL_TREE, + build_x_delete (ptype, base_tbd, + 2 | use_global_delete, + virtual_size)); + body = build (COND_EXPR, void_type_node, + build (BIT_AND_EXPR, integer_type_node, + auto_delete, integer_one_node), + body, integer_zero_node); + } + else + body = NULL_TREE; + + body = tree_cons (NULL_TREE, + build_delete (ptype, tbase, auto_delete, + LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1), + body); + + body = tree_cons (NULL_TREE, + build_modify_expr (tbase, NOP_EXPR, build (MINUS_EXPR, ptype, tbase, size_exp)), + body); + + 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 = tree_cons (NULL_TREE, tbase_init, + tree_cons (NULL_TREE, loop, NULL_TREE)); + loop = build_compound_expr (loop); + + no_destructor: + /* If the delete flag is one, or anything else with the low bit set, + delete the storage. */ + if (auto_delete_vec == integer_zero_node + || auto_delete_vec == integer_two_node) + deallocate_expr = integer_zero_node; + else + { + tree base_tbd; + + /* The below is short by BI_header_size */ + virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex)); + + if (! TYPE_VEC_NEW_USES_COOKIE (type)) + /* no header */ + base_tbd = base; + else + { + base_tbd = convert (ptype, + build_binary_op (MINUS_EXPR, + convert (string_type_node, base), + BI_header_size, + 1)); + /* True size with header. */ + virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size); + } + deallocate_expr = build_x_delete (ptype, 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 (loop && deallocate_expr != integer_zero_node) + { + 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 = build1 (NOP_EXPR, void_type_node, body); + + if (controller) + { + TREE_OPERAND (controller, 1) = body; + return controller; + } + else + return convert (void_type_node, body); +} + +/* Build a tree to cleanup partially built arrays. + BASE is that starting address of the array. + COUNT is the count of objects that have been built, that need destroying. + TYPE is the type of elements in the array. */ +static tree +build_array_eh_cleanup (base, count, type) + tree base, count, type; +{ + tree expr = build_vec_delete_1 (base, count, type, integer_two_node, + integer_zero_node, 0); + return expr; +} + /* `expand_vec_init' performs initialization of a vector of aggregate types. @@ -3329,12 +3537,12 @@ expand_vec_init (decl, base, maxindex, i /* Set to zero in case size is <= 0. Optimizer will delete this if it is not needed. */ - rval = get_temp_regvar (TYPE_POINTER_TO (type), - convert (TYPE_POINTER_TO (type), null_pointer_node)); + rval = get_temp_regvar (build_pointer_type (type), + convert (build_pointer_type (type), null_pointer_node)); base = default_conversion (base); - base = convert (TYPE_POINTER_TO (type), base); + base = convert (build_pointer_type (type), base); expand_assignment (rval, base, 0, 0); - base = get_temp_regvar (TYPE_POINTER_TO (type), base); + base = get_temp_regvar (build_pointer_type (type), base); if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR @@ -3343,7 +3551,7 @@ expand_vec_init (decl, base, maxindex, i /* Initialization of array from {...}. */ tree elts = CONSTRUCTOR_ELTS (init); tree baseref = build1 (INDIRECT_REF, type, base); - tree baseinc = build (PLUS_EXPR, TYPE_POINTER_TO (type), base, size); + tree baseinc = build (PLUS_EXPR, build_pointer_type (type), base, size); int host_i = TREE_INT_CST_LOW (maxindex); if (IS_AGGR_TYPE (type)) @@ -3351,7 +3559,7 @@ expand_vec_init (decl, base, maxindex, i while (elts) { host_i -= 1; - expand_aggr_init (baseref, TREE_VALUE (elts), 0); + expand_aggr_init (baseref, TREE_VALUE (elts), 0, 0); expand_assignment (base, baseinc, 0, 0); elts = TREE_CHAIN (elts); @@ -3418,8 +3626,10 @@ expand_vec_init (decl, base, maxindex, i } } - expand_start_cond (build (GE_EXPR, integer_type_node, + expand_start_cond (build (GE_EXPR, boolean_type_node, iterator, integer_zero_node), 0); + if (TYPE_NEEDS_DESTRUCTOR (type)) + start_protect (); expand_start_loop_continue_elsewhere (1); if (from_array) @@ -3435,7 +3645,7 @@ expand_vec_init (decl, base, maxindex, i if (from_array == 2) expand_expr_stmt (build_modify_expr (to, NOP_EXPR, from)); else if (TYPE_NEEDS_CONSTRUCTING (type)) - expand_aggr_init (to, from, 0); + expand_aggr_init (to, from, 0, 0); else if (from) expand_assignment (to, from, 0, 0); else @@ -3445,20 +3655,20 @@ expand_vec_init (decl, base, maxindex, i { if (init != 0) sorry ("cannot initialize multi-dimensional array with initializer"); - expand_vec_init (decl, build1 (NOP_EXPR, TYPE_POINTER_TO (TREE_TYPE (type)), base), + expand_vec_init (decl, build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), base), array_type_nelts (type), 0, 0); } else - expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0); + expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0, 0); expand_assignment (base, - build (PLUS_EXPR, TYPE_POINTER_TO (type), base, size), + build (PLUS_EXPR, build_pointer_type (type), base, size), 0, 0); if (base2) expand_assignment (base2, - build (PLUS_EXPR, TYPE_POINTER_TO (type), base2, size), 0, 0); + build (PLUS_EXPR, build_pointer_type (type), base2, size), 0, 0); expand_loop_continue_here (); - expand_exit_loop_if_false (0, build (NE_EXPR, integer_type_node, + expand_exit_loop_if_false (0, build (NE_EXPR, boolean_type_node, build (PREDECREMENT_EXPR, integer_type_node, iterator, integer_one_node), minus_one)); if (obey_regdecls) @@ -3468,6 +3678,13 @@ expand_vec_init (decl, base, maxindex, i use_variable (DECL_RTL (base2)); } expand_end_loop (); + if (TYPE_NEEDS_DESTRUCTOR (type)) + end_protect (build_array_eh_cleanup (rval, + build_binary_op (MINUS_EXPR, + maxindex, + iterator, + 1), + type)); expand_end_cond (); if (obey_regdecls) use_variable (DECL_RTL (iterator)); @@ -3566,7 +3783,7 @@ build_delete (type, addr, auto_delete, f addr = save_expr (addr); /* throw away const and volatile on target type of addr */ - addr = convert_force (build_pointer_type (type), addr); + addr = convert_force (build_pointer_type (type), addr, 0); ref = build_indirect_ref (addr, NULL_PTR); ptr = 1; } @@ -3575,6 +3792,11 @@ build_delete (type, addr, auto_delete, f handle_array: if (TREE_SIDE_EFFECTS (addr)) addr = save_expr (addr); + if (TYPE_DOMAIN (type) == NULL_TREE) + { + error ("unknown array size in delete"); + return error_mark_node; + } return build_vec_delete (addr, array_type_nelts (type), c_sizeof_nowarn (TREE_TYPE (type)), auto_delete, integer_two_node, @@ -3592,7 +3814,7 @@ build_delete (type, addr, auto_delete, f if (TREE_CONSTANT (addr)) addr = convert_pointer_to (type, addr); else - addr = convert_force (build_pointer_type (type), addr); + addr = convert_force (build_pointer_type (type), addr, 0); if (TREE_CODE (addr) == NOP_EXPR && TREE_OPERAND (addr, 0) == current_class_decl) @@ -3822,7 +4044,7 @@ build_delete (type, addr, auto_delete, f else this_auto_delete = integer_zero_node; - expr = build_delete (TYPE_POINTER_TO (BINFO_TYPE (base_binfo)), addr, + expr = build_delete (build_pointer_type (BINFO_TYPE (base_binfo)), addr, this_auto_delete, flags, 0); exprstmt = tree_cons (NULL_TREE, expr, exprstmt); } @@ -3836,10 +4058,10 @@ build_delete (type, addr, auto_delete, f continue; /* May be zero offset if other baseclasses are virtual. */ - expr = fold (build (PLUS_EXPR, TYPE_POINTER_TO (BINFO_TYPE (base_binfo)), + expr = fold (build (PLUS_EXPR, build_pointer_type (BINFO_TYPE (base_binfo)), addr, BINFO_OFFSET (base_binfo))); - expr = build_delete (TYPE_POINTER_TO (BINFO_TYPE (base_binfo)), expr, + expr = build_delete (build_pointer_type (BINFO_TYPE (base_binfo)), expr, integer_zero_node, flags, 0); @@ -3880,8 +4102,8 @@ build_vbase_delete (type, decl) while (vbases) { - tree this_addr = convert_force (TYPE_POINTER_TO (BINFO_TYPE (vbases)), - addr); + tree this_addr = convert_force (build_pointer_type (BINFO_TYPE (vbases)), + addr, 0); result = tree_cons (NULL_TREE, build_delete (TREE_TYPE (this_addr), this_addr, integer_zero_node, @@ -3915,30 +4137,12 @@ build_vec_delete (base, maxindex, elt_si tree auto_delete_vec, auto_delete; int use_global_delete; { - tree ptype = TREE_TYPE (base); tree type; - tree virtual_size; - /* Temporary variables used by the loop. */ - tree tbase, size_exp, tbase_init; - - /* This is the body of the loop that implements the deletion of a - single element, and moves temp variables to next elements. */ - tree body; - - /* This is the LOOP_EXPR that governs the deletion of the elements. */ - tree loop; - - /* This is the thing that governs what to do after the loop has run. */ - tree deallocate_expr = 0; - /* This is the BIND_EXPR which holds the outermost iterator of the - loop. It is convenient to set this variable up and test it before - executing any other code in the loop. - This is also the containing expression returned by this function. */ - tree controller = NULL_TREE; + if (TREE_CODE (base) == OFFSET_REF) + base = resolve_offset_ref (base); - /* This is the BLOCK to record the symbol binding for debugging. */ - tree block; + type = TREE_TYPE (base); base = stabilize_reference (base); @@ -3946,23 +4150,23 @@ build_vec_delete (base, maxindex, elt_si if (TREE_SIDE_EFFECTS (base)) base = save_expr (base); - if (TREE_CODE (ptype) == POINTER_TYPE) + if (TREE_CODE (type) == POINTER_TYPE) { /* Step back one from start of vector, and read dimension. */ - tree cookie_addr = build (MINUS_EXPR, TYPE_POINTER_TO (BI_header_type), + tree cookie_addr = build (MINUS_EXPR, build_pointer_type (BI_header_type), base, BI_header_size); tree cookie = build_indirect_ref (cookie_addr, NULL_PTR); maxindex = build_component_ref (cookie, nc_nelts_field_id, 0, 0); do - ptype = TREE_TYPE (ptype); - while (TREE_CODE (ptype) == ARRAY_TYPE); + type = TREE_TYPE (type); + while (TREE_CODE (type) == ARRAY_TYPE); } - else if (TREE_CODE (ptype) == ARRAY_TYPE) + 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 (ptype); - while (TREE_CODE (ptype) == ARRAY_TYPE) - ptype = TREE_TYPE (ptype); + maxindex = array_type_nelts_total (type); + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); base = build_unary_op (ADDR_EXPR, base, 1); } else @@ -3970,129 +4174,7 @@ build_vec_delete (base, maxindex, elt_si error ("type to vector delete is neither pointer or array type"); return error_mark_node; } - type = ptype; - ptype = TYPE_POINTER_TO (type); - size_exp = size_in_bytes (type); - - if (! IS_AGGR_TYPE (type) || ! TYPE_NEEDS_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)); - - tbase = build_decl (VAR_DECL, NULL_TREE, ptype); - tbase_init = build_modify_expr (tbase, NOP_EXPR, - fold (build (PLUS_EXPR, ptype, - base, - virtual_size))); - DECL_REGISTER (tbase) = 1; - controller = build (BIND_EXPR, void_type_node, tbase, 0, 0); - TREE_SIDE_EFFECTS (controller) = 1; - block = build_block (tbase, 0, 0, 0, 0); - add_block_current_level (block); - - if (auto_delete != integer_zero_node - && auto_delete != integer_two_node) - { - tree base_tbd = convert (ptype, - build_binary_op (MINUS_EXPR, - convert (ptr_type_node, base), - BI_header_size, - 1)); - /* This is the real size */ - virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size); - body = build_tree_list (NULL_TREE, - build_x_delete (ptype, base_tbd, - 2 | use_global_delete, - virtual_size)); - body = build (COND_EXPR, void_type_node, - build (BIT_AND_EXPR, integer_type_node, - auto_delete, integer_one_node), - body, integer_zero_node); - } - else - body = NULL_TREE; - - body = tree_cons (NULL_TREE, - build_delete (ptype, tbase, auto_delete, - LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1), - body); - - body = tree_cons (NULL_TREE, - build_modify_expr (tbase, NOP_EXPR, build (MINUS_EXPR, ptype, tbase, size_exp)), - body); - - body = tree_cons (NULL_TREE, - build (EXIT_EXPR, void_type_node, - build (EQ_EXPR, integer_type_node, base, tbase)), - body); - - loop = build (LOOP_EXPR, void_type_node, build_compound_expr (body)); - - loop = tree_cons (NULL_TREE, tbase_init, - tree_cons (NULL_TREE, loop, NULL_TREE)); - loop = build_compound_expr (loop); - - no_destructor: - /* If the delete flag is one, or anything else with the low bit set, - delete the storage. */ - if (auto_delete_vec == integer_zero_node - || auto_delete_vec == integer_two_node) - deallocate_expr = integer_zero_node; - else - { - tree base_tbd; - - /* The below is short by BI_header_size */ - virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex)); - - if (! TYPE_VEC_NEW_USES_COOKIE (type)) - /* no header */ - base_tbd = base; - else - { - base_tbd = convert (ptype, - build_binary_op (MINUS_EXPR, - convert (string_type_node, base), - BI_header_size, - 1)); - /* True size with header. */ - virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size); - } - deallocate_expr = build_x_delete (ptype, 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 (loop && deallocate_expr != integer_zero_node) - { - 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, integer_type_node, base, integer_zero_node), - body, integer_zero_node); - body = build1 (NOP_EXPR, void_type_node, body); - - if (controller) - { - TREE_OPERAND (controller, 1) = body; - return controller; - } - else - return convert (void_type_node, body); + return build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete, + use_global_delete); }