The previous fix for PR 98160 was incomplete and while it fixed the more interesting aspect of the problem (a false positive) it didn't remedy the ICE that showed up only with LTO. I have reduced (again) the problem to a non-LTO test case and committed the attached trivial fix in r11-6329 after regtesting in on x86_64-linux.
Martin
commit 0df311657dc8c2a7f6ce3464c9d9ae5d5033840c Author: Martin Sebor <mse...@redhat.com> Date: Wed Dec 23 16:34:12 2020 -0700 PR middle-end/98160 - ICE in warn_dealloc_offset on member placement new and delete gcc/ChangeLog: PR middle-end/98160 * builtins.c (warn_dealloc_offset): Avoid assuming calls are made through declared functions and not pointers. gcc/testsuite/ChangeLog: PR middle-end/98160 * g++.dg/warn/pr98160.C: New test. diff --git a/gcc/builtins.c b/gcc/builtins.c index 498a1121dec..ffbb9b7f5f1 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -13400,6 +13400,8 @@ warn_dealloc_offset (location_t loc, tree exp, const access_ref &aref) return false; tree dealloc_decl = get_callee_fndecl (exp); + if (!dealloc_decl) + return false; if (DECL_IS_OPERATOR_DELETE_P (dealloc_decl) && !DECL_IS_REPLACEABLE_OPERATOR (dealloc_decl)) @@ -13413,7 +13415,7 @@ warn_dealloc_offset (location_t loc, tree exp, const access_ref &aref) if (is_gimple_call (def_stmt)) { tree alloc_decl = gimple_call_fndecl (def_stmt); - if (!DECL_IS_OPERATOR_NEW_P (alloc_decl)) + if (!alloc_decl || !DECL_IS_OPERATOR_NEW_P (alloc_decl)) return false; } } diff --git a/gcc/testsuite/g++.dg/warn/pr98160.C b/gcc/testsuite/g++.dg/warn/pr98160.C new file mode 100644 index 00000000000..b3c5783b5e1 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/pr98160.C @@ -0,0 +1,30 @@ +/* PR middle-end/98160 - ICE in warn_dealloc_offset on member placement + new and delete + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +void* (*pf) (size_t); + +struct A; +struct B +{ + B (); + + void* operator new (size_t, A*); + void operator delete (void*, A*); +}; + +void operator delete (void *, A*); + +void B::operator delete (void*, A *p) +{ + void *q = pf (1); + ::operator delete ((char*)q + 1, p); +} + +void* f (A *p) +{ + return new (p) B; +}