Hi!

This patch implements the proposed resolution of
https://cplusplus.github.io/LWG/issue4477
The PR complains that one can't successfully throw from constructor
in placement new in a constant expression and catch that exception
later on.  The problem is while P2747R2 made placement ::operator new
and ::operator new[] constexpr, when the ctor throws it invokes also
these weird placement ::operator delete and ::operator delete[]
which intentionally perform no action, and those weren't constexpr,
so constant expression evaluation failed.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2025-11-19  Jakub Jelinek  <[email protected]>

        PR libstdc++/122671
        * libsupc++/new (::operator delete, ::operator delete[]): Implement
        proposed LWG4477 resolution.  Use _GLIBCXX_PLACEMENT_CONSTEXPR for
        placement operator deletes.

        * g++.dg/cpp26/constexpr-eh17.C: New test.

--- libstdc++-v3/libsupc++/new.jj       2025-09-06 11:18:17.987614541 +0200
+++ libstdc++-v3/libsupc++/new  2025-11-18 15:40:39.752001426 +0100
@@ -229,15 +229,16 @@ void* operator new[](std::size_t, void*
   _GLIBCXX_TXN_SAFE _GLIBCXX_USE_NOEXCEPT
 { return __p; }
 
-#undef _GLIBCXX_PLACEMENT_CONSTEXPR
-
 // Default placement versions of operator delete.
-inline void operator delete  (void*, void*)
+_GLIBCXX_PLACEMENT_CONSTEXPR void operator delete  (void*, void*)
   _GLIBCXX_TXN_SAFE _GLIBCXX_USE_NOEXCEPT
 { }
-inline void operator delete[](void*, void*)
+_GLIBCXX_PLACEMENT_CONSTEXPR void operator delete[](void*, void*)
   _GLIBCXX_TXN_SAFE _GLIBCXX_USE_NOEXCEPT
 { }
+
+#undef _GLIBCXX_PLACEMENT_CONSTEXPR
+
 //@}
 } // extern "C++"
 
--- gcc/testsuite/g++.dg/cpp26/constexpr-eh17.C.jj      2025-11-18 
15:08:17.232427900 +0100
+++ gcc/testsuite/g++.dg/cpp26/constexpr-eh17.C 2025-11-18 15:08:12.663492819 
+0100
@@ -0,0 +1,38 @@
+// PR libstdc++/122671
+// { dg-do compile { target c++26 } }
+
+#include <new>
+#include <memory>
+
+consteval auto
+foo ()
+{
+  struct E {};
+  struct O
+  {
+    constexpr explicit O (int x)
+    {
+      if (x < 0) { throw E {}; }
+    }
+  };
+
+  try
+  {
+    struct S
+    {
+      O *s;
+      constexpr S () : s { std::allocator <O> {}.allocate (1) } {}
+      constexpr ~S () { std::allocator <O> {}.deallocate (s, 1); }
+    };
+
+    auto s = S {};
+
+    ::new (s.s) O { -1 };
+  }
+  catch (E &)
+  {
+  }
+  return true;
+}
+
+static_assert (foo ());

        Jakub

Reply via email to