https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480
--- Comment #24 from Richard Biener <rguenth at gcc dot gnu.org> --- (In reply to Jonathan Wakely from comment #23) > The first thing a delete expression does is invoke the destructor, after > that there is no object anyway. The situation where we avoid the escape only is also hard to exploit since the caller would have to use the object after deletion. But one can do sth like static int *storage; void operator delete (void *p) { storage = (int *)p; } int main() { int *p = new int; *p = 1; int q; storage = &q; q = 3; delete p; *storage = 2; if (q != 3) __builtin_abort (); } where we while we still cannot CSE q across the delete call because q escapes (to 'storage'), we do elide the new/delete pair which then causes a runfail. The critical point here is (as in the original example in this PR) that the user of new/delete expects a specific implementation detail of new/delete (here setting of 'storage' by delete, upthread the requirement to setting 'flag'). The whole point of making sure the argument of the delete does not make the storage pointed to it escape (and not used) is to be able to DSE stores to it (see the affected g++.dg/cpp1y/new1.C testcase) and thus to elide more new/delete pairs.