public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/c++-contracts] c++: build contract_violation object directly
@ 2022-11-01 11:43 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2022-11-01 11:43 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:6f047a4540277fe70d0fe73b2e2db24659093ec5

commit 6f047a4540277fe70d0fe73b2e2db24659093ec5
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Oct 27 10:31:28 2022 -0400

    c++: build contract_violation object directly
    
    The __on_contract_violation function was an awkward library dependency;
    instead, let's build up a temporary contract_violation and call
    handle_contract_violation directly.
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (enum cp_tree_index): Remove
            CPTI_ON_CONTRACT_VIOLATION*, add CPTI_PSEUDO_CONTRACT_VIOLATION.
            (pseudo_contract_violation_type): New.
            (on_contract_violation_fn)
            (on_contract_violation_never_fn): Remove.
            * contracts.cc (get_pseudo_contract_violation_type): New.
            (build_contract_violation): New.
            (declare_handle_contract_violation): New.
            (build_contract_handler_call): Use them.
            (build_contract_check): Call terminate here.
            (init_contract_processing): Remove.
            * decl.cc (cxx_init_decl_processing): Don't call it.
    
    libstdc++-v3/ChangeLog:
    
            * src/experimental/contract.cc (__on_contract_violation): Remove.
            * include/experimental/contract: Remove its comment.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/contracts/contracts14.C
            * g++.dg/contracts/contracts15.C: Remove __on_contract_violation.

Diff:
---
 gcc/cp/cp-tree.h                                 |   7 +-
 gcc/cp/contracts.cc                              | 214 ++++++++++++++++-------
 gcc/cp/decl.cc                                   |   3 -
 gcc/testsuite/g++.dg/contracts/contracts-post6.C |   3 +-
 gcc/testsuite/g++.dg/contracts/contracts14.C     |  35 +---
 gcc/testsuite/g++.dg/contracts/contracts15.C     |  17 +-
 libstdc++-v3/src/experimental/contract.cc        |  30 +---
 libstdc++-v3/include/experimental/contract       |  15 +-
 8 files changed, 171 insertions(+), 153 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 48d2fd15f5d..11ac082c89f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -233,8 +233,7 @@ enum cp_tree_index
     CPTI_DSO_HANDLE,
     CPTI_DCAST,
 
-    CPTI_ON_CONTRACT_VIOLATION,
-    CPTI_ON_CONTRACT_VIOLATION_NEVER,
+    CPTI_PSEUDO_CONTRACT_VIOLATION,
 
     CPTI_SOURCE_LOCATION_IMPL,
 
@@ -270,6 +269,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define current_aggr			cp_global_trees[CPTI_AGGR_TAG]
 /* std::align_val_t */
 #define align_type_node			cp_global_trees[CPTI_ALIGN_TYPE]
+#define pseudo_contract_violation_type	cp_global_trees[CPTI_PSEUDO_CONTRACT_VIOLATION]
 
 /* We cache these tree nodes so as to call get_identifier less frequently.
    For identifiers for functions, including special member functions such
@@ -372,9 +372,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define throw_fn			cp_global_trees[CPTI_THROW_FN]
 #define rethrow_fn			cp_global_trees[CPTI_RETHROW_FN]
 
-#define on_contract_violation_fn        cp_global_trees[CPTI_ON_CONTRACT_VIOLATION]
-#define on_contract_violation_never_fn  cp_global_trees[CPTI_ON_CONTRACT_VIOLATION_NEVER]
-
 /* The type of the function-pointer argument to "__cxa_atexit" (or
    "std::atexit", if "__cxa_atexit" is not being used).  */
 #define atexit_fn_ptr_type_node         cp_global_trees[CPTI_ATEXIT_FN_PTR_TYPE]
diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index 2fa7023f76b..214be7c671f 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -34,7 +34,7 @@ along with GCC; see the file COPYING3.  If not see
    is transformed into:
 
      if (!(v > 0)) {
-       __on_contract_violation (true, // continue_
+       handle_contract_violation(__pseudo_contract_violation{
 	 5, // line_number,
 	 "main.cpp", // file_name,
 	 "fun", // function_name,
@@ -42,21 +42,18 @@ along with GCC; see the file COPYING3.  If not see
 	 "default", // assertion_level,
 	 "default", // assertion_role,
 	 MAYBE_CONTINUE, // continuation_mode
-	 );
+       });
+       terminate (); // if NEVER_CONTINUE
      }
 
