[gcc r17-2482] c++: Implement C++29 P3424R2 - Deallocation Functions with Throwing Exception Specification Are Ill-

Jakub Jelinek via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:57ecb9897a096418ec3335bc0d18ec590e100396

commit r17-2482-g57ecb9897a096418ec3335bc0d18ec590e100396
Author: Jakub Jelinek <[email protected]>
Date:   Fri Jul 17 09:58:00 2026 +0200

    c++: Implement C++29 P3424R2 - Deallocation Functions with Throwing Exception Specification Are Ill-formed [PR125833]
    
    The following patch attempts to implement the C++29 P3424R2
    Deallocation Functions with Throwing Exception Specification Are Ill-formed
    paper by diagnosing those cases in grokfndecl, maybe_instantiate_noexcept and
    cp_parser_class_specifier.
    
    2026-07-17  Jakub Jelinek  <[email protected]>
    
            PR c++/125833
            * cp-tree.h: Implement C++29 P3424R2 - Deallocation Functions with
            Throwing Exception Specification Are Ill-formed.
            (maybe_diagnose_deallocation_noexcept_false): Declare.
            * decl.cc (maybe_diagnose_deallocation_noexcept_false): New function.
            (grokfndecl): Call it.
            * pt.cc (maybe_instantiate_noexcept): Likewise.
            * parser.cc (cp_parser_class_specifier): Likewise.
    
            * g++.dg/cpp0x/dealloc2.C: Expect extra diagnostics in C++29.
            * g++.dg/cpp29/dealloc1.C: New test.
    
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/cp-tree.h                      |  1 +
 gcc/cp/decl.cc                        | 23 ++++++++++++++++++
 gcc/cp/parser.cc                      |  4 ++++
 gcc/cp/pt.cc                          |  4 ++++
 gcc/testsuite/g++.dg/cpp0x/dealloc2.C |  3 ++-
 gcc/testsuite/g++.dg/cpp29/dealloc1.C | 45 +++++++++++++++++++++++++++++++++++
 6 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9271209ba2eb..c73b42ed44ff 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7651,6 +7651,7 @@ extern tree start_decl				(const cp_declarator *, cp_decl_specifier_seq *, int,
 extern void start_decl_1			(tree, bool);
 extern bool check_array_initializer		(tree, tree, tree);
 extern void omp_declare_variant_finalize	(tree, tree);
+extern void maybe_diagnose_deallocation_noexcept_false (tree);
 struct cp_decomp { tree decl; unsigned int count; };
 extern void cp_finish_decl			(tree, tree, bool, tree, int, cp_decomp * = nullptr);
 extern tree lookup_decomp_type			(tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index d10290752e7b..639eb85c0760 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -9430,6 +9430,25 @@ omp_declare_variant_finalize (tree decl, tree attr)
     }
 }
 
+/* [basic.stc.dynamic.deallocation]/3 - A deallocation function shall not
+   have a potentially throwing exception specification.  */
+
+void
+maybe_diagnose_deallocation_noexcept_false (tree decl)
+{
+  if (cxx_dialect >= cxx29
+      && DECL_NAME (decl)
+      && IDENTIFIER_NEWDEL_OP_P (DECL_NAME (decl))
+      && !IDENTIFIER_NEW_OP_P (DECL_NAME (decl)))
+    {
+      tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
+      if (spec && spec == noexcept_false_spec)
+	error_at (DECL_SOURCE_LOCATION (decl),
+		  "deallocation function %qD declared possibly throwing",
+		  decl);
+    }
+}
+
 static void cp_maybe_mangle_decomp (tree, cp_decomp *);
 
 /* Finish processing of a declaration;
@@ -12621,6 +12640,10 @@ grokfndecl (tree ctype,
 	}
     }
 
+  /* [basic.stc.dynamic.deallocation]/3 - A deallocation function shall not
+     have a potentially throwing exception specification.  */
+  maybe_diagnose_deallocation_noexcept_false (decl);
+
   /* Caller will do the rest of this.  */
   if (check < 0)
     {
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f455092b989e..3f042bec1c66 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -30135,6 +30135,10 @@ cp_parser_class_specifier (cp_parser* parser)
 
 	  /* Remove any template parameters from the symbol table.  */
 	  maybe_end_member_template_processing ();
+
+	  /* [basic.stc.dynamic.deallocation]/3 - A deallocation function
+	     shall not have a potentially throwing exception specification.  */
+	  maybe_diagnose_deallocation_noexcept_false (decl);
 	}
       vec_safe_truncate (unparsed_noexcepts, 0);
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 1fe94a863102..1290db45e182 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -28802,6 +28802,10 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
   if (orig_fn)
     TREE_TYPE (orig_fn) = TREE_TYPE (fn);
 
+  /* [basic.stc.dynamic.deallocation]/3 - A deallocation function shall not
+     have a potentially throwing exception specification.  */
+  maybe_diagnose_deallocation_noexcept_false (fn);
+
   return true;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/dealloc2.C b/gcc/testsuite/g++.dg/cpp0x/dealloc2.C
