Hi.

The patch ensures that a deleted new/delete pair has a same context.
That will fix the issue presented in the PR.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

gcc/ChangeLog:

2020-03-30  Martin Liska  <mli...@suse.cz>

        PR c++/94314
        * tree-ssa-dce.c (propagate_necessity): Verify that
        DECL_CONTEXT of a new/delete operators do match.

gcc/testsuite/ChangeLog:

2020-03-30  Martin Liska  <mli...@suse.cz>

        PR c++/94314
        * g++.dg/pr94314.C: New test.
---
 gcc/testsuite/g++.dg/pr94314.C | 84 ++++++++++++++++++++++++++++++++++
 gcc/tree-ssa-dce.c             | 31 +++++++++----
 2 files changed, 105 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/pr94314.C


diff --git a/gcc/testsuite/g++.dg/pr94314.C b/gcc/testsuite/g++.dg/pr94314.C
new file mode 100644
index 00000000000..76cd9d8d2a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr94314.C
@@ -0,0 +1,84 @@
+/* PR c++/94314.  */
+/* { dg-options "-O2 -fdump-tree-cddce-details" } */
+/* { dg-additional-options "-fdelete-null-pointer-checks" } */
+
+#include <stdio.h>
+
+struct A
+{
+  __attribute__((malloc,noinline))
+  static void* operator new(unsigned long sz)
+  {
+    ++count;
+    return ::operator new(sz);
+  }
+
+  static void operator delete(void* ptr)
+  {
+    --count;
+    ::operator delete(ptr);
+  }
+
+  static int count;
+};
+
+int A::count = 0;
+
+struct B
+{
+  __attribute__((malloc,noinline))
+  static void* operator new(unsigned long sz)
+  {
+    ++count;
+    return ::operator new(sz);
+  }
+
+  __attribute__((noinline))
+  static void operator delete(void* ptr)
+  {
+    --count;
+    ::operator delete(ptr);
+  }
+
+  static int count;
+};
+
+int B::count = 0;
+
+struct C
+{
+  static void* operator new(unsigned long sz)
+  {
+    ++count;
+    return ::operator new(sz);
+  }
+
+  static void operator delete(void* ptr)
+  {
+    --count;
+    ::operator delete(ptr);
+  }
+
+  static int count;
+};
+
+int C::count = 0;
+
+int main(){
+  delete new A;
+  if (A::count != 0)
+    __builtin_abort ();
+
+  delete new B;
+  if (B::count != 0)
+    __builtin_abort ();
+
+  delete new C;
+  if (C::count != 0)
+    __builtin_abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Deleting : operator delete" 1 "cddce1"} } */
+/* { dg-final { scan-tree-dump-times "Deleting : B::operator delete" 1 "cddce1"} } */
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index e4077b58890..d86234ead23 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -824,16 +824,27 @@ propagate_necessity (bool aggressive)
 			   || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
 		      || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
 		{
-		  /* Delete operators can have alignment and (or) size as next
-		     arguments.  When being a SSA_NAME, they must be marked
-		     as necessary.  */
-		  if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
-		    for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
-		      {
-			tree arg = gimple_call_arg (stmt, i);
-			if (TREE_CODE (arg) == SSA_NAME)
-			  mark_operand_necessary (arg);
-		      }
+		  if (is_delete_operator)
+		    {
+		      /* Verify that new and delete operators have the same
+			 context.  */
+		      if (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)
+			  && (DECL_CONTEXT (def_callee)
+			      != DECL_CONTEXT (gimple_call_fndecl (stmt))))
+			mark_operand_necessary (gimple_call_arg (stmt, 0));
+
+		      /* Delete operators can have alignment and (or) size
+			 as next arguments.  When being a SSA_NAME, they
+			 must be marked as necessary.  */
+		      if (gimple_call_num_args (stmt) >= 2)
+			for (unsigned i = 1; i < gimple_call_num_args (stmt);
+			     i++)
+			  {
+			    tree arg = gimple_call_arg (stmt, i);
+			    if (TREE_CODE (arg) == SSA_NAME)
+			      mark_operand_necessary (arg);
+			  }
+		    }
 
 		  continue;
 		}

Reply via email to