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.

Reply via email to