diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2020-05-04 12:50:10 +0200 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2020-09-09 06:00:28 +0200 |
commit | e2e493a0169969f34cb0053d96a2f45944aea838 (patch) | |
tree | fdbe898eea7108d32d795417116118c8a30ea765 /src/corelib/global/qflags.h | |
parent | 348b86d976e1b433729114c3cdb29b7397a0a3d4 (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.h | 22 |
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 */ |