We currently ignore all delete calls from delete expressions for
the purpose of generating PTA constraints.  That's in error from
r11-3612-g4f4ced28826ece which did a tree-wide change to clarify
and improve eliding of new/delete pairs.  The following restores
the original restriction of only ignoring calls to the standard
library copy of delete.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

I'll assume this is OK, but please tell me whether I got the
wording above wrong.

Thanks,
Richard.

        PR tree-optimization/126194
        * gimple-ssa-pta-constraints.cc (find_func_aliases_for_call):
        Only ignore calls to delete if DECL_IS_REPLACEABLE_OPERATOR.

        * g++.dg/lto/pr126194.h: New testcase.
        * g++.dg/lto/pr126194_0.C: Likewise.
        * g++.dg/lto/pr126194_1.C: Likewise.
        * g++.dg/lto/pr126194_2.C: Likewise.
---
 gcc/gimple-ssa-pta-constraints.cc     |  1 +
 gcc/testsuite/g++.dg/lto/pr126194.h   | 87 +++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/lto/pr126194_0.C | 71 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/lto/pr126194_1.C | 41 +++++++++++++
 gcc/testsuite/g++.dg/lto/pr126194_2.C |  8 +++
 5 files changed, 208 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/lto/pr126194.h
 create mode 100644 gcc/testsuite/g++.dg/lto/pr126194_0.C
 create mode 100644 gcc/testsuite/g++.dg/lto/pr126194_1.C
 create mode 100644 gcc/testsuite/g++.dg/lto/pr126194_2.C

diff --git a/gcc/gimple-ssa-pta-constraints.cc 
b/gcc/gimple-ssa-pta-constraints.cc
index a377b891d80..eda2f89b281 100644
--- a/gcc/gimple-ssa-pta-constraints.cc
+++ b/gcc/gimple-ssa-pta-constraints.cc
@@ -2151,6 +2151,7 @@ find_func_aliases_for_call (struct function *fn, gcall *t)
         the escaping of the pointer) can be ignored.  */
       else if (fndecl
               && DECL_IS_OPERATOR_DELETE_P (fndecl)
+              && DECL_IS_REPLACEABLE_OPERATOR (fndecl)
               && gimple_call_from_new_or_delete (t))
        ;
       else