-   Here, __on_contract_violation is a shim used to actually construct the
-   std::contract_violation and call the installed handler, finally terminating
-   if the contract should not continue on violation. This prevents requiring
-   including <contract> and simplifies building the call.
+   We use an internal type with the same layout as contract_violation rather
+   than try to define the latter internally and somehow deal with its actual
+   definition in a TU that includes <contract>.
 
-   FIXME the overhead would be lower if we write out the contract_violation
-   object statically and pass it directly to the handler.  Though the current
-   way is more tolerant of layout changes, so maybe leave it alone until the
-   feature is more mature.
+   ??? is it worth factoring out the calls to handle_contract_violation and
+   terminate into a local function?
 
-   Assumed contracts have a similar transformation that results the body of the
-   if being __builtin_unreachable ();
+   Assumed contracts use the same implementation as C++23 [[assume]].
 
    Parsing of pre and post contract conditions need to be deferred when the
    contracts are attached to a member function. The postcondition identifier
@@ -163,6 +160,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "tree-iterator.h"
 #include "print-tree.h"
+#include "stor-layout.h"
 
 const int max_custom_roles = 32;
 static contract_role contract_build_roles[max_custom_roles] = {
@@ -1581,43 +1579,160 @@ get_contract_role_name (tree contract)
   return "default";
 }
 
-static void
-build_contract_handler_call (tree contract,
-			     contract_continuation cmode)
+/* Build a layout-compatible internal version of std::contract_violation.  */
+
+static tree
+get_pseudo_contract_violation_type ()
 {
-  const char *level = get_contract_level_name (contract);
-  const char *role = get_contract_role_name (contract);
-  tree comment = CONTRACT_COMMENT (contract);
+  if (!pseudo_contract_violation_type)
+    {
+      /* Must match <contract>:
+	 class contract_violation {
+	   uint_least32_t _M_line;
+	   const char* _M_file;
+	   const char* _M_function;
+	   const char* _M_comment;
+	   const char* _M_level;
+	   const char* _M_role;
+	   signed char _M_continue;
+	 If this changes, also update the initializer in
+	 build_contract_violation.  */
+      const tree types[] = { uint_least32_type_node,
+			     const_string_type_node,
+			     const_string_type_node,
+			     const_string_type_node,
+			     const_string_type_node,
+			     const_string_type_node,
+			     signed_char_type_node };
+      tree fields = NULL_TREE;
+      for (tree type : types)
+	{
+	  /* finish_builtin_struct wants fieldss chained in reverse.  */
+	  tree next = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+				  NULL_TREE, type);
+	  DECL_CHAIN (next) = fields;
+	  fields = next;
+	}
+      iloc_sentinel ils (input_location);
+      input_location = BUILTINS_LOCATION;
+      pseudo_contract_violation_type = make_class_type (RECORD_TYPE);
+      finish_builtin_struct (pseudo_contract_violation_type,
+			     "__pseudo_contract_violation",
+			     fields, NULL_TREE);
+      CLASSTYPE_AS_BASE (pseudo_contract_violation_type)
+	= pseudo_contract_violation_type;
+      DECL_CONTEXT (TYPE_NAME (pseudo_contract_violation_type))
+	= FROB_CONTEXT (global_namespace);
+      TREE_PUBLIC (TYPE_NAME (pseudo_contract_violation_type)) = true;
+      CLASSTYPE_LITERAL_P (pseudo_contract_violation_type) = true;
+      CLASSTYPE_LAZY_COPY_CTOR (pseudo_contract_violation_type) = true;
+      xref_basetypes (pseudo_contract_violation_type, /*bases=*/NULL_TREE);
+      pseudo_contract_violation_type
+	= cp_build_qualified_type (pseudo_contract_violation_type,
+				   TYPE_QUAL_CONST);
+    }
+  return pseudo_contract_violation_type;
+}
 
