Improve error message when mixing incompatible Qt library versions

The implementation of the check has been moved to a single helper
function. The reason for doing this check in QWidgetPrivate as well,
when it's already done in QObjectPrivate, is to catch incompatible
libraries where QtWidgets is the odd one out, e.g.:

 QtSomeModule 5.15.0 -> QtWidget 5.15.1 -> QtCore 5.15.0

Technically any non-final subclass of QObjectPrivate should have
this check.

Change-Id: Ia74064ad27de7335040a6d6b37d11574f818c878
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Tor Arne Vestbø 2020-02-11 16:31:10 +01:00
parent a2206b74ae
commit bace97aa5b
3 changed files with 26 additions and 18 deletions

View File

@ -184,15 +184,7 @@ QMetaObject *QObjectData::dynamicMetaObject() const
QObjectPrivate::QObjectPrivate(int version)
: threadData(nullptr), currentChildBeingDeleted(nullptr)
{
#ifdef QT_BUILD_INTERNAL
// Don't check the version parameter in internal builds.
// This allows incompatible versions to be loaded, possibly for testing.
Q_UNUSED(version);
#else
if (Q_UNLIKELY(version != QObjectPrivateVersion))
qFatal("Cannot mix incompatible Qt library (version 0x%x) with this library (version 0x%x)",
version, QObjectPrivateVersion);
#endif
checkForIncompatibleLibraryVersion(version);
// QObjectData initialization
q_ptr = nullptr;

View File

@ -322,6 +322,8 @@ public:
virtual ~QObjectPrivate();
void deleteChildren();
inline void checkForIncompatibleLibraryVersion(int version) const;
void setParent_helper(QObject *);
void moveToThread_helper();
void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
@ -396,6 +398,28 @@ public:
Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE);
/*
Catch mixing of incompatible library versions.
Should be called from the constructor of every non-final subclass
of QObjectPrivate, to ensure we catch incompatibilities between
the intermediate base and subclasses thereof.
*/
inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) const
{
#if defined(QT_BUILD_INTERNAL)
// Don't check the version parameter in internal builds.
// This allows incompatible versions to be loaded, possibly for testing.
Q_UNUSED(version);
#else
if (Q_UNLIKELY(version != QObjectPrivateVersion)) {
qFatal("Cannot mix incompatible Qt library (%d.%d.%d) with this library (%d.%d.%d)",
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff,
(QObjectPrivateVersion >> 16) & 0xff, (QObjectPrivateVersion >> 8) & 0xff, QObjectPrivateVersion & 0xff);
}
#endif
}
inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
{
return declarativeData && QAbstractDeclarativeData::isSignalConnected

View File

@ -191,15 +191,7 @@ QWidgetPrivate::QWidgetPrivate(int version)
return;
}
#ifdef QT_BUILD_INTERNAL
// Don't check the version parameter in internal builds.
// This allows incompatible versions to be loaded, possibly for testing.
Q_UNUSED(version);
#else
if (Q_UNLIKELY(version != QObjectPrivateVersion))
qFatal("Cannot mix incompatible Qt library (version 0x%x) with this library (version 0x%x)",
version, QObjectPrivateVersion);
#endif
checkForIncompatibleLibraryVersion(version);
isWidget = true;
memset(high_attributes, 0, sizeof(high_attributes));