https://gcc.gnu.org/g:40a990c8b512fd25bd7d7b45aa509e1880d77209

commit r15-2076-g40a990c8b512fd25bd7d7b45aa509e1880d77209
Author: Nina Ranns <dinka.ra...@gmail.com>
Date:   Thu Jul 11 17:47:34 2024 +0100

    c++/contracts: ICE in C++ Contracts with '-fno-exceptions' [PR 110159]
    
    We currently only initialise terminate_fn if exceptions are enabled.
    However, contract handling requires terminate_fn when building the
    contract because a contract failure may result in std::terminate call
    regardless of whether the exceptions are enabled. Refactored
    init_exception_processing to extract the initialisation of
    terminate_fn. New function init_terminate_fn added that initialises
    terminate_fn if it hasn't already been initialised. Call to terminate_fn
    added in cxx_init_decl_processing if contracts are enabled.
    
            PR c++/110159
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (init_terminate_fn): Declaration of a new function.
            * decl.cc (cxx_init_decl_processing): If contracts are enabled,
            call init_terminate_fn.
            * except.cc (init_exception_processing): Function refactored to
            call init_terminate_fn.
            (init_terminate_fn): Added new function that initializes
            terminate_fn if it hasn't already been initialised.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/contracts/pr110159.C: New test.
    
    Signed-off-by: Nina Ranns <dinka.ra...@gmail.com>

Diff:
---
 gcc/cp/cp-tree.h                          |  1 +
 gcc/cp/decl.cc                            |  3 +++
 gcc/cp/except.cc                          | 31 +++++++++++++++++++++++--------
 gcc/testsuite/g++.dg/contracts/pr110159.C | 27 +++++++++++++++++++++++++++
 4 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c1a371bc7218..c6f102564ce0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7194,6 +7194,7 @@ extern void qualified_name_lookup_error           (tree, 
tree, tree,
                                                 location_t);
 
 /* in except.cc */
+extern void init_terminate_fn                  (void);
 extern void init_exception_processing          (void);
 extern tree expand_start_catch_block           (tree);
 extern void expand_end_catch_block             (void);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index d64b993329dd..66e8a973cce5 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -5172,6 +5172,9 @@ cxx_init_decl_processing (void)
   if (flag_exceptions)
     init_exception_processing ();
 
+  if (flag_contracts)
+    init_terminate_fn ();
+
   if (modules_p ())
     init_modules (parse_in);
 
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index 1eb3ba53b4b5..3c69ab695028 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -42,6 +42,28 @@ static tree wrap_cleanups_r (tree *, int *, void *);
 static bool is_admissible_throw_operand_or_catch_parameter (tree, bool,
                                                            tsubst_flags_t);
 
+/* Initializes the node to std::terminate, which is used in exception
+  handling and contract handling.  */
+
+void
+init_terminate_fn (void)
+{
+  if (terminate_fn)
+    return;
+
+  tree tmp;
+
+  push_nested_namespace (std_node);
+  tmp = build_function_type_list (void_type_node, NULL_TREE);
+  terminate_fn = build_cp_library_fn_ptr ("terminate", tmp,
+                                          ECF_NOTHROW | ECF_NORETURN
+                                          | ECF_COLD);
+  gcc_checking_assert (TREE_THIS_VOLATILE (terminate_fn)
+                      && TREE_NOTHROW (terminate_fn));
+  pop_nested_namespace (std_node);
+
+}
+
 /* Sets up all the global eh stuff that needs to be initialized at the
    start of compilation.  */
 
@@ -51,14 +73,7 @@ init_exception_processing (void)
   tree tmp;
 
   /* void std::terminate (); */
-  push_nested_namespace (std_node);
-  tmp = build_function_type_list (void_type_node, NULL_TREE);
-  terminate_fn = build_cp_library_fn_ptr ("terminate", tmp,
-                                          ECF_NOTHROW | ECF_NORETURN
-                                          | ECF_COLD);
-  gcc_checking_assert (TREE_THIS_VOLATILE (terminate_fn)
-                      && TREE_NOTHROW (terminate_fn));
-  pop_nested_namespace (std_node);
+  init_terminate_fn ();
 
   /* void __cxa_call_unexpected(void *); */
   tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
diff --git a/gcc/testsuite/g++.dg/contracts/pr110159.C 
b/gcc/testsuite/g++.dg/contracts/pr110159.C
new file mode 100644
index 000000000000..614b466b1a39
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/pr110159.C
@@ -0,0 +1,27 @@
+// check that contracts can be handled even when exceptions are disabled
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts -fno-exceptions " }
+// { dg-output "contract violation in function f at .* a<5" }
+
+#include <exception>
+#include <cstdlib>
+
+int terminate_called = 0;
+void my_term()
+{
+    std::exit(0);
+}
+
+
+void f(int a)
+  [[ pre : a<5 ]]
+  {
+  }
+
+int
+main ()
+{
+  std::set_terminate (my_term);
+  f(3);
+  f(10);
+}

Reply via email to