+/* Return a VAR_DECL to pass to handle_contract_violation.  */
+
+static tree
+build_contract_violation (tree contract, contract_continuation cmode)
+{
   expanded_location loc = expand_location (EXPR_LOCATION (contract));
-
-  tree continue_mode = build_int_cst (boolean_type_node, cmode != NEVER_CONTINUE);
-  tree line_number = build_int_cst (integer_type_node, loc.line);
-  tree file_name = build_string_literal (strlen (loc.file) + 1, loc.file);
-  const char *function_name_str =
+  const char *function =
     TREE_CODE (contract) == ASSERTION_STMT
       || DECL_CONSTRUCTOR_P (current_function_decl)
       || DECL_DESTRUCTOR_P (current_function_decl)
     ? current_function_name ()
     : fndecl_name (DECL_ORIGINAL_FN (current_function_decl));
-  tree function_name = build_string_literal (strlen (function_name_str) + 1,
-					     function_name_str);
-  tree level_str = build_string_literal (strlen (level) + 1, level);
-  tree role_str = build_string_literal (strlen (role) + 1, role);
+  const char *level = get_contract_level_name (contract);
+  const char *role = get_contract_role_name (contract);
 
-  /* FIXME: Do we want a string for this?.  */
-  tree continuation = build_int_cst (integer_type_node, cmode);
+  /* Must match the type layout in get_pseudo_contract_violation_type.  */
+  tree ctor = build_constructor_va
+    (init_list_type_node, 7,
+     NULL_TREE, build_int_cst (uint_least32_type_node, loc.line),
+     NULL_TREE, build_string_literal (loc.file),
+     NULL_TREE, build_string_literal (function),
+     NULL_TREE, CONTRACT_COMMENT (contract),
+     NULL_TREE, build_string_literal (level),
+     NULL_TREE, build_string_literal (role),
+     NULL_TREE, build_int_cst (signed_char_type_node, cmode));
 
-  tree violation_fn;
-  if (cmode == MAYBE_CONTINUE)
-    violation_fn = on_contract_violation_fn;
+  ctor = finish_compound_literal (get_pseudo_contract_violation_type (),
+				  ctor, tf_none);
+  protected_set_expr_location (ctor, EXPR_LOCATION (contract));
+  return ctor;
+}
+
+/* Return handle_contract_violation(), declaring it if needed.  */
+
+static tree
+declare_handle_contract_violation ()
+{
+  tree fnname = get_identifier ("handle_contract_violation");
+  tree viol_name = get_identifier ("contract_violation");
+  tree l = lookup_qualified_name (global_namespace, fnname,
+				  LOOK_want::HIDDEN_FRIEND);
+  for (tree f: lkp_range (l))
+    if (TREE_CODE (f) == FUNCTION_DECL)
+	{
+	  tree parms = TYPE_ARG_TYPES (TREE_TYPE (f));
+	  if (remaining_arguments (parms) != 1)
+	    continue;
+	  tree parmtype = non_reference (TREE_VALUE (parms));
+	  if (CLASS_TYPE_P (parmtype)
+	      && TYPE_IDENTIFIER (parmtype) == viol_name)
+	    return f;
+	}
+
+  tree id_exp = get_identifier ("experimental");
+  tree ns_exp = lookup_qualified_name (std_node, id_exp);
+
+  tree violation = error_mark_node;
+  if (TREE_CODE (ns_exp) == NAMESPACE_DECL)
+    violation = lookup_qualified_name (ns_exp, viol_name,
+				       LOOK_want::TYPE
+				       |LOOK_want::HIDDEN_FRIEND);
+
+  if (TREE_CODE (violation) == TYPE_DECL)
+    violation = TREE_TYPE (violation);
   else
-    violation_fn = on_contract_violation_never_fn;
-  tree call = build_call_n (violation_fn, 8, continue_mode, line_number,
-			    file_name, function_name, comment,
-			    level_str, role_str,
-			    continuation);
+    {
+      push_nested_namespace (std_node);
+      push_namespace (id_exp, /*inline*/false);
+      violation = make_class_type (RECORD_TYPE);
+      create_implicit_typedef (viol_name, violation);
+      DECL_SOURCE_LOCATION (TYPE_NAME (violation)) = BUILTINS_LOCATION;
+      DECL_CONTEXT (TYPE_NAME (violation)) = current_namespace;
+      pushdecl_namespace_level (TYPE_NAME (violation), /*hidden*/true);
+      pop_namespace ();
+      pop_nested_namespace (std_node);
+    }
 
+  tree argtype = cp_build_qualified_type (violation, TYPE_QUAL_CONST);
+  argtype = cp_build_reference_type (argtype, /*rval*/false);
+  tree fntype = build_function_type_list (void_type_node, argtype, NULL_TREE);
+
+  push_nested_namespace (global_namespace);
+  tree fn = build_cp_library_fn_ptr ("handle_contract_violation", fntype,
+				     ECF_COLD);
+  pushdecl_namespace_level (fn, /*hiding*/true);
+  pop_nested_namespace (global_namespace);
+
+  return fn;
+}
+
+/* Build the call to handle_contract_violation for CONTRACT.  */
+
+static void
+build_contract_handler_call (tree contract,
+			     contract_continuation cmode)
+{
+  tree violation = build_contract_violation (contract, cmode);
+  tree violation_fn = declare_handle_contract_violation ();
+  tree call = build_call_n (violation_fn, 1, build_address (violation));
   finish_expr_stmt (call);
 }
 
