On 7/9/19 11:00 PM, Jason Merrill wrote:
On 7/9/19 6:17 AM, Marc Glisse wrote:
On Tue, 9 Jul 2019, Martin Liška wrote:

On 7/9/19 9:49 AM, Marc Glisse wrote:
On Tue, 9 Jul 2019, Marc Glisse wrote:

On Mon, 8 Jul 2019, Martin Liška wrote:

The patch apparently has DECL_IS_OPERATOR_DELETE only on the replaceable global 
deallocation functions, not all delete operators, contrary to 
DECL_IS_OPERATOR_NEW, so the name is misleading. On the other hand, those seem 
to be the ones for which the optimization is legal (well, not quite, the rules 
are in terms of operator new, and I am not sure how well operator delete has to 
match, but close enough).

Are you talking about this location where we set OPERATOR_NEW:
https://github.com/gcc-mirror/gcc/blob/master/gcc/cp/decl.c#L13643
?

That's the only place where we set OPERATOR_NEW flag and not OPERATOR_DELETE.

Yes, I think that's the place.

Again, not setting DECL_IS_OPERATOR_DELETE on local operator delete
seems misleading, but setting it would let us optimize in cases where we
are not really allowed to. Maybe just rename your macro to
DECL_IS_GLOBAL_OPERATOR_DELETE?

Hmm, I replied too fast.

Global operator delete does not seem like a good terminology, the ones marked 
in the patch would be the usual (=non-placement) replaceable deallocation 
functions.

I cannot find a requirement that operator new and operator delete should match. The rules to omit allocation are stated in terms of which operator new is called, but do not seem to care which operator delete is used. So allocating with the global operator new and deallocating with a class overload of operator delete can be removed, but not the reverse (not sure how they came up with such a rule...).

Correct.  The standard just says that an implementation is allowed to omit a 
call to the replaceable ::operator new; it does not place any constraints on 
that, the conditions for such omission are left up to the implementation.

If the user's code uses global new and class delete for the same pointer, that 
would suggest that they're doing something odd, and we might as well leave it 
alone.  I would expect this to be very rare.

Which means we would need:

Thank you Mark for digging deep in that.


keep DECL_IS_OPERATOR_NEW for the current uses

DECL_IS_REPLACEABLE_OPERATOR_NEW (equivalent to DECL_IS_OPERATOR_NEW && 
DECL_IS_MALLOC? not exactly but close I think) for DCE

DECL_IS_OPERATOR_DELETE (which also includes some class overloads) for DCE

Note that with the current version of the patch we are out of free bits in 
struct GTY(()) tree_function_decl.
Would it be possible to tweak the current patch to cover what you described?

If you approximate DECL_IS_REPLACEABLE_OPERATOR_NEW with DECL_IS_OPERATOR_NEW 
&& DECL_IS_MALLOC, it shouldn't need more bits than the current patch. I think 
the main difference is if a user adds attribute malloc to his class-specific operator 
new, where it will enable DCE, but since the attribute is non-standard, we can just 
document that behavior, it might even be desirable.

Sure, it seems desirable to me.

Jason

Ok, I hopefully addressed the suggested improvements to the patch.

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

Ready to be installed?
Thanks,
Martin
>From 771d9128144745fe530577912521fc8228ca7424 Mon Sep 17 00:00:00 2001
From: Martin Liska <mli...@suse.cz>
Date: Tue, 2 Jul 2019 09:08:27 +0200
Subject: [PATCH] Extend DCE to remove unnecessary new/delete-pairs (PR
 c++/23383).

gcc/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz>
	    Dominik Infuhr  <dominik.infu...@theobroma-systems.com>

	PR c++/23383
	* common.opt: Add -fallocation-dce
	* gimple.c (gimple_call_operator_delete_p): New.
	* gimple.h (gimple_call_operator_delete_p): Likewise.
	* tree-core.h (enum function_decl_type): Add OPERATOR_DELETE.
	* tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Handle
	DECL_IS_OPERATOR_DELETE_P.
	(mark_all_reaching_defs_necessary_1): Likewise.
	(propagate_necessity): Likewise.
	(eliminate_unnecessary_stmts): Handle
	gimple_call_operator_delete_p.
	* tree-streamer-in.c (unpack_ts_function_decl_value_fields):
	Add packing of OPERATOR_DELETE.
	* tree-streamer-out.c (pack_ts_function_decl_value_fields):
	Similarly here.
	* tree.h (DECL_IS_OPERATOR_DELETE_P): New.
	(DECL_SET_IS_OPERATOR_DELETE): New.
	(DECL_IS_REPLACEABLE_OPERATOR_NEW_P): Likewise.

