]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++, contracts: Add base P2900R14 contracts support.
authorNina Ranns <dinka.ranns@gmail.com>
Sun, 19 Oct 2025 14:55:52 +0000 (15:55 +0100)
committerIain Sandoe <iain@sandoe.co.uk>
Wed, 28 Jan 2026 01:25:12 +0000 (01:25 +0000)
What we need to do here (and, of course, in the code synthesis
that produces the objects) needs to be interoperable with other
platforms that share ABI.  For the present, this means Itanium
and to interoperate with clang and libc++.

The model we have followed in the development is essentially the
same as the model used for the C++2a edition.  However there is some
concern that the read-only data footprint of this is potentially
high and alternate schemes are in discussion with the clang folks.

Since the layout of the violation object is ABI let's leave this
in experimental until an agreed solution is fixed.

Remove the cxx2a support at the same time, GCC no longer supports
this mode.

libstdc++-v3/ChangeLog:

* include/Makefile.am: Add contract include.
* include/Makefile.in: Regenerate.
* include/bits/version.def: Add ftm for contracts.
* include/bits/version.h: Regenerate.
* include/precompiled/stdc++.h: Add contracts header.
* include/std/source_location: Befriend the contract_violation
class so that we can initialise a source_location from an
existing __impl *.
* src/c++23/std.cc.in: Add contracts support.
* src/experimental/Makefile.am: Add new contract violation
implementation, remove the old one.
* src/experimental/Makefile.in: Regenerate.
* include/experimental/contract: Removed.
* src/experimental/contract.cc: Removed.
* include/std/contracts: New file.
* src/experimental/contract26.cc: New file.
* testsuite/18_support/contracts/invoke_default_cvh.cc: New test.
* testsuite/18_support/contracts/invoke_default_cvh2.cc: New test.

Co-Authored-by: Iain Sandoe <iain@sandoe.co.uk>
Co-Authored-by: Ville Voutilainen <ville.voutilainen@gmail.com>
Signed-off-by: Nina Ranns <dinka.ranns@gmail.com>
15 files changed:
libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/bits/version.def
libstdc++-v3/include/bits/version.h
libstdc++-v3/include/experimental/contract [deleted file]
libstdc++-v3/include/precompiled/stdc++.h
libstdc++-v3/include/std/contracts [new file with mode: 0644]
libstdc++-v3/include/std/source_location
libstdc++-v3/src/c++23/std.cc.in
libstdc++-v3/src/experimental/Makefile.am
libstdc++-v3/src/experimental/Makefile.in
libstdc++-v3/src/experimental/contract.cc [deleted file]
libstdc++-v3/src/experimental/contract26.cc [new file with mode: 0644]
libstdc++-v3/testsuite/18_support/contracts/invoke_default_cvh.cc [new file with mode: 0644]
libstdc++-v3/testsuite/18_support/contracts/invoke_default_cvh2.cc [new file with mode: 0644]

index dd1cc1ceb2f478238bc1b11778ce1b262897111b..e6ac312ac7a4b0c1b13a82ccea769b6f70cd0ac8 100644 (file)
@@ -32,6 +32,7 @@ std_freestanding = \
        ${std_srcdir}/bit \
        ${std_srcdir}/bitset \
        ${std_srcdir}/concepts \
+       ${std_srcdir}/contracts \
        ${std_srcdir}/coroutine \
        ${std_srcdir}/expected \
        ${std_srcdir}/functional \
@@ -801,7 +802,6 @@ experimental_headers = \
        ${experimental_srcdir}/array \
        ${experimental_srcdir}/buffer \
        ${experimental_srcdir}/chrono \
-       ${experimental_srcdir}/contract \
        ${experimental_srcdir}/deque \
        ${experimental_srcdir}/executor \
        ${experimental_srcdir}/forward_list \
index 1dfb40385f5de7acf439003078bfccbbef72e5b2..b2e40c4d313f030757ccc53e837498c80490dcc3 100644 (file)
@@ -393,6 +393,7 @@ std_freestanding = \
        ${std_srcdir}/bit \
        ${std_srcdir}/bitset \
        ${std_srcdir}/concepts \
