/* Handle initialization things in C++.
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001 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.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
+along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "expr.h"
#include "output.h"
#include "except.h"
#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
if (building_stmt_tree ())
*compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
- /*
- else
- *compound_stmt_p = genrtl_begin_compound_stmt (has_no_scope=1);
- */
}
/* Finish out the statement-expression begun by the previous call to
finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
if (building_stmt_tree ())
- stmt_expr = finish_stmt_expr (stmt_expr);
+ {
+ stmt_expr = finish_stmt_expr (stmt_expr);
+ STMT_EXPR_NO_SCOPE (stmt_expr) = true;
+ }
else
stmt_expr = finish_global_stmt_expr (stmt_expr);
expand_virtual_init (binfo, base_ptr);
}
- SET_BINFO_MARKED (binfo);
+ BINFO_MARKED (binfo) = 1;
return NULL_TREE;
}
class. We do these in pre-order because can't find the virtual
bases for a class until we've initialized the vtbl for that
class. */
- dfs_walk_real (TYPE_BINFO (type), dfs_initialize_vtbl_ptrs,
- NULL, dfs_unmarked_real_bases_queue_p, list);
- dfs_walk (TYPE_BINFO (type), dfs_unmark,
- dfs_marked_real_bases_queue_p, type);
+ dfs_walk_real (TYPE_BINFO (type), dfs_initialize_vtbl_ptrs,
+ NULL, unmarkedp, list);
+ dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, type);
}
-/* [dcl.init]:
+/* 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. */
- To default-initialize an object of type T means:
+tree
+build_zero_init (tree type, tree nelts, bool static_storage_p)
+{
+ tree init = NULL_TREE;
- --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);
+ /* [dcl.init]
- --if T is an array type, each element is default-initialized;
+ To zero-initialization storage for an object of type T means:
- --otherwise, the storage for the object is zero-initialized.
+ -- if T is a scalar type, the storage is set to the value of zero
+ converted to T.
- A program that calls for default-initialization of an entity of refer-
- ence type is ill-formed. */
+ -- if T is a non-union class type, the storage for each nonstatic
+ data member and each base-class subobject is zero-initialized.
-static tree
-build_default_init (type)
- tree type;
-{
- tree init = NULL_TREE;
+ -- if T is a union type, the storage for its first data member is
+ zero-initialized.
- if (TYPE_NEEDS_CONSTRUCTING (type))
- /* Other code will handle running the default constructor. We can't do
- anything with a CONSTRUCTOR for arrays here, as that would imply
- copy-initialization. */
- return NULL_TREE;
- else if (AGGREGATE_TYPE_P (type) && !TYPE_PTRMEMFUNC_P (type))
+ -- if T is an array type, the storage for each element is
+ zero-initialized.
+
+ -- if T is a reference type, no initialization is performed. */
+
+ 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);
+ 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 ();
+
+ /* In all cases, the initializer is a constant. */
+ if (init)
+ TREE_CONSTANT (init) = 1;
- init = digest_init (type, init, 0);
return init;
}
-/* Subroutine of emit_base_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. */
+
+static tree
+build_default_init (type, nelts)
+ tree type;
+ tree nelts;
+{
+ /* [dcl.init]:
+
+ To default-initialize an object of type T means:
+
+ --if T is a non-POD class type (clause _class_), the default construc-
+ tor for T is called (and the initialization is ill-formed if T has
+ no accessible default constructor);
+
+ --if T is an array type, each element is default-initialized;
+
+ --otherwise, the storage for the object is zero-initialized.
+
+ A program that calls for default-initialization of an entity of refer-
+ ence type is ill-formed. */
+
+ /* 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].
+
+ 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))
+ 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);
+}
+
+/* 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;
- decl = build_component_ref (current_class_ref, member, NULL_TREE, explicit);
+ explicit = (init != NULL_TREE);
+ /* 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;
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
&& 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));
{
if (explicit)
{
- init = build_default_init (type);
+ init = build_default_init (type, /*nelts=*/NULL_TREE);
if (TREE_CODE (type) == REFERENCE_TYPE)
- cp_warning
+ warning
("default-initialization of `%#D', which has reference type",
member);
}
/* member traversal: note it leaves init NULL */
else if (TREE_CODE (type) == REFERENCE_TYPE)
- cp_pedwarn ("uninitialized reference member `%D'", member);
+ pedwarn ("uninitialized reference member `%D'", member);
}
else if (TREE_CODE (init) == TREE_LIST)
{
{
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);
}
}
{
tree fields;
+ *uses_unions_p = 0;
+
/* Note whether or not T is a union. */
if (TREE_CODE (t) == UNION_TYPE)
*uses_unions_p = 1;
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. */
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))
- cp_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]
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. */
if (same_type_p (last_field_type, field_type))
{
if (TREE_CODE (field_type) == UNION_TYPE)
- cp_error ("initializations for multiple members of `%T'",
+ error ("initializations for multiple members of `%T'",
last_field_type);
done = 1;
break;
}
}
- return init_list;
-}
-
-/* Like sort_member_init, but used for initializers of base classes.
- *RBASE_PTR is filled in with the initializers for non-virtual bases;
- vbase_ptr gets the virtual bases. */
-
-static void
-sort_base_init (t, 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)
- {
- cp_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;
+ return sorted_inits;
}
-/* 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;
-
- 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))
- cp_warning ("base class `%#T' should be explicitly initialized in the copy constructor",
- BINFO_TYPE (base_binfo));
- }
-
- if (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);
+
+ /* 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);
}
- /* 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)
- cp_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);
}
}
/* 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
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. */
{
if (field == error_mark_node)
return 0;
- if (field == NULL_TREE || initializing_context (field) != type)
+ if (!field)
{
- cp_error ("class `%T' does not have any field named `%D'", type,
- member_name);
+ error ("class `%T' does not have any field named `%D'", type,
+ member_name);
+ return 0;
+ }
+ if (TREE_CODE (field) == VAR_DECL)
+ {
+ error ("`%#D' is a static data member; it can only be "
+ "initialized at its definition",
+ field);
+ return 0;
+ }
+ if (TREE_CODE (field) != FIELD_DECL)
+ {
+ error ("`%#D' is not a non-static data member of `%T'",
+ field, type);
return 0;
}
- if (TREE_STATIC (field))
+ if (initializing_context (field) != type)
{
- cp_error ("field `%#D' is static; the only point of initialization is its definition",
- field);
+ error ("class `%T' does not have any field named `%D'", type,
+ member_name);
return 0;
}
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.
+ 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. 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 init)
{
- 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:
- cp_error ("unnamed initializer for `%T', which has no base classes",
- type);
+ error ("unnamed initializer for `%T', which has no base classes",
+ current_class_type);
return NULL_TREE;
case 1:
- basetype = TYPE_BINFO_BASETYPE (type, 0);
+ basetype = TYPE_BINFO_BASETYPE (current_class_type, 0);
break;
default:
- cp_error ("unnamed initializer for `%T', which uses multiple inheritance",
- type);
+ error ("unnamed initializer for `%T', which uses multiple inheritance",
+ current_class_type);
return NULL_TREE;
}
}
else if (TYPE_P (name))
{
- basetype = name;
+ basetype = TYPE_MAIN_VARIANT (name);
name = TYPE_NAME (name);
}
else if (TREE_CODE (name) == TYPE_DECL)
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
+ else
+ basetype = NULL_TREE;
my_friendly_assert (init != NULL_TREE, 0);
- if (init == void_type_node)
- init = 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 build_tree_list (basetype, init);
+
+ binfo = lookup_base (current_class_type, basetype,
+ ba_ignore, NULL);
+ if (!binfo || (!TREE_VIA_VIRTUAL (binfo)
+ && (BINFO_INHERITANCE_CHAIN (binfo)
+ != TYPE_BINFO (current_class_type))))
{
- if (TYPE_USES_VIRTUAL_BASECLASSES (type))
- cp_error ("type `%D' is not a direct or virtual base of `%T'",
- name, type);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ error ("type `%D' is not a direct or virtual base of `%T'",
+ name, current_class_type);
else
- cp_error ("type `%D' is not a direct base of `%T'",
- name, type);
+ error ("type `%D' is not a direct base of `%T'",
+ name, current_class_type);
return NULL_TREE;
}
-
- init = build_tree_list (basetype, init);
+ return build_tree_list (binfo, init);
}
else
{
- field = lookup_field (type, name, 1, 0);
-
- if (! member_init_ok_or_else (field, type, name))
- return NULL_TREE;
+ if (TREE_CODE (name) == IDENTIFIER_NODE)
+ field = lookup_field (current_class_type, name, 1, false);
+ else
+ field = name;
- init = build_tree_list (field, init);
+ if (member_init_ok_or_else (field, current_class_type, name))
+ return build_tree_list (field, init);
}
- return init;
+ return NULL_TREE;
}
/* This is like `expand_member_init', only it stores one aggregate
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.
COMPLEX zees(1.0, 0.0)[10];
}
*/
- cp_error ("bad array initializer");
+ error ("bad array initializer");
return error_mark_node;
}
if (cp_type_quals (type) != TYPE_UNQUALIFIED)
- {
- TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
- if (init)
- TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
- }
- stmt_expr = build_vec_init (exp, init,
+ 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, NULL_TREE, init,
init && same_type_p (TREE_TYPE (init),
TREE_TYPE (exp)));
TREE_READONLY (exp) = was_const;
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;
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);
- if (TREE_CODE (init) == TRY_CATCH_EXPR)
- /* We need to protect the initialization of a catch parm
- with a call to terminate(), which shows up as a TRY_CATCH_EXPR
+ if (TREE_CODE (init) == MUST_NOT_THROW_EXPR)
+ /* We need to protect the initialization of a catch parm with a
+ call to terminate(), which shows up as a MUST_NOT_THROW_EXPR
around the TARGET_EXPR for the copy constructor. See
- expand_start_catch_block. */
- TREE_OPERAND (init, 0) = build (INIT_EXPR, TREE_TYPE (exp), exp,
- TREE_OPERAND (init, 0));
+ initialize_handler_parm. */
+ {
+ TREE_OPERAND (init, 0) = build (INIT_EXPR, TREE_TYPE (exp), exp,
+ TREE_OPERAND (init, 0));
+ TREE_TYPE (init) = void_type_node;
+ }
else
init = build (INIT_EXPR, TREE_TYPE (exp), exp, init);
TREE_SIDE_EFFECTS (init) = 1;
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 ())
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
/* 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;
}
&& TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
{
if (or_else)
- cp_error ("`%T' is not an aggregate type", type);
+ error ("`%T' is not an aggregate type", type);
return 0;
}
return 1;
else
{
if (or_else)
- cp_error ("`%T' fails to be an aggregate typedef", name);
+ error ("`%T' fails to be an aggregate typedef", name);
return NULL_TREE;
}
&& TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
{
if (or_else)
- cp_error ("type `%T' is of non-aggregate type", type);
+ error ("type `%T' is of non-aggregate type", type);
return NULL_TREE;
}
return type;
{
tree t;
tree method_name;
+ tree fns;
int dtor = 0;
tree basetype_path, decl;
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)
{
{
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))
if (dtor)
{
- cp_error ("cannot call destructor `%T::~%T' without object", type,
+ error ("cannot call destructor `%T::~%T' without object", type,
method_name);
return error_mark_node;
}
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. Apparently Standard C++ says that we
- shouldn't do this. */
+ to the function's context. */
if (decl == current_class_ref
- && ! pedantic
+ /* ??? 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))))
+ && ((t = lookup_field (TYPE_BINFO (type), name, 1, false))))
{
if (t == error_mark_node)
return error_mark_node;
{
if (is_dummy_object (decl))
{
- cp_error ("invalid use of non-static field `%D'", t);
+ error ("invalid use of non-static field `%D'", t);
return error_mark_node;
}
decl = build (COMPONENT_REF, TREE_TYPE (t), decl, t);
decl = t;
else
{
- cp_error ("invalid use of member `%D'", t);
+ error ("invalid use of member `%D'", t);
return error_mark_node;
}
if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl)))
- return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, decl,
- parmlist, NULL_TREE);
+ return build_new_op (CALL_EXPR, LOOKUP_NORMAL, decl,
+ parmlist, NULL_TREE);
return build_function_call (decl, parmlist);
}
else
{
- cp_error ("no method `%T::%D'", type, name);
+ error ("no method `%T::%D'", type, name);
return error_mark_node;
}
}
if (TREE_CODE (name) == BIT_NOT_EXPR)
{
if (! check_dtor_name (type, name))
- cp_error ("qualified type `%T' does not match destructor name `~%T'",
+ error ("qualified type `%T' does not match destructor name `~%T'",
type, TREE_OPERAND (name, 0));
name = dtor_identifier;
}
if (!COMPLETE_TYPE_P (complete_type (type))
&& !TYPE_BEING_DEFINED (type))
{
- cp_error ("incomplete type `%T' does not have member `%D'", type,
+ error ("incomplete type `%T' does not have member `%D'", type,
name);
return error_mark_node;
}
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)
{
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);
if (t == NULL_TREE)
{
- cp_error ("`%D' is not a member of type `%T'", name, type);
+ error ("`%D' is not a member of type `%T'", name, type);
return error_mark_node;
}
if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t))
{
- cp_error ("illegal pointer to bit field `%D'", t);
+ error ("invalid pointer to bit-field `%D'", t);
return error_mark_node;
}
/* static class functions too. */
if (TREE_CODE (t) == FUNCTION_DECL
&& TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
- my_friendly_abort (53);
+ abort ();
/* In member functions, the form `type::name' is no longer
equivalent to `this->type::name', at least not until
|| 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;
}
if (TREE_CODE (member) == FIELD_DECL
&& (base == current_class_ref || is_dummy_object (base)))
{
- tree expr;
-
- basetype = DECL_CONTEXT (member);
+ tree binfo = NULL_TREE;
/* Try to get to basetype from 'this'; if that doesn't work,
nothing will. */
/* First convert to the intermediate base specified, if appropriate. */
if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
- base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type));
-
- /* Don't check access on the conversion; we might be after a member
- promoted by an access- or using-declaration, and we have already
- checked access for the member itself. */
- basetype = lookup_base (TREE_TYPE (base), basetype, ba_ignore, NULL);
- expr = build_base_path (PLUS_EXPR, base, basetype, 1);
+ base = build_scoped_ref (base, TYPE_OFFSET_BASETYPE (type), &binfo);
- if (expr == error_mark_node)
- return error_mark_node;
-
- expr = build (COMPONENT_REF, TREE_TYPE (member),
- expr, member);
- return convert_from_reference (expr);
+ return build_class_member_access_expr (base, member,
+ /*access_path=*/NULL_TREE,
+ /*preserve_reference=*/false);
}
/* Ensure that we have an object. */
{
if (addr == error_mark_node)
{
- cp_error ("object missing in `%E'", exp);
+ error ("object missing in `%E'", exp);
return error_mark_node;
}
member = cp_convert (ptrdiff_type_node, member);
- return build1 (INDIRECT_REF, type,
- build (PLUS_EXPR, build_pointer_type (type),
- addr, member));
+ addr = build (PLUS_EXPR, build_pointer_type (type), addr, member);
+ return build_indirect_ref (addr, 0);
}
else if (TYPE_PTRMEMFUNC_P (TREE_TYPE (member)))
{
return get_member_function_from_ptrfunc (&addr, member);
}
- my_friendly_abort (56);
+ abort ();
/* NOTREACHED */
return NULL_TREE;
}
nelts = integer_one_node;
if (absdcl && TREE_CODE (absdcl) == CALL_EXPR)
- my_friendly_abort (215);
+ abort ();
while (absdcl && TREE_CODE (absdcl) == INDIRECT_REF)
{
last_absdcl = absdcl;
else
{
if (build_expr_type_conversion (WANT_INT | WANT_ENUM,
- this_nelts, 0)
+ this_nelts, false)
== NULL_TREE)
pedwarn ("size in array new must have integral type");
else
t = type;
- rval = build_min_nt (NEW_EXPR, placement, t, init);
+ rval = build_min (NEW_EXPR, build_pointer_type (type),
+ placement, t, init);
NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
return rval;
}
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)
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;
tree cookie_expr, init_expr;
int has_array = 0;
enum tree_code code;
- int use_cookie, nothrow, check_new;
+ int nothrow, check_new;
/* Nonzero if the user wrote `::new' rather than just `new'. */
int globally_qualified_p;
- /* Nonzero if we're going to call a global operator new, rather than
- a class-specific version. */
- int use_global_new;
int use_java_new = 0;
/* If non-NULL, the number of extra bytes to allocate at the
beginning of the storage allocated for an array-new expression in
/* True if the function we are calling is a placement allocation
function. */
bool placement_allocation_fn_p;
+ tree args = NULL_TREE;
placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1);
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;
if (!complete_type_or_else (true_type, exp))
return error_mark_node;
- size = size_in_bytes (true_type);
- if (has_array)
- size = fold (cp_build_binary_op (MULT_EXPR, size, nelts));
-
if (TREE_CODE (true_type) == VOID_TYPE)
{
error ("invalid type `void' for new");
if (abstract_virtuals_error (NULL_TREE, true_type))
return error_mark_node;
- /* Figure out whether or not we're going to use the global operator
- new. */
- if (!globally_qualified_p
- && IS_AGGR_TYPE (true_type)
- && (has_array
- ? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
- : TYPE_HAS_NEW_OPERATOR (true_type)))
- use_global_new = 0;
- else
- use_global_new = 1;
-
- /* We only need cookies for arrays containing types for which we
- need cookies. */
- if (!has_array || !TYPE_VEC_NEW_USES_COOKIE (true_type))
- use_cookie = 0;
- /* When using placement new, users may not realize that they need
- the extra storage. We require that the operator called be
- the global placement operator delete[]. */
- else if (placement && !TREE_CHAIN (placement)
- && same_type_p (TREE_TYPE (TREE_VALUE (placement)),
- ptr_type_node))
- use_cookie = !use_global_new;
- /* Otherwise, we need the cookie. */
- else
- use_cookie = 1;
-
- /* Compute the number of extra bytes to allocate, now that we know
- whether or not we need the cookie. */
- if (use_cookie)
- {
- cookie_size = get_cookie_size (true_type);
- size = size_binop (PLUS_EXPR, size, cookie_size);
- }
+ size = size_in_bytes (true_type);
+ if (has_array)
+ size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
/* Allocate the object. */
-
if (! placement && TYPE_FOR_JAVA (true_type))
{
tree class_addr, alloc_decl;
else
{
tree fnname;
- tree args;
- args = tree_cons (NULL_TREE, size, placement);
fnname = ansi_opname (code);
- if (use_global_new)
- alloc_call = (build_new_function_call
- (lookup_function_nonclass (fnname, args),
- args));
+ if (!globally_qualified_p
+ && CLASS_TYPE_P (true_type)
+ && (has_array
+ ? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
+ : TYPE_HAS_NEW_OPERATOR (true_type)))
+ {
+ /* Use a class-specific operator new. */
+ /* If a cookie is required, add some extra space. */
+ if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
+ {
+ cookie_size = get_cookie_size (true_type);
+ size = size_binop (PLUS_EXPR, size, cookie_size);
+ }
+ /* Create the argument list. */
+ args = tree_cons (NULL_TREE, size, placement);
+ /* Call the function. */
+ alloc_call = build_method_call (build_dummy_object (true_type),
+ fnname, args,
+ TYPE_BINFO (true_type),
+ LOOKUP_NORMAL);
+ }
else
- alloc_call = build_method_call (build_dummy_object (true_type),
- fnname, args, NULL_TREE,
- LOOKUP_NORMAL);
+ {
+ /* Use a global operator new. */
+ /* See if a cookie might be required. */
+ if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
+ cookie_size = get_cookie_size (true_type);
+ else
+ cookie_size = NULL_TREE;
+
+ alloc_call = build_operator_new_call (fnname, placement,
+ &size, &cookie_size);
+ }
}
if (alloc_call == error_mark_node)
return error_mark_node;
- /* The ALLOC_CALL should be a CALL_EXPR, and the first operand
- should be the address of a known FUNCTION_DECL. */
- my_friendly_assert (TREE_CODE (alloc_call) == CALL_EXPR, 20000521);
- t = TREE_OPERAND (alloc_call, 0);
- my_friendly_assert (TREE_CODE (t) == ADDR_EXPR, 20000521);
- t = TREE_OPERAND (t, 0);
- my_friendly_assert (TREE_CODE (t) == FUNCTION_DECL, 20000521);
+ /* The ALLOC_CALL should be a CALL_EXPR -- or a COMPOUND_EXPR whose
+ right-hand-side is ultimately a CALL_EXPR -- and the first
+ operand should be the address of a known FUNCTION_DECL. */
+ t = alloc_call;
+ while (TREE_CODE (t) == COMPOUND_EXPR)
+ t = TREE_OPERAND (t, 1);
+ alloc_fn = get_callee_fndecl (t);
+ my_friendly_assert (alloc_fn != NULL_TREE, 20020325);
+
/* Now, check to see if this function is actually a placement
allocation function. This can happen even when PLACEMENT is NULL
because we might have something like:
one argument, or there are variable arguments, then this is a
placement allocation function. */
placement_allocation_fn_p
- = (type_num_arguments (TREE_TYPE (t)) > 1 || varargs_function_p (t));
+ = (type_num_arguments (TREE_TYPE (alloc_fn)) > 1
+ || varargs_function_p (alloc_fn));
/* unless an allocation function is declared with an empty excep-
tion-specification (_except.spec_), throw(), it indicates failure to
So check for a null exception spec on the op new we just called. */
- /* The ADDR_EXPR. */
- t = TREE_OPERAND (alloc_call, 0);
- /* The function. */
- t = TREE_OPERAND (t, 0);
- nothrow = TYPE_NOTHROW_P (TREE_TYPE (t));
+ nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
check_new = (flag_check_new || nothrow) && ! use_java_new;
alloc_expr = alloc_call;
- if (use_cookie)
+ if (cookie_size)
/* Adjust so we're pointing to the start of the object. */
alloc_expr = build (PLUS_EXPR, TREE_TYPE (alloc_expr),
alloc_expr, cookie_size);
alloc_node = TREE_OPERAND (alloc_expr, 0);
/* Now initialize the cookie. */
- if (use_cookie)
+ if (cookie_size)
{
tree cookie;
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)
- cp_pedwarn ("ISO C++ forbids initialization in array new");
+ 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
tree cleanup;
int flags = (LOOKUP_NORMAL
| (globally_qualified_p * LOOKUP_GLOBAL));
+ tree delete_node;
+
+ if (cookie_size)
+ /* Subtract the padding back out to get to the pointer returned
+ from operator new. */
+ delete_node = fold (build (MINUS_EXPR, TREE_TYPE (alloc_node),
+ alloc_node, cookie_size));
+ else
+ delete_node = alloc_node;
/* The Standard is unclear here, but the right thing to do
is to use the same method for finding deallocation
functions that we use for finding allocation functions. */
flags |= LOOKUP_SPECULATIVELY;
- cleanup = build_op_delete_call (dcode, alloc_node, size, flags,
+ cleanup = build_op_delete_call (dcode, delete_node, size, flags,
(placement_allocation_fn_p
? alloc_call : NULL_TREE));
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.
+
+ FIXME FIXME FIXME inline invisible refs as refs. That way we
+ can preevaluate value parameters. */
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);
}
}
else if (CP_TYPE_CONST_P (true_type))
- cp_error ("uninitialized const in `new' of `%#T'", true_type);
+ error ("uninitialized const in `new' of `%#T'", true_type);
/* Now build up the return value in reverse order. */
This is also the containing expression returned by this function. */
tree controller = NULL_TREE;
+ /* We should only have 1-D arrays here. */
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ abort ();
+
if (! IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
{
loop = integer_zero_node;
if (controller)
{
TREE_OPERAND (controller, 1) = body;
- return controller;
+ body = controller;
}
- else
- return cp_convert (void_type_node, body);
+
+ if (TREE_CODE (base) == SAVE_EXPR)
+ /* Pre-evaluate the SAVE_EXPR outside of the BIND_EXPR. */
+ body = build (COMPOUND_EXPR, void_type_node, base, body);
+
+ return cp_convert (void_type_node, body);
}
/* Create an unnamed variable of the indicated TYPE. */
decl = create_temporary_var (type);
if (building_stmt_tree ())
add_decl_stmt (decl);
- if (!building_stmt_tree ())
+ else
SET_DECL_RTL (decl, assign_temp (type, 2, 0, 1));
finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, 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
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;
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. */
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;
}
T* rval = t1;
ptrdiff_t iterator = maxindex;
try {
- do {
+ for (; iterator != -1; --iterator) {
... initialize *t1 ...
++t1;
- } while (--iterator != -1);
+ }
} catch (...) {
... destroy elements that were constructed ...
}
{
/* If the ITERATOR is equal to -1, then we don't have to loop;
we've already initialized all the elements. */
- tree if_stmt;
- tree do_stmt;
- tree do_body;
+ tree for_stmt;
+ tree for_body;
tree elt_init;
- if_stmt = begin_if_stmt ();
- finish_if_stmt_cond (build (NE_EXPR, boolean_type_node,
- iterator, integer_minus_one_node),
- if_stmt);
+ for_stmt = begin_for_stmt ();
+ finish_for_init_stmt (for_stmt);
+ finish_for_cond (build (NE_EXPR, boolean_type_node,
+ iterator, integer_minus_one_node),
+ for_stmt);
+ finish_for_expr (build_unary_op (PREDECREMENT_EXPR, iterator, 0),
+ for_stmt);
/* Otherwise, loop through the elements. */
- do_stmt = begin_do_stmt ();
- do_body = begin_compound_stmt (/*has_no_scope=*/1);
+ for_body = begin_compound_stmt (/*has_no_scope=*/1);
/* When we're not building a statement-tree, things are a little
complicated. If, when we recursively call build_aggr_init,
else if (from)
elt_init = build_modify_expr (to, NOP_EXPR, from);
else
- my_friendly_abort (57);
+ abort ();
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
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),
if (base2)
finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base2, 0));
- finish_compound_stmt (/*has_no_scope=*/1, do_body);
- finish_do_body (do_stmt);
- finish_do_stmt (build (NE_EXPR, boolean_type_node,
- build_unary_op (PREDECREMENT_EXPR, iterator, 0),
- integer_minus_one_node),
- do_stmt);
-
- finish_then_clause (if_stmt);
- finish_if_stmt ();
+ finish_compound_stmt (/*has_no_scope=*/1, for_body);
+ finish_for_stmt (for_stmt);
}
/* Make sure to cleanup any partially constructed elements. */
&& from_array != 2)
{
tree e;
+ tree m = cp_build_binary_op (MINUS_EXPR, maxindex, iterator);
+
+ /* Flatten multi-dimensional array since build_vec_delete only
+ expects one-dimensional array. */
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ m = cp_build_binary_op (MULT_EXPR, m,
+ array_type_nelts_total (type));
+ type = strip_array_types (type);
+ }
finish_compound_stmt (/*has_no_scope=*/1, try_body);
finish_cleanup_try_block (try_block);
- e = build_vec_delete_1 (rval,
- cp_build_binary_op (MINUS_EXPR, maxindex,
- iterator),
+ e = build_vec_delete_1 (rval, m,
type,
sfk_base_destructor,
/*use_global_delete=*/0);
break;
default:
- my_friendly_abort (20000524);
+ 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.
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);
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");
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);
}
{
/* 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. */
/* 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. */
auto_delete = sfk_complete_destructor;
}
+ else if (auto_delete == sfk_deleting_destructor
+ && TYPE_GETS_REG_DELETE (type))
+ {
+ /* 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, cxx_sizeof_nowarn (type),
+ LOOKUP_NORMAL, NULL_TREE);
+ }
expr = build_dtor_call (build_indirect_ref (addr, NULL),
auto_delete, flags);
/* At the beginning of a destructor, push cleanups that will call the
destructors for our base classes and members.
- Called from setup_vtbl_ptr. */
+ Called from begin_destructor_body. */
void
push_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);
finish_decl_cleanup (NULL_TREE, expr);
|| TREE_VIA_VIRTUAL (base_binfo))
continue;
- expr = build_scoped_method_call (current_class_ref, base_binfo,
- base_dtor_identifier,
- NULL_TREE);
-
+ 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)
+ if (TREE_CODE (member) != FIELD_DECL || DECL_ARTIFICIAL (member))
continue;
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
{
- tree this_member = (build_component_ref
- (current_class_ref, DECL_NAME (member),
- NULL_TREE, 0));
+ tree this_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,
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),
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
{