gcc/c/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz>
	    Dominik Infuhr  <dominik.infu...@theobroma-systems.com>

	PR c++/23383
	* c-decl.c (merge_decls): Merge OPERATOR_DELETE flag.

gcc/cp/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz>
	    Dominik Infuhr  <dominik.infu...@theobroma-systems.com>

	PR c++/23383
	* decl.c (cxx_init_decl_processing): Mark delete operators
	with DECL_SET_IS_OPERATOR_DELETE.

gcc/testsuite/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz
	    Dominik Infuhr  <dominik.infu...@theobroma-systems.com>

	PR c++/23383
	* g++.dg/cpp1y/new1.C: New test.

libstdc++-v3/ChangeLog:

2019-07-02  Martin Liska  <mli...@suse.cz>
	    Dominik Infuhr  <dominik.infu...@theobroma-systems.com>

	PR c++/23383
	* testsuite/ext/bitmap_allocator/check_delete.cc: Add
	-fno-allocation-dce.
	* testsuite/ext/bitmap_allocator/check_new.cc: Likewise.
	* testsuite/ext/new_allocator/check_delete.cc: Likewise.
	* testsuite/ext/new_allocator/check_new.cc: Likewise.
---
 gcc/c/c-decl.c                                |  2 +
 gcc/common.opt                                |  4 ++
 gcc/cp/decl.c                                 | 24 ++++---
 gcc/gimple.c                                  | 12 ++++
 gcc/gimple.h                                  |  1 +
 gcc/testsuite/g++.dg/cpp1y/new1.C             | 65 +++++++++++++++++++
 gcc/tree-core.h                               |  1 +
 gcc/tree-ssa-dce.c                            | 34 ++++++++--
 gcc/tree-streamer-in.c                        |  1 +
 gcc/tree-streamer-out.c                       |  1 +
 gcc/tree.h                                    | 11 ++++
 .../ext/bitmap_allocator/check_delete.cc      |  2 +
 .../ext/bitmap_allocator/check_new.cc         |  2 +
 .../ext/new_allocator/check_delete.cc         |  2 +
 .../testsuite/ext/new_allocator/check_new.cc  |  2 +
 15 files changed, 150 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/new1.C

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index b1392213fe3..42f7baf06e2 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2641,6 +2641,8 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 	  DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
 	  if (DECL_IS_OPERATOR_NEW_P (olddecl))
 	    DECL_SET_IS_OPERATOR_NEW (newdecl, true);
+	  if (DECL_IS_OPERATOR_DELETE_P (olddecl))
+	    DECL_SET_IS_OPERATOR_DELETE (newdecl, true);
 	  TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
 	  DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
 	  DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl);
