*** Changes in GCC 3.1:
+* The C++ ABI has been changed to correctly handle this code:
+
+ struct A {
+ void operator delete[] (void *, size_t);
+ };
+
+ struct B : public A {
+ };
+
+ new B[10];
+
+ The amount of storage allocated for the array will be greater than
+ it was in 3.0, in order to store the number of elements in the
+ array, so that the correct size can be passed to `operator delete[]'
+ when the array is deleted. Previously, the value passed to
+ `operator delete[]' was unpredictable.
+
+ This change will only affect code that declares a two-argument
+ `operator delete[]' with a second parameter of type `size_t'
+ in a base class, and does not override that definition in a
+ derived class.
+
+* The C++ ABI has been changed so that:
+
+ struct A {
+ void operator delete[] (void *, size_t);
+ void operator delete[] (void *);
+ };
+
+ does not cause unncessary storage to be allocated when an array of
+ `A' objects is allocated.
+
+ This change will only affect code that declares both of these
+ forms of `operator delete[]', and declared the two-argument form
+ before the one-argument form.
+
*** Changes in GCC 3.0:
* Support for guiding declarations has been removed.
static int splay_tree_compare_integer_csts PARAMS ((splay_tree_key k1,
splay_tree_key k2));
static void warn_about_ambiguous_direct_bases PARAMS ((tree));
+static bool type_requires_array_cookie PARAMS ((tree));
/* Macros for dfs walking during vtt construction. See
dfs_ctor_vtable_bases_queue_p, dfs_build_secondary_vptr_vtt_inits
tree t;
{
tree x;
- int seen_one_arg_array_delete_p = 0;
for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x))
{
CLASSTYPE_PURE_VIRTUALS (t)
= tree_cons (NULL_TREE, x, CLASSTYPE_PURE_VIRTUALS (t));
}
-
- if (DECL_ARRAY_DELETE_OPERATOR_P (x))
- {
- tree second_parm;
-
- /* When dynamically allocating an array of this type, we
- need a "cookie" to record how many elements we allocated,
- even if the array elements have no non-trivial
- destructor, if the usual array deallocation function
- takes a second argument of type size_t. The standard (in
- [class.free]) requires that the second argument be set
- correctly. */
- second_parm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (x)));
- /* Under the new ABI, we choose only those function that are
- explicitly declared as `operator delete[] (void *,
- size_t)'. */
- if (!seen_one_arg_array_delete_p
- && second_parm
- && TREE_CHAIN (second_parm) == void_list_node
- && same_type_p (TREE_VALUE (second_parm), sizetype))
- TYPE_VEC_DELETE_TAKES_SIZE (t) = 1;
- /* If there's no second parameter, then this is the usual
- deallocation function. */
- else if (second_parm == void_list_node)
- seen_one_arg_array_delete_p = 1;
- }
}
}
}
}
+/* Returns TRUE iff we need a cookie when dynamically allocating an
+ array whose elements have the indicated class TYPE. */
+
+static bool
+type_requires_array_cookie (type)
+ tree type;
+{
+ tree fns;
+ bool has_two_argument_delete_p;
+
+ my_friendly_assert (CLASS_TYPE_P (type), 20010712);
+
+ /* If there's a non-trivial destructor, we need a cookie. In order
+ to iterate through the array calling the destructor for each
+ element, we'll have to know how many elements there are. */
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+ return true;
+
+ /* If the usual deallocation function is a two-argument whose second
+ argument is of type `size_t', then we have to pass the size of
+ the array to the deallocation function, so we will need to store
+ a cookie. */
+ fns = lookup_fnfields (TYPE_BINFO (type),
+ ansi_opname (VEC_DELETE_EXPR),
+ /*protect=*/0);
+ /* If there are no `operator []' members, or the lookup is
+ ambiguous, then we don't need a cookie. */
+ if (!fns || fns == error_mark_node)
+ return false;
+ /* Loop through all of the functions. */
+ for (fns = TREE_VALUE (fns); fns; fns = OVL_NEXT (fns))
+ {
+ tree fn;
+ tree second_parm;
+
+ /* Select the current function. */
+ fn = OVL_CURRENT (fns);
+ /* See if this function is a one-argument delete function. If
+ it is, then it will be the usual deallocation function. */
+ second_parm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn)));
+ if (second_parm == void_list_node)
+ return false;
+ /* Otherwise, if we have a two-argument function and the second
+ argument is `size_t', it will be the usual deallocation
+ function -- unless there is one-argument function, too. */
+ if (TREE_CHAIN (second_parm) == void_list_node
+ && same_type_p (TREE_VALUE (second_parm), sizetype))
+ has_two_argument_delete_p = true;
+ }
+
+ return has_two_argument_delete_p;
+}
+
/* Check the validity of the bases and members declared in T. Add any
implicitly-generated functions (like copy-constructors and
assignment operators). Compute various flag bits (like
/* Build and sort the CLASSTYPE_METHOD_VEC. */
finish_struct_methods (t);
+
+ /* Figure out whether or not we will need a cookie when dynamically
+ allocating an array of this type. */
+ TYPE_LANG_SPECIFIC (t)->vec_new_uses_cookie
+ = type_requires_array_cookie (t);
}
/* If T needs a pointer to its virtual function table, set TYPE_VFIELD
unsigned needs_virtual_reinit : 1;
unsigned marks: 6;
- unsigned vec_delete_takes_size : 1;
+ unsigned vec_new_uses_cookie : 1;
unsigned declared_class : 1;
unsigned being_defined : 1;
#define TYPE_GETS_DELETE(NODE) (TYPE_LANG_SPECIFIC(NODE)->gets_delete)
#define TYPE_GETS_REG_DELETE(NODE) (TYPE_GETS_DELETE (NODE) & 1)
-/* Nonzero for _CLASSTYPE means that operator vec delete is defined and
- takes the optional size_t argument. */
-#define TYPE_VEC_DELETE_TAKES_SIZE(NODE) \
- (TYPE_LANG_SPECIFIC(NODE)->vec_delete_takes_size)
-
/* Nonzero if `new NODE[x]' should cause the allocation of extra
- storage to indicate how many array elements are in use. The old
- ABI had a bug in that we always allocate the extra storage if NODE
- has a two-argument array operator delete. */
-#define TYPE_VEC_NEW_USES_COOKIE(NODE) \
- (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (NODE) \
- || (TYPE_LANG_SPECIFIC (NODE) \
- && TYPE_VEC_DELETE_TAKES_SIZE (NODE)))
+ storage to indicate how many array elements are in use. */
+#define TYPE_VEC_NEW_USES_COOKIE(NODE) \
+ (CLASS_TYPE_P (NODE) \
+ && TYPE_LANG_SPECIFIC (NODE)->vec_new_uses_cookie)
/* Nonzero means that this _CLASSTYPE node defines ways of converting
itself to other types. */
struct W1 { void operator delete[] (void *, size_t) {}; };
struct W2 { void operator delete[] (void *) {};
void operator delete[] (void *, size_t) {}; };
+struct W3 { void operator delete[] (void *, size_t) {};
+ void operator delete[] (void *) {}; };
+struct W4 : public W1 {};
struct V { void *operator new[] (size_t s, void *p)
{ return p; }
// There should be a cookie when using the two-argument array delete
// operator.
check_cookie<W1> (9);
+ check_cookie<W4> (10);
// But not when the one-argument version is also available.
- check_no_cookie<W2> (10);
+ check_no_cookie<W2> (11);
+ check_no_cookie<W3> (12);
// There should be a cookie when using a non-global placement new.
- check_placement_cookie<V> (11);
+ check_placement_cookie<V> (13);
}
#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */