Fix the AppVeyor (MSVC 2015-2019) build

- binary_reader: emit_signed/emit_unsigned pass integers that do not fit
  the number types to emit_float as long double, because MSVC's <cmath>
  has no integer overloads of std::isfinite (C2668 'fpclassify'), from #5607
- scalar comparisons: the friend operators take the JSON type for their
  noexcept from their parameter, because MSVC 2015/2017 take basic_json as
  the class template there (C3203) and MSVC 2019 16.0 does not see member
  types or template parameters, from #5751
- unit-conversions2: skip the !is_nothrow_constructible static_assert for
  std::optional on MSVC 2017, which evaluates the conditional noexcept as
  true (C2607), from #5754

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-10-05 12:57:44 +02:00
parent f88e209ea9
commit 98eff63537
4 changed files with 53 additions and 34 deletions
@@ -4004,7 +4004,8 @@ class binary_reader
{
return sax->number_unsigned(static_cast<number_unsigned_t>(number));
}
return emit_float(number);
// std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
}
/*!
@@ -4027,7 +4028,8 @@ class binary_reader
{
return sax->number_unsigned(static_cast<number_unsigned_t>(number));
}
return emit_float(number);
// std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
}
/*!
@@ -4038,7 +4040,8 @@ class binary_reader
and NaN in the input are passed on unchanged. Integers only overflow if
number_float_t cannot represent 2^64, e.g., a half-precision type.
@tparam NumberType a floating-point or integer type
@tparam NumberType a floating-point type (emit_signed and emit_unsigned
convert integers to long double first)
@param[in] number the number
@return whether the SAX parser accepted the value
+19 -14
View File
@@ -5098,7 +5098,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType>
requires std::is_scalar_v<ScalarType>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) <= rhs;
}
@@ -5107,7 +5107,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType>
requires std::is_scalar_v<ScalarType>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) >= rhs;
}
@@ -5128,11 +5128,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
#endif
}
// The friend comparisons with a scalar name the JSON type via decltype of
// their parameter in noexcept, because older MSVC versions do not see the
// class scope there: MSVC 2015 and 2017 take basic_json as the template,
// and MSVC 2019 16.0 rejects member types and template parameters.
/// @brief comparison: equal
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs == basic_json(rhs);
}
@@ -5141,7 +5146,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) == rhs;
}
@@ -5157,7 +5162,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs != basic_json(rhs);
}
@@ -5166,7 +5171,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) != rhs;
}
@@ -5186,7 +5191,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs < basic_json(rhs);
}
@@ -5195,7 +5200,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) < rhs;
}
@@ -5215,7 +5220,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs <= basic_json(rhs);
}
@@ -5224,7 +5229,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) <= rhs;
}
@@ -5245,7 +5250,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs > basic_json(rhs);
}
@@ -5254,7 +5259,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) > rhs;
}
@@ -5274,7 +5279,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs >= basic_json(rhs);
}
@@ -5283,7 +5288,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) >= rhs;
}
+25 -17
View File
@@ -17695,7 +17695,8 @@ class binary_reader
{
return sax->number_unsigned(static_cast<number_unsigned_t>(number));
}
return emit_float(number);
// std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
}
/*!
@@ -17718,7 +17719,8 @@ class binary_reader
{
return sax->number_unsigned(static_cast<number_unsigned_t>(number));
}
return emit_float(number);
// std::isfinite has no integer overloads in MSVC's <cmath>
return emit_float(static_cast<long double>(number));
}
/*!
@@ -17729,7 +17731,8 @@ class binary_reader
and NaN in the input are passed on unchanged. Integers only overflow if
number_float_t cannot represent 2^64, e.g., a half-precision type.
@tparam NumberType a floating-point or integer type
@tparam NumberType a floating-point type (emit_signed and emit_unsigned
convert integers to long double first)
@param[in] number the number
@return whether the SAX parser accepted the value
@@ -32249,7 +32252,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType>
requires std::is_scalar_v<ScalarType>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) <= rhs;
}
@@ -32258,7 +32261,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType>
requires std::is_scalar_v<ScalarType>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) >= rhs;
}
@@ -32279,11 +32282,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
#endif
}
// The friend comparisons with a scalar name the JSON type via decltype of
// their parameter in noexcept: older MSVC versions (2015 to 2019 16.0) do
// not see the class scope there, so basic_json would name the template
// and member types or template parameters would be undeclared.
/// @brief comparison: equal
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator==(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs == basic_json(rhs);
}
@@ -32292,7 +32300,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator==(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) == rhs;
}
@@ -32308,7 +32316,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs != basic_json(rhs);
}
@@ -32317,7 +32325,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) != rhs;
}
@@ -32337,7 +32345,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs < basic_json(rhs);
}
@@ -32346,7 +32354,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) < rhs;
}
@@ -32366,7 +32374,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs <= basic_json(rhs);
}
@@ -32375,7 +32383,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) <= rhs;
}
@@ -32396,7 +32404,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs > basic_json(rhs);
}
@@ -32405,7 +32413,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) > rhs;
}
@@ -32425,7 +32433,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(lhs)>, ScalarType>::value)
{
return lhs >= basic_json(rhs);
}
@@ -32434,7 +32442,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
template<typename ScalarType, typename std::enable_if<
std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<detail::uncvref_t<decltype(rhs)>, ScalarType>::value)
{
return basic_json(lhs) >= rhs;
}
+3
View File
@@ -851,7 +851,10 @@ TEST_CASE("std::optional")
CHECK_THROWS_WITH_AS(json(opt), "cannot serialize throwing_to_json_type", std::runtime_error&);
// the conversion is noexcept exactly when converting the contained value is
// (MSVC 2017 evaluates the conditional noexcept of this conversion as true)
#if !defined(_MSC_VER) || _MSC_VER >= 1920
static_assert(!std::is_nothrow_constructible<json, const std::optional<throwing_to_json_type>&>::value);
#endif
static_assert(std::is_nothrow_constructible<json, const std::optional<int>&>::value);
}
#endif