From ccaeffe5655cba23b4f708ec575e34f03cf08a1c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 26 Nov 2021 16:31:59 +0100 Subject: [PATCH] QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH: use unqualified qHash() lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... instead of QT_PREPEND_NAMESPACE(qHash), which is qualified (prepends at least '::'), and therefore disables ADL. This is not a problem as long as we wrote our qHash() overloads as free functions (incl. non-hidden friends), but it should™ fail for hidden friends, so use the old using-std::swap() trick to bring QT_PREPEND_NAMESPACE(qHash) into scope, proceeding with an unqualified lookup. Pick-to: 6.2 Change-Id: I00860b2313699849f86bfe3dd9f41db4ce993cd3 Reviewed-by: Qt CI Bot Reviewed-by: Mårten Nordheim --- src/corelib/tools/qhashfunctions.h | 11 +++++--- .../qhashfunctions/tst_qhashfunctions.cpp | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h index 4f8e4066ee..4d0b2d9519 100644 --- a/src/corelib/tools/qhashfunctions.h +++ b/src/corelib/tools/qhashfunctions.h @@ -251,6 +251,9 @@ struct QNothrowHashable : std::false_type {}; template struct QNothrowHashable>> : std::true_type {}; +template +constexpr inline bool QNothrowHashable_v = QNothrowHashable::value; + } // namespace QtPrivate template @@ -317,15 +320,15 @@ template inline size_t qHash(const std::pair using argument_type = QT_PREPEND_NAMESPACE(Class); \ using result_type = size_t; \ size_t operator()(Arguments s) const \ - noexcept(noexcept(QT_PREPEND_NAMESPACE(qHash)(s))) \ + noexcept(QT_PREPEND_NAMESPACE( \ + QtPrivate::QNothrowHashable_v)) \ { \ /* this seeds qHash with the result of */ \ /* std::hash applied to an int, to reap */ \ /* any protection against predictable hash */ \ /* values the std implementation may provide */ \ - return QT_PREPEND_NAMESPACE(qHash)(s, \ - QT_PREPEND_NAMESPACE(qHash)( \ - std::hash{}(0))); \ + using QT_PREPEND_NAMESPACE(qHash); \ + return qHash(s, qHash(std::hash{}(0))); \ } \ }; \ } \ diff --git a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp index 86305b101f..3281c4cefd 100644 --- a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp +++ b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp @@ -303,8 +303,34 @@ void tst_QHashFunctions::rangeCommutative() } } +// QVarLengthArray these days has a qHash() as a hidden friend. +// This checks that QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH can deal with that: + +QT_BEGIN_NAMESPACE +QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QVarLengthArray>) +QT_END_NAMESPACE + void tst_QHashFunctions::stdHash() { + { + std::unordered_set>> s = { + { + {0, 1, 2}, + {42, 43, 44}, + {}, + }, { + {11, 12, 13}, + {}, + }, + }; + QCOMPARE(s.size(), 2UL); + s.insert({ + {11, 12, 13}, + {}, + }); + QCOMPARE(s.size(), 2UL); + } + { std::unordered_set s = {QStringLiteral("Hello"), QStringLiteral("World")}; QCOMPARE(s.size(), 2UL);