diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index a87b98b12d3..95557bf0212 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -2050,8 +2050,17 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType, // handle QObject conversion if ((fromType.flags() & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) { QObject *fromObject = *static_cast(from); - *static_cast(to) = fromObject ? fromObject->metaObject()->cast(fromObject) : nullptr; - return true; + // use dynamic metatype of from if possible + if (fromObject && fromObject->metaObject()->inherits(toType.metaObject())) { + *static_cast(to) = toType.metaObject()->cast(fromObject); + return true; + } else if (!fromObject) { + // if fromObject is null, use static fromType to check if conversion works + *static_cast(to) = nullptr; + return fromType.metaObject()->inherits(toType.metaObject()); + } else { + return false; + } } #endif diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 48d68db2988..8796589df3e 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -221,6 +221,7 @@ private slots: void compareCustomTypes() const; void timeToDateTime() const; void copyingUserTypes() const; + void valueClassHierarchyConversion() const; void convertBoolToByteArray() const; void convertBoolToByteArray_data() const; void convertByteArrayToBool() const; @@ -2894,6 +2895,43 @@ void tst_QVariant::copyingUserTypes() const QCOMPARE(copiedType.myValue, 42); } + +struct NonQObjectBase {}; +struct NonQObjectDerived : NonQObjectBase {}; + +void tst_QVariant::valueClassHierarchyConversion() const +{ + + { + // QVariant allows downcasting + QScopedPointer derived {new CustomQObjectDerived}; + QVariant var = QVariant::fromValue(derived.get()); + CustomQObject *object = var.value(); + QVERIFY(object); + } + { + // QVariant supports upcasting to the correct dynamic type for QObjects + QScopedPointer derived {new CustomQObjectDerived}; + QVariant var = QVariant::fromValue(derived.get()); + CustomQObjectDerived *object = var.value(); + QVERIFY(object); + } + { + // QVariant forbids unsafe upcasting + QScopedPointer base {new CustomQObject}; + QVariant var = QVariant::fromValue(base.get()); + CustomQObjectDerived *object = var.value(); + QVERIFY(!object); + } + { + // QVariant does not support upcastingfor non-QObjects + QScopedPointer derived {new NonQObjectDerived}; + QVariant var = QVariant::fromValue(derived.get()); + NonQObjectDerived *object = var.value(); + QVERIFY(!object); + } +} + void tst_QVariant::convertBoolToByteArray() const { QFETCH(QByteArray, input);