Compare commits

..
Author SHA1 Message Date
Niels Lohmann 59ccf04a39 Fix the build of develop: tests from #5997 and #5991
- unit-msgpack-cpp17: assign the result of json::parse in
  CHECK_THROWS_WITH_AS (GCC -Werror=unused-result)
- unit-json_view: failing_allocator::allocate is [[noreturn]]
  (clang -Wmissing-noreturn)
- unit-class_lexer: build the quoted string once
  (clang-tidy performance-inefficient-string-concatenation)
- unit-allocator: sweep_allocator provides pointer, reference and size
  typedefs, which GCC 4.8's std::map takes from the allocator
- unit-allocator: skip the "sax_parse into an existing value" sweep with
  iterator debugging, like the parser callback sweep: MSVC's std::vector
  default constructor is noexcept but allocates its debug proxy through
  the allocator, so a failing allocation in create<array_t>() terminates

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 22:31:50 +01:00
Niels Lohmann baba5db36f Fix the MSVC and GCC builds of develop (C4127, -Weffc++) (#6016)
json_view number(): #6006 folded the check of the digit after a minus
sign into `else if (!negative || ...)`, which MSVC 19.44 reports as
C4127 (conditional expression is constant) and /WX turns into an
error in every MSVC and clang-cl job. The check now sits in the
`if (negative)` block, right after the sign is skipped; the error and
its position are unchanged.

unit-locale-cpp.cpp: the locale_switching_token added in #5997 held a
`const char*`, so GCC's -Weffc++ asked for a copy constructor and copy
assignment. The locale name is now a std::string.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 20:07:00 +01:00
Niels Lohmann 07876e2292 json_view: a value that is not found has no bytes in its exception context (#6015) 2026-11-02 19:11:07 +01:00
7 changed files with 36 additions and 26 deletions

No files matched your search

+6 -5
View File
@@ -1168,19 +1168,20 @@ indent_done:
if (negative) if (negative)
{ {
++p; ++p;
if (NLOHMANN_VIEW_UNLIKELY(cur() < '0' || cur() > '9'))
{
return fail(error_code::number_after_minus);
}
} }
const unsigned char* const int_start = p; const unsigned char* const int_start = p;
if (cur() == '0') if (cur() == '0')
{ {
++p; ++p;
} }
else if (NLOHMANN_VIEW_LIKELY(cur() >= '1' && cur() <= '9'))
{
p = skip_digits(p + 1, e);
}
else else
{ {
return fail(error_code::number_after_minus); // (a digit: the dispatch or the check after the sign saw it)
p = skip_digits(p + 1, e);
} }
const auto int_digits = static_cast<std::size_t>(p - int_start); const auto int_digits = static_cast<std::size_t>(p - int_start);
std::size_t frac_digits = 0; std::size_t frac_digits = 0;
+6 -5
View File
@@ -2473,19 +2473,20 @@ indent_done:
if (negative) if (negative)
{ {
++p; ++p;
if (NLOHMANN_VIEW_UNLIKELY(cur() < '0' || cur() > '9'))
{
return fail(error_code::number_after_minus);
}
} }
const unsigned char* const int_start = p; const unsigned char* const int_start = p;
if (cur() == '0') if (cur() == '0')
{ {
++p; ++p;
} }
else if (NLOHMANN_VIEW_LIKELY(cur() >= '1' && cur() <= '9'))
{
p = skip_digits(p + 1, e);
}
else else
{ {
return fail(error_code::number_after_minus); // (a digit: the dispatch or the check after the sign saw it)
p = skip_digits(p + 1, e);
} }
const auto int_digits = static_cast<std::size_t>(p - int_start); const auto int_digits = static_cast<std::size_t>(p - int_start);
std::size_t frac_digits = 0; std::size_t frac_digits = 0;
+13 -7
View File
@@ -1026,10 +1026,7 @@ TEST_CASE("insert() provides its documented exception guarantees (#5986)")
} }
#endif #endif
// the no-exceptions CI job has no std::bad_alloc to catch; with iterator #if !defined(JSON_NOEXCEPTION)
// debugging (MSVC STL debug builds) containers allocate inside noexcept
// functions, so failing an allocation there terminates the program
#if !defined(JSON_NOEXCEPTION) && !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
namespace namespace
{ {
// the allocation numbered sweep_fail_at (counted from 1) throws; 0 never fails // the allocation numbered sweep_fail_at (counted from 1) throws; 0 never fails
@@ -1041,6 +1038,14 @@ template<class T>
struct sweep_allocator struct sweep_allocator
{ {
using value_type = T; using value_type = T;
// GCC 4.8's std::map takes these from the allocator instead of from
// std::allocator_traits
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
sweep_allocator() = default; sweep_allocator() = default;
template<class U> sweep_allocator(const sweep_allocator<U>& /*unused*/) noexcept {} template<class U> sweep_allocator(const sweep_allocator<U>& /*unused*/) noexcept {}
@@ -1158,8 +1163,9 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)")
// With iterator debugging (MSVC STL debug builds, also used by clang-cl), // With iterator debugging (MSVC STL debug builds, also used by clang-cl),
// containers allocate a debug proxy through the allocator inside their // containers allocate a debug proxy through the allocator inside their
// noexcept move constructors, so failing that allocation terminates the // noexcept default and move constructors, so failing that allocation
// program instead of throwing std::bad_alloc. Nothing to check there. // terminates the program instead of throwing std::bad_alloc. Nothing to
// check there.
#if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0) #if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
SECTION("parser callback") SECTION("parser callback")
{ {
@@ -1181,7 +1187,6 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)")
return sweep_json::parse(text, drop_d); return sweep_json::parse(text, drop_d);
}); });
} }
#endif
SECTION("sax_parse into an existing value") SECTION("sax_parse into an existing value")
{ {
@@ -1195,5 +1200,6 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)")
return value; return value;
}); });
} }
#endif
} }
#endif #endif
+4 -3
View File
@@ -2222,9 +2222,10 @@ TEST_CASE("serialization of short strings")
{ {
CAPTURE(s) CAPTURE(s)
const json j = s; const json j = s;
CHECK(j.dump() == "\"" + s + "\""); const std::string quoted = "\"" + s + "\""; // NOLINT(performance-inefficient-string-concatenation)
CHECK(j.dump(-1, ' ', true) == "\"" + s + "\""); CHECK(j.dump() == quoted);
CHECK(json({{s, s}}).dump() == "{\"" + s + "\":\"" + s + "\"}"); CHECK(j.dump(-1, ' ', true) == quoted);
CHECK(json({{s, s}}).dump() == "{" + quoted + ":" + quoted + "}"); // NOLINT(performance-inefficient-string-concatenation)
} }
// a character that needs an escape // a character that needs an escape
+1 -1
View File
@@ -111,7 +111,7 @@ struct failing_allocator
template<typename U> template<typename U>
explicit failing_allocator(const failing_allocator<U>& /*other*/) noexcept {} explicit failing_allocator(const failing_allocator<U>& /*other*/) noexcept {}
T* allocate(std::size_t /*n*/) // NOLINT(readability-convert-member-functions-to-static) [[noreturn]] T* allocate(std::size_t /*n*/) // NOLINT(readability-convert-member-functions-to-static)
{ {
throw std::bad_alloc(); throw std::bad_alloc();
} }
+4 -4
View File
@@ -505,8 +505,8 @@ struct locale_switching_token
{ {
using value_type = char; using value_type = char;
locale_switching_token(std::string text_, const char* switch_to_) locale_switching_token(std::string text_, std::string switch_to_)
: text(std::move(text_)), switch_to(switch_to_) : text(std::move(text_)), switch_to(std::move(switch_to_))
{} {}
std::size_t size() const std::size_t size() const
@@ -523,13 +523,13 @@ struct locale_switching_token
{ {
if (!switched) if (!switched)
{ {
switched = std::setlocale(LC_NUMERIC, switch_to) != nullptr; switched = std::setlocale(LC_NUMERIC, switch_to.c_str()) != nullptr;
} }
return &text[0]; return &text[0];
} }
std::string text; std::string text;
const char* switch_to; std::string switch_to;
bool switched = false; bool switched = false;
}; };
+2 -1
View File
@@ -122,7 +122,8 @@ TEST_CASE("JSON text with std::byte")
SECTION("invalid text") SECTION("invalid text")
{ {
CHECK_FALSE(json::accept(to_bytes("[1,\n2,"))); CHECK_FALSE(json::accept(to_bytes("[1,\n2,")));
CHECK_THROWS_WITH_AS(json::parse(to_bytes("[1,\n2,")), json _;
CHECK_THROWS_WITH_AS(_ = json::parse(to_bytes("[1,\n2,")),
"[json.exception.parse_error.101] parse error at line 2, column 3: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 2, column 3: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
} }
} }