From c7443d2e11c6558dc415d611d4d99e9286ddf0c0 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Fri, 4 Dec 2020 10:16:54 +0100 Subject: QPropertyBindingPrivate: Enable QML engine error handling The QPropertyBindingSourceLocation is only useful for C++ bindings; for QML bindings we store the binding location in the V4 function. As the QML binding needs to store some additional information for error handling, we allow that memory to be reused by putting it into a union with an array of byte. Moreover, we use some of the space to store a callback pointer, which gets called when an error occurs during binding evaluation. That callback is only called when we know that the binding actually was set up from the QML engine, in which case a bitflag is set. Task-number: QTBUG-87733 Change-Id: I4387a4bd59d4d1ccfe75756ce81f4608319e0490 Reviewed-by: Ulf Hermann --- src/corelib/kernel/qproperty.cpp | 4 ++++ src/corelib/kernel/qproperty_p.h | 23 +++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'src/corelib/kernel') diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index d2fd572b69..e2c5c7bff3 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -105,6 +105,8 @@ void QPropertyBindingPrivate::markDirtyAndNotifyObservers() dirty = true; if (eagerlyUpdating) { error = QPropertyBindingError(QPropertyBindingError::BindingLoop); + if (isQQmlPropertyBinding) + errorCallBack(this); return; } @@ -129,6 +131,8 @@ bool QPropertyBindingPrivate::evaluateIfDirtyAndReturnTrueIfValueChanged_helper( if (updating) { error = QPropertyBindingError(QPropertyBindingError::BindingLoop); + if (isQQmlPropertyBinding) + errorCallBack(this); return false; } diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index e88547569e..d5feef1008 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -176,6 +176,7 @@ private: bool hasBindingWrapper:1; // used to detect binding loops for eagerly evaluated properties bool eagerlyUpdating:1; + bool isQQmlPropertyBinding:1; const QtPrivate::BindingFunctionVTable *vtable; @@ -190,7 +191,24 @@ private: QUntypedPropertyData *propertyDataPtr = nullptr; - QPropertyBindingSourceLocation location; + /* For bindings set up from C++, location stores where the binding was created in the C++ source + For QQmlPropertyBinding that information does not make sense, and the location in the QML file + is stored somewhere else. To make efficient use of the space, we instead provide a scratch space + for QQmlPropertyBinding (which stores further binding information there). + Anything stored in the union must be trivially destructible. + */ + static_assert(std::is_trivially_destructible_v); + static_assert(std::is_trivially_destructible_v); +protected: + using DeclarativeErrorCallback = void(*)(QPropertyBindingPrivate *); + union { + QPropertyBindingSourceLocation location; + struct { + std::byte declarativeExtraData[sizeof(QPropertyBindingSourceLocation) - sizeof(DeclarativeErrorCallback)]; + DeclarativeErrorCallback errorCallBack; + }; + }; +private: QPropertyBindingError error; QMetaType metaType; @@ -209,9 +227,10 @@ public: size_t dependencyObserverCount = 0; QPropertyBindingPrivate(QMetaType metaType, const QtPrivate::BindingFunctionVTable *vtable, - const QPropertyBindingSourceLocation &location) + const QPropertyBindingSourceLocation &location, bool isQQmlPropertyBinding=false) : hasBindingWrapper(false) , eagerlyUpdating(false) + , isQQmlPropertyBinding(isQQmlPropertyBinding) , vtable(vtable) , inlineDependencyObservers() // Explicit initialization required because of union , location(location) -- cgit v1.2.3