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;
|
inline int ownConstructorMethodIndex() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface, int index) const;
|
||||||
QMetaMethodPrivate();
|
QMetaMethodPrivate();
|
||||||
};
|
};
|
||||||
} // unnamed namespace
|
} // unnamed namespace
|
||||||
@ -1786,18 +1787,32 @@ int QMetaMethodPrivate::parameterCount() const
|
|||||||
return data.argc();
|
return data.argc();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
inline void
|
||||||
checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface, uint typeInfo)
|
QMetaMethodPrivate::checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface,
|
||||||
|
int index) const
|
||||||
{
|
{
|
||||||
|
uint typeInfo = parameterTypeInfo(index);
|
||||||
QMetaType mt(iface);
|
QMetaType mt(iface);
|
||||||
if (iface) {
|
if (iface) {
|
||||||
if ((typeInfo & IsUnresolvedType) == 0)
|
if ((typeInfo & IsUnresolvedType) == 0)
|
||||||
Q_ASSERT(mt.id() == int(typeInfo & TypeNameIndexMask));
|
Q_ASSERT(mt.id() == int(typeInfo & TypeNameIndexMask));
|
||||||
Q_ASSERT(mt.name());
|
Q_ASSERT(mt.name());
|
||||||
} else {
|
} else {
|
||||||
// prior to Qt 6.5, the meta object did not record interfaces for void
|
// The iface can only be null for a parameter if that parameter is a
|
||||||
// (obviously only the return type may be void)
|
// const-ref to a forward-declared type. Since primitive types are
|
||||||
Q_ASSERT(typeInfo & IsUnresolvedType || typeInfo == QMetaType::Void);
|
// 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
|
return nullptr; // constructors don't have return types
|
||||||
|
|
||||||
const QtPrivate::QMetaTypeInterface *iface = mobj->d.metaTypes[data.metaTypeOffset()];
|
const QtPrivate::QMetaTypeInterface *iface = mobj->d.metaTypes[data.metaTypeOffset()];
|
||||||
checkMethodMetaTypeConsistency(iface, parameterTypeInfo(-1));
|
checkMethodMetaTypeConsistency(iface, -1);
|
||||||
return iface;
|
return iface;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1831,7 +1846,7 @@ const QtPrivate::QMetaTypeInterface * const *QMetaMethodPrivate::parameterMetaTy
|
|||||||
const auto ifaces = &mobj->d.metaTypes[data.metaTypeOffset() + offset];
|
const auto ifaces = &mobj->d.metaTypes[data.metaTypeOffset() + offset];
|
||||||
|
|
||||||
for (int i = 0; i < parameterCount(); ++i)
|
for (int i = 0; i < parameterCount(); ++i)
|
||||||
checkMethodMetaTypeConsistency(ifaces[i], parameterTypeInfo(i));
|
checkMethodMetaTypeConsistency(ifaces[i], i);
|
||||||
|
|
||||||
return ifaces;
|
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
|
// 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 "forwarddeclared.h"
|
||||||
|
#include "qeasingcurve.h"
|
||||||
|
|
||||||
struct MyForwardDeclaredType { };
|
struct MyForwardDeclaredType { };
|
||||||
static MyForwardDeclaredType t;
|
static MyForwardDeclaredType t;
|
||||||
@ -15,3 +16,18 @@ MyForwardDeclaredType *getForwardDeclaredPointer() noexcept
|
|||||||
{
|
{
|
||||||
return &t;
|
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
|
#ifndef FORWARDDECLARED_H
|
||||||
#define FORWARDDECLARED_H
|
#define FORWARDDECLARED_H
|
||||||
|
|
||||||
|
#include <qglobal.h>
|
||||||
|
|
||||||
struct MyForwardDeclaredType; // and ONLY forward-declared
|
struct MyForwardDeclaredType; // and ONLY forward-declared
|
||||||
|
|
||||||
const MyForwardDeclaredType &getForwardDeclaredType() noexcept;
|
const MyForwardDeclaredType &getForwardDeclaredType() noexcept;
|
||||||
MyForwardDeclaredType *getForwardDeclaredPointer() noexcept;
|
MyForwardDeclaredType *getForwardDeclaredPointer() noexcept;
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QEasingCurve;
|
||||||
|
|
||||||
|
const QEasingCurve &getEasingCurve() noexcept;
|
||||||
|
QEasingCurve *getEasingCurvePointer() noexcept;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FORWARDDECLARED_H
|
#endif // FORWARDDECLARED_H
|
||||||
|
@ -14,6 +14,14 @@ Q_DECLARE_METATYPE(const QMetaObject *)
|
|||||||
|
|
||||||
#include "forwarddeclared.h"
|
#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
|
struct MyStruct
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -489,6 +497,7 @@ public slots:
|
|||||||
qint64 sl14();
|
qint64 sl14();
|
||||||
qlonglong *sl15(qlonglong *);
|
qlonglong *sl15(qlonglong *);
|
||||||
MyForwardDeclaredType *sl16(MyForwardDeclaredType *);
|
MyForwardDeclaredType *sl16(MyForwardDeclaredType *);
|
||||||
|
void sl17(const QEasingCurve &curve);
|
||||||
|
|
||||||
void overloadedSlot();
|
void overloadedSlot();
|
||||||
void overloadedSlot(int, int);
|
void overloadedSlot(int, int);
|
||||||
@ -605,6 +614,8 @@ MyForwardDeclaredType *QtTestObject::sl16(MyForwardDeclaredType *ptr)
|
|||||||
slotResult += "null";
|
slotResult += "null";
|
||||||
return getForwardDeclaredPointer();
|
return getForwardDeclaredPointer();
|
||||||
}
|
}
|
||||||
|
void QtTestObject::sl17(const QEasingCurve &)
|
||||||
|
{ slotResult = "sl17"; }
|
||||||
|
|
||||||
void QtTestObject::overloadedSlot()
|
void QtTestObject::overloadedSlot()
|
||||||
{ slotResult = "overloadedSlot"; }
|
{ slotResult = "overloadedSlot"; }
|
||||||
@ -783,6 +794,11 @@ void tst_QMetaObject::invokeMetaMember()
|
|||||||
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
||||||
QCOMPARE(obj.slotResult, QString("sl16:null"));
|
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
|
// test overloads
|
||||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot"));
|
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot"));
|
||||||
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
||||||
@ -919,6 +935,12 @@ void tst_QMetaObject::invokeQueuedMetaMember()
|
|||||||
qApp->processEvents(QEventLoop::AllEvents);
|
qApp->processEvents(QEventLoop::AllEvents);
|
||||||
QCOMPARE(obj.slotResult, QString("sl15"));
|
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
|
// test overloads
|
||||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection));
|
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection));
|
||||||
qApp->processEvents(QEventLoop::AllEvents);
|
qApp->processEvents(QEventLoop::AllEvents);
|
||||||
@ -1172,6 +1194,11 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember()
|
|||||||
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
||||||
QCOMPARE(obj.slotResult, QString("sl16:null"));
|
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
|
// test overloads
|
||||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection));
|
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection));
|
||||||
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
||||||
@ -2183,4 +2210,7 @@ void tst_QMetaObject::notifySignalsInParentClass()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QMetaObject)
|
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"
|
#include "tst_qmetaobject.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user