summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@qt.io>2023-09-11 19:44:38 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-09-13 04:51:10 +0000
commiteb5be509dcdbfafe39e191870d4a4541a840e65d (patch)
treef643deac01eede5c73235c138ed8ce6120ef4946
parent047ecf5b2151978b6675767f5f1ce44e3e696ff3 (diff)
Fix qHash(qfloat16) to match Qt 6.4 behavior
There were two problems: - On platforms where QFLOAT16_IS_NATIVE == true, a qHash(qfloat16{}) call has become ambiguous between the three FP qHash() overloads (float, double, long double), where it was unambiguously calling the float one in Qt 6.4. This SiC was caused by the replacement of operator float() by operator __fp16() in 99c7f0419e66692260be56c0385badeacb3f6760, which is in Qt 6.5. - On platforms where QFLOAT16_IS_NATIVE == false, qHash(qfloat16{}) would produce a different value from qHash(float{}), and therefore Qt 6.4, when the seed was != 0, because the former would go via the one-arg-to-two-arg qHash adapter while the latter one would not. Since participating functions are inline, this causes old and new code to produce different hash values for the same qfloat16, leading to a BiC possibly corrupting QHash etc. Fix both by adding an explicit qHash(qfloat16). This function is inline, so it doesn't add a new symbol to 6.5.x. [ChangeLog][QtCore] Fixed qHash(qfloat16) which was broken from 6.5.0 to 6.5.3, inclusive. If you compiled against one of the affected Qt versions, you need to recompile against either Qt 6.4 or earlier or 6.5.4 or later, because the problematic code is inline. Fixes: QTBUG-116064 Fixes: QTBUG-116076 Change-Id: Id02bc29a6c3ec463352f4bef314c040369081e9b Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit 6da6a17de9ccfcd5458ea72507b131660e0ab948) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit e8fb761f758fe00f3f778e2b475ef3efbefff271)
-rw-r--r--src/corelib/global/qfloat16.cpp14
-rw-r--r--src/corelib/global/qfloat16.h5
-rw-r--r--tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp6
3 files changed, 19 insertions, 6 deletions
diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp
index b8e7cbe928..376d6440e0 100644
--- a/src/corelib/global/qfloat16.cpp
+++ b/src/corelib/global/qfloat16.cpp
@@ -363,6 +363,20 @@ Q_CORE_EXPORT void qFloatFromFloat16(float *out, const qfloat16 *in, qsizetype l
out[i] = float(in[i]);
}
+/*!
+ \fn size_t qfloat16::qHash(qfloat16 key, size_t seed)
+ \since 6.5.4
+ \relates qfloat16
+
+ Returns the hash value for the \a key, using \a seed to seed the
+ calculation.
+
+ \note In Qt versions before 6.5, this operation was provided by the
+ qHash(float) overload. In Qt versions 6.5.0 to 6.5.3, this functionality
+ was broken in various ways. In Qt versions 6.5.4 and 6.6 onwards, this
+ overload restores the Qt 6.4 behavior.
+*/
+
#ifndef QT_NO_DATASTREAM
/*!
\fn qfloat16::operator<<(QDataStream &ds, qfloat16 f)
diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h
index d6a3ac164e..06542c4b4d 100644
--- a/src/corelib/global/qfloat16.h
+++ b/src/corelib/global/qfloat16.h
@@ -6,8 +6,10 @@
#define QFLOAT16_H
#include <QtCore/qglobal.h>
+#include <QtCore/qhashfunctions.h>
#include <QtCore/qmath.h>
#include <QtCore/qnamespace.h>
+
#include <limits>
#include <string.h>
@@ -144,6 +146,9 @@ private:
friend inline qfloat16 operator*(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) * static_cast<NearestFloat>(b)); }
friend inline qfloat16 operator/(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) / static_cast<NearestFloat>(b)); }
+ friend size_t qHash(qfloat16 key, size_t seed = 0) noexcept
+ { return qHash(float(key), seed); } // 6.4 algorithm, so keep using it; ### Qt 7: fix QTBUG-116077
+
#define QF16_MAKE_ARITH_OP_FP(FP, OP) \
friend inline FP operator OP(qfloat16 lhs, FP rhs) noexcept { return static_cast<FP>(lhs) OP rhs; } \
friend inline FP operator OP(FP lhs, qfloat16 rhs) noexcept { return lhs OP static_cast<FP>(rhs); }
diff --git a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
index 69e401ae66..8618a03d14 100644
--- a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
+++ b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
@@ -107,16 +107,10 @@ void tst_QHashFunctions::consistent()
// floats
{
const/*expr broken: QTBUG-116079*/ qfloat16 f16 = -42.f;
-#if !QFLOAT16_IS_NATIVE // QTBUG-116064
const auto h16 = qHash(f16, seed);
-#endif
const auto h32 = qHash(float(f16), seed);
const auto h64 = qHash(double(f16), seed);
-#if !QFLOAT16_IS_NATIVE // QTBUG-116064
- if (seed != 0)
- QEXPECT_FAIL("", "QTBUG-116076", Continue);
QCOMPARE(h16, h32);
-#endif
QEXPECT_FAIL("", "QTBUG-116077", Continue);
QCOMPARE(h32, h64);
}