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

Reply via email to