QmlCompiler: Coerce values when calling methods

The type of the register may not be the one to be passed to the method.
We cannot rely on the run time internals to coerce the value anymore
since we've moved the type determination out of the generated code.

To make this happen, we need to adjust the storage types of read
registers in the storage generalizer.

Pick-to: 6.9
Fixes: QTBUG-132329
Change-Id: I642027f349f7c05f714ec36ef4e23f9d59b4a8df
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
This commit is contained in:
Ulf Hermann 2024-12-18 14:22:38 +01:00
parent f90bdf9d7a
commit 3d12a83170
7 changed files with 159 additions and 3 deletions

View File

@ -1735,10 +1735,22 @@ QString QQmlJSCodeGenerator::initAndCall(
args = contentPointer(m_state.accumulatorOut(), *outVar);
}
// We may need to convert the arguments to the function call so that they match what the
// function expects. They are passed as void* after all. We try to convert them where they
// are created, but if they are read as different types in multiple places, we can't.
QString argumentPreparation;
for (int i = 0; i < argc; ++i) {
const QQmlJSRegisterContent content = registerType(argv + i);
const QString var = registerVariable(argv + i);
args += u", "_s + contentPointer(content, var);
const QQmlJSRegisterContent read = m_state.readRegister(argv + i);
if (read.contains(content.containedType())) {
args += u", "_s + contentPointer(read, registerVariable(argv + i));
} else {
const QString var = u"arg"_s + QString::number(i);
argumentPreparation +=
u" "_s + read.storedType()->augmentedInternalName() + u' ' + var + u" = "_s
+ conversion(content, read, consumedRegisterVariable(argv + i)) + u";\n";
args += u", "_s + contentPointer(read, var);
}
}
QString initMethod;
@ -1755,6 +1767,7 @@ QString QQmlJSCodeGenerator::initAndCall(
}
return u"const auto doCall = [&]() {\n"_s
+ argumentPreparation
+ u" void *args[] = {" + args + u"};\n"_s
+ u" return aotContext->"_s + callMethodTemplate.arg(u"args"_s).arg(argc) + u";\n"
+ u"};\n"_s

View File

