diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-10-09 17:53:53 +0200 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-10-13 08:06:18 +0200 |
commit | b83225fcc3c6aa5655884cbf9e7391afe38b4392 (patch) | |
tree | c509ef650db260053d4d599a775e0ea267fbacf4 /src/corelib/kernel/qvariant.h | |
parent | 9aa2be236f432dcf4e95a114aeb7254d78ca9dad (diff) |
qDebug: Avoid implicit QVariant conversion
This commit restricts operator<<(QDebug lhs, QVariant rhs) to only work
if rhs is actually of type QVariant (instead of any type convertible to
QVariant). This is especially important as
a) we check in QMetaType whether (slightly simplified) QDebug{} <<
std::declval<T>() is valid, and if so, register a function which
simply uses the operator.
b) In QVariant, we ask the metatype system for the contained types
registered debug function and then use it.
If a type now does not have its own operator<< for QDebug, but is
implicitly convertible to QVariant containing itself, this would lead to
an infinite recursion, when trying to use qDebug with that type. The
registered function in a) would just convert the type to QVariant, and
then ask the QVariant to print itself.
Disallowing implicit conversions in qDebug in general was considered
(i.e. adding template<typename T> operator<<(T) = delete in QDebug ),
but discarded as it breaks too much code relying on conversions.
Fixes: QTBUG-87122
Change-Id: Ib709297670cbc6cc307efd0dfd8e5b0279df9414
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qvariant.h')
-rw-r--r-- | src/corelib/kernel/qvariant.h | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 907094d25c..9df9c53802 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -494,7 +494,11 @@ private: friend inline bool operator!=(const QVariant &a, const QVariant &b) { return !a.equals(b); } #ifndef QT_NO_DEBUG_STREAM - friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &); + template <typename T> + friend auto operator<<(const QDebug &debug, const T &variant) -> std::enable_if_t<std::is_same_v<T, QVariant>, QDebug> { + return variant.qdebugHelper(debug); + } + QDebug qdebugHelper(QDebug) const; #endif template<typename T> friend inline T qvariant_cast(const QVariant &); @@ -595,7 +599,6 @@ template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v) #endif #ifndef QT_NO_DEBUG_STREAM -Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &); Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant::Type); #endif |