From 3695b35dfc427f274e55f8e2a6a9876deb52f1b4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 16 Jul 2022 08:45:31 -0700 Subject: 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: :1:56: required from here qmetatype.h:1131:45: error: static assertion failed: Meta Types must be fully defined :1:50: required from here qmetatype.h:1132:29: error: static assertion failed: Meta Types cannot be non-const references or rvalue references. :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 --- src/corelib/kernel/qmetatype.h | 44 +++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) (limited to 'src/corelib/kernel/qmetatype.h') 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 struct MetatypeDecay { using type = T; }; template struct MetatypeDecay { using type = T; }; + template struct IsPointerDeclaredOpaque : + std::disjunction, + std::is_function>> + {}; + template <> struct IsPointerDeclaredOpaque : std::true_type {}; + template <> struct IsPointerDeclaredOpaque : 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 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(nullptr))) == sizeof(yes_type) }; }; @@ -1147,6 +1156,22 @@ namespace QtPrivate }; #endif + template static constexpr bool checkTypeIsSuitableForMetaType() + { + using T = typename MetatypeDecay::type; + static_assert(is_complete::value || std::is_void_v, + "Meta Types must be fully defined"); + static_assert(!std::is_reference_v, + "Meta Types cannot be non-const references or rvalue references."); + if constexpr (std::is_pointer_v && !IsPointerDeclaredOpaque::value) { + using Pointed = std::remove_pointer_t; + static_assert(is_complete::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 #define Q_DECLARE_OPAQUE_POINTER(POINTER) \ QT_BEGIN_NAMESPACE namespace QtPrivate { \ - template <> \ - struct IsPointerToTypeDerivedFromQObject \ - { \ - enum { Value = false }; \ - }; \ + template <> struct IsPointerDeclaredOpaque \ + : std::true_type {}; \ } QT_END_NAMESPACE \ /**/ @@ -1460,6 +1482,7 @@ struct QMetaTypeIdQObject struct QMetaTypeId< TYPE > \ { \ enum { Defined = 1 }; \ + static_assert(QtPrivate::checkTypeIsSuitableForMetaType()); \ static int qt_metatype_id() \ { \ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ @@ -2511,6 +2534,7 @@ struct TypeAndForceComplete template constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType() { + // don't check the type is suitable here using Ty = typename MetatypeDecay::type; return &QMetaTypeInterfaceWrapper::metaType; } @@ -2523,13 +2547,18 @@ constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType() using Ty = typename MetatypeDecay::type; using Tz = qRemovePointerLike_t; - if constexpr (ForceComplete::value) { + if constexpr (std::is_void_v) { + // early out to avoid expanding the rest of the templates + return &QMetaTypeInterfaceWrapper::metaType; + } else if constexpr (ForceComplete::value) { + checkTypeIsSuitableForMetaType(); return &QMetaTypeInterfaceWrapper::metaType; } else if constexpr (std::is_reference_v) { return nullptr; } else if constexpr (!is_complete::value) { return nullptr; } else { + // don't check the type is suitable here return &QMetaTypeInterfaceWrapper::metaType; } } @@ -2539,6 +2568,7 @@ constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType() template constexpr QMetaType QMetaType::fromType() { + QtPrivate::checkTypeIsSuitableForMetaType(); return QMetaType(QtPrivate::qMetaTypeInterfaceForType()); } -- cgit v1.2.3