@@ -1683,6 +1798,8 @@ build_contract_check (tree contract)
     }
 
   build_contract_handler_call (contract, cmode);
+  if (cmode == NEVER_CONTINUE)
+    finish_expr_stmt (build_call_a (terminate_fn, 0, nullptr));
 
   finish_then_clause (if_stmt);
   tree scope = IF_SCOPE (if_stmt);
@@ -1970,27 +2087,4 @@ apply_postcondition_to_return (tree expr)
   return call;
 }
 
-/* Set up built-ins for contracts.  */
-
-void
-init_contract_processing (void)
-{
-  /* std::contract_violation */
-  tree tmp = build_function_type_list (integer_type_node,
-				  boolean_type_node,
-				  integer_type_node,
-				  const_string_type_node,
-				  const_string_type_node,
-				  const_string_type_node,
-				  const_string_type_node,
-				  const_string_type_node,
-				  integer_type_node,
-				  NULL_TREE);
-  on_contract_violation_fn =
-    build_cp_library_fn_ptr ("__on_contract_violation", tmp, ECF_COLD);
-  on_contract_violation_never_fn =
-    build_cp_library_fn_ptr ("__on_contract_violation", tmp,
-			     ECF_COLD | ECF_NORETURN);
-}
-
 #include "gt-cp-contracts.h"
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 4423049cd6c..b5e132c09d5 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -5025,9 +5025,6 @@ cxx_init_decl_processing (void)
   if (flag_exceptions)
     init_exception_processing ();
 
-  if (flag_contracts)
-    init_contract_processing ();
-
   if (modules_p ())
     init_modules (parse_in);
 
diff --git a/gcc/testsuite/g++.dg/contracts/contracts-post6.C b/gcc/testsuite/g++.dg/contracts/contracts-post6.C
index dacb97b9ebf..f8246fbc15f 100644
--- a/gcc/testsuite/g++.dg/contracts/contracts-post6.C
+++ b/gcc/testsuite/g++.dg/contracts/contracts-post6.C
@@ -26,4 +26,5 @@ struct S
 void driver()
 {
   S<int> s1(0);
-}
\ No newline at end of file
+  s1.f1(2);
+}
diff --git a/gcc/testsuite/g++.dg/contracts/contracts14.C b/gcc/testsuite/g++.dg/contracts/contracts14.C
index 4e81155ba11..55208dbc0a1 100644
--- a/gcc/testsuite/g++.dg/contracts/contracts14.C
+++ b/gcc/testsuite/g++.dg/contracts/contracts14.C
@@ -5,16 +5,6 @@
 #include <iostream>
 #include <experimental/contract>
 
