From 516b9b516aa4fc2d608fff206523bf05aab44cc9 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 9 Oct 2026 23:14:53 +0200 Subject: [PATCH] Fix the Visual Studio 2015 build of the recovery code and its tests - parser::report_error() calls only sax->parse_error(). For a SAX parser whose parse_error() is static, as in unit-disabled_exceptions.cpp, Visual Studio 2015 then reports the parameter as unreferenced (C4100), which /WX turns into an error. - The variadic concatenated() helper in unit-sax_parse.cpp made Visual Studio 2015 fail with an internal compiler error (C1001). It now takes an initializer list of byte vectors. Signed-off-by: Niels Lohmann --- include/nlohmann/detail/input/parser.hpp | 2 ++ single_include/nlohmann/json.hpp | 2 ++ tests/src/unit-sax_parse.cpp | 15 ++++++++------- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 5ca6fa52c..431791611 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -851,6 +851,7 @@ class parser JSON_INTERNAL_ALWAYS_INLINE std::false_type report_error(SAX* sax, const Exception& ex, std::false_type /*allow_recovery*/) { + static_cast(sax); // MSVC 2015 does not count calling a static parse_error() as using it error_reported = true; static_cast(sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), ex)); return {}; @@ -863,6 +864,7 @@ class parser template bool report_error(SAX* sax, const Exception& ex, std::true_type /*allow_recovery*/) { + static_cast(sax); // MSVC 2015 does not count calling a static parse_error() as using it const std::size_t position = m_lexer.get_position().chars_read_total; if (error_reported && position == last_error_position && last_token == last_error_token) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index aa78b5765..19daed6b9 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -20646,6 +20646,7 @@ class parser JSON_INTERNAL_ALWAYS_INLINE std::false_type report_error(SAX* sax, const Exception& ex, std::false_type /*allow_recovery*/) { + static_cast(sax); // MSVC 2015 does not count calling a static parse_error() as using it error_reported = true; static_cast(sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), ex)); return {}; @@ -20658,6 +20659,7 @@ class parser template bool report_error(SAX* sax, const Exception& ex, std::true_type /*allow_recovery*/) { + static_cast(sax); // MSVC 2015 does not count calling a static parse_error() as using it const std::size_t position = m_lexer.get_position().chars_read_total; if (error_reported && position == last_error_position && last_token == last_error_token) { diff --git a/tests/src/unit-sax_parse.cpp b/tests/src/unit-sax_parse.cpp index 51d549e04..207c6e9d1 100644 --- a/tests/src/unit-sax_parse.cpp +++ b/tests/src/unit-sax_parse.cpp @@ -30,6 +30,7 @@ using json = nlohmann::json; #include #include #include +#include #include #include #include @@ -293,11 +294,11 @@ std::vector bytes(const std::size_t count) return std::vector(count, 0xAB); } -template -std::vector concatenated(const std::vector& first, const Parts& ... rest) +/// the bytes of @a parts, one after the other +std::vector concatenated(std::initializer_list> parts) { - std::vector result = first; - for (const auto& part : std::initializer_list> {rest...}) + std::vector result; + for (const auto& part : parts) { result.insert(result.end(), part.begin(), part.end()); } @@ -437,8 +438,8 @@ TEST_CASE("regression test - #3989 SAX parse_error() returning true") bson_element(0x0B, "regex", {'a', '+', 0, 'i', 0}), // regular expression bson_element(0x0D, "code", bson_string("f()")), // JavaScript code bson_element(0x0E, "symbol", bson_string("s")), // symbol - bson_element(0x0C, "pointer", concatenated(bson_string("c"), bytes(12))), // DBPointer - bson_element(0x0F, "scope", concatenated(bson_int32(15), bson_string("g"), bson_document({}))), // code with scope + bson_element(0x0C, "pointer", concatenated({bson_string("c"), bytes(12)})), // DBPointer + bson_element(0x0F, "scope", concatenated({bson_int32(15), bson_string("g"), bson_document({})})), // code with scope bson_element(0x06, "undefined", {}), // undefined bson_element(0xFF, "min", {}), // min key bson_element(0x7F, "max", {}), // max key @@ -463,7 +464,7 @@ TEST_CASE("regression test - #3989 SAX parse_error() returning true") json::input_format_t::bson, bson_document( { bson_element(0x03, "inner", bson_document({bson_element(0x02, "s", bson_string("abc", -10)), bson_element(0x10, "b", bson_int32(2))})), - bson_element(0x03, "bin", bson_document({bson_element(0x05, "b", concatenated(bson_int32(-1), bytes(1))), bson_element(0x10, "b", bson_int32(2))})), + bson_element(0x03, "bin", bson_document({bson_element(0x05, "b", concatenated({bson_int32(-1), bytes(1)})), bson_element(0x10, "b", bson_int32(2))})), bson_element(0x10, "after", bson_int32(3)), }), {{"inner", {{"s", nullptr}}}, {"bin", {{"b", nullptr}}}, {"after", 3}},