+       ${std_srcdir}/contracts \
        ${std_srcdir}/coroutine \
        ${std_srcdir}/expected \
        ${std_srcdir}/functional \
@@ -1150,7 +1151,6 @@ experimental_headers = \
        ${experimental_srcdir}/array \
        ${experimental_srcdir}/buffer \
        ${experimental_srcdir}/chrono \
-       ${experimental_srcdir}/contract \
        ${experimental_srcdir}/deque \
        ${experimental_srcdir}/executor \
        ${experimental_srcdir}/forward_list \
index 8bb3e8d185f39be9d4b3afde9ac030779f9ce92f..a1672b6be49ffe1dc886dc093290b03631cf26c1 100644 (file)
@@ -2272,6 +2272,15 @@ ftms = {
   };
 };
 
+ftms = {
+  name = contracts;
+  values = {
+    v = 202502;
+    cxxmin = 26;
+    extra_cond = "__cpp_contracts >= 202502L";
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
index 107b19002d7a3fcf7d5b9bfceaa53a038ed8a13c..dccc2a6c0df6f71d89d485e7655fac77ba2de870 100644 (file)
 #endif /* !defined(__cpp_lib_is_implicit_lifetime) */
 #undef __glibcxx_want_is_implicit_lifetime
 
+#if !defined(__cpp_lib_contracts)
+# if (__cplusplus >  202302L) && (__cpp_contracts >= 202502L)
+#  define __glibcxx_contracts 202502L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_contracts)
+#   define __cpp_lib_contracts 202502L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_contracts) */
+#undef __glibcxx_want_contracts
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/experimental/contract b/libstdc++-v3/include/experimental/contract
deleted file mode 100644 (file)
index 697045e..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-// Contracts support header for -*- C++ -*-
-
-// Copyright (C) 2019-2026 Free Software Foundation, Inc.
-//
-// This file is part of GCC.
-//
-// GCC is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3, or (at your option)
-// any later version.
-//
-// GCC is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-// <http://www.gnu.org/licenses/>.
-
-/** @file contract
- *  This is a Standard C++ Library header.
- */
-
-#ifndef _GLIBCXX_CONTRACT
-#define _GLIBCXX_CONTRACT 1
-
-#ifdef _GLIBCXX_SYSHDR
-#pragma GCC system_header
-#endif
-
-#if __cplusplus >= 201703L
-
-#include <string_view>
-#include <cstdint>
-
-namespace std _GLIBCXX_VISIBILITY(default)
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-namespace experimental
-{
-  // From P1332
-  enum class contract_violation_continuation_mode {
-    never_continue, maybe_continue
-  };
-
-  class contract_violation {
-    const char* _M_file;
-    const char* _M_function;
-    const char* _M_comment;
-    const char* _M_level;
-    const char* _M_role;
-    uint_least32_t _M_line;
-    signed char _M_continue;
-  public:
-    // From N4820
-    uint_least32_t line_number() const noexcept { return _M_line; }
-    string_view file_name() const noexcept { return _M_file; }
-    string_view function_name() const noexcept { return _M_function; }
-    string_view comment() const noexcept { return _M_comment; }
-    string_view assertion_level() const noexcept { return _M_level; }
-    // From P1332
-    string_view assertion_role() const noexcept { return _M_role; }
-    contract_violation_continuation_mode continuation_mode() const noexcept
-    { return static_cast<contract_violation_continuation_mode>(_M_continue); }
-  };
-
-} // namespace experimental
-
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace std
-
-// To override the contract violation handler, define
-//void ::handle_contract_violation (const std::experimental::contract_violation &);
-
-#endif // C++17
-#endif // _GLIBCXX_CONTRACT
index 433082facacdbb12b12bc753ccfd6dce7e58dbed..91f54edb15bdf66c3df446621df7d282ca7fcbb0 100644 (file)
 #endif
 
 #if __cplusplus > 202302L
+#include <contracts>
 #include <debugging>
 #include <inplace_vector>
 #include <meta>
diff --git a/libstdc++-v3/include/std/contracts b/libstdc++-v3/include/std/contracts
new file mode 100644 (file)
index 0000000..2cf67ac
--- /dev/null
@@ -0,0 +1,111 @@
+// Contracts support header for -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file contracts
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_CONTRACTS
+#define _GLIBCXX_CONTRACTS 1
+
+#pragma GCC system_header
+
+#define __glibcxx_want_contracts
+#include <bits/version.h>
+
+#ifdef __cpp_lib_contracts
+#include <source_location>
+#include <bits/exception_ptr.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace contracts
+{
+  // From P2900R14
+
+  enum class assertion_kind : __UINT16_TYPE__ {
+    pre = 1,
+    post = 2,
+    assert = 3,
+
+    /* Implementation−defined values should have a minimum value of 1000. */
+  };
+
+  enum class evaluation_semantic : __UINT16_TYPE__ {
+    ignore = 1,
+    observe = 2,
+    enforce = 3,
+    quick_enforce = 4,
+
+    /* Implementation−defined values should have a minimum value of 1000.  */
+  };
+
+  enum class detection_mode : __UINT16_TYPE__ {
+    predicate_false = 1,
+    evaluation_exception = 2,
+
+    /* Implementation−defined values should have a minimum value of 1000. */
+  };
+
+  using __vendor_ext = void;
+
+  class contract_violation {
+    __UINT16_TYPE__ _M_version;
+    assertion_kind _M_assertion_kind;
+    evaluation_semantic _M_evaluation_semantic;
+    detection_mode _M_detection_mode;
+    const char* _M_comment;
+    const void* _M_src_loc_ptr;
+    __vendor_ext* _M_ext;
+
+  public:
+    // cannot be copied or moved or assigned to
+    contract_violation(const contract_violation&) = delete;
+    contract_violation& operator=(const contract_violation&) = delete;
+
+    assertion_kind kind() const noexcept { return _M_assertion_kind; }
+    evaluation_semantic semantic() const noexcept { return _M_evaluation_semantic; }
+    detection_mode mode() const noexcept { return _M_detection_mode; }
+    const char* comment() const noexcept { return _M_comment; }
+    std::source_location location() const noexcept {
+      return std::source_location (_M_src_loc_ptr);
+    }
+    bool is_terminating () const noexcept {
+      return _M_evaluation_semantic == std::contracts::evaluation_semantic::enforce
+           || _M_evaluation_semantic == std::contracts::evaluation_semantic::quick_enforce;
+    }
+  };
+
+  void invoke_default_contract_violation_handler(const contract_violation&) noexcept;
+
+} // namespace contracts
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // __cpp_lib_contracts
+#endif // _GLIBCXX_CONTRACTS
index ca09e980e172b6e9f6c23475d7a0c14371af96f4..3a631c31c1e31f4b70f2b55188b0c32c52ac1862 100644 (file)
 namespace std
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
+#ifdef __cpp_lib_contracts
+  namespace contracts
+  {
+    class contract_violation;
+  }
+#endif // __cpp_lib_contracts
 
   /// A class that describes a location in source code.
   struct source_location
@@ -85,6 +91,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   private:
     const __impl* _M_impl = nullptr;
+
+    constexpr source_location (const void *__t)
+      : _M_impl (static_cast <const __impl*>(__t)) {}
+      
+#ifdef __cpp_lib_contracts
+    /* To enable use of the source __impl*.  */
+    friend class std::contracts::contract_violation;
+#endif // __cpp_lib_contracts
   };
 
 _GLIBCXX_END_NAMESPACE_VERSION
index e134e395bb675c86d6a41ca202792129dcae1516..f38660498ccfd2cfc9272377f3e5a2defc60d3ab 100644 (file)
@@ -1017,6 +1017,18 @@ export namespace std
 }
 #endif
 
