summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qmetatype.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qmetatype.h')
-rw-r--r--src/corelib/kernel/qmetatype.h673
1 files changed, 461 insertions, 212 deletions
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index bdea0b2879..e3ef1474da 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
-** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2018 Intel Corporation.
+// Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMETATYPE_H
#define QMETATYPE_H
@@ -46,13 +10,14 @@
#include <QtCore/qatomic.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qcompare.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qrefcount.h>
#include <QtCore/qdatastream.h>
+#include <QtCore/qfloat16.h>
+#include <QtCore/qhashfunctions.h>
#include <QtCore/qiterable.h>
#ifndef QT_NO_QOBJECT
#include <QtCore/qobjectdefs.h>
#endif
+#include <QtCore/qscopeguard.h>
#include <array>
#include <new>
@@ -60,6 +25,8 @@
#include <list>
#include <map>
#include <functional>
+#include <optional>
+#include <QtCore/q20type_traits.h>
#ifdef Bool
#error qmetatype.h must be included before any header file that defines Bool
@@ -77,8 +44,7 @@ template <typename T>
inline constexpr int qMetaTypeId();
// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType)
-#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
- F(Void, 43, void) \
+#define QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F)\
F(Bool, 1, bool) \
F(Int, 2, int) \
F(UInt, 3, uint) \
@@ -98,7 +64,11 @@ inline constexpr int qMetaTypeId();
F(Nullptr, 51, std::nullptr_t) \
F(QCborSimpleType, 52, QCborSimpleType) \
-#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\
+#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F) \
+ QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F) \
+ F(Void, 43, void) \
+
+#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F) \
F(VoidStar, 31, void*) \
#if QT_CONFIG(easingcurve)
@@ -122,6 +92,12 @@ inline constexpr int qMetaTypeId();
#else
# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F)
#endif
+#ifndef QT_NO_VARIANT
+# define QT_FOR_EACH_STATIC_QVARIANT(F) \
+ F(QVariant, 41, QVariant)
+#else
+# define QT_FOR_EACH_STATIC_QVARIANT(F)
+#endif
#define QT_FOR_EACH_STATIC_CORE_CLASS(F)\
F(QChar, 7, QChar) \
@@ -143,7 +119,7 @@ inline constexpr int qMetaTypeId();
F(QPointF, 26, QPointF) \
QT_FOR_EACH_STATIC_EASINGCURVE(F) \
F(QUuid, 30, QUuid) \
- F(QVariant, 41, QVariant) \
+ QT_FOR_EACH_STATIC_QVARIANT(F) \
QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \
F(QJsonValue, 45, QJsonValue) \
F(QJsonObject, 46, QJsonObject) \
@@ -152,18 +128,26 @@ inline constexpr int qMetaTypeId();
F(QCborValue, 53, QCborValue) \
F(QCborArray, 54, QCborArray) \
F(QCborMap, 55, QCborMap) \
+ F(Float16, 63, qfloat16) \
QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)
#define QT_FOR_EACH_STATIC_CORE_POINTER(F)\
F(QObjectStar, 39, QObject*)
-#define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
+#ifndef QT_NO_VARIANT
+# define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
F(QVariantMap, 8, QVariantMap) \
F(QVariantList, 9, QVariantList) \
F(QVariantHash, 28, QVariantHash) \
F(QVariantPair, 58, QVariantPair) \
F(QByteArrayList, 49, QByteArrayList) \
F(QStringList, 11, QStringList) \
+ /**/
+#else
+# define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
+ F(QByteArrayList, 49, QByteArrayList) \
+ F(QStringList, 11, QStringList)
+#endif
#if QT_CONFIG(shortcut)
#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)\
@@ -217,12 +201,20 @@ inline constexpr int qMetaTypeId();
F(UInt, -1, uint, "quint32") \
F(LongLong, -1, qlonglong, "qint64") \
F(ULongLong, -1, qulonglong, "quint64") \
+ F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
+ F(QStringList, -1, QStringList, "QList<QString>") \
+ QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F)
+
+#ifndef QT_NO_VARIANT
+#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F) \
F(QVariantList, -1, QVariantList, "QList<QVariant>") \
F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \
F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \
F(QVariantPair, -1, QVariantPair, "QPair<QVariant,QVariant>") \
- F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
- F(QStringList, -1, QStringList, "QList<QString>") \
+ /**/
+#else
+#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F)
+#endif
#define QT_FOR_EACH_STATIC_TYPE(F)\
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
@@ -258,17 +250,38 @@ 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:
- ushort revision; // 0 in Qt 6.0. Can increase if new field are added
+
+ /* Revision: Can increase if new field are added, or if semantics changes
+ 0: Initial Revision
+ 1: the meaning of the NeedsDestruction flag changed
+ */
+ static inline constexpr ushort CurrentRevision = 1;
+
+ ushort revision;
ushort alignment;
uint size;
uint flags;
- mutable QBasicAtomicInt typeId;
+ QMTI_MUTABLE QBasicAtomicInt typeId;
using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
- const MetaObjectFn metaObjectFn;
+ MetaObjectFn metaObjectFn;
const char *name;
@@ -294,6 +307,7 @@ public:
using LegacyRegisterOp = void (*)();
LegacyRegisterOp legacyRegisterOp;
};
+#undef QMTI_MUTABLE
/*!
This template is used for implicit conversion from type From to type To.
@@ -326,14 +340,14 @@ To convertImplicit(const From& from)
class Q_CORE_EXPORT QMetaType {
public:
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
// The code that actually gets compiled.
enum Type {
// these are merged with QVariant
QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)
FirstCoreType = Bool,
- LastCoreType = QVariantPair,
+ LastCoreType = Float16,
FirstGuiType = QFont,
LastGuiType = QColorSpace,
FirstWidgetsType = QSizePolicy,
@@ -362,9 +376,10 @@ public:
QByteArrayList = 49, QObjectStar = 39, SChar = 40,
Void = 43,
Nullptr = 51,
- QVariantMap = 8, QVariantList = 9, QVariantHash = 28,
+ QVariantMap = 8, QVariantList = 9, QVariantHash = 28, QVariantPair = 58,
QCborSimpleType = 52, QCborValue = 53, QCborArray = 54, QCborMap = 55,
Char16 = 56, Char32 = 57,
+ Int128 = 59, UInt128 = 60, Float128 = 61, BFloat16 = 62, Float16 = 63,
// Gui types
QFont = 0x1000, QPixmap = 0x1001, QBrush = 0x1002, QColor = 0x1003, QPalette = 0x1004,
@@ -375,8 +390,8 @@ public:
// Widget types
QSizePolicy = 0x2000,
- LastCoreType = Char32,
- LastGuiType = QColorSpace,
+
+ // Start-point for client-code types:
User = 65536
};
#endif
@@ -399,6 +414,9 @@ public:
IsPointer = 0x800,
IsQmlList =0x1000, // used in the QML engine to recognize QQmlListProperty<T> and list<T>
IsConst = 0x2000,
+ // since 6.5:
+ NeedsCopyConstruction = 0x4000,
+ NeedsMoveConstruction = 0x8000,
};
Q_DECLARE_FLAGS(TypeFlags, TypeFlag)
@@ -416,7 +434,7 @@ public:
{ return QMetaType(type).name(); }
QT_DEPRECATED_VERSION_6_0
static int sizeOf(int type)
- { return QMetaType(type).sizeOf(); }
+ { return int(QMetaType(type).sizeOf()); }
QT_DEPRECATED_VERSION_6_0
static TypeFlags typeFlags(int type)
{ return QMetaType(type).flags(); }
@@ -444,15 +462,22 @@ public:
bool isValid() const;
bool isRegistered() const;
- int id() const
+ void registerType() const
{
- if (d_ptr) {
- if (int id = d_ptr->typeId.loadRelaxed())
- return id;
- return idHelper();
- }
- return 0;
- };
+ // "register" is a reserved keyword
+ registerHelper();
+ }
+#if QT_CORE_REMOVED_SINCE(6, 1) || defined(Q_QDOC)
+ int id() const;
+#else
+ // ### Qt 7: Remove traces of out of line version
+ // unused int parameter is used to avoid ODR violation
+ int id(int = 0) const
+ {
+ // keep in sync with the version in removed_api.cpp
+ return registerHelper();
+ }
+#endif
constexpr qsizetype sizeOf() const;
constexpr qsizetype alignOf() const;
constexpr TypeFlags flags() const;
@@ -466,6 +491,10 @@ public:
QPartialOrdering compare(const void *lhs, const void *rhs) const;
bool equals(const void *lhs, const void *rhs) const;
+ bool isDefaultConstructible() const noexcept { return d_ptr && isDefaultConstructible(d_ptr); }
+ bool isCopyConstructible() const noexcept { return d_ptr && isCopyConstructible(d_ptr); }
+ bool isMoveConstructible() const noexcept { return d_ptr && isMoveConstructible(d_ptr); }
+ bool isDestructible() const noexcept { return d_ptr && isDestructible(d_ptr); }
bool isEqualityComparable() const;
bool isOrdered() const;
@@ -484,6 +513,8 @@ public:
#endif
#endif
+ QMetaType underlyingType() const;
+
template<typename T>
constexpr static QMetaType fromType();
static QMetaType fromName(QByteArrayView name);
@@ -501,9 +532,10 @@ public:
}
friend bool operator!=(QMetaType a, QMetaType b) { return !(a == b); }
-public:
-
#ifndef QT_NO_DEBUG_STREAM
+private:
+ friend Q_CORE_EXPORT QDebug operator<<(QDebug d, QMetaType m);
+public:
bool debugStream(QDebug& dbg, const void *rhs);
bool hasRegisteredDebugStreamOperator() const;
@@ -534,21 +566,6 @@ public:
return registerConverter<From, To>(QtPrivate::convertImplicit<From, To>);
}
-#ifdef Q_CLANG_QDOC
- template<typename MemberFunction, int>
- static bool registerConverter(MemberFunction function);
- template<typename MemberFunctionOk, char>
- static bool registerConverter(MemberFunctionOk function);
- template<typename UnaryFunction>
- static bool registerConverter(UnaryFunction function);
-
- template<typename MemberFunction, int>
- static bool registerMutableView(MemberFunction function);
- template<typename MemberFunctionOk, char>
- static bool registerMutableView(MemberFunctionOk function);
- template<typename UnaryFunction>
- static bool registerMutableView(UnaryFunction function);
-#else
// member function as in "QString QFont::toString() const"
template<typename From, typename To>
static bool registerConverter(To(From::*function)() const)
@@ -564,7 +581,7 @@ public:
*t = (f->*function)();
return true;
};
- return registerConverterFunction(converter, fromType, toType);
+ return registerConverterImpl<From, To>(converter, fromType, toType);
}
// member function
@@ -582,7 +599,7 @@ public:
*t = (f->*function)();
return true;
};
- return registerMutableViewFunction(view, fromType, toType);
+ return registerMutableViewImpl<From, To>(view, fromType, toType);
}
// member function as in "double QString::toDouble(bool *ok = nullptr) const"
@@ -603,7 +620,7 @@ public:
*t = To();
return result;
};
- return registerConverterFunction(converter, fromType, toType);
+ return registerConverterImpl<From, To>(converter, fromType, toType);
}
// functor or function pointer
@@ -615,13 +632,20 @@ public:
const QMetaType fromType = QMetaType::fromType<From>();
const QMetaType toType = QMetaType::fromType<To>();
- auto converter = [function](const void *from, void *to) -> bool {
+ auto converter = [function = std::move(function)](const void *from, void *to) -> bool {
const From *f = static_cast<const From *>(from);
To *t = static_cast<To *>(to);
- *t = function(*f);
+ auto &&r = function(*f);
+ if constexpr (std::is_same_v<q20::remove_cvref_t<decltype(r)>, std::optional<To>>) {
+ if (!r)
+ return false;
+ *t = *std::forward<decltype(r)>(r);
+ } else {
+ *t = std::forward<decltype(r)>(r);
+ }
return true;
};
- return registerConverterFunction(converter, fromType, toType);
+ return registerConverterImpl<From, To>(std::move(converter), fromType, toType);
}
// functor or function pointer
@@ -633,15 +657,42 @@ public:
const QMetaType fromType = QMetaType::fromType<From>();
const QMetaType toType = QMetaType::fromType<To>();
- auto view = [function](void *from, void *to) -> bool {
+ auto view = [function = std::move(function)](void *from, void *to) -> bool {
From *f = static_cast<From *>(from);
To *t = static_cast<To *>(to);
*t = function(*f);
return true;
};
- return registerMutableViewFunction(view, fromType, toType);
+ return registerMutableViewImpl<From, To>(std::move(view), fromType, toType);
}
-#endif
+
+private:
+ template<typename From, typename To>
+ static bool registerConverterImpl(ConverterFunction converter, QMetaType fromType, QMetaType toType)
+ {
+ if (registerConverterFunction(std::move(converter), fromType, toType)) {
+ static const auto unregister = qScopeGuard([=] {
+ unregisterConverterFunction(fromType, toType);
+ });
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ template<typename From, typename To>
+ static bool registerMutableViewImpl(MutableViewFunction view, QMetaType fromType, QMetaType toType)
+ {
+ if (registerMutableViewFunction(std::move(view), fromType, toType)) {
+ static const auto unregister = qScopeGuard([=] {
+ unregisterMutableViewFunction(fromType, toType);
+ });
+ return true;
+ } else {
+ return false;
+ }
+ }
+public:
static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to);
static bool canConvert(QMetaType fromType, QMetaType toType);
@@ -700,7 +751,7 @@ public:
static bool hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType);
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
template<typename, bool> friend struct QtPrivate::SequentialValueTypeIsMetaType;
template<typename, bool> friend struct QtPrivate::AssociativeValueTypeIsMetaType;
template<typename, bool> friend struct QtPrivate::IsMetaTypePair;
@@ -713,10 +764,35 @@ public:
static void unregisterMutableViewFunction(QMetaType from, QMetaType to);
static void unregisterMetaType(QMetaType type);
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
const QtPrivate::QMetaTypeInterface *iface() { return d_ptr; }
+#endif
+ const QtPrivate::QMetaTypeInterface *iface() const { return d_ptr; }
private:
+ static bool isDefaultConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
+ static bool isCopyConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
+ static bool isMoveConstructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
+ static bool isDestructible(const QtPrivate::QMetaTypeInterface *) noexcept Q_DECL_PURE_FUNCTION;
+
+#if QT_CORE_REMOVED_SINCE(6, 5)
int idHelper() const;
+#endif
+ static int registerHelper(const QtPrivate::QMetaTypeInterface *iface);
+ int registerHelper() const
+ {
+ // keep in sync with the QMetaType::id() version in removed_api.cpp
+ if (d_ptr) {
+ if (int id = d_ptr->typeId.loadRelaxed())
+ return id;
+ return registerHelper(d_ptr);
+ }
+ return 0;
+ }
+
+ friend int qRegisterMetaType(QMetaType meta);
+
friend class QVariant;
const QtPrivate::QMetaTypeInterface *d_ptr = nullptr;
};
@@ -797,6 +873,34 @@ QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(QT_FORWARD_DECLARE_SHARED_POINTER_T
namespace QtPrivate
{
+ namespace detail {
+ template<typename T, typename ODR_VIOLATION_PREVENTER>
+ struct is_complete_helper
+ {
+ template<typename U>
+ static auto check(U *) -> std::integral_constant<bool, sizeof(U) != 0>;
+ static auto check(...) -> std::false_type;
+ using type = decltype(check(static_cast<T *>(nullptr)));
+ };
+ } // namespace detail
+
+ template <typename T, typename ODR_VIOLATION_PREVENTER>
+ struct is_complete : detail::is_complete_helper<std::remove_reference_t<T>, ODR_VIOLATION_PREVENTER>::type {};
+
+ template <typename T> struct MetatypeDecay { using type = T; };
+ 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
{
@@ -831,7 +935,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) };
};
@@ -850,6 +953,9 @@ namespace QtPrivate
};
};
+ template <typename T>
+ using IsRealGadget = std::bool_constant<IsGadgetHelper<T>::IsRealGadget>;
+
template<typename T, typename Enable = void>
struct IsPointerToGadgetHelper { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false }; };
@@ -888,13 +994,6 @@ namespace QtPrivate
static constexpr MetaObjectFn metaObjectFunction = nullptr;
};
#ifndef QT_NO_QOBJECT
- template<>
- struct MetaObjectForType<void>
- {
- static constexpr const QMetaObject *value() { return nullptr; }
- using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
- static constexpr MetaObjectFn metaObjectFunction = nullptr;
- };
template<typename T>
struct MetaObjectForType<T*, typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type>
{
@@ -902,7 +1001,12 @@ namespace QtPrivate
static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
};
template<typename T>
- struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
+ struct MetaObjectForType<T, std::enable_if_t<
+ std::disjunction_v<
+ std::bool_constant<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>,
+ std::is_base_of<QObject, T>
+ >
+ >>
{
static constexpr const QMetaObject *value() { return &T::staticMetaObject; }
static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
@@ -1086,12 +1190,36 @@ namespace QtPrivate
static bool registerConverter() { return false; }
};
+#if QT_CONFIG(future)
+ template<typename T>
+ struct MetaTypeQFutureHelper
+ {
+ static bool registerConverter() { return false; }
+ };
+#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
template <typename T, int =
QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject :
- QtPrivate::IsGadgetHelper<T>::IsRealGadget ? QMetaType::IsGadget :
+ QtPrivate::IsRealGadget<T>::value ? QMetaType::IsGadget :
QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget ? QMetaType::PointerToGadget :
QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0>
struct QMetaTypeIdQObject
@@ -1118,7 +1246,12 @@ template <typename T>
struct QMetaTypeId2<const T&> : QMetaTypeId2<T> {};
template <typename T>
-struct QMetaTypeId2<T&> { enum {Defined = false }; };
+struct QMetaTypeId2<T&>
+{
+ using NameAsArrayType = void;
+ enum { Defined = false, IsBuiltIn = false };
+ static inline constexpr int qt_metatype_id() { return 0; }
+};
namespace QtPrivate {
template <typename T, bool Defined = QMetaTypeId2<T>::Defined>
@@ -1147,8 +1280,10 @@ namespace QtPrivate {
struct QMetaTypeTypeFlags
{
enum { Flags = (QTypeInfo<T>::isRelocatable ? QMetaType::RelocatableType : 0)
- | (QTypeInfo<T>::isComplex ? QMetaType::NeedsConstruction : 0)
- | (QTypeInfo<T>::isComplex ? QMetaType::NeedsDestruction : 0)
+ | ((!std::is_default_constructible_v<T> || !QTypeInfo<T>::isValueInitializationBitwiseZero) ? QMetaType::NeedsConstruction : 0)
+ | (!std::is_trivially_destructible_v<T> ? QMetaType::NeedsDestruction : 0)
+ | (!std::is_trivially_copy_constructible_v<T> ? QMetaType::NeedsCopyConstruction : 0)
+ | (!std::is_trivially_move_constructible_v<T> ? QMetaType::NeedsMoveConstruction : 0)
| (IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject : 0)
| (IsSharedPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::SharedPointerToQObject : 0)
| (IsWeakPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::WeakPointerToQObject : 0)
@@ -1156,7 +1291,7 @@ namespace QtPrivate {
| (IsEnumOrFlags<T>::value ? QMetaType::IsEnumeration : 0)
| (IsGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::IsGadget : 0)
| (IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom ? QMetaType::PointerToGadget : 0)
- | (QTypeInfo<T>::isPointer ? QMetaType::IsPointer : 0)
+ | (std::is_pointer_v<T> ? QMetaType::IsPointer : 0)
| (IsUnsignedEnum<T> ? QMetaType::IsUnsignedEnumeration : 0)
| (IsQmlListType<T> ? QMetaType::IsQmlList : 0)
| (std::is_const_v<std::remove_pointer_t<T>> ? QMetaType::IsConst : 0)
@@ -1194,28 +1329,67 @@ namespace QtPrivate {
}
template <typename T>
-int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
+int qRegisterNormalizedMetaTypeImplementation(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
{
#ifndef QT_NO_QOBJECT
- Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()), "qRegisterNormalizedMetaType", "qRegisterNormalizedMetaType was called with a not normalized type name, please call qRegisterMetaType instead.");
+ Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()),
+ "qRegisterNormalizedMetaType",
+ "qRegisterNormalizedMetaType was called with a not normalized type name, "
+ "please call qRegisterMetaType instead.");
#endif
const QMetaType metaType = QMetaType::fromType<T>();
const int id = metaType.id();
- if (id > 0) {
+ QtPrivate::SequentialContainerTransformationHelper<T>::registerConverter();
+ QtPrivate::SequentialContainerTransformationHelper<T>::registerMutableView();
+ QtPrivate::AssociativeContainerTransformationHelper<T>::registerConverter();
+ QtPrivate::AssociativeContainerTransformationHelper<T>::registerMutableView();
+ QtPrivate::MetaTypePairHelper<T>::registerConverter();
+ QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter();
+#if QT_CONFIG(future)
+ QtPrivate::MetaTypeQFutureHelper<T>::registerConverter();
+#endif
+
+ if (normalizedTypeName != metaType.name())
QMetaType::registerNormalizedTypedef(normalizedTypeName, metaType);
- QtPrivate::SequentialContainerTransformationHelper<T>::registerConverter();
- QtPrivate::SequentialContainerTransformationHelper<T>::registerMutableView();
- QtPrivate::AssociativeContainerTransformationHelper<T>::registerConverter();
- QtPrivate::AssociativeContainerTransformationHelper<T>::registerMutableView();
- QtPrivate::MetaTypePairHelper<T>::registerConverter();
- QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter();
- }
return id;
}
+// This primary template calls the -Implementation, like all other specialisations should.
+// But the split allows to
+// - in a header:
+// - define a specialization of this template calling an out-of-line function
+// (QT_DECL_METATYPE_EXTERN{,_TAGGED})
+// - in the .cpp file:
+// - define the out-of-line wrapper to call the -Implementation
+// (QT_IMPL_METATYPE_EXTERN{,_TAGGED})
+// The _TAGGED variants let you choose a tag (must be a C identifier) to disambiguate
+// the out-of-line function; the non-_TAGGED variants use the passed class name as tag.
+template <typename T>
+int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
+{
+ return qRegisterNormalizedMetaTypeImplementation<T>(normalizedTypeName);
+}
+
+#define QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TAG, EXPORT) \
+ QT_BEGIN_NAMESPACE \
+ EXPORT int qRegisterNormalizedMetaType_ ## TAG (const QByteArray &); \
+ template <> inline int qRegisterNormalizedMetaType< TYPE >(const QByteArray &name) \
+ { return qRegisterNormalizedMetaType_ ## TAG (name); } \
+ QT_END_NAMESPACE \
+ Q_DECLARE_METATYPE(TYPE) \
+ /* end */
+#define QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TAG) \
+ int qRegisterNormalizedMetaType_ ## TAG (const QByteArray &name) \
+ { return qRegisterNormalizedMetaTypeImplementation< TYPE >(name); } \
+ /* end */
+#define QT_DECL_METATYPE_EXTERN(TYPE, EXPORT) \
+ QT_DECL_METATYPE_EXTERN_TAGGED(TYPE, TYPE, EXPORT)
+#define QT_IMPL_METATYPE_EXTERN(TYPE) \
+ QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TYPE)
+
template <typename T>
int qRegisterMetaType(const char *typeName)
{
@@ -1231,6 +1405,9 @@ template <typename T>
inline constexpr int qMetaTypeId()
{
if constexpr (bool(QMetaTypeId2<T>::IsBuiltIn)) {
+ // this has the same result as the below code, but avoids asking the
+ // compiler to load a global variable whose value we know at compile
+ // time
return QMetaTypeId2<T>::MetaType;
} else {
return QMetaType::fromType<T>().id();
@@ -1244,6 +1421,11 @@ inline constexpr int qRegisterMetaType()
return id;
}
+inline int qRegisterMetaType(QMetaType meta)
+{
+ return meta.registerHelper();
+}
+
#ifndef QT_NO_QOBJECT
template <typename T>
struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>
@@ -1254,12 +1436,12 @@ struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>
static int qt_metatype_id()
{
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
const char *const cName = T::staticMetaObject.className();
QByteArray typeName;
- typeName.reserve(int(strlen(cName)) + 1);
+ typeName.reserve(strlen(cName) + 1);
typeName.append(cName).append('*');
const int newId = qRegisterNormalizedMetaType<T *>(typeName);
metatype_id.storeRelease(newId);
@@ -1276,7 +1458,7 @@ struct QMetaTypeIdQObject<T, QMetaType::IsGadget>
static int qt_metatype_id()
{
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
const char *const cName = T::staticMetaObject.className();
@@ -1295,12 +1477,12 @@ struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget>
static int qt_metatype_id()
{
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
const char *const cName = T::staticMetaObject.className();
QByteArray typeName;
- typeName.reserve(int(strlen(cName)) + 1);
+ typeName.reserve(strlen(cName) + 1);
typeName.append(cName).append('*');
const int newId = qRegisterNormalizedMetaType<T *>(typeName);
metatype_id.storeRelease(newId);
@@ -1317,13 +1499,13 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration>
static int qt_metatype_id()
{
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
const char *eName = qt_getEnumName(T());
const char *cName = qt_getEnumMetaObject(T())->className();
QByteArray typeName;
- typeName.reserve(int(strlen(cName) + 2 + strlen(eName)));
+ typeName.reserve(strlen(cName) + 2 + strlen(eName));
typeName.append(cName).append("::").append(eName);
const int newId = qRegisterNormalizedMetaType<T>(typeName);
metatype_id.storeRelease(newId);
@@ -1334,11 +1516,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 \
/**/
@@ -1350,11 +1529,19 @@ struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration>
struct QMetaTypeId< TYPE > \
{ \
enum { Defined = 1 }; \
+ static_assert(QtPrivate::checkTypeIsSuitableForMetaType<TYPE>()); \
static int qt_metatype_id() \
{ \
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (const int id = metatype_id.loadAcquire()) \
return id; \
+ constexpr auto arr = QtPrivate::typenameHelper<TYPE>(); \
+ auto name = arr.data(); \
+ if (QByteArrayView(name) == (#TYPE)) { \
+ const int id = qRegisterNormalizedMetaType<TYPE>(name); \
+ metatype_id.storeRelease(id); \
+ return id; \
+ } \
const int newId = qRegisterMetaType< TYPE >(#TYPE); \
metatype_id.storeRelease(newId); \
return newId; \
@@ -1393,14 +1580,14 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
}; \
static int qt_metatype_id() \
{ \
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (const int id = metatype_id.loadRelaxed()) \
return id; \
const char *tName = QMetaType::fromType<T>().name(); \
Q_ASSERT(tName); \
- const int tNameLen = int(qstrlen(tName)); \
+ const size_t tNameLen = qstrlen(tName); \
QByteArray typeName; \
- typeName.reserve(int(sizeof(#SINGLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + 1); \
+ typeName.reserve(sizeof(#SINGLE_ARG_TEMPLATE) + 1 + tNameLen + 1 + 1); \
typeName.append(#SINGLE_ARG_TEMPLATE, int(sizeof(#SINGLE_ARG_TEMPLATE)) - 1) \
.append('<').append(tName, tNameLen); \
typeName.append('>'); \
@@ -1409,13 +1596,6 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
return newId; \
} \
}; \
-namespace QtPrivate { \
-template<typename T> \
-struct IsSequentialContainer<SINGLE_ARG_TEMPLATE<T> > \
-{ \
- enum { Value = true }; \
-}; \
-} \
QT_END_NAMESPACE
#define Q_DECLARE_METATYPE_TEMPLATE_2ARG(DOUBLE_ARG_TEMPLATE) \
@@ -1428,17 +1608,17 @@ struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \
}; \
static int qt_metatype_id() \
{ \
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (const int id = metatype_id.loadAcquire()) \
return id; \
const char *tName = QMetaType::fromType<T>().name(); \
const char *uName = QMetaType::fromType<U>().name(); \
Q_ASSERT(tName); \
Q_ASSERT(uName); \
- const int tNameLen = int(qstrlen(tName)); \
- const int uNameLen = int(qstrlen(uName)); \
+ const size_t tNameLen = qstrlen(tName); \
+ const size_t uNameLen = qstrlen(uName); \
QByteArray typeName; \
- typeName.reserve(int(sizeof(#DOUBLE_ARG_TEMPLATE)) + 1 + tNameLen + 1 + uNameLen + 1 + 1); \
+ typeName.reserve(sizeof(#DOUBLE_ARG_TEMPLATE) + 1 + tNameLen + 1 + uNameLen + 1 + 1); \
typeName.append(#DOUBLE_ARG_TEMPLATE, int(sizeof(#DOUBLE_ARG_TEMPLATE)) - 1) \
.append('<').append(tName, tNameLen).append(',').append(uName, uNameLen); \
typeName.append('>'); \
@@ -1476,12 +1656,12 @@ struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
}; \
static int qt_metatype_id() \
{ \
- static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
+ Q_CONSTINIT static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (const int id = metatype_id.loadAcquire()) \
return id; \
const char * const cName = T::staticMetaObject.className(); \
QByteArray typeName; \
- typeName.reserve(int(sizeof(#SMART_POINTER) + 1 + strlen(cName) + 1)); \
+ typeName.reserve(sizeof(#SMART_POINTER) + 1 + strlen(cName) + 1); \
typeName.append(#SMART_POINTER, int(sizeof(#SMART_POINTER)) - 1) \
.append('<').append(cName).append('>'); \
const int newId = qRegisterNormalizedMetaType< SMART_POINTER<T> >(typeName); \
@@ -1491,7 +1671,7 @@ struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
}; \
template<typename T> \
struct MetaTypeSmartPointerHelper<SMART_POINTER<T> , \
- typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> \
+ typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value && !std::is_const_v<T>>::type> \
{ \
static bool registerConverter() \
{ \
@@ -1512,8 +1692,20 @@ struct QMetaTypeId< SMART_POINTER<T> > \
};\
QT_END_NAMESPACE
+#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(SINGLE_ARG_TEMPLATE) \
+ QT_BEGIN_NAMESPACE \
+ namespace QtPrivate { \
+ template<typename T> \
+ struct IsSequentialContainer<SINGLE_ARG_TEMPLATE<T> > \
+ { \
+ enum { Value = true }; \
+ }; \
+ } \
+ QT_END_NAMESPACE \
+ Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE)
+
#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER(TEMPLATENAME) \
- Q_DECLARE_METATYPE_TEMPLATE_1ARG(TEMPLATENAME)
+ Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(TEMPLATENAME)
QT_END_NAMESPACE
@@ -1521,8 +1713,6 @@ QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER
#undef Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER
-#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE Q_DECLARE_METATYPE_TEMPLATE_1ARG
-
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::vector)
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::list)
@@ -1557,7 +1747,6 @@ QT_END_NAMESPACE
QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
-Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl)
QT_BEGIN_NAMESPACE
@@ -1686,7 +1875,7 @@ private:
#ifdef Q_CC_MSVC
/// On MSVC, keywords like class or struct are not separated with spaces in constexpr
/// context
- if (msvcKw)
+ if (msvcKw && !is_ident_char(*b))
return true;
#endif
Q_UNUSED(msvcKw);
@@ -1718,7 +1907,7 @@ private:
if (x != e)
x++;
return x;
- };
+ }
static constexpr const char *skipTemplate(const char *x, const char *e, bool stopAtComa = false)
{
int scopeDepth = 0;
@@ -1759,7 +1948,7 @@ private:
x++;
}
return x;
- };
+ }
constexpr void append(char x)
{
@@ -1780,7 +1969,7 @@ private:
{
while (*x)
append(*x++);
- };
+ }
constexpr void normalizeIntegerTypes(const char *&begin, const char *end)
{
@@ -1866,12 +2055,20 @@ private:
}
public:
-#ifndef Q_CC_MSVC
+#if defined(Q_CC_CLANG) || defined (Q_CC_GNU)
// this is much simpler than the full type normalization below
// the reason is that the signature returned by Q_FUNC_INFO is already
// normalized to the largest degree, and we need to do only small adjustments
constexpr int normalizeTypeFromSignature(const char *begin, const char *end)
{
+ // bail out if there is an anonymous struct
+ std::string_view name(begin, end-begin);
+#if defined (Q_CC_CLANG)
+ if (name.find("anonymous ") != std::string_view::npos)
+ return normalizeType(begin, end);
+#endif
+ if (name.find("unnamed ") != std::string_view::npos)
+ return normalizeType(begin, end);
while (begin < end) {
if (*begin == ' ') {
if (last == ',' || last == '>' || last == '<' || last == '*' || last == '&') {
@@ -1880,7 +2077,7 @@ public:
}
}
if (last == ' ') {
- if (*begin == '*' || *begin == '&') {
+ if (*begin == '*' || *begin == '&' || *begin == '(') {
replaceLast(*begin);
++begin;
continue;
@@ -2059,6 +2256,7 @@ struct is_std_pair<std::pair<T1_, T2_>> : std::true_type {
using T2 = T2_;
};
+namespace TypeNameHelper {
template<typename T>
constexpr auto typenameHelper()
{
@@ -2099,23 +2297,25 @@ constexpr auto typenameHelper()
#ifdef QT_NAMESPACE
QT_STRINGIFY(QT_NAMESPACE) "::"
#endif
-#ifdef Q_CC_MSVC
- "auto __cdecl QtPrivate::typenameHelper<"
+#if defined(Q_CC_MSVC) && defined(Q_CC_CLANG)
+ "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper(void) [T = "
+#elif defined(Q_CC_MSVC)
+ "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper<"
#elif defined(Q_CC_CLANG)
- "auto QtPrivate::typenameHelper() [T = "
+ "auto QtPrivate::TypeNameHelper::typenameHelper() [T = "
#elif defined(Q_CC_GHS)
- "auto QtPrivate::typenameHelper<T>() [with T = "
+ "auto QtPrivate::TypeNameHelper::typenameHelper<T>()[with T="
#else
- "constexpr auto QtPrivate::typenameHelper() [with T = "
+ "constexpr auto QtPrivate::TypeNameHelper::typenameHelper() [with T = "
#endif
) - 1;
-#ifdef Q_CC_MSVC
+#if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
constexpr int suffix = sizeof(">(void)");
#else
constexpr int suffix = sizeof("]");
#endif
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG) && Q_CC_GNU < 804)
+#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU_ONLY < 804
auto func = Q_FUNC_INFO;
const char *begin = func + prefix;
const char *end = func + sizeof(Q_FUNC_INFO) - suffix;
@@ -2132,6 +2332,8 @@ constexpr auto typenameHelper()
return result;
}
}
+} // namespace TypeNameHelper
+using TypeNameHelper::typenameHelper;
template<typename T, typename = void>
struct BuiltinMetaType : std::integral_constant<int, 0>
@@ -2188,28 +2390,45 @@ struct QDebugStreamOperatorForType <T, false>
template<typename T, bool = QTypeTraits::has_stream_operator_v<QDataStream, T>>
struct QDataStreamOperatorForType
{
+ static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr;
+ static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
+};
+
+#ifndef QT_NO_DATASTREAM
+template<typename T>
+struct QDataStreamOperatorForType <T, true>
+{
static void dataStreamOut(const QMetaTypeInterface *, QDataStream &ds, const void *a)
{ ds << *reinterpret_cast<const T *>(a); }
static void dataStreamIn(const QMetaTypeInterface *, QDataStream &ds, void *a)
{ ds >> *reinterpret_cast<T *>(a); }
};
+#endif
-template<typename T>
-struct QDataStreamOperatorForType <T, false>
-{
- static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr;
- static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
-};
+// Performance optimization:
+//
+// Don't add all these symbols to the dynamic symbol tables on ELF systems and
+// on Darwin. Each library is going to have a copy anyway and QMetaType already
+// copes with some of these being "hidden" (see QMetaType::idHelper()). We may
+// as well let the linker know it can always use the local copy.
+//
+// This is currently not enabled for GCC due to
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106023
+
+#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
+# pragma GCC visibility push(hidden)
+#endif
template<typename S>
class QMetaTypeForType
{
public:
static constexpr decltype(typenameHelper<S>()) name = typenameHelper<S>();
+ static constexpr unsigned Flags = QMetaTypeTypeFlags<S>::Flags;
static constexpr QMetaTypeInterface::DefaultCtrFn getDefaultCtr()
{
- if constexpr (std::is_default_constructible_v<S>) {
+ if constexpr (std::is_default_constructible_v<S> && !QTypeInfo<S>::isValueInitializationBitwiseZero) {
return [](const QMetaTypeInterface *, void *addr) { new (addr) S(); };
} else {
return nullptr;
@@ -2218,7 +2437,7 @@ public:
static constexpr QMetaTypeInterface::CopyCtrFn getCopyCtr()
{
- if constexpr (std::is_copy_constructible_v<S>) {
+ if constexpr (std::is_copy_constructible_v<S> && !std::is_trivially_copy_constructible_v<S>) {
return [](const QMetaTypeInterface *, void *addr, const void *other) {
new (addr) S(*reinterpret_cast<const S *>(other));
};
@@ -2229,7 +2448,7 @@ public:
static constexpr QMetaTypeInterface::MoveCtrFn getMoveCtr()
{
- if constexpr (std::is_move_constructible_v<S>) {
+ if constexpr (std::is_move_constructible_v<S> && !std::is_trivially_move_constructible_v<S>) {
return [](const QMetaTypeInterface *, void *addr, void *other) {
new (addr) S(std::move(*reinterpret_cast<S *>(other)));
};
@@ -2270,11 +2489,17 @@ public:
template<typename T>
struct QMetaTypeInterfaceWrapper
{
- static inline constexpr const QMetaTypeInterface metaType = {
- /*.revision=*/ 0,
+ // 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<T>::value;
+ using InterfaceType = std::conditional_t<IsConstMetaTypeInterface, const QMetaTypeInterface, NonConstMetaTypeInterface>;
+
+ static inline InterfaceType metaType = {
+ /*.revision=*/ QMetaTypeInterface::CurrentRevision,
/*.alignment=*/ alignof(T),
/*.size=*/ sizeof(T),
- /*.flags=*/ QMetaTypeTypeFlags<T>::Flags,
+ /*.flags=*/ QMetaTypeForType<T>::Flags,
/*.typeId=*/ BuiltinMetaType<T>::value,
/*.metaObjectFn=*/ MetaObjectForType<T>::metaObjectFunction,
/*.name=*/ QMetaTypeForType<T>::getName(),
@@ -2291,6 +2516,9 @@ struct QMetaTypeInterfaceWrapper
};
};
+#if !defined(Q_OS_WIN) && defined(Q_CC_CLANG)
+# pragma GCC visibility pop
+#endif
template<>
class QMetaTypeInterfaceWrapper<void>
@@ -2317,52 +2545,37 @@ public:
/*.legacyRegisterOp=*/ nullptr
};
};
-#undef QT_METATYPE_CONSTEXPRLAMDA
-#ifndef QT_BOOTSTRAPPED
+/*
+ MSVC instantiates extern templates
+(https://developercommunity.visualstudio.com/t/c11-extern-templates-doesnt-work-for-class-templat/157868)
+
+ The INTEGRITY compiler apparently does too.
+
+ On Windows (with other compilers or whenever MSVC is fixed), we can't declare
+ QMetaTypeInterfaceWrapper with __declspec(dllimport) because taking its
+ address is not a core constant expression.
+ */
+#if !defined(QT_BOOTSTRAPPED) && !defined(Q_CC_MSVC) && !defined(Q_OS_INTEGRITY)
-#if !defined(Q_CC_MSVC) || !defined(QT_BUILD_CORE_LIB)
-#define QT_METATYPE_TEMPLATE_EXPORT Q_CORE_EXPORT
+#ifdef QT_NO_DATA_RELOCATION
+# define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \
+ extern template class Q_CORE_EXPORT QMetaTypeForType<Name>;
#else
-#define QT_METATYPE_TEMPLATE_EXPORT
+# define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \
+ extern template class Q_CORE_EXPORT QMetaTypeForType<Name>; \
+ extern template struct Q_CORE_EXPORT QMetaTypeInterfaceWrapper<Name>;
#endif
-#define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name) \
- extern template class QT_METATYPE_TEMPLATE_EXPORT QMetaTypeForType<Name>;
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_GCC("-Wattributes") // false positive because of QMetaTypeForType<void>
-QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
-QT_WARNING_POP
+QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
#undef QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER
-#undef QT_METATYPE_TEMPLATE_EXPORT
#endif
template<typename T>
-constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType()
-{
- using Ty = std::remove_cv_t<std::remove_reference_t<T>>;
- return &QMetaTypeInterfaceWrapper<Ty>::metaType;
-}
-
-namespace detail {
-template<typename T, typename ODR_VIOLATION_PREVENTER>
-struct is_complete_helper
-{
- template<typename U>
- static auto check(U *) -> std::integral_constant<bool, sizeof(U) != 0>;
- static auto check(...) -> std::false_type;
- using type = decltype(check(static_cast<T *>(nullptr)));
-};
-} // namespace detail
-
-template <typename T, typename ODR_VIOLATION_PREVENTER>
-struct is_complete : detail::is_complete_helper<T, ODR_VIOLATION_PREVENTER>::type {};
-
-template<typename T>
struct qRemovePointerLike
{
using type = std::remove_pointer_t<T>;
@@ -2387,16 +2600,34 @@ struct TypeAndForceComplete
using ForceComplete = ForceComplete_;
};
+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;
+}
+
template<typename Unique, typename TypeCompletePair>
constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType()
{
using T = typename TypeCompletePair::type;
using ForceComplete = typename TypeCompletePair::ForceComplete;
- using Ty = std::remove_cv_t<std::remove_reference_t<T>>;
+ using Ty = typename MetatypeDecay<T>::type;
using Tz = qRemovePointerLike_t<Ty>;
- if constexpr (!is_complete<Tz, Unique>::value && !ForceComplete::value) {
+
+ if constexpr (std::is_void_v<Tz>) {
+ // early out to avoid expanding the rest of the templates
+ return &QMetaTypeInterfaceWrapper<Ty>::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;
}
}
@@ -2406,6 +2637,7 @@ constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType()
template<typename T>
constexpr QMetaType QMetaType::fromType()
{
+ QtPrivate::checkTypeIsSuitableForMetaType<T>();
return QMetaType(QtPrivate::qMetaTypeInterfaceForType<T>());
}
@@ -2431,7 +2663,14 @@ constexpr const QMetaObject *QMetaType::metaObject() const
template<typename... T>
constexpr const QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = {
- QtPrivate::qMetaTypeInterfaceForType<T>()...
+ /*
+ Unique in qTryMetaTypeInterfaceForType does not have to be unique here
+ as we require _all_ types here to be actually complete.
+ We just want to have the additional type processing that exist in
+ QtPrivate::qTryMetaTypeInterfaceForType as opposed to the normal
+ QtPrivate::qMetaTypeInterfaceForType used in QMetaType::fromType
+ */
+ QtPrivate::qTryMetaTypeInterfaceForType<void, QtPrivate::TypeAndForceComplete<T, std::true_type>>()...
};
constexpr const char *QMetaType::name() const
@@ -2444,6 +2683,16 @@ constexpr const QtPrivate::QMetaTypeInterface *const qt_incomplete_metaTypeArray
QtPrivate::qTryMetaTypeInterfaceForType<Unique, T>()...
};
+inline size_t qHash(QMetaType type, size_t seed = 0)
+{
+ // We cannot use d_ptr here since the same type in different DLLs
+ // might result in different pointers!
+ return qHash(type.id(), seed);
+}
+
QT_END_NAMESPACE
+QT_DECL_METATYPE_EXTERN_TAGGED(QtMetaTypePrivate::QPairVariantInterfaceImpl,
+ QPairVariantInterfaceImpl, Q_CORE_EXPORT)
+
#endif // QMETATYPE_H