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
