QVariant: Tolerate QObject* metatypes without QMetaObject

QMetaType does. QVariant should do the same.

Pick-to: 6.2
Change-Id: I3419276b78b3b5ce8bd144dee92685195797d568
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Daniel Nicoletti <daniel.nicoletti@kdab.com>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Ulf Hermann 2021-07-13 11:48:46 +02:00
parent 79a219862f
commit 6f8ef8c64d
2 changed files with 53 additions and 3 deletions

View File

@ -2341,9 +2341,11 @@ static bool numericEquals(const QVariant::Private *d1, const QVariant::Private *
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
static bool canConvertMetaObject(QMetaType fromType, QMetaType toType) static bool canConvertMetaObject(QMetaType fromType, QMetaType toType)
{ {
if ((fromType.flags() & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) { if ((fromType.flags() & QMetaType::PointerToQObject)
return fromType.metaObject()->inherits(toType.metaObject()) || && (toType.flags() & QMetaType::PointerToQObject)) {
toType.metaObject()->inherits(fromType.metaObject()); const QMetaObject *f = fromType.metaObject();
const QMetaObject *t = toType.metaObject();
return f && t && (f->inherits(t) || t->inherits(f));
} }
return false; return false;
} }

View File

@ -63,6 +63,7 @@
#include "qnumeric.h" #include "qnumeric.h"
#include <private/qlocale_p.h> #include <private/qlocale_p.h>
#include <private/qmetatype_p.h>
#include "tst_qvariant_common.h" #include "tst_qvariant_common.h"
#include <unordered_map> #include <unordered_map>
@ -309,6 +310,7 @@ private slots:
void mutableView(); void mutableView();
void moveOperations(); void moveOperations();
void equalsWithoutMetaObject();
private: private:
void dataStream_data(QDataStream::Version version); void dataStream_data(QDataStream::Version version);
@ -5086,5 +5088,51 @@ void tst_QVariant::moveOperations()
QVERIFY(v2.value<std::list<int>>() == list); QVERIFY(v2.value<std::list<int>>() == list);
} }
class NoMetaObject : public QObject {};
void tst_QVariant::equalsWithoutMetaObject()
{
using T = NoMetaObject*;
QtPrivate::QMetaTypeInterface d = {
/*.revision=*/ 0,
/*.alignment=*/ alignof(T),
/*.size=*/ sizeof(T),
/*.flags=*/ QtPrivate::QMetaTypeTypeFlags<T>::Flags,
/*.typeId=*/ 0,
/*.metaObject=*/ nullptr, // on purpose.
/*.name=*/ "NoMetaObject*",
/*.defaultCtr=*/ [](const QtPrivate::QMetaTypeInterface *, void *addr) {
new (addr) T();
},
/*.copyCtr=*/ [](const QtPrivate::QMetaTypeInterface *, void *addr, const void *other) {
new (addr) T(*reinterpret_cast<const T *>(other));
},
/*.moveCtr=*/ [](const QtPrivate::QMetaTypeInterface *, void *addr, void *other) {
new (addr) T(std::move(*reinterpret_cast<T *>(other)));
},
/*.dtor=*/ [](const QtPrivate::QMetaTypeInterface *, void *addr) {
reinterpret_cast<T *>(addr)->~T();
},
/*.equals*/ nullptr,
/*.lessThan*/ nullptr,
/*.debugStream=*/ nullptr,
/*.dataStreamOut=*/ nullptr,
/*.dataStreamIn=*/ nullptr,
/*.legacyRegisterOp=*/ nullptr
};
QMetaType noMetaObjectMetaType(&d);
QMetaType qobjectMetaType = QMetaType::fromType<tst_QVariant*>();
QVERIFY(noMetaObjectMetaType.flags() & QMetaType::PointerToQObject);
QVERIFY(qobjectMetaType.flags() & QMetaType::PointerToQObject);
QVariant noMetaObjectVariant(noMetaObjectMetaType, nullptr);
QVariant qobjectVariant(qobjectMetaType, nullptr);
// Shouldn't crash
QVERIFY(noMetaObjectVariant != qobjectVariant);
QVERIFY(qobjectVariant != noMetaObjectVariant);
}
QTEST_MAIN(tst_QVariant) QTEST_MAIN(tst_QVariant)
#include "tst_qvariant.moc" #include "tst_qvariant.moc"