summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qmetatype.h
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2022-07-16 08:45:31 -0700
committerThiago Macieira <thiago.macieira@intel.com>2022-07-27 14:51:50 -0700
commit3695b35dfc427f274e55f8e2a6a9876deb52f1b4 (patch)
tree2830ca8dbbf73c1111465fb5bd1b4535af669d86 /src/corelib/kernel/qmetatype.h
parent2d0c31e7d92a3e9df4ce2b9c1d41b94fb12735fc (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.h44
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>());
}