[libcxx-commits] [libcxx] [WIP][libc++] Implement library support for contracts (PR #86251)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Mar 21 23:45:53 PDT 2024


https://github.com/ldionne created https://github.com/llvm/llvm-project/pull/86251

This is a WIP patch with a naive implementation of the library support necessary for contracts as described in http://wg21.link/p2900, with the changes proposed by http://wg21.link/p3191r0.

>From 163ca4384ddbc4961bb12eadd682996c15fb5ca3 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Wed, 20 Mar 2024 13:42:59 +0900
Subject: [PATCH] [WIP][libc++] Implement library support for contracts

This is a WIP patch with a naive implementation of the library support
necessary for contracts as described in http://wg21.link/p2900, with the
changes proposed by http://wg21.link/p3191r0.
---
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__assert                       |   8 +-
 libcxx/include/contracts                      | 166 ++++++++++++++++++
 libcxx/include/module.modulemap               |   4 +
 libcxx/include/vector                         |  27 ++-
 libcxx/src/CMakeLists.txt                     |   1 +
 libcxx/src/contracts.cpp                      |  24 +++
 libcxx/test/std/contracts/enforce.pass.cpp    |  34 ++++
 .../test/std/contracts/enforce_fast.pass.cpp  |  35 ++++
 libcxx/test/std/contracts/ignore.pass.cpp     |  27 +++
 libcxx/test/std/contracts/observe.pass.cpp    |  25 +++
 11 files changed, 332 insertions(+), 20 deletions(-)
 create mode 100644 libcxx/include/contracts
 create mode 100644 libcxx/src/contracts.cpp
 create mode 100644 libcxx/test/std/contracts/enforce.pass.cpp
 create mode 100644 libcxx/test/std/contracts/enforce_fast.pass.cpp
 create mode 100644 libcxx/test/std/contracts/ignore.pass.cpp
 create mode 100644 libcxx/test/std/contracts/observe.pass.cpp

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 6ed8d21d98a15a..952942da86f457 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -887,6 +887,7 @@ set(files
   complex.h
   concepts
   condition_variable
+  contracts
   coroutine
   csetjmp
   csignal
diff --git a/libcxx/include/__assert b/libcxx/include/__assert
index 49769fb4d44978..ef73421d81b698 100644
--- a/libcxx/include/__assert
+++ b/libcxx/include/__assert
@@ -10,18 +10,14 @@
 #ifndef _LIBCPP___ASSERT
 #define _LIBCPP___ASSERT
 
-#include <__assertion_handler> // Note: this include is generated by CMake and is potentially vendor-provided.
+#include <contracts>
 #include <__config>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
 
-#define _LIBCPP_ASSERT(expression, message)                                                                            \
-  (__builtin_expect(static_cast<bool>(expression), 1)                                                                  \
-       ? (void)0                                                                                                       \
-       : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING(            \
-             expression) " failed: " message "\n"))
+#define _LIBCPP_ASSERT(expression, message) _LIBCPP_ASSERT_ENFORCE(expression, message)
 
 // TODO: __builtin_assume can currently inhibit optimizations. Until this has been fixed and we can add
 //       assumptions without a clear optimization intent, disable that to avoid worsening the code generation.
diff --git a/libcxx/include/contracts b/libcxx/include/contracts
new file mode 100644
index 00000000000000..4018fc36a4985e
--- /dev/null
+++ b/libcxx/include/contracts
@@ -0,0 +1,166 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_CONTRACTS
+#define _LIBCPP_CONTRACTS
+
+#include <__assertion_handler> // Note: this include is generated by CMake and is potentially vendor-provided.
+#include <__config>
+#include <source_location>
+#include <version>
+
+#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace contracts {
+
+struct __private_constructor_tag {};
+
+enum class assertion_kind { pre = 1, post = 2, assert = 3 };
+
+enum class evaluation_semantic { enforce = 1, observe = 2, fast = 3 };
+
+enum class detection_mode { predicate_false = 1, evaluation_exception = 2 };
+
+class contract_violation {
+public:
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit contract_violation(
+      __private_constructor_tag,
+      char const* __comment,
+      enum detection_mode __mode,
+      assertion_kind __kind,
+      evaluation_semantic __semantic,
+      source_location __location = source_location::current())
+      : __comment_(__comment),
+        __detection_mode_(__mode),
+        __assertion_kind_(__kind),
+        __location_(__location),
+        __semantic_(__semantic) {}
+
+  contract_violation(const contract_violation&)            = delete;
+  contract_violation& operator=(const contract_violation&) = delete;
+
+  ~contract_violation() = default;
+
+  _LIBCPP_HIDE_FROM_ABI const char* comment() const noexcept;
+  _LIBCPP_HIDE_FROM_ABI enum detection_mode detection_mode() const noexcept;
+  _LIBCPP_HIDE_FROM_ABI assertion_kind kind() const noexcept;
+  _LIBCPP_HIDE_FROM_ABI source_location location() const noexcept;
+  _LIBCPP_HIDE_FROM_ABI evaluation_semantic semantic() const noexcept;
+
+private:
+  char const* __comment_;
+  enum detection_mode __detection_mode_;
+  assertion_kind __assertion_kind_;
+  source_location __location_;
+  evaluation_semantic __semantic_;
+};
+
+_LIBCPP_EXPORTED_FROM_ABI void __default_contract_violation_handler(contract_violation const&) noexcept;
+
+_LIBCPP_HIDE_FROM_ABI inline void invoke_default_contract_violation_handler(contract_violation const& __cv) {
+  contracts::__default_contract_violation_handler(__cv);
+}
+
+} // namespace contracts
+_LIBCPP_END_NAMESPACE_STD
+
+// Note that we could avoid declaring this function once we don't need to define the macros below.
+_LIBCPP_OVERRIDABLE_FUNC_VIS void handle_contract_violation(const std::contracts::contract_violation&) noexcept
+    /* strenghtened */;
+
+#define _LIBCPP_TRAP(expr, message)                                                                                    \
+  _LIBCPP_ASSERTION_HANDLER(                                                                                           \
+      __FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING(expr) " failed: " message "\n")
+
+#define _LIBCPP_ASSERT_IGNORE(expr, message, kind) /* nothing */
+
+#define _LIBCPP_ASSERT_OBSERVE(expr, message, kind)                                                                    \
+  do {                                                                                                                 \
+    bool __violation;                                                                                                  \
+    try {                                                                                                              \
+      __violation = !__builtin_expect(static_cast<bool>(expr), 1);                                                     \
+    } catch (...) {                                                                                                    \
+      static constinit ::std::contracts::contract_violation __cv(                                                      \
+          ::std::contracts::__private_constructor_tag{},                                                               \
+          message,                                                                                                     \
+          ::std::contracts::detection_mode::evaluation_exception,                                                      \
+          kind,                                                                                                        \
+          ::std::contracts::evaluation_semantic::observe);                                                             \
+      ::handle_contract_violation(__cv);                                                                               \
+      _LIBCPP_TRAP(expr, message);                                                                                     \
+    }                                                                                                                  \
+    if (__violation) {                                                                                                 \
+      static constinit ::std::contracts::contract_violation __cv(                                                      \
+          ::std::contracts::__private_constructor_tag{},                                                               \
+          message,                                                                                                     \
+          ::std::contracts::detection_mode::predicate_false,                                                           \
+          kind,                                                                                                        \
+          ::std::contracts::evaluation_semantic::observe);                                                             \
+      ::handle_contract_violation(__cv);                                                                               \
+    }                                                                                                                  \
+  } while (false)
+
+#define _LIBCPP_ASSERT_ENFORCE(expr, message, kind)                                                                    \
+  do {                                                                                                                 \
+    bool __violation;                                                                                                  \
+    try {                                                                                                              \
+      __violation = !__builtin_expect(static_cast<bool>(expr), 1);                                                     \
+    } catch (...) {                                                                                                    \
+      ::std::contracts::contract_violation __cv(                                                                       \
+          ::std::contracts::__private_constructor_tag{},                                                               \
+          message,                                                                                                     \
+          ::std::contracts::detection_mode::evaluation_exception,                                                      \
+          kind,                                                                                                        \
+          ::std::contracts::evaluation_semantic::enforce);                                                             \
+      ::handle_contract_violation(__cv);                                                                               \
+      _LIBCPP_TRAP(expr, message);                                                                                     \
+    }                                                                                                                  \
+    if (__violation) {                                                                                                 \
+      ::std::contracts::contract_violation __cv(                                                                       \
+          ::std::contracts::__private_constructor_tag{},                                                               \
+          message,                                                                                                     \
+          ::std::contracts::detection_mode::predicate_false,                                                           \
+          kind,                                                                                                        \
+          ::std::contracts::evaluation_semantic::enforce);                                                             \
+      ::handle_contract_violation(__cv);                                                                               \
+      _LIBCPP_TRAP(expr, message);                                                                                     \
+    }                                                                                                                  \
+  } while (false)
+
+#define _LIBCPP_ASSERT_ENFORCE_FAST(expr, message, kind)                                                                     \
+  (__builtin_expect(static_cast<bool>(expr), 1) ? (void)0 : _LIBCPP_TRAP(expr, message))
+
+// Recommended practice: by default, enable the 'enforce' semantic.
+#if !defined(_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_IGNORE) &&                                                          \
+    !defined(_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_OBSERVE) &&                                                         \
+    !defined(_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_ENFORCE) &&                                                         \
+    !defined(_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_ENFORCE_FAST)
+#  define _LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_ENFORCE
+#endif
+
+// TODO: We should also take this in account for the ODR signature.
+#if defined(_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_IGNORE)
+#  define _LIBCPP_CONTRACT_ASSERT(expr, message, kind) _LIBCPP_ASSERT_IGNORE(expr, message, kind)
+#elif defined(_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_OBSERVE)
+#  define _LIBCPP_CONTRACT_ASSERT(expr, message, kind) _LIBCPP_ASSERT_OBSERVE(expr, message, kind)
+#elif defined(_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_ENFORCE)
+#  define _LIBCPP_CONTRACT_ASSERT(expr, message, kind) _LIBCPP_ASSERT_ENFORCE(expr, message, kind)
+#elif defined(_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_ENFORCE_FAST)
+#  define _LIBCPP_CONTRACT_ASSERT(expr, message, kind) _LIBCPP_ASSERT_ENFORCE_FAST(expr, message, kind)
+#endif
+
+#define __contract_assert__(expr, message)                                                                             \
+  _LIBCPP_CONTRACT_ASSERT(expr, message, ::std::contracts::assertion_kind::assert)
+#define __pre__(expr, message) _LIBCPP_CONTRACT_ASSERT(expr, message, ::std::contracts::assertion_kind::pre)
+#define __post__(expr, message) _LIBCPP_CONTRACT_ASSERT(expr, message, ::std::contracts::assertion_kind::post)
+
+#endif // _LIBCPP_CONTRACTS
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index f36a47cef00977..3d60996bed440e 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -55,6 +55,10 @@ module std_condition_variable [system] {
   header "condition_variable"
   export *
 }
