summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qflags.h
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-05-04 12:50:10 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-09-09 06:00:28 +0200
commite2e493a0169969f34cb0053d96a2f45944aea838 (patch)
treefdbe898eea7108d32d795417116118c8a30ea765 /src/corelib/global/qflags.h
parent348b86d976e1b433729114c3cdb29b7397a0a3d4 (diff)
Disable operator+ and operator- for QFlags
... and the associated enumeration. Using them is almost always a certain mistake. 1) op+ between two enumerators of the same enumeration yields int, not QFlags, so removing the type safety that QFlags is supposed to give and breaking the semantics of bitwise operations. 2) op+ between two enumerators of different enumerations is deprecated in C++20 (already flagged by GCC10), and again yields int. This is a code smell. Dedicated classes (holding a combination of unrelated enums) should be used instead. 3) op+ between an enumerator and its QFlags loses the semantic meaning of bitwise operations. If the real meaning was to use operator|, then use that instead; operator+ hides the intent, and can introduce bugs by creating a result not expressible via OR combinations of enumerators: enum E { A = 0x01, B = 0x02 }; QFlags<E> f = E::A; f + E::A; // ??? f + E::B; // ??? Identical reasoning applies for operator-. Technically the other arithmetic operators could be disabled as well, but I really don't expect any real-world usage for them. This has spotted bugs in Qt. [ChangeLog][Potentially Source-Incompatible Changes][QFlags] Using operator+ or operator- with a QFlags object or with an enumeration that has a corresponding QFlags object will now result in a compile-time error, because it's a generally unsafe operation. Use the proper bitwise operations instead (|, &, ~); or cast the enumeration to a integral type before attempting arithmetic manipulations on it. Change-Id: I5eabc5195dec3d3082bc9da10dbc8cf5dff3e1eb Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/corelib/global/qflags.h')
-rw-r--r--src/corelib/global/qflags.h22
1 files changed, 20 insertions, 2 deletions
diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h
index 2319a78877..e576128bce 100644
--- a/src/corelib/global/qflags.h
+++ b/src/corelib/global/qflags.h
@@ -144,6 +144,13 @@ public:
constexpr inline QFlags operator&(Enum other) const noexcept { return QFlags(QFlag(i & Int(other))); }
constexpr inline QFlags operator~() const noexcept { return QFlags(QFlag(~i)); }
+ constexpr inline void operator+(QFlags other) const noexcept = delete;
+ constexpr inline void operator+(Enum other) const noexcept = delete;
+ constexpr inline void operator+(int other) const noexcept = delete;
+ constexpr inline void operator-(QFlags other) const noexcept = delete;
+ constexpr inline void operator-(Enum other) const noexcept = delete;
+ constexpr inline void operator-(int other) const noexcept = delete;
+
constexpr inline bool operator!() const noexcept { return !i; }
constexpr inline bool testFlag(Enum flag) const noexcept { return (i & Int(flag)) == Int(flag) && (Int(flag) != 0 || i == Int(flag) ); }
@@ -170,13 +177,24 @@ typedef QFlags<Enum> Flags;
#define Q_DECLARE_INCOMPATIBLE_FLAGS(Flags) \
constexpr inline QIncompatibleFlag operator|(Flags::enum_type f1, int f2) noexcept \
-{ return QIncompatibleFlag(int(f1) | f2); }
+{ return QIncompatibleFlag(int(f1) | f2); } \
+constexpr inline void operator+(int f1, Flags::enum_type f2) noexcept = delete; \
+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;
#define Q_DECLARE_OPERATORS_FOR_FLAGS(Flags) \
constexpr inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) noexcept \
{ return QFlags<Flags::enum_type>(f1) | f2; } \
constexpr inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept \
-{ return f2 | f1; } Q_DECLARE_INCOMPATIBLE_FLAGS(Flags)
+{ return f2 | f1; } \
+constexpr inline void operator+(Flags::enum_type f1, Flags::enum_type f2) noexcept = delete; \
+constexpr inline void operator+(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept = delete; \
+constexpr inline void operator+(int f1, QFlags<Flags::enum_type> f2) noexcept = delete; \
+constexpr inline void operator-(Flags::enum_type f1, Flags::enum_type f2) noexcept = delete; \
+constexpr inline void operator-(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept = delete; \
+constexpr inline void operator-(int f1, QFlags<Flags::enum_type> f2) noexcept = delete; \
+Q_DECLARE_INCOMPATIBLE_FLAGS(Flags)
#else /* Q_NO_TYPESAFE_FLAGS */