@ -55,6 +55,7 @@ QQmlJSCompilePass::BlocksAndAnnotations QQmlJSStorageGeneralizer::run(Function *
for (auto i = m_annotations.begin(), iEnd = m_annotations.end(); i != iEnd; ++i) {
transformRegister(i->second.changedRegister);
transformRegisters(i->second.typeConversions);
transformRegisters(i->second.readRegisters);
}
return { std::move(m_basicBlocks), std::move(m_annotations) };

View File

@ -24,6 +24,7 @@ set(cpp_sources
sequenceToIterable.h
sequencetypeexample.cpp sequencetypeexample.h
state.h
takenumber.cpp takenumber.h
theme.cpp theme.h
timelinetheme.cpp timelinetheme.h
variantMapLookup.h
@ -275,6 +276,7 @@ set(qml_files
stringLength.qml
stringToByteArray.qml
structuredValueType.qml
takenumber.qml
testlogger.js
text.qml
themerbad.qml

View File

@ -0,0 +1,28 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "takenumber.h"
TakeNumber::TakeNumber(QObject *parent)
: QObject{parent}
{}
void TakeNumber::takeInt(int a)
{
takenInt = a;
}
void TakeNumber::takeNegativeInt(int a)
{
takenNegativeInt = a;
}
void TakeNumber::takeQSizeType(qsizetype a)
{
takenQSizeType = a;
}
void TakeNumber::takeQLongLong(qlonglong a)
{
takenQLongLong = a;
}

View File

@ -0,0 +1,29 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef TAKENUMBER_H
#define TAKENUMBER_H
#include <QtCore/qobject.h>
#include <QtQml/qqml.h>
class TakeNumber : public QObject
{
Q_OBJECT
QML_ELEMENT
public:
explicit TakeNumber(QObject *parent = nullptr);
Q_INVOKABLE void takeInt(int a);
Q_INVOKABLE void takeNegativeInt(int a);
Q_INVOKABLE void takeQSizeType(qsizetype a);
Q_INVOKABLE void takeQLongLong(qlonglong a);
int takenInt = 0;
int takenNegativeInt = 0;
qsizetype takenQSizeType = 0;
qlonglong takenQLongLong = 0;
};
#endif // TAKENUMBER_H

View File

@ -0,0 +1,36 @@
pragma Strict
import QtQml
TakeNumber {
id: foo
function literal0() {
foo.takeInt(0)
foo.takeNegativeInt(0)
foo.takeQSizeType(0)
foo.takeQLongLong(0)
}
function literal56() {
foo.takeInt(56)
foo.takeNegativeInt(-56)
foo.takeQSizeType(56)
foo.takeQLongLong(56)
}
function variable0() {
var a = 0
foo.takeInt(a)
foo.takeNegativeInt(-a)
foo.takeQSizeType(a)
foo.takeQLongLong(a)
}
function variable484() {
var a = 484
foo.takeInt(a)
foo.takeNegativeInt(-a)
foo.takeQSizeType(a)
foo.takeQLongLong(a)
}
}

View File

@ -9,10 +9,11 @@
#include <data/getOptionalLookup.h>
#include <data/listprovider.h>
#include <data/objectwithmethod.h>
#include <data/qmlusing.h>
#include <data/resettable.h>
#include <data/takenumber.h>
#include <data/weathermoduleurl.h>
#include <data/withlength.h>
#include <data/qmlusing.h>
#include <QtQml/private/qqmlengine_p.h>
#include <QtQml/private/qqmlpropertycachecreator_p.h>
@ -239,6 +240,7 @@ private slots:
void stringLength();
void stringToByteArray();
void structuredValueType();
void takeNumbers();
void testIsnan();
void thisObject();
void throwObjectName();
@ -4909,6 +4911,51 @@ void tst_QmlCppCodegen::structuredValueType()
QCOMPARE(o->property("w2").value<WeatherModelUrl>(), w2);
}
void tst_QmlCppCodegen::takeNumbers()
{
QQmlEngine engine;
QQmlComponent c(&engine, QUrl(u"qrc:/qt/qml/TestTypes/takenumber.qml"_s));
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
QScopedPointer<QObject> o(c.create());
QVERIFY(!o.isNull());
TakeNumber *takeNumber = qobject_cast<TakeNumber *>(o.data());
QVERIFY(takeNumber != nullptr);
QCOMPARE(takeNumber->takenInt, 0);
QCOMPARE(takeNumber->takenNegativeInt, 0);
QCOMPARE(takeNumber->takenQSizeType, 0);
QCOMPARE(takeNumber->takenQLongLong, 0);
o->metaObject()->invokeMethod(o.data(), "literal56");
QCOMPARE(takeNumber->takenInt, 56);
QCOMPARE(takeNumber->takenNegativeInt, -56);
QCOMPARE(takeNumber->takenQSizeType, 56);
QCOMPARE(takeNumber->takenQLongLong, 56);
o->metaObject()->invokeMethod(o.data(), "variable0");
QCOMPARE(takeNumber->takenInt, 0);
QCOMPARE(takeNumber->takenNegativeInt, 0);
QCOMPARE(takeNumber->takenQSizeType, 0);
QCOMPARE(takeNumber->takenQLongLong, 0);
o->metaObject()->invokeMethod(o.data(), "variable484");
QCOMPARE(takeNumber->takenInt, 484);
QCOMPARE(takeNumber->takenNegativeInt, -484);
QCOMPARE(takeNumber->takenQSizeType, 484);
QCOMPARE(takeNumber->takenQLongLong, 484);
o->metaObject()->invokeMethod(o.data(), "literal0");
QCOMPARE(takeNumber->takenInt, 0);
QCOMPARE(takeNumber->takenNegativeInt, 0);
QCOMPARE(takeNumber->takenQSizeType, 0);
QCOMPARE(takeNumber->takenQLongLong, 0);
}
void tst_QmlCppCodegen::testIsnan()
{
QQmlEngine engine;