From 9883f888501d50239272635398ca4d6dd0087354 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 7 Aug 2024 15:28:51 -0700 Subject: [PATCH] QDebug: cast the QFlags value to the right-sized unsigned type (1/2) This change fixes three problems in the non-Q_ENUM overload. First, the printing of the sign bit for a signed flag. This is correct, but unexpected: QFlags(0x1|0x2|-0x80000000) By using unsigned types, we'll print instead: QFlags(0x1|0x2|0x80000000) Second, shifting into the sign bit is UB, so we remove the problem by not having a sign bit at all. Third, this provides an out-of-line non-template overload of the implementation for unsigned QFlags, thereby avoiding an unnecessary instantiation of the template function qt_QMetaEnum_flagDebugOperator() in user code. Change-Id: I8a96935cf6c742259c9dfffd17e992caa315e1d3 Reviewed-by: Ahmad Samir Reviewed-by: Fabian Kosmale (cherry picked from commit 91a27c1a516068b69ab62778a07c566ad22f3576) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/compat/removed_api.cpp | 7 +++++++ src/corelib/io/qdebug.cpp | 6 +++--- src/corelib/io/qdebug.h | 7 +++++-- tests/auto/corelib/io/qdebug/tst_qdebug.cpp | 7 ++++--- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp index 0963602ca5..44e6250813 100644 --- a/src/corelib/compat/removed_api.cpp +++ b/src/corelib/compat/removed_api.cpp @@ -984,6 +984,13 @@ QDataStream &QDataStream::operator<<(bool i) return (*this << qint8(i)); } +#include "qdebug.h" + +Q_CORE_EXPORT void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, int value) +{ + qt_QMetaEnum_flagDebugOperator(debug, sizeofT, uint(value)); +} + #include "qdir.h" // inlined API bool QDir::operator==(const QDir &dir) const diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index e9b58855f5..93a90953a9 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -1251,13 +1251,13 @@ QDebugStateSaver::~QDebugStateSaver() \internal Specialization of the primary template in qdebug.h to out-of-line - the common case of QFlags::Int being int. + the common case of QFlags::Int being 32-bit. Just call the generic version so the two don't get out of sync. */ -void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, int value) +void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, uint value) { - qt_QMetaEnum_flagDebugOperator(debug, sizeofT, value); + qt_QMetaEnum_flagDebugOperator(debug, sizeofT, value); } #ifndef QT_NO_QOBJECT diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index a2c270f5cd..ea0bb86938 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -488,11 +488,13 @@ inline QDebug operator<<(QDebug debug, const QTaggedPointer &ptr) return debug; } -Q_CORE_EXPORT void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, int value); +Q_CORE_EXPORT void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, uint value); template void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, Int value) { + static_assert(std::is_unsigned_v, + "Cast value to an unsigned type before calling this function"); const QDebugStateSaver saver(debug); debug.resetFormat(); debug.nospace() << "QFlags(" << Qt::hex << Qt::showbase; @@ -556,7 +558,8 @@ template inline QDebug qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags &flags) #endif { - qt_QMetaEnum_flagDebugOperator(debug, sizeof(T), typename QFlags::Int(flags)); + using UInt = typename QIntegerForSizeof::Unsigned; + qt_QMetaEnum_flagDebugOperator(debug, sizeof(T), UInt(flags.toInt())); return debug; } diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp index 7ee2ff42cc..877924e6e4 100644 --- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp +++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp @@ -1082,7 +1082,8 @@ void tst_QDebug::qDebugQByteArrayView() const enum TestEnum { Flag1 = 0x1, - Flag2 = 0x10 + Flag2 = 0x10, + SignFlag = INT_MIN, }; Q_DECLARE_FLAGS(TestFlags, TestEnum) @@ -1091,7 +1092,7 @@ void tst_QDebug::qDebugQFlags() const { QString file, function; int line = 0; - QFlags flags(Flag1 | Flag2); + QFlags flags(Flag1 | Flag2 | SignFlag); MessageHandlerSetter mhs(myMessageHandler); { qDebug() << flags; } @@ -1099,7 +1100,7 @@ void tst_QDebug::qDebugQFlags() const file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO; #endif QCOMPARE(s_msgType, QtDebugMsg); - QCOMPARE(s_msg, QString::fromLatin1("QFlags(0x1|0x10)")); + QCOMPARE(s_msg, QString::fromLatin1("QFlags(0x1|0x10|0x80000000)")); QCOMPARE(QString::fromLatin1(s_file), file); QCOMPARE(s_line, line); QCOMPARE(QString::fromLatin1(s_function), function);