+module std_contracts [system] {
+  header "contracts"
+  export *
+}
 module std_coroutine [system] {
   header "coroutine"
   export *
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 0908482600c533..f6ec8db6b15522 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -356,6 +356,7 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
 #include <__utility/pair.h>
 #include <__utility/swap.h>
 #include <climits>
+#include <contracts>
 #include <cstring>
 #include <iosfwd> // for forward declaration of vector
 #include <limits>
@@ -611,19 +612,19 @@ public:
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __n) const;
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector");
+    __pre__(!empty(), "front() called on an empty vector");
     return *this->__begin_;
   }
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector");
+    __pre__(!empty(), "front() called on an empty vector");
     return *this->__begin_;
   }
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector");
+    __pre__(!empty(), "back() called on an empty vector");
     return *(this->__end_ - 1);
   }
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector");
+    __pre__(!empty(), "back() called on an empty vector");
     return *(this->__end_ - 1);
   }
 
@@ -1408,14 +1409,14 @@ vector<_Tp, _Allocator>::end() const _NOEXCEPT {
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::reference
 vector<_Tp, _Allocator>::operator[](size_type __n) _NOEXCEPT {
-  _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds");
+  __pre__(__n < size(), "vector[] index out of bounds");
   return this->__begin_[__n];
 }
 
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::const_reference
 vector<_Tp, _Allocator>::operator[](size_type __n) const _NOEXCEPT {
-  _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds");
+  __pre__(__n < size(), "vector[] index out of bounds");
   return this->__begin_[__n];
 }
 
@@ -1536,15 +1537,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline
 
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 inline void vector<_Tp, _Allocator>::pop_back() {
-  _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector::pop_back called on an empty vector");
+  __pre__(!empty(), "vector::pop_back called on an empty vector");
   this->__destruct_at_end(this->__end_ - 1);
 }
 
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator
 vector<_Tp, _Allocator>::erase(const_iterator __position) {
-  _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
-      __position != end(), "vector::erase(iterator) called with a non-dereferenceable iterator");
+  __pre__(__position != end(), "vector::erase(iterator) called with a non-dereferenceable iterator");
   difference_type __ps = __position - cbegin();
   pointer __p          = this->__begin_ + __ps;
   this->__destruct_at_end(std::move(__p + 1, this->__end_, __p));
@@ -1554,7 +1554,7 @@ vector<_Tp, _Allocator>::erase(const_iterator __position) {
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
 vector<_Tp, _Allocator>::erase(const_iterator __first, const_iterator __last) {
-  _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "vector::erase(first, last) called with invalid range");
+  __pre__(__first <= __last, "vector::erase(first, last) called with invalid range");
   pointer __p = this->__begin_ + (__first - begin());
   if (__first != __last) {
     this->__destruct_at_end(std::move(__p + (__last - __first), this->__end_, __p));
@@ -1786,8 +1786,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::swap(vector& __x)
     _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable<allocator_type>::value)
 #endif
 {
-  _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
-      __alloc_traits::propagate_on_container_swap::value || this->__alloc() == __x.__alloc(),
+  __pre__(__alloc_traits::propagate_on_container_swap::value || this->__alloc() == __x.__alloc(),
       "vector::swap: Either propagate_on_container_swap must be true"
       " or the allocators must compare equal");
   std::swap(this->__begin_, __x.__begin_);
@@ -2583,7 +2582,7 @@ template <class _Allocator>
 template <class _ForwardIterator, class _Sentinel>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
 vector<bool, _Allocator>::__assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __ns) {
-  _LIBCPP_ASSERT_VALID_INPUT_RANGE(__ns >= 0, "invalid range specified");
+  __pre__(__ns >= 0, "invalid range specified");
 
   clear();
 
@@ -2741,7 +2740,7 @@ template <class _ForwardIterator, class _Sentinel>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector<bool, _Allocator>::iterator
 vector<bool, _Allocator>::__insert_with_size(
     const_iterator __position, _ForwardIterator __first, _Sentinel __last, difference_type __n_signed) {
-  _LIBCPP_ASSERT_VALID_INPUT_RANGE(__n_signed >= 0, "invalid range specified");
+  __pre__(__n_signed >= 0, "invalid range specified");
   const size_type __n = static_cast<size_type>(__n_signed);
   iterator __r;
   size_type __c = capacity();
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index 1110a79ddcacd5..0a25b07e0756d9 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -8,6 +8,7 @@ set(LIBCXX_SOURCES
   call_once.cpp
   charconv.cpp
   chrono.cpp
+  contracts.cpp
   error_category.cpp
   exception.cpp
   filesystem/filesystem_clock.cpp
diff --git a/libcxx/src/contracts.cpp b/libcxx/src/contracts.cpp
new file mode 100644
index 00000000000000..edc58de4252461
--- /dev/null
+++ b/libcxx/src/contracts.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <contracts>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace contracts {
+
+void __default_contract_violation_handler(contract_violation const& __cv) noexcept {
+  // TODO: basically reimplement __libcpp_verbose_abort.
+}
+
+} // namespace contracts
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_WEAK void handle_contract_violation(std::contracts::contract_violation const& __cv) noexcept
+/* strenghtened */ {
+  std::contracts::__default_contract_violation_handler(__cv);
+}
diff --git a/libcxx/test/std/contracts/enforce.pass.cpp b/libcxx/test/std/contracts/enforce.pass.cpp
new file mode 100644
index 00000000000000..57928a78838567
--- /dev/null
+++ b/libcxx/test/std/contracts/enforce.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <contracts>
+
+// TODO
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_ENFORCE
+
+#include <contracts>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+    TEST_LIBCPP_ASSERT_FAILURE([](){
+        __pre__(false, "some message");
+    }(), "some message");
+
+    TEST_LIBCPP_ASSERT_FAILURE([](){
+        __post__(false, "some message");
+    }(), "some message");
+    TEST_LIBCPP_ASSERT_FAILURE([](){
+        __contract_assert__(false, "some message");
+    }(), "some message");
+
+    return 0;
+}
diff --git a/libcxx/test/std/contracts/enforce_fast.pass.cpp b/libcxx/test/std/contracts/enforce_fast.pass.cpp
new file mode 100644
index 00000000000000..7260df579030cc
--- /dev/null
+++ b/libcxx/test/std/contracts/enforce_fast.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <contracts>
+
+// TODO
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_ENFORCE_FAST
+
+#include <contracts>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+    TEST_LIBCPP_ASSERT_FAILURE([](){
+        __pre__(false, "some message");
+    }(), "some message");
+
+    TEST_LIBCPP_ASSERT_FAILURE([](){
+        __post__(false, "some message");
+    }(), "some message");
+
+    TEST_LIBCPP_ASSERT_FAILURE([](){
+        __contract_assert__(false, "some message");
+    }(), "some message");
+
+    return 0;
+}
diff --git a/libcxx/test/std/contracts/ignore.pass.cpp b/libcxx/test/std/contracts/ignore.pass.cpp
new file mode 100644
index 00000000000000..0fcb08ec52ab64
--- /dev/null
+++ b/libcxx/test/std/contracts/ignore.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <contracts>
+
+// TODO
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_IGNORE
+
+#include <contracts>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+    __pre__(false, "some message"); // nothing happening
+    __post__(false, "some message"); // nothing happening
+    __contract_assert__(false, "some message"); // nothing happening
+
+    return 0;
+}
diff --git a/libcxx/test/std/contracts/observe.pass.cpp b/libcxx/test/std/contracts/observe.pass.cpp
new file mode 100644
index 00000000000000..3250551943cec1
--- /dev/null
+++ b/libcxx/test/std/contracts/observe.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <contracts>
+
+// TODO
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_CONTRACTS_EVALUATION_SEMANTIC_OBSERVE
+
+#include <contracts>
+
+int main(int, char**) {
+    __pre__(false, "some message"); // no termination happening
+    __post__(false, "some message"); // no termination happening
+    __contract_assert__(false, "some message"); // no termination happening
+
+    return 0;
+}



More information about the libcxx-commits mailing list