diff --git a/gcc/common.opt b/gcc/common.opt
index b998b25522b..11637c8cab0 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2211,6 +2211,10 @@ Enum(live_patching_level) String(inline-only-static) Value(LIVE_PATCHING_INLINE_
 EnumValue
 Enum(live_patching_level) String(inline-clone) Value(LIVE_PATCHING_INLINE_CLONE)
 
+fallocation-dce
+Common Report Var(flag_allocation_dce) Init(1) Optimization
+Tell DCE to remove unused C++ allocations.
+
 flive-range-shrinkage
 Common Report Var(flag_live_range_shrinkage) Init(0) Optimization
 Relief of register pressure through live range shrinkage.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 28adb205078..9cafec84c6e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4363,8 +4363,10 @@ cxx_init_decl_processing (void)
     opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
     DECL_IS_MALLOC (opnew) = 1;
     DECL_SET_IS_OPERATOR_NEW (opnew, true);
-    push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
-    push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+    tree opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+    DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+    opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+    DECL_SET_IS_OPERATOR_DELETE (opdel, true);
     if (flag_sized_deallocation)
       {
 	/* Also push the sized deallocation variants:
@@ -4376,8 +4378,10 @@ cxx_init_decl_processing (void)
 	deltype = cp_build_type_attribute_variant (void_ftype_ptr_size,
 						   extvisattr);
 	deltype = build_exception_variant (deltype, empty_except_spec);
-	push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
-	push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+	opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_SET_IS_OPERATOR_DELETE (opdel, true);
       }
 
     if (aligned_new_threshold)
@@ -4405,8 +4409,10 @@ cxx_init_decl_processing (void)
 					    align_type_node, NULL_TREE);
 	deltype = cp_build_type_attribute_variant (deltype, extvisattr);
 	deltype = build_exception_variant (deltype, empty_except_spec);
-	push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
-	push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+	opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	DECL_SET_IS_OPERATOR_DELETE (opdel, true);
 
 	if (flag_sized_deallocation)
 	  {
@@ -4416,8 +4422,10 @@ cxx_init_decl_processing (void)
 						NULL_TREE);
 	    deltype = cp_build_type_attribute_variant (deltype, extvisattr);
 	    deltype = build_exception_variant (deltype, empty_except_spec);
-	    push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
-	    push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	    opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+	    DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+	    opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+	    DECL_SET_IS_OPERATOR_DELETE (opdel, true);
 	  }
       }
 
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 513bde209e2..a0eac8703bd 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2695,6 +2695,18 @@ gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl)
   return true;
 }
 
+/* Return true when STMT is operator delete call.  */
+
+bool
+gimple_call_operator_delete_p (const gcall *stmt)
+{
+  tree fndecl;
+
+  if ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE)
+    return DECL_IS_OPERATOR_DELETE_P (fndecl);
+  return false;
+}
+
 /* Return true when STMT is builtins call.  */
 
 bool
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 47070e7f409..f5872178109 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1549,6 +1549,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_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);
diff --git a/gcc/testsuite/g++.dg/cpp1y/new1.C b/gcc/testsuite/g++.dg/cpp1y/new1.C
new file mode 100644
index 00000000000..a95dd4d1ee3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/new1.C
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cddce-details" } */
+
+#include <stdlib.h>
+
+void
+new_without_use() {
+  int *x = new int;
+}
+
+void
+new_array_without_use() {
+  int *x = new int[5];
+}
+
+void
+new_primitive() {
+  int *x = new int;
+  delete x;
+}
+
+void
+new_array() {
+  int *x = new int[10];
+  delete [] x;
+}
+
+void
+new_primitive_store() {
+  int *x = new int;
+  *x = 10;
+  delete x;
+}
+
+void
+new_primitive_load() {
+  int *x = new int;
+  int tmp = *x;
+  delete x;
+}
+
+int
+new_primitive_load_with_use() {
+  int *x = new int;
+  int tmp = *x;
+  delete x;
+  return tmp;
+}
+
+void
+new_array_store() {
+  int *x = new int[10];
+  x[4] = 10;
+  delete [] x;
+}
+
+void
+new_array_load() {
+  int *x = new int[10];
+  int tmp = x[4];
+  delete [] x;
+}
+
+/* { dg-final { scan-tree-dump-times "Deleting : operator delete" 5 "cddce1"} } */
+/* { dg-final { scan-tree-dump-times "Deleting : _\\d+ = operator new" 7 "cddce1"} } */
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 1b1a50df52a..e22e1c67699 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1813,6 +1813,7 @@ enum function_decl_type
 {
   NONE,
   OPERATOR_NEW,
+  OPERATOR_DELETE,
   LAMBDA_FUNCTION
 
   /* 0 values left */
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index 6398c1e4457..90b3f4d7c45 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -237,6 +237,12 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
 
 	    default:;
 	    }
+
+	if (callee != NULL_TREE
+	    && flag_allocation_dce
+	    && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee))
+	  return;
+
 	/* Most, but not all function calls are required.  Function calls that
 	   produce no result and have no side effects (i.e. const pure
 	   functions) are unnecessary.  */
@@ -588,6 +594,11 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
 
 	  default:;
 	  }
+
+      if (callee != NULL_TREE
+	  && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
+	      || DECL_IS_OPERATOR_DELETE_P (callee)))
+	return false;
     }
 
   if (! gimple_clobber_p (def_stmt))
@@ -774,7 +785,10 @@ propagate_necessity (bool aggressive)
 	  /* If this is a call to free which is directly fed by an
 	     allocation function do not mark that necessary through
 	     processing the argument.  */
-	  if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+	  if (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
+	      || (is_gimple_call (stmt)
+		  && gimple_call_operator_delete_p (as_a <gcall *> (stmt))))
+
 	    {
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      gimple *def_stmt;
@@ -784,10 +798,11 @@ propagate_necessity (bool aggressive)
 	      if (TREE_CODE (ptr) == SSA_NAME
 		  && is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
 		  && (def_callee = gimple_call_fndecl (def_stmt))
-		  && DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
-		  && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
-		      || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
-		      || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
+		  && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
+		       && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
+			   || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
+			   || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
+		      || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
 		continue;
 	    }
 
@@ -842,6 +857,11 @@ propagate_necessity (bool aggressive)
 		      || DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED))
 		continue;
 
+	      if (callee != NULL_TREE
+		  && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
+		      || DECL_IS_OPERATOR_DELETE_P (callee)))
+		continue;
+
 	      /* Calls implicitly load from memory, their arguments
 	         in addition may explicitly perform memory loads.  */
 	      mark_all_reaching_defs_necessary (stmt);