-int
-__on_contract_violation (bool continue_,
-        int line_number,
-        const char * file_name,
-        const char * function_name,
-        const char * comment,
-        const char * assertion_level,
-        const char * assertion_role,
-        int continuation_mode);
-
 void handle_contract_violation(const std::experimental::contract_violation &violation) {
   std::cerr << "custom std::handle_contract_violation called:"
     << " " << violation.line_number()
@@ -29,11 +19,6 @@ int fun() {
   return 0;
 }
 
-int fun2() {
-  __on_contract_violation(true, 1, "T1", "T2", "T3", "T4", "T5", 1);
-  return 1;
-}
-
 int fun3() {
   fun();
   return 2;
@@ -47,12 +32,6 @@ int main(int, char**) {
     std::cerr << "synth caught direct: " << ex << std::endl;
   }
 
-  try {
-    fun2();
-  } catch(int &ex) {
-    std::cerr << "caught lib direct: " << ex << std::endl;
-  }
-
   try {
     fun();
   } catch(int &ex) {
@@ -69,13 +48,11 @@ int main(int, char**) {
   return 0;
 }
 
-// { dg-output "custom std::handle_contract_violation called: 45 .*/contracts14.C(\n|\r\n|\r)*" }
-// { dg-output "synth caught direct: -45(\n|\r\n|\r)*" }
-// { dg-output "custom std::handle_contract_violation called: 1 T1(\n|\r\n|\r)*" }
-// { dg-output "caught lib direct: -1(\n|\r\n|\r)*" }
-// { dg-output "custom std::handle_contract_violation called: 28 .*/contracts14.C(\n|\r\n|\r)*" }
-// { dg-output "synth caught indirect: -28(\n|\r\n|\r)*" }
-// { dg-output "custom std::handle_contract_violation called: 28 .*/contracts14.C(\n|\r\n|\r)*" }
-// { dg-output "synth caught double indirect: -28(\n|\r\n|\r)*" }
+// { dg-output "custom std::handle_contract_violation called: 30 .*/contracts14.C(\n|\r\n|\r)*" }
+// { dg-output "synth caught direct: -30(\n|\r\n|\r)*" }
+// { dg-output "custom std::handle_contract_violation called: 18 .*/contracts14.C(\n|\r\n|\r)*" }
+// { dg-output "synth caught indirect: -18(\n|\r\n|\r)*" }
+// { dg-output "custom std::handle_contract_violation called: 18 .*/contracts14.C(\n|\r\n|\r)*" }
+// { dg-output "synth caught double indirect: -18(\n|\r\n|\r)*" }
 // { dg-output "end main" }
 
diff --git a/gcc/testsuite/g++.dg/contracts/contracts15.C b/gcc/testsuite/g++.dg/contracts/contracts15.C
index af3e539e1ce..35bb5223a70 100644
--- a/gcc/testsuite/g++.dg/contracts/contracts15.C
+++ b/gcc/testsuite/g++.dg/contracts/contracts15.C
@@ -29,11 +29,6 @@ int fun() noexcept {
   return 0;
 }
 
-int fun2() {
-  __on_contract_violation(true, 1, "T1", "T2", "T3", "T4", "T5", 1);
-  return 1;
-}
-
 int fun3() {
   fun();
   return 2;
@@ -47,12 +42,6 @@ int main(int, char**) {
     std::cerr << "synth caught direct: " << ex << std::endl;
   }
 
-  try {
-    fun2();
-  } catch(int &ex) {
-    std::cerr << "caught lib direct: " << ex << std::endl;
-  }
-
   try {
     fun();
   } catch(int &ex) {
@@ -69,10 +58,8 @@ int main(int, char**) {
   return 0;
 }
 
-// { dg-output "custom std::handle_contract_violation called: 45 .*/contracts15.C(\n|\r\n|\r)*" }
-// { dg-output "synth caught direct: -45(\n|\r\n|\r)*" }
-// { dg-output "custom std::handle_contract_violation called: 1 T1(\n|\r\n|\r)*" }
-// { dg-output "caught lib direct: -1(\n|\r\n|\r)*" }
+// { dg-output "custom std::handle_contract_violation called: 40 .*/contracts15.C(\n|\r\n|\r)*" }
+// { dg-output "synth caught direct: -40(\n|\r\n|\r)*" }
 // { dg-output "custom std::handle_contract_violation called: 28 .*/contracts15.C(\n|\r\n|\r)*" }
 // { dg-output "terminate called after throwing an instance of .int.(\n|\r\n|\r)*" }
 // { dg-shouldfail "throwing in noexcept" }
diff --git a/libstdc++-v3/src/experimental/contract.cc b/libstdc++-v3/src/experimental/contract.cc
index ddb1df47cb5..f1b6eb3a58a 100644
--- a/libstdc++-v3/src/experimental/contract.cc
+++ b/libstdc++-v3/src/experimental/contract.cc
@@ -1,5 +1,5 @@
 // -*- C++ -*- std::experimental::contract_violation and friends
-// Copyright (C) 1994-2018 Free Software Foundation, Inc.
+// Copyright (C) 1994-2022 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -24,7 +24,6 @@
 
 #include <experimental/contract>
 #include <iostream>
-#include <cstdlib>
 
 __attribute__ ((weak)) void
 handle_contract_violation (const std::experimental::contract_violation &violation)
@@ -39,30 +38,3 @@ handle_contract_violation (const std::experimental::contract_violation &violatio
     << " " << (int)violation.continuation_mode()
     << std::endl;
 }
-
-// We take POD types here to make synthesis easier
-int
-__on_contract_violation (bool continue_,
-			 int line_number,
-			 const char *file_name,
-			 const char *function_name,
-			 const char *comment,
-			 const char *assertion_level,
-			 const char *assertion_role,
-			 int continuation_mode)
-{
-  using cvmc = std::experimental::contract_violation_continuation_mode;
-  std::experimental::contract_violation violation (line_number,
-				     file_name,
-				     function_name,
-				     comment,
-				     assertion_level,
-				     assertion_role,
-				     static_cast<cvmc>(continuation_mode));
-  handle_contract_violation (violation);
-
-  if (!continue_)
-    std::abort ();
-
-  return 0;
-}
diff --git a/libstdc++-v3/include/experimental/contract b/libstdc++-v3/include/experimental/contract
index dc58a38a343..fb03f116847 100644
--- a/libstdc++-v3/include/experimental/contract
+++ b/libstdc++-v3/include/experimental/contract
@@ -24,7 +24,6 @@
 // <http://www.gnu.org/licenses/>.
 
 // FIXME string_view vs. freestanding
-// FIXME remove on_contract_violation?
 
 /** @file contract
  *  This is a Standard C++ Library header.
@@ -59,13 +58,8 @@ namespace experimental
     const char* _M_comment;
     const char* _M_level;
     const char* _M_role;
-    contract_violation_continuation_mode _M_continue;
+    signed char _M_continue;
   public:
-    contract_violation (int __l, const char* __f, const char* __fn,
-			const char* __c, const char* __lv, const char *__r,
-                        contract_violation_continuation_mode __m)
-      : _M_line(__l), _M_file(__f), _M_function(__fn), _M_comment(__c),
-	_M_level(__lv), _M_role(__r), _M_continue(__m) { }
     // From N4820
     uint_least32_t line_number() const noexcept { return _M_line; }
     string_view file_name() const noexcept { return _M_file; }
@@ -75,7 +69,7 @@ namespace experimental
     // From P1332
     string_view assertion_role() const noexcept { return _M_role; }
     contract_violation_continuation_mode continuation_mode() const noexcept
-    { return _M_continue; }
+    { return static_cast<contract_violation_continuation_mode>(_M_continue); }
   };
 
 } // namespace experimental
@@ -83,9 +77,8 @@ namespace experimental
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
-  //void handle_contract_violation (const contract_violation &);
-
-  //int on_contract_violation (bool, int, const char *, const char *, const char *, const char *, const char *, int);
+// To override the contract violation handler, define
+//void ::handle_contract_violation (const std::experimental::contract_violation &);
 
 #endif // C++17
 #endif // _GLIBCXX_CONTRACT

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-11-01 11:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-01 11:43 [gcc/devel/c++-contracts] c++: build contract_violation object directly Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).