From 67072a70aff6688180bd3e008aef1f2a44e7469a Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 13 Nov 2023 18:48:32 +0100 Subject: Q*Ordering: supply is_{lt,gt,n,}eq std::is_eq etc work fine on our Q*Ordering types when C++20 is available. But in C++17 mode, they're absent. Plug the hole by providing them for our own types as hidden friends, so that users can use unqualified calls to transparently support both std::*ordering and Q*Ordering types, just like with comparison to literal zero. For some reason, we running here into https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903, even though this wasn't seen in other commits of the chain that use comparisons to literal zero. Suppress the warning. Then at least is_eq etc provide a safe fall-back for compilers and users affected by this bogus warning. Fixes: QTBUG-119100 Change-Id: Ie8519c92363401a0c9c8efba6eb0b6e030a8e235 Reviewed-by: Ivan Solovev Reviewed-by: Qt CI Bot --- src/corelib/global/qcompare.h | 33 +++++++ src/corelib/global/qcompare.qdoc | 50 ++++++++++ .../auto/corelib/global/qcompare/tst_qcompare.cpp | 109 +++++++++++++++++++++ 3 files changed, 192 insertions(+) diff --git a/src/corelib/global/qcompare.h b/src/corelib/global/qcompare.h index 4bc97fa24e..2c0392097c 100644 --- a/src/corelib/global/qcompare.h +++ b/src/corelib/global/qcompare.h @@ -152,6 +152,17 @@ private: : m_order(static_cast(order)) {} + QT_WARNING_PUSH + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903 + QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant") + friend constexpr bool is_eq (QPartialOrdering o) noexcept { return o == 0; } + friend constexpr bool is_neq (QPartialOrdering o) noexcept { return o != 0; } + friend constexpr bool is_lt (QPartialOrdering o) noexcept { return o < 0; } + friend constexpr bool is_lteq(QPartialOrdering o) noexcept { return o <= 0; } + friend constexpr bool is_gt (QPartialOrdering o) noexcept { return o > 0; } + friend constexpr bool is_gteq(QPartialOrdering o) noexcept { return o >= 0; } + QT_WARNING_POP + // instead of the exposition only is_ordered member in [cmp.partialord], // use a private function constexpr bool isOrdered() const noexcept @@ -309,6 +320,17 @@ private: : m_order(static_cast(order)) {} + QT_WARNING_PUSH + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903 + QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant") + friend constexpr bool is_eq (QWeakOrdering o) noexcept { return o == 0; } + friend constexpr bool is_neq (QWeakOrdering o) noexcept { return o != 0; } + friend constexpr bool is_lt (QWeakOrdering o) noexcept { return o < 0; } + friend constexpr bool is_lteq(QWeakOrdering o) noexcept { return o <= 0; } + friend constexpr bool is_gt (QWeakOrdering o) noexcept { return o > 0; } + friend constexpr bool is_gteq(QWeakOrdering o) noexcept { return o >= 0; } + QT_WARNING_POP + QtPrivate::CompareUnderlyingType m_order; }; @@ -478,6 +500,17 @@ public: : m_order(static_cast(order)) {} + QT_WARNING_PUSH + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903 + QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant") + friend constexpr bool is_eq (QStrongOrdering o) noexcept { return o == 0; } + friend constexpr bool is_neq (QStrongOrdering o) noexcept { return o != 0; } + friend constexpr bool is_lt (QStrongOrdering o) noexcept { return o < 0; } + friend constexpr bool is_lteq(QStrongOrdering o) noexcept { return o <= 0; } + friend constexpr bool is_gt (QStrongOrdering o) noexcept { return o > 0; } + friend constexpr bool is_gteq(QStrongOrdering o) noexcept { return o >= 0; } + QT_WARNING_POP + QtPrivate::CompareUnderlyingType m_order; }; diff --git a/src/corelib/global/qcompare.qdoc b/src/corelib/global/qcompare.qdoc index ffeb1ec887..ab0f2fb49f 100644 --- a/src/corelib/global/qcompare.qdoc +++ b/src/corelib/global/qcompare.qdoc @@ -223,6 +223,30 @@ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QStrongOrdering rhs) */ +/*! + \fn QStrongOrdering::is_eq (QStrongOrdering o) + \fn QStrongOrdering::is_neq (QStrongOrdering o) + \fn QStrongOrdering::is_lt (QStrongOrdering o) + \fn QStrongOrdering::is_lteq(QStrongOrdering o) + \fn QStrongOrdering::is_gt (QStrongOrdering o) + \fn QStrongOrdering::is_gteq(QStrongOrdering o) + +//! [is_eq_table] + Converts \a o into the result of one of the six relational operators: + \table + \header \li Function \li Operation + \row \li \c{is_eq} \li \a o \c{== 0} + \row \li \c{is_neq} \li \a o \c{!= 0} + \row \li \c{is_lt} \li \a o \c{< 0} + \row \li \c{is_lteq} \li \a o \c{<= 0} + \row \li \c{is_gt} \li \a o \c{> 0} + \row \li \c{is_gteq} \li \a o \c{>= 0} + \endtable +//! [is_eq_table] + + These functions are provided for compatibility with \c{std::strong_ordering}. +*/ + /*! \variable QStrongOrdering::Less @@ -366,6 +390,19 @@ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QWeakOrdering rhs) */ +/*! + \fn QWeakOrdering::is_eq (QWeakOrdering o) + \fn QWeakOrdering::is_neq (QWeakOrdering o) + \fn QWeakOrdering::is_lt (QWeakOrdering o) + \fn QWeakOrdering::is_lteq(QWeakOrdering o) + \fn QWeakOrdering::is_gt (QWeakOrdering o) + \fn QWeakOrdering::is_gteq(QWeakOrdering o) + + \include qcompare.qdoc is_eq_table + + These functions are provided for compatibility with \c{std::weak_ordering}. +*/ + /*! \variable QWeakOrdering::Less @@ -499,6 +536,19 @@ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs) */ +/*! + \fn QPartialOrdering::is_eq (QPartialOrdering o) + \fn QPartialOrdering::is_neq (QPartialOrdering o) + \fn QPartialOrdering::is_lt (QPartialOrdering o) + \fn QPartialOrdering::is_lteq(QPartialOrdering o) + \fn QPartialOrdering::is_gt (QPartialOrdering o) + \fn QPartialOrdering::is_gteq(QPartialOrdering o) + + \include qcompare.qdoc is_eq_table + + These functions are provided for compatibility with \c{std::partial_ordering}. +*/ + /*! \variable QPartialOrdering::Less diff --git a/tests/auto/corelib/global/qcompare/tst_qcompare.cpp b/tests/auto/corelib/global/qcompare/tst_qcompare.cpp index a8dcc3a201..ac5aa7cb17 100644 --- a/tests/auto/corelib/global/qcompare/tst_qcompare.cpp +++ b/tests/auto/corelib/global/qcompare/tst_qcompare.cpp @@ -16,6 +16,7 @@ private slots: void weakOrdering(); void strongOrdering(); void conversions(); + void is_eq_overloads(); }; void tst_QCompare::partialOrdering() @@ -40,6 +41,12 @@ void tst_QCompare::partialOrdering() static_assert(QPartialOrdering::Greater != QPartialOrdering::Equivalent); static_assert(QPartialOrdering::Greater == QPartialOrdering::Greater); + static_assert(!is_eq (QPartialOrdering::Unordered)); + static_assert(!is_neq (QPartialOrdering::Unordered)); + static_assert(!is_lt (QPartialOrdering::Unordered)); + static_assert(!is_lteq(QPartialOrdering::Unordered)); + static_assert(!is_gt (QPartialOrdering::Unordered)); + static_assert(!is_gteq(QPartialOrdering::Unordered)); static_assert(!(QPartialOrdering::Unordered == 0)); static_assert(!(QPartialOrdering::Unordered != 0)); @@ -56,6 +63,13 @@ void tst_QCompare::partialOrdering() static_assert(!(0 >= QPartialOrdering::Unordered)); + static_assert(!is_eq (QPartialOrdering::Less)); + static_assert( is_neq (QPartialOrdering::Less)); + static_assert( is_lt (QPartialOrdering::Less)); + static_assert( is_lteq(QPartialOrdering::Less)); + static_assert(!is_gt (QPartialOrdering::Less)); + static_assert(!is_gteq(QPartialOrdering::Less)); + static_assert(!(QPartialOrdering::Less == 0)); static_assert( (QPartialOrdering::Less != 0)); static_assert( (QPartialOrdering::Less < 0)); @@ -71,6 +85,13 @@ void tst_QCompare::partialOrdering() static_assert( (0 >= QPartialOrdering::Less)); + static_assert( is_eq (QPartialOrdering::Equivalent)); + static_assert(!is_neq (QPartialOrdering::Equivalent)); + static_assert(!is_lt (QPartialOrdering::Equivalent)); + static_assert( is_lteq(QPartialOrdering::Equivalent)); + static_assert(!is_gt (QPartialOrdering::Equivalent)); + static_assert( is_gteq(QPartialOrdering::Equivalent)); + static_assert( (QPartialOrdering::Equivalent == 0)); static_assert(!(QPartialOrdering::Equivalent != 0)); static_assert(!(QPartialOrdering::Equivalent < 0)); @@ -86,6 +107,13 @@ void tst_QCompare::partialOrdering() static_assert( (0 >= QPartialOrdering::Equivalent)); + static_assert(!is_eq (QPartialOrdering::Greater)); + static_assert( is_neq (QPartialOrdering::Greater)); + static_assert(!is_lt (QPartialOrdering::Greater)); + static_assert(!is_lteq(QPartialOrdering::Greater)); + static_assert( is_gt (QPartialOrdering::Greater)); + static_assert( is_gteq(QPartialOrdering::Greater)); + static_assert(!(QPartialOrdering::Greater == 0)); static_assert( (QPartialOrdering::Greater != 0)); static_assert(!(QPartialOrdering::Greater < 0)); @@ -115,6 +143,13 @@ void tst_QCompare::weakOrdering() static_assert(QWeakOrdering::Greater != QWeakOrdering::Equivalent); static_assert(QWeakOrdering::Greater == QWeakOrdering::Greater); + static_assert(!is_eq (QWeakOrdering::Less)); + static_assert( is_neq (QWeakOrdering::Less)); + static_assert( is_lt (QWeakOrdering::Less)); + static_assert( is_lteq(QWeakOrdering::Less)); + static_assert(!is_gt (QWeakOrdering::Less)); + static_assert(!is_gteq(QWeakOrdering::Less)); + static_assert(!(QWeakOrdering::Less == 0)); static_assert( (QWeakOrdering::Less != 0)); static_assert( (QWeakOrdering::Less < 0)); @@ -129,6 +164,14 @@ void tst_QCompare::weakOrdering() static_assert( (0 > QWeakOrdering::Less)); static_assert( (0 >= QWeakOrdering::Less)); + + static_assert( is_eq (QWeakOrdering::Equivalent)); + static_assert(!is_neq (QWeakOrdering::Equivalent)); + static_assert(!is_lt (QWeakOrdering::Equivalent)); + static_assert( is_lteq(QWeakOrdering::Equivalent)); + static_assert(!is_gt (QWeakOrdering::Equivalent)); + static_assert( is_gteq(QWeakOrdering::Equivalent)); + static_assert( (QWeakOrdering::Equivalent == 0)); static_assert(!(QWeakOrdering::Equivalent != 0)); static_assert(!(QWeakOrdering::Equivalent < 0)); @@ -143,6 +186,14 @@ void tst_QCompare::weakOrdering() static_assert(!(0 > QWeakOrdering::Equivalent)); static_assert( (0 >= QWeakOrdering::Equivalent)); + + static_assert(!is_eq (QWeakOrdering::Greater)); + static_assert( is_neq (QWeakOrdering::Greater)); + static_assert(!is_lt (QWeakOrdering::Greater)); + static_assert(!is_lteq(QWeakOrdering::Greater)); + static_assert( is_gt (QWeakOrdering::Greater)); + static_assert( is_gteq(QWeakOrdering::Greater)); + static_assert(!(QWeakOrdering::Greater == 0)); static_assert( (QWeakOrdering::Greater != 0)); static_assert(!(QWeakOrdering::Greater < 0)); @@ -180,6 +231,13 @@ void tst_QCompare::strongOrdering() static_assert(QStrongOrdering::Greater != QStrongOrdering::Equivalent); static_assert(QStrongOrdering::Greater == QStrongOrdering::Greater); + static_assert(!is_eq (QStrongOrdering::Less)); + static_assert( is_neq (QStrongOrdering::Less)); + static_assert( is_lt (QStrongOrdering::Less)); + static_assert( is_lteq(QStrongOrdering::Less)); + static_assert(!is_gt (QStrongOrdering::Less)); + static_assert(!is_gteq(QStrongOrdering::Less)); + static_assert(!(QStrongOrdering::Less == 0)); static_assert( (QStrongOrdering::Less != 0)); static_assert( (QStrongOrdering::Less < 0)); @@ -194,6 +252,14 @@ void tst_QCompare::strongOrdering() static_assert( (0 > QStrongOrdering::Less)); static_assert( (0 >= QStrongOrdering::Less)); + + static_assert( is_eq (QStrongOrdering::Equal)); + static_assert(!is_neq (QStrongOrdering::Equal)); + static_assert(!is_lt (QStrongOrdering::Equal)); + static_assert( is_lteq(QStrongOrdering::Equal)); + static_assert(!is_gt (QStrongOrdering::Equal)); + static_assert( is_gteq(QStrongOrdering::Equal)); + static_assert( (QStrongOrdering::Equal == 0)); static_assert(!(QStrongOrdering::Equal != 0)); static_assert(!(QStrongOrdering::Equal < 0)); @@ -208,6 +274,14 @@ void tst_QCompare::strongOrdering() static_assert(!(0 > QStrongOrdering::Equal)); static_assert( (0 >= QStrongOrdering::Equal)); + + static_assert( is_eq (QStrongOrdering::Equivalent)); + static_assert(!is_neq (QStrongOrdering::Equivalent)); + static_assert(!is_lt (QStrongOrdering::Equivalent)); + static_assert( is_lteq(QStrongOrdering::Equivalent)); + static_assert(!is_gt (QStrongOrdering::Equivalent)); + static_assert( is_gteq(QStrongOrdering::Equivalent)); + static_assert( (QStrongOrdering::Equivalent == 0)); static_assert(!(QStrongOrdering::Equivalent != 0)); static_assert(!(QStrongOrdering::Equivalent < 0)); @@ -222,6 +296,14 @@ void tst_QCompare::strongOrdering() static_assert(!(0 > QStrongOrdering::Equivalent)); static_assert( (0 >= QStrongOrdering::Equivalent)); + + static_assert(!is_eq (QStrongOrdering::Greater)); + static_assert( is_neq (QStrongOrdering::Greater)); + static_assert(!is_lt (QStrongOrdering::Greater)); + static_assert(!is_lteq(QStrongOrdering::Greater)); + static_assert( is_gt (QStrongOrdering::Greater)); + static_assert( is_gteq(QStrongOrdering::Greater)); + static_assert(!(QStrongOrdering::Greater == 0)); static_assert( (QStrongOrdering::Greater != 0)); static_assert(!(QStrongOrdering::Greater < 0)); @@ -366,5 +448,32 @@ void tst_QCompare::conversions() } +void tst_QCompare::is_eq_overloads() +{ +#ifndef __cpp_lib_three_way_comparison + QSKIP("This test requires C++20 three-way-comparison support enabled in the stdlib."); +#else + constexpr auto u = std::partial_ordering::unordered; + constexpr auto l = std::weak_ordering::less; + constexpr auto g = std::strong_ordering::greater; + constexpr auto e = std::weak_ordering::equivalent; + constexpr auto s = std::strong_ordering::equal; + + // This is a compile-time check that unqualified name lookup of + // std::is_eq-like functions isn't ambiguous, so we can recommend it to our + // users for minimizing porting on the way to C++20. + + // The goal is to check each std::ordering and each is_eq function at least + // once, not to test all combinations (we're not the stdlib test suite here). + + QVERIFY(is_eq(s)); + QVERIFY(is_neq(u)); + QVERIFY(is_lt(l)); + QVERIFY(is_gt(g)); + QVERIFY(is_lteq(e)); + QVERIFY(is_gteq(s)); +#endif // __cpp_lib_three_way_comparison +} + QTEST_MAIN(tst_QCompare) #include "tst_qcompare.moc" -- cgit v1.2.3