+// 17.10.1 <contracts>
+#if __cpp_lib_contracts
+export namespace std::contracts
+{
+  using std::contracts::assertion_kind;
+  using std::contracts::evaluation_semantic;
+  using std::contracts::detection_mode;
+  using std::contracts::contract_violation;
+  using std::contracts::invoke_default_violation_handler;
+}
+#endif // __cpp_lib_contracts
+
 // 17.12.2 <coroutine>
 #if __cpp_lib_coroutine
 export namespace std
index e6d41cf66eb2cfabded77c1295f5a7d310338b9a..e428aef23c041ae510c14fe2bea0713bbdd03580 100644 (file)
@@ -39,10 +39,16 @@ endif
 headers =
 
 sources = \
-       contract.cc
+       contract26.cc
 
 # vpath % $(top_srcdir)/src/experimental
 
+
+contract26.lo: contract26.cc
+       $(LTCXXCOMPILE) -std=gnu++26 -fcontracts -c $<
+contract26.o: contract26.cc
+       $(CXXCOMPILE) -std=gnu++26 -fcontracts -c $<
+
 libstdc__exp_la_SOURCES = $(sources)
 
 libstdc__exp_la_LIBADD = \
index 8cb0acd4e68b0bcaed66b9edc293ddd9ec22434a..a9248197f8c7aedd8b8f5ae3779602cdcf1d5fdd 100644 (file)
@@ -152,7 +152,7 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
 LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
 @ENABLE_FILESYSTEM_TS_TRUE@am__DEPENDENCIES_1 = $(top_builddir)/src/filesystem/libstdc++fsconvenience.la
 @ENABLE_BACKTRACE_TRUE@am__DEPENDENCIES_2 = $(top_builddir)/src/libbacktrace/libstdc++_libbacktrace.la
