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;
+}

Reply via email to