index 5a0a89257b7a..75b833382e98 100644
--- a/gcc/testsuite/g++.dg/cpp0x/dealloc2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/dealloc2.C
@@ -3,6 +3,7 @@
 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" }
+// { dg-error "deallocation function 'void operator delete\\\(void\\\*, A\\\)' declared possibly throwing" "" { target c++29 } .-1 }
 struct B {};
-void operator delete (void *, B) noexcept (false);
+void operator delete (void *, B) noexcept (false);	// { dg-error "deallocation function 'void operator delete\\\(void\\\*, B\\\)' declared possibly throwing" "" { target c++29 } }
 void operator delete (void *, B);			// { dg-error "declaration of 'void operator delete\\\(void\\\*, B\\\) noexcept' has a different exception specifier" }
diff --git a/gcc/testsuite/g++.dg/cpp29/dealloc1.C b/gcc/testsuite/g++.dg/cpp29/dealloc1.C
new file mode 100644
index 000000000000..cf39a68830d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp29/dealloc1.C
@@ -0,0 +1,45 @@
+// P3424R2 - Deallocation Functions with Throwing Exception Specification Are Ill-formed
+// { dg-do compile { target c++11 } }
+
+struct A {};
+struct B {};
+void operator delete (void *, A) noexcept (false);	// { dg-error "deallocation function 'void operator delete\\\(void\\\*, A\\\)' declared possibly throwing" "" { target c++29 } }
+void operator delete (void *, B) noexcept (false) {}	// { dg-error "deallocation function 'void operator delete\\\(void\\\*, B\\\)' declared possibly throwing" "" { target c++29 } }
+void operator delete[] (void *, A) noexcept (false);	// { dg-error "deallocation function 'void operator delete \\\[\\\]\\\(void\\\*, A\\\)' declared possibly throwing" "" { target c++29 } }
+void operator delete[] (void *, B) noexcept (false) {}	// { dg-error "deallocation function 'void operator delete \\\[\\\]\\\(void\\\*, B\\\)' declared possibly throwing" "" { target c++29 } }
+template <bool T, bool U>
+struct C {
+  static void operator delete (void *) noexcept (T);	// { dg-error "deallocation function 'static void C<T, U>::operator delete\\\(void\\\*\\\) \\\[with bool T = false; bool U = true\\\]' declared possibly throwing" "" { target c++29 } }
+  static void operator delete[] (void *) noexcept (T);	// { dg-error "deallocation function 'static void C<T, U>::operator delete \\\[\\\]\\\(void\\\*\\\) \\\[with bool T = false; bool U = true\\\]' declared possibly throwing" "" { target c++29 } }
+};
+template <bool T, bool U>
+struct D {
+  static void operator delete (void *) noexcept (T) {}	// { dg-error "deallocation function 'static void D<T, U>::operator delete\\\(void\\\*\\\) \\\[with bool T = false; bool U = true\\\]' declared possibly throwing" "" { target c++29 } }
+  static void operator delete[] (void *) noexcept (T) {}// { dg-error "deallocation function 'static void D<T, U>::operator delete \\\[\\\]\\\(void\\\*\\\) \\\[with bool T = false; bool U = true\\\]' declared possibly throwing" "" { target c++29 } }
+};
+C <false, false> a;
+C <true, false> b;
+D <false, false> c;
+D <true, false> d;
+auto e = &C <false, true>::operator delete;
+auto f = &C <true, true>::operator delete;
+auto g = &D <false, true>::operator delete;
+auto h = &D <true, true>::operator delete;
+auto i = &C <false, true>::operator delete[];
+auto j = &C <true, true>::operator delete[];
+auto k = &D <false, true>::operator delete[];
+auto l = &D <true, true>::operator delete[];
+struct E {
+  static void operator delete (void *) noexcept (C) {}	// { dg-error "deallocation function 'static void E::operator delete\\\(void\\\*\\\)' declared possibly throwing" "" { target c++29 } }
+  static constexpr bool C = false;
+};
+template <int N>
+struct F {
+  static void operator delete (void *) noexcept (false);	// { dg-error "deallocation function 'static void F<N>::operator delete\\\(void\\\*\\\)' declared possibly throwing" "" { target c++29 } }
+  static void operator delete[] (void *) noexcept (false);	// { dg-error "deallocation function 'static void F<N>::operator delete \\\[\\\]\\\(void\\\*\\\)' declared possibly throwing" "" { target c++29 } }
+};
+template <int N>
+struct G {
+  static void operator delete (void *) noexcept (false) {}	// { dg-error "deallocation function 'static void G<N>::operator delete\\\(void\\\*\\\)' declared possibly throwing" "" { target c++29 } }
+  static void operator delete[] (void *) noexcept (false) {}	// { dg-error "deallocation function 'static void G<N>::operator delete \\\[\\\]\\\(void\\\*\\\)' declared possibly throwing" "" { target c++29 } }
+};
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.