On Wed, 23 Sep 2020, Jason Merrill wrote: > On 9/23/20 2:42 PM, Richard Biener wrote: > > On September 23, 2020 7:53:18 PM GMT+02:00, Jason Merrill <ja...@redhat.com> > > wrote: > >> On 9/23/20 4:14 AM, Richard Biener wrote: > >>> C++ operator delete, when DECL_IS_REPLACEABLE_OPERATOR_DELETE_P, > >>> does not cause the deleted object to be escaped. It also has no > >>> other interesting side-effects for PTA so skip it like we do > >>> for BUILT_IN_FREE. > >> > >> Hmm, this is true of the default implementation, but since the function > >> > >> is replaceable, we don't know what a user definition might do with the > >> pointer. > > > > But can the object still be 'used' after delete? Can delete fail / throw? > > > > What guarantee does the predicate give us? > > The deallocation function is called as part of a delete expression in order to > release the storage for an object, ending its lifetime (if it was not ended by > a destructor), so no, the object can't be used afterward.
OK, but the delete operator can access the object contents if there wasn't a destructor ... > A deallocation function that throws has undefined behavior. OK, so it seems the 'replaceable' operators are the global ones (for user-defined/class-specific placement variants I see arbitrary extra arguments that we'd possibly need to handle). I'm happy to revert but I'd like to have a testcase that FAILs with the patch ;) Now, the following aborts: struct X { static struct X saved; int *p; X() { __builtin_memcpy (this, &saved, sizeof (X)); } }; void operator delete (void *p) { __builtin_memcpy (&X::saved, p, sizeof (X)); } int main() { int y = 1; X *p = new X; p->p = &y; delete p; X *q = new X; *(q->p) = 2; if (y != 2) __builtin_abort (); } and I could fix this by not making *p but what *p points to escape. The testcase is of course maximally awkward, but hey ... ;) Now this would all be moot if operator delete may not access the object (or if the object contents are undefined at that point). Oh, and the testcase segfaults when compiled with GCC 10 because there we elide the new X / delete p pair ... which is invalid then? Hmm, we emit MEM[(struct X *)_8] ={v} {CLOBBER}; operator delete (_8, 8); so the object contents are undefined _before_ calling delete even when I do not have a DTOR? That is, the above, w/o -fno-lifetime-dse, makes the PTA patch OK for the testcase. Richard. > >>> Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed. > >>> > >>> Richard. > >>> > >>> 2020-09-23 Richard Biener <rguent...@suse.de> > >>> > >>> PR tree-optimization/97151 > >>> * tree-ssa-structalias.c (find_func_aliases_for_call): > >>> DECL_IS_REPLACEABLE_OPERATOR_DELETE_P has no effect on > >>> arguments. > >>> > >>> * g++.dg/cpp1y/new1.C: Adjust for two more handled transforms. > >>> --- > >>> gcc/testsuite/g++.dg/cpp1y/new1.C | 4 ++-- > >>> gcc/tree-ssa-structalias.c | 2 ++ > >>> 2 files changed, 4 insertions(+), 2 deletions(-) > >>> > >>> diff --git a/gcc/testsuite/g++.dg/cpp1y/new1.C > >> b/gcc/testsuite/g++.dg/cpp1y/new1.C > >>> index aa5f647d535..fec0088cb40 100644 > >>> --- a/gcc/testsuite/g++.dg/cpp1y/new1.C > >>> +++ b/gcc/testsuite/g++.dg/cpp1y/new1.C > >>> @@ -69,5 +69,5 @@ test_unused() { > >>> delete p; > >>> } > >>> > >>> -/* { dg-final { scan-tree-dump-times "Deleting : operator delete" 5 > >> "cddce1"} } */ > >>> -/* { dg-final { scan-tree-dump-times "Deleting : _\\d+ = operator > >> new" 7 "cddce1"} } */ > >>> +/* { dg-final { scan-tree-dump-times "Deleting : operator delete" 6 > >> "cddce1"} } */ > >>> +/* { dg-final { scan-tree-dump-times "Deleting : _\\d+ = operator > >> new" 8 "cddce1"} } */ > >>> diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c > >>> index 44fe52e0f65..f676bf91e95 100644 > >>> --- a/gcc/tree-ssa-structalias.c > >>> +++ b/gcc/tree-ssa-structalias.c > >>> @@ -4857,6 +4857,8 @@ find_func_aliases_for_call (struct function > >> *fn, gcall *t) > >>> point for reachable memory of their arguments. */ > >>> else if (flags & (ECF_PURE|ECF_LOOPING_CONST_OR_PURE)) > >>> handle_pure_call (t, &rhsc); > >>> + else if (fndecl && DECL_IS_REPLACEABLE_OPERATOR_DELETE_P > >> (fndecl)) > >>> + ; > >>> else > >>> handle_rhs_call (t, &rhsc); > >>> if (gimple_call_lhs (t)) > >>> > > > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany; GF: Felix Imend