class.c (type_requires_array_cookie): New function.
authorMark Mitchell <mark@codesourcery.com>
Thu, 19 Jul 2001 04:27:16 +0000 (04:27 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Thu, 19 Jul 2001 04:27:16 +0000 (04:27 +0000)
* 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

gcc/cp/ChangeLog
gcc/cp/NEWS
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/g++.old-deja/g++.abi/arraynew.C

index 78602c776c9aa562c6db0d3eed09becb8d9c418c..6825721315bf096b3dede15c791b1aca61678931 100644 (file)
@@ -1,3 +1,15 @@
+2001-07-18  Mark Mitchell  <mark@codesourcery.com>
+
+       * 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 <xavier@fmaudio.net>,
             Gerald Pfeifer  <pfeifer@dbai.tuwien.ac.at>
 
index 966572ceff9b178014e53b1581290f5ae4ed7aad..69b6fb46ff725068d9eeba3772d3afa5f05214ab 100644 (file)
@@ -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.
index 2ec3448d6365ce717613496143f17e14218664d6..c3aa297236b513fc63e33a032807cba87cc9ff8d 100644 (file)
@@ -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
index e8a61a8b11c8a06dd7b4d546646451c66d452afa..b32bd0cb88172c208a569991256263b2d0ac955e 100644 (file)
@@ -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.  */
index 3d6279a82823dd81224999c839c7ce80130b896c..d09ce8f70ca02bc2030fd3c1d142b03e94d7aa5e 100644 (file)
@@ -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);
index 3aa32c84ab2e7bc69846860a80eaf460060b9688..5f296ebeef1b6120958c25a221271a791659911a 100644 (file)
@@ -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<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) */