From: Mark Mitchell Date: Thu, 19 Jul 2001 04:27:16 +0000 (+0000) Subject: class.c (type_requires_array_cookie): New function. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dbc957f103982bd3d8cb973beb26439d4e99ad8c;p=gcc.git class.c (type_requires_array_cookie): New function. * class.c (type_requires_array_cookie): New function. (check_methods): Don't try to figure out whether the type needs a cookie here. (check_bases_and_members): Set TYPE_VEC_NEW_USES_COOKIE here. * cp-tree.h (TYPE_VEC_DELETE_TAKES_SIZE): Remove. (TYPE_VEC_NEW_USES_COOKIE): Reimplement. * pt.c (instantiate_class_template): Don't set TYPE_VEC_DELETE_TAKES_SIZE. * NEWS: Document ABI changes from GCC 3.0. From-SVN: r44142 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 78602c776c9..6825721315b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2001-07-18 Mark Mitchell + + * class.c (type_requires_array_cookie): New function. + (check_methods): Don't try to figure out whether the type needs a + cookie here. + (check_bases_and_members): Set TYPE_VEC_NEW_USES_COOKIE here. + * cp-tree.h (TYPE_VEC_DELETE_TAKES_SIZE): Remove. + (TYPE_VEC_NEW_USES_COOKIE): Reimplement. + * pt.c (instantiate_class_template): Don't set + TYPE_VEC_DELETE_TAKES_SIZE. + * NEWS: Document ABI changes from GCC 3.0. + 2001-07-18 Xavier Delacour , Gerald Pfeifer diff --git a/gcc/cp/NEWS b/gcc/cp/NEWS index 966572ceff9..69b6fb46ff7 100644 --- a/gcc/cp/NEWS +++ b/gcc/cp/NEWS @@ -1,5 +1,41 @@ *** 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. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 2ec3448d636..c3aa297236b 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -218,6 +218,7 @@ static int layout_conflict_p PARAMS ((tree, tree, splay_tree, int)); 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 @@ -4210,7 +4211,6 @@ check_methods (t) tree t; { tree x; - int seen_one_arg_array_delete_p = 0; for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x)) { @@ -4234,32 +4234,6 @@ check_methods (t) 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; - } } } @@ -4556,6 +4530,59 @@ remove_zero_width_bit_fields (t) } } +/* 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 @@ -4641,6 +4668,11 @@ check_bases_and_members (t, empty_p) /* 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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e8a61a8b11c..b32bd0cb881 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1291,7 +1291,7 @@ struct lang_type 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; @@ -1353,19 +1353,11 @@ struct lang_type #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. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3d6279a8282..d09ce8f70ca 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4988,7 +4988,6 @@ instantiate_class_template (type) TYPE_HAS_NEW_OPERATOR (type) = TYPE_HAS_NEW_OPERATOR (pattern); TYPE_HAS_ARRAY_NEW_OPERATOR (type) = TYPE_HAS_ARRAY_NEW_OPERATOR (pattern); TYPE_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern); - TYPE_VEC_DELETE_TAKES_SIZE (type) = TYPE_VEC_DELETE_TAKES_SIZE (pattern); TYPE_HAS_ASSIGN_REF (type) = TYPE_HAS_ASSIGN_REF (pattern); TYPE_HAS_CONST_ASSIGN_REF (type) = TYPE_HAS_CONST_ASSIGN_REF (pattern); TYPE_HAS_ABSTRACT_ASSIGN_REF (type) = TYPE_HAS_ABSTRACT_ASSIGN_REF (pattern); diff --git a/gcc/testsuite/g++.old-deja/g++.abi/arraynew.C b/gcc/testsuite/g++.old-deja/g++.abi/arraynew.C index 3aa32c84ab2..5f296ebeef1 100644 --- a/gcc/testsuite/g++.old-deja/g++.abi/arraynew.C +++ b/gcc/testsuite/g++.old-deja/g++.abi/arraynew.C @@ -82,6 +82,9 @@ struct Z2 { ~Z2 () {}; long double d; }; 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; } @@ -108,11 +111,13 @@ int main () // There should be a cookie when using the two-argument array delete // operator. check_cookie (9); + check_cookie (10); // But not when the one-argument version is also available. - check_no_cookie (10); + check_no_cookie (11); + check_no_cookie (12); // There should be a cookie when using a non-global placement new. - check_placement_cookie (11); + check_placement_cookie (13); } #else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */