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 <memory> for std::allocator (IWYU)

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-10-04 14:49:51 +02:00
parent fa2465b325
commit fd0261d909
7 changed files with 52 additions and 26 deletions
@@ -110,15 +110,15 @@ class binary_reader
@param[in] adapter input adapter to read from @param[in] adapter input adapter to read from
@param[in] format the binary format to parse @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 are not well-formed UTF-8; none of the supported formats
requires a decoder to reject those, so the default is to requires a decoder to reject those, so the default is to
@ref error_handler_t::keep them unchanged, as every binary @ref error_handler_t::keep them unchanged, as every binary
reader did before this parameter existed reader did before this parameter existed
*/ */
explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json, 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 const error_handler_t error_handler_ = error_handler_t::keep) noexcept
: ia(std::move(adapter)), input_format(format), error_handler(error_handler) : ia(std::move(adapter)), input_format(format), error_handler(error_handler_)
{ {
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {}; (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
} }
+4
View File
@@ -322,6 +322,8 @@ class json_pointer
typename BasicJsonType::size_type idx{}; typename BasicJsonType::size_type idx{};
switch (parse_array_index<BasicJsonType>(s, idx)) switch (parse_array_index<BasicJsonType>(s, idx))
{ {
// the branches differ in their messages, not after JSON_THROW's expansion
// NOLINTNEXTLINE(bugprone-branch-clone)
case array_index_status::leading_zero: 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)); 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: case array_index_status::not_a_number:
@@ -685,6 +687,8 @@ class json_pointer
typename BasicJsonType::size_type idx{}; typename BasicJsonType::size_type idx{};
switch (parse_array_index<BasicJsonType>(reference_token, idx)) switch (parse_array_index<BasicJsonType>(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: 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)); 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: case array_index_status::not_a_number:
@@ -2260,18 +2260,18 @@ class binary_writer
switch (error_handler) switch (error_handler)
{ {
case error_handler_t::keep: 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: case error_handler_t::strict:
check_utf8(s, context); 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::replace:
case error_handler_t::ignore: case error_handler_t::ignore:
default: default:
if (is_valid_utf8(s)) 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); storage = sanitize_utf8(s, error_handler);
return storage; return storage;
@@ -706,6 +706,11 @@ class serializer
@a ensure_ascii is a template parameter here so that the branch on it is @a ensure_ascii is a template parameter here so that the branch on it is
resolved once, outside the loop; see @ref dump_escaped. 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<bool EnsureAscii> template<bool EnsureAscii>
void dump_escaped_impl(const string_t& s) void dump_escaped_impl(const string_t& s)
{ {
@@ -1055,6 +1060,9 @@ class serializer
} }
} }
} }
#ifdef JSON_HEDLEY_MSVC_VERSION
#pragma warning(pop)
#endif
private: private:
/*! /*!
+6 -5
View File
@@ -1048,6 +1048,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
never name it to call this constructor itself. never name it to call this constructor itself.
*/ */
basic_json(copy_construct_tag /*unused*/, const basic_json& src) basic_json(copy_construct_tag /*unused*/, const basic_json& src)
noexcept(std::is_nothrow_copy_constructible<json_base_class_t>::value)
: json_base_class_t(src) : json_base_class_t(src)
#if JSON_DIAGNOSTIC_POSITIONS #if JSON_DIAGNOSTIC_POSITIONS
, start_position(src.start_position) , 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 static compare_result compare_leaves(const_reference lhs, const_reference rhs, std::true_type /*ordered*/) noexcept
{ {
const std::partial_ordering order = lhs <=> rhs; // *NOPAD* const std::partial_ordering order = lhs <=> rhs; // *NOPAD*
if (order == 0) if (std::is_eq(order))
{ {
return compare_result::equal; return compare_result::equal;
} }
if (order < 0) if (std::is_lt(order))
{ {
return compare_result::less; return compare_result::less;
} }
if (order > 0) if (std::is_gt(order))
{ {
return compare_result::greater; 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/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; 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/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }
+2 -2
View File
@@ -12,7 +12,7 @@
#include <functional> // equal_to, less #include <functional> // equal_to, less
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <iterator> // input_iterator_tag, iterator_traits #include <iterator> // input_iterator_tag, iterator_traits
#include <memory> // allocator #include <memory> // allocator // IWYU pragma: keep
#include <new> // for operator new (placement new) #include <new> // for operator new (placement new)
#include <stdexcept> // for out_of_range #include <stdexcept> // for out_of_range
#include <tuple> // forward_as_tuple #include <tuple> // forward_as_tuple
@@ -78,7 +78,7 @@ private:
/// @brief find the entry for @a key, for either constness of @a self /// @brief find the entry for @a key, for either constness of @a self
/// @note the single place that performs the linear key search /// @note the single place that performs the linear key search
template<typename Self, typename KeyType> template<typename Self, typename KeyType>
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) for (auto it = self.begin(); it != self.end(); ++it)
{ {
+26 -13
View File
@@ -13696,15 +13696,15 @@ class binary_reader
@param[in] adapter input adapter to read from @param[in] adapter input adapter to read from
@param[in] format the binary format to parse @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 are not well-formed UTF-8; none of the supported formats
requires a decoder to reject those, so the default is to requires a decoder to reject those, so the default is to
@ref error_handler_t::keep them unchanged, as every binary @ref error_handler_t::keep them unchanged, as every binary
reader did before this parameter existed reader did before this parameter existed
*/ */
explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json, 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 const error_handler_t error_handler_ = error_handler_t::keep) noexcept
: ia(std::move(adapter)), input_format(format), error_handler(error_handler) : ia(std::move(adapter)), input_format(format), error_handler(error_handler_)
{ {
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {}; (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
} }
@@ -19998,6 +19998,8 @@ class json_pointer
typename BasicJsonType::size_type idx{}; typename BasicJsonType::size_type idx{};
switch (parse_array_index<BasicJsonType>(s, idx)) switch (parse_array_index<BasicJsonType>(s, idx))
{ {
// the branches differ in their messages, not after JSON_THROW's expansion
// NOLINTNEXTLINE(bugprone-branch-clone)
case array_index_status::leading_zero: 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)); 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: case array_index_status::not_a_number:
@@ -20361,6 +20363,8 @@ class json_pointer
typename BasicJsonType::size_type idx{}; typename BasicJsonType::size_type idx{};
switch (parse_array_index<BasicJsonType>(reference_token, idx)) switch (parse_array_index<BasicJsonType>(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: 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)); 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: case array_index_status::not_a_number:
@@ -23485,18 +23489,18 @@ class binary_writer
switch (error_handler) switch (error_handler)
{ {
case error_handler_t::keep: 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: case error_handler_t::strict:
check_utf8(s, context); 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::replace:
case error_handler_t::ignore: case error_handler_t::ignore:
default: default:
if (is_valid_utf8(s)) 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); storage = sanitize_utf8(s, error_handler);
return storage; return storage;
@@ -25681,6 +25685,11 @@ class serializer
@a ensure_ascii is a template parameter here so that the branch on it is @a ensure_ascii is a template parameter here so that the branch on it is
resolved once, outside the loop; see @ref dump_escaped. 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<bool EnsureAscii> template<bool EnsureAscii>
void dump_escaped_impl(const string_t& s) void dump_escaped_impl(const string_t& s)
{ {
@@ -26030,6 +26039,9 @@ class serializer
} }
} }
} }
#ifdef JSON_HEDLEY_MSVC_VERSION
#pragma warning(pop)
#endif
private: private:
/*! /*!
@@ -26612,7 +26624,7 @@ NLOHMANN_JSON_NAMESPACE_END
#include <functional> // equal_to, less #include <functional> // equal_to, less
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <iterator> // input_iterator_tag, iterator_traits #include <iterator> // input_iterator_tag, iterator_traits
#include <memory> // allocator #include <memory> // allocator // IWYU pragma: keep
#include <new> // for operator new (placement new) #include <new> // for operator new (placement new)
#include <stdexcept> // for out_of_range #include <stdexcept> // for out_of_range
#include <tuple> // forward_as_tuple #include <tuple> // forward_as_tuple
@@ -26681,7 +26693,7 @@ private:
/// @brief find the entry for @a key, for either constness of @a self /// @brief find the entry for @a key, for either constness of @a self
/// @note the single place that performs the linear key search /// @note the single place that performs the linear key search
template<typename Self, typename KeyType> template<typename Self, typename KeyType>
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) 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. never name it to call this constructor itself.
*/ */
basic_json(copy_construct_tag /*unused*/, const basic_json& src) basic_json(copy_construct_tag /*unused*/, const basic_json& src)
noexcept(std::is_nothrow_copy_constructible<json_base_class_t>::value)
: json_base_class_t(src) : json_base_class_t(src)
#if JSON_DIAGNOSTIC_POSITIONS #if JSON_DIAGNOSTIC_POSITIONS
, start_position(src.start_position) , 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 static compare_result compare_leaves(const_reference lhs, const_reference rhs, std::true_type /*ordered*/) noexcept
{ {
const std::partial_ordering order = lhs <=> rhs; // *NOPAD* const std::partial_ordering order = lhs <=> rhs; // *NOPAD*
if (order == 0) if (std::is_eq(order))
{ {
return compare_result::equal; return compare_result::equal;
} }
if (order < 0) if (std::is_lt(order))
{ {
return compare_result::less; return compare_result::less;
} }
if (order > 0) if (std::is_gt(order))
{ {
return compare_result::greater; 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/ /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) <= rhs; 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/ /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType> template<typename ScalarType>
requires std::is_scalar_v<ScalarType> requires std::is_scalar_v<ScalarType>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
{ {
return basic_json(lhs) >= rhs; return basic_json(lhs) >= rhs;
} }