diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 55fe9d3c3f7..ca724dbfac0 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -220,11 +220,15 @@ static void customConstruct(QVariant::Private *d, const void *copy) *d = QVariant::Private(); return; } + if (!(iface->copyCtr && iface->defaultCtr)) { + // QVariant requires type to be copy and default constructible + *d = QVariant::Private(); + qWarning("QVariant: Provided metatype does not support " + "destruction, copy and default construction"); + return; + } if (QVariant::Private::canUseInternalSpace(iface)) { - // QVariant requires type to be copy and default constructible - Q_ASSERT(iface->copyCtr); - Q_ASSERT(iface->defaultCtr); if (copy) iface->copyCtr(iface, &d->data, copy); else @@ -781,6 +785,9 @@ QVariant::QVariant(const QVariant &p) instead to construct variants from the pointer types represented by \c QMetaType::VoidStar, and \c QMetaType::QObjectStar. + If \a type does not support copy and default construction, the variant will + be invalid. + \sa QVariant::fromValue(), QMetaType::Type */ QVariant::QVariant(QMetaType type, const void *copy) : d(type) diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 520515df613..240c25ae480 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -287,6 +287,9 @@ private slots: void moveOperations(); void equalsWithoutMetaObject(); + void constructFromIncompatibleMetaType_data(); + void constructFromIncompatibleMetaType(); + private: void dataStream_data(QDataStream::Version version); void loadQVariantFromDataStream(QDataStream::Version version); @@ -5107,5 +5110,49 @@ void tst_QVariant::equalsWithoutMetaObject() QVERIFY(qobjectVariant != noMetaObjectVariant); } +class NonDefaultConstructible +{ + NonDefaultConstructible(int ) {} +}; + +struct Indestructible +{ + Indestructible() {} + Indestructible(const Indestructible &) {} + Indestructible &operator=(const Indestructible &) { return *this; } +private: + ~Indestructible() {} +}; + +void tst_QVariant::constructFromIncompatibleMetaType_data() +{ + QTest::addColumn("type"); + auto addRow = [](QMetaType meta) { + QTest::newRow(meta.name()) << meta; + }; + addRow(QMetaType::fromType()); + addRow(QMetaType::fromType()); + addRow(QMetaType::fromType()); + addRow(QMetaType::fromType()); +} + +void tst_QVariant::constructFromIncompatibleMetaType() +{ + QFETCH(QMetaType, type); + // in that case, we run into a different condition (size == 0), and do not warn + if (QTest::currentDataTag() != QLatin1String("void")) + QTest::ignoreMessage( + QtWarningMsg, + "QVariant: Provided metatype does not support destruction, copy and default construction"); + QVariant var(type, nullptr); + QVERIFY(!var.isValid()); + QVERIFY(!var.metaType().isValid()); + + QVariant regular(1.0); + QVERIFY(!var.canView(type)); + QVERIFY(!var.canConvert(type)); + QVERIFY(!QVariant(regular).convert(type)); +} + QTEST_MAIN(tst_QVariant) #include "tst_qvariant.moc"