Allow new/delete operator deletion only for replaceable.
authorMartin Liska <mliska@suse.cz>
Wed, 8 Apr 2020 15:16:55 +0000 (17:16 +0200)
committerMartin Liska <mliska@suse.cz>
Wed, 8 Apr 2020 15:16:55 +0000 (17:16 +0200)
PR c++/94314
* gimple.c (gimple_call_operator_delete_p): Rename to...
(gimple_call_replaceable_operator_delete_p): ... this.
Use DECL_IS_REPLACEABLE_OPERATOR_DELETE_P.
* gimple.h (gimple_call_operator_delete_p): Rename to ...
(gimple_call_replaceable_operator_delete_p): ... this.
* tree-core.h (tree_function_decl): Add replaceable_operator
flag.
* tree-ssa-dce.c (mark_all_reaching_defs_necessary_1):
Use DECL_IS_REPLACEABLE_OPERATOR_DELETE_P.
(propagate_necessity): Use gimple_call_replaceable_operator_delete_p.
(eliminate_unnecessary_stmts): Likewise.
* tree-streamer-in.c (unpack_ts_function_decl_value_fields):
Pack DECL_IS_REPLACEABLE_OPERATOR.
* tree-streamer-out.c (pack_ts_function_decl_value_fields):
Unpack the field here.
* tree.h (DECL_IS_REPLACEABLE_OPERATOR): New.
(DECL_IS_REPLACEABLE_OPERATOR_NEW_P): New.
(DECL_IS_REPLACEABLE_OPERATOR_DELETE_P): New.
* cgraph.c (cgraph_node::dump): Dump if an operator is replaceable.
* ipa-icf.c (sem_item::compare_referenced_symbol_properties): Compare
replaceable operator flags.
PR c++/94314
* decl.c (duplicate_decls): Duplicate also DECL_IS_REPLACEABLE_OPERATOR.
(cxx_init_decl_processing): Mark replaceable all implicitly defined
operators.
PR c++/94314
* lto-common.c (compare_tree_sccs_1): Compare also
DECL_IS_REPLACEABLE_OPERATOR.
PR c++/94314
* g++.dg/pr94314-2.C: New test.
* g++.dg/pr94314-3.C: New test.
* g++.dg/pr94314.C: New test.

18 files changed:
gcc/ChangeLog
gcc/cgraph.c
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/gimple.c
gcc/gimple.h
gcc/ipa-icf.c
gcc/lto/ChangeLog
gcc/lto/lto-common.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/pr94314-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/pr94314-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/pr94314.C [new file with mode: 0644]
gcc/tree-core.h
gcc/tree-ssa-dce.c
gcc/tree-streamer-in.c
gcc/tree-streamer-out.c
gcc/tree.h

index ffd4679e4ed2fa2edb1f13641bb8535467806e87..88e7952080702cbf902befe16dbf4a335a189caf 100644 (file)
@@ -1,3 +1,28 @@
+2020-04-08  Martin Liska  <mliska@suse.cz>
+
+       PR c++/94314
+       * gimple.c (gimple_call_operator_delete_p): Rename to...
+       (gimple_call_replaceable_operator_delete_p): ... this.
+       Use DECL_IS_REPLACEABLE_OPERATOR_DELETE_P.
+       * gimple.h (gimple_call_operator_delete_p): Rename to ...
+       (gimple_call_replaceable_operator_delete_p): ... this.
+       * tree-core.h (tree_function_decl): Add replaceable_operator
+       flag.
+       * tree-ssa-dce.c (mark_all_reaching_defs_necessary_1):
+       Use DECL_IS_REPLACEABLE_OPERATOR_DELETE_P.
+       (propagate_necessity): Use gimple_call_replaceable_operator_delete_p.
+       (eliminate_unnecessary_stmts): Likewise.
+       * tree-streamer-in.c (unpack_ts_function_decl_value_fields):
+       Pack DECL_IS_REPLACEABLE_OPERATOR.
+       * tree-streamer-out.c (pack_ts_function_decl_value_fields):
+       Unpack the field here.
+       * tree.h (DECL_IS_REPLACEABLE_OPERATOR): New.
+       (DECL_IS_REPLACEABLE_OPERATOR_NEW_P): New.
+       (DECL_IS_REPLACEABLE_OPERATOR_DELETE_P): New.
+       * cgraph.c (cgraph_node::dump): Dump if an operator is replaceable.
+       * ipa-icf.c (sem_item::compare_referenced_symbol_properties): Compare
+       replaceable operator flags.
+
 2020-04-08  Dennis Zhang  <dennis.zhang@arm.com>
            Matthew Malcomson  <matthew.malcomson@arm.com>
 
