diff options
author | kan <kan@FreeBSD.org> | 2003-07-11 03:40:53 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2003-07-11 03:40:53 +0000 |
commit | b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180 (patch) | |
tree | f6b0610f4a17fd26aa234354f050080f789861a4 /contrib/gcc/cp/init.c | |
parent | 52e69d78eee5612ac195e0701a5cebe40d1ab0e1 (diff) | |
download | FreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.zip FreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.tar.gz |
Gcc 3.3.1-pre as of 2003-07-11.
Diffstat (limited to 'contrib/gcc/cp/init.c')
-rw-r--r-- | contrib/gcc/cp/init.c | 1259 |
1 files changed, 602 insertions, 657 deletions
diff --git a/contrib/gcc/cp/init.c b/contrib/gcc/cp/init.c index 1e08908..279e3b1 100644 --- a/contrib/gcc/cp/init.c +++ b/contrib/gcc/cp/init.c @@ -1,6 +1,6 @@ /* Handle initialization things in C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GNU CC. @@ -34,48 +34,26 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #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 construct_virtual_base (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 void perform_member_init (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 sort_mem_initializers (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_default_init PARAMS ((tree, 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; - -void init_init_processing () -{ - tree fields[1]; - - /* Define the structure that holds header information for - arrays allocated via operator new. */ - 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); - - 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 @@ -167,7 +145,7 @@ initialize_vtbl_ptrs (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 + class. We do these in pre-order because we can't find the virtual bases for a class until we've initialized the vtbl for that class. */ dfs_walk_real (TYPE_BINFO (type), dfs_initialize_vtbl_ptrs, @@ -176,86 +154,194 @@ initialize_vtbl_ptrs (addr) dfs_marked_real_bases_queue_p, type); } -/* Types containing pointers to data members cannot be - zero-initialized with zeros, because the NULL value for such - pointers is -1. - - TYPE is a type that requires such zero initialization. The - returned value is the initializer. */ +/* Return an expression for the zero-initialization of an object with + type T. This expression will either be a constant (in the case + that T is a scalar), or a CONSTRUCTOR (in the case that T is an + aggregate). In either case, the value can be used as DECL_INITIAL + for a decl of the indicated TYPE; it is a valid static initializer. + If NELTS is non-NULL, and TYPE is an ARRAY_TYPE, NELTS is the + number of elements in the array. If STATIC_STORAGE_P is TRUE, + initializers are only generated for entities for which + zero-initialization does not simply mean filling the storage with + zero bytes. */ tree -build_forced_zero_init (type) - tree type; +build_zero_init (tree type, tree nelts, bool static_storage_p) { - tree init = NULL; + tree init = NULL_TREE; + + /* [dcl.init] + + To zero-initialization storage for an object of type T means: + + -- if T is a scalar type, the storage is set to the value of zero + converted to T. + + -- if T is a non-union class type, the storage for each nonstatic + data member and each base-class subobject is zero-initialized. + + -- if T is a union type, the storage for its first data member is + zero-initialized. + + -- if T is an array type, the storage for each element is + zero-initialized. - if (AGGREGATE_TYPE_P (type) && !TYPE_PTRMEMFUNC_P (type)) + -- if T is a reference type, no initialization is performed. */ + + my_friendly_assert (nelts == NULL_TREE || TREE_CODE (nelts) == INTEGER_CST, + 20030618); + + if (type == error_mark_node) + ; + else if (static_storage_p && zero_init_p (type)) + /* In order to save space, we do not explicitly build initializers + for items that do not need them. GCC's semantics are that + items with static storage duration that are not otherwise + initialized are initialized to zero. */ + ; + else if (SCALAR_TYPE_P (type)) + init = convert (type, integer_zero_node); + else if (CLASS_TYPE_P (type)) + { + tree field; + tree inits; + + /* Build a constructor to contain the initializations. */ + init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE); + /* Iterate over the fields, building initializations. */ + inits = NULL_TREE; + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + /* Note that for class types there will be FIELD_DECLs + corresponding to base classes as well. Thus, iterating + over TYPE_FIELDs will result in correct initialization of + all of the subobjects. */ + if (static_storage_p && !zero_init_p (TREE_TYPE (field))) + inits = tree_cons (field, + build_zero_init (TREE_TYPE (field), + /*nelts=*/NULL_TREE, + static_storage_p), + inits); + + /* For unions, only the first field is initialized. */ + if (TREE_CODE (type) == UNION_TYPE) + break; + } + CONSTRUCTOR_ELTS (init) = nreverse (inits); + } + else if (TREE_CODE (type) == ARRAY_TYPE) { - /* 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); + tree index; + tree max_index; + tree inits; + + /* Build a constructor to contain the initializations. */ + init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE); + /* Iterate over the array elements, building initializations. */ + inits = NULL_TREE; + max_index = nelts ? nelts : array_type_nelts (type); + my_friendly_assert (TREE_CODE (max_index) == INTEGER_CST, 20030618); + + for (index = size_zero_node; + !tree_int_cst_lt (max_index, index); + index = size_binop (PLUS_EXPR, index, size_one_node)) + inits = tree_cons (index, + build_zero_init (TREE_TYPE (type), + /*nelts=*/NULL_TREE, + static_storage_p), + inits); + CONSTRUCTOR_ELTS (init) = nreverse (inits); } else if (TREE_CODE (type) == REFERENCE_TYPE) - /* --if T is a reference type, no initialization is performed. */ - return NULL_TREE; + ; else - { - 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)); - } + abort (); - init = digest_init (type, init, 0); + /* In all cases, the initializer is a constant. */ + if (init) + TREE_CONSTANT (init) = 1; return init; } -/* [dcl.init]: +/* Build an expression for the default-initialization of an object of + the indicated TYPE. If NELTS is non-NULL, and TYPE is an + ARRAY_TYPE, NELTS is the number of elements in the array. If + initialization of TYPE requires calling constructors, this function + returns NULL_TREE; the caller is responsible for arranging for the + constructors to be called. */ - To default-initialize an object of type T means: +static tree +build_default_init (type, nelts) + tree type; + tree nelts; +{ + /* [dcl.init]: - --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); + To default-initialize an object of type T means: - --if T is an array type, each element is default-initialized; + --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); - --otherwise, the storage for the object is zero-initialized. + --if T is an array type, each element is default-initialized; - A program that calls for default-initialization of an entity of refer- - ence type is ill-formed. */ + --otherwise, the storage for the object is zero-initialized. -static tree -build_default_init (type) - tree type; -{ - tree init = NULL_TREE; + A program that calls for default-initialization of an entity of refer- + ence type is ill-formed. */ - 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; + /* If TYPE_NEEDS_CONSTRUCTING is true, the caller is responsible for + performing the initialization. This is confusing in that some + non-PODs do not have TYPE_NEEDS_CONSTRUCTING set. (For example, + a class with a pointer-to-data member as a non-static data member + does not have TYPE_NEEDS_CONSTRUCTING set.) Therefore, we end up + passing non-PODs to build_zero_init below, which is contrary to + the semantics quoted above from [dcl.init]. - return build_forced_zero_init (type); + It happens, however, that the behavior of the constructor the + standard says we should have generated would be precisely the + same as that obtained by calling build_zero_init below, so things + work out OK. */ + if (TYPE_NEEDS_CONSTRUCTING (type) + || (nelts && TREE_CODE (nelts) != INTEGER_CST)) + return NULL_TREE; + + /* At this point, TYPE is either a POD class type, an array of POD + classes, or something even more inoccuous. */ + return build_zero_init (type, nelts, /*static_storage_p=*/false); } -/* Subroutine of emit_base_init. */ +/* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of + arguments. If TREE_LIST is void_type_node, an empty initializer + list was given; if NULL_TREE no initializer was given. */ static void -perform_member_init (member, init, explicit) - tree member, init; - int explicit; +perform_member_init (tree member, tree init) { tree decl; tree type = TREE_TYPE (member); + bool explicit; + + explicit = (init != NULL_TREE); - decl = build_component_ref (current_class_ref, member, NULL_TREE, explicit); + /* Effective C++ rule 12 requires that all data members be + initialized. */ + if (warn_ecpp && !explicit && TREE_CODE (type) != ARRAY_TYPE) + warning ("`%D' should be initialized in the member initialization " + "list", + member); + if (init == void_type_node) + init = NULL_TREE; + + /* Get an lvalue for the data member. */ + decl = build_class_member_access_expr (current_class_ref, member, + /*access_path=*/NULL_TREE, + /*preserve_reference=*/true); if (decl == error_mark_node) return; @@ -273,11 +359,6 @@ perform_member_init (member, init, explicit) else if (TYPE_NEEDS_CONSTRUCTING (type) || (init && TYPE_HAS_CONSTRUCTOR (type))) { - /* 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_tree_list (NULL_TREE, init); - if (explicit && TREE_CODE (type) == ARRAY_TYPE && init != NULL_TREE @@ -285,7 +366,8 @@ perform_member_init (member, init, explicit) && TREE_CODE (TREE_TYPE (TREE_VALUE (init))) == ARRAY_TYPE) { /* Initialization of one array from another. */ - finish_expr_stmt (build_vec_init (decl, TREE_VALUE (init), 1)); + finish_expr_stmt (build_vec_init (decl, NULL_TREE, TREE_VALUE (init), + /* from_array=*/1)); } else finish_expr_stmt (build_aggr_init (decl, init, 0)); @@ -296,7 +378,7 @@ perform_member_init (member, init, explicit) { if (explicit) { - init = build_default_init (type); + init = build_default_init (type, /*nelts=*/NULL_TREE); if (TREE_CODE (type) == REFERENCE_TYPE) warning ("default-initialization of `%#D', which has reference type", @@ -327,13 +409,14 @@ perform_member_init (member, init, explicit) { tree expr; - expr = build_component_ref (current_class_ref, member, NULL_TREE, - explicit); + expr = build_class_member_access_expr (current_class_ref, member, + /*access_path=*/NULL_TREE, + /*preserve_reference=*/false); expr = build_delete (type, expr, sfk_complete_destructor, LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); if (expr != error_mark_node) - finish_subobject (expr); + finish_eh_cleanup (expr); } } @@ -357,7 +440,7 @@ build_field_list (t, list, uses_unions_p) 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) + if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields)) continue; /* Keep track of whether or not any fields are unions. */ @@ -384,79 +467,107 @@ build_field_list (t, list, uses_unions_p) 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. */ +/* The MEM_INITS are a TREE_LIST. The TREE_PURPOSE of each list gives + a FIELD_DECL or BINFO in T that needs initialization. The + TREE_VALUE gives the initializer, or list of initializer arguments. + + Return a TREE_LIST containing all of the initializations required + for T, in the order in which they should be performed. The output + list has the same format as the input. */ static tree -sort_member_init (t, member_init_list) - tree t; - tree member_init_list; +sort_mem_initializers (tree t, tree mem_inits) { - tree init_list; - tree last_field; tree init; + tree base; + tree sorted_inits; + tree next_subobject; + int i; 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) + /* Build up a list of initializations. The TREE_PURPOSE of entry + will be the subobject (a FIELD_DECL or BINFO) to initialize. The + TREE_VALUE will be the constructor arguments, or NULL if no + explicit initialization was provided. */ + sorted_inits = NULL_TREE; + /* Process the virtual bases. */ + for (base = CLASSTYPE_VBASECLASSES (t); base; base = TREE_CHAIN (base)) + sorted_inits = tree_cons (TREE_VALUE (base), NULL_TREE, sorted_inits); + /* Process the direct bases. */ + for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i) + { + base = BINFO_BASETYPE (TYPE_BINFO (t), i); + if (!TREE_VIA_VIRTUAL (base)) + sorted_inits = tree_cons (base, NULL_TREE, sorted_inits); + } + /* Process the non-static data members. */ + sorted_inits = build_field_list (t, sorted_inits, &uses_unions_p); + /* Reverse the entire list of initializations, so that they are in + the order that they will actually be performed. */ + sorted_inits = nreverse (sorted_inits); + + /* If the user presented the initializers in an order different from + that in which they will actually occur, we issue a warning. Keep + track of the next subobject which can be explicitly initialized + without issuing a warning. */ + next_subobject = sorted_inits; + + /* Go through the explicit initializers, filling in TREE_PURPOSE in + the SORTED_INITS. */ + for (init = mem_inits; init; init = TREE_CHAIN (init)) + { + tree subobject; + tree subobject_init; + + subobject = TREE_PURPOSE (init); + + /* If the explicit initializers are in sorted order, then + SUBOBJECT will be NEXT_SUBOBJECT, or something following + it. */ + for (subobject_init = next_subobject; + subobject_init; + subobject_init = TREE_CHAIN (subobject_init)) + if (TREE_PURPOSE (subobject_init) == subobject) break; - /* Give a warning, if appropriate. */ - if (warn_reorder && !f) + /* Issue a warning if the explicit initializer order does not + match that which will actually occur. */ + if (warn_reorder && !subobject_init) { - 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"); + if (TREE_CODE (TREE_PURPOSE (next_subobject)) == FIELD_DECL) + cp_warning_at ("`%D' will be initialized after", + TREE_PURPOSE (next_subobject)); + else + warning ("base `%T' will be initialized after", + TREE_PURPOSE (next_subobject)); + if (TREE_CODE (subobject) == FIELD_DECL) + cp_warning_at (" `%#D'", subobject); + else + warning (" base `%T'", subobject); } - /* Look again, from the beginning of the list. We must find the - field on this loop. */ - if (!f) + /* Look again, from the beginning of the list. */ + if (!subobject_init) { - f = init_list; - while (TREE_PURPOSE (f) != initialized_field) - f = TREE_CHAIN (f); + subobject_init = sorted_inits; + while (TREE_PURPOSE (subobject_init) != subobject) + subobject_init = TREE_CHAIN (subobject_init); } - - /* 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 + + /* It is invalid to initialize the same subobject more than + once. */ + if (TREE_VALUE (subobject_init)) { - /* Mark the field as explicitly initialized. */ - TREE_TYPE (f) = error_mark_node; - /* And insert the initializer. */ - TREE_VALUE (f) = TREE_VALUE (init); + if (TREE_CODE (subobject) == FIELD_DECL) + error ("multiple initializations given for `%D'", subobject); + else + error ("multiple initializations given for base `%T'", + subobject); } - /* Remember the location of the last explicitly initialized - field. */ - last_field = f; + /* Record the initialization. */ + TREE_VALUE (subobject_init) = TREE_VALUE (init); + next_subobject = subobject_init; } /* [class.base.init] @@ -466,15 +577,16 @@ sort_member_init (t, member_init_list) anonymous unions), the ctor-initializer is ill-formed. */ if (uses_unions_p) { - last_field = NULL_TREE; - for (init = init_list; init; init = TREE_CHAIN (init)) + tree last_field = NULL_TREE; + for (init = sorted_inits; init; init = TREE_CHAIN (init)) { tree field; tree field_type; int done; - /* Skip uninitialized members. */ - if (!TREE_TYPE (init)) + /* Skip uninitialized members and base classes. */ + if (!TREE_VALUE (init) + || TREE_CODE (TREE_PURPOSE (init)) != FIELD_DECL) continue; /* See if this field is a member of a union, or a member of a structure contained in a union, etc. */ @@ -541,231 +653,76 @@ sort_member_init (t, member_init_list) } } - return init_list; + return sorted_inits; } -/* 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, 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; - - int i; - tree x; - tree last; - - /* For warn_reorder. */ - int last_pos = 0; - tree last_base = NULL_TREE; - - tree rbases = NULL_TREE; - tree vbases = NULL_TREE; - - /* First walk through and splice out vbase and invalid initializers. - Also replace types with binfos. */ - - 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 = (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 (TREE_VIA_VIRTUAL (binfo)) - { - /* 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 - { - /* 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; - } - } - TREE_CHAIN (last) = NULL_TREE; - - /* Now walk through our regular bases and make sure they're initialized. */ - - 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; - - /* 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 == base_binfo && !init) - { - 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; - 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. */ - if (!init) - init = build_tree_list (NULL_TREE, NULL_TREE); - rbases = chainon (rbases, init); - } - - *rbase_ptr = rbases; - *vbase_ptr = vbases; -} - -/* Perform whatever initializations have yet to be done on the base - 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. */ +/* Initialize all bases and members of CURRENT_CLASS_TYPE. MEM_INITS + is a TREE_LIST giving the explicit mem-initializer-list for the + constructor. The TREE_PURPOSE of each entry is a subobject (a + FIELD_DECL or a BINFO) of the CURRENT_CLASS_TYPE. The TREE_VALUE + is a TREE_LIST giving the arguments to the constructor or + void_type_node for an empty list of arguments. */ void -emit_base_init (mem_init_list, base_init_list) - tree mem_init_list; - tree base_init_list; +emit_mem_initializers (tree mem_inits) { - tree member; - 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; - int n_baseclasses = BINFO_N_BASETYPES (t_binfo); - - 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. */ - if (TYPE_USES_VIRTUAL_BASECLASSES (t)) - { - tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl)); - construct_virtual_bases (t, current_class_ref, current_class_ptr, - vbase_init_list, first_arg); - } - - /* Now, perform initialization of non-virtual base classes. */ - for (i = 0; i < n_baseclasses; i++) - { - tree base_binfo = TREE_VEC_ELT (binfos, i); - tree init = void_list_node; + /* Sort the mem-initializers into the order in which the + initializations should be performed. */ + mem_inits = sort_mem_initializers (current_class_type, mem_inits); - if (TREE_VIA_VIRTUAL (base_binfo)) - continue; - - my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo, - 999); - - if (TREE_PURPOSE (rbase_init_list)) - init = TREE_VALUE (rbase_init_list); - else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo))) - { - init = NULL_TREE; - 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) + in_base_initializer = 1; + + /* Initialize base classes. */ + while (mem_inits + && TREE_CODE (TREE_PURPOSE (mem_inits)) != FIELD_DECL) + { + tree subobject = TREE_PURPOSE (mem_inits); + tree arguments = TREE_VALUE (mem_inits); + + /* If these initializations are taking place in a copy + constructor, the base class should probably be explicitly + initialized. */ + if (extra_warnings && !arguments + && DECL_COPY_CONSTRUCTOR_P (current_function_decl) + && TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (subobject))) + warning ("base class `%#T' should be explicitly initialized in the " + "copy constructor", + BINFO_TYPE (subobject)); + + /* If an explicit -- but empty -- initializer list was present, + treat it just like default initialization at this point. */ + if (arguments == void_type_node) + arguments = NULL_TREE; + + /* Initialize the base. */ + if (TREE_VIA_VIRTUAL (subobject)) + construct_virtual_base (subobject, arguments); + else { - 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), init, + tree base_addr; + + base_addr = build_base_path (PLUS_EXPR, current_class_ptr, + subobject, 1); + expand_aggr_init_1 (subobject, NULL_TREE, + build_indirect_ref (base_addr, NULL), + arguments, LOOKUP_NORMAL); + expand_cleanup_for_base (subobject, NULL_TREE); } - expand_cleanup_for_base (base_binfo, NULL_TREE); - rbase_init_list = TREE_CHAIN (rbase_init_list); + mem_inits = TREE_CHAIN (mem_inits); } + in_base_initializer = 0; - /* Initialize the vtable pointers for the class. */ + /* Initialize the vptrs. */ initialize_vtbl_ptrs (current_class_ptr); - - while (mem_init_list) + + /* Initialize the data members. */ + while (mem_inits) { - tree init; - tree member; - int from_init_list; - - member = TREE_PURPOSE (mem_init_list); - - /* See if we had a user-specified member initialization. */ - if (TREE_TYPE (mem_init_list)) - { - init = TREE_VALUE (mem_init_list); - from_init_list = 1; - } - else - { - 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) - warning ("`%D' should be initialized in the member initialization list", member); - } - - perform_member_init (member, init, from_init_list); - mem_init_list = TREE_CHAIN (mem_init_list); + perform_member_init (TREE_PURPOSE (mem_inits), + TREE_VALUE (mem_inits)); + mem_inits = TREE_CHAIN (mem_inits); } } @@ -862,7 +819,7 @@ expand_virtual_init (binfo, decl) /* If an exception is thrown in a constructor, those base classes already constructed must be destroyed. This function creates the cleanup for BINFO, which has just been constructed. If FLAG is non-NULL, - it is a DECL which is non-zero when this base needs to be + it is a DECL which is nonzero when this base needs to be destroyed. */ static void @@ -876,99 +833,70 @@ expand_cleanup_for_base (binfo, flag) return; /* Call the destructor. */ - expr = (build_scoped_method_call - (current_class_ref, binfo, base_dtor_identifier, NULL_TREE)); + expr = build_special_member_call (current_class_ref, + base_dtor_identifier, + NULL_TREE, + binfo, + LOOKUP_NORMAL | LOOKUP_NONVIRTUAL); if (flag) expr = fold (build (COND_EXPR, void_type_node, - truthvalue_conversion (flag), + c_common_truthvalue_conversion (flag), expr, integer_zero_node)); - finish_subobject (expr); + finish_eh_cleanup (expr); } -/* Subroutine of `expand_aggr_vbase_init'. - BINFO is the binfo of the type that is being initialized. - INIT_LIST is the list of initializers for the virtual baseclass. */ +/* Construct the virtual base-class VBASE passing the ARGUMENTS to its + constructor. */ static void -expand_aggr_vbase_init_1 (binfo, exp, addr, init_list) - tree binfo, exp, addr, init_list; +construct_virtual_base (tree vbase, tree arguments) { - tree init = purpose_member (binfo, init_list); - 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); -} - -/* 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 initializations for constructors to perform. */ - -static void -construct_virtual_bases (type, this_ref, this_ptr, init_list, flag) - tree type; - tree this_ref; - tree this_ptr; - tree init_list; - tree flag; -{ - tree vbases; - - /* If there are no virtual baseclasses, we shouldn't even be here. */ - my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621); - - /* Now, run through the baseclasses, initializing each. */ - for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; - vbases = TREE_CHAIN (vbases)) - { - 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 - period during which the cleanups must occur) begin from the time - the construction is complete to the end of the function. If we - create a conditional block in which to initialize the - base-classes, then the cleanup region for the virtual base begins - inside a block, and ends outside of that block. This situation - confuses the sjlj exception-handling code. Therefore, we do not - create a single conditional block, but one for each - initialization. (That way the cleanup regions always begin - in the outer block.) We trust the back-end to figure out - that the FLAG will not change across initializations, and - avoid doing multiple tests. */ - inner_if_stmt = begin_if_stmt (); - finish_if_stmt_cond (flag, inner_if_stmt); - compound_stmt = begin_compound_stmt (/*has_no_scope=*/1); - - /* 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 (vbase, flag); - } + tree inner_if_stmt; + tree compound_stmt; + tree exp; + tree flag; + + /* If there are virtual base classes with destructors, we need to + emit cleanups to destroy them if an exception is thrown during + the construction process. These exception regions (i.e., the + period during which the cleanups must occur) begin from the time + the construction is complete to the end of the function. If we + create a conditional block in which to initialize the + base-classes, then the cleanup region for the virtual base begins + inside a block, and ends outside of that block. This situation + confuses the sjlj exception-handling code. Therefore, we do not + create a single conditional block, but one for each + initialization. (That way the cleanup regions always begin + in the outer block.) We trust the back-end to figure out + that the FLAG will not change across initializations, and + avoid doing multiple tests. */ + flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl)); + inner_if_stmt = begin_if_stmt (); + finish_if_stmt_cond (flag, inner_if_stmt); + compound_stmt = begin_compound_stmt (/*has_no_scope=*/1); + + /* Compute the location of the virtual base. If we're + constructing virtual bases, then we must be the most derived + class. Therefore, we don't have to look up the virtual base; + we already know where it is. */ + exp = build (PLUS_EXPR, + TREE_TYPE (current_class_ptr), + current_class_ptr, + fold (build1 (NOP_EXPR, TREE_TYPE (current_class_ptr), + BINFO_OFFSET (vbase)))); + exp = build1 (NOP_EXPR, + build_pointer_type (BINFO_TYPE (vbase)), + exp); + exp = build1 (INDIRECT_REF, BINFO_TYPE (vbase), exp); + + expand_aggr_init_1 (vbase, current_class_ref, exp, + arguments, LOOKUP_COMPLAIN); + finish_compound_stmt (/*has_no_scope=*/1, compound_stmt); + finish_then_clause (inner_if_stmt); + finish_if_stmt (); + + expand_cleanup_for_base (vbase, flag); } /* Find the context in which this FIELD can be initialized. */ @@ -1017,46 +945,40 @@ member_init_ok_or_else (field, type, member_name) return 1; } -/* 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. +/* NAME is a FIELD_DECL, an IDENTIFIER_NODE which names a field, or it + is a _TYPE node or TYPE_DECL which names a base for that type. + Check the validity of NAME, and return either the base _TYPE, base + binfo, or the FIELD_DECL of the member. If NAME is invalid, return + NULL_TREE and issue a diagnostic. An old style unnamed direct single base construction is permitted, where NAME is NULL. */ tree -expand_member_init (exp, name, init) - tree exp, name, init; +expand_member_init (tree name) { - tree basetype = NULL_TREE, field; - tree type; + tree basetype; + tree field; - if (exp == NULL_TREE) + if (!current_class_ref) return NULL_TREE; - type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); - my_friendly_assert (IS_AGGR_TYPE (type), 20011113); - if (!name) { /* This is an obsolete unnamed base class initializer. The parser will already have warned about its use. */ - switch (CLASSTYPE_N_BASECLASSES (type)) + switch (CLASSTYPE_N_BASECLASSES (current_class_type)) { case 0: error ("unnamed initializer for `%T', which has no base classes", - type); + current_class_type); return NULL_TREE; case 1: - basetype = TYPE_BINFO_BASETYPE (type, 0); + basetype = TYPE_BINFO_BASETYPE (current_class_type, 0); break; default: error ("unnamed initializer for `%T', which uses multiple inheritance", - type); + current_class_type); return NULL_TREE; } } @@ -1067,47 +989,52 @@ expand_member_init (exp, name, init) } else if (TREE_CODE (name) == TYPE_DECL) basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name)); - - my_friendly_assert (init != NULL_TREE, 0); - - if (init == void_type_node) - init = NULL_TREE; + else + basetype = NULL_TREE; if (basetype) { + tree binfo; + 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 + return basetype; + + binfo = lookup_base (current_class_type, basetype, + ba_ignore, NULL); + if (binfo) { - if (TYPE_USES_VIRTUAL_BASECLASSES (type)) + if (TREE_VIA_VIRTUAL (binfo)) + binfo = binfo_for_vbase (basetype, current_class_type); + else if (BINFO_INHERITANCE_CHAIN (binfo) + != TYPE_BINFO (current_class_type)) + binfo = NULL_TREE; + } + if (!binfo) + { + if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) error ("type `%D' is not a direct or virtual base of `%T'", - name, type); + name, current_class_type); else error ("type `%D' is not a direct base of `%T'", - name, type); + name, current_class_type); return NULL_TREE; } - init = build_tree_list (basetype, init); + if (binfo) + return binfo; } else { if (TREE_CODE (name) == IDENTIFIER_NODE) - field = lookup_field (type, name, 1, 0); + field = lookup_field (current_class_type, name, 1, 0); else field = name; - if (! member_init_ok_or_else (field, type, name)) - return NULL_TREE; - - init = build_tree_list (field, init); + if (member_init_ok_or_else (field, current_class_type, name)) + return field; } - return init; + return NULL_TREE; } /* This is like `expand_member_init', only it stores one aggregate @@ -1131,8 +1058,6 @@ expand_member_init (exp, name, init) The virtual function table pointer cannot be set up here, because we do not really know its type. - Virtual baseclass pointers are also set up here. - This never calls operator=(). When initializing, nothing is CONST. @@ -1191,7 +1116,7 @@ build_aggr_init (exp, init, flags) TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type); if (itype && cp_type_quals (itype) != TYPE_UNQUALIFIED) TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype); - stmt_expr = build_vec_init (exp, init, + stmt_expr = build_vec_init (exp, NULL_TREE, init, init && same_type_p (TREE_TYPE (init), TREE_TYPE (exp))); TREE_READONLY (exp) = was_const; @@ -1221,6 +1146,24 @@ build_aggr_init (exp, init, flags) return stmt_expr; } +/* Like build_aggr_init, but not just for aggregates. */ + +tree +build_init (decl, init, flags) + tree decl, init; + int flags; +{ + tree expr; + + if (IS_AGGR_TYPE (TREE_TYPE (decl)) + || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + expr = build_aggr_init (decl, init, flags); + else + expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init); + + return expr; +} + static void expand_default_init (binfo, true_exp, exp, init, flags) tree binfo; @@ -1253,10 +1196,13 @@ 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 if (TREE_CODE (init) == CONSTRUCTOR + && TREE_HAS_CONSTRUCTOR (init)) + { + /* A brace-enclosed initializer for an aggregate. */ + my_friendly_assert (CP_AGGREGATE_TYPE_P (type), 20021016); + init = digest_init (type, init, (tree *)NULL); + } else init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags); @@ -1289,7 +1235,7 @@ expand_default_init (binfo, true_exp, exp, init, flags) else ctor_name = base_ctor_identifier; - rval = build_method_call (exp, ctor_name, parms, binfo, flags); + rval = build_special_member_call (exp, ctor_name, parms, binfo, flags); if (TREE_SIDE_EFFECTS (rval)) { if (building_stmt_tree ()) @@ -1329,6 +1275,7 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags) tree type = TREE_TYPE (exp); my_friendly_assert (init != error_mark_node && type != error_mark_node, 211); + my_friendly_assert (building_stmt_tree (), 20021010); /* Use a function returning the desired type to initialize EXP for us. If the function is a constructor, and its first argument is @@ -1343,12 +1290,7 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags) /* 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)) - { - if (!building_stmt_tree ()) - expand_decl_init (exp); - } - else + if (store_init_value (exp, init)) finish_expr_stmt (build (INIT_EXPR, type, exp, init)); return; } @@ -1438,6 +1380,7 @@ build_member_call (type, name, parmlist) { tree t; tree method_name; + tree fns; int dtor = 0; tree basetype_path, decl; @@ -1458,15 +1401,16 @@ build_member_call (type, name, parmlist) TREE_OPERAND (name, 0) = method_name; } my_friendly_assert (is_overloaded_fn (method_name), 980519); - return build_x_function_call (name, parmlist, current_class_ref); + return finish_call_expr (name, parmlist, /*disallow_virtual=*/true); } 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); + return finish_call_expr (lookup_namespace_name (type, name), + parmlist, + /*disallow_virtual=*/true); if (TREE_CODE (name) == TEMPLATE_ID_EXPR) { @@ -1493,10 +1437,9 @@ 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 finish_call_expr (lookup_namespace_name (ns, name), + parmlist, + /*disallow_virtual=*/true); } if (type == NULL_TREE || ! is_aggr_type (type, 1)) @@ -1515,30 +1458,34 @@ build_member_call (type, name, parmlist) decl = maybe_dummy_object (type, &basetype_path); + fns = lookup_fnfields (basetype_path, method_name, 0); + if (fns) + { + if (TREE_CODE (name) == TEMPLATE_ID_EXPR) + BASELINK_FUNCTIONS (fns) = build_nt (TEMPLATE_ID_EXPR, + BASELINK_FUNCTIONS (fns), + TREE_OPERAND (name, 1)); + return build_new_method_call (decl, fns, parmlist, + /*conversion_path=*/NULL_TREE, + LOOKUP_NORMAL|LOOKUP_NONVIRTUAL); + } + /* Convert 'this' to the specified type to disambiguate conversion to the function's context. */ if (decl == current_class_ref + /* ??? this is wrong, but if this conversion is invalid we need to + defer it until we know whether we are calling a static or + non-static member function. Be conservative for now. */ && ACCESSIBLY_UNIQUELY_DERIVED_P (type, current_class_type)) { - tree olddecl = current_class_ptr; - tree oldtype = TREE_TYPE (TREE_TYPE (olddecl)); - if (oldtype != type) - { - tree newtype = build_qualified_type (type, TYPE_QUALS (oldtype)); - decl = convert_force (build_pointer_type (newtype), olddecl, 0); - decl = build_indirect_ref (decl, NULL); - } + basetype_path = NULL_TREE; + decl = build_scoped_ref (decl, type, &basetype_path); + if (decl == error_mark_node) + return error_mark_node; } - if (method_name == constructor_name (type) - || method_name == constructor_name_full (type)) + if (constructor_name_p (method_name, type)) return build_functional_cast (type, parmlist); - if (lookup_fnfields (basetype_path, method_name, 0)) - return build_method_call (decl, - TREE_CODE (name) == TEMPLATE_ID_EXPR - ? name : method_name, - parmlist, basetype_path, - LOOKUP_NORMAL|LOOKUP_NONVIRTUAL); if (TREE_CODE (name) == IDENTIFIER_NODE && ((t = lookup_field (TYPE_BINFO (type), name, 1, 0)))) { @@ -1667,17 +1614,22 @@ build_offset_ref (type, name) decl = maybe_dummy_object (type, &basebinfo); - member = lookup_member (basebinfo, name, 1, 0); - - if (member == error_mark_node) - return error_mark_node; + if (BASELINK_P (name) || DECL_P (name)) + member = name; + else + { + member = lookup_member (basebinfo, name, 1, 0); + + if (member == error_mark_node) + return error_mark_node; + } /* 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. */ tree fnfields = member; - t = TREE_VALUE (fnfields); + t = BASELINK_FUNCTIONS (fnfields); if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR) { @@ -1702,7 +1654,7 @@ build_offset_ref (type, name) return t; } - if (!really_overloaded_fn (t)) + if (TREE_CODE (t) != TEMPLATE_ID_EXPR && !really_overloaded_fn (t)) { /* Get rid of a potential OVERLOAD around it */ t = OVL_CURRENT (t); @@ -1748,7 +1700,7 @@ build_offset_ref (type, name) if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t)) { - error ("illegal pointer to bit-field `%D'", t); + error ("invalid pointer to bit-field `%D'", t); return error_mark_node; } @@ -1814,7 +1766,7 @@ resolve_offset_ref (exp) || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE) { /* These were static members. */ - if (mark_addressable (member) == 0) + if (!cxx_mark_addressable (member)) return error_mark_node; return member; } @@ -1837,7 +1789,7 @@ resolve_offset_ref (exp) if (TREE_CODE (member) == FIELD_DECL && (base == current_class_ref || is_dummy_object (base))) { - tree binfo = TYPE_BINFO (current_class_type); + tree binfo = NULL_TREE; /* Try to get to basetype from 'this'; if that doesn't work, nothing will. */ @@ -1845,15 +1797,11 @@ resolve_offset_ref (exp) /* First convert to the intermediate base specified, if appropriate. */ if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE) - { - binfo = binfo_or_else (TYPE_OFFSET_BASETYPE (type), - current_class_type); - if (!binfo) - return error_mark_node; - base = build_base_path (PLUS_EXPR, base, binfo, 1); - } + base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type), &binfo); - return build_component_ref (base, member, binfo, 1); + return build_class_member_access_expr (base, member, + /*access_path=*/NULL_TREE, + /*preserve_reference=*/false); } /* Ensure that we have an object. */ @@ -2122,7 +2070,7 @@ build_new (placement, decl, init, use_global_new) return rval; } -/* Given a Java class, return a decl for the corresponding java.lang.Class. */ +/* Given a Java class, return a decl for the corresponding java.lang.Class. */ tree build_java_class_ref (type) @@ -2205,6 +2153,7 @@ build_new_1 (exp) tree placement, init; tree type, true_type, size, rval, t; tree full_type; + tree outer_nelts = NULL_TREE; tree nelts = NULL_TREE; tree alloc_call, alloc_expr, alloc_node; tree alloc_fn; @@ -2234,12 +2183,11 @@ build_new_1 (exp) if (TREE_CODE (type) == ARRAY_REF) { has_array = 1; - nelts = TREE_OPERAND (type, 1); + nelts = outer_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); + /* Use an incomplete array type to avoid VLA headaches. */ + full_type = build_cplus_array_type (type, NULL_TREE); } else full_type = type; @@ -2341,7 +2289,8 @@ build_new_1 (exp) args)); else alloc_call = build_method_call (build_dummy_object (true_type), - fnname, args, NULL_TREE, + fnname, args, + TYPE_BINFO (true_type), LOOKUP_NORMAL); } @@ -2423,17 +2372,21 @@ build_new_1 (exp) init_expr = build_indirect_ref (alloc_node, NULL); if (init == void_zero_node) - init = build_default_init (full_type); + init = build_default_init (full_type, nelts); 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); + init_expr + = build_vec_init (init_expr, + cp_build_binary_op (MINUS_EXPR, outer_nelts, + integer_one_node), + init, /*from_array=*/0); else if (TYPE_NEEDS_CONSTRUCTING (type)) - init_expr = build_method_call (init_expr, - complete_ctor_identifier, - init, TYPE_BINFO (true_type), - LOOKUP_NORMAL); + init_expr = build_special_member_call (init_expr, + complete_ctor_identifier, + init, TYPE_BINFO (true_type), + LOOKUP_NORMAL); else { /* We are processing something like `new int (10)', which @@ -2509,16 +2462,20 @@ build_new_1 (exp) 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 the allocation function returns null. Er, no, it wouldn't; + we just don't run the constructor. The standard says it's + unspecified whether or not the args are evaluated. */ if (cleanup) { tree end, sentry, begin; begin = get_target_expr (boolean_true_node); - sentry = TREE_OPERAND (begin, 0); + CLEANUP_EH_ONLY (begin) = 1; + + sentry = TARGET_EXPR_SLOT (begin); - TREE_OPERAND (begin, 2) + TARGET_EXPR_CLEANUP (begin) = build (COND_EXPR, void_type_node, sentry, cleanup, void_zero_node); @@ -2552,8 +2509,12 @@ build_new_1 (exp) { if (check_new) { - tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node, - integer_zero_node); + tree nullexp; + tree ifexp; + + nullexp = convert (TREE_TYPE (alloc_node), + use_cookie ? cookie_size : size_zero_node); + ifexp = cp_build_binary_op (NE_EXPR, alloc_node, nullexp); rval = build_conditional_expr (ifexp, rval, alloc_node); } @@ -2748,6 +2709,9 @@ get_temp_regvar (type, init) initialization of a vector of aggregate types. BASE is a reference to the vector, of ARRAY_TYPE. + MAXINDEX is the maximum index of the array (one less than the + number of elements). It is only used if + TYPE_DOMAIN (TREE_TYPE (BASE)) == NULL_TREE. INIT is the (possibly NULL) initializer. FROM_ARRAY is 0 if we should init everything with INIT @@ -2758,8 +2722,8 @@ get_temp_regvar (type, init) but use assignment instead of initialization. */ tree -build_vec_init (base, init, from_array) - tree base, init; +build_vec_init (base, maxindex, init, from_array) + tree base, init, maxindex; int from_array; { tree rval; @@ -2779,16 +2743,17 @@ build_vec_init (base, init, from_array) tree try_block = NULL_TREE; tree try_body = NULL_TREE; int num_initialized_elts = 0; - tree maxindex = array_type_nelts (TREE_TYPE (base)); - if (maxindex == error_mark_node) + if (TYPE_DOMAIN (atype)) + maxindex = array_type_nelts (atype); + + if (maxindex == NULL_TREE || maxindex == error_mark_node) return error_mark_node; - /* 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) + if (init + && (from_array == 2 + ? (!CLASS_TYPE_P (type) || !TYPE_HAS_COMPLEX_ASSIGN_REF (type)) + : !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. */ @@ -2801,7 +2766,6 @@ build_vec_init (base, init, from_array) 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; } @@ -2973,7 +2937,7 @@ build_vec_init (base, init, from_array) sorry ("cannot initialize multi-dimensional array with initializer"); elt_init = build_vec_init (build1 (INDIRECT_REF, type, base), - 0, 0); + 0, 0, 0); } else elt_init = build_aggr_init (build1 (INDIRECT_REF, type, base), @@ -3098,7 +3062,8 @@ build_dtor_call (exp, dtor_kind, flags) default: abort (); } - return build_method_call (exp, name, NULL_TREE, NULL_TREE, flags); + return build_method_call (exp, name, NULL_TREE, + TYPE_BINFO (TREE_TYPE (exp)), flags); } /* Generate a call to a destructor. TYPE is the type to cast ADDR to. @@ -3132,11 +3097,18 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) if (TREE_CODE (type) == POINTER_TYPE) { type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - if (!VOID_TYPE_P (type) && !complete_type_or_else (type, addr)) - return error_mark_node; if (TREE_CODE (type) == ARRAY_TYPE) goto handle_array; - if (! IS_AGGR_TYPE (type)) + + if (VOID_TYPE_P (type) + /* We don't want to warn about delete of void*, only other + incomplete types. Deleting other incomplete types + invokes undefined behavior, but it is not ill-formed, so + compile to something that would even do The Right Thing + (TM) should the type have a trivial dtor and no delete + operator. */ + || !complete_type_or_diagnostic (type, addr, 1) + || !IS_AGGR_TYPE (type)) { /* Call the builtin operator delete. */ return build_builtin_delete_call (addr); @@ -3150,8 +3122,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) else if (TREE_CODE (type) == ARRAY_TYPE) { handle_array: - if (TREE_SIDE_EFFECTS (addr)) - addr = save_expr (addr); + if (TYPE_DOMAIN (type) == NULL_TREE) { error ("unknown array size in delete"); @@ -3180,7 +3151,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) return void_zero_node; return build_op_delete_call - (DELETE_EXPR, addr, c_sizeof_nowarn (type), + (DELETE_EXPR, addr, cxx_sizeof_nowarn (type), LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL), NULL_TREE); } @@ -3198,7 +3169,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) { /* We will use ADDR multiple times so we must save it. */ addr = save_expr (addr); - /* Delete the object. */ + /* Delete the object. */ do_delete = build_builtin_delete_call (addr); /* Otherwise, treat this like a complete object destructor call. */ @@ -3215,7 +3186,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) /* Build the call. */ do_delete = build_op_delete_call (DELETE_EXPR, addr, - c_sizeof_nowarn (type), + cxx_sizeof_nowarn (type), LOOKUP_NORMAL, NULL_TREE); /* Call the complete object destructor. */ @@ -3226,7 +3197,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) { /* Make sure we have access to the member op delete, even though we'll actually be calling it from the destructor. */ - build_op_delete_call (DELETE_EXPR, addr, c_sizeof_nowarn (type), + build_op_delete_call (DELETE_EXPR, addr, cxx_sizeof_nowarn (type), LOOKUP_NORMAL, NULL_TREE); } @@ -3250,65 +3221,18 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) } } -/* At the end of a destructor, call the destructors for our base classes - and members. +/* At the beginning of a destructor, push cleanups that will call the + destructors for our base classes and members. - Called from finish_destructor_body. */ + Called from begin_destructor_body. */ void -perform_base_cleanups () +push_base_cleanups () { tree binfos; int i, n_baseclasses; tree member; tree expr; - tree member_destructions = NULL; - tree vbase_destructions = NULL; - - 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, 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); - if (!member_destructions) - member_destructions = expr; - else - member_destructions = build (COMPOUND_EXPR, - TREE_TYPE (member_destructions), - expr, - member_destructions); - } - } - if (member_destructions) - finish_expr_stmt (member_destructions); - - binfos = BINFO_BASETYPES (TYPE_BINFO (current_class_type)); - n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type); - - /* Take care of the remaining baseclasses. */ - for (i = n_baseclasses - 1; i >= 0; 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_expr_stmt (expr); - } /* Run destructors for all virtual baseclasses. */ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) @@ -3330,35 +3254,56 @@ perform_base_cleanups () if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (base_type)) { - 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_special_member_call (current_class_ref, + base_dtor_identifier, + NULL_TREE, + vbase, + (LOOKUP_NORMAL + | LOOKUP_NONVIRTUAL)); expr = build (COND_EXPR, void_type_node, cond, expr, void_zero_node); - if (!vbase_destructions) - vbase_destructions = expr; - else - vbase_destructions = build (COMPOUND_EXPR, - TREE_TYPE (vbase_destructions), - expr, - vbase_destructions); + finish_decl_cleanup (NULL_TREE, expr); } } } - if (vbase_destructions) - finish_expr_stmt (vbase_destructions); + + binfos = BINFO_BASETYPES (TYPE_BINFO (current_class_type)); + n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type); + + /* 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_special_member_call (current_class_ref, + base_dtor_identifier, + NULL_TREE, base_binfo, + LOOKUP_NORMAL | LOOKUP_NONVIRTUAL); + finish_decl_cleanup (NULL_TREE, expr); + } + + for (member = TYPE_FIELDS (current_class_type); member; + member = TREE_CHAIN (member)) + { + if (TREE_CODE (member) != FIELD_DECL || DECL_ARTIFICIAL (member)) + continue; + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member))) + { + tree this_member = (build_class_member_access_expr + (current_class_ref, member, + /*access_path=*/NULL_TREE, + /*preserve_reference=*/false)); + 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); + } + } } /* For type TYPE, delete the virtual baseclass objects of DECL. */ @@ -3419,15 +3364,13 @@ build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete) base = stabilize_reference (base); - /* Since we can use base many times, save_expr it. */ - if (TREE_SIDE_EFFECTS (base)) - base = save_expr (base); - if (TREE_CODE (type) == POINTER_TYPE) { /* Step back one from start of vector, and read dimension. */ tree cookie_addr; + if (TREE_SIDE_EFFECTS (base)) + base = save_expr (base); type = strip_array_types (TREE_TYPE (type)); cookie_addr = build (MINUS_EXPR, build_pointer_type (sizetype), @@ -3441,6 +3384,8 @@ build_vec_delete (base, maxindex, auto_delete_vec, use_global_delete) maxindex = array_type_nelts_total (type); type = strip_array_types (type); base = build_unary_op (ADDR_EXPR, base, 1); + if (TREE_SIDE_EFFECTS (base)) + base = save_expr (base); } else { |