From 9e9e28cc4eeb01b54d3c744513c9cf6ff7a71ca8 Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Sat, 18 Apr 2026 22:15:47 +0530 Subject: [PATCH 01/10] contracts: add violation handler infrastructure Signed-off-by: Sanchit2662 --- libs/core/contracts/CMakeLists.txt | 8 ++- .../hpx/contracts/violation_handler.hpp | 36 +++++++++++ libs/core/contracts/src/violation_handler.cpp | 64 +++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 libs/core/contracts/include/hpx/contracts/violation_handler.hpp create mode 100644 libs/core/contracts/src/violation_handler.cpp diff --git a/libs/core/contracts/CMakeLists.txt b/libs/core/contracts/CMakeLists.txt index 8d19136d388a..3e46417d4a1a 100644 --- a/libs/core/contracts/CMakeLists.txt +++ b/libs/core/contracts/CMakeLists.txt @@ -24,11 +24,15 @@ if(HPX_WITH_CXX26_CONTRACTS) endif() # Default location is $HPX_ROOT/libs/contracts/include -set(contracts_headers hpx/contracts.hpp hpx/contracts/macros.hpp) +set(contracts_headers + hpx/contracts.hpp + hpx/contracts/macros.hpp + hpx/contracts/violation_handler.hpp +) set(contracts_macro_headers hpx/contracts/macros.hpp) # Default location is $HPX_ROOT/libs/contracts/src -set(contracts_sources) +set(contracts_sources violation_handler.cpp) include(HPX_AddModule) add_hpx_module( diff --git a/libs/core/contracts/include/hpx/contracts/violation_handler.hpp b/libs/core/contracts/include/hpx/contracts/violation_handler.hpp new file mode 100644 index 000000000000..e30be9d63932 --- /dev/null +++ b/libs/core/contracts/include/hpx/contracts/violation_handler.hpp @@ -0,0 +1,36 @@ +// Copyright (c) 2026 The STE||AR-Group +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#include +#include + +namespace hpx::contracts { + + enum class contract_kind + { + pre, + post, + assertion + }; + + struct violation_info + { + contract_kind kind; + char const* condition; + hpx::source_location location; + }; + + HPX_CXX_CORE_EXPORT using violation_handler_t = void (*)(violation_info const&); + + HPX_CORE_EXPORT void set_violation_handler(violation_handler_t handler) noexcept; + HPX_CORE_EXPORT violation_handler_t get_violation_handler() noexcept; + + HPX_CORE_EXPORT void default_violation_handler(violation_info const& info); + HPX_CORE_EXPORT void invoke_violation_handler(violation_info const& info); + +} // namespace hpx::contracts diff --git a/libs/core/contracts/src/violation_handler.cpp b/libs/core/contracts/src/violation_handler.cpp new file mode 100644 index 000000000000..d3d0fc0430e7 --- /dev/null +++ b/libs/core/contracts/src/violation_handler.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2026 The STE||AR-Group +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include + +namespace hpx::contracts { + + namespace detail { + + [[nodiscard]] violation_handler_t& get_handler() noexcept + { + static violation_handler_t handler = nullptr; + return handler; + } + + } // namespace detail + + void set_violation_handler(violation_handler_t handler) noexcept + { + detail::get_handler() = handler; + } + + violation_handler_t get_violation_handler() noexcept + { + return detail::get_handler(); + } + + void default_violation_handler(violation_info const& info) + { + char const* kind_str = nullptr; + switch (info.kind) + { + case contract_kind::pre: + kind_str = "precondition"; + break; + case contract_kind::post: + kind_str = "postcondition"; + break; + case contract_kind::assertion: + kind_str = "assertion"; + break; + } + + std::cerr << info.location << ": Contract " << kind_str << " '" + << info.condition << "' violated\n"; + std::abort(); + } + + void invoke_violation_handler(violation_info const& info) + { + violation_handler_t handler = detail::get_handler(); + if (handler == nullptr) + default_violation_handler(info); + else + handler(info); + } + +} // namespace hpx::contracts From 943199f20584a5917b524bdd3d3be1f4ba6515c9 Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Sun, 19 Apr 2026 00:19:58 +0530 Subject: [PATCH 02/10] contracts: add ENFORCE/OBSERVE/IGNORE mode support Signed-off-by: Sanchit2662 --- libs/core/contracts/CMakeLists.txt | 30 +++++++++-- .../include/hpx/contracts/macros.hpp | 51 +++++++++++++++---- .../hpx/contracts/violation_handler.hpp | 6 ++- libs/core/contracts/src/violation_handler.cpp | 4 ++ 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/libs/core/contracts/CMakeLists.txt b/libs/core/contracts/CMakeLists.txt index 3e46417d4a1a..f45973e38e9f 100644 --- a/libs/core/contracts/CMakeLists.txt +++ b/libs/core/contracts/CMakeLists.txt @@ -21,13 +21,35 @@ if(HPX_WITH_CXX26_CONTRACTS) DEFINE HPX_CONTRACTS_HAVE_ASSERTS_AS_CONTRACT_ASSERTS NAMESPACE CONTRACTS ) endif() +else() + # Contract evaluation mode for pre-C++26 compilers + hpx_option( + HPX_WITH_CONTRACTS_MODE STRING + "Contract evaluation mode for pre-C++26 compilers (ENFORCE, OBSERVE, IGNORE). (default: ENFORCE)" + "ENFORCE" + STRINGS "ENFORCE;OBSERVE;IGNORE" + CATEGORY "Modules" + MODULE CONTRACTS + ) + + if(HPX_WITH_CONTRACTS_MODE STREQUAL "ENFORCE") + hpx_add_config_define_namespace( + DEFINE HPX_CONTRACTS_MODE VALUE 0 NAMESPACE CONTRACTS + ) + elseif(HPX_WITH_CONTRACTS_MODE STREQUAL "OBSERVE") + hpx_add_config_define_namespace( + DEFINE HPX_CONTRACTS_MODE VALUE 1 NAMESPACE CONTRACTS + ) + elseif(HPX_WITH_CONTRACTS_MODE STREQUAL "IGNORE") + hpx_add_config_define_namespace( + DEFINE HPX_CONTRACTS_MODE VALUE 2 NAMESPACE CONTRACTS + ) + endif() endif() # Default location is $HPX_ROOT/libs/contracts/include -set(contracts_headers - hpx/contracts.hpp - hpx/contracts/macros.hpp - hpx/contracts/violation_handler.hpp +set(contracts_headers hpx/contracts.hpp hpx/contracts/macros.hpp + hpx/contracts/violation_handler.hpp ) set(contracts_macro_headers hpx/contracts/macros.hpp) diff --git a/libs/core/contracts/include/hpx/contracts/macros.hpp b/libs/core/contracts/include/hpx/contracts/macros.hpp index c1f9d0a06469..716e65f4c017 100644 --- a/libs/core/contracts/include/hpx/contracts/macros.hpp +++ b/libs/core/contracts/include/hpx/contracts/macros.hpp @@ -1,5 +1,6 @@ // Copyright (c) 2025 The STE||AR-Group // Copyright (c) 2025 Alexandros Papadakis +// Copyright (c) 2026 The STE||AR-Group // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -13,22 +14,22 @@ /// behavior when contracts are not available. /// /// ## API Reference: -/// - **HPX_PRE(condition)**: Precondition contracts (no-op in fallback mode) -/// - **HPX_POST(condition)**: Postcondition contracts (no-op in fallback mode) -/// - **HPX_CONTRACT_ASSERT(condition)**: Contract assertions (always available, maps to HPX_ASSERT) +/// - **HPX_PRE(condition)**: Precondition contracts +/// - **HPX_POST(condition)**: Postcondition contracts +/// - **HPX_CONTRACT_ASSERT(condition)**: Contract assertions /// /// ## Configuration: -/// Enable with: `cmake -DHPX_WITH_CONTRACTS=ON -DCMAKE_CXX_STANDARD=26` +/// Enable native contracts with: `cmake -DHPX_WITH_CONTRACTS=ON -DCMAKE_CXX_STANDARD=26` +/// Set fallback mode with: `cmake -DHPX_WITH_CONTRACTS_MODE=ENFORCE|OBSERVE|IGNORE` /// /// See docs/index.rst for comprehensive usage guide. #pragma once -#include #include +#include +#include -// Contract implementation: automatically selects native C++26 contracts -// or provides appropriate fallback behavior based on compiler capabilities #if defined(HPX_HAVE_CXX26_CONTRACTS) // Native C++26 contracts mode @@ -42,12 +43,40 @@ #define HPX_ASSERT(x) contract_assert(x) #endif -#else +#elif HPX_CONTRACTS_MODE == 2 // IGNORE: all contracts are no-ops -// Fallback mode: PRE/POST become no-ops for forward compatibility, -// CONTRACT_ASSERT maps to HPX_ASSERT for runtime validation #define HPX_PRE(x) -#define HPX_CONTRACT_ASSERT(x) HPX_ASSERT((x)) #define HPX_POST(x) +#define HPX_CONTRACT_ASSERT(x) + +#else // ENFORCE (0) or OBSERVE (1): runtime checking via violation handler + +#include + +// clang-format off +#define HPX_PRE(x) \ + do { \ + if (!(x)) \ + ::hpx::contracts::invoke_violation_handler( \ + {::hpx::contracts::contract_kind::pre, #x, \ + HPX_CURRENT_SOURCE_LOCATION()}); \ + } while (false) + +#define HPX_POST(x) \ + do { \ + if (!(x)) \ + ::hpx::contracts::invoke_violation_handler( \ + {::hpx::contracts::contract_kind::post, #x, \ + HPX_CURRENT_SOURCE_LOCATION()}); \ + } while (false) + +#define HPX_CONTRACT_ASSERT(x) \ + do { \ + if (!(x)) \ + ::hpx::contracts::invoke_violation_handler( \ + {::hpx::contracts::contract_kind::assertion, #x, \ + HPX_CURRENT_SOURCE_LOCATION()}); \ + } while (false) +// clang-format on #endif diff --git a/libs/core/contracts/include/hpx/contracts/violation_handler.hpp b/libs/core/contracts/include/hpx/contracts/violation_handler.hpp index e30be9d63932..c3573caa2fda 100644 --- a/libs/core/contracts/include/hpx/contracts/violation_handler.hpp +++ b/libs/core/contracts/include/hpx/contracts/violation_handler.hpp @@ -25,9 +25,11 @@ namespace hpx::contracts { hpx::source_location location; }; - HPX_CXX_CORE_EXPORT using violation_handler_t = void (*)(violation_info const&); + HPX_CXX_CORE_EXPORT using violation_handler_t = + void (*)(violation_info const&); - HPX_CORE_EXPORT void set_violation_handler(violation_handler_t handler) noexcept; + HPX_CORE_EXPORT void set_violation_handler( + violation_handler_t handler) noexcept; HPX_CORE_EXPORT violation_handler_t get_violation_handler() noexcept; HPX_CORE_EXPORT void default_violation_handler(violation_info const& info); diff --git a/libs/core/contracts/src/violation_handler.cpp b/libs/core/contracts/src/violation_handler.cpp index d3d0fc0430e7..ac01a8d05f4a 100644 --- a/libs/core/contracts/src/violation_handler.cpp +++ b/libs/core/contracts/src/violation_handler.cpp @@ -4,6 +4,7 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include #include #include @@ -49,7 +50,10 @@ namespace hpx::contracts { std::cerr << info.location << ": Contract " << kind_str << " '" << info.condition << "' violated\n"; + +#if HPX_CONTRACTS_MODE != 1 // abort in ENFORCE; continue in OBSERVE std::abort(); +#endif } void invoke_violation_handler(violation_info const& info) From f790fd276bf00b754439ac805e62b60e9b6d27e2 Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Sun, 19 Apr 2026 00:41:35 +0530 Subject: [PATCH 03/10] contracts: port test cases from PoC into module tests Signed-off-by: Sanchit2662 --- libs/core/contracts/CMakeLists.txt | 30 +++++++----- .../include/hpx/contracts/macros.hpp | 39 +++++++--------- libs/core/contracts/tests/unit/CMakeLists.txt | 13 ++++++ .../tests/unit/default_handler_aborts.cpp | 13 ++++++ .../unit/handler_receives_correct_info.cpp | 46 +++++++++++++++++++ .../tests/unit/violation_handler_invoked.cpp | 46 +++++++++++++++++++ 6 files changed, 154 insertions(+), 33 deletions(-) create mode 100644 libs/core/contracts/tests/unit/default_handler_aborts.cpp create mode 100644 libs/core/contracts/tests/unit/handler_receives_correct_info.cpp create mode 100644 libs/core/contracts/tests/unit/violation_handler_invoked.cpp diff --git a/libs/core/contracts/CMakeLists.txt b/libs/core/contracts/CMakeLists.txt index f45973e38e9f..22ddaa274d17 100644 --- a/libs/core/contracts/CMakeLists.txt +++ b/libs/core/contracts/CMakeLists.txt @@ -22,27 +22,35 @@ if(HPX_WITH_CXX26_CONTRACTS) ) endif() else() - # Contract evaluation mode for pre-C++26 compilers - hpx_option( - HPX_WITH_CONTRACTS_MODE STRING - "Contract evaluation mode for pre-C++26 compilers (ENFORCE, OBSERVE, IGNORE). (default: ENFORCE)" - "ENFORCE" - STRINGS "ENFORCE;OBSERVE;IGNORE" - CATEGORY "Modules" - MODULE CONTRACTS + # Contract evaluation mode for pre-C++26 compilers. Not registered via + # hpx_option(MODULE CONTRACTS) to avoid triggering the config_entries.cpp + # generation mechanism before add_hpx_module creates the build directory. + set(HPX_WITH_CONTRACTS_MODE + "ENFORCE" + CACHE STRING + "Contract evaluation mode for pre-C++26 compilers (ENFORCE, OBSERVE, IGNORE)." + ) + set_property( + CACHE HPX_WITH_CONTRACTS_MODE PROPERTY STRINGS "ENFORCE;OBSERVE;IGNORE" ) if(HPX_WITH_CONTRACTS_MODE STREQUAL "ENFORCE") hpx_add_config_define_namespace( - DEFINE HPX_CONTRACTS_MODE VALUE 0 NAMESPACE CONTRACTS + DEFINE HPX_CONTRACTS_MODE + VALUE 0 + NAMESPACE CONTRACTS ) elseif(HPX_WITH_CONTRACTS_MODE STREQUAL "OBSERVE") hpx_add_config_define_namespace( - DEFINE HPX_CONTRACTS_MODE VALUE 1 NAMESPACE CONTRACTS + DEFINE HPX_CONTRACTS_MODE + VALUE 1 + NAMESPACE CONTRACTS ) elseif(HPX_WITH_CONTRACTS_MODE STREQUAL "IGNORE") hpx_add_config_define_namespace( - DEFINE HPX_CONTRACTS_MODE VALUE 2 NAMESPACE CONTRACTS + DEFINE HPX_CONTRACTS_MODE + VALUE 2 + NAMESPACE CONTRACTS ) endif() endif() diff --git a/libs/core/contracts/include/hpx/contracts/macros.hpp b/libs/core/contracts/include/hpx/contracts/macros.hpp index 716e65f4c017..9e7077cda642 100644 --- a/libs/core/contracts/include/hpx/contracts/macros.hpp +++ b/libs/core/contracts/include/hpx/contracts/macros.hpp @@ -14,9 +14,12 @@ /// behavior when contracts are not available. /// /// ## API Reference: -/// - **HPX_PRE(condition)**: Precondition contracts -/// - **HPX_POST(condition)**: Postcondition contracts -/// - **HPX_CONTRACT_ASSERT(condition)**: Contract assertions +/// - **HPX_PRE(condition)**: Precondition contracts (declaration specifier in +/// C++26; no-op in fallback mode) +/// - **HPX_POST(condition)**: Postcondition contracts (declaration specifier +/// in C++26; no-op in fallback mode) +/// - **HPX_CONTRACT_ASSERT(condition)**: Contract assertions (always active; +/// dispatches on HPX_WITH_CONTRACTS_MODE in fallback mode) /// /// ## Configuration: /// Enable native contracts with: `cmake -DHPX_WITH_CONTRACTS=ON -DCMAKE_CXX_STANDARD=26` @@ -26,9 +29,9 @@ #pragma once -#include #include #include +#include #if defined(HPX_HAVE_CXX26_CONTRACTS) @@ -43,10 +46,16 @@ #define HPX_ASSERT(x) contract_assert(x) #endif -#elif HPX_CONTRACTS_MODE == 2 // IGNORE: all contracts are no-ops +#else // fallback mode +// HPX_PRE and HPX_POST are declaration specifiers in C++26 and cannot be +// replicated as statement macros without changing call sites. Keep them as +// no-ops in fallback regardless of mode. #define HPX_PRE(x) #define HPX_POST(x) + +#if HPX_CONTRACTS_MODE == 2 // IGNORE + #define HPX_CONTRACT_ASSERT(x) #else // ENFORCE (0) or OBSERVE (1): runtime checking via violation handler @@ -54,22 +63,6 @@ #include // clang-format off -#define HPX_PRE(x) \ - do { \ - if (!(x)) \ - ::hpx::contracts::invoke_violation_handler( \ - {::hpx::contracts::contract_kind::pre, #x, \ - HPX_CURRENT_SOURCE_LOCATION()}); \ - } while (false) - -#define HPX_POST(x) \ - do { \ - if (!(x)) \ - ::hpx::contracts::invoke_violation_handler( \ - {::hpx::contracts::contract_kind::post, #x, \ - HPX_CURRENT_SOURCE_LOCATION()}); \ - } while (false) - #define HPX_CONTRACT_ASSERT(x) \ do { \ if (!(x)) \ @@ -79,4 +72,6 @@ } while (false) // clang-format on -#endif +#endif // HPX_CONTRACTS_MODE + +#endif // HPX_HAVE_CXX26_CONTRACTS diff --git a/libs/core/contracts/tests/unit/CMakeLists.txt b/libs/core/contracts/tests/unit/CMakeLists.txt index 78f1e62e0f93..efb2527bbcfe 100644 --- a/libs/core/contracts/tests/unit/CMakeLists.txt +++ b/libs/core/contracts/tests/unit/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright (c) 2025 Alexandros Papadakis +# Copyright (c) 2026 The STE||AR-Group # HPX Contracts Module Unit Tests # # SPDX-License-Identifier: BSL-1.0 @@ -15,6 +16,9 @@ set(contract_tests fallback_contracts_succeed fallback_contracts_fail disabled_contracts + violation_handler_invoked + default_handler_aborts + handler_receives_correct_info ) foreach(test ${contract_tests}) @@ -54,4 +58,13 @@ else() tests.unit.modules.contracts.fallback_contracts_fail PROPERTIES WILL_FAIL $<$:ON> ) + + # default_handler_aborts calls HPX_CONTRACT_ASSERT(false) with no custom + # handler; the default handler aborts in ENFORCE mode + if(HPX_WITH_CONTRACTS_MODE STREQUAL "ENFORCE" OR NOT HPX_WITH_CONTRACTS_MODE) + set_tests_properties( + tests.unit.modules.contracts.default_handler_aborts PROPERTIES WILL_FAIL + ON + ) + endif() endif() diff --git a/libs/core/contracts/tests/unit/default_handler_aborts.cpp b/libs/core/contracts/tests/unit/default_handler_aborts.cpp new file mode 100644 index 000000000000..6b03112188a8 --- /dev/null +++ b/libs/core/contracts/tests/unit/default_handler_aborts.cpp @@ -0,0 +1,13 @@ +// Copyright (c) 2026 The STE||AR-Group +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +int main() +{ + HPX_CONTRACT_ASSERT(false); // default handler should abort here + return 0; +} diff --git a/libs/core/contracts/tests/unit/handler_receives_correct_info.cpp b/libs/core/contracts/tests/unit/handler_receives_correct_info.cpp new file mode 100644 index 000000000000..f33e331b76b8 --- /dev/null +++ b/libs/core/contracts/tests/unit/handler_receives_correct_info.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2026 The STE||AR-Group +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#include + +#if !defined(HPX_HAVE_CXX26_CONTRACTS) && HPX_CONTRACTS_MODE == 2 + +int main() +{ + return 0; +} + +#else + +namespace { + hpx::contracts::violation_info captured{ + hpx::contracts::contract_kind::assertion, nullptr, {}}; + + void capturing_handler(hpx::contracts::violation_info const& info) + { + captured = info; + } +} // namespace + +int main() +{ + hpx::contracts::set_violation_handler(capturing_handler); + + HPX_CONTRACT_ASSERT(1 == 2); // NOLINT: intentional false assertion + + HPX_TEST(captured.condition != nullptr); + HPX_TEST(std::strstr(captured.condition, "1 == 2") != nullptr); + HPX_TEST(captured.kind == hpx::contracts::contract_kind::assertion); + HPX_TEST(captured.location.line() > 0); + + return hpx::util::report_errors(); +} + +#endif diff --git a/libs/core/contracts/tests/unit/violation_handler_invoked.cpp b/libs/core/contracts/tests/unit/violation_handler_invoked.cpp new file mode 100644 index 000000000000..ca0d614e7485 --- /dev/null +++ b/libs/core/contracts/tests/unit/violation_handler_invoked.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2026 The STE||AR-Group +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#if !defined(HPX_HAVE_CXX26_CONTRACTS) && HPX_CONTRACTS_MODE == 2 + +// IGNORE mode: contracts are no-ops, nothing to test here. +int main() +{ + return 0; +} + +#else + +namespace { + int handler_call_count = 0; + hpx::contracts::contract_kind last_kind = + hpx::contracts::contract_kind::assertion; + + void recording_handler(hpx::contracts::violation_info const& info) + { + ++handler_call_count; + last_kind = info.kind; + // deliberately does not abort so the test can continue + } +} // namespace + +int main() +{ + hpx::contracts::set_violation_handler(recording_handler); + + HPX_CONTRACT_ASSERT(false); // should invoke recording_handler + + HPX_TEST_EQ(handler_call_count, 1); + HPX_TEST(last_kind == hpx::contracts::contract_kind::assertion); + + return hpx::util::report_errors(); +} + +#endif From 7dfefd116d9fa25810397e14f1af5776df50c43b Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Sun, 19 Apr 2026 02:22:21 +0530 Subject: [PATCH 04/10] contracts: fix cmake-format issues Signed-off-by: Sanchit2662 --- libs/core/contracts/CMakeLists.txt | 5 +++-- libs/core/contracts/tests/unit/CMakeLists.txt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/core/contracts/CMakeLists.txt b/libs/core/contracts/CMakeLists.txt index 22ddaa274d17..9e8726d65a1f 100644 --- a/libs/core/contracts/CMakeLists.txt +++ b/libs/core/contracts/CMakeLists.txt @@ -27,8 +27,9 @@ else() # generation mechanism before add_hpx_module creates the build directory. set(HPX_WITH_CONTRACTS_MODE "ENFORCE" - CACHE STRING - "Contract evaluation mode for pre-C++26 compilers (ENFORCE, OBSERVE, IGNORE)." + CACHE + STRING + "Contract evaluation mode for pre-C++26 compilers (ENFORCE, OBSERVE, IGNORE)." ) set_property( CACHE HPX_WITH_CONTRACTS_MODE PROPERTY STRINGS "ENFORCE;OBSERVE;IGNORE" diff --git a/libs/core/contracts/tests/unit/CMakeLists.txt b/libs/core/contracts/tests/unit/CMakeLists.txt index efb2527bbcfe..ef1bb03df468 100644 --- a/libs/core/contracts/tests/unit/CMakeLists.txt +++ b/libs/core/contracts/tests/unit/CMakeLists.txt @@ -64,7 +64,7 @@ else() if(HPX_WITH_CONTRACTS_MODE STREQUAL "ENFORCE" OR NOT HPX_WITH_CONTRACTS_MODE) set_tests_properties( tests.unit.modules.contracts.default_handler_aborts PROPERTIES WILL_FAIL - ON + ON ) endif() endif() From dd154846bcd8f1d30e813c1b7e5b7b691ec5312e Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Sun, 19 Apr 2026 04:06:29 +0530 Subject: [PATCH 05/10] contracts: address review feedback Signed-off-by: Sanchit2662 --- libs/core/contracts/CMakeLists.txt | 23 ++++++++----------- .../include/hpx/contracts/macros.hpp | 7 +++--- .../hpx/contracts/violation_handler.hpp | 17 ++++++++------ libs/core/contracts/src/violation_handler.cpp | 8 +++++-- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/libs/core/contracts/CMakeLists.txt b/libs/core/contracts/CMakeLists.txt index 9e8726d65a1f..62310dbda5af 100644 --- a/libs/core/contracts/CMakeLists.txt +++ b/libs/core/contracts/CMakeLists.txt @@ -22,34 +22,29 @@ if(HPX_WITH_CXX26_CONTRACTS) ) endif() else() - # Contract evaluation mode for pre-C++26 compilers. Not registered via - # hpx_option(MODULE CONTRACTS) to avoid triggering the config_entries.cpp - # generation mechanism before add_hpx_module creates the build directory. - set(HPX_WITH_CONTRACTS_MODE - "ENFORCE" - CACHE - STRING - "Contract evaluation mode for pre-C++26 compilers (ENFORCE, OBSERVE, IGNORE)." - ) - set_property( - CACHE HPX_WITH_CONTRACTS_MODE PROPERTY STRINGS "ENFORCE;OBSERVE;IGNORE" + hpx_option( + HPX_WITH_CONTRACTS_MODE + STRING + "Contract evaluation mode for pre-C++26 compilers, options are: ENFORCE, OBSERVE, IGNORE" + "ENFORCE" + STRINGS "ENFORCE;OBSERVE;IGNORE" ) if(HPX_WITH_CONTRACTS_MODE STREQUAL "ENFORCE") hpx_add_config_define_namespace( - DEFINE HPX_CONTRACTS_MODE + DEFINE HPX_HAVE_CONTRACTS_MODE VALUE 0 NAMESPACE CONTRACTS ) elseif(HPX_WITH_CONTRACTS_MODE STREQUAL "OBSERVE") hpx_add_config_define_namespace( - DEFINE HPX_CONTRACTS_MODE + DEFINE HPX_HAVE_CONTRACTS_MODE VALUE 1 NAMESPACE CONTRACTS ) elseif(HPX_WITH_CONTRACTS_MODE STREQUAL "IGNORE") hpx_add_config_define_namespace( - DEFINE HPX_CONTRACTS_MODE + DEFINE HPX_HAVE_CONTRACTS_MODE VALUE 2 NAMESPACE CONTRACTS ) diff --git a/libs/core/contracts/include/hpx/contracts/macros.hpp b/libs/core/contracts/include/hpx/contracts/macros.hpp index 9e7077cda642..d0c3b2ecec11 100644 --- a/libs/core/contracts/include/hpx/contracts/macros.hpp +++ b/libs/core/contracts/include/hpx/contracts/macros.hpp @@ -1,6 +1,5 @@ -// Copyright (c) 2025 The STE||AR-Group +// Copyright (c) 2025-2026 The STE||AR-Group // Copyright (c) 2025 Alexandros Papadakis -// Copyright (c) 2026 The STE||AR-Group // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -54,7 +53,7 @@ #define HPX_PRE(x) #define HPX_POST(x) -#if HPX_CONTRACTS_MODE == 2 // IGNORE +#if HPX_HAVE_CONTRACTS_MODE == 2 // IGNORE #define HPX_CONTRACT_ASSERT(x) @@ -72,6 +71,6 @@ } while (false) // clang-format on -#endif // HPX_CONTRACTS_MODE +#endif // HPX_HAVE_CONTRACTS_MODE #endif // HPX_HAVE_CXX26_CONTRACTS diff --git a/libs/core/contracts/include/hpx/contracts/violation_handler.hpp b/libs/core/contracts/include/hpx/contracts/violation_handler.hpp index c3573caa2fda..f22825ac18a3 100644 --- a/libs/core/contracts/include/hpx/contracts/violation_handler.hpp +++ b/libs/core/contracts/include/hpx/contracts/violation_handler.hpp @@ -11,14 +11,14 @@ namespace hpx::contracts { - enum class contract_kind + HPX_CXX_CORE_EXPORT enum class contract_kind { pre, post, assertion }; - struct violation_info + HPX_CXX_CORE_EXPORT struct violation_info { contract_kind kind; char const* condition; @@ -28,11 +28,14 @@ namespace hpx::contracts { HPX_CXX_CORE_EXPORT using violation_handler_t = void (*)(violation_info const&); - HPX_CORE_EXPORT void set_violation_handler( - violation_handler_t handler) noexcept; - HPX_CORE_EXPORT violation_handler_t get_violation_handler() noexcept; + HPX_CXX_CORE_EXPORT HPX_CORE_EXPORT violation_handler_t + set_violation_handler(violation_handler_t handler) noexcept; + HPX_CXX_CORE_EXPORT HPX_CORE_EXPORT violation_handler_t + get_violation_handler() noexcept; - HPX_CORE_EXPORT void default_violation_handler(violation_info const& info); - HPX_CORE_EXPORT void invoke_violation_handler(violation_info const& info); + HPX_CXX_CORE_EXPORT HPX_CORE_EXPORT void default_violation_handler( + violation_info const& info); + HPX_CXX_CORE_EXPORT HPX_CORE_EXPORT void invoke_violation_handler( + violation_info const& info); } // namespace hpx::contracts diff --git a/libs/core/contracts/src/violation_handler.cpp b/libs/core/contracts/src/violation_handler.cpp index ac01a8d05f4a..bc7d9b1e2538 100644 --- a/libs/core/contracts/src/violation_handler.cpp +++ b/libs/core/contracts/src/violation_handler.cpp @@ -4,6 +4,7 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include #include #include @@ -22,9 +23,12 @@ namespace hpx::contracts { } // namespace detail - void set_violation_handler(violation_handler_t handler) noexcept + violation_handler_t set_violation_handler( + violation_handler_t handler) noexcept { + violation_handler_t old = detail::get_handler(); detail::get_handler() = handler; + return old; } violation_handler_t get_violation_handler() noexcept @@ -51,7 +55,7 @@ namespace hpx::contracts { std::cerr << info.location << ": Contract " << kind_str << " '" << info.condition << "' violated\n"; -#if HPX_CONTRACTS_MODE != 1 // abort in ENFORCE; continue in OBSERVE +#if HPX_HAVE_CONTRACTS_MODE != 1 // abort in ENFORCE; continue in OBSERVE std::abort(); #endif } From 2f9cfba2d421c2681d39adb37d8fbba0179003c7 Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Sun, 19 Apr 2026 13:32:52 +0530 Subject: [PATCH 06/10] contracts: fix CI build failures hpx_add_config_define_namespace treats a numeric "0" argument as falsy and emits a valueless #define, which caused the #if HPX_HAVE_CONTRACTS_MODE preprocessor check to fail with a syntax error on every build job. Shift the mode encoding to 1/2/3 (ENFORCE/OBSERVE/IGNORE) and guard the checks with defined() so the macro is robust to the emit path. Also update the fallback test WILL_FAIL expectations: HPX_CONTRACT_ASSERT now routes through the violation handler in every build config, so tests that hit it must WILL_FAIL unconditionally under ENFORCE (the default), not only in Debug. --- libs/core/contracts/CMakeLists.txt | 8 ++-- .../include/hpx/contracts/macros.hpp | 2 +- .../hpx/contracts/violation_handler.hpp | 7 +--- libs/core/contracts/src/violation_handler.cpp | 3 +- libs/core/contracts/tests/unit/CMakeLists.txt | 38 ++++++++++--------- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/libs/core/contracts/CMakeLists.txt b/libs/core/contracts/CMakeLists.txt index 62310dbda5af..51e344dd5923 100644 --- a/libs/core/contracts/CMakeLists.txt +++ b/libs/core/contracts/CMakeLists.txt @@ -30,22 +30,24 @@ else() STRINGS "ENFORCE;OBSERVE;IGNORE" ) + # Note: values start at 1 because hpx_add_config_define_namespace treats a + # numeric "0" as falsy and would emit a valueless #define. if(HPX_WITH_CONTRACTS_MODE STREQUAL "ENFORCE") hpx_add_config_define_namespace( DEFINE HPX_HAVE_CONTRACTS_MODE - VALUE 0 + VALUE 1 NAMESPACE CONTRACTS ) elseif(HPX_WITH_CONTRACTS_MODE STREQUAL "OBSERVE") hpx_add_config_define_namespace( DEFINE HPX_HAVE_CONTRACTS_MODE - VALUE 1 + VALUE 2 NAMESPACE CONTRACTS ) elseif(HPX_WITH_CONTRACTS_MODE STREQUAL "IGNORE") hpx_add_config_define_namespace( DEFINE HPX_HAVE_CONTRACTS_MODE - VALUE 2 + VALUE 3 NAMESPACE CONTRACTS ) endif() diff --git a/libs/core/contracts/include/hpx/contracts/macros.hpp b/libs/core/contracts/include/hpx/contracts/macros.hpp index d0c3b2ecec11..418254456ad7 100644 --- a/libs/core/contracts/include/hpx/contracts/macros.hpp +++ b/libs/core/contracts/include/hpx/contracts/macros.hpp @@ -53,7 +53,7 @@ #define HPX_PRE(x) #define HPX_POST(x) -#if HPX_HAVE_CONTRACTS_MODE == 2 // IGNORE +#if defined(HPX_HAVE_CONTRACTS_MODE) && HPX_HAVE_CONTRACTS_MODE == 3 // IGNORE #define HPX_CONTRACT_ASSERT(x) diff --git a/libs/core/contracts/include/hpx/contracts/violation_handler.hpp b/libs/core/contracts/include/hpx/contracts/violation_handler.hpp index f22825ac18a3..1f3455c8db89 100644 --- a/libs/core/contracts/include/hpx/contracts/violation_handler.hpp +++ b/libs/core/contracts/include/hpx/contracts/violation_handler.hpp @@ -11,12 +11,7 @@ namespace hpx::contracts { - HPX_CXX_CORE_EXPORT enum class contract_kind - { - pre, - post, - assertion - }; + HPX_CXX_CORE_EXPORT enum class contract_kind { pre, post, assertion }; HPX_CXX_CORE_EXPORT struct violation_info { diff --git a/libs/core/contracts/src/violation_handler.cpp b/libs/core/contracts/src/violation_handler.cpp index bc7d9b1e2538..a80838c03cf9 100644 --- a/libs/core/contracts/src/violation_handler.cpp +++ b/libs/core/contracts/src/violation_handler.cpp @@ -55,7 +55,8 @@ namespace hpx::contracts { std::cerr << info.location << ": Contract " << kind_str << " '" << info.condition << "' violated\n"; -#if HPX_HAVE_CONTRACTS_MODE != 1 // abort in ENFORCE; continue in OBSERVE +#if !defined(HPX_HAVE_CONTRACTS_MODE) || HPX_HAVE_CONTRACTS_MODE != 2 + // abort in ENFORCE (and by default); continue in OBSERVE std::abort(); #endif } diff --git a/libs/core/contracts/tests/unit/CMakeLists.txt b/libs/core/contracts/tests/unit/CMakeLists.txt index ef1bb03df468..10ba004be7b6 100644 --- a/libs/core/contracts/tests/unit/CMakeLists.txt +++ b/libs/core/contracts/tests/unit/CMakeLists.txt @@ -33,16 +33,8 @@ foreach(test ${contract_tests}) add_hpx_unit_test("modules.contracts" ${test}) endforeach() -# Set failure expectation for fallback failure test Fallback only fails in Debug -# mode (HPX_ASSERT or HPX_CONTRACT_ASSERT behavior) -set_tests_properties( - tests.unit.modules.contracts.declaration_contracts_fail_contract_assert - PROPERTIES WILL_FAIL $<$:ON> -) - if(HPX_HAVE_CXX26_CONTRACTS) - # Set failure expectations for declaration contract failure tests Native - # contracts should fail when violated + # Native C++26 contracts always fail when violated, regardless of build config set_tests_properties( tests.unit.modules.contracts.declaration_contracts_fail_pre PROPERTIES WILL_FAIL ON @@ -51,20 +43,32 @@ if(HPX_HAVE_CXX26_CONTRACTS) tests.unit.modules.contracts.declaration_contracts_fail_post PROPERTIES WILL_FAIL ON ) -else() - # Set failure expectation for fallback failure test Fallback only fails in - # Debug mode (HPX_ASSERT behavior) + # HPX_CONTRACT_ASSERT still routes through HPX_ASSERT in native mode — Debug + # only set_tests_properties( - tests.unit.modules.contracts.fallback_contracts_fail + tests.unit.modules.contracts.declaration_contracts_fail_contract_assert PROPERTIES WILL_FAIL $<$:ON> ) - - # default_handler_aborts calls HPX_CONTRACT_ASSERT(false) with no custom - # handler; the default handler aborts in ENFORCE mode - if(HPX_WITH_CONTRACTS_MODE STREQUAL "ENFORCE" OR NOT HPX_WITH_CONTRACTS_MODE) +else() + # Fallback mode: HPX_PRE / HPX_POST are no-ops so fail_pre / fail_post succeed. + # HPX_CONTRACT_ASSERT routes through invoke_violation_handler, whose default + # handler aborts unless HPX_WITH_CONTRACTS_MODE=OBSERVE. + if(NOT HPX_WITH_CONTRACTS_MODE STREQUAL "OBSERVE" + AND NOT HPX_WITH_CONTRACTS_MODE STREQUAL "IGNORE" + ) + set_tests_properties( + tests.unit.modules.contracts.declaration_contracts_fail_contract_assert + PROPERTIES WILL_FAIL ON + ) set_tests_properties( tests.unit.modules.contracts.default_handler_aborts PROPERTIES WILL_FAIL ON ) endif() + + # fallback_contracts_fail uses HPX_ASSERT directly, so it only fails in Debug + set_tests_properties( + tests.unit.modules.contracts.fallback_contracts_fail + PROPERTIES WILL_FAIL $<$:ON> + ) endif() From 4f8ca41dc7888e224b16f66556dd1601cffad43f Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Sun, 19 Apr 2026 15:08:24 +0530 Subject: [PATCH 07/10] futures: annotate future::get() and shared_future::get() with preconditions Adds HPX_PRE(this->valid()) to both get() overloads as the first real end-to-end use of the contracts infrastructure. Under native C++26 the compiler enforces the pre-condition; in fallback mode HPX_PRE is a no-op and the existing no_state throw continues to handle invalid futures. Also fold in clang-format and cmake-format fixes flagged by CI on the previous commit. Signed-off-by: Sanchit2662 --- libs/core/contracts/include/hpx/contracts/macros.hpp | 3 ++- libs/core/contracts/tests/unit/CMakeLists.txt | 6 +++--- libs/core/futures/CMakeLists.txt | 1 + libs/core/futures/include/hpx/futures/future.hpp | 4 +++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/libs/core/contracts/include/hpx/contracts/macros.hpp b/libs/core/contracts/include/hpx/contracts/macros.hpp index 418254456ad7..ee997030d379 100644 --- a/libs/core/contracts/include/hpx/contracts/macros.hpp +++ b/libs/core/contracts/include/hpx/contracts/macros.hpp @@ -53,7 +53,8 @@ #define HPX_PRE(x) #define HPX_POST(x) -#if defined(HPX_HAVE_CONTRACTS_MODE) && HPX_HAVE_CONTRACTS_MODE == 3 // IGNORE +#if defined(HPX_HAVE_CONTRACTS_MODE) && \ + HPX_HAVE_CONTRACTS_MODE == 3 // IGNORE #define HPX_CONTRACT_ASSERT(x) diff --git a/libs/core/contracts/tests/unit/CMakeLists.txt b/libs/core/contracts/tests/unit/CMakeLists.txt index 10ba004be7b6..aab3272ddafc 100644 --- a/libs/core/contracts/tests/unit/CMakeLists.txt +++ b/libs/core/contracts/tests/unit/CMakeLists.txt @@ -50,9 +50,9 @@ if(HPX_HAVE_CXX26_CONTRACTS) PROPERTIES WILL_FAIL $<$:ON> ) else() - # Fallback mode: HPX_PRE / HPX_POST are no-ops so fail_pre / fail_post succeed. - # HPX_CONTRACT_ASSERT routes through invoke_violation_handler, whose default - # handler aborts unless HPX_WITH_CONTRACTS_MODE=OBSERVE. + # Fallback mode: HPX_PRE / HPX_POST are no-ops so fail_pre / fail_post + # succeed. HPX_CONTRACT_ASSERT routes through invoke_violation_handler, whose + # default handler aborts unless HPX_WITH_CONTRACTS_MODE=OBSERVE. if(NOT HPX_WITH_CONTRACTS_MODE STREQUAL "OBSERVE" AND NOT HPX_WITH_CONTRACTS_MODE STREQUAL "IGNORE" ) diff --git a/libs/core/futures/CMakeLists.txt b/libs/core/futures/CMakeLists.txt index 86cf24785a9c..98863b63bde0 100644 --- a/libs/core/futures/CMakeLists.txt +++ b/libs/core/futures/CMakeLists.txt @@ -77,6 +77,7 @@ add_hpx_module( hpx_concepts hpx_concurrency hpx_config + hpx_contracts hpx_coroutines hpx_datastructures hpx_errors diff --git a/libs/core/futures/include/hpx/futures/future.hpp b/libs/core/futures/include/hpx/futures/future.hpp index 6c777b0e3574..1f72de3f3d78 100644 --- a/libs/core/futures/include/hpx/futures/future.hpp +++ b/libs/core/futures/include/hpx/futures/future.hpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -662,6 +663,7 @@ namespace hpx { // shared state. // Postcondition: valid() == false. typename hpx::traits::future_traits::result_type get() + HPX_PRE(this->valid()) { if (!this->shared_state_) { @@ -1012,7 +1014,7 @@ namespace hpx { // shared state. // Postcondition: valid() == false. typename hpx::traits::future_traits::result_type get() - const //-V659 + const HPX_PRE(this->valid()) //-V659 { if (!this->shared_state_) { From 5e294d96301626dd34c1b5b59beea8a9b2e42725 Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Sun, 19 Apr 2026 16:22:28 +0530 Subject: [PATCH 08/10] datastructures: annotate small_vector element access with preconditions enforced pre-conditions; under fallback they are no-ops, matching the design of HPX_PRE as a declaration specifier. Signed-off-by: Sanchit2662 --- libs/core/datastructures/CMakeLists.txt | 4 ++-- .../hpx/datastructures/detail/small_vector.hpp | 16 ++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libs/core/datastructures/CMakeLists.txt b/libs/core/datastructures/CMakeLists.txt index f8dcfc7630b0..fd1587308996 100644 --- a/libs/core/datastructures/CMakeLists.txt +++ b/libs/core/datastructures/CMakeLists.txt @@ -101,7 +101,7 @@ add_hpx_module( "hpx/datastructures/detail/flat_set.hpp" "hpx/datastructures/detail/intrusive_list.hpp" "hpx/datastructures/detail/small_vector.hpp" - MODULE_DEPENDENCIES hpx_assertion hpx_config hpx_concepts hpx_errors - hpx_serialization hpx_type_support + MODULE_DEPENDENCIES hpx_assertion hpx_config hpx_concepts hpx_contracts + hpx_errors hpx_serialization hpx_type_support CMAKE_SUBDIRS examples tests ) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index f601f921d157..1b6118e2eedc 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -938,12 +939,13 @@ namespace hpx::detail { } [[nodiscard]] auto operator[](std::size_t idx) const noexcept - -> T const& + HPX_PRE(idx < this->size()) -> T const& { return *(data() + idx); } - [[nodiscard]] auto operator[](std::size_t idx) noexcept -> T& + [[nodiscard]] auto operator[](std::size_t idx) noexcept + HPX_PRE(idx < this->size()) -> T& { return *(data() + idx); } @@ -1034,17 +1036,19 @@ namespace hpx::detail { return const_reverse_iterator{begin()}; } - [[nodiscard]] auto front() const noexcept -> T const& + [[nodiscard]] auto front() const noexcept + HPX_PRE(!this->empty()) -> T const& { return *data(); } - [[nodiscard]] auto front() noexcept -> T& + [[nodiscard]] auto front() noexcept HPX_PRE(!this->empty()) -> T& { return *data(); } - [[nodiscard]] auto back() const noexcept -> T const& + [[nodiscard]] auto back() const noexcept + HPX_PRE(!this->empty()) -> T const& { if (is_direct()) { @@ -1055,7 +1059,7 @@ namespace hpx::detail { data() + size() - 1); } - [[nodiscard]] auto back() noexcept -> T& + [[nodiscard]] auto back() noexcept HPX_PRE(!this->empty()) -> T& { if (is_direct()) { From 3fc42f07a5dda3bcaf8b54dfd744513042cb617b Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Sun, 19 Apr 2026 17:24:10 +0530 Subject: [PATCH 09/10] datastructures: fix clang-format / cmake-format Signed-off-by: Sanchit2662 --- libs/core/datastructures/CMakeLists.txt | 10 ++++++++-- .../include/hpx/datastructures/detail/small_vector.hpp | 8 ++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/libs/core/datastructures/CMakeLists.txt b/libs/core/datastructures/CMakeLists.txt index fd1587308996..db0d23c5cb02 100644 --- a/libs/core/datastructures/CMakeLists.txt +++ b/libs/core/datastructures/CMakeLists.txt @@ -101,7 +101,13 @@ add_hpx_module( "hpx/datastructures/detail/flat_set.hpp" "hpx/datastructures/detail/intrusive_list.hpp" "hpx/datastructures/detail/small_vector.hpp" - MODULE_DEPENDENCIES hpx_assertion hpx_config hpx_concepts hpx_contracts - hpx_errors hpx_serialization hpx_type_support + MODULE_DEPENDENCIES + hpx_assertion + hpx_config + hpx_concepts + hpx_contracts + hpx_errors + hpx_serialization + hpx_type_support CMAKE_SUBDIRS examples tests ) diff --git a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp index 1b6118e2eedc..4cec16a192b0 100644 --- a/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp +++ b/libs/core/datastructures/include/hpx/datastructures/detail/small_vector.hpp @@ -1036,8 +1036,8 @@ namespace hpx::detail { return const_reverse_iterator{begin()}; } - [[nodiscard]] auto front() const noexcept - HPX_PRE(!this->empty()) -> T const& + [[nodiscard]] auto front() const noexcept HPX_PRE(!this->empty()) + -> T const& { return *data(); } @@ -1047,8 +1047,8 @@ namespace hpx::detail { return *data(); } - [[nodiscard]] auto back() const noexcept - HPX_PRE(!this->empty()) -> T const& + [[nodiscard]] auto back() const noexcept HPX_PRE(!this->empty()) + -> T const& { if (is_direct()) { From 93e4cfee7564a05f8e4cbf9eb5adfc527f74a90a Mon Sep 17 00:00:00 2001 From: Sanchit2662 Date: Tue, 21 Apr 2026 17:52:43 +0530 Subject: [PATCH 10/10] algorithms: annotate sort and stable_sort with preconditions Add HPX_PRE(first <= last) to hpx::sort and hpx::stable_sort (both sequential and parallel overloads). Both algorithms already enforce std::random_access_iterator via static_assert, so <= is always valid. Signed-off-by: Sanchit2662 --- libs/core/algorithms/CMakeLists.txt | 1 + .../algorithms/include/hpx/parallel/algorithms/sort.hpp | 7 ++++--- .../include/hpx/parallel/algorithms/stable_sort.hpp | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libs/core/algorithms/CMakeLists.txt b/libs/core/algorithms/CMakeLists.txt index 1b880638f24d..a7898abeb80b 100644 --- a/libs/core/algorithms/CMakeLists.txt +++ b/libs/core/algorithms/CMakeLists.txt @@ -279,6 +279,7 @@ add_hpx_module( hpx_concepts hpx_concurrency hpx_config + hpx_contracts hpx_coroutines hpx_datastructures hpx_errors diff --git a/libs/core/algorithms/include/hpx/parallel/algorithms/sort.hpp b/libs/core/algorithms/include/hpx/parallel/algorithms/sort.hpp index 8b018d02da16..26cee15f7399 100644 --- a/libs/core/algorithms/include/hpx/parallel/algorithms/sort.hpp +++ b/libs/core/algorithms/include/hpx/parallel/algorithms/sort.hpp @@ -152,6 +152,7 @@ namespace hpx { #include #include #include +#include #include #include #include @@ -392,8 +393,8 @@ namespace hpx { > ) // clang-format on - friend void tag_fallback_invoke( - hpx::sort_t, RandomIt first, RandomIt last, Comp comp = Comp()) + friend void tag_fallback_invoke(hpx::sort_t, RandomIt first, + RandomIt last, Comp comp = Comp()) HPX_PRE(first <= last) { static_assert(std::random_access_iterator, "Requires a random access iterator."); @@ -416,7 +417,7 @@ namespace hpx { // clang-format on friend parallel::util::detail::algorithm_result_t tag_fallback_invoke(hpx::sort_t, ExPolicy&& policy, RandomIt first, - RandomIt last, Comp comp = Comp()) + RandomIt last, Comp comp = Comp()) HPX_PRE(first <= last) { static_assert(std::random_access_iterator, "Requires a random access iterator."); diff --git a/libs/core/algorithms/include/hpx/parallel/algorithms/stable_sort.hpp b/libs/core/algorithms/include/hpx/parallel/algorithms/stable_sort.hpp index 0ef9f99219f8..71d7e8d6a2db 100644 --- a/libs/core/algorithms/include/hpx/parallel/algorithms/stable_sort.hpp +++ b/libs/core/algorithms/include/hpx/parallel/algorithms/stable_sort.hpp @@ -150,6 +150,7 @@ namespace hpx { #include #include +#include #include #include #include @@ -285,7 +286,7 @@ namespace hpx { ) // clang-format on friend void tag_fallback_invoke(hpx::stable_sort_t, RandomIt first, - RandomIt last, Comp comp = Comp()) + RandomIt last, Comp comp = Comp()) HPX_PRE(first <= last) { static_assert(std::random_access_iterator, "Requires a random access iterator."); @@ -310,6 +311,7 @@ namespace hpx { friend hpx::parallel::util::detail::algorithm_result_t tag_fallback_invoke(hpx::stable_sort_t, ExPolicy&& policy, RandomIt first, RandomIt last, Comp comp = Comp()) + HPX_PRE(first <= last) { static_assert(std::random_access_iterator, "Requires a random access iterator.");