diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index 823a1812de6..bb3f1a976b2 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -189,6 +189,19 @@ template static inline bool convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true) { static_assert(std::numeric_limits::is_integer); + static_assert(std::is_integral_v); + constexpr bool TypeIsLarger = std::numeric_limits::digits > std::numeric_limits::digits; + + if constexpr (TypeIsLarger) { + using S = std::make_signed_t; + constexpr S max_mantissa = S(1) << std::numeric_limits::digits; + // T has more bits than double's mantissa, so don't allow "upgrading" + // to T (makes it look like the number had more precision than really + // was transmitted) + if (!allow_precision_upgrade && (v > double(max_mantissa) || v < double(-max_mantissa - 1))) + return false; + } + // The [conv.fpint] (7.10 Floating-integral conversions) section of the C++ // standard says only exact conversions are guaranteed. Converting @@ -211,10 +224,6 @@ static inline bool convertDoubleTo(double v, T *value, bool allow_precision_upgr supremum = -2.0 * std::numeric_limits::min(); // -2 * (-2^63) = 2^64, exact (for T = quint64) v = fabs(v); } - if (std::is_integral::value && sizeof(T) > 4 && !allow_precision_upgrade) { - if (v > double(Q_INT64_C(1)<<53) || v < double(-((Q_INT64_C(1)<<53) + 1))) - return false; - } *value = std::numeric_limits::max(); if (v >= supremum)