diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 6de9bc803..7af2ee522 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -80,7 +80,11 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) { case value_t::number_unsigned: { - val = static_cast(*j.template get_ptr()); + // never null: a basic_json whose number_unsigned_t is number_integer_t + // stores no number_unsigned values (#2573) + const auto* ptr = j.template get_ptr(); + JSON_ASSERT(ptr != nullptr); + val = static_cast(*ptr); break; } case value_t::number_integer: @@ -406,7 +410,11 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val) { case value_t::number_unsigned: { - val = static_cast(*j.template get_ptr()); + // never null: a basic_json whose number_unsigned_t is number_integer_t + // stores no number_unsigned values (#2573) + const auto* ptr = j.template get_ptr(); + JSON_ASSERT(ptr != nullptr); + val = static_cast(*ptr); break; } case value_t::number_integer: diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 036aeb7d9..3fff8ac62 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -1042,13 +1042,20 @@ using bool_constant = std::integral_constant; // number_integer (#2573). struct same_as_number_integer_type {}; +// NumberUnsignedType, or same_as_number_integer_type if it is the same type as +// NumberIntegerType; basic_json uses this one, as it cannot name its own member +// types through an incomplete basic_json (MSVC reports a recursive alias, and +// old GCC versions crash) +template +using number_unsigned_overload_type = typename std::conditional < + std::is_same::value, + same_as_number_integer_type, + NumberUnsignedType >::type; + // number_unsigned_t of BasicJsonType, or same_as_number_integer_type if it is // the same type as number_integer_t template -using number_unsigned_overload_t = typename std::conditional < - std::is_same::value, - same_as_number_integer_type, - typename BasicJsonType::number_unsigned_t >::type; +using number_unsigned_overload_t = number_unsigned_overload_type; /////////////////////////////////////////////////////////////////////////////// // is_c_string diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 5d6ed07c8..6bbb06a70 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -590,7 +590,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// constructor for numbers (integer) json_value(number_integer_t v) noexcept : number_integer(v) {} /// constructor for numbers (unsigned); takes a placeholder if number_unsigned_t is number_integer_t - json_value(detail::number_unsigned_overload_t v) noexcept : number_unsigned(v) {} + json_value(detail::number_unsigned_overload_type v) noexcept : number_unsigned(v) {} /// constructor for numbers (floating-point) json_value(number_float_t v) noexcept : number_float(v) {} /// constructor for empty values of a given type @@ -2863,14 +2863,14 @@ public: /// get a pointer to the value (unsigned number); takes a placeholder if /// number_unsigned_t is number_integer_t (the integer overload handles it then) - number_unsigned_t* get_impl_ptr(detail::number_unsigned_overload_t* /*unused*/) noexcept + number_unsigned_t* get_impl_ptr(detail::number_unsigned_overload_type* /*unused*/) noexcept { return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr; } /// get a pointer to the value (unsigned number); takes a placeholder if /// number_unsigned_t is number_integer_t (the integer overload handles it then) - constexpr const number_unsigned_t* get_impl_ptr(const detail::number_unsigned_overload_t* /*unused*/) const noexcept + constexpr const number_unsigned_t* get_impl_ptr(const detail::number_unsigned_overload_type* /*unused*/) const noexcept { return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr; } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 9a572f69a..8191bbd19 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5046,13 +5046,20 @@ using bool_constant = std::integral_constant; // number_integer (#2573). struct same_as_number_integer_type {}; +// NumberUnsignedType, or same_as_number_integer_type if it is the same type as +// NumberIntegerType; basic_json uses this one, as it cannot name its own member +// types through an incomplete basic_json (MSVC reports a recursive alias, and +// old GCC versions crash) +template +using number_unsigned_overload_type = typename std::conditional < + std::is_same::value, + same_as_number_integer_type, + NumberUnsignedType >::type; + // number_unsigned_t of BasicJsonType, or same_as_number_integer_type if it is // the same type as number_integer_t template -using number_unsigned_overload_t = typename std::conditional < - std::is_same::value, - same_as_number_integer_type, - typename BasicJsonType::number_unsigned_t >::type; +using number_unsigned_overload_t = number_unsigned_overload_type; /////////////////////////////////////////////////////////////////////////////// // is_c_string @@ -5806,7 +5813,11 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) { case value_t::number_unsigned: { - val = static_cast(*j.template get_ptr()); + // never null: a basic_json whose number_unsigned_t is number_integer_t + // stores no number_unsigned values (#2573) + const auto* ptr = j.template get_ptr(); + JSON_ASSERT(ptr != nullptr); + val = static_cast(*ptr); break; } case value_t::number_integer: @@ -6132,7 +6143,11 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val) { case value_t::number_unsigned: { - val = static_cast(*j.template get_ptr()); + // never null: a basic_json whose number_unsigned_t is number_integer_t + // stores no number_unsigned values (#2573) + const auto* ptr = j.template get_ptr(); + JSON_ASSERT(ptr != nullptr); + val = static_cast(*ptr); break; } case value_t::number_integer: @@ -28916,7 +28931,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// constructor for numbers (integer) json_value(number_integer_t v) noexcept : number_integer(v) {} /// constructor for numbers (unsigned); takes a placeholder if number_unsigned_t is number_integer_t - json_value(detail::number_unsigned_overload_t v) noexcept : number_unsigned(v) {} + json_value(detail::number_unsigned_overload_type v) noexcept : number_unsigned(v) {} /// constructor for numbers (floating-point) json_value(number_float_t v) noexcept : number_float(v) {} /// constructor for empty values of a given type @@ -31189,14 +31204,14 @@ public: /// get a pointer to the value (unsigned number); takes a placeholder if /// number_unsigned_t is number_integer_t (the integer overload handles it then) - number_unsigned_t* get_impl_ptr(detail::number_unsigned_overload_t* /*unused*/) noexcept + number_unsigned_t* get_impl_ptr(detail::number_unsigned_overload_type* /*unused*/) noexcept { return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr; } /// get a pointer to the value (unsigned number); takes a placeholder if /// number_unsigned_t is number_integer_t (the integer overload handles it then) - constexpr const number_unsigned_t* get_impl_ptr(const detail::number_unsigned_overload_t* /*unused*/) const noexcept + constexpr const number_unsigned_t* get_impl_ptr(const detail::number_unsigned_overload_type* /*unused*/) const noexcept { return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr; } diff --git a/tests/src/unit-same-number-types.cpp b/tests/src/unit-same-number-types.cpp index ba6b45004..ba42710c1 100644 --- a/tests/src/unit-same-number-types.cpp +++ b/tests/src/unit-same-number-types.cpp @@ -157,10 +157,7 @@ TEST_CASE_TEMPLATE("same type for number_integer_t and number_unsigned_t", Json, { const Json source = Json::parse(R"({"a": [1, 2, 3], "b": 4})"); const Json target = Json::parse(R"({"a": [1, 5], "c": 6})"); - // GCC 5 crashes with an internal compiler error when instantiating patch_inplace for this type -#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 6 CHECK(source.patch(Json::diff(source, target)) == target); -#endif CHECK(source.flatten().unflatten() == source); }