PR c++/90171 - ICE with destroying delete with size_t parm.
authorJason Merrill <jason@redhat.com>
Sat, 20 Apr 2019 06:18:30 +0000 (02:18 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 20 Apr 2019 06:18:30 +0000 (02:18 -0400)
The problem here was that "second parm is size_t" is false for a destroying
sized delete.  So let's introduce sized_deallocation_fn_p when that's what
we're asking, and reserve second_parm_is_size_t for the specific case of
warning about possible confusion with placement delete.

* call.c (sized_deallocation_fn_p): New.  Use it instead of
second_parm_is_size_t in most cases.
(second_parm_is_size_t): Don't check for aligned.

From-SVN: r270467

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/g++.dg/cpp2a/destroying-delete4.C [new file with mode: 0644]

index 8eb2953e051e96c6e8c3678f61add7bc903eaa18..9e2c46624de4067a4f6daacebd20a68e591687fb 100644 (file)
@@ -1,3 +1,10 @@
+2019-04-19  Jason Merrill  <jason@redhat.com>
+
+       PR c++/90171 - ICE with destroying delete with size_t parm.
+       * call.c (sized_deallocation_fn_p): New.  Use it instead of
+       second_parm_is_size_t in most cases.
+       (second_parm_is_size_t): Don't check for aligned.
+
 2019-04-19  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/89900
index 9582345d7e828d38f66d4342ed22d1f369deb84a..f27a80dfa3b420f0bd5ab7d5e01439d00b17c627 100644 (file)
@@ -6307,10 +6307,6 @@ second_parm_is_size_t (tree fn)
   t = TREE_CHAIN (t);
   if (t == void_list_node)
     return true;
-  if (aligned_new_threshold && t
-      && same_type_p (TREE_VALUE (t), align_type_node)
-      && TREE_CHAIN (t) == void_list_node)
-    return true;
   return false;
 }
 
@@ -6383,6 +6379,26 @@ aligned_deallocation_fn_p (tree t)
   return false;
 }
 
+/* Returns true if FN is a usual deallocation fn with a size_t parameter.  */
+
+static bool
+sized_deallocation_fn_p (tree fn)
+{
+  tree t = FUNCTION_ARG_CHAIN (fn);
+  if (destroying_delete_p (fn))
+    t = TREE_CHAIN (t);
+  if (!t || !same_type_p (TREE_VALUE (t), size_type_node))
+    return false;
+  t = TREE_CHAIN (t);
+  if (t == void_list_node)
+    return true;
+  if (aligned_new_threshold && t
+      && same_type_p (TREE_VALUE (t), align_type_node)
+      && TREE_CHAIN (t) == void_list_node)
+    return true;
+  return false;
+}
+
 /* Returns true iff T, an element of an OVERLOAD chain, is a usual
    deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]).  */
 
@@ -6395,13 +6411,11 @@ usual_deallocation_fn_p (tree t)
       || primary_template_specialization_p (t))
     return false;
 
-  /* If a class T has a member deallocation function named operator delete
-     with exactly one parameter, then that function is a usual
-     (non-placement) deallocation function. If class T does not declare
-     such an operator delete but does declare a member deallocation
-     function named operator delete with exactly two parameters, the second
-     of which has type std::size_t (18.2), then this function is a usual
-     deallocation function.  */
+  /* A usual deallocation function is a deallocation function whose parameters
+     after the first are
+     - optionally, a parameter of type std::destroying_delete_t, then
+     - optionally, a parameter of type std::size_t, then
+     - optionally, a parameter of type std::align_val_t.  */
   bool global = DECL_NAMESPACE_SCOPE_P (t);
   tree chain = FUNCTION_ARG_CHAIN (t);
   if (!chain)
@@ -6410,7 +6424,7 @@ usual_deallocation_fn_p (tree t)
     chain = TREE_CHAIN (chain);
   if (chain == void_list_node
       || ((!global || flag_sized_deallocation)
-         && second_parm_is_size_t (t)))
+         && sized_deallocation_fn_p (t)))
     return true;
   if (aligned_deallocation_fn_p (t))
     return true;
@@ -6625,8 +6639,8 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
                  /* We need a cookie to determine the array size.  */
                  want_size = false;
              }
-           bool fn_size = second_parm_is_size_t (fn);
-           bool elt_size = second_parm_is_size_t (elt);
+           bool fn_size = sized_deallocation_fn_p (fn);
+           bool elt_size = sized_deallocation_fn_p (elt);
            gcc_assert (fn_size != elt_size);
            if (want_size == elt_size)
              fn = elt;
@@ -6682,7 +6696,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
          args->quick_push (addr);
          if (destroying)
            args->quick_push (destroying);
-         if (second_parm_is_size_t (fn))
+         if (sized_deallocation_fn_p (fn))
            args->quick_push (size);
          if (aligned_deallocation_fn_p (fn))
            {
diff --git a/gcc/testsuite/g++.dg/cpp2a/destroying-delete4.C b/gcc/testsuite/g++.dg/cpp2a/destroying-delete4.C
new file mode 100644 (file)
index 0000000..c122cee
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/90171
+// { dg-do compile { target c++2a } }
+
+#include <new>
+
+struct A {
+  void operator delete(A*, std::destroying_delete_t, std::align_val_t);
+  void operator delete(A*, std::destroying_delete_t, std::size_t, std::align_val_t);
+};
+
+void delete_A(A *a) { delete a; }