diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 3b0406fae08..6635fec1a9b 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -16,6 +16,7 @@ #include "qlist.h" #include "qlocale.h" #include "qdebug.h" +#include "private/qnumeric_p.h" #if QT_CONFIG(easingcurve) #include "qeasingcurve.h" #endif @@ -972,6 +973,28 @@ static const struct { const char * typeName; int typeNameLength; int type; } typ {nullptr, 0, QMetaType::UnknownType} }; +template +static bool qIntegerConversionFromFPHelper(From from, To *to) +{ +#ifndef Q_CC_GHS + // actually is_floating_point, but include qfloat16: + static_assert(std::numeric_limits::is_iec559); +#endif + static_assert(std::is_integral_v); + static_assert(sizeof(From) <= sizeof(double)); + const double fromD = static_cast(from); + + if (qt_is_nan(fromD)) { + *to = To(0); + return false; + } + + qint64 result; + convertDoubleTo(std::round(fromD), &result); + *to = To(result); + return true; +} + // NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class static constexpr struct : QMetaTypeModuleHelper { @@ -1074,9 +1097,9 @@ static constexpr struct : QMetaTypeModuleHelper QMETATYPE_CONVERTER_ASSIGN(To, ULong); \ QMETATYPE_CONVERTER_ASSIGN(To, LongLong); \ QMETATYPE_CONVERTER_ASSIGN(To, ULongLong); \ - QMETATYPE_CONVERTER(To, Float16, result = qRound64(source); return true;); \ - QMETATYPE_CONVERTER(To, Float, result = qRound64(source); return true;); \ - QMETATYPE_CONVERTER(To, Double, result = qRound64(source); return true;); \ + QMETATYPE_CONVERTER(To, Float16, return qIntegerConversionFromFPHelper(source, &result);); \ + QMETATYPE_CONVERTER(To, Float, return qIntegerConversionFromFPHelper(source, &result);); \ + QMETATYPE_CONVERTER(To, Double, return qIntegerConversionFromFPHelper(source, &result);); \ QMETATYPE_CONVERTER(To, QChar, result = source.unicode(); return true;); \ QMETATYPE_CONVERTER(To, QString, \ bool ok = false; \ diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 62f6c30b60a..a573b196683 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -914,8 +914,20 @@ template static void addNumberConversions() } } - if constexpr (std::is_integral_v) + if constexpr (std::is_integral_v) { QTest::newRow("QChar") << QVariant(QChar('a')) << To('a') << true; + + QTest::newRow("NaN") << QVariant::fromValue(qQNaN()) << To(0) << false; + + constexpr qint64 maximal = std::numeric_limits::max(); + constexpr qint64 minimal = std::numeric_limits::min(); + + QTest::newRow("positive overflow") << QVariant(1.0e200) << To(maximal) << true; + QTest::newRow("positive inf") << QVariant(qInf()) << To(maximal) << true; + QTest::newRow("negative overflow") << QVariant(-1.0e200) << To(minimal) << true; + QTest::newRow("negative inf") << QVariant(-qInf()) << To(minimal) << true; + } + QTest::newRow("nonint-QByteArray") << QVariant(QByteArray("zzzz")) << To{} << false; QTest::newRow("nonint-QString") << QVariant(QString("zzzz")) << To{} << false; QTest::newRow("undefined-QCborValue") << QVariant::fromValue({}) << To{} << false;