diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 130b30481d..780ae10396 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -75,8 +75,11 @@ struct QMetaTypeCustomRegistry // index of first empty (unregistered) type in registry, if any. int firstEmpty = 0; - int registerCustomType(const QtPrivate::QMetaTypeInterface *ti) + int registerCustomType(const QtPrivate::QMetaTypeInterface *cti) { + // we got here because cti->typeId is 0, so this is a custom meta type + // (not read-only) + auto ti = const_cast(cti); { QWriteLocker l(&lock); if (int id = ti->typeId.loadRelaxed()) @@ -789,9 +792,11 @@ bool QMetaType::isOrdered() const void QMetaType::unregisterMetaType(QMetaType type) { if (type.d_ptr && type.d_ptr->typeId.loadRelaxed() >= QMetaType::User) { + // this is a custom meta type (not read-only) + auto d = const_cast(type.d_ptr); if (auto reg = customTypeRegistry()) - reg->unregisterDynamicType(type.d_ptr->typeId.loadRelaxed()); - type.d_ptr->typeId.storeRelease(0); + reg->unregisterDynamicType(d->typeId.loadRelaxed()); + d->typeId.storeRelease(0); } } diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index a2639c1dfa..82d799ac41 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -225,6 +225,20 @@ struct QMetaObject; namespace QtPrivate { +class QMetaTypeInterface; + +// MSVC is the only supported compiler that includes the type of a variable in +// its mangled form, so it's not binary-compatible to drop the const in +// QMetaTypeInterfaceWrapper::metaType for it, which means we must keep the +// mutable field until Qt 7. +#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) || !defined(Q_CC_MSVC) +# define QMTI_MUTABLE +using NonConstMetaTypeInterface = QMetaTypeInterface; +#else +# define QMTI_MUTABLE mutable +using NonConstMetaTypeInterface = const QMetaTypeInterface; +#endif + class QMetaTypeInterface { public: @@ -232,7 +246,7 @@ public: ushort alignment; uint size; uint flags; - mutable QBasicAtomicInt typeId; + QMTI_MUTABLE QBasicAtomicInt typeId; using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *); MetaObjectFn metaObjectFn; @@ -261,6 +275,7 @@ public: using LegacyRegisterOp = void (*)(); LegacyRegisterOp legacyRegisterOp; }; +#undef QMTI_MUTABLE /*! This template is used for implicit conversion from type From to type To. @@ -2326,7 +2341,13 @@ public: template struct QMetaTypeInterfaceWrapper { - static inline constexpr const QMetaTypeInterface metaType = { + // if the type ID for T is known at compile-time, then we can declare + // the QMetaTypeInterface object const; otherwise, we declare it as + // non-const and the .typeId is updated by QMetaType::idHelper(). + static constexpr bool IsConstMetaTypeInterface = !!BuiltinMetaType::value; + using InterfaceType = std::conditional_t; + + static inline InterfaceType metaType = { /*.revision=*/ 0, /*.alignment=*/ alignof(T), /*.size=*/ sizeof(T),