@@ -1262,7 +1282,9 @@ eliminate_unnecessary_stmts (void)
 	     defining statement of its argument is not necessary
 	     (and thus is getting removed).  */
 	  if (gimple_plf (stmt, STMT_NECESSARY)
-	      && gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+	      && (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
+		  || (is_gimple_call (stmt)
+		      && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
 	    {
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      if (TREE_CODE (ptr) == SSA_NAME)
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index f2880f1021f..7ab72a7e0d7 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -334,6 +334,7 @@ unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_SET_IS_OPERATOR_NEW (expr, (unsigned) bp_unpack_value (bp, 1));
+  DECL_SET_IS_OPERATOR_DELETE (expr, (unsigned) bp_unpack_value (bp, 1));
   DECL_DECLARED_INLINE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_STATIC_CHAIN (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
index 7e93e6c23bb..dbdc5d5e736 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -296,6 +296,7 @@ pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   bp_pack_value (bp, DECL_IS_RETURNS_TWICE (expr), 1);
   bp_pack_value (bp, DECL_IS_MALLOC (expr), 1);
   bp_pack_value (bp, DECL_IS_OPERATOR_NEW_P (expr), 1);
+  bp_pack_value (bp, DECL_IS_OPERATOR_DELETE_P (expr), 1);
   bp_pack_value (bp, DECL_DECLARED_INLINE_P (expr), 1);
   bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
   bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
diff --git a/gcc/tree.h b/gcc/tree.h
index 308836fba73..95cd583f4ae 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3017,9 +3017,20 @@ set_function_decl_type (tree decl, function_decl_type t, bool set)
 #define DECL_IS_OPERATOR_NEW_P(NODE) \
   (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))
+
 #define DECL_SET_IS_OPERATOR_NEW(NODE, VAL) \
   set_function_decl_type (FUNCTION_DECL_CHECK (NODE), OPERATOR_NEW, VAL)
 
+/* Nonzero in a FUNCTION_DECL means this function should be treated as
+   C++ operator delete.  */
+#define DECL_IS_OPERATOR_DELETE_P(NODE) \
+  (FUNCTION_DECL_CHECK (NODE)->function_decl.decl_type == OPERATOR_DELETE)
+
+#define DECL_SET_IS_OPERATOR_DELETE(NODE, VAL) \
+  set_function_decl_type (FUNCTION_DECL_CHECK (NODE), OPERATOR_DELETE, VAL)
+
 /* Nonzero in a FUNCTION_DECL means this function may return more
    than once.  */
 #define DECL_IS_RETURNS_TWICE(NODE) \
diff --git a/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc b/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc
index 1b445643599..1ad1f3c242c 100644
--- a/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc
+++ b/libstdc++-v3/testsuite/ext/bitmap_allocator/check_delete.cc
@@ -15,6 +15,8 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
+// { dg-options "-fno-allocation-dce" }
+
 // 20.4.1.1 allocator members
 
 #include <cstdlib>
diff --git a/libstdc++-v3/testsuite/ext/bitmap_allocator/check_new.cc b/libstdc++-v3/testsuite/ext/bitmap_allocator/check_new.cc
index 0c5f9b6da7c..be16952c10d 100644
--- a/libstdc++-v3/testsuite/ext/bitmap_allocator/check_new.cc
+++ b/libstdc++-v3/testsuite/ext/bitmap_allocator/check_new.cc
@@ -15,6 +15,8 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
+// { dg-options "-fno-allocation-dce" }
+
 // 20.4.1.1 allocator members
 
 #include <cstdlib>
diff --git a/libstdc++-v3/testsuite/ext/new_allocator/check_delete.cc b/libstdc++-v3/testsuite/ext/new_allocator/check_delete.cc
index 8778bc9ccaa..dccee1d5293 100644
--- a/libstdc++-v3/testsuite/ext/new_allocator/check_delete.cc
+++ b/libstdc++-v3/testsuite/ext/new_allocator/check_delete.cc
@@ -17,6 +17,8 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
+// { dg-options "-fno-allocation-dce" }
+
 // 20.4.1.1 allocator members
 
 #include <cstdlib>
diff --git a/libstdc++-v3/testsuite/ext/new_allocator/check_new.cc b/libstdc++-v3/testsuite/ext/new_allocator/check_new.cc
index fd90d284224..a1d164a6d49 100644
--- a/libstdc++-v3/testsuite/ext/new_allocator/check_new.cc
+++ b/libstdc++-v3/testsuite/ext/new_allocator/check_new.cc
@@ -17,6 +17,8 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
+// { dg-options "-fno-allocation-dce" }
+
 // 20.4.1.1 allocator members
 
 #include <cstdlib>
-- 
2.22.0

Reply via email to