diff --git a/src/testlib/qcomparisontesthelper_p.h b/src/testlib/qcomparisontesthelper_p.h index 00e00925db..da92aeb985 100644 --- a/src/testlib/qcomparisontesthelper_p.h +++ b/src/testlib/qcomparisontesthelper_p.h @@ -16,12 +16,22 @@ // #include +#include #include QT_BEGIN_NAMESPACE namespace QTestPrivate { +#ifdef __cpp_lib_three_way_comparison +template +using HasThreeWayComparisonOp = decltype(std::declval() <=> std::declval()); + +template +constexpr bool implementsThreeWayComparisonOp_v = qxp::is_detected_v; +#endif + Q_TESTLIB_EXPORT QByteArray formatTypeWithCRefImpl(QMetaType type, bool isConst, bool isRef, bool isRvalueRef); @@ -95,6 +105,9 @@ void testEqualityOperatorsCompile() This function checks that the types \c LeftType and \c RightType properly define all comparison operators (==, !=, <, >, <=, >=). The checks are performed for all combinations of cvref-qualified lvalues and rvalues. + + If compiled in C++20 mode, also checks \c {operator<=>()} if that is + implemented. */ template void testAllComparisonOperatorsCompile() @@ -106,6 +119,11 @@ void testAllComparisonOperatorsCompile() FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <, bool) FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, >=, bool) FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <=, bool) +#ifdef __cpp_lib_three_way_comparison + if constexpr (implementsThreeWayComparisonOp_v) { + FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <=>, std::partial_ordering) + } +#endif } #undef CHECK_SINGLE_OPERATOR @@ -127,6 +145,20 @@ void testAllComparisonOperatorsCompile() Func(std::as_const(Left), std::as_const(Right), Op, Expected); \ /* END */ +#ifdef __cpp_lib_three_way_comparison + +// Hide the macro under an ifdef, because it otherwise triggers a warning +// in Clang C++17 build. +#define CHECK_RUNTIME_3WAY(Left, Right, Op, Expected) \ + do { \ + QCOMPARE_EQ((Left <=> Right) Op 0, Expected); \ + QCOMPARE_EQ((std::move(Left) <=> Right) Op 0, Expected); \ + QCOMPARE_EQ((Left <=> std::move(Right)) Op 0, Expected); \ + QCOMPARE_EQ((std::move(Left) <=> std::move(Right)) Op 0, Expected); \ + } while (false); \ + /* END */ + +#endif // __cpp_lib_three_way_comparison /*! \internal @@ -167,6 +199,9 @@ void testEqualityOperators(LeftType lhs, RightType rhs, bool expectedEqual) (==, !=, <, >, <=, >=) for the \a lhs operand of type \c {LeftType} and the \a rhs operand of type \c {RightType}. + If compiled in C++20 mode, also checks \c {operator<=>()} if that is + implemented. + When compiled in C++17 mode, the \c OrderingType must be one of Qt::partial_ordering, Qt::strong_ordering, or Qt::weak_ordering. In C++20 mode, also the \c {std::*_ordering} types can be used. @@ -222,6 +257,29 @@ void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expect !expectedUnordered && (expectedEqual || expectedLess)) CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, >=, !expectedUnordered && !expectedLess) +#ifdef __cpp_lib_three_way_comparison + if constexpr (implementsThreeWayComparisonOp_v) { + if constexpr (std::is_convertible_v) + static_assert(std::is_same_v rhs), std::strong_ordering>); + else if constexpr (std::is_convertible_v) + static_assert(std::is_same_v rhs), std::weak_ordering>); + else + static_assert(std::is_same_v rhs), std::partial_ordering>); + + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, ==, + !expectedUnordered && expectedEqual) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, !=, + expectedUnordered || !expectedEqual) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, <, + !expectedUnordered && expectedLess) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, >, + !expectedUnordered && !expectedLess && !expectedEqual) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, <=, + !expectedUnordered && (expectedEqual || expectedLess)) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, >=, + !expectedUnordered && !expectedLess) + } +#endif if constexpr (!std::is_same_v) { CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==, @@ -236,9 +294,35 @@ void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expect !expectedUnordered && !expectedLess) CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, >=, !expectedUnordered && (expectedEqual || expectedLess)) +#ifdef __cpp_lib_three_way_comparison + if constexpr (implementsThreeWayComparisonOp_v) { + if constexpr (std::is_convertible_v) + static_assert(std::is_same_v lhs), std::strong_ordering>); + else if constexpr (std::is_convertible_v) + static_assert(std::is_same_v lhs), std::weak_ordering>); + else + static_assert(std::is_same_v lhs), std::partial_ordering>); + + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, ==, + !expectedUnordered && expectedEqual) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, !=, + expectedUnordered || !expectedEqual) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, <, + !expectedUnordered && !expectedLess && !expectedEqual) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, >, + !expectedUnordered && expectedLess) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, <=, + !expectedUnordered && !expectedLess) + CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, >=, + !expectedUnordered && (expectedEqual || expectedLess)) + } +#endif } } +#ifdef __cpp_lib_three_way_comparison +#undef CHECK_RUNTIME_3WAY +#endif #undef CHECK_RUNTIME_CREF #undef CHECK_RUNTIME_LR