On 7/13/26 2:00 PM, Jakub Jelinek wrote:
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?
Does this affect mangling?
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