diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2022-07-16 08:45:31 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2022-07-27 14:51:50 -0700 |
commit | 3695b35dfc427f274e55f8e2a6a9876deb52f1b4 (patch) | |
tree | 2830ca8dbbf73c1111465fb5bd1b4535af669d86 /src/corelib/kernel/qmetatype.h | |
parent | 2d0c31e7d92a3e9df4ce2b9c1d41b94fb12735fc (diff) |
QMetaType: re-fix them for pointers
Instead of placing the error deep into IsPointerToTypeDerivedFromQObject
with a message about weird the sizes, move them closer to the front-end
so we get a proper error message like:
<stdin>:1:56: required from here
qmetatype.h:1131:45: error: static assertion failed: Meta Types must be fully defined
<stdin>:1:50: required from here
qmetatype.h:1132:29: error: static assertion failed: Meta Types cannot be non-const references or rvalue references.
<stdin>:1:56: required from here
qmetatype.h:1136:55: error: static assertion failed: Pointer Meta Types must either point to fully-defined types or be declared with Q_DECLARE_OPAQUE_POINTER(T *)
This does not apply to the meta type list stored in a meta object, as
meta method parameters may be opaque pointers or even forward-declared
only.
Change-Id: I36b24183fbd041179f2ffffd17025f10f38e04e6
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib/kernel/qmetatype.h')
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 44 |
1 files changed, 37 insertions, 7 deletions
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index ae13590658..77bb68e218 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -849,6 +849,16 @@ namespace QtPrivate template <typename T> struct MetatypeDecay<const T> { using type = T; }; template <typename T> struct MetatypeDecay<const T &> { using type = T; }; + template <typename T> struct IsPointerDeclaredOpaque : + std::disjunction<std::is_member_pointer<T>, + std::is_function<std::remove_pointer_t<T>>> + {}; + template <> struct IsPointerDeclaredOpaque<void *> : std::true_type {}; + template <> struct IsPointerDeclaredOpaque<const void *> : std::true_type {}; + + // Note: this does not check that T = U* isn't pointing to a + // forward-declared type. You may want to combine with + // checkTypeIsSuitableForMetaType(). template<typename T> struct IsPointerToTypeDerivedFromQObject { @@ -883,7 +893,6 @@ namespace QtPrivate static yes_type checkType(const QObject* ); #endif static no_type checkType(...); - static_assert(sizeof(T), "Type argument of Q_PROPERTY or Q_DECLARE_METATYPE(T*) must be fully defined"); enum { Value = sizeof(checkType(static_cast<T*>(nullptr))) == sizeof(yes_type) }; }; @@ -1147,6 +1156,22 @@ namespace QtPrivate }; #endif + template <typename X> static constexpr bool checkTypeIsSuitableForMetaType() + { + using T = typename MetatypeDecay<X>::type; + static_assert(is_complete<T, void>::value || std::is_void_v<T>, + "Meta Types must be fully defined"); + static_assert(!std::is_reference_v<T>, + "Meta Types cannot be non-const references or rvalue references."); + if constexpr (std::is_pointer_v<T> && !IsPointerDeclaredOpaque<T>::value) { + using Pointed = std::remove_pointer_t<T>; + static_assert(is_complete<Pointed, void>::value, + "Pointer Meta Types must either point to fully-defined types " + "or be declared with Q_DECLARE_OPAQUE_POINTER(T *)"); + } + return true; + } + Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type); } // namespace QtPrivate @@ -1444,11 +1469,8 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration> #define Q_DECLARE_OPAQUE_POINTER(POINTER) \ QT_BEGIN_NAMESPACE namespace QtPrivate { \ - template <> \ - struct IsPointerToTypeDerivedFromQObject<POINTER > \ - { \ - enum { Value = false }; \ - }; \ + template <> struct IsPointerDeclaredOpaque<POINTER> \ + : std::true_type {}; \ } QT_END_NAMESPACE \ /**/ @@ -1460,6 +1482,7 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration> struct QMetaTypeId< TYPE > \ { \ enum { Defined = 1 }; \ + static_assert(QtPrivate::checkTypeIsSuitableForMetaType<TYPE>()); \ static int qt_metatype_id() \ { \ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ @@ -2511,6 +2534,7 @@ struct TypeAndForceComplete template<typename T> constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType() { + // don't check the type is suitable here using Ty = typename MetatypeDecay<T>::type; return &QMetaTypeInterfaceWrapper<Ty>::metaType; } @@ -2523,13 +2547,18 @@ constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType() using Ty = typename MetatypeDecay<T>::type; using Tz = qRemovePointerLike_t<Ty>; - if constexpr (ForceComplete::value) { + if constexpr (std::is_void_v<Ty>) { + // early out to avoid expanding the rest of the templates + return &QMetaTypeInterfaceWrapper<void>::metaType; + } else if constexpr (ForceComplete::value) { + checkTypeIsSuitableForMetaType<Ty>(); return &QMetaTypeInterfaceWrapper<Ty>::metaType; } else if constexpr (std::is_reference_v<Tz>) { return nullptr; } else if constexpr (!is_complete<Tz, Unique>::value) { return nullptr; } else { + // don't check the type is suitable here return &QMetaTypeInterfaceWrapper<Ty>::metaType; } } @@ -2539,6 +2568,7 @@ constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType() template<typename T> constexpr QMetaType QMetaType::fromType() { + QtPrivate::checkTypeIsSuitableForMetaType<T>(); return QMetaType(QtPrivate::qMetaTypeInterfaceForType<T>()); } |