index 6b780f80eb355080afa37c2bde84af1d926d886f..ecb234d032f6ec53bbf8df78fd719656a66701d5 100644 (file)
@@ -2157,10 +2157,11 @@ cgraph_node::dump (FILE *f)
   if (parallelized_function)
     fprintf (f, " parallelized_function");
   if (DECL_IS_OPERATOR_NEW_P (decl))
-    fprintf (f, " operator_new");
+    fprintf (f, " %soperator_new",
+            DECL_IS_REPLACEABLE_OPERATOR (decl) ? "replaceable_" : "");
   if (DECL_IS_OPERATOR_DELETE_P (decl))
-    fprintf (f, " operator_delete");
-
+    fprintf (f, " %soperator_delete",
+            DECL_IS_REPLACEABLE_OPERATOR (decl) ? "replaceable_" : "");
 
   fprintf (f, "\n");
 
index cedd157dbf9795d0bbf45dc43e7e57432520b088..7c5edc266d60e82d9ef336cf7db75b3c9380060c 100644 (file)
@@ -1,3 +1,10 @@
+2020-04-08  Martin Liska  <mliska@suse.cz>
+
+       PR c++/94314
+       * decl.c (duplicate_decls): Duplicate also DECL_IS_REPLACEABLE_OPERATOR.
+       (cxx_init_decl_processing): Mark replaceable all implicitly defined
+       operators.
+
 2020-04-08  Patrick Palka  <ppalka@redhat.com>
 
        Core issues 1001 and 1322
index 0ea4b320d8654f051c5d21fc16ab0f6951d16021..a6a1340e63179f1d7719361b49878e2940955987 100644 (file)
@@ -2368,6 +2368,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
            DECL_SET_IS_OPERATOR_NEW (newdecl, true);
          DECL_LOOPING_CONST_OR_PURE_P (newdecl)
            |= DECL_LOOPING_CONST_OR_PURE_P (olddecl);
+         DECL_IS_REPLACEABLE_OPERATOR (newdecl)
+           |= DECL_IS_REPLACEABLE_OPERATOR (olddecl);
 
          if (merge_attr)
            merge_attribute_bits (newdecl, olddecl);
@@ -4438,13 +4440,17 @@ cxx_init_decl_processing (void)
     tree opnew = push_cp_library_fn (NEW_EXPR, newtype, 0);
     DECL_IS_MALLOC (opnew) = 1;
     DECL_SET_IS_OPERATOR_NEW (opnew, true);
+    DECL_IS_REPLACEABLE_OPERATOR (opnew) = 1;
     opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
     DECL_IS_MALLOC (opnew) = 1;
     DECL_SET_IS_OPERATOR_NEW (opnew, true);
+    DECL_IS_REPLACEABLE_OPERATOR (opnew) = 1;
     tree opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
     DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+    DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
     opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
     DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+    DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
     if (flag_sized_deallocation)
       {
        /* Also push the sized deallocation variants:
@@ -4458,8 +4464,10 @@ cxx_init_decl_processing (void)
        deltype = build_exception_variant (deltype, empty_except_spec);
        opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
        DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+       DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
        opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
        DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+       DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
       }
 
     if (aligned_new_threshold)
@@ -4478,9 +4486,11 @@ cxx_init_decl_processing (void)
        opnew = push_cp_library_fn (NEW_EXPR, newtype, 0);
        DECL_IS_MALLOC (opnew) = 1;
        DECL_SET_IS_OPERATOR_NEW (opnew, true);
+       DECL_IS_REPLACEABLE_OPERATOR (opnew) = 1;
        opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
        DECL_IS_MALLOC (opnew) = 1;
        DECL_SET_IS_OPERATOR_NEW (opnew, true);
+       DECL_IS_REPLACEABLE_OPERATOR (opnew) = 1;
 
        /* operator delete (void *, align_val_t); */
        deltype = build_function_type_list (void_type_node, ptr_type_node,
@@ -4489,8 +4499,10 @@ cxx_init_decl_processing (void)
        deltype = build_exception_variant (deltype, empty_except_spec);
        opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
        DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+       DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
        opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
        DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+       DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
 
        if (flag_sized_deallocation)
          {
@@ -4502,8 +4514,10 @@ cxx_init_decl_processing (void)
            deltype = build_exception_variant (deltype, empty_except_spec);
            opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
            DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+           DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
            opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
            DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+           DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
          }
       }
 
index 61a400b356f8cb435174bbb72ea857d019bfe69c..10c562f4deffdd7237be2663aefb1594c1a8c426 100644 (file)
@@ -2730,15 +2730,15 @@ gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl)
   return true;
 }
 
