Hi! https://eel.is/c++draft/except.spec#9 says A deallocation function with no explicit noexcept-specifier has a non-throwing exception specification. and something like that is there back to C++11. We only imply noexcept for destructors though (in deduce_noexcept_on_destructor). The following patch does that for operator delete/operator delete[] both for :: namespace ones and for class member functions.
So far tested with GXX_TESTSUITE_STDS=98,11,14,17,20,23,26,29 make -j32 -k check-g++ make -j32 check-target-libstdc++-v3 Ok for trunk if it passes full bootstrap/regtest? 2026-07-13 Jakub Jelinek <[email protected]> * decl.cc (grokfndecl): If raises is NULL_TREE for C++11 deallocation function, use noexcept_true_spec instead. * g++.dg/cpp0x/dealloc1.C: New test. * g++.dg/cpp0x/dealloc2.C: New test. * g++.dg/cpp2a/destroying-delete7.C: New test. * g++.dg/reflect/is_noexcept5.C: New test. * g++.dg/cpp1z/aligned-new3.C (operator delete): Don't expect a warning. --- gcc/cp/decl.cc.jj 2026-07-13 18:35:54.649463659 +0200 +++ gcc/cp/decl.cc 2026-07-13 18:38:06.504832958 +0200 @@ -12166,6 +12166,14 @@ grokfndecl (tree ctype, return NULL_TREE; } + /* [except.spec]/9 - A deallocation function with no explicit noexcept-specifier + has a non-throwing exception specification. */ + if (raises == NULL_TREE + && cxx_dialect >= cxx11 + && IDENTIFIER_NEWDEL_OP_P (declarator) + && !IDENTIFIER_NEW_OP_P (declarator)) + raises = noexcept_true_spec; + type = build_cp_fntype_variant (type, rqual, raises, late_return_type_p); decl = build_lang_decl_loc (location, FUNCTION_DECL, declarator, type); --- gcc/testsuite/g++.dg/cpp0x/dealloc1.C.jj 2026-07-13 18:40:39.847938089 +0200 +++ gcc/testsuite/g++.dg/cpp0x/dealloc1.C 2026-07-13 18:40:51.958788435 +0200 @@ -0,0 +1,8 @@ +// { dg-do compile { target c++11 } } + +struct A {}; +void operator delete (void *, A); +void operator delete (void *, A) noexcept; +struct B {}; +void operator delete (void *, B) noexcept (true); +void operator delete (void *, B); --- gcc/testsuite/g++.dg/cpp0x/dealloc2.C.jj 2026-07-13 18:41:10.751556215 +0200 +++ gcc/testsuite/g++.dg/cpp0x/dealloc2.C 2026-07-13 18:53:34.391367059 +0200 @@ -0,0 +1,8 @@ +// { dg-do compile { target c++11 } } + +struct A {}; +void operator delete (void *, A); +void operator delete (void *, A) noexcept (false); // { dg-error "declaration of 'void operator delete\\\(void\\\*, A\\\) noexcept \\\(false\\\)' has a different exception specifier" } +struct B {}; +void operator delete (void *, B) noexcept (false); +void operator delete (void *, B); // { dg-error "declaration of 'void operator delete\\\(void\\\*, B\\\) noexcept' has a different exception specifier" } --- gcc/testsuite/g++.dg/cpp2a/destroying-delete7.C.jj 2026-07-13 18:56:56.253889575 +0200 +++ gcc/testsuite/g++.dg/cpp2a/destroying-delete7.C 2026-07-13 18:57:11.223707141 +0200 @@ -0,0 +1,10 @@ +// { dg-do compile { target c++20 } } + +#include <new> + +struct T { + ~T () noexcept (false); + static void operator delete (T *, std::destroying_delete_t); +}; +T *p = nullptr; +static_assert (noexcept (delete (p))); --- gcc/testsuite/g++.dg/reflect/is_noexcept5.C.jj 2026-07-13 18:38:36.654460399 +0200 +++ gcc/testsuite/g++.dg/reflect/is_noexcept5.C 2026-07-13 18:39:06.386093002 +0200 @@ -0,0 +1,25 @@ +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } +// Test std::meta::is_noexcept. + +#include <meta> +#include <new> + +struct A { + ~A (); +}; +static_assert (is_noexcept (^^A::~A)); +struct B { + ~B () noexcept (false); +}; +static_assert (!is_noexcept (^^B::~B)); +struct C { + ~C () noexcept (false); + static void operator delete (void *); +}; +static_assert (is_noexcept (^^C::operator delete)); +struct D { + ~D () noexcept (false); + static void operator delete (D *, std::destroying_delete_t); +}; +static_assert (is_noexcept (^^D::operator delete)); --- gcc/testsuite/g++.dg/cpp1z/aligned-new3.C.jj 2026-03-27 10:17:15.600306817 +0100 +++ gcc/testsuite/g++.dg/cpp1z/aligned-new3.C 2026-07-13 19:22:37.478045368 +0200 @@ -13,7 +13,7 @@ void* operator new (std::size_t n, std:: } bool deleted = false; -void operator delete (void *p, std::size_t, std::align_val_t) // { dg-warning "exception specifier" } +void operator delete (void *p, std::size_t, std::align_val_t) { deleted = true; operator delete (p); Jakub
