QMetaObject: fix the consistency check for forward-declared builtins
For those, moc does know their type ID, and yet they may be still forward-declared in the C++ side, so the meta object may have recorded a null pointer in the metatype array. Fixes: QTBUG-105832 Change-Id: Ic6547f8247454b47baa8fffd170dae07c0813dc7 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
e1cf523354
commit
7deb49d886
@ -192,6 +192,7 @@ public:
|
||||
inline int ownConstructorMethodIndex() const;
|
||||
|
||||
private:
|
||||
void checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface, int index) const;
|
||||
QMetaMethodPrivate();
|
||||
};
|
||||
} // unnamed namespace
|
||||
@ -1786,18 +1787,32 @@ int QMetaMethodPrivate::parameterCount() const
|
||||
return data.argc();
|
||||
}
|
||||
|
||||
static inline void
|
||||
checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface, uint typeInfo)
|
||||
inline void
|
||||
QMetaMethodPrivate::checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface,
|
||||
int index) const
|
||||
{
|
||||
uint typeInfo = parameterTypeInfo(index);
|
||||
QMetaType mt(iface);
|
||||
if (iface) {
|
||||
if ((typeInfo & IsUnresolvedType) == 0)
|
||||
Q_ASSERT(mt.id() == int(typeInfo & TypeNameIndexMask));
|
||||
Q_ASSERT(mt.name());
|
||||
} else {
|
||||
// prior to Qt 6.5, the meta object did not record interfaces for void
|
||||
// (obviously only the return type may be void)
|
||||
Q_ASSERT(typeInfo & IsUnresolvedType || typeInfo == QMetaType::Void);
|
||||
// The iface can only be null for a parameter if that parameter is a
|
||||
// const-ref to a forward-declared type. Since primitive types are
|
||||
// never incomplete, we can assert it's not one of them.
|
||||
|
||||
#define ASSERT_NOT_PRIMITIVE_TYPE(TYPE, METATYPEID, NAME) \
|
||||
Q_ASSERT(typeInfo != QMetaType::TYPE);
|
||||
QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(ASSERT_NOT_PRIMITIVE_TYPE)
|
||||
#undef ASSERT_NOT_PRIMITIVE_TYPE
|
||||
Q_ASSERT(typeInfo != QMetaType::QObjectStar);
|
||||
|
||||
// Prior to Qt 6.4 we failed to record void and void*
|
||||
if (priv(mobj->d.data)->revision >= 11) {
|
||||
Q_ASSERT(typeInfo != QMetaType::Void);
|
||||
Q_ASSERT(typeInfo != QMetaType::VoidStar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1820,7 +1835,7 @@ const QtPrivate::QMetaTypeInterface *QMetaMethodPrivate::returnMetaTypeInterface
|
||||
return nullptr; // constructors don't have return types
|
||||
|
||||
const QtPrivate::QMetaTypeInterface *iface = mobj->d.metaTypes[data.metaTypeOffset()];
|
||||
checkMethodMetaTypeConsistency(iface, parameterTypeInfo(-1));
|
||||
checkMethodMetaTypeConsistency(iface, -1);
|
||||
return iface;
|
||||
}
|
||||
|
||||
@ -1831,7 +1846,7 @@ const QtPrivate::QMetaTypeInterface * const *QMetaMethodPrivate::parameterMetaTy
|
||||
const auto ifaces = &mobj->d.metaTypes[data.metaTypeOffset() + offset];
|
||||
|
||||
for (int i = 0; i < parameterCount(); ++i)
|
||||
checkMethodMetaTypeConsistency(ifaces[i], parameterTypeInfo(i));
|
||||
checkMethodMetaTypeConsistency(ifaces[i], i);
|
||||
|
||||
return ifaces;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "forwarddeclared.h"
|
||||
#include "qeasingcurve.h"
|
||||
|
||||
struct MyForwardDeclaredType { };
|
||||
static MyForwardDeclaredType t;
|
||||
@ -15,3 +16,18 @@ MyForwardDeclaredType *getForwardDeclaredPointer() noexcept
|
||||
{
|
||||
return &t;
|
||||
}
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
const QEasingCurve &getEasingCurve() noexcept
|
||||
{
|
||||
return *getEasingCurvePointer();
|
||||
}
|
||||
|
||||
QEasingCurve *getEasingCurvePointer() noexcept
|
||||
{
|
||||
static QEasingCurve curve;
|
||||
return &curve;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -4,9 +4,18 @@
|
||||
#ifndef FORWARDDECLARED_H
|
||||
#define FORWARDDECLARED_H
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
struct MyForwardDeclaredType; // and ONLY forward-declared
|
||||
|
||||
const MyForwardDeclaredType &getForwardDeclaredType() noexcept;
|
||||
MyForwardDeclaredType *getForwardDeclaredPointer() noexcept;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QEasingCurve;
|
||||
|
||||
const QEasingCurve &getEasingCurve() noexcept;
|
||||
QEasingCurve *getEasingCurvePointer() noexcept;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // FORWARDDECLARED_H
|
||||
|
@ -14,6 +14,14 @@ Q_DECLARE_METATYPE(const QMetaObject *)
|
||||
|
||||
#include "forwarddeclared.h"
|
||||
|
||||
#ifdef QEASINGCURVE_H
|
||||
# error "Please make sure qeasingcurve.h is not #include'd here! " \
|
||||
"We need QEasingCurve to be only forward-declared."
|
||||
#endif
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QEasingCurve;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
struct MyStruct
|
||||
{
|
||||
int i;
|
||||
@ -489,6 +497,7 @@ public slots:
|
||||
qint64 sl14();
|
||||
qlonglong *sl15(qlonglong *);
|
||||
MyForwardDeclaredType *sl16(MyForwardDeclaredType *);
|
||||
void sl17(const QEasingCurve &curve);
|
||||
|
||||
void overloadedSlot();
|
||||
void overloadedSlot(int, int);
|
||||
@ -605,6 +614,8 @@ MyForwardDeclaredType *QtTestObject::sl16(MyForwardDeclaredType *ptr)
|
||||
slotResult += "null";
|
||||
return getForwardDeclaredPointer();
|
||||
}
|
||||
void QtTestObject::sl17(const QEasingCurve &)
|
||||
{ slotResult = "sl17"; }
|
||||
|
||||
void QtTestObject::overloadedSlot()
|
||||
{ slotResult = "overloadedSlot"; }
|
||||
@ -783,6 +794,11 @@ void tst_QMetaObject::invokeMetaMember()
|
||||
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
||||
QCOMPARE(obj.slotResult, QString("sl16:null"));
|
||||
|
||||
// forward-declared builtin
|
||||
obj.slotResult.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Q_ARG(QEasingCurve, getEasingCurve())));
|
||||
QCOMPARE(obj.slotResult, "sl17");
|
||||
|
||||
// test overloads
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot"));
|
||||
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
||||
@ -919,6 +935,12 @@ void tst_QMetaObject::invokeQueuedMetaMember()
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
QCOMPARE(obj.slotResult, QString("sl15"));
|
||||
|
||||
// forward-declared builtin
|
||||
obj.slotResult.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::QueuedConnection, Q_ARG(QEasingCurve, getEasingCurve())));
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
QCOMPARE(obj.slotResult, "sl17");
|
||||
|
||||
// test overloads
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection));
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
@ -1172,6 +1194,11 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember()
|
||||
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
||||
QCOMPARE(obj.slotResult, QString("sl16:null"));
|
||||
|
||||
// forward-declared builtin
|
||||
obj.slotResult.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::BlockingQueuedConnection, Q_ARG(QEasingCurve, getEasingCurve())));
|
||||
QCOMPARE(obj.slotResult, "sl17");
|
||||
|
||||
// test overloads
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection));
|
||||
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
||||
@ -2183,4 +2210,7 @@ void tst_QMetaObject::notifySignalsInParentClass()
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QMetaObject)
|
||||
|
||||
static_assert(!QtPrivate::is_complete<QEasingCurve, void>::value,
|
||||
"QEasingCurve must only be forward-declared at this point");
|
||||
#include "tst_qmetaobject.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user