moc: Allow calling ctors on pre-allocated data
When calling a ctor this way, an object is created in the memory pointed to by _a[0] using the other arguments for the ctor. This allows separate allocation and initialization of an object through the metaobject system. Fixes: QTBUG-108879 Change-Id: Ifb154373ee42faab281cfb62aa14334980ec6b7d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>bb10
parent
b291217457
commit
41248f2590
|
|
@ -107,6 +107,7 @@ using namespace Qt::StringLiterals;
|
|||
\value RegisterMethodArgumentMetaType
|
||||
\value BindableProperty
|
||||
\value CustomCall
|
||||
\value ConstructInPlace
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -521,7 +521,8 @@ struct Q_CORE_EXPORT QMetaObject
|
|||
RegisterPropertyMetaType,
|
||||
RegisterMethodArgumentMetaType,
|
||||
BindableProperty,
|
||||
CustomCall
|
||||
CustomCall,
|
||||
ConstructInPlace,
|
||||
};
|
||||
|
||||
int static_metacall(Call, int, void **) const;
|
||||
|
|
|
|||
|
|
@ -1073,33 +1073,45 @@ void Generator::generateStaticMetacall()
|
|||
bool needElse = false;
|
||||
bool isUsed_a = false;
|
||||
|
||||
const auto generateCtorArguments = [&](int ctorindex) {
|
||||
const FunctionDef &f = cdef->constructorList.at(ctorindex);
|
||||
Q_ASSERT(!f.isPrivateSignal); // That would be a strange ctor indeed
|
||||
int offset = 1;
|
||||
|
||||
int argsCount = f.arguments.size();
|
||||
for (int j = 0; j < argsCount; ++j) {
|
||||
const ArgumentDef &a = f.arguments.at(j);
|
||||
if (j)
|
||||
fprintf(out, ",");
|
||||
fprintf(out, "(*reinterpret_cast<%s>(_a[%d]))",
|
||||
a.typeNameForCast.constData(), offset++);
|
||||
}
|
||||
};
|
||||
|
||||
if (!cdef->constructorList.isEmpty()) {
|
||||
fprintf(out, " if (_c == QMetaObject::CreateInstance) {\n");
|
||||
fprintf(out, " switch (_id) {\n");
|
||||
for (int ctorindex = 0; ctorindex < cdef->constructorList.size(); ++ctorindex) {
|
||||
const int ctorend = cdef->constructorList.size();
|
||||
for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) {
|
||||
fprintf(out, " case %d: { %s *_r = new %s(", ctorindex,
|
||||
cdef->classname.constData(), cdef->classname.constData());
|
||||
const FunctionDef &f = cdef->constructorList.at(ctorindex);
|
||||
int offset = 1;
|
||||
|
||||
int argsCount = f.arguments.size();
|
||||
for (int j = 0; j < argsCount; ++j) {
|
||||
const ArgumentDef &a = f.arguments.at(j);
|
||||
if (j)
|
||||
fprintf(out, ",");
|
||||
fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))", a.typeNameForCast.constData(), offset++);
|
||||
}
|
||||
if (f.isPrivateSignal) {
|
||||
if (argsCount > 0)
|
||||
fprintf(out, ", ");
|
||||
fprintf(out, "%s", QByteArray("QPrivateSignal()").constData());
|
||||
}
|
||||
generateCtorArguments(ctorindex);
|
||||
fprintf(out, ");\n");
|
||||
fprintf(out, " if (_a[0]) *reinterpret_cast<%s**>(_a[0]) = _r; } break;\n",
|
||||
(cdef->hasQGadget || cdef->hasQNamespace) ? "void" : "QObject");
|
||||
}
|
||||
fprintf(out, " default: break;\n");
|
||||
fprintf(out, " }\n");
|
||||
fprintf(out, " } else if (_c == QMetaObject::ConstructInPlace) {\n");
|
||||
fprintf(out, " switch (_id) {\n");
|
||||
for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) {
|
||||
fprintf(out, " case %d: { new (_a[0]) %s(",
|
||||
ctorindex, cdef->classname.constData());
|
||||
generateCtorArguments(ctorindex);
|
||||
fprintf(out, "); } break;\n");
|
||||
}
|
||||
fprintf(out, " default: break;\n");
|
||||
fprintf(out, " }\n");
|
||||
fprintf(out, " }");
|
||||
needElse = true;
|
||||
isUsed_a = true;
|
||||
|
|
|
|||
|
|
@ -758,6 +758,7 @@ private slots:
|
|||
void setQPRopertyBinding();
|
||||
void privateQPropertyShim();
|
||||
void readWriteThroughBindable();
|
||||
void invokableCtors();
|
||||
|
||||
signals:
|
||||
void sigWithUnsignedArg(unsigned foo);
|
||||
|
|
@ -4424,6 +4425,42 @@ void tst_Moc::readWriteThroughBindable()
|
|||
}
|
||||
}
|
||||
|
||||
struct WithInvokableCtor
|
||||
{
|
||||
Q_GADGET
|
||||
Q_PROPERTY(int thing MEMBER m_thing CONSTANT FINAL)
|
||||
public:
|
||||
WithInvokableCtor() = default;
|
||||
Q_INVOKABLE WithInvokableCtor(int theThing) : m_thing(theThing) {}
|
||||
|
||||
int m_thing = 10;
|
||||
};
|
||||
|
||||
void tst_Moc::invokableCtors()
|
||||
{
|
||||
const QMetaType metaType = QMetaType::fromType<WithInvokableCtor>();
|
||||
Q_ASSERT(metaType.sizeOf() > 0);
|
||||
const QMetaObject *metaObject = metaType.metaObject();
|
||||
QVERIFY(metaObject);
|
||||
|
||||
QCOMPARE(metaObject->constructorCount(), 1);
|
||||
WithInvokableCtor *result = nullptr;
|
||||
const auto guard = qScopeGuard([&]() { delete result; });
|
||||
int argument = 17;
|
||||
void *a[] = { &result, &argument };
|
||||
metaObject->static_metacall(QMetaObject::CreateInstance, 0, a);
|
||||
QVERIFY(result);
|
||||
QCOMPARE(result->m_thing, 17);
|
||||
|
||||
// Call dtor so that we're left with "uninitialized" memory.
|
||||
WithInvokableCtor result2;
|
||||
result2.~WithInvokableCtor();
|
||||
|
||||
void *b[] = { &result2, &argument };
|
||||
metaObject->static_metacall(QMetaObject::ConstructInPlace, 0, b);
|
||||
QCOMPARE(result2.m_thing, 17);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_Moc)
|
||||
|
||||
// the generated code must compile with QT_NO_KEYWORDS
|
||||
|
|
|
|||
Loading…
Reference in New Issue