diff mbox series

[C++] PR c++/90171 - ICE with destroying delete with size_t parm.

Message ID 20190420061419.19585-1-jason@redhat.com
State New
Headers show
Series [C++] PR c++/90171 - ICE with destroying delete with size_t parm. | expand

Commit Message

Jason Merrill April 20, 2019, 6:14 a.m. UTC
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.

Tested x86_64-pc-linux-gnu, applying to trunk.

	* 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.
---
 gcc/cp/call.c                                 | 44 ++++++++++++-------
 .../g++.dg/cpp2a/destroying-delete4.C         | 11 +++++
 gcc/cp/ChangeLog                              |  7 +++
 3 files changed, 47 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/destroying-delete4.C


base-commit: dbb68bd891ba4d345f3667c3ae7f1bfda04233b2
diff mbox series

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 9582345d7e8..f27a80dfa3b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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
index 00000000000..c122cee4942
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/destroying-delete4.C
@@ -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; }
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 9c1c49bda28..e7521446b59 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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  Jakub Jelinek  <jakub@redhat.com>
 
 	PR c++/90108