-/* Return true when STMT is operator delete call.  */
+/* Return true when STMT is operator a replaceable delete call.  */
 
 bool
-gimple_call_operator_delete_p (const gcall *stmt)
+gimple_call_replaceable_operator_delete_p (const gcall *stmt)
 {
   tree fndecl;
 
   if ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE)
-    return DECL_IS_OPERATOR_DELETE_P (fndecl);
+    return DECL_IS_REPLACEABLE_OPERATOR_DELETE_P (fndecl);
   return false;
 }
 
index 305d98f5438b2b5c9e2dda57035c5343ba4099a1..ca7fec6247ea64286ff15c15a81e131acd60c86c 100644 (file)
@@ -1615,7 +1615,7 @@ extern alias_set_type gimple_get_alias_set (tree);
 extern bool gimple_ior_addresses_taken (bitmap, gimple *);
 extern bool gimple_builtin_call_types_compatible_p (const gimple *, tree);
 extern combined_fn gimple_call_combined_fn (const gimple *);
-extern bool gimple_call_operator_delete_p (const gcall *);
+extern bool gimple_call_replaceable_operator_delete_p (const gcall *);
 extern bool gimple_call_builtin_p (const gimple *);
 extern bool gimple_call_builtin_p (const gimple *, enum built_in_class);
 extern bool gimple_call_builtin_p (const gimple *, enum built_in_function);
