[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