-am__objects_1 = contract.lo
+am__objects_1 = contract26.lo
 am_libstdc__exp_la_OBJECTS = $(am__objects_1)
 libstdc__exp_la_OBJECTS = $(am_libstdc__exp_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -458,10 +458,8 @@ toolexeclib_LTLIBRARIES = libstdc++exp.la
 @ENABLE_BACKTRACE_TRUE@backtrace_lib = $(top_builddir)/src/libbacktrace/libstdc++_libbacktrace.la
 headers = 
 sources = \
-       contract.cc
+       contract26.cc
 
-
-# vpath % $(top_srcdir)/src/experimental
 libstdc__exp_la_SOURCES = $(sources)
 libstdc__exp_la_LIBADD = \
        $(top_builddir)/src/c++23/libc++23convenience.la \
@@ -480,7 +478,7 @@ libstdc__exp_la_DEPENDENCIES = \
 # OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden
 # as the occasion calls for it.
 AM_CXXFLAGS = \
-       -std=gnu++17 -nostdinc++ \
+       -std=gnu++20 -nostdinc++ \
        $(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
        $(XTEMPLATE_FLAGS) $(VTV_CXXFLAGS) \
        $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) \
@@ -808,6 +806,13 @@ uninstall-am: uninstall-toolexeclibLTLIBRARIES
 .PRECIOUS: Makefile
 
 
+# vpath % $(top_srcdir)/src/experimental
+
+contract26.lo: contract26.cc
+       $(LTCXXCOMPILE) -std=gnu++26 -fcontracts -c $<
+contract26.o: contract26.cc
+       $(CXXCOMPILE) -std=gnu++26 -fcontracts -c $<
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/libstdc++-v3/src/experimental/contract.cc b/libstdc++-v3/src/experimental/contract.cc
deleted file mode 100644 (file)
index 35ae714..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-// -*- C++ -*- std::experimental::contract_violation and friends
-
-// Copyright (C) 2019-2026 Free Software Foundation, Inc.
-//
-// This file is part of GCC.
-//
-// GCC is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 3, or (at your option)
-// any later version.
-//
-// GCC is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-// <http://www.gnu.org/licenses/>.
-
-#include <experimental/contract>
-#if _GLIBCXX_HOSTED && _GLIBCXX_VERBOSE
-# include <iostream>
-#endif
-
-__attribute__ ((weak)) void
-handle_contract_violation (const std::experimental::contract_violation &violation)
-{
-#if _GLIBCXX_HOSTED && _GLIBCXX_VERBOSE
-  bool level_default_p = violation.assertion_level() == "default";
-  bool role_default_p = violation.assertion_role() == "default";
-  bool cont_mode_default_p = violation.continuation_mode()
-    == std::experimental::contract_violation_continuation_mode::never_continue;
-
-  const char* modes[]{ "off", "on" }; // Must match enumerators in header.
-  std::cerr << "contract violation in function " << violation.function_name()
-    << " at " << violation.file_name() << ':' << violation.line_number()
-    << ": " << violation.comment();
-
-  const char* delimiter = "\n[";
-
-  if (!level_default_p)
-    {
-      std::cerr << delimiter << "level:" << violation.assertion_level();
-      delimiter = ", ";
-    }
-  if (!role_default_p)
-    {
-      std::cerr << delimiter << "role:" << violation.assertion_role();
-      delimiter = ", ";
-    }
-  if (!cont_mode_default_p)
-    {
-      std::cerr << delimiter << "continue:"
-               << modes[(int)violation.continuation_mode() & 1];
-      delimiter = ", ";
-    }
-
-  if (delimiter[0] == ',')
-    std::cerr << ']';
-
-  std::cerr << std::endl;
-#endif
-}
-
-#if _GLIBCXX_INLINE_VERSION
-// The compiler expects the contract_violation class to be in an unversioned
-// namespace, so provide a forwarding function with the expected symbol name.
-extern "C" void
-_Z25handle_contract_violationRKNSt12experimental18contract_violationE
-(const std::experimental::contract_violation &violation)
-{ handle_contract_violation(violation); }
-#endif
diff --git a/libstdc++-v3/src/experimental/contract26.cc b/libstdc++-v3/src/experimental/contract26.cc
new file mode 100644 (file)
index 0000000..d32a2ca
--- /dev/null
@@ -0,0 +1,157 @@
+// -*- C++ -*- std::contracts::contract_violation and friends
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#include <contracts>
+
+#ifdef __cpp_lib_contracts
+#if _GLIBCXX_HOSTED && _GLIBCXX_VERBOSE
+# include <iostream>
+# include <cxxabi.h>
+#endif
+
+void __handle_contract_violation(const std::contracts::contract_violation &violation) noexcept
+{
+#if _GLIBCXX_HOSTED && _GLIBCXX_VERBOSE
+
+  std::cerr << "contract violation in function " << violation.location().function_name()
+    << " at " << violation.location().file_name() << ':' << violation.location().line()
+    << ": " << violation.comment();
+
+  const char* delimiter = "\n[";
+
+  std::cerr << delimiter << "assertion_kind:";
+   switch (violation.kind())
+   {
+     case std::contracts::assertion_kind::pre:
+       std::cerr << " pre";
+       break;
+     case std::contracts::assertion_kind::post:
+       std::cerr << " post";
+       break;
+     case std::contracts::assertion_kind::assert:
+       std::cerr << " assert";
+       break;
+     default:
+       std::cerr << " unknown" << (int) violation.semantic();
+   }
+   delimiter = ", ";
+
+  std::cerr << delimiter << "semantic:";
+  switch (violation.semantic())
+  {
+    case std::contracts::evaluation_semantic::enforce:
+      std::cerr << " enforce";
+      break;
+    case std::contracts::evaluation_semantic::observe:
+      std::cerr << " observe";
+      break;
+    default:
+      std::cerr << " unknown" << (int) violation.semantic();
+  }
+  delimiter = ", ";
+
+  std::cerr << delimiter << "mode:";
+  switch (violation.mode())
+  {
+    case std::contracts::detection_mode::predicate_false:
+      std::cerr << " predicate_false";
+      break;
+    case std::contracts::detection_mode::evaluation_exception:
+      std::cerr << " evaluation_exception";
+      break;
+    default:
+      std::cerr << "unknown";
+  }
+  delimiter = ", ";
+
+  if (violation.mode() == std::contracts::detection_mode::evaluation_exception)
+    {
+      /* Based on the impl. in vterminate.cc.  */
+      std::type_info *t = __cxxabiv1::__cxa_current_exception_type();
+      if (t)
+       {
+         int status = -1;
+         char *dem = 0;
+         // Note that "name" is the mangled name.
+         char const *name = t->name();
+         dem = __cxxabiv1::__cxa_demangle(name, 0, 0, &status);
+         std::cerr << ": threw an instance of '";
+         std::cerr << ( status == 0 ? dem : name) << "'";
+       }
+      else
+       std::cerr << ": threw an unknown type";
+    }
+
+  std::cerr << delimiter << "terminating:"
+           << (violation.is_terminating () ? " yes" : " no");
+
+  if (delimiter[0] == ',')
+    std::cerr << ']';
+
+  std::cerr << std::endl;
+#endif
+}
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace contracts
+{
+
+void invoke_default_contract_violation_handler(const std::contracts::contract_violation& violation) noexcept
+{
+  return __handle_contract_violation(violation);
+}
+
+}
+}
+
+__attribute__ ((weak)) void
+handle_contract_violation (const std::contracts::contract_violation &violation)
+{
+  return __handle_contract_violation(violation);
+}
+
+#if _GLIBCXX_INLINE_VERSION
+// The compiler expects the contract_violation class to be in an unversioned
+// namespace, so provide a forwarding function with the expected symbol name.
+extern "C" void
+_Z25handle_contract_violationRKNSt9contracts18contract_violationE
+(const std::contracts::contract_violation &violation)
+{ handle_contract_violation(violation); }
+
+extern "C" void
+_Z27__handle_contract_violationRKNSt9contracts18contract_violationE
+(const std::contracts::contract_violation &violation)
+{ __handle_contract_violation(violation); }
+
+extern "C" void
+_Z41invoke_default_contract_violation_handlerRKNSt9contracts18contract_violationE
+(const std::contracts::contract_violation &violation)
+{ invoke_default_contract_violation_handler(violation); }
+
+#endif
+#endif // __cpp_lib_contracts
diff --git a/libstdc++-v3/testsuite/18_support/contracts/invoke_default_cvh.cc b/libstdc++-v3/testsuite/18_support/contracts/invoke_default_cvh.cc
new file mode 100644 (file)
index 0000000..9b40ca1
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-options "-fcontracts -fcontract-evaluation-semantic=observe" }
+// { dg-do run { target c++26 } }
+
+#include <contracts>
+#include <testsuite_hooks.h>
+
+bool custom_called = false;
+
+
+void handle_contract_violation(const std::contracts::contract_violation& v)
+{
+  invoke_default_contract_violation_handler(v);
+  custom_called = true;
+}
+
+void f(int i) pre (i>10) {};
+
+int main()
+{
+  f(0);
+  VERIFY(custom_called);
+}
+// { dg-output "contract violation in function void f.int. at .*(\n|\r\n|\r)" }
diff --git a/libstdc++-v3/testsuite/18_support/contracts/invoke_default_cvh2.cc b/libstdc++-v3/testsuite/18_support/contracts/invoke_default_cvh2.cc
new file mode 100644 (file)
index 0000000..72a8e2f
--- /dev/null
@@ -0,0 +1,55 @@
+// check that default contract violation is not invoked if not explicitly invoked
+// { dg-options "-fcontracts -fcontract-evaluation-semantic=observe" }
+// { dg-do run { target c++26 } }
+
+#include <contracts>
+#include <testsuite_hooks.h>
+#include <iostream>
+#include <sstream>
+
+
+struct checking_buf
+  : public std::streambuf
+{
+  bool written = false;
+
+  checking_buf() = default;
+
+  virtual int_type
+  overflow(int_type)
+  {
+    written = true;
+    return int_type();
+  }
+
+  std::streamsize xsputn(const char* s, std::streamsize count)
+  {
+    written = true;
+    return count;
+  }
+
+};
+
+
+bool custom_called = false;
+
+
+void handle_contract_violation(const std::contracts::contract_violation& v)
+{
+  custom_called = true;
+}
+
+void f(int i) pre (i>10) {};
+
+int main()
+{
+  auto save_buf = std::cerr.rdbuf();
+  checking_buf buf;
+  std::cerr.rdbuf(&buf);
+
+  f(0);
+  std::cerr.rdbuf(save_buf);
+  VERIFY(!buf.written);
+  return 0;
+}
+