From fd0261d9092f9dd9b0b41fa6a4f89c77a2b04ec4 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 4 Oct 2026 14:49:51 +0200 Subject: [PATCH] Fix the library warnings and noexcept specifications from the merged PRs - binary_reader: rename the error_handler constructor parameter, which shadowed the member (-Wshadow, -Wshadow-field-in-constructor; #5746) - basic_json(copy_construct_tag, ...): declare it noexcept when copying the base class is (GCC 16 -Wnoexcept; #5690) - the scalar-on-left legacy comparison operators: noexcept only when converting the scalar is, like their member counterparts (#5682, #5751) - compare_leaves: use std::is_eq/is_lt/is_gt instead of comparing a std::partial_ordering with 0 (-Wzero-as-null-pointer-constant; #5686) - serializer: silence MSVC C4127 for the EnsureAscii template parameter (#5741, #5746) - clang-tidy: return the sanitized reference in binary_writer, take the key of ordered_map::find_impl by const reference (#5727), and mark the switches over parse_array_index (#5728) - ordered_map: keep for std::allocator (IWYU) Signed-off-by: Niels Lohmann --- .../nlohmann/detail/input/binary_reader.hpp | 6 +-- include/nlohmann/detail/json_pointer.hpp | 4 ++ .../nlohmann/detail/output/binary_writer.hpp | 6 +-- include/nlohmann/detail/output/serializer.hpp | 8 ++++ include/nlohmann/json.hpp | 11 +++--- include/nlohmann/ordered_map.hpp | 4 +- single_include/nlohmann/json.hpp | 39 ++++++++++++------- 7 files changed, 52 insertions(+), 26 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 1a78a6502..d6b45909a 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -110,15 +110,15 @@ class binary_reader @param[in] adapter input adapter to read from @param[in] format the binary format to parse - @param[in] error_handler how to treat text strings and object keys that + @param[in] error_handler_ how to treat text strings and object keys that are not well-formed UTF-8; none of the supported formats requires a decoder to reject those, so the default is to @ref error_handler_t::keep them unchanged, as every binary reader did before this parameter existed */ explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json, - const error_handler_t error_handler = error_handler_t::keep) noexcept - : ia(std::move(adapter)), input_format(format), error_handler(error_handler) + const error_handler_t error_handler_ = error_handler_t::keep) noexcept + : ia(std::move(adapter)), input_format(format), error_handler(error_handler_) { (void)detail::is_sax_static_asserts {}; } diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 788af1047..30edb4a3b 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -322,6 +322,8 @@ class json_pointer typename BasicJsonType::size_type idx{}; switch (parse_array_index(s, idx)) { + // the branches differ in their messages, not after JSON_THROW's expansion + // NOLINTNEXTLINE(bugprone-branch-clone) case array_index_status::leading_zero: JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); case array_index_status::not_a_number: @@ -685,6 +687,8 @@ class json_pointer typename BasicJsonType::size_type idx{}; switch (parse_array_index(reference_token, idx)) { + // the branches differ in their messages, not after JSON_THROW's expansion + // NOLINTNEXTLINE(bugprone-branch-clone) case array_index_status::leading_zero: JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr)); case array_index_status::not_a_number: diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index e74671db2..a4921f217 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -2260,18 +2260,18 @@ class binary_writer switch (error_handler) { case error_handler_t::keep: - return s; + return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call case error_handler_t::strict: check_utf8(s, context); - return s; + return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call case error_handler_t::replace: case error_handler_t::ignore: default: if (is_valid_utf8(s)) { - return s; + return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call } storage = sanitize_utf8(s, error_handler); return storage; diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index dcaae8055..8306440ef 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -706,6 +706,11 @@ class serializer @a ensure_ascii is a template parameter here so that the branch on it is resolved once, outside the loop; see @ref dump_escaped. */ +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning(push) + // EnsureAscii is a template parameter; C++11 has no if constexpr +#pragma warning(disable : 4127) // conditional expression is constant +#endif template void dump_escaped_impl(const string_t& s) { @@ -1055,6 +1060,9 @@ class serializer } } } +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning(pop) +#endif private: /*! diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 52fa86e77..1f083750f 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1048,6 +1048,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec never name it to call this constructor itself. */ basic_json(copy_construct_tag /*unused*/, const basic_json& src) + noexcept(std::is_nothrow_copy_constructible::value) : json_base_class_t(src) #if JSON_DIAGNOSTIC_POSITIONS , start_position(src.start_position) @@ -1641,15 +1642,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static compare_result compare_leaves(const_reference lhs, const_reference rhs, std::true_type /*ordered*/) noexcept { const std::partial_ordering order = lhs <=> rhs; // *NOPAD* - if (order == 0) + if (std::is_eq(order)) { return compare_result::equal; } - if (order < 0) + if (std::is_lt(order)) { return compare_result::less; } - if (order > 0) + if (std::is_gt(order)) { return compare_result::greater; } @@ -5075,7 +5076,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ template requires std::is_scalar_v - friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept + friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) { return basic_json(lhs) <= rhs; } @@ -5084,7 +5085,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ template requires std::is_scalar_v - friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept + friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) { return basic_json(lhs) >= rhs; } diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index eb521114e..2e0970726 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -12,7 +12,7 @@ #include // equal_to, less #include // initializer_list #include // input_iterator_tag, iterator_traits -#include // allocator +#include // allocator // IWYU pragma: keep #include // for operator new (placement new) #include // for out_of_range #include // forward_as_tuple @@ -78,7 +78,7 @@ private: /// @brief find the entry for @a key, for either constness of @a self /// @note the single place that performs the linear key search template - static auto find_impl(Self& self, KeyType&& key) -> decltype(self.begin()) + static auto find_impl(Self& self, const KeyType& key) -> decltype(self.begin()) { for (auto it = self.begin(); it != self.end(); ++it) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index eeacbff8e..1a50c03c2 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -13696,15 +13696,15 @@ class binary_reader @param[in] adapter input adapter to read from @param[in] format the binary format to parse - @param[in] error_handler how to treat text strings and object keys that + @param[in] error_handler_ how to treat text strings and object keys that are not well-formed UTF-8; none of the supported formats requires a decoder to reject those, so the default is to @ref error_handler_t::keep them unchanged, as every binary reader did before this parameter existed */ explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json, - const error_handler_t error_handler = error_handler_t::keep) noexcept - : ia(std::move(adapter)), input_format(format), error_handler(error_handler) + const error_handler_t error_handler_ = error_handler_t::keep) noexcept + : ia(std::move(adapter)), input_format(format), error_handler(error_handler_) { (void)detail::is_sax_static_asserts {}; } @@ -19998,6 +19998,8 @@ class json_pointer typename BasicJsonType::size_type idx{}; switch (parse_array_index(s, idx)) { + // the branches differ in their messages, not after JSON_THROW's expansion + // NOLINTNEXTLINE(bugprone-branch-clone) case array_index_status::leading_zero: JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); case array_index_status::not_a_number: @@ -20361,6 +20363,8 @@ class json_pointer typename BasicJsonType::size_type idx{}; switch (parse_array_index(reference_token, idx)) { + // the branches differ in their messages, not after JSON_THROW's expansion + // NOLINTNEXTLINE(bugprone-branch-clone) case array_index_status::leading_zero: JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr)); case array_index_status::not_a_number: @@ -23485,18 +23489,18 @@ class binary_writer switch (error_handler) { case error_handler_t::keep: - return s; + return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call case error_handler_t::strict: check_utf8(s, context); - return s; + return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call case error_handler_t::replace: case error_handler_t::ignore: default: if (is_valid_utf8(s)) { - return s; + return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call } storage = sanitize_utf8(s, error_handler); return storage; @@ -25681,6 +25685,11 @@ class serializer @a ensure_ascii is a template parameter here so that the branch on it is resolved once, outside the loop; see @ref dump_escaped. */ +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning(push) + // EnsureAscii is a template parameter; C++11 has no if constexpr +#pragma warning(disable : 4127) // conditional expression is constant +#endif template void dump_escaped_impl(const string_t& s) { @@ -26030,6 +26039,9 @@ class serializer } } } +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning(pop) +#endif private: /*! @@ -26612,7 +26624,7 @@ NLOHMANN_JSON_NAMESPACE_END #include // equal_to, less #include // initializer_list #include // input_iterator_tag, iterator_traits -#include // allocator +#include // allocator // IWYU pragma: keep #include // for operator new (placement new) #include // for out_of_range #include // forward_as_tuple @@ -26681,7 +26693,7 @@ private: /// @brief find the entry for @a key, for either constness of @a self /// @note the single place that performs the linear key search template - static auto find_impl(Self& self, KeyType&& key) -> decltype(self.begin()) + static auto find_impl(Self& self, const KeyType& key) -> decltype(self.begin()) { for (auto it = self.begin(); it != self.end(); ++it) { @@ -27985,6 +27997,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec never name it to call this constructor itself. */ basic_json(copy_construct_tag /*unused*/, const basic_json& src) + noexcept(std::is_nothrow_copy_constructible::value) : json_base_class_t(src) #if JSON_DIAGNOSTIC_POSITIONS , start_position(src.start_position) @@ -28578,15 +28591,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static compare_result compare_leaves(const_reference lhs, const_reference rhs, std::true_type /*ordered*/) noexcept { const std::partial_ordering order = lhs <=> rhs; // *NOPAD* - if (order == 0) + if (std::is_eq(order)) { return compare_result::equal; } - if (order < 0) + if (std::is_lt(order)) { return compare_result::less; } - if (order > 0) + if (std::is_gt(order)) { return compare_result::greater; } @@ -32012,7 +32025,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ template requires std::is_scalar_v - friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept + friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) { return basic_json(lhs) <= rhs; } @@ -32021,7 +32034,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ template requires std::is_scalar_v - friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept + friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible::value) { return basic_json(lhs) >= rhs; }