/* Handle initialization things in C++.
- Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-98, 1999 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
#include "expr.h"
#include "toplev.h"
-extern void compiler_error ();
-
/* In C++, structures with well-defined constructors are initialized by
those constructors, unasked. CURRENT_BASE_INIT_LIST
holds a list of stmts for a BASE_INIT term in the grammar.
static void expand_aggr_vbase_init_1 PROTO((tree, tree, tree, tree));
static void expand_aggr_vbase_init PROTO((tree, tree, tree, tree));
-static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int,
- int));
-static void expand_default_init PROTO((tree, tree, tree, tree, int,
- int));
+static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int));
+static void expand_default_init PROTO((tree, tree, tree, tree, int));
static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, tree,
int));
static void perform_member_init PROTO((tree, tree, tree, int));
static void sort_base_init PROTO((tree, tree *, tree *));
-static tree build_builtin_call PROTO((tree, tree, tree));
-static tree build_array_eh_cleanup PROTO((tree, tree, tree));
-static int member_init_ok_or_else PROTO((tree, tree, char *));
+static tree build_builtin_delete_call PROTO((tree));
+static int member_init_ok_or_else PROTO((tree, tree, const char *));
static void expand_virtual_init PROTO((tree, tree));
static tree sort_member_init PROTO((tree));
static tree build_partial_cleanup_for PROTO((tree));
static tree initializing_context PROTO((tree));
-
-/* Cache _builtin_new and _builtin_delete exprs. */
-static tree BIN, BID, BIVN, BIVD;
+static void expand_vec_init_try_block PROTO((tree));
+static void expand_vec_init_catch_clause PROTO((tree, tree, tree, tree));
+static tree build_java_class_ref PROTO((tree));
/* Cache the identifier nodes for the magic field of a new cookie. */
static tree nc_nelts_field_id;
{
tree fields[1];
- /* Define implicit `operator new' and `operator delete' functions. */
- BIN = default_conversion (get_first_fn (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) NEW_EXPR])));
- TREE_USED (TREE_OPERAND (BIN, 0)) = 0;
- BID = default_conversion (get_first_fn (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) DELETE_EXPR])));
- TREE_USED (TREE_OPERAND (BID, 0)) = 0;
- BIVN = default_conversion (get_first_fn (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) VEC_NEW_EXPR])));
- TREE_USED (TREE_OPERAND (BIVN, 0)) = 0;
- BIVD = default_conversion (get_first_fn (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) VEC_DELETE_EXPR])));
- TREE_USED (TREE_OPERAND (BIVD, 0)) = 0;
minus_one = build_int_2 (-1, -1);
/* Define the structure that holds header information for
array_type_nelts (type), TREE_VALUE (init), 1);
}
else
- expand_aggr_init (decl, init, 0, 0);
+ expand_aggr_init (decl, init, 0);
}
else
{
{
if (explicit)
{
- cp_error ("incomplete initializer for member `%D' of class `%T' which has no constructor",
- member, current_class_type);
- init = error_mark_node;
+ /* default-initialization. */
+ if (AGGREGATE_TYPE_P (type))
+ init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ cp_error ("default-initialization of `%#D', which has reference type",
+ member);
+ init = error_mark_node;
+ }
+ else
+ init = integer_zero_node;
}
/* member traversal: note it leaves init NULL */
else if (TREE_CODE (TREE_TYPE (member)) == REFERENCE_TYPE)
current_member_init_list. */
if (init || explicit)
{
- decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
+ decl = build_component_ref (current_class_ref, name, NULL_TREE,
+ explicit);
expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
}
push_obstacks_nochange ();
resume_temporary_allocation ();
- expr = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
+ expr = build_component_ref (current_class_ref, name, NULL_TREE,
+ explicit);
expr = build_delete (type, expr, integer_zero_node,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
-#if 0 /* Once unsharing happens soon enough. */
- my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo, 999);
-#else
- BINFO_INHERITANCE_CHAIN (base_binfo) = t_binfo;
-#endif
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo,
+ 999);
if (TREE_PURPOSE (rbase_init_list))
init = TREE_VALUE (rbase_init_list);
member = convert_pointer_to_real (base_binfo, current_class_ptr);
expand_aggr_init_1 (base_binfo, NULL_TREE,
build_indirect_ref (member, NULL_PTR), init,
- BINFO_OFFSET_ZEROP (base_binfo), LOOKUP_NORMAL);
+ LOOKUP_NORMAL);
expand_end_target_temps ();
free_temp_slots ();
if (init)
init = TREE_VALUE (init);
/* Call constructors, but don't set up vtables. */
- expand_aggr_init_1 (binfo, exp, ref, init, 0, LOOKUP_COMPLAIN);
+ expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
expand_end_target_temps ();
free_temp_slots ();
}
}
-/* Subroutine to perform parser actions for member initialization.
- S_ID is the scoped identifier.
- NAME is the name of the member.
- INIT is the initializer, or `void_type_node' if none. */
-
-void
-do_member_init (s_id, name, init)
- tree s_id, name, init;
-{
- tree binfo, base;
-
- if (current_class_type == NULL_TREE
- || ! is_aggr_typedef (s_id, 1))
- return;
- binfo = get_binfo (IDENTIFIER_TYPE_VALUE (s_id),
- current_class_type, 1);
- if (binfo == error_mark_node)
- return;
- if (binfo == 0)
- {
- error_not_base_type (IDENTIFIER_TYPE_VALUE (s_id), current_class_type);
- return;
- }
-
- base = convert_pointer_to (binfo, current_class_ptr);
- expand_member_init (build_indirect_ref (base, NULL_PTR), name, init);
-}
-
/* Find the context in which this FIELD can be initialized. */
static tree
/* Anonymous union members can be initialized in the first enclosing
non-anonymous union context. */
- while (t && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
+ while (t && ANON_UNION_TYPE_P (t))
t = TYPE_CONTEXT (t);
return t;
}
member_init_ok_or_else (field, type, member_name)
tree field;
tree type;
- char *member_name;
+ const char *member_name;
{
if (field == error_mark_node)
return 0;
expand_member_init (exp, name, init)
tree exp, name, init;
{
- extern tree ptr_type_node; /* should be in tree.h */
-
tree basetype = NULL_TREE, field;
- tree parm;
- tree rval = NULL_TREE, type;
+ tree type;
if (exp == NULL_TREE)
return; /* complain about this later */
if (name && TREE_CODE (name) == TYPE_DECL)
{
- basetype = TREE_TYPE (name);
+ basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
name = DECL_NAME (name);
}
return;
}
- if (init)
- {
- /* The grammar should not allow fields which have names
- that are TYPENAMEs. Therefore, if the field has
- a non-NULL TREE_TYPE, we may assume that this is an
- attempt to initialize a base class member of the current
- type. Otherwise, it is an attempt to initialize a
- member field. */
+ my_friendly_assert (init != NULL_TREE, 0);
- if (init == void_type_node)
- init = NULL_TREE;
+ /* The grammar should not allow fields which have names that are
+ TYPENAMEs. Therefore, if the field has a non-NULL TREE_TYPE, we
+ may assume that this is an attempt to initialize a base class
+ member of the current type. Otherwise, it is an attempt to
+ initialize a member field. */
- if (name == NULL_TREE || basetype)
- {
- tree base_init;
+ if (init == void_type_node)
+ init = NULL_TREE;
- if (name == NULL_TREE)
- {
-#if 0
- if (basetype)
- name = TYPE_IDENTIFIER (basetype);
- else
- {
- error ("no base class to initialize");
- return;
- }
-#endif
- }
- else if (basetype != type
- && ! current_template_parms
- && ! vec_binfo_member (basetype,
- TYPE_BINFO_BASETYPES (type))
- && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
- {
- if (IDENTIFIER_CLASS_VALUE (name))
- goto try_member;
- if (TYPE_USES_VIRTUAL_BASECLASSES (type))
- cp_error ("type `%T' is not an immediate or virtual basetype for `%T'",
- basetype, type);
- else
- cp_error ("type `%T' is not an immediate basetype for `%T'",
- basetype, type);
- return;
- }
+ if (name == NULL_TREE || basetype)
+ {
+ tree base_init;
- if (purpose_member (basetype, current_base_init_list))
+ if (name == NULL_TREE)
+ {
+#if 0
+ if (basetype)
+ name = TYPE_IDENTIFIER (basetype);
+ else
{
- cp_error ("base class `%T' already initialized", basetype);
+ error ("no base class to initialize");
return;
}
-
- if (warn_reorder && current_member_init_list)
- {
- cp_warning ("base initializer for `%T'", basetype);
- warning (" will be re-ordered to precede member initializations");
- }
-
- base_init = build_tree_list (basetype, init);
- current_base_init_list = chainon (current_base_init_list, base_init);
+#endif
}
- else
+ else if (basetype != type
+ && ! current_template_parms
+ && ! vec_binfo_member (basetype,
+ TYPE_BINFO_BASETYPES (type))
+ && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
{
- tree member_init;
-
- try_member:
- field = lookup_field (type, name, 1, 0);
-
- if (! member_init_ok_or_else (field, type, IDENTIFIER_POINTER (name)))
- return;
-
- if (purpose_member (name, current_member_init_list))
- {
- cp_error ("field `%D' already initialized", field);
- return;
- }
-
- member_init = build_tree_list (name, init);
- current_member_init_list = chainon (current_member_init_list, member_init);
+ if (IDENTIFIER_CLASS_VALUE (name))
+ goto try_member;
+ if (TYPE_USES_VIRTUAL_BASECLASSES (type))
+ cp_error ("type `%T' is not an immediate or virtual basetype for `%T'",
+ basetype, type);
+ else
+ cp_error ("type `%T' is not an immediate basetype for `%T'",
+ basetype, type);
+ return;
}
- return;
- }
- else if (name == NULL_TREE)
- {
- compiler_error ("expand_member_init: name == NULL_TREE");
- return;
- }
-
- basetype = type;
- field = lookup_field (basetype, name, 0, 0);
-
- if (! member_init_ok_or_else (field, basetype, IDENTIFIER_POINTER (name)))
- return;
-
- /* now see if there is a constructor for this type
- which will take these args. */
-
- if (TYPE_HAS_CONSTRUCTOR (TREE_TYPE (field)))
- {
- tree parmtypes, fndecl;
- if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
+ if (purpose_member (basetype, current_base_init_list))
{
- /* just know that we've seen something for this node */
- DECL_INITIAL (exp) = error_mark_node;
- TREE_USED (exp) = 1;
+ cp_error ("base class `%T' already initialized", basetype);
+ return;
}
- type = TYPE_MAIN_VARIANT (TREE_TYPE (field));
- parm = build_component_ref (exp, name, NULL_TREE, 0);
- /* Now get to the constructors. */
- fndecl = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0);
+ if (warn_reorder && current_member_init_list)
+ {
+ cp_warning ("base initializer for `%T'", basetype);
+ warning (" will be re-ordered to precede member initializations");
+ }
- if (fndecl)
- my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 209);
+ base_init = build_tree_list (basetype, init);
+ current_base_init_list = chainon (current_base_init_list, base_init);
+ }
+ else
+ {
+ tree member_init;
- parmtypes = NULL_TREE;
- fndecl = NULL_TREE;
+ try_member:
+ field = lookup_field (type, name, 1, 0);
- init = convert_arguments (parm, parmtypes, NULL_TREE, fndecl, LOOKUP_NORMAL);
- if (init == NULL_TREE || TREE_TYPE (init) != error_mark_node)
- rval = build_method_call (NULL_TREE, ctor_identifier, init,
- TYPE_BINFO (type), LOOKUP_NORMAL);
- else
+ if (! member_init_ok_or_else (field, type, IDENTIFIER_POINTER (name)))
return;
- if (rval != error_mark_node)
+ if (purpose_member (name, current_member_init_list))
{
- /* Now, fill in the first parm with our guy */
- TREE_VALUE (TREE_OPERAND (rval, 1))
- = build_unary_op (ADDR_EXPR, parm, 0);
- TREE_TYPE (rval) = ptr_type_node;
- TREE_SIDE_EFFECTS (rval) = 1;
+ cp_error ("field `%D' already initialized", field);
+ return;
}
- }
- else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field)))
- {
- parm = build_component_ref (exp, name, NULL_TREE, 0);
- expand_aggr_init (parm, NULL_TREE, 0, 0);
- rval = error_mark_node;
- }
- /* Now initialize the member. It does not have to
- be of aggregate type to receive initialization. */
- if (rval != error_mark_node)
- expand_expr_stmt (rval);
+ member_init = build_tree_list (name, init);
+ current_member_init_list = chainon (current_member_init_list, member_init);
+ }
}
/* This is like `expand_member_init', only it stores one aggregate
perform the initialization, but not both, as it would be ambiguous. */
void
-expand_aggr_init (exp, init, alias_this, flags)
+expand_aggr_init (exp, init, flags)
tree exp, init;
- int alias_this;
int flags;
{
tree type = TREE_TYPE (exp);
/* Must arrange to initialize each element of EXP
from elements of INIT. */
tree itype = init ? TREE_TYPE (init) : NULL_TREE;
- if (TYPE_READONLY (TREE_TYPE (type)) || TYPE_VOLATILE (TREE_TYPE (type)))
+ if (CP_TYPE_QUALS (type) != TYPE_UNQUALIFIED)
{
TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
if (init)
return;
}
expand_vec_init (exp, exp, array_type_nelts (type), init,
- init && comptypes (TREE_TYPE (init), TREE_TYPE (exp), 1));
+ init && same_type_p (TREE_TYPE (init),
+ TREE_TYPE (exp)));
TREE_READONLY (exp) = was_const;
TREE_THIS_VOLATILE (exp) = was_volatile;
TREE_TYPE (exp) = type;
TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
- init, alias_this, LOOKUP_NORMAL|flags);
+ init, LOOKUP_NORMAL|flags);
TREE_TYPE (exp) = type;
TREE_READONLY (exp) = was_const;
TREE_THIS_VOLATILE (exp) = was_volatile;
}
static void
-expand_default_init (binfo, true_exp, exp, init, alias_this, flags)
+expand_default_init (binfo, true_exp, exp, init, flags)
tree binfo;
tree true_exp, exp;
tree init;
- int alias_this;
int flags;
{
tree type = TREE_TYPE (exp);
if (true_exp != exp)
abort ();
- /* We special-case TARGET_EXPRs here to avoid an error about
- private copy constructors for temporaries bound to reference vars.
- If the TARGET_EXPR represents a call to a function that has
- permission to create such objects, a reference can bind directly
- to the return value. An object variable must be initialized
- via the copy constructor, even if the call is elided. */
- if (! (TREE_CODE (exp) == VAR_DECL && DECL_ARTIFICIAL (exp)
- && TREE_CODE (init) == TARGET_EXPR && TREE_TYPE (init) == type))
+ if (flags & DIRECT_BIND)
+ /* Do nothing. We hit this in two cases: Reference initialization,
+ where we aren't initializing a real variable, so we don't want
+ 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
init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
if (TREE_CODE (init) == TRY_CATCH_EXPR)
rval = build_method_call (exp, ctor_identifier,
parms, binfo, flags);
- expand_expr_stmt (rval);
+ if (TREE_SIDE_EFFECTS (rval))
+ expand_expr_stmt (rval);
}
/* This function is responsible for initializing EXP with INIT
its description. */
static void
-expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
+expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
tree binfo;
tree true_exp, exp;
tree init;
- int alias_this;
int flags;
{
tree type = TREE_TYPE (exp);
/* We know that expand_default_init can handle everything we want
at this point. */
- expand_default_init (binfo, true_exp, exp, init, alias_this, flags);
+ expand_default_init (binfo, true_exp, exp, init, flags);
}
/* Report an error if NAME is not the name of a user-defined,
tree t;
tree method_name;
int dtor = 0;
- int dont_use_this = 0;
tree basetype_path, decl;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR
if (TREE_CODE (name) != TEMPLATE_ID_EXPR)
method_name = name;
else
- method_name = TREE_OPERAND (name, 0);
+ {
+ method_name = TREE_OPERAND (name, 0);
+ if (is_overloaded_fn (method_name))
+ method_name = DECL_NAME (OVL_CURRENT (method_name));
+ }
if (TREE_CODE (method_name) == BIT_NOT_EXPR)
{
return error_mark_node;
}
- /* No object? Then just fake one up, and let build_method_call
- figure out what to do. */
- if (current_class_type == 0
- || get_base_distance (type, current_class_type, 0, &basetype_path) == -1)
- dont_use_this = 1;
+ decl = maybe_dummy_object (type, &basetype_path);
- if (dont_use_this)
- {
- basetype_path = TYPE_BINFO (type);
- decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
- }
- else if (current_class_ptr == 0)
- {
- dont_use_this = 1;
- decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
- }
- else
+ /* Convert 'this' to the specified type to disambiguate conversion
+ to the function's context. Apparently Standard C++ says that we
+ shouldn't do this. */
+ if (decl == current_class_ref
+ && ! pedantic
+ && 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_type_variant (type, TYPE_READONLY (oldtype),
- TYPE_VOLATILE (oldtype));
+ tree newtype = build_qualified_type (type, TYPE_QUALS (oldtype));
decl = convert_force (build_pointer_type (newtype), olddecl, 0);
+ decl = build_indirect_ref (decl, NULL_PTR);
}
- else
- decl = olddecl;
}
- decl = build_indirect_ref (decl, NULL_PTR);
-
if (method_name == constructor_name (type)
|| method_name == constructor_name_full (type))
return build_functional_cast (type, parmlist);
return error_mark_node;
if (TREE_CODE (t) == FIELD_DECL)
{
- if (dont_use_this)
+ if (is_dummy_object (decl))
{
cp_error ("invalid use of non-static field `%D'", t);
return error_mark_node;
build_offset_ref (type, name)
tree type, name;
{
- tree decl, fnfields, fields, t = error_mark_node;
+ tree decl, t = error_mark_node;
+ tree member;
tree basebinfo = NULL_TREE;
- int dtor = 0;
+ tree orig_name = name;
/* class templates can come in as TEMPLATE_DECLs here. */
- if (TREE_CODE (name) != IDENTIFIER_NODE)
+ if (TREE_CODE (name) == TEMPLATE_DECL)
return name;
if (type == std_node)
/* Handle namespace names fully here. */
if (TREE_CODE (type) == NAMESPACE_DECL)
- return lookup_namespace_name (type, name);
+ {
+ t = lookup_namespace_name (type, name);
+ if (t != error_mark_node && ! type_unknown_p (t))
+ {
+ mark_used (t);
+ t = convert_from_reference (t);
+ }
+ return t;
+ }
if (type == NULL_TREE || ! is_aggr_type (type, 1))
return error_mark_node;
- if (TREE_CODE (name) == BIT_NOT_EXPR)
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
{
- dtor = 1;
- name = TREE_OPERAND (name, 0);
- }
+ /* If the NAME is a TEMPLATE_ID_EXPR, we are looking at
+ something like `a.template f<int>' or the like. For the most
+ part, we treat this just like a.f. We do remember, however,
+ the template-id that was used. */
+ name = TREE_OPERAND (orig_name, 0);
- if (name == constructor_name_full (type))
- name = constructor_name (type);
+ if (TREE_CODE (name) == LOOKUP_EXPR)
+ /* This can happen during tsubst'ing. */
+ name = TREE_OPERAND (name, 0);
- if (TYPE_SIZE (complete_type (type)) == 0)
- {
- if (type == current_class_type)
- t = IDENTIFIER_CLASS_VALUE (name);
- else
- t = NULL_TREE;
- if (t == 0)
- {
- cp_error ("incomplete type `%T' does not have member `%D'", type,
- name);
- return error_mark_node;
- }
- if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == VAR_DECL
- || TREE_CODE (t) == CONST_DECL)
- {
- mark_used (t);
- return t;
- }
- if (TREE_CODE (t) == FIELD_DECL)
- sorry ("use of member in incomplete aggregate type");
- else if (TREE_CODE (t) == FUNCTION_DECL)
- sorry ("use of member function in incomplete aggregate type");
- else
- my_friendly_abort (52);
- return error_mark_node;
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 0);
}
- if (current_class_type == 0
- || get_base_distance (type, current_class_type, 0, &basebinfo) == -1)
+ if (TREE_CODE (name) == BIT_NOT_EXPR)
{
- basebinfo = TYPE_BINFO (type);
- decl = build1 (NOP_EXPR, type, error_mark_node);
+ if (! check_dtor_name (type, name))
+ cp_error ("qualified type `%T' does not match destructor name `~%T'",
+ type, TREE_OPERAND (name, 0));
+ name = dtor_identifier;
}
- else if (current_class_ptr == 0)
- decl = build1 (NOP_EXPR, type, error_mark_node);
- else
- decl = current_class_ref;
+#if 0
+ /* I think this is wrong, but the draft is unclear. --jason 6/15/98 */
+ else if (name == constructor_name_full (type)
+ || name == constructor_name (type))
+ name = ctor_identifier;
+#endif
- if (constructor_name (BINFO_TYPE (basebinfo)) == name)
+ if (TYPE_SIZE (complete_type (type)) == 0
+ && !TYPE_BEING_DEFINED (type))
{
- if (dtor)
- name = dtor_identifier;
- else
- name = ctor_identifier;
+ cp_error ("incomplete type `%T' does not have member `%D'", type,
+ name);
+ return error_mark_node;
}
- else
- if (dtor)
- my_friendly_abort (999);
-
- fnfields = lookup_fnfields (basebinfo, name, 1);
- fields = lookup_field (basebinfo, name, 0, 0);
+ decl = maybe_dummy_object (type, &basebinfo);
+
+ member = lookup_member (basebinfo, name, 1, 0);
- if (fields == error_mark_node || fnfields == error_mark_node)
+ if (member == error_mark_node)
return error_mark_node;
/* A lot of this logic is now handled in lookup_field and
lookup_fnfield. */
- if (fnfields)
+ if (member && TREE_CODE (member) == TREE_LIST)
{
- extern int flag_save_memoized_contexts;
- basebinfo = TREE_PURPOSE (fnfields);
-
/* Go from the TREE_BASELINK to the member function info. */
+ tree fnfields = member;
t = TREE_VALUE (fnfields);
- if (!really_overloaded_fn (t))
+ if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
{
- tree access;
+ /* The FNFIELDS are going to contain functions that aren't
+ necessarily templates, and templates that don't
+ necessarily match the explicit template parameters. We
+ save all the functions, and the explicit parameters, and
+ then figure out exactly what to instantiate with what
+ arguments in instantiate_type. */
+
+ if (TREE_CODE (t) != OVERLOAD)
+ /* The code in instantiate_type which will process this
+ expects to encounter OVERLOADs, not raw functions. */
+ t = ovl_cons (t, NULL_TREE);
+
+ return build (OFFSET_REF,
+ build_offset_type (type, unknown_type_node),
+ decl,
+ build (TEMPLATE_ID_EXPR,
+ TREE_TYPE (t),
+ t,
+ TREE_OPERAND (orig_name, 1)));
+ }
+ if (!really_overloaded_fn (t))
+ {
/* Get rid of a potential OVERLOAD around it */
t = OVL_CURRENT (t);
/* unique functions are handled easily. */
- access = compute_access (basebinfo, t);
- if (access == access_protected_node)
- {
- cp_error_at ("member function `%#D' is protected", t);
- error ("in this context");
- return error_mark_node;
- }
- if (access == access_private_node)
- {
- cp_error_at ("member function `%#D' is private", t);
- error ("in this context");
- return error_mark_node;
- }
+ basebinfo = TREE_PURPOSE (fnfields);
+ if (!enforce_access (basebinfo, t))
+ return error_mark_node;
mark_used (t);
+ if (DECL_STATIC_FUNCTION_P (t))
+ return t;
return build (OFFSET_REF, TREE_TYPE (t), decl, t);
}
/* FNFIELDS is most likely allocated on the search_obstack,
which will go away after this class scope. If we need
- to save this value for later (either for memoization
- or for use as an initializer for a static variable), then
- do so here.
+ to save this value for later (i.e. for use as an initializer
+ for a static variable), then do so here.
??? The smart thing to do for the case of saving initializers
is to resolve them before we're done with this scope. */
if (!TREE_PERMANENT (fnfields)
- && ((flag_save_memoized_contexts && toplevel_bindings_p ())
- || ! allocation_temporary_p ()))
+ && ! allocation_temporary_p ())
fnfields = copy_list (fnfields);
t = build_tree_list (error_mark_node, fnfields);
return t;
}
- /* Now that we know we are looking for a field, see if we
- have access to that field. Lookup_field will give us the
- error message. */
-
- t = lookup_field (basebinfo, name, 1, 0);
-
- if (t == error_mark_node)
- return error_mark_node;
+ t = member;
if (t == NULL_TREE)
{
return convert_from_reference (t);
}
- if (TREE_CODE (t) == FIELD_DECL && DECL_BIT_FIELD (t))
+ if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t))
{
cp_error ("illegal pointer to bit field `%D'", t);
return error_mark_node;
}
if ((TREE_CODE (member) == VAR_DECL
- && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member)))
+ && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member))
+ && ! TYPE_PTRMEM_P (TREE_TYPE (member)))
|| TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (member)) == METHOD_TYPE)
{
/* The first case is really just a reference to a member of `this'. */
if (TREE_CODE (member) == FIELD_DECL
- && (base == current_class_ref
- || (TREE_CODE (base) == NOP_EXPR
- && TREE_OPERAND (base, 0) == error_mark_node)))
+ && (base == current_class_ref || is_dummy_object (base)))
{
- tree basetype_path, access;
+ tree basetype_path;
+ tree expr;
if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
basetype = TYPE_OFFSET_BASETYPE (type);
}
/* Kludge: we need to use basetype_path now, because
convert_pointer_to will bash it. */
- access = compute_access (basetype_path, member);
+ enforce_access (basetype_path, member);
addr = convert_pointer_to (basetype, base);
- if (access == access_public_node)
- return build (COMPONENT_REF, TREE_TYPE (member),
- build_indirect_ref (addr, NULL_PTR), member);
- if (access == access_protected_node)
- {
- cp_error_at ("member `%D' is protected", member);
- error ("in this context");
- return error_mark_node;
- }
- if (access == access_private_node)
- {
- cp_error_at ("member `%D' is private", member);
- error ("in this context");
- return error_mark_node;
- }
- my_friendly_abort (55);
+
+ /* Even in the case of illegal access, we form the
+ COMPONENT_REF; that will allow better error recovery than
+ just feeding back error_mark_node. */
+ expr = build (COMPONENT_REF, TREE_TYPE (member),
+ build_indirect_ref (addr, NULL_PTR), member);
+ return convert_from_reference (expr);
}
/* Ensure that we have an object. */
- if (TREE_CODE (base) == NOP_EXPR
- && TREE_OPERAND (base, 0) == error_mark_node)
+ if (is_dummy_object (base))
addr = error_mark_node;
else
- {
- /* If this is a reference to a member function, then return the
- address of the member function (which may involve going
- through the object's vtable), otherwise, return an expression
- for the dereferenced pointer-to-member construct. */
- addr = build_unary_op (ADDR_EXPR, base, 0);
- }
+ /* If this is a reference to a member function, then return the
+ address of the member function (which may involve going
+ through the object's vtable), otherwise, return an expression
+ for the dereferenced pointer-to-member construct. */
+ addr = build_unary_op (ADDR_EXPR, base, 0);
- if (TREE_CODE (TREE_TYPE (member)) == OFFSET_TYPE)
+ if (TYPE_PTRMEM_P (TREE_TYPE (member)))
{
if (addr == error_mark_node)
{
return error_mark_node;
}
- basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (member));
+ basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member)));
addr = convert_pointer_to (basetype, addr);
- member = cp_convert (ptrdiff_type_node,
- build_unary_op (ADDR_EXPR, member, 0));
+ member = cp_convert (ptrdiff_type_node, member);
/* Pointer to data members are offset by one, so that a null
pointer with a real value of 0 is distinguishable from an
tree decl;
{
if (! TREE_THIS_VOLATILE (decl)
-#if 0
- /* These may be necessary for C, but they break C++. */
- ! TREE_PUBLIC (decl)
- /* Don't change a variable array bound or initial value to a constant
- in a place where a variable is invalid. */
- && ! pedantic
-#endif /* 0 */
- && DECL_INITIAL (decl) != 0
+ && DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node
/* This is invalid if initial value is not constant.
If it has either a function call, a memory reference,
or a variable, then re-evaluating it could give different results. */
&& TREE_CONSTANT (DECL_INITIAL (decl))
/* Check for cases where this is sub-optimal, even though valid. */
- && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR
-#if 0
- /* We must allow this to work outside of functions so that
- static constants can be used for array sizes. */
- && current_function_decl != 0
- && DECL_MODE (decl) != BLKmode
-#endif
- )
+ && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR)
return DECL_INITIAL (decl);
return decl;
}
\f
/* Common subroutines of build_new and build_vec_delete. */
-/* Common interface for calling "builtin" functions that are not
- really builtin. */
+/* Call the global __builtin_delete to delete ADDR. */
static tree
-build_builtin_call (type, node, arglist)
- tree type;
- tree node;
- tree arglist;
+build_builtin_delete_call (addr)
+ tree addr;
{
- tree rval = build (CALL_EXPR, type, node, arglist, NULL_TREE);
- TREE_SIDE_EFFECTS (rval) = 1;
- assemble_external (TREE_OPERAND (node, 0));
- TREE_USED (TREE_OPERAND (node, 0)) = 1;
- return rval;
+ mark_used (global_delete_fndecl);
+ return build_call (global_delete_fndecl,
+ void_type_node, build_expr_list (NULL_TREE, addr));
}
\f
/* Generate a C++ "new" expression. DECL is either a TREE_LIST
}
else
{
+ int flags = pedantic ? WANT_INT : (WANT_INT | WANT_ENUM);
+ if (build_expr_type_conversion (flags, this_nelts, 0)
+ == NULL_TREE)
+ pedwarn ("size in array new must have integral type");
+
this_nelts = save_expr (cp_convert (sizetype, this_nelts));
absdcl = TREE_OPERAND (absdcl, 0);
if (this_nelts == integer_zero_node)
return rval;
}
+/* If non-NULL, a POINTER_TYPE equivalent to (java::lang::Class*). */
+
+static tree jclass_node = NULL_TREE;
+
+/* Given a Java class, return a decl for the corresponding java.lang.Class. */
+
+static tree
+build_java_class_ref (type)
+ tree type;
+{
+ tree name, class_decl;
+ static tree CL_prefix = NULL_TREE;
+ if (CL_prefix == NULL_TREE)
+ CL_prefix = get_identifier("_CL_");
+ if (jclass_node == NULL_TREE)
+ {
+ jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier("jclass"));
+ if (jclass_node == NULL_TREE)
+ fatal("call to Java constructor, while `jclass' undefined");
+ jclass_node = TREE_TYPE (jclass_node);
+ }
+ name = build_overload_with_type (CL_prefix, type);
+ class_decl = IDENTIFIER_GLOBAL_VALUE (name);
+ if (class_decl == NULL_TREE)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ class_decl = build_decl (VAR_DECL, name, TREE_TYPE (jclass_node));
+ TREE_STATIC (class_decl) = 1;
+ DECL_EXTERNAL (class_decl) = 1;
+ TREE_PUBLIC (class_decl) = 1;
+ DECL_ARTIFICIAL (class_decl) = 1;
+ DECL_IGNORED_P (class_decl) = 1;
+ pushdecl_top_level (class_decl);
+ make_decl_rtl (class_decl, NULL_PTR, 1);
+ pop_obstacks ();
+ }
+ return class_decl;
+}
+
/* Called from cplus_expand_expr when expanding a NEW_EXPR. The return
value is immediately handed to expand_expr. */
enum tree_code code = NEW_EXPR;
int use_cookie, nothrow, check_new;
int use_global_new;
+ int use_java_new = 0;
placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1);
}
true_type = type;
- if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
+ if (CP_TYPE_QUALS (type))
type = TYPE_MAIN_VARIANT (type);
/* If our base type is an array, then make sure we know how many elements
true_type = TREE_TYPE (true_type);
}
- if (TYPE_SIZE (complete_type (true_type)) == 0)
- {
- incomplete_type_error (0, true_type);
- return error_mark_node;
- }
+ if (!complete_type_or_else (true_type, exp))
+ return error_mark_node;
if (has_array)
size = fold (build_binary_op (MULT_EXPR, size_in_bytes (true_type),
else
size = size_in_bytes (type);
- if (true_type == void_type_node)
+ if (TREE_CODE (true_type) == VOID_TYPE)
{
error ("invalid type `void' for new");
return error_mark_node;
return error_mark_node;
}
}
+ else if (! placement && TYPE_FOR_JAVA (true_type))
+ {
+ tree class_addr, alloc_decl;
+ tree class_decl = build_java_class_ref (true_type);
+ tree class_size = size_in_bytes (true_type);
+ static char alloc_name[] = "_Jv_AllocObject";
+ use_java_new = 1;
+ alloc_decl = IDENTIFIER_GLOBAL_VALUE (get_identifier (alloc_name));
+ if (alloc_decl == NULL_TREE)
+ fatal("call to Java constructor, while `%s' undefined", alloc_name);
+ class_addr = build1 (ADDR_EXPR, jclass_node, class_decl);
+ rval = build_function_call (alloc_decl,
+ tree_cons (NULL_TREE, class_addr,
+ build_tree_list (NULL_TREE,
+ class_size)));
+ rval = cp_convert (build_pointer_type (true_type), rval);
+ }
else
{
- int susp;
+ int susp = 0;
if (flag_exceptions)
/* We will use RVAL when generating an exception handler for
if (t && TREE_VALUE (t) == NULL_TREE)
nothrow = 1;
}
- check_new = flag_check_new || nothrow;
+ check_new = (flag_check_new || nothrow) && ! use_java_new;
if ((check_new || flag_exceptions) && rval)
{
if (! TYPE_NEEDS_CONSTRUCTING (type)
&& ! IS_AGGR_TYPE (type) && ! has_array)
{
- /* New 2.0 interpretation: `new int (10)' means
- allocate an int, and initialize it with 10. */
+ /* We are processing something like `new int (10)', which
+ means allocate an int, and initialize it with 10. */
tree deref;
+ tree deref_type;
+ /* At present RVAL is a temporary variable, created to hold
+ the value from the call to `operator new'. We transform
+ it to (*RVAL = INIT, RVAL). */
rval = save_expr (rval);
deref = build_indirect_ref (rval, NULL_PTR);
+
+ /* Even for something like `new const int (10)' we must
+ allow the expression to be non-const while we do the
+ initialization. */
+ deref_type = TREE_TYPE (deref);
+ if (CP_TYPE_CONST_P (deref_type))
+ TREE_TYPE (deref)
+ = cp_build_qualified_type (deref_type,
+ CP_TYPE_QUALS (deref_type)
+ & ~TYPE_QUAL_CONST);
TREE_READONLY (deref) = 0;
if (TREE_CHAIN (init) != NULL_TREE)
flags |= LOOKUP_HAS_IN_CHARGE;
}
+ if (use_java_new)
+ rval = save_expr (rval);
newrval = rval;
if (newrval && TREE_CODE (TREE_TYPE (newrval)) == POINTER_TYPE)
if (newrval == NULL_TREE || newrval == error_mark_node)
return error_mark_node;
+ /* Java constructors compiled by jc1 do not return this. */
+ if (use_java_new)
+ newrval = build (COMPOUND_EXPR, TREE_TYPE (newrval),
+ newrval, rval);
rval = newrval;
TREE_HAS_CONSTRUCTOR (rval) = 1;
}
an exception and the new-expression does not contain a
new-placement, then the deallocation function is called to free
the memory in which the object was being constructed. */
- if (flag_exceptions && alloc_expr)
+ if (flag_exceptions && alloc_expr && ! use_java_new)
{
enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
- tree cleanup;
+ tree cleanup, fn = NULL_TREE;
int flags = LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL);
/* All cleanups must last longer than normal. */
int yes = suspend_momentary ();
if (placement)
- flags |= LOOKUP_SPECULATIVELY;
+ {
+ flags |= LOOKUP_SPECULATIVELY;
+
+ /* We expect alloc_expr to look like a TARGET_EXPR around
+ a NOP_EXPR around the CALL_EXPR we want. */
+ fn = TREE_OPERAND (alloc_expr, 1);
+ fn = TREE_OPERAND (fn, 0);
+ }
/* Copy size to the saveable obstack. */
size = copy_node (size);
- /* If we have a new-placement, we need to pass the alloc TARGET_EXPR
- to build_op_delete_call so it can extract the args. */
- cleanup = build_op_delete_call
- (dcode, placement ? alloc_expr : alloc_node, size, flags);
+ cleanup = build_op_delete_call (dcode, alloc_node, size, flags, fn);
resume_momentary (yes);
if (cleanup)
{
-#if 0
- /* Disable this until flow is fixed so that it doesn't
- think the initialization of sentry is a dead write. */
tree end, sentry, begin, buf, t = TREE_TYPE (rval);
begin = get_target_expr (boolean_true_node);
rval = build (COMPOUND_EXPR, t, begin,
build (COMPOUND_EXPR, t, rval,
build (COMPOUND_EXPR, t, end, buf)));
-#else
- /* FIXME: this is a workaround for a crash due to overlapping
- exception regions. Cleanups shouldn't really happen here. */
- rval = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (rval), rval);
-
- rval = build (TRY_CATCH_EXPR, TREE_TYPE (rval), rval, cleanup);
- rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
-#endif
}
}
}
- else if (TYPE_READONLY (true_type))
+ else if (CP_TYPE_CONST_P (true_type))
cp_error ("uninitialized const in `new' of `%#T'", true_type);
done:
/* This is the real size */
virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
body = build_expr_list (NULL_TREE,
- build_x_delete (ptype, base_tbd,
+ build_x_delete (base_tbd,
2 | use_global_delete,
virtual_size));
body = build (COND_EXPR, void_type_node,
no_destructor:
/* If the delete flag is one, or anything else with the low bit set,
delete the storage. */
- if (auto_delete_vec == integer_zero_node
- || auto_delete_vec == integer_two_node)
+ if (auto_delete_vec == integer_zero_node)
deallocate_expr = integer_zero_node;
else
{
/* True size with header. */
virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
}
- deallocate_expr = build_x_delete (ptype, base_tbd,
+ deallocate_expr = build_x_delete (base_tbd,
2 | use_global_delete,
virtual_size);
if (auto_delete_vec != integer_one_node)
return cp_convert (void_type_node, body);
}
-/* Build a tree to cleanup partially built arrays.
- BASE is that starting address of the array.
- COUNT is the count of objects that have been built, that need destroying.
- TYPE is the type of elements in the array. */
+/* Protect the vector initialization with a try-block so that we can
+ destroy the first few elements if constructing a later element
+ causes an exception to be thrown. TYPE is the type of the array
+ elements. */
-static tree
-build_array_eh_cleanup (base, count, type)
- tree base, count, type;
+static void
+expand_vec_init_try_block (type)
+ tree type;
+{
+ if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions)
+ return;
+
+ /* The code we generate looks like:
+
+ try {
+ // Initialize the vector.
+ } catch (...) {
+ // Destory the elements that need destroying.
+ throw;
+ }
+
+ Here we're just beginning the `try'. */
+
+ expand_eh_region_start ();
+}
+
+/* Add code to destroy the array elements constructed so far if the
+ construction of some element in the array causes an exception to be
+ thrown. RVAL is the address of the last element in the array.
+ TYPE is the type of the array elements. MAXINDEX is the maximum
+ allowable index into the array. ITERATOR is an integer variable
+ indicating how many elements remain to be constructed. */
+
+static void
+expand_vec_init_catch_clause (rval, type, maxindex, iterator)
+ tree rval;
+ tree type;
+ tree maxindex;
+ tree iterator;
{
- tree expr = build_vec_delete_1 (base, count, type, integer_two_node,
- integer_zero_node, 0);
- return expr;
+ tree e;
+ tree cleanup;
+
+ if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions)
+ return;
+
+ /* We have to ensure that this can live to the cleanup expansion
+ time, since we know it is only ever needed once, generate code
+ now. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+
+ cleanup = make_node (RTL_EXPR);
+ TREE_TYPE (cleanup) = void_type_node;
+ RTL_EXPR_RTL (cleanup) = const0_rtx;
+ TREE_SIDE_EFFECTS (cleanup) = 1;
+ do_pending_stack_adjust ();
+ start_sequence_for_rtl_expr (cleanup);
+
+ e = build_vec_delete_1 (rval,
+ build_binary_op (MINUS_EXPR, maxindex,
+ iterator, 1),
+ type,
+ /*auto_delete_vec=*/integer_zero_node,
+ /*auto_delete=*/integer_zero_node,
+ /*use_global_delete=*/0);
+ expand_expr (e, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ do_pending_stack_adjust ();
+ RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
+ end_sequence ();
+ cleanup = protect_with_terminate (cleanup);
+ expand_eh_region_end (cleanup);
+ pop_obstacks ();
}
/* `expand_vec_init' performs initialization of a vector of aggregate
int from_array;
{
tree rval;
- tree iterator, base2 = NULL_TREE;
+ tree base2 = NULL_TREE;
tree type = TREE_TYPE (TREE_TYPE (base));
tree size;
+ tree itype = NULL_TREE;
+ tree iterator;
+ int num_initialized_elts = 0;
maxindex = cp_convert (ptrdiff_type_node, maxindex);
if (maxindex == error_mark_node)
size = size_in_bytes (type);
- /* Set to zero in case size is <= 0. Optimizer will delete this if
- it is not needed. */
- rval = get_temp_regvar (build_pointer_type (type),
- cp_convert (build_pointer_type (type), null_pointer_node));
base = default_conversion (base);
base = cp_convert (build_pointer_type (type), base);
- expand_assignment (rval, base, 0, 0);
+ rval = get_temp_regvar (build_pointer_type (type), base);
base = get_temp_regvar (build_pointer_type (type), base);
+ iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
- if (init != NULL_TREE
- && TREE_CODE (init) == CONSTRUCTOR
- && (! decl || TREE_TYPE (init) == TREE_TYPE (decl)))
+ /* Protect the entire array initialization so that we can destroy
+ the partially constructed array if an exception is thrown. */
+ expand_vec_init_try_block (type);
+
+ if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR
+ && (!decl || same_type_p (TREE_TYPE (init), TREE_TYPE (decl))))
{
- /* Initialization of array from {...}. */
- tree elts = CONSTRUCTOR_ELTS (init);
+ /* Do non-default initialization resulting from brace-enclosed
+ initializers. */
+
+ tree elts;
tree baseref = build1 (INDIRECT_REF, type, base);
- tree baseinc = build (PLUS_EXPR, build_pointer_type (type), base, size);
- int host_i = TREE_INT_CST_LOW (maxindex);
- if (IS_AGGR_TYPE (type))
+ from_array = 0;
+
+ for (elts = CONSTRUCTOR_ELTS (init); elts; elts = TREE_CHAIN (elts))
{
- while (elts)
- {
- host_i -= 1;
- expand_aggr_init (baseref, TREE_VALUE (elts), 0, 0);
+ tree elt = TREE_VALUE (elts);
- expand_assignment (base, baseinc, 0, 0);
- elts = TREE_CHAIN (elts);
- }
- /* Initialize any elements by default if possible. */
- if (host_i >= 0)
- {
- if (TYPE_NEEDS_CONSTRUCTING (type) == 0)
- {
- if (obey_regdecls)
- use_variable (DECL_RTL (base));
- goto done_init;
- }
+ num_initialized_elts++;
- iterator = get_temp_regvar (ptrdiff_type_node,
- build_int_2 (host_i, 0));
- init = NULL_TREE;
- goto init_by_default;
- }
+ if (IS_AGGR_TYPE (type) || TREE_CODE (type) == ARRAY_TYPE)
+ expand_aggr_init (baseref, elt, 0);
+ else
+ expand_assignment (baseref, elt, 0, 0);
+
+ expand_assignment (base,
+ build (PLUS_EXPR, build_pointer_type (type),
+ base, size),
+ 0, 0);
+ expand_assignment (iterator,
+ build (MINUS_EXPR, ptrdiff_type_node,
+ iterator, integer_one_node),
+ 0, 0);
}
- else
- while (elts)
- {
- expand_assignment (baseref, TREE_VALUE (elts), 0, 0);
- expand_assignment (base, baseinc, 0, 0);
- elts = TREE_CHAIN (elts);
- }
+ /* Clear out INIT so that we don't get confused below. */
+ init = NULL_TREE;
if (obey_regdecls)
use_variable (DECL_RTL (base));
}
- else
+ else if (from_array)
{
- tree itype;
+ /* If initializing one array from another, initialize element by
+ element. We rely upon the below calls the do argument
+ checking. */
+ if (decl == NULL_TREE)
+ {
+ sorry ("initialization of array from dissimilar array type");
+ return error_mark_node;
+ }
+ if (init)
+ {
+ base2 = default_conversion (init);
+ itype = TREE_TYPE (base2);
+ base2 = get_temp_regvar (itype, base2);
+ itype = TREE_TYPE (itype);
+ }
+ else if (TYPE_LANG_SPECIFIC (type)
+ && TYPE_NEEDS_CONSTRUCTING (type)
+ && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+ {
+ error ("initializer ends prematurely");
+ return error_mark_node;
+ }
+ }
- iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
+ /* Now, default-initialize any remaining elements. We don't need to
+ do that if a) the type does not need constructing, or b) we've
+ already initialized all the elements.
- init_by_default:
- itype = NULL_TREE;
+ We do need to keep going if we're copying an array. */
- /* If initializing one array from another,
- initialize element by element. */
- if (from_array)
- {
- /* We rely upon the below calls the do argument checking */
- if (decl == NULL_TREE)
- {
- sorry ("initialization of array from dissimilar array type");
- return error_mark_node;
- }
- if (init)
- {
- base2 = default_conversion (init);
- itype = TREE_TYPE (base2);
- base2 = get_temp_regvar (itype, base2);
- itype = TREE_TYPE (itype);
- }
- else if (TYPE_LANG_SPECIFIC (type)
- && TYPE_NEEDS_CONSTRUCTING (type)
- && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
- {
- error ("initializer ends prematurely");
- return error_mark_node;
- }
- }
+ if (from_array
+ || (TYPE_NEEDS_CONSTRUCTING (type)
+ && !(TREE_CODE (maxindex) == INTEGER_CST
+ && num_initialized_elts == TREE_INT_CST_LOW (maxindex) + 1)))
+ {
+ /* If the ITERATOR is equal to -1, then we don't have to loop;
+ we've already initialized all the elements. */
+ expand_start_cond (build (NE_EXPR, boolean_type_node,
+ iterator, minus_one),
+ 0);
- expand_start_cond (build (GE_EXPR, boolean_type_node,
- iterator, integer_zero_node), 0);
- if (TYPE_NEEDS_DESTRUCTOR (type))
- expand_eh_region_start ();
+ /* Otherwise, loop through the elements. */
expand_start_loop_continue_elsewhere (1);
-
+
/* The initialization of each array element is a full-expression. */
expand_start_target_temps ();
if (from_array == 2)
expand_expr_stmt (build_modify_expr (to, NOP_EXPR, from));
else if (TYPE_NEEDS_CONSTRUCTING (type))
- expand_aggr_init (to, from, 0, 0);
+ expand_aggr_init (to, from, 0);
else if (from)
expand_assignment (to, from, 0, 0);
else
{
if (init != 0)
sorry ("cannot initialize multi-dimensional array with initializer");
- expand_vec_init (decl, build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), base),
+ expand_vec_init (decl,
+ build1 (NOP_EXPR,
+ build_pointer_type (TREE_TYPE
+ (type)),
+ base),
array_type_nelts (type), 0, 0);
}
else
- expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0, 0);
+ expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0);
expand_assignment (base,
- build (PLUS_EXPR, build_pointer_type (type), base, size),
- 0, 0);
+ build (PLUS_EXPR, build_pointer_type (type),
+ base, size), 0, 0);
if (base2)
expand_assignment (base2,
- build (PLUS_EXPR, build_pointer_type (type), base2, size), 0, 0);
+ build (PLUS_EXPR, build_pointer_type (type),
+ base2, size), 0, 0);
/* Cleanup any temporaries needed for the initial value. */
expand_end_target_temps ();
-
+
expand_loop_continue_here ();
expand_exit_loop_if_false (0, build (NE_EXPR, boolean_type_node,
- build (PREDECREMENT_EXPR, ptrdiff_type_node, iterator, integer_one_node), minus_one));
-
+ build (PREDECREMENT_EXPR,
+ ptrdiff_type_node,
+ iterator,
+ integer_one_node),
+ minus_one));
+
if (obey_regdecls)
{
use_variable (DECL_RTL (base));
if (base2)
use_variable (DECL_RTL (base2));
}
+
expand_end_loop ();
- if (TYPE_NEEDS_DESTRUCTOR (type) && flag_exceptions)
- {
- /* We have to ensure that this can live to the cleanup
- expansion time, since we know it is only ever needed
- once, generate code now. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
- {
- tree e1, cleanup = make_node (RTL_EXPR);
- TREE_TYPE (cleanup) = void_type_node;
- RTL_EXPR_RTL (cleanup) = const0_rtx;
- TREE_SIDE_EFFECTS (cleanup) = 1;
- do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (cleanup);
-
- e1 = build_array_eh_cleanup
- (rval,
- build_binary_op (MINUS_EXPR, maxindex, iterator, 1),
- type);
- expand_expr (e1, const0_rtx, VOIDmode, EXPAND_NORMAL);
- do_pending_stack_adjust ();
- RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
- end_sequence ();
-
- cleanup = protect_with_terminate (cleanup);
- expand_eh_region_end (cleanup);
- }
- pop_obstacks ();
- }
expand_end_cond ();
- if (obey_regdecls)
- use_variable (DECL_RTL (iterator));
}
- done_init:
+
+ /* Make sure to cleanup any partially constructed elements. */
+ expand_vec_init_catch_clause (rval, type, maxindex, iterator);
if (obey_regdecls)
- use_variable (DECL_RTL (rval));
+ {
+ use_variable (DECL_RTL (iterator));
+ use_variable (DECL_RTL (rval));
+ }
+
return rval;
}
This does not call any destructors. */
tree
-build_x_delete (type, addr, which_delete, virtual_size)
- tree type, addr;
+build_x_delete (addr, which_delete, virtual_size)
+ tree addr;
int which_delete;
tree virtual_size;
{
enum tree_code code = use_vec_delete ? VEC_DELETE_EXPR : DELETE_EXPR;
int flags = LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL);
- return build_op_delete_call (code, addr, virtual_size, flags);
+ return build_op_delete_call (code, addr, virtual_size, flags, NULL_TREE);
}
/* 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 (TYPE_SIZE (complete_type (type)) == 0)
- {
- incomplete_type_error (0, type);
- return error_mark_node;
- }
+ if (type != void_type_node && !complete_type_or_else (type, addr))
+ return error_mark_node;
if (TREE_CODE (type) == ARRAY_TYPE)
goto handle_array;
if (! IS_AGGR_TYPE (type))
{
/* Call the builtin operator delete. */
- return build_builtin_call (void_type_node, BID,
- build_expr_list (NULL_TREE, addr));
+ return build_builtin_delete_call (addr);
}
if (TREE_SIDE_EFFECTS (addr))
addr = save_expr (addr);
return error_mark_node;
}
return build_vec_delete (addr, array_type_nelts (type),
- auto_delete, integer_two_node,
+ auto_delete, integer_zero_node,
use_global_delete);
}
else
return build_op_delete_call
(DELETE_EXPR, addr, c_sizeof_nowarn (type),
- LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL));
+ LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
+ NULL_TREE);
}
/* Below, we will reverse the order in which these calls are made.
{
tree cond = fold (build (BIT_AND_EXPR, integer_type_node,
auto_delete, integer_one_node));
- tree call = build_builtin_call
- (void_type_node, BID, build_expr_list (NULL_TREE, addr));
+ tree call = build_builtin_delete_call (addr);
cond = fold (build (COND_EXPR, void_type_node, cond,
call, void_zero_node));
tree parent_auto_delete = auto_delete;
tree cond;
+ /* Set this again before we call anything, as we might get called
+ recursively. */
+ TYPE_HAS_DESTRUCTOR (type) = 1;
+
/* If we have member delete or vbases, we call delete in
finish_function. */
if (auto_delete == integer_zero_node)
{
cond = build (COND_EXPR, void_type_node,
build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_node),
- build_builtin_call (void_type_node, BID,
- build_expr_list (NULL_TREE, addr)),
+ build_builtin_delete_call (addr),
void_zero_node);
}
else