diff --git a/CHANGELOG.md b/CHANGELOG.md index 126fdff584c8..480b9883166a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [7.0.14] + +[7.0.14]: https://github.com/microsoft/CCF/releases/tag/ccf-7.0.14 + +### Changed + +- CCF and C++ applications built against it now require C++23. The supported minimum Clang version remains 18.1.2. (#8234) + ## [7.0.13] [7.0.13]: https://github.com/microsoft/CCF/releases/tag/ccf-7.0.13 diff --git a/cmake/preproject.cmake b/cmake/preproject.cmake index 289929b6bcbc..a8cb2db85488 100644 --- a/cmake/preproject.cmake +++ b/cmake/preproject.cmake @@ -83,4 +83,5 @@ function(add_warning_checks name) ) endfunction() -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/include/ccf/byte_vector.h b/include/ccf/byte_vector.h index 8c4fc6043011..7cb14debf5ff 100644 --- a/include/ccf/byte_vector.h +++ b/include/ccf/byte_vector.h @@ -8,7 +8,10 @@ #include #include #include +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" #include +#pragma clang diagnostic pop namespace ccf { diff --git a/include/ccf/ds/enum_formatter.h b/include/ccf/ds/enum_formatter.h index 2aa16f62a530..d96ca9d359e3 100644 --- a/include/ccf/ds/enum_formatter.h +++ b/include/ccf/ds/enum_formatter.h @@ -4,6 +4,7 @@ #define FMT_HEADER_ONLY #include +#include /** * Generic formatter for scoped enums. @@ -22,8 +23,7 @@ struct formatter, char>> template auto format(const E& value, FormatContext& ctx) const { - return fmt::format_to( - ctx.out(), "{}", static_cast>(value)); + return fmt::format_to(ctx.out(), "{}", std::to_underlying(value)); } }; FMT_END_NAMESPACE diff --git a/include/ccf/ds/hash.h b/include/ccf/ds/hash.h index 3f1b3227a2c2..28ab493cdb69 100644 --- a/include/ccf/ds/hash.h +++ b/include/ccf/ds/hash.h @@ -6,7 +6,10 @@ #include #include +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" #include +#pragma clang diagnostic pop #include #include diff --git a/include/ccf/ds/logger.h b/include/ccf/ds/logger.h index dd7cb6513264..1747fa23342c 100644 --- a/include/ccf/ds/logger.h +++ b/include/ccf/ds/logger.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace ccf::logger { @@ -25,7 +26,7 @@ namespace ccf::logger static constexpr const char* to_string(LoggerLevel l) { - return LevelNames[static_cast(l)]; + return LevelNames[std::to_underlying(l)]; } static constexpr long int ns_per_s = 1'000'000'000; diff --git a/include/ccf/endpoint.h b/include/ccf/endpoint.h index eafcc4d34c39..9f75fd969da8 100644 --- a/include/ccf/endpoint.h +++ b/include/ccf/endpoint.h @@ -542,8 +542,7 @@ struct formatter default: { throw std::logic_error(fmt::format( - "Unhandled value for ForwardingRequired: {}", - static_cast(v))); + "Unhandled value for ForwardingRequired: {}", std::to_underlying(v))); } } } diff --git a/include/ccf/js/kv_access_permissions.h b/include/ccf/js/kv_access_permissions.h index 9ce17b0bc402..86641f56ff82 100644 --- a/include/ccf/js/kv_access_permissions.h +++ b/include/ccf/js/kv_access_permissions.h @@ -4,6 +4,8 @@ #include "ccf/js/core/context.h" +#include + namespace ccf::js { enum class KVAccessPermissions : uint8_t @@ -17,9 +19,7 @@ namespace ccf::js inline KVAccessPermissions intersect_access_permissions( KVAccessPermissions l, KVAccessPermissions r) { - /* This could use std::to_underlying from C++23 */ - using T = std::underlying_type_t; - const auto intersection = (T)l & (T)r; - return KVAccessPermissions(intersection); + const auto intersection = std::to_underlying(l) & std::to_underlying(r); + return static_cast(intersection); } } diff --git a/include/ccf/service/node_info_network.h b/include/ccf/service/node_info_network.h index d5433ad60325..b6788e58d6a5 100644 --- a/include/ccf/service/node_info_network.h +++ b/include/ccf/service/node_info_network.h @@ -222,7 +222,7 @@ namespace ccf // rsplit_1 splits on the last ':'. When the address has no port it returns // ("", addr), which would wrongly put the host in the port slot; handle the // port-less case explicitly so the host stays in the first position. - if (addr.find(':') == std::string::npos) + if (!addr.contains(':')) { return std::make_pair(addr, std::string()); } @@ -238,7 +238,7 @@ namespace ccf inline static NodeInfoNetwork::NetAddress make_net_address( const std::string& host, const std::string& port) { - if (host.find(':') != std::string::npos && !host.starts_with('[')) + if (host.contains(':') && !host.starts_with('[')) { return fmt::format("[{}]:{}", host, port); } diff --git a/include/ccf/service/tables/proposals.h b/include/ccf/service/tables/proposals.h index 50813b7c2bf2..d71850d0b394 100644 --- a/include/ccf/service/tables/proposals.h +++ b/include/ccf/service/tables/proposals.h @@ -6,6 +6,7 @@ #include "ccf/service/map.h" #include +#include #include namespace ccf @@ -82,8 +83,8 @@ struct formatter } default: { - throw std::logic_error(fmt::format( - "Unknown proposal state {}", static_cast(state))); + throw std::logic_error( + fmt::format("Unknown proposal state {}", std::to_underlying(state))); } } } diff --git a/include/ccf/tx_status.h b/include/ccf/tx_status.h index 9802f43cafaf..0aabbbfcd1a2 100644 --- a/include/ccf/tx_status.h +++ b/include/ccf/tx_status.h @@ -5,6 +5,8 @@ #include "ccf/ds/json.h" #include "ccf/tx_id.h" +#include + namespace ccf { /** Describes the status of a transaction, as seen by this node. @@ -34,9 +36,8 @@ namespace ccf // Contains only the terminal values of TxStatus enum class FinalTxStatus : std::underlying_type_t { - Committed = - static_cast>(TxStatus::Committed), - Invalid = static_cast>(TxStatus::Invalid), + Committed = std::to_underlying(TxStatus::Committed), + Invalid = std::to_underlying(TxStatus::Invalid), }; constexpr char const* tx_status_to_str(TxStatus status) diff --git a/python/pyproject.toml b/python/pyproject.toml index 18462482f034..7529d0383b9b 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "ccf" -version = "7.0.13" +version = "7.0.14" authors = [ { name="CCF Team", email="CCF-Sec@microsoft.com" }, ] diff --git a/src/common/cli_helper.h b/src/common/cli_helper.h index dbaa3ff55e01..8b0578080ba3 100644 --- a/src/common/cli_helper.h +++ b/src/common/cli_helper.h @@ -68,9 +68,7 @@ namespace cli // Unbracketed IPv6 literals are ambiguous with the host:port separator. // Require bracketed "[host]:port" form for any address containing more // than one ':' (e.g. "::1"). - if ( - addr.find(':') != std::string::npos && - addr.find(':') != addr.find_last_of(':')) + if (addr.contains(':') && addr.find(':') != addr.find_last_of(':')) { throw std::logic_error(fmt::format( "IPv6 address '{}' must be bracketed as '[host]:port'", addr)); diff --git a/src/consensus/aft/test/committable_suffix.cpp b/src/consensus/aft/test/committable_suffix.cpp index 3571bedea2e5..206492e94b85 100644 --- a/src/consensus/aft/test/committable_suffix.cpp +++ b/src/consensus/aft/test/committable_suffix.cpp @@ -4,6 +4,7 @@ #include "test_common.h" #define DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES +#include #include void keep_messages_for_multiple( @@ -16,7 +17,7 @@ void keep_messages_for_multiple( while (it != messages.end()) { if ( - std::find(targets.begin(), targets.end(), it->first) == targets.end() || + !std::ranges::contains(targets, it->first) || (max_to_keep.has_value() && kept[it->first] >= *max_to_keep)) { it = messages.erase(it); diff --git a/src/cose/test/cose_ffi_test.cpp b/src/cose/test/cose_ffi_test.cpp index 60164c7ef06c..167ef1709862 100644 --- a/src/cose/test/cose_ffi_test.cpp +++ b/src/cose/test/cose_ffi_test.cpp @@ -147,9 +147,7 @@ TEST_CASE("cose_sign_ledger fails with invalid key") CoseKey::from_private(bad_key.data(), bad_key.size(), key_err); CHECK(!cose_key.is_set()); CHECK(key_err.is_set()); - CHECK( - key_err.to_string().find("d2i_AutoPrivateKey failed:") != - std::string::npos); + CHECK(key_err.to_string().contains("d2i_AutoPrivateKey failed:")); } TEST_CASE("CoseKey error propagation") @@ -169,8 +167,7 @@ TEST_CASE("CoseKey error propagation") auto k = CoseKey::from_private(truncated.data(), truncated.size(), err); CHECK(!k.is_set()); CHECK(err.is_set()); - CHECK( - err.to_string().find("d2i_AutoPrivateKey failed:") != std::string::npos); + CHECK(err.to_string().contains("d2i_AutoPrivateKey failed:")); } SUBCASE("valid key succeeds without error") diff --git a/src/crypto/pem.cpp b/src/crypto/pem.cpp index 16680715cef8..1b8980033f9f 100644 --- a/src/crypto/pem.cpp +++ b/src/crypto/pem.cpp @@ -6,7 +6,7 @@ namespace ccf::crypto { void Pem::check_pem_format() { - if (s.find("-----BEGIN") == std::string::npos) + if (!s.contains("-----BEGIN")) { throw std::runtime_error( fmt::format("PEM constructed with non-PEM data: {}", s)); diff --git a/src/crypto/test/crypto.cpp b/src/crypto/test/crypto.cpp index 94dcb2bb8678..e29043e66dbe 100644 --- a/src/crypto/test/crypto.cpp +++ b/src/crypto/test/crypto.cpp @@ -628,8 +628,8 @@ void run_csr(bool corrupt_csr = false) std::string valid_from_, valid_to_; std::tie(valid_from_, valid_to_) = v.validity_period(); - REQUIRE(valid_from_.find(valid_from) != std::string::npos); - REQUIRE(valid_to_.find(valid_to) != std::string::npos); + REQUIRE(valid_from_.contains(valid_from)); + REQUIRE(valid_to_.contains(valid_to)); } TEST_CASE("2-digit years") diff --git a/src/ds/test/json_schema.cpp b/src/ds/test/json_schema.cpp index b4da55354051..77147725eb9f 100644 --- a/src/ds/test/json_schema.cpp +++ b/src/ds/test/json_schema.cpp @@ -3,6 +3,7 @@ #include "ccf/ds/json.h" #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include #include #include #include @@ -598,14 +599,14 @@ TEST_CASE("JSON with different field names") for (const auto s : required_json_fields) { REQUIRE(properties.find(s) != properties.end()); - REQUIRE(std::find(required.begin(), required.end(), s) != required.end()); + REQUIRE(std::ranges::contains(required, s)); } std::vector optional_json_fields{"A", "OTHER_NAME", "c"}; for (const auto s : optional_json_fields) { REQUIRE(properties.find(s) != properties.end()); - REQUIRE(std::find(required.begin(), required.end(), s) == required.end()); + REQUIRE(!std::ranges::contains(required, s)); } renamed::Foo foo; diff --git a/src/ds/test/logger.cpp b/src/ds/test/logger.cpp index ef33892cdde9..43e0ddc7667d 100644 --- a/src/ds/test/logger.cpp +++ b/src/ds/test/logger.cpp @@ -59,9 +59,9 @@ TEST_CASE("Framework logging macros") REQUIRE(logs.size() == 1); const auto& log = logs[0]; - REQUIRE(log.find("info") != std::string::npos); - REQUIRE(log.find("logger.cpp") != std::string::npos); - REQUIRE(log.find("Hello A") != std::string::npos); + REQUIRE(log.contains("info")); + REQUIRE(log.contains("logger.cpp")); + REQUIRE(log.contains("Hello A")); logs.clear(); } @@ -72,9 +72,9 @@ TEST_CASE("Framework logging macros") REQUIRE(logs.size() == 1); const auto& log = logs[0]; - REQUIRE(log.find("fail") != std::string::npos); - REQUIRE(log.find("logger.cpp") != std::string::npos); - REQUIRE(log.find("Hello B") != std::string::npos); + REQUIRE(log.contains("fail")); + REQUIRE(log.contains("logger.cpp")); + REQUIRE(log.contains("Hello B")); logs.clear(); } @@ -85,9 +85,9 @@ TEST_CASE("Framework logging macros") REQUIRE(logs.size() == 1); const auto& log = logs[0]; - REQUIRE(log.find("fatal") != std::string::npos); - REQUIRE(log.find("logger.cpp") != std::string::npos); - REQUIRE(log.find("Hello C") != std::string::npos); + REQUIRE(log.contains("fatal")); + REQUIRE(log.contains("logger.cpp")); + REQUIRE(log.contains("Hello C")); logs.clear(); } @@ -108,10 +108,10 @@ TEST_CASE("Application logging macros") REQUIRE(logs.size() == 1); const auto& log = logs[0]; - REQUIRE(log.find("info") != std::string::npos); - REQUIRE(log.find("[app]") != std::string::npos); - REQUIRE(log.find("logger.cpp") != std::string::npos); - REQUIRE(log.find("Hello A") != std::string::npos); + REQUIRE(log.contains("info")); + REQUIRE(log.contains("[app]")); + REQUIRE(log.contains("logger.cpp")); + REQUIRE(log.contains("Hello A")); logs.clear(); } @@ -122,10 +122,10 @@ TEST_CASE("Application logging macros") REQUIRE(logs.size() == 1); const auto& log = logs[0]; - REQUIRE(log.find("fail") != std::string::npos); - REQUIRE(log.find("[app]") != std::string::npos); - REQUIRE(log.find("logger.cpp") != std::string::npos); - REQUIRE(log.find("Hello B") != std::string::npos); + REQUIRE(log.contains("fail")); + REQUIRE(log.contains("[app]")); + REQUIRE(log.contains("logger.cpp")); + REQUIRE(log.contains("Hello B")); logs.clear(); } @@ -136,10 +136,10 @@ TEST_CASE("Application logging macros") REQUIRE(logs.size() == 1); const auto& log = logs[0]; - REQUIRE(log.find("fatal") != std::string::npos); - REQUIRE(log.find("[app]") != std::string::npos); - REQUIRE(log.find("logger.cpp") != std::string::npos); - REQUIRE(log.find("Hello C") != std::string::npos); + REQUIRE(log.contains("fatal")); + REQUIRE(log.contains("[app]")); + REQUIRE(log.contains("logger.cpp")); + REQUIRE(log.contains("Hello C")); logs.clear(); } @@ -167,10 +167,10 @@ TEST_CASE("Custom logging macros") REQUIRE(logs.size() == 1); const auto& log = logs[0]; - REQUIRE(log.find("info") != std::string::npos); - REQUIRE(log.find(custom_tag) != std::string::npos); - REQUIRE(log.find("logger.cpp") != std::string::npos); - REQUIRE(log.find("Some message") != std::string::npos); + REQUIRE(log.contains("info")); + REQUIRE(log.contains(custom_tag)); + REQUIRE(log.contains("logger.cpp")); + REQUIRE(log.contains("Some message")); logs.clear(); } @@ -181,21 +181,20 @@ TEST_CASE("Custom logging macros") REQUIRE(logs.size() == 1); const auto& log = logs[0]; - REQUIRE(log.find("info") != std::string::npos); + REQUIRE(log.contains("info")); // Search for smaller prefixes of the long tag, expect that one is // eventually present std::string truncated_tag = custom_long_tag; while (truncated_tag.size() > 0) { - const auto search = log.find(truncated_tag); - if (search != std::string::npos) + if (log.contains(truncated_tag)) { break; } truncated_tag.resize(truncated_tag.size() - 1); } REQUIRE(truncated_tag.size() > 0); - REQUIRE(log.find("Some other message") != std::string::npos); + REQUIRE(log.contains("Some other message")); logs.clear(); } diff --git a/src/ds/test/messaging.cpp b/src/ds/test/messaging.cpp index 102fa0254224..df3ce15f315d 100644 --- a/src/ds/test/messaging.cpp +++ b/src/ds/test/messaging.cpp @@ -35,12 +35,12 @@ void require_throws_with( for (const auto& s : includes) { - REQUIRE(what.find(s) != std::string::npos); + REQUIRE(what.contains(s)); } for (const auto& s : excludes) { - REQUIRE(what.find(s) == std::string::npos); + REQUIRE(!what.contains(s)); } } REQUIRE(threw); diff --git a/src/host/test/ledger.cpp b/src/host/test/ledger.cpp index 608d37b6677f..53a6aa0b338b 100644 --- a/src/host/test/ledger.cpp +++ b/src/host/test/ledger.cpp @@ -113,7 +113,7 @@ size_t number_of_committed_files_in_ledger_dir(bool allow_recovery = false) auto file_name = f.path().string(); if ( (allow_recovery && is_ledger_file_name_recovery(file_name) && - file_name.find(ledger_committed_suffix) != std::string::npos) || + file_name.contains(ledger_committed_suffix)) || is_ledger_file_name_committed(file_name)) { committed_file_count++; diff --git a/src/http/http2_parser.h b/src/http/http2_parser.h index 8c10d68c582a..11eb03bfa84f 100644 --- a/src/http/http2_parser.h +++ b/src/http/http2_parser.h @@ -10,6 +10,8 @@ #include "http_proc.h" #include "http_rpc_context.h" +#include + namespace http2 { using DataHandlerCB = std::function)>; @@ -273,8 +275,7 @@ namespace http2 { std::vector hdrs = {}; - auto status_str = fmt::format( - "{}", static_cast>(status)); + auto status_str = fmt::format("{}", std::to_underlying(status)); hdrs.emplace_back( make_nv(ccf::http2::headers::STATUS, status_str.data())); diff --git a/src/http/test/http_test.cpp b/src/http/test/http_test.cpp index 6fe95680f500..eb8feec6a3d7 100644 --- a/src/http/test/http_test.cpp +++ b/src/http/test/http_test.cpp @@ -10,6 +10,7 @@ #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #define DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES +#include #include #include #include @@ -466,9 +467,9 @@ DOCTEST_TEST_CASE("URL parsing") std::string path_, query_, fragment_; std::tie(path_, query_, fragment_) = http::split_url_path(m.url); DOCTEST_CHECK(path_ == path); - DOCTEST_CHECK(query_.find("balance=42") != std::string::npos); - DOCTEST_CHECK(query_.find("id=100") != std::string::npos); - DOCTEST_CHECK(query_.find("&") != std::string::npos); + DOCTEST_CHECK(query_.contains("balance=42")); + DOCTEST_CHECK(query_.contains("id=100")); + DOCTEST_CHECK(query_.contains("&")); } DOCTEST_TEST_CASE("Pessimal transport") @@ -837,8 +838,7 @@ DOCTEST_TEST_CASE("Query parser") for (auto it = parsed.begin(); it != parsed.end(); ++it) { const auto k = it->first; - const auto found = std::find(checked_keys.begin(), checked_keys.end(), k); - DOCTEST_REQUIRE(found != checked_keys.end()); + DOCTEST_REQUIRE(std::ranges::contains(checked_keys, k)); } } diff --git a/src/js/extensions/ccf/kv_helpers.h b/src/js/extensions/ccf/kv_helpers.h index 0423134d3427..ade67e1c4192 100644 --- a/src/js/extensions/ccf/kv_helpers.h +++ b/src/js/extensions/ccf/kv_helpers.h @@ -362,7 +362,6 @@ namespace ccf::js::extensions::kvhelpers HANDLE_GETTER) \ do \ { \ - /* This could use std::to_underlying from C++23 */ \ const auto permitted = \ ccf::js::intersect_access_permissions( \ access_permission, PERMISSION_FLAGS) != KVAccessPermissions::ILLEGAL; \ diff --git a/src/js/test/js.cpp b/src/js/test/js.cpp index e56fa96c618b..9366a3bb3f4d 100644 --- a/src/js/test/js.cpp +++ b/src/js/test/js.cpp @@ -176,7 +176,7 @@ TEST_CASE("Check KV Map access") bool str_contains(const std::string& s, std::string_view sv) { - const auto b = s.find(sv) != std::string::npos; + const auto b = s.contains(sv); if (!b) { fmt::print("Didn't find\n {}\nin\n {}\n", sv, s); diff --git a/src/kv/raw_serialise.h b/src/kv/raw_serialise.h index 8b1f061750ae..d0d3f5240284 100644 --- a/src/kv/raw_serialise.h +++ b/src/kv/raw_serialise.h @@ -8,7 +8,10 @@ #include #include #include +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" #include +#pragma clang diagnostic pop #include #include #include diff --git a/src/kv/test/kv_test.cpp b/src/kv/test/kv_test.cpp index a356b968e6d1..0bec4c7f4666 100644 --- a/src/kv/test/kv_test.cpp +++ b/src/kv/test/kv_test.cpp @@ -1536,7 +1536,7 @@ TEST_CASE("foreach_key") auto tx = kv_store.create_tx(); auto handle = tx.rw(map); REQUIRE_NOTHROW(handle->foreach_key([](const std::string& k) { - REQUIRE(k.find('k') != std::string::npos); + REQUIRE(k.contains('k')); return true; })); @@ -1573,7 +1573,7 @@ TEST_CASE("foreach_value") auto tx = kv_store.create_tx(); auto handle = tx.rw(map); REQUIRE_NOTHROW(handle->foreach_value([](const std::string& v) { - REQUIRE(v.find('v') != std::string::npos); + REQUIRE(v.contains('v')); return true; })); diff --git a/src/kv/untyped_map.h b/src/kv/untyped_map.h index cc04eb637a8c..0ed674ea2119 100644 --- a/src/kv/untyped_map.h +++ b/src/kv/untyped_map.h @@ -631,13 +631,6 @@ namespace ccf::kv::untyped return ok; } -#ifndef __cpp_impl_three_way_comparison - bool operator!=(const Map& that) const - { - return !(*this == that); - } -#endif - std::unique_ptr snapshot(Version v) override { // This takes a snapshot of the state of the map at the last entry diff --git a/src/node/node_inbound_message.h b/src/node/node_inbound_message.h index 273501d9c105..83e390516070 100644 --- a/src/node/node_inbound_message.h +++ b/src/node/node_inbound_message.h @@ -9,6 +9,7 @@ #include "node/node_types.h" #include +#include namespace ccf { @@ -80,7 +81,7 @@ namespace ccf default: { throw std::logic_error(fmt::format( - "Unknown node message type: {}", static_cast(msg_type))); + "Unknown node message type: {}", std::to_underlying(msg_type))); } } } diff --git a/src/node/node_state.h b/src/node/node_state.h index eb4f64e7a911..8e27555ceb4c 100644 --- a/src/node/node_state.h +++ b/src/node/node_state.h @@ -2886,7 +2886,7 @@ namespace ccf private: bool is_ip(const std::string_view& hostname) { - if (hostname.find(':') != std::string_view::npos) + if (hostname.contains(':')) { in6_addr addr{}; if (inet_pton(AF_INET6, std::string(hostname).c_str(), &addr) == 1) diff --git a/src/node/rpc/file_serving_handlers.h b/src/node/rpc/file_serving_handlers.h index cc74de27eca1..29170a2c6b17 100644 --- a/src/node/rpc/file_serving_handlers.h +++ b/src/node/rpc/file_serving_handlers.h @@ -222,7 +222,7 @@ namespace ccf::node return; } - if (ranges.find(',') != std::string::npos) + if (ranges.contains(',')) { ctx.rpc_ctx->set_error( HTTP_STATUS_BAD_REQUEST, diff --git a/src/node/rpc/node_frontend_utils.h b/src/node/rpc/node_frontend_utils.h index 58b632de1146..f5adaf9b91fb 100644 --- a/src/node/rpc/node_frontend_utils.h +++ b/src/node/rpc/node_frontend_utils.h @@ -6,6 +6,7 @@ #include "ccf/node/quote.h" #include +#include namespace ccf { @@ -46,8 +47,7 @@ namespace ccf HTTP_STATUS_UNAUTHORIZED, "Quote TCB version is too low"); default: throw std::logic_error(fmt::format( - "Unknown QuoteVerificationResult: {}", - static_cast(result))); + "Unknown QuoteVerificationResult: {}", std::to_underlying(result))); } } } \ No newline at end of file diff --git a/src/node/rpc/test/frontend_test.cpp b/src/node/rpc/test/frontend_test.cpp index e1fe0365593e..f4035d791fdc 100644 --- a/src/node/rpc/test/frontend_test.cpp +++ b/src/node/rpc/test/frontend_test.cpp @@ -740,9 +740,7 @@ TEST_CASE("process with caller") auto response = parse_response(serialized_response); REQUIRE(response.status == HTTP_STATUS_UNAUTHORIZED); const std::string error_msg(response.body.begin(), response.body.end()); - CHECK( - error_msg.find("Could not find matching user certificate") != - std::string::npos); + CHECK(error_msg.contains("Could not find matching user certificate")); } INFO("Anonymous caller"); @@ -752,7 +750,7 @@ TEST_CASE("process with caller") auto response = parse_response(serialized_response); REQUIRE(response.status == HTTP_STATUS_UNAUTHORIZED); const std::string error_msg(response.body.begin(), response.body.end()); - CHECK(error_msg.find("No caller user certificate") != std::string::npos); + CHECK(error_msg.contains("No caller user certificate")); } } } @@ -952,7 +950,7 @@ TEST_CASE("Restricted verbs") const auto it = response.headers.find(ccf::http::headers::ALLOW); REQUIRE(it != response.headers.end()); const auto v = it->second; - CHECK(v.find(llhttp_method_name(HTTP_GET)) != std::string::npos); + CHECK(v.contains(llhttp_method_name(HTTP_GET))); } } @@ -973,7 +971,7 @@ TEST_CASE("Restricted verbs") const auto it = response.headers.find(ccf::http::headers::ALLOW); REQUIRE(it != response.headers.end()); const auto v = it->second; - CHECK(v.find(llhttp_method_name(HTTP_POST)) != std::string::npos); + CHECK(v.contains(llhttp_method_name(HTTP_POST))); } } @@ -995,11 +993,11 @@ TEST_CASE("Restricted verbs") const auto it = response.headers.find(ccf::http::headers::ALLOW); REQUIRE(it != response.headers.end()); const auto v = it->second; - CHECK(v.find(llhttp_method_name(HTTP_PUT)) != std::string::npos); - CHECK(v.find(llhttp_method_name(HTTP_DELETE)) != std::string::npos); + CHECK(v.contains(llhttp_method_name(HTTP_PUT))); + CHECK(v.contains(llhttp_method_name(HTTP_DELETE))); if (verb != HTTP_OPTIONS) { - CHECK(v.find(llhttp_method_name(verb)) == std::string::npos); + CHECK(!v.contains(llhttp_method_name(verb))); } } } diff --git a/src/node/rpc/test/frontend_test_infra.h b/src/node/rpc/test/frontend_test_infra.h index ebc3bf68c2e0..f30c7c8b8725 100644 --- a/src/node/rpc/test/frontend_test_infra.h +++ b/src/node/rpc/test/frontend_test_infra.h @@ -73,7 +73,7 @@ void check_error(const TResponse& r, ccf::http_status expected) void check_error_message(const TResponse& r, const std::string& msg) { const std::string body_s(r.body.begin(), r.body.end()); - CHECK(body_s.find(msg) != std::string::npos); + CHECK(body_s.contains(msg)); } std::vector create_request( diff --git a/src/node/test/historical_queries.cpp b/src/node/test/historical_queries.cpp index 47a8561da949..e1464dd309d8 100644 --- a/src/node/test/historical_queries.cpp +++ b/src/node/test/historical_queries.cpp @@ -851,10 +851,7 @@ TEST_CASE("StateCache range queries") // Don't validate anything about signature transactions, just the // business transactions between them - if ( - std::find( - signature_versions.begin(), signature_versions.end(), seqno) == - signature_versions.end()) + if (!std::ranges::contains(signature_versions, seqno)) { validate_business_transaction(store, seqno); } @@ -1193,10 +1190,7 @@ TEST_CASE("StateCache sparse queries") // Don't validate anything about signature transactions, just the // business transactions between them - if ( - std::find( - signature_versions.begin(), signature_versions.end(), seqno) == - signature_versions.end()) + if (!std::ranges::contains(signature_versions, seqno)) { validate_business_transaction(store, seqno); } @@ -1382,10 +1376,7 @@ TEST_CASE("StateCache concurrent access") { REQUIRE(store != nullptr); const auto seqno = store->current_txid().seqno; - if ( - std::find( - signature_versions.begin(), signature_versions.end(), seqno) == - signature_versions.end()) + if (!std::ranges::contains(signature_versions, seqno)) { validate_business_transaction(store, seqno); } @@ -1398,10 +1389,7 @@ TEST_CASE("StateCache concurrent access") { REQUIRE(state != nullptr); const auto seqno = state->store->current_txid().seqno; - if ( - std::find( - signature_versions.begin(), signature_versions.end(), seqno) == - signature_versions.end()) + if (!std::ranges::contains(signature_versions, seqno)) { validate_business_transaction(state, seqno); } diff --git a/src/node/test/js_policy.cpp b/src/node/test/js_policy.cpp index 05f087357341..09e3ca192aea 100644 --- a/src/node/test/js_policy.cpp +++ b/src/node/test/js_policy.cpp @@ -77,8 +77,7 @@ TEST_CASE("Policy error handling") )"; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Unexpected return value") != std::string::npos); + REQUIRE(result.value().contains("Unexpected return value")); } SUBCASE("Returns undefined gives unexpected return value") @@ -90,8 +89,7 @@ TEST_CASE("Policy error handling") )"; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Unexpected return value") != std::string::npos); + REQUIRE(result.value().contains("Unexpected return value")); } SUBCASE("Returns null gives unexpected return value") @@ -103,8 +101,7 @@ TEST_CASE("Policy error handling") )"; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Unexpected return value") != std::string::npos); + REQUIRE(result.value().contains("Unexpected return value")); } SUBCASE("Returns number gives unexpected return value") @@ -116,8 +113,7 @@ TEST_CASE("Policy error handling") )"; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Unexpected return value") != std::string::npos); + REQUIRE(result.value().contains("Unexpected return value")); } SUBCASE("Throws is reported as error") @@ -129,9 +125,8 @@ TEST_CASE("Policy error handling") )"; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Code update policy threw") != std::string::npos); - REQUIRE(result.value().find("intentional failure") != std::string::npos); + REQUIRE(result.value().contains("Code update policy threw")); + REQUIRE(result.value().contains("intentional failure")); } SUBCASE("Syntax error") @@ -143,9 +138,7 @@ TEST_CASE("Policy error handling") )"; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Invalid code update policy module") != - std::string::npos); + REQUIRE(result.value().contains("Invalid code update policy module")); } SUBCASE("Missing apply export") @@ -157,9 +150,7 @@ TEST_CASE("Policy error handling") )"; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Invalid code update policy module") != - std::string::npos); + REQUIRE(result.value().contains("Invalid code update policy module")); } SUBCASE("Empty policy string") @@ -167,9 +158,7 @@ TEST_CASE("Policy error handling") const std::string policy; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Invalid code update policy module") != - std::string::npos); + REQUIRE(result.value().contains("Invalid code update policy module")); } SUBCASE("Runtime error in JS") @@ -181,8 +170,7 @@ TEST_CASE("Policy error handling") )"; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Code update policy threw") != std::string::npos); + REQUIRE(result.value().contains("Code update policy threw")); } SUBCASE("Infinite loop is handled") @@ -195,8 +183,7 @@ TEST_CASE("Policy error handling") )"; auto result = apply_node_join_policy(policy, inputs); REQUIRE(result.has_value()); - REQUIRE( - result.value().find("Code update policy threw") != std::string::npos); + REQUIRE(result.value().contains("Code update policy threw")); } SUBCASE("Empty inputs") diff --git a/src/tasks/fan_in_tasks.h b/src/tasks/fan_in_tasks.h index 6b12cd8a427c..cc1a816002a5 100644 --- a/src/tasks/fan_in_tasks.h +++ b/src/tasks/fan_in_tasks.h @@ -14,7 +14,7 @@ namespace ccf::tasks { protected: struct PImpl; - std::unique_ptr pimpl = nullptr; + std::unique_ptr pimpl; void enqueue_on_board(); void do_task_implementation() override; diff --git a/src/tasks/job_board.h b/src/tasks/job_board.h index 13705b9b7231..b57d332595f6 100644 --- a/src/tasks/job_board.h +++ b/src/tasks/job_board.h @@ -13,7 +13,7 @@ namespace ccf::tasks class JobBoard { struct PImpl; - std::unique_ptr pimpl = nullptr; + std::unique_ptr pimpl; void add_timed_task( Task task, diff --git a/src/tasks/ordered_tasks.h b/src/tasks/ordered_tasks.h index c22a6f0b9208..fd0e0c5ac130 100644 --- a/src/tasks/ordered_tasks.h +++ b/src/tasks/ordered_tasks.h @@ -57,7 +57,7 @@ namespace ccf::tasks { protected: struct PImpl; - std::unique_ptr pimpl = nullptr; + std::unique_ptr pimpl; struct ResumeOrderedTasks; diff --git a/src/tasks/test/basic_tasks.cpp b/src/tasks/test/basic_tasks.cpp index 8a8ea35667d6..c19a20090e94 100644 --- a/src/tasks/test/basic_tasks.cpp +++ b/src/tasks/test/basic_tasks.cpp @@ -326,7 +326,7 @@ TEST_CASE("Exception handling" * doctest::test_suite("basic_tasks")) ccf::pal::MutexGuard lock(mutex); for (const auto& m : messages) { - if (m.find(substring) != std::string::npos) + if (m.contains(substring)) { return true; } diff --git a/src/tasks/worker.cpp b/src/tasks/worker.cpp index cbf11a6f36d0..3a9c25af10ea 100644 --- a/src/tasks/worker.cpp +++ b/src/tasks/worker.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace ccf::tasks { @@ -285,6 +286,6 @@ extern "C" // Both real_cxa_throw and std::abort() are [[noreturn]], but the compiler // may not recognize that for function pointers. This satisfies the compiler // that we never return from this function. - __builtin_unreachable(); + std::unreachable(); } } diff --git a/tests/test_install_build.sh b/tests/test_install_build.sh index 546c0f31803e..e94ac8f3a2f6 100755 --- a/tests/test_install_build.sh +++ b/tests/test_install_build.sh @@ -10,8 +10,8 @@ CC=$(which clang || true) CXX=$(which clang++ || true) if [ "$CC" = "" ] || [ "$CXX" = "" ]; then - CC=$(command -v clang-15 || true) - CXX=$(command -v clang++-15 || true) + CC=$(command -v clang-18 || true) + CXX=$(command -v clang++-18 || true) fi CC=$CC CXX=$CXX cmake -GNinja "$@" ../samples/apps/logging/