diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h index ab46af2d8e7..c6cbaa1adb2 100644 --- a/src/corelib/global/qflags.h +++ b/src/corelib/global/qflags.h @@ -205,6 +205,33 @@ constexpr inline void operator+(Flags::enum_type f1, int f2) noexcept = delete; constexpr inline void operator-(int f1, Flags::enum_type f2) noexcept = delete; \ constexpr inline void operator-(Flags::enum_type f1, int f2) noexcept = delete; +// restore bit-wise enum-enum operators deprecated in C++20, +// but used in a few places in the API +#if __cplusplus > 201702L // assume compilers don't warn if in C++17 mode + // in C++20 mode, provide user-defined operators to override the deprecated operations: +# define Q_DECLARE_MIXED_ENUM_OPERATOR(op, Ret, LHS, RHS) \ + constexpr inline Ret operator op (LHS lhs, RHS rhs) noexcept \ + { return static_cast(qToUnderlying(lhs) op qToUnderlying(rhs)); } \ + /* end */ +#else + // in C++17 mode, statically-assert that this compiler's result of the + // operation is the same that the C++20 version would produce: +# define Q_DECLARE_MIXED_ENUM_OPERATOR(op, Ret, LHS, RHS) \ + static_assert(std::is_same_v() op std::declval()), Ret>); +#endif + +#define Q_DECLARE_MIXED_ENUM_OPERATORS(Ret, Flags, Enum) \ + Q_DECLARE_MIXED_ENUM_OPERATOR(|, Ret, Flags, Enum) \ + Q_DECLARE_MIXED_ENUM_OPERATOR(&, Ret, Flags, Enum) \ + Q_DECLARE_MIXED_ENUM_OPERATOR(^, Ret, Flags, Enum) \ + /* end */ + +#define Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(Ret, Flags, Enum) \ + Q_DECLARE_MIXED_ENUM_OPERATORS(Ret, Flags, Enum) \ + Q_DECLARE_MIXED_ENUM_OPERATORS(Ret, Enum, Flags) \ + /* end */ + + QT_END_NAMESPACE #endif // QFLAGS_H diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 6bbe2426098..99678cf97e7 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -208,6 +208,7 @@ namespace Qt { // size of a multi-variant string. TextLongestVariant = 0x80000 }; + Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, AlignmentFlag, TextFlag) enum TextElideMode { ElideLeft, @@ -215,6 +216,7 @@ namespace Qt { ElideMiddle, ElideNone }; + Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, TextElideMode, TextFlag) enum WhiteSpaceMode { WhiteSpaceNormal, diff --git a/src/corelib/text/qunicodetools.cpp b/src/corelib/text/qunicodetools.cpp index be235aa0bf7..bf271223f73 100644 --- a/src/corelib/text/qunicodetools.cpp +++ b/src/corelib/text/qunicodetools.cpp @@ -1699,6 +1699,8 @@ enum MymrCharClassFlags { Mymr_CF_AFTER_KINZI = 0x00100000 }; +Q_DECLARE_MIXED_ENUM_OPERATORS(int, MymrCharClassValues, MymrCharClassFlags) + /* Characters that get refrered to by name */ enum MymrChar { @@ -1946,6 +1948,7 @@ enum KhmerCharClassFlags { CF_POS_MASK = 0x000f0000 }; +Q_DECLARE_MIXED_ENUM_OPERATORS(int, KhmerCharClassValues, KhmerCharClassFlags) /* Characters that get referred to by name */ enum KhmerChar { diff --git a/src/widgets/kernel/qsizepolicy.h b/src/widgets/kernel/qsizepolicy.h index 5e948175f31..977f8008ead 100644 --- a/src/widgets/kernel/qsizepolicy.h +++ b/src/widgets/kernel/qsizepolicy.h @@ -199,6 +199,7 @@ private: Q_DECLARE_TYPEINFO(QSizePolicy, Q_PRIMITIVE_TYPE); Q_DECLARE_OPERATORS_FOR_FLAGS(QSizePolicy::ControlTypes) +Q_DECLARE_MIXED_ENUM_OPERATORS(int, QSizePolicy::Policy, QSizePolicy::PolicyFlag) #ifndef QT_NO_DATASTREAM Q_WIDGETS_EXPORT QDataStream &operator<<(QDataStream &, const QSizePolicy &); diff --git a/src/widgets/widgets/qframe.h b/src/widgets/widgets/qframe.h index 144003bc0ef..2e97938c6b1 100644 --- a/src/widgets/widgets/qframe.h +++ b/src/widgets/widgets/qframe.h @@ -123,6 +123,8 @@ private: Q_DECLARE_PRIVATE(QFrame) }; +Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QFrame::Shape, QFrame::Shadow) + QT_END_NAMESPACE #endif // QFRAME_H diff --git a/tests/auto/corelib/global/qflags/tst_qflags.cpp b/tests/auto/corelib/global/qflags/tst_qflags.cpp index c252d797b21..e9caaf6dce4 100644 --- a/tests/auto/corelib/global/qflags/tst_qflags.cpp +++ b/tests/auto/corelib/global/qflags/tst_qflags.cpp @@ -35,6 +35,7 @@ class tst_QFlags: public QObject private slots: void boolCasts() const; void operators() const; + void mixingDifferentEnums() const; void testFlag() const; void testFlagZeroFlag() const; void testFlagMultiBits() const; @@ -109,7 +110,41 @@ void tst_QFlags::operators() const CHECK(&, Qt::AlignHCenter, Qt::AlignHCenter, Qt::AlignHCenter); CHECK(^, Qt::AlignHCenter, Qt::AlignVCenter, Qt::AlignCenter); CHECK(^, Qt::AlignHCenter, Qt::AlignHCenter, Qt::Alignment()); +#undef CHECK +} +void tst_QFlags::mixingDifferentEnums() const +{ +#define CHECK(op, LHS, RHS, RES) \ + /* LHS must be QFlags'able */ \ + do { \ + QCOMPARE((LHS op RHS), (RES)); \ + QCOMPARE((RHS op LHS), (RES)); \ + /*QCOMPARE(( / *CTAD* / QFlags(LHS) op RHS), (RES));*/ \ + /*QCOMPARE((QFlags(LHS) op ## = RHS), (RES));*/ \ + } while (false) + + // AlignmentFlags <-> TextFlags + { + CHECK(|, Qt::AlignCenter, Qt::TextSingleLine, 0x0184); + CHECK(&, Qt::AlignCenter, Qt::TextSingleLine, 0x0000); + CHECK(^, Qt::AlignCenter, Qt::TextSingleLine, 0x0184); + } + // QFlags <-> TextFlags + { +#ifndef QT_TYPESAFE_FLAGS // QTBUG-101344 + Qt::Alignment MyAlignCenter = Qt::AlignCenter; // convert enum to QFlags + CHECK(|, MyAlignCenter, Qt::TextSingleLine, 0x0184U); // yes, unsigned! + CHECK(&, MyAlignCenter, Qt::TextSingleLine, 0x0000U); // yes, unsigned! + CHECK(^, MyAlignCenter, Qt::TextSingleLine, 0x0184U); // yes, unsigned! +#endif + } + // TextElideMode <-> TextFlags + { + CHECK(|, Qt::ElideNone, Qt::TextSingleLine, 0x0103); + CHECK(&, Qt::ElideNone, Qt::TextSingleLine, 0x0000); + CHECK(^, Qt::ElideNone, Qt::TextSingleLine, 0x0103); + } #undef CHECK }