summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cp/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/cp/init.c')
-rw-r--r--contrib/gcc/cp/init.c1259
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
{
OpenPOWER on IntegriCloud