diff --git a/gcc/testsuite/g++.dg/lto/pr126194.h 
b/gcc/testsuite/g++.dg/lto/pr126194.h
new file mode 100644
index 00000000000..21db1d9885d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126194.h
@@ -0,0 +1,87 @@
+#pragma once
+
+using Size = decltype(sizeof(0));
+
+struct A
+{
+    void (*const f_)(void**) noexcept;
+    void** const p_;
+    Size const a_;
+
+    A(void** pp, void (*f)(void**) noexcept, Size a) noexcept
+        : f_(f), p_(pp), a_(a) {}
+
+    void reset() const noexcept
+    {
+        if (*p_) {
+            (*f_)(p_);
+        }
+    }
+
+    A& operator=(const A&) = delete;
+
+    void* create(Size size, const void* caller, struct R& r) const;
+    void destroy(void* p, const void* caller, struct R& r) const noexcept;
+};
+
+struct R
+{
+    virtual ~R() = default;
+    virtual void* allocate(Size size, const void* caller) = 0;
+    virtual void deallocate(void* p, const void* caller) noexcept = 0;
+};
+
+R& get_r() noexcept;
+void touch(const void* p) noexcept;
+
+struct B
+{
+    void* q = nullptr;
+
+    static void cb(void** pp) noexcept
+    {
+        B* self = reinterpret_cast<B*>(pp);
+        if (self->q) {
+            extern void release_q(void*);
+            release_q(self->q);
+        }
+        self->q = nullptr;
+    }
+
+    ~B() noexcept
+    {
+        touch(this);
+        if (q) {
+            extern void release_q(void*);
+            release_q(q);
+        }
+    }
+
+    B() noexcept = default;
+    B(const B&) = delete;
+    B& operator=(const B&) = delete;
+    B(B&& other) noexcept : q(other.q)
+    {
+        other.q = nullptr;
+    }
+    B& operator=(B&& other) noexcept
+    {
+        if (this != &other) {
+            if (q) {
+                extern void release_q(void*);
+                release_q(q);
+            }
+            q = other.q;
+            other.q = nullptr;
+        }
+        return *this;
+    }
+
+    operator A() noexcept
+    {
+        return A(&q, &cb, alignof(void*));
+    }
+};
+
+void* operator new(Size size, A const& a, R& r) noexcept(false);
+void  operator delete(void* p, A const& a, R& r) noexcept;
diff --git a/gcc/testsuite/g++.dg/lto/pr126194_0.C 
b/gcc/testsuite/g++.dg/lto/pr126194_0.C
new file mode 100644
index 00000000000..b7c85039862
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126194_0.C
@@ -0,0 +1,71 @@
+// { dg-lto-do run }
+// { dg-lto-options { { -O2 -flto } } }
+
+#include "pr126194.h"
+
+extern "C" void* malloc(Size size) noexcept;
+extern "C" void free(void* p) noexcept;
+
+namespace {
+class M final : public R
+{
+public:
+    void* allocate(Size size, const void* /*caller*/) override
+    {
+        return malloc(size);
+    }
+
+    void deallocate(void* p, const void* /*caller*/) noexcept override
+    {
+        free(p);
+    }
+};
+
+M g_r;
+}
+
+R& get_r() noexcept
+{
+    return g_r;
+}
+
+void touch(const void* p) noexcept
+{
+    static const volatile void* sink = nullptr;
+    sink = p;
+}
+
+void release_q(void* p)
+{
+    free(p);
+}
+
+int g_should_throw = 0;
+
+void* A::create(Size size, const void* caller, R& r) const
+{
+    reset();
+    if (size < a_) size = a_;
+    void* p = r.allocate(size, caller);
+    if (!p) throw 2;
+    *p_ = p;
+    return p;
+}
+
+__attribute__((noinline))
+void A::destroy(void* p, const void* caller, R& r) const noexcept
+{
+    *p_ = nullptr;
+    r.deallocate(p, caller);
+}
+
+void* operator new(Size size, A const& a, R& r) noexcept(false)
+{
+    return a.create(size, __builtin_return_address(0), r);
+}
+
+__attribute__((noinline))
+void operator delete(void* p, A const& a, R& r) noexcept
+{
+    a.destroy(p, __builtin_return_address(0), r);
+}
diff --git a/gcc/testsuite/g++.dg/lto/pr126194_1.C 
b/gcc/testsuite/g++.dg/lto/pr126194_1.C
new file mode 100644
index 00000000000..e2894cd0105
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126194_1.C
@@ -0,0 +1,41 @@
+#include "pr126194.h"
+
+extern int g_should_throw;
+
+struct T
+{
+    int a;
+    __attribute__((noinline)) T() : a(0)
+    {
+        if (g_should_throw) {
+            throw 1;
+        }
+    }
+};
+
+__attribute__((noinline))
+int make_widget(bool go, void** out_ptr)
+{
+    B b;
+    R& r = get_r();
+    if (go) {
+        T* t = new(b, r) T();
+        (void)t;
+    }
+    *out_ptr = b.q;
+    b.q = nullptr;
+    return 42;
+}
+
+extern "C" __attribute__((visibility("default")))
+int run_repro(int argc)
+{
+    g_should_throw = (argc > 0);
+    void* p = nullptr;
+    try {
+        (void)make_widget(argc > 0, &p);
+        return 1;
+    } catch (...) {
+        return 0;
+    }
+}
diff --git a/gcc/testsuite/g++.dg/lto/pr126194_2.C 
b/gcc/testsuite/g++.dg/lto/pr126194_2.C
new file mode 100644
index 00000000000..3c024f47a19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126194_2.C
@@ -0,0 +1,8 @@
+// { dg-options "-fno-lto" }
+
+extern "C" int run_repro(int argc);
+
+int main(int argc, char**)
+{
+    return run_repro(argc);
+}
-- 
2.51.0

Reply via email to