index 17a0ed9760bf2e339f6906091057c26cb1351fe3..069de9d82fb3e2c6385b54b412e9e81a6993ab1c 100644 (file)
@@ -347,6 +347,10 @@ sem_item::compare_referenced_symbol_properties (symtab_node *used_by,
       if (DECL_IS_OPERATOR_NEW_P (n1->decl)
          != DECL_IS_OPERATOR_NEW_P (n2->decl))
        return return_false_with_msg ("operator new flags are different");
+
+      if (DECL_IS_REPLACEABLE_OPERATOR (n1->decl)
+         != DECL_IS_REPLACEABLE_OPERATOR (n2->decl))
+       return return_false_with_msg ("replaceable operator flags are different");
     }
 
   /* Merging two definitions with a reference to equivalent vtables, but
index 4171a3dc4aede05126a15079c04598b2a4f0776d..829b26d40051ac57ff29c3e6c68862a53fbbfbe6 100644 (file)
@@ -1,3 +1,9 @@
+2020-04-08  Martin Liska  <mliska@suse.cz>
+
+       PR c++/94314
+       * lto-common.c (compare_tree_sccs_1): Compare also
+       DECL_IS_REPLACEABLE_OPERATOR.
+
 2020-03-25  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/94223
index c95a9b00d9eddd19bfaae69964fc39dd95afd88c..e073abce2e732a0a25e6280a4136cf4135a94abe 100644 (file)
@@ -1236,6 +1236,7 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map)
       compare_values (DECL_DISREGARD_INLINE_LIMITS);
       compare_values (DECL_PURE_P);
       compare_values (DECL_LOOPING_CONST_OR_PURE_P);
+      compare_values (DECL_IS_REPLACEABLE_OPERATOR);
       compare_values (DECL_FINAL_P);
       compare_values (DECL_CXX_CONSTRUCTOR_P);
       compare_values (DECL_CXX_DESTRUCTOR_P);
index 9b2d1f6272105651aa7daa289ba3877877e1e507..a420deaad0554dac95714c451c005d07ae7d44ee 100644 (file)
@@ -1,3 +1,10 @@
+2020-04-08  Martin Liska  <mliska@suse.cz>
+
+       PR c++/94314
+       * g++.dg/pr94314-2.C: New test.
+       * g++.dg/pr94314-3.C: New test.
+       * g++.dg/pr94314.C: New test.
+
 2020-04-08  Dennis Zhang  <dennis.zhang@arm.com>
 
        * gcc.target/arm/acle/cde_v_1.c: New test.
diff --git a/gcc/testsuite/g++.dg/pr94314-2.C b/gcc/testsuite/g++.dg/pr94314-2.C
new file mode 100644 (file)
index 0000000..36b93ed
--- /dev/null
@@ -0,0 +1,26 @@
+/* PR c++/94314.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-cddce-details" } */
+/* { dg-additional-options "-fdelete-null-pointer-checks" } */
+
+#include <stdio.h>
+
+struct A
+{
+  __attribute__((always_inline)) A(int x)
+  {
+    if (x == 123)
+      throw x;
+  }
+};
+
+int
+main(int argc, char **argv)
+{
+  A *a = new A (argc);
+  delete a;
+
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Deleting : operator delete" 2 "cddce1"} } */
diff --git a/gcc/testsuite/g++.dg/pr94314-3.C b/gcc/testsuite/g++.dg/pr94314-3.C
new file mode 100644 (file)
index 0000000..a5b1013
--- /dev/null
@@ -0,0 +1,55 @@
+/* PR c++/94314.  */
+/* { dg-do run } */
+/* { dg-options "-O2 --param early-inlining-insns=100 -fdump-tree-cddce-details" } */
+/* { dg-additional-options "-fdelete-null-pointer-checks" } */
+
+#include <stdio.h>
+
+volatile int idx;
+
+struct base
+{
+  __attribute__ ((malloc, noinline)) static void *
+  operator new (unsigned long sz)
+  {
+    return ::operator new (sz);
+  }
+
+  __attribute__ ((noinline)) static void operator delete (void *ptr)
+  {
+    int c = count[idx];
+    count[idx] = c - 1;
+    ::operator delete (ptr);
+  }
+  volatile static int count[2];
+};
+
+volatile int base::count[2] = {0, 0};
+
+struct B : base
+{
+  static void *operator new (unsigned long sz)
+  {
+    int c = count[idx];
+    count[idx] = c + 1;
+    return base::operator new (sz);
+  }
+};
+
+volatile int c = 1;
+
+int
+main ()
+{
+  for (int i; i < c; i++)
+    {
+      idx = 0;
+      delete new B;
+      if (B::count[0] != 0)
+       __builtin_abort ();
+    }
+
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "Deleting : operator delete" "cddce1"} } */
diff --git a/gcc/testsuite/g++.dg/pr94314.C b/gcc/testsuite/g++.dg/pr94314.C
new file mode 100644 (file)
index 0000000..a06800d
--- /dev/null
@@ -0,0 +1,85 @@
+/* PR c++/94314.  */
+/* { dg-do run } */
+/* { 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-not "Deleting : B::operator delete" "cddce1"} } */
index 765ea2a9542309ad739a5ccebca4dd1867200ec7..d84fe959acccc98a31a75f368b4e9e414c545ade 100644 (file)
@@ -1896,8 +1896,9 @@ struct GTY(()) tree_function_decl {
   ENUM_BITFIELD(function_decl_type) decl_type: 2;
   unsigned has_debug_args_flag : 1;
   unsigned versioned_function : 1;
+  unsigned replaceable_operator : 1;
 
-  /* 12 bits left for future expansion.  */
+  /* 11 bits left for future expansion.  */
 };
 
 struct GTY(()) tree_translation_unit_decl {
index e4077b588904bd9a8aabc1cd080187399d0b25b9..fd5f24c746ca0359fdf5f883bfefeaf87e473848 100644 (file)
@@ -614,7 +614,7 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
 
       if (callee != NULL_TREE
          && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
-             || DECL_IS_OPERATOR_DELETE_P (callee)))
+             || DECL_IS_REPLACEABLE_OPERATOR_DELETE_P (callee)))
        return false;
     }
 
