static void expand_aggr_init_1 ();
static void expand_recursive_init_1 ();
static void expand_recursive_init ();
+static void expand_virtual_init PROTO((tree, tree));
tree expand_vec_init ();
-tree build_vec_delete ();
static void add_friend (), add_friends ();
/* Cache _builtin_new and _builtin_delete exprs. */
-static tree BIN, BID;
+static tree BIN, BID, BIVN, BIVD;
/* Cache the identifier nodes for the two magic field of a new cookie. */
static tree nc_nelts_field_id;
+#if 0
static tree nc_ptr_2comp_field_id;
+#endif
static tree minus_one;
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
virtual base classes. Initialize binfo's vtable pointer, if
INIT_SELF is true. CAN_ELIDE is true when we know that all virtual
function table pointers in all bases have been initialized already,
- probably because their constructors have just be run. */
+ probably because their constructors have just be run. ADDR is the
+ pointer to the object whos vtables we are going to initialize.
+
+ REAL_BINFO is usually the same as BINFO, except when addr is not of
+ pointer to the type of the real derived type that we want to
+ initialize for. This is the case when addr is a pointer to a sub
+ object of a complete object, and we only want to do part of the
+ complete object's initiailzation of vtable pointers. This is done
+ for all virtual table pointers in virtual base classes. REAL_BINFO
+ is used to find the BINFO_VTABLE that we initialize with. BINFO is
+ used for conversions of addr to subobjects.
+
+ BINFO_TYPE (real_binfo) must be BINFO_TYPE (binfo).
+
+ Relies upon binfo being inside TYPE_BINFO (TREE_TYPE (TREE_TYPE
+ (addr))). */
void
-init_vtbl_ptrs (binfo, init_self, can_elide)
- tree binfo;
+expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
+ tree real_binfo, binfo, addr;
int init_self, can_elide;
{
- tree vfields;
+ tree real_binfos = BINFO_BASETYPES (real_binfo);
tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ int i, n_baselinks = real_binfos ? TREE_VEC_LENGTH (real_binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
+ tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
- if (! TREE_VIA_VIRTUAL (base_binfo))
- init_vtbl_ptrs (base_binfo, is_not_base_vtable, can_elide);
+ i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+ if (! TREE_VIA_VIRTUAL (real_base_binfo))
+ expand_direct_vtbls_init (real_base_binfo, base_binfo,
+ is_not_base_vtable, can_elide, addr);
}
#if 0
/* Before turning this on, make sure it is correct. */
return;
#endif
/* Should we use something besides CLASSTYPE_VFIELDS? */
- if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+ if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (real_binfo)))
{
- tree base_ptr = convert_pointer_to_real (binfo, current_class_decl);
- expand_expr_stmt (build_virtual_init (binfo, binfo, base_ptr));
+ tree base_ptr = convert_pointer_to_real (binfo, addr);
+ expand_virtual_init (real_binfo, base_ptr);
}
}
\f
expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
}
-
- if (flag_handle_exceptions == 2 && TYPE_NEEDS_DESTRUCTOR (type))
- {
- cplus_expand_start_try (1);
- push_exception_cleanup (build_unary_op (ADDR_EXPR, decl, 0));
- }
+ if (flag_handle_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
+ cp_warning ("caution, member `%D' may not be destroyed in the presense of an exception during construction", member);
}
/* Subroutine of emit_member_init. */
{
extern tree in_charge_identifier;
- tree member, decl, vbases;
- tree init_list, member_init;
+ tree member, vbases;
+ tree init_list;
int pass, start;
tree t_binfo = TYPE_BINFO (t);
tree binfos = BINFO_BASETYPES (t_binfo);
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- tree fields_to_unmark = NULL_TREE;
int have_init_list = 0, from_init_list;
if (! immediately)
emit_line_note_force (DECL_SOURCE_FILE (current_function_decl),
DECL_SOURCE_LINE (current_function_decl));
- /* In this case, we always need IN_CHARGE_NODE, because we have
- to know whether to deallocate or not before exiting. */
- if (flag_handle_exceptions == 2
- && lookup_name (in_charge_identifier, 0) == NULL_TREE)
- {
- tree in_charge_node = pushdecl (build_decl (VAR_DECL, in_charge_identifier,
- integer_type_node));
- store_init_value (in_charge_node, build (EQ_EXPR, integer_type_node,
- current_class_decl,
- integer_zero_node));
- expand_decl (in_charge_node);
- expand_decl_init (in_charge_node);
- }
-
start = ! TYPE_USES_VIRTUAL_BASECLASSES (t);
for (pass = start; pass < 2; pass++)
{
expand_aggr_init_1 (t_binfo, 0,
build_indirect_ref (member, NULL_PTR), init,
BINFO_OFFSET_ZEROP (binfo), LOOKUP_COMPLAIN);
- if (flag_handle_exceptions == 2 && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo)))
- {
- cplus_expand_start_try (1);
- push_exception_cleanup (member);
- }
}
if (pass == 0)
expand_aggr_init_1 (t_binfo, 0, ref, NULL_TREE,
BINFO_OFFSET_ZEROP (base_binfo),
LOOKUP_COMPLAIN);
- if (flag_handle_exceptions == 2
- && TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
- {
- cplus_expand_start_try (1);
- push_exception_cleanup (base);
- }
}
}
CLEAR_BINFO_BASEINIT_MARKED (base_binfo);
/* Initialize all the virtual function table fields that
do come from virtual base classes. */
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
- expand_expr_stmt (build_vbase_vtables_init (t_binfo, t_binfo,
- C_C_D, current_class_decl, 0));
+ expand_indirect_vtbls_init (t_binfo, C_C_D, current_class_decl, 0);
for (vbases = CLASSTYPE_VBASECLASSES (t); vbases; vbases = TREE_CHAIN (vbases))
CLEAR_BINFO_BASEINIT_MARKED (vbases);
/* Initialize all the virtual function table fields that
do not come from virtual base classes. */
- init_vtbl_ptrs (t_binfo, 0, 1);
-
- if (CLASSTYPE_NEEDS_VIRTUAL_REINIT (t))
- expand_expr_stmt (build_virtual_init (TYPE_BINFO (t), t,
- current_class_decl));
+ expand_direct_vtbls_init (t_binfo, t_binfo, 1, 1, current_class_decl);
if (current_member_init_list)
{
/* member could be, for example, a CONST_DECL for an enumerated
tag; we don't want to try to initialize that, since it already
has a value. */
- if (TREE_CODE (member) != FIELD_DECL)
+ if (TREE_CODE (member) != FIELD_DECL || !DECL_NAME (member))
continue;
name = DECL_NAME (member);
BINFO is the exact type that DECL is supposed to be. In
multiple inheritance, this might mean "C's A" if C : A, B. */
-tree
-build_virtual_init (main_binfo, binfo, decl)
- tree main_binfo, binfo;
- tree decl;
+static void
+expand_virtual_init (binfo, decl)
+ tree binfo, decl;
{
- tree type;
+ tree type = BINFO_TYPE (binfo);
tree vtbl, vtbl_ptr;
tree vtype, vtype_binfo;
- if (TREE_CODE (binfo) == TREE_VEC)
- type = BINFO_TYPE (binfo);
- else if (TREE_CODE (binfo) == RECORD_TYPE)
- {
- type = binfo;
- binfo = TYPE_BINFO (type);
- }
- else
- my_friendly_abort (46);
-
+ /* This code is crusty. Should be simple, like:
+ vtbl = BINFO_VTABLE (binfo);
+ */
vtype = DECL_CONTEXT (CLASSTYPE_VFIELD (type));
vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0);
-#if 0
- /* This code suggests that it's time to rewrite how we handle
- replicated baseclasses in G++. */
- if (get_base_distance (vtype, TREE_TYPE (TREE_TYPE (decl)),
- 0, (tree *) 0) == -2)
- {
- tree binfos = TYPE_BINFO_BASETYPES (TREE_TYPE (TREE_TYPE (decl)));
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- tree result = NULL_TREE;
-
- for (i = n_baselinks-1; i >= 0; i--)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- tree this_decl;
-
- if (get_base_distance (vtype, BINFO_TYPE (base_binfo), 0, 0) == -1)
- continue;
-
- if (TREE_VIA_VIRTUAL (base_binfo))
- this_decl = build_vbase_pointer (build_indirect_ref (decl, NULL_PTR), BINFO_TYPE (base_binfo));
- else if (BINFO_OFFSET_ZEROP (base_binfo))
- this_decl = build1 (NOP_EXPR, TYPE_POINTER_TO (BINFO_TYPE (base_binfo)),
- decl);
- else
- this_decl = build (PLUS_EXPR, TYPE_POINTER_TO (BINFO_TYPE (base_binfo)),
- decl, BINFO_OFFSET (base_binfo));
- result = tree_cons (NULL_TREE, build_virtual_init (main_binfo, base_binfo, this_decl), result);
- }
- return build_compound_expr (result);
- }
-#endif
-
- {
-#if 1
-#if 1
- vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)), binfo));
-#else
- /* The below does not work when we have to step through the
- vfield, on our way down to the most base class for the
- vfield. */
- vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)),
- BINFO_TYPE (main_binfo)));
-#endif
-#else
- my_friendly_assert (BINFO_TYPE (main_binfo) == BINFO_TYPE (binfo), 208);
- vtbl = BINFO_VTABLE (main_binfo);
-#endif /* 1 */
- assemble_external (vtbl);
- TREE_USED (vtbl) = 1;
- vtbl = build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (vtbl)), vtbl);
- }
+ vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (type)), binfo));
+ if (!flag_vtable_thunks)
+ assemble_external (vtbl);
+ TREE_USED (vtbl) = 1;
+ vtbl = build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (vtbl)), vtbl);
decl = convert_pointer_to_real (vtype_binfo, decl);
vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL_PTR), vtype);
if (vtbl_ptr == error_mark_node)
- return error_mark_node;
+ return;
/* Have to convert VTBL since array sizes may be different. */
- return build_modify_expr (vtbl_ptr, NOP_EXPR,
- convert (TREE_TYPE (vtbl_ptr), vtbl));
+ vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl);
+ expand_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
}
/* Subroutine of `expand_aggr_vbase_init'.
int was_const_elts = TYPE_READONLY (TREE_TYPE (type));
tree itype = init ? TREE_TYPE (init) : NULL_TREE;
if (was_const_elts)
- {
- tree atype = build_cplus_array_type (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
- TYPE_DOMAIN (type));
- if (init && (TREE_TYPE (exp) == TREE_TYPE (init)))
- TREE_TYPE (init) = atype;
- TREE_TYPE (exp) = atype;
- }
+ TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
if (init && TREE_TYPE (init) == NULL_TREE)
{
/* Handle bad initializers like:
tree addr = build_unary_op (ADDR_EXPR, exp, 0);
expand_aggr_vbase_init (binfo, exp, addr, NULL_TREE);
- expand_expr_stmt (build_vbase_vtables_init (binfo, binfo,
- exp, addr, 1));
+ expand_indirect_vtbls_init (binfo, exp, addr, 1);
}
expand_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
return;
{
tree type = TREE_TYPE (exp);
tree init_type = NULL_TREE;
- tree rval;
my_friendly_assert (init != error_mark_node && type != error_mark_node, 211);
are initializing the ultimate users of those vtables. */
if (TREE_VALUE (init_list))
{
- /* We have to ensure that the second argment to
- build_virtual_init is in binfo's hierarchy. */
- expand_expr_stmt (build_virtual_init (binfo,
- get_binfo (TREE_VALUE (init_list), binfo, 0),
- addr));
+ /* We have to ensure that the first argment to
+ expand_virtual_init is in binfo's hierarchy. */
+ /* Is it the case that this is exactly the right binfo? */
+ /* If it is ok, then fixup expand_virtual_init, to make
+ it much simpler. */
+ expand_virtual_init (get_binfo (TREE_VALUE (init_list), binfo, 0),
+ addr);
if (TREE_VALUE (init_list) == binfo
&& TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
- expand_expr_stmt (build_vbase_vtables_init (binfo, binfo, true_exp, addr, 1));
+ expand_indirect_vtbls_init (binfo, true_exp, addr, 1);
}
}
else
if (true_exp == exp && TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
{
expand_aggr_vbase_init (binfo, exp, addr, init_list);
- expand_expr_stmt (build_vbase_vtables_init (binfo, binfo, true_exp, addr, 1));
+ expand_indirect_vtbls_init (binfo, true_exp, addr, 1);
}
expand_recursive_init_1 (binfo, true_exp, addr, init_list, alias_this);
if (IDENTIFIER_HAS_TYPE_VALUE (name))
type = IDENTIFIER_TYPE_VALUE (name);
- else if (IDENTIFIER_HAS_CLASS_TYPE_VALUE (name))
- type = IDENTIFIER_CLASS_TYPE_VALUE (name);
else
{
if (or_else)
- cp_error ("`%T' fails to be an aggregate typedef", name);
+ cp_error ("`%T' is not an aggregate typedef", name);
return 0;
}
&& TREE_CODE (type) != TEMPLATE_TYPE_PARM)
{
if (or_else)
- cp_error ("type `%T' is of non-aggregate type", type);
+ cp_error ("`%T' is not an aggregate type", type);
return 0;
}
return 1;
if (IDENTIFIER_HAS_TYPE_VALUE (name))
type = IDENTIFIER_TYPE_VALUE (name);
- else if (IDENTIFIER_HAS_CLASS_TYPE_VALUE (name))
- type = IDENTIFIER_CLASS_TYPE_VALUE (name);
else
{
if (or_else)
get_type_value (name)
tree name;
{
- tree type;
-
if (name == error_mark_node)
return NULL_TREE;
if (IDENTIFIER_HAS_TYPE_VALUE (name))
return IDENTIFIER_TYPE_VALUE (name);
- else if (IDENTIFIER_CLASS_VALUE (name))
- return IDENTIFIER_CLASS_TYPE_VALUE (name);
else
return NULL_TREE;
}
if (dont_use_this)
{
- basetype_path = NULL_TREE;
+ basetype_path = TYPE_BINFO (type);
decl = build1 (NOP_EXPR, TYPE_POINTER_TO (type), error_mark_node);
}
else if (current_class_decl == 0)
{
tree newtype = build_type_variant (type, TYPE_READONLY (oldtype),
TYPE_VOLATILE (oldtype));
- decl = convert_force (TYPE_POINTER_TO (newtype), olddecl);
+ decl = convert_force (build_pointer_type (newtype), olddecl);
}
else
decl = olddecl;
decl = build_indirect_ref (decl, NULL_PTR);
- if (t = lookup_fnfields (TYPE_BINFO (type), method_name, 0))
+ if (t = lookup_fnfields (basetype_path, method_name, 0))
return build_method_call (decl, 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, 0))))
{
if (t == error_mark_node)
return error_mark_node;
return error_mark_node;
}
+#if 0
if (TREE_CODE (name) == TYPE_EXPR)
/* Pass a TYPE_DECL to build_component_type_expr. */
return build_component_type_expr (TYPE_NAME (TREE_TYPE (cname)),
name, NULL_TREE, 1);
+#endif
fnfields = lookup_fnfields (TYPE_BINFO (type), name, 1);
fields = lookup_field (type, name, 0, 0);
if (t == NULL_TREE)
{
- cp_error ("`%D' is not a member of type `%T'", name,
- IDENTIFIER_TYPE_VALUE (cname));
+ cp_error ("`%D' is not a member of type `%T'", name, type);
return error_mark_node;
}
/* Cast function to signed integer. */
e0 = build1 (NOP_EXPR, integer_type_node, function);
-#ifdef VTABLE_USES_MASK
- /* If we are willing to limit the number of
- virtual functions a class may have to some
- *small* number, then if, for a function address,
- we are passed some small number, we know that
- it is a virtual function index, and work from there. */
- e1 = build (BIT_AND_EXPR, integer_type_node, e0, vtbl_mask);
-#else
/* There is a hack here that takes advantage of
twos complement arithmetic, and the fact that
there are more than one UNITS to the WORD.
e1 = build_compound_expr (tree_cons (NULL_TREE, exp_addr,
build_tree_list (NULL_TREE, e1)));
e1 = save_expr (e1);
-#endif
if (TREE_SIDE_EFFECTS (*exp_addr_ptr))
{
enum access_type access;
if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
- {
- basetype = TYPE_OFFSET_BASETYPE (type);
- base = convert_pointer_to (basetype, current_class_decl);
- }
+ basetype = TYPE_OFFSET_BASETYPE (type);
else
- base = current_class_decl;
- basetype = DECL_CONTEXT (member);
+ basetype = DECL_CONTEXT (member);
+
+ base = current_class_decl;
if (get_base_distance (basetype, TREE_TYPE (TREE_TYPE (base)), 0, &basetype_path) < 0)
{
{
if (decl == TREE_VALUE (friends))
{
- cp_pedwarn_at ("`%D' is already a friend of class `%T'",
- decl, type);
+ cp_pedwarn ("`%D' is already a friend of class `%T'",
+ decl, type);
+ cp_pedwarn_at ("previous friend declaration of `%D'",
+ TREE_VALUE (friends));
return;
}
}
xref_friend (type, decl, ctype)
tree type, decl, ctype;
{
- tree typedecl = TYPE_NAME (type);
tree friend_decl = TYPE_NAME (ctype);
#if 0
+ tree typedecl = TYPE_NAME (type);
tree t = tree_cons (NULL_TREE, ctype, DECL_UNDEFINED_FRIENDS (typedecl));
DECL_UNDEFINED_FRIENDS (typedecl) = t;
enum overload_flags flags;
tree quals;
{
- /* first, lets find out if what we are making a friend needs overloading */
- tree previous_decl;
- int was_c_linkage = 0;
-
/* Every decl that gets here is a friend of something. */
DECL_FRIEND_P (decl) = 1;
- /* If we find something in scope, let see if it has extern "C" linkage. */
- /* This code is pretty general and should be ripped out and reused
- as a separate function. */
- if (DECL_NAME (decl))
- {
- previous_decl = lookup_name (DECL_NAME (decl), 0);
- if (previous_decl && TREE_CODE (previous_decl) == TREE_LIST)
- {
- do
- {
- if (TREE_TYPE (TREE_VALUE (previous_decl)) == TREE_TYPE (decl))
- {
- previous_decl = TREE_VALUE (previous_decl);
- break;
- }
- previous_decl = TREE_CHAIN (previous_decl);
- }
- while (previous_decl);
- }
-
- /* It had extern "C" linkage, so don't overload this. */
- if (previous_decl && TREE_CODE (previous_decl) == FUNCTION_DECL
- && TREE_TYPE (decl) == TREE_TYPE (previous_decl)
- && DECL_LANGUAGE (previous_decl) == lang_c)
- was_c_linkage = 1;
- }
-
if (ctype)
{
tree cname = TYPE_NAME (ctype);
decl = void_type_node;
}
}
- /* never overload C functions */
else if (TREE_CODE (decl) == FUNCTION_DECL
&& ((IDENTIFIER_LENGTH (declarator) == 4
&& IDENTIFIER_POINTER (declarator)[0] == 'm'
&& IDENTIFIER_POINTER (declarator)[0] == '_'
&& IDENTIFIER_POINTER (declarator)[1] == '_'
&& strncmp (IDENTIFIER_POINTER (declarator)+2,
- "builtin_", 8) == 0)
- || was_c_linkage))
+ "builtin_", 8) == 0)))
{
/* raw "main", and builtin functions never gets overloaded,
but they can become friends. */
TREE_PUBLIC (decl) = 1;
add_friend (current_class_type, decl);
DECL_FRIEND_P (decl) = 1;
- if (IDENTIFIER_POINTER (declarator)[0] == '_')
- {
- if (! strcmp (IDENTIFIER_POINTER (declarator)+10, "new"))
- TREE_GETS_NEW (current_class_type) = 0;
- else if (! strcmp (IDENTIFIER_POINTER (declarator)+10, "delete"))
- TREE_GETS_DELETE (current_class_type) = 0;
- }
decl = void_type_node;
}
/* A global friend.
/* We can call pushdecl here, because the TREE_CHAIN of this
FUNCTION_DECL is not needed for other purposes. */
- decl = pushdecl_top_level (decl);
+ decl = pushdecl (decl);
make_decl_rtl (decl, NULL_PTR, 1);
add_friend (current_class_type, decl);
- if (! TREE_OVERLOADED (declarator)
- && IDENTIFIER_GLOBAL_VALUE (declarator)
- && TREE_CODE (IDENTIFIER_GLOBAL_VALUE (declarator)) == FUNCTION_DECL)
- {
- error ("friend `%s' implicitly overloaded",
- IDENTIFIER_POINTER (declarator));
- cp_error_at ("after declaration of non-overloaded `%D'", IDENTIFIER_GLOBAL_VALUE (declarator));
- }
DECL_FRIEND_P (decl) = 1;
- DECL_OVERLOADED (decl) = 1;
+#if 0
TREE_OVERLOADED (declarator) = 1;
- decl = push_overloaded_decl (decl, 1);
+#endif
}
else
{
/* @@ Should be able to ingest later definitions of this function
before use. */
- tree decl = IDENTIFIER_GLOBAL_VALUE (declarator);
+ tree decl = lookup_name_nonclass (declarator);
if (decl == NULL_TREE)
{
warning ("implicitly declaring `%s' as struct",
Unless I am mistaken, a call to new () will return initialized
data regardless of whether the constructor itself is private or
- not.
+ not. NOPE; new fails if the constructor is private (jcm).
Note that build_new does nothing to assure that any special
alignment requirements of the type are met. Rather, it leaves
int use_global_new;
{
tree type, true_type, size, rval;
- tree init1 = NULL_TREE, nelts;
- int has_call = 0, has_array = 0;
+ tree nelts;
+ int has_array = 0;
+ enum tree_code code = NEW_EXPR;
tree pending_sizes = NULL_TREE;
nelts = integer_one_node;
if (absdcl && TREE_CODE (absdcl) == CALL_EXPR)
- {
- /* probably meant to be a call */
- has_call = 1;
- init1 = TREE_OPERAND (absdcl, 1);
- absdcl = TREE_OPERAND (absdcl, 0);
- TREE_VALUE (decl) = absdcl;
- }
+ my_friendly_abort (215);
while (absdcl && TREE_CODE (absdcl) == INDIRECT_REF)
{
last_absdcl = absdcl;
error ("new of array type fails to specify size");
else
{
- this_nelts = save_expr (this_nelts);
+ this_nelts = save_expr (convert (sizetype, this_nelts));
absdcl = TREE_OPERAND (absdcl, 0);
if (this_nelts == integer_zero_node)
{
TREE_VALUE (decl) = absdcl;
type = true_type = groktypename (decl);
- if (! type || type == error_mark_node
- || true_type == error_mark_node)
+ if (! type || type == error_mark_node)
{
immediate_size_expand = old_immediate_size_expand;
return error_mark_node;
}
- /* ``A reference cannot be created by the new operator. A reference
- is not an object (8.2.2, 8.4.3), so a pointer to it could not be
- returned by new.'' ARM 5.3.3 */
- if (TREE_CODE (type) == REFERENCE_TYPE)
- error ("new cannot be applied to a reference type");
-
- type = TYPE_MAIN_VARIANT (type);
- if (type == void_type_node)
- {
- error ("invalid type: `void []'");
- return error_mark_node;
- }
if (current_function_decl
&& DECL_CONSTRUCTOR_P (current_function_decl))
{
decl = TYPE_NAME (type);
}
- if (TYPE_SIZE (type) == 0)
+ /* ``A reference cannot be created by the new operator. A reference
+ is not an object (8.2.2, 8.4.3), so a pointer to it could not be
+ returned by new.'' ARM 5.3.3 */
+ if (TREE_CODE (type) == REFERENCE_TYPE)
{
- if (type == void_type_node)
- error ("invalid type for new: `void'");
- else
- incomplete_type_error (0, type);
- return error_mark_node;
+ error ("new cannot be applied to a reference type");
+ type = true_type = TREE_TYPE (type);
}
- if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_ABSTRACT_VIRTUALS (type))
+ /* When the object being created is an array, the new-expression yields a
+ pointer to the initial element (if any) of the array. For example,
+ both new int and new int[10] return an int*. 5.3.4. */
+ if (TREE_CODE (type) == ARRAY_TYPE && has_array == 0)
{
- abstract_virtuals_error (NULL_TREE, type);
- return error_mark_node;
+ nelts = array_type_nelts_top (type);
+ has_array = 1;
+ type = true_type = TREE_TYPE (type);
}
- if (TYPE_LANG_SPECIFIC (type) && IS_SIGNATURE (type))
+ if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
{
- signature_error (NULL_TREE, type);
- return error_mark_node;
+ pedwarn ("const and volatile types cannot be created with operator new");
+ type = true_type = TYPE_MAIN_VARIANT (type);
}
-
+
/* If our base type is an array, then make sure we know how many elements
it has. */
while (TREE_CODE (true_type) == ARRAY_TYPE)
{
tree this_nelts = array_type_nelts_top (true_type);
- if (nelts == integer_one_node)
- {
- has_array = 1;
- nelts = this_nelts;
- }
- else
- {
- my_friendly_assert (has_array != 0, 216);
- nelts = build_binary_op (MULT_EXPR, nelts, this_nelts, 1);
- }
+ nelts = build_binary_op (MULT_EXPR, nelts, this_nelts, 1);
true_type = TREE_TYPE (true_type);
}
if (has_array)
else
size = size_in_bytes (type);
- if (has_call)
- init = init1;
+ if (TYPE_SIZE (true_type) == 0)
+ {
+ if (true_type == void_type_node)
+ error ("invalid type for new: `void'");
+ else
+ incomplete_type_error (0, true_type);
+ return error_mark_node;
+ }
+
+ if (TYPE_LANG_SPECIFIC (true_type)
+ && CLASSTYPE_ABSTRACT_VIRTUALS (true_type))
+ {
+ abstract_virtuals_error (NULL_TREE, true_type);
+ return error_mark_node;
+ }
+
+ if (TYPE_LANG_SPECIFIC (true_type) && IS_SIGNATURE (true_type))
+ {
+ signature_error (NULL_TREE, true_type);
+ return error_mark_node;
+ }
/* Get a little extra space to store a couple of things before the new'ed
array. */
- if (has_array && TYPE_NEEDS_DESTRUCTOR (true_type))
+ if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
{
tree extra = BI_header_size;
size = size_binop (PLUS_EXPR, size, extra);
}
+ if (has_array)
+ code = VEC_NEW_EXPR;
+
/* Allocate the object. */
- if (TYPE_LANG_SPECIFIC (true_type)
- && (TREE_GETS_NEW (true_type) || TREE_GETS_PLACED_NEW (true_type))
- && !use_global_new)
- rval = build_opfncall (NEW_EXPR, LOOKUP_NORMAL,
+ if (! use_global_new && TYPE_LANG_SPECIFIC (true_type)
+ && (TYPE_GETS_NEW (true_type) & (1 << has_array)))
+ rval = build_opfncall (code, LOOKUP_NORMAL,
TYPE_POINTER_TO (true_type), size, placement);
else if (placement)
{
- rval = build_opfncall (NEW_EXPR, LOOKUP_GLOBAL|LOOKUP_COMPLAIN,
+ rval = build_opfncall (code, LOOKUP_GLOBAL|LOOKUP_COMPLAIN,
ptr_type_node, size, placement);
rval = convert (TYPE_POINTER_TO (true_type), rval);
}
- else if (flag_this_is_variable > 0
+ else if (! has_array && flag_this_is_variable > 0
&& TYPE_HAS_CONSTRUCTOR (true_type) && init != void_type_node)
{
if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST)
else
{
rval = build_builtin_call (build_pointer_type (true_type),
- BIN, build_tree_list (NULL_TREE, size));
+ has_array ? BIVN : BIN,
+ build_tree_list (NULL_TREE, size));
#if 0
/* See comment above as to why this is disabled. */
if (alignment)
}
#endif
TREE_CALLS_NEW (rval) = 1;
- TREE_SIDE_EFFECTS (rval) = 1;
}
/* if rval is NULL_TREE I don't have to allocate it, but are we totally
sure we have some extra bytes in that case for the BI_header_size
cookies? And how does that interact with the code below? (mrs) */
/* Finish up some magic for new'ed arrays */
- if (has_array && TYPE_NEEDS_DESTRUCTOR (true_type) && rval != NULL_TREE)
+ if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type) && rval != NULL_TREE)
{
tree extra = BI_header_size;
tree cookie, exp1;
if (init == void_type_node)
goto done;
- if (TYPE_NEEDS_CONSTRUCTING (type)
- || (has_call || init))
+ if (TYPE_NEEDS_CONSTRUCTING (type) || init)
{
if (! TYPE_NEEDS_CONSTRUCTING (type) && ! IS_AGGR_TYPE (type))
{
This does not call any destructors. */
tree
-build_x_delete (type, addr, use_global_delete, virtual_size)
+build_x_delete (type, addr, which_delete, virtual_size)
tree type, addr;
- int use_global_delete;
+ int which_delete;
tree virtual_size;
{
+ int use_global_delete = which_delete & 1;
+ int use_vec_delete = !!(which_delete & 2);
tree rval;
+ enum tree_code code = use_vec_delete ? VEC_DELETE_EXPR : DELETE_EXPR;
- if (!use_global_delete
- && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
- && TREE_GETS_DELETE (TREE_TYPE (type)))
- rval = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
- virtual_size, NULL_TREE);
+ if (! use_global_delete && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
+ && (TYPE_GETS_DELETE (TREE_TYPE (type)) & (1 << use_vec_delete)))
+ rval = build_opfncall (code, LOOKUP_NORMAL, addr, virtual_size, NULL_TREE);
else
- rval = build_builtin_call (void_type_node, BID,
+ rval = build_builtin_call (void_type_node, use_vec_delete ? BIVD : BID,
build_tree_list (NULL_TREE, addr));
return rval;
}
if (TREE_CODE (type) == POINTER_TYPE)
{
- type = TREE_TYPE (type);
+ type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
if (TYPE_SIZE (type) == 0)
{
incomplete_type_error (0, type);
}
if (TREE_SIDE_EFFECTS (addr))
addr = save_expr (addr);
+
+ /* throw away const and volatile on target type of addr */
+ addr = convert_force (build_pointer_type (type), addr);
ref = build_indirect_ref (addr, NULL_PTR);
ptr = 1;
}
addr = save_expr (addr);
return build_vec_delete (addr, array_type_nelts (type),
c_sizeof_nowarn (TREE_TYPE (type)),
- NULL_TREE, auto_delete, integer_two_node);
+ auto_delete, integer_two_node,
+ use_global_delete);
}
else
{
if (! TYPE_NEEDS_DESTRUCTOR (type))
{
- tree virtual_size;
-
if (auto_delete == integer_zero_node)
return void_zero_node;
/* Pass the size of the object down to the operator delete() in
addition to the ADDR. */
- if (TREE_GETS_DELETE (type) && !use_global_delete)
+ if (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
{
- /* This is probably wrong. It should be the size of the virtual
- object being deleted. */
tree virtual_size = c_sizeof_nowarn (type);
return build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
virtual_size, NULL_TREE);
{
tree dtor = DECL_MAIN_VARIANT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0));
tree basetypes = TYPE_BINFO (type);
+ tree passed_auto_delete;
+ tree do_delete = NULL_TREE;
+
+ if (use_global_delete)
+ {
+ 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_tree_list (NULL_TREE, addr));
+
+ cond = fold (build (COND_EXPR, void_type_node, cond,
+ call, void_zero_node));
+ if (cond != void_zero_node)
+ do_delete = cond;
+
+ passed_auto_delete = fold (build (BIT_AND_EXPR, integer_type_node,
+ auto_delete, integer_two_node));
+ }
+ else
+ passed_auto_delete = auto_delete;
if (flags & LOOKUP_PROTECT)
{
if (function == error_mark_node)
return error_mark_node;
TREE_TYPE (function) = build_pointer_type (TREE_TYPE (dtor));
- TREE_CHAIN (parms) = build_tree_list (NULL_TREE, auto_delete);
+ TREE_CHAIN (parms) = build_tree_list (NULL_TREE, passed_auto_delete);
expr = build_function_call (function, parms);
+ if (do_delete)
+ expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
if (ptr && (flags & LOOKUP_DESTRUCTOR) == 0)
{
/* Handle the case where a virtual destructor is
but that's now obsolete. */
my_friendly_assert (DECL_INITIAL (dtor) != void_type_node, 221);
- TREE_CHAIN (parms) = build_tree_list (NULL_TREE, auto_delete);
+ TREE_CHAIN (parms) = build_tree_list (NULL_TREE, passed_auto_delete);
expr = build_function_call (dtor, parms);
+ if (do_delete)
+ expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
if (ifexp != integer_one_node)
expr = build (COND_EXPR, void_type_node,
operator delete, call the parent parent destructor (if any),
but let this node do the deleting. Otherwise, it is ok
to let the parent destructor do the deleting. */
- if (TREE_GETS_DELETE (type) && !use_global_delete)
+ if (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
{
parent_auto_delete = integer_zero_node;
if (auto_delete == integer_zero_node)
MAXINDEX is the number of elements to be deleted.
ELT_SIZE is the nominal size of each element in the vector.
BASE is the expression that should yield the store to be deleted.
- DTOR_DUMMY is a placeholder for a destructor. The library function
- __builtin_vec_delete has a pointer to function in this position.
This function expands (or synthesizes) these calls itself.
AUTO_DELETE_VEC says whether the container (vector) should be deallocated.
AUTO_DELETE say whether each item in the container should be deallocated.
confirm the size, and trap if the numbers differ; not clear that it'd
be worth bothering.) */
tree
-build_vec_delete (base, maxindex, elt_size, dtor_dummy, auto_delete_vec, auto_delete)
+build_vec_delete (base, maxindex, elt_size, auto_delete_vec, auto_delete,
+ use_global_delete)
tree base, maxindex, elt_size;
- tree dtor_dummy;
tree auto_delete_vec, auto_delete;
+ int use_global_delete;
{
tree ptype = TREE_TYPE (base);
tree type;
/* This is the real size */
virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
body = build_tree_list (NULL_TREE,
- build_x_delete (ptr_type_node, base_tbd, 0,
+ build_x_delete (ptype, base_tbd,
+ 2 | use_global_delete,
virtual_size));
body = build (COND_EXPR, void_type_node,
build (BIT_AND_EXPR, integer_type_node,
body = tree_cons (NULL_TREE,
build_delete (ptype, tbase, auto_delete,
- LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
+ LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1),
body);
body = tree_cons (NULL_TREE,
/* The below is short by BI_header_size */
virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex));
- if (loop == integer_zero_node)
+ if (! TYPE_VEC_NEW_USES_COOKIE (type))
/* no header */
base_tbd = base;
else
/* True size with header. */
virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
}
- deallocate_expr = build_x_delete (ptr_type_node, base_tbd, 1,
+ deallocate_expr = build_x_delete (ptype, base_tbd,
+ 2 | use_global_delete,
virtual_size);
if (auto_delete_vec != integer_one_node)
deallocate_expr = build (COND_EXPR, void_type_node,