@@ -806,7 +806,7 @@ propagate_necessity (bool aggressive)
             processing the argument.  */
          bool is_delete_operator
            = (is_gimple_call (stmt)
-              && gimple_call_operator_delete_p (as_a <gcall *> (stmt)));
+              && gimple_call_replaceable_operator_delete_p (as_a <gcall *> (stmt)));
          if (is_delete_operator
              || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
            {
@@ -896,7 +896,7 @@ propagate_necessity (bool aggressive)
 
              if (callee != NULL_TREE
                  && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
-                     || DECL_IS_OPERATOR_DELETE_P (callee)))
+                     || DECL_IS_REPLACEABLE_OPERATOR_DELETE_P (callee)))
                continue;
 
              /* Calls implicitly load from memory, their arguments
@@ -1321,7 +1321,7 @@ eliminate_unnecessary_stmts (void)
          if (gimple_plf (stmt, STMT_NECESSARY)
              && (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
                  || (is_gimple_call (stmt)
-                     && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
+                     && gimple_call_replaceable_operator_delete_p (as_a <gcall *> (stmt)))))
            {
              tree ptr = gimple_call_arg (stmt, 0);
              if (TREE_CODE (ptr) == SSA_NAME)
index 4e035e9638f7b7585667b9365d6d5e8450994ba3..0bfc272d0763d569d4037963f1a93f79387a15fc 100644 (file)
@@ -343,6 +343,7 @@ unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_LOOPING_CONST_OR_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+  DECL_IS_REPLACEABLE_OPERATOR (expr) = (unsigned) bp_unpack_value (bp, 1);
   unsigned int fcode = 0;
   if (cl != NOT_BUILT_IN)
     {
index 8e5e1355196b76a88d721b0f030f13f0880805ba..5bbcebba87ed2dacdd07fe12cd249bf6275aebc6 100644 (file)
@@ -305,6 +305,7 @@ pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
   bp_pack_value (bp, DECL_PURE_P (expr), 1);
   bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1);
+  bp_pack_value (bp, DECL_IS_REPLACEABLE_OPERATOR (expr), 1);
   if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
     bp_pack_value (bp, DECL_UNCHECKED_FUNCTION_CODE (expr), 32);
 }
index 66dfa8762562947ded74b2db5e6f62d96234d10f..1c28785d411f1c4d92597333356a7e2de3e3c2e3 100644 (file)
@@ -3037,6 +3037,11 @@ set_function_decl_type (tree decl, function_decl_type t, bool set)
     FUNCTION_DECL_DECL_TYPE (decl) = NONE;
 }
 
+/* Nonzero in a FUNCTION_DECL means this function is a replaceable
+   function (like replaceable operators new or delete).  */
+#define DECL_IS_REPLACEABLE_OPERATOR(NODE)\
+   (FUNCTION_DECL_CHECK (NODE)->function_decl.replaceable_operator)
+
 /* Nonzero in a FUNCTION_DECL means this function should be treated as
    C++ operator new, meaning that it returns a pointer for which we
    should not use type based aliasing.  */
@@ -3044,7 +3049,7 @@ set_function_decl_type (tree decl, function_decl_type t, bool set)
   (FUNCTION_DECL_CHECK (NODE)->function_decl.decl_type == OPERATOR_NEW)
 
 #define DECL_IS_REPLACEABLE_OPERATOR_NEW_P(NODE) \
-  (DECL_IS_OPERATOR_NEW_P (NODE) && DECL_IS_MALLOC (NODE))
+  (DECL_IS_OPERATOR_NEW_P (NODE) && DECL_IS_REPLACEABLE_OPERATOR (NODE))
 
 #define DECL_SET_IS_OPERATOR_NEW(NODE, VAL) \
   set_function_decl_type (FUNCTION_DECL_CHECK (NODE), OPERATOR_NEW, VAL)
@@ -3054,6 +3059,9 @@ set_function_decl_type (tree decl, function_decl_type t, bool set)
 #define DECL_IS_OPERATOR_DELETE_P(NODE) \
   (FUNCTION_DECL_CHECK (NODE)->function_decl.decl_type == OPERATOR_DELETE)
 
+#define DECL_IS_REPLACEABLE_OPERATOR_DELETE_P(NODE) \
+  (DECL_IS_OPERATOR_DELETE_P (NODE) && DECL_IS_REPLACEABLE_OPERATOR (NODE))
+
 #define DECL_SET_IS_OPERATOR_DELETE(NODE, VAL) \
   set_function_decl_type (FUNCTION_DECL_CHECK (NODE), OPERATOR_DELETE, VAL)