Skip to content

Commit

Permalink
QMetaType & moc: remove the pair type from qTryMetaTypeInterfaceForTy…
Browse files Browse the repository at this point in the history
…pe()

We can detect whether the intent is to require completeness by having
Unique = void. This simplifies QtMocHelpers as well, removing one more
class that needed to be instantiated for each metatype.

Change-Id: I3a256568bb6ce1754399fffd6f61144d0a3e8deb
Reviewed-by: Fabian Kosmale <[email protected]>
  • Loading branch information
thiagomacieira committed Nov 28, 2024
1 parent 2da8647 commit 3378987
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 44 deletions.
18 changes: 7 additions & 11 deletions src/corelib/kernel/qmetatype.h
Original file line number Diff line number Diff line change
Expand Up @@ -2617,13 +2617,6 @@ struct QRemovePointerLike<Pointer<T>> \
QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(Q_REMOVE_POINTER_LIKE_IMPL)
#undef Q_REMOVE_POINTER_LIKE_IMPL

template<typename T, typename ForceComplete_>
struct TypeAndForceComplete
{
using type = T;
using ForceComplete = ForceComplete_;
};

template<typename T>
constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType()
{
Expand All @@ -2632,18 +2625,21 @@ constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType()
return &QMetaTypeInterfaceWrapper<Ty>::metaType;
}

template<typename Unique, typename TypeCompletePair>
// Relaxed vesion of the above, used by moc-generated code to create the
// metatype array without requiring types to be complete and allowing
// references. Unique is passed to is_complete and must be a different unique
// type; if it is void, this function is equal to qMetaTypeInterfaceForType()
// above.
template<typename Unique, typename T>
constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType()
{
using T = typename TypeCompletePair::type;
using ForceComplete = typename TypeCompletePair::ForceComplete;
using Ty = typename MetatypeDecay<T>::type;
using Tz = typename QRemovePointerLike<Ty>::type;

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) {
} else if constexpr (std::is_void_v<Unique>) {
checkTypeIsSuitableForMetaType<Ty>();
return &QMetaTypeInterfaceWrapper<Ty>::metaType;
} else if constexpr (std::is_reference_v<Tz>) {
Expand Down
41 changes: 13 additions & 28 deletions src/corelib/kernel/qtmochelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ template <typename Prop, typename Value> inline bool setProperty(Prop &property,
}

struct NoType {};
template <typename T> struct ForceCompleteMetaTypes {};

namespace detail {
template<typename Enum> constexpr int payloadSizeForEnum()
Expand All @@ -150,39 +149,25 @@ template <uint H, uint P> struct UintDataBlock

// By default, we allow metatypes for incomplete types to be stored in the
// metatype array, but we provide a way to require them to be complete by using
// ForceCompleteMetaTypes in either the Unique type (used by moc if
// --require-complete-types is passed or some internal heuristic for QML
// matches) or in the type itself, used below for properties and enums.
template <typename T> struct TypeMustBeComplete : std::false_type {};
template <typename T> struct TypeMustBeComplete<ForceCompleteMetaTypes<T>> : std::true_type {};
// template <> struct TypeMustBeComplete<void> : std::true_type {};

template <typename Unique, typename T, typename RequireComplete = TypeMustBeComplete<Unique>>
struct TryMetaTypeInterfaceForType
{
static constexpr const QtPrivate::QMetaTypeInterface *type() noexcept
{
using namespace QtPrivate;
using Query = TypeAndForceComplete<T, RequireComplete>;
return qTryMetaTypeInterfaceForType<Unique, Query>();
}
// void as the Unique type (used by moc if --require-complete-types is passed
// or some internal heuristic for QML matches) or by using the enum below, for
// properties and enums.
enum TypeCompletenessForMetaType : bool {
TypeMayBeIncomplete = false,
TypeMustBeComplete = true,
};

template <typename Unique, typename T, typename RequireComplete>
struct TryMetaTypeInterfaceForType<Unique, ForceCompleteMetaTypes<T>, RequireComplete> :
TryMetaTypeInterfaceForType<void, T, std::true_type>
{};

template <typename... T> struct MetaTypeList
template <bool TypeMustBeComplete, typename... T> struct MetaTypeList
{
static constexpr int count() { return sizeof...(T); }
template <typename Unique, typename Result> static constexpr void
copyTo(Result &result, uint &metatypeoffset)
{
if constexpr (count()) {
using namespace QtPrivate;
using U = std::conditional_t<TypeMustBeComplete, void, Unique>;
const QMetaTypeInterface *metaTypes[] = {
TryMetaTypeInterfaceForType<Unique, T>::type()...
qTryMetaTypeInterfaceForType<U, T>()...
};
for (const QMetaTypeInterface *mt : metaTypes)
result.relocatingData.metaTypes[metatypeoffset++] = mt;
Expand Down Expand Up @@ -315,7 +300,7 @@ template <typename PropertyType> struct PropertyData : detail::UintDataBlock<5,
}

static constexpr auto metaTypes()
{ return detail::MetaTypeList<ForceCompleteMetaTypes<PropertyType>>{}; }
{ return detail::MetaTypeList<detail::TypeMustBeComplete, PropertyType>{}; }

static constexpr void adjustOffsets(uint *, uint, uint, uint) noexcept {}
};
Expand Down Expand Up @@ -371,7 +356,7 @@ struct EnumData : detail::UintDataBlock<5, N * detail::payloadSizeForEnum<Enum>(
}

static constexpr auto metaTypes()
{ return detail::MetaTypeList<ForceCompleteMetaTypes<Enum>>{}; }
{ return detail::MetaTypeList<detail::TypeMustBeComplete, Enum>{}; }

static constexpr void
adjustOffsets(uint *ptr, uint dataoffset, uint payloadoffset, uint metatypeoffset) noexcept
Expand Down Expand Up @@ -402,11 +387,11 @@ struct FunctionData<Ret (Args...), ExtraFlags>
"NoType return type used on a non-constructor");
static_assert((ExtraFlags & MethodIsConst) == 0,
"Constructors cannot be const");
return detail::MetaTypeList<Args...>{};
return detail::MetaTypeList<detail::TypeMayBeIncomplete, Args...>{};
} else {
static_assert((ExtraFlags & MethodConstructor) != MethodConstructor,
"Constructors must use NoType as return type");
return detail::MetaTypeList<Ret, Args...>{};
return detail::MetaTypeList<detail::TypeMayBeIncomplete, Ret, Args...>{};
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/tools/moc/generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,9 @@ void Generator::generateCode()
metaObjectFlags = "QMC::PropertyAccessInStaticMetaCall";
}
{
QByteArray tagType = "qt_meta_tag_" + qualifiedClassNameIdentifier + "_t";
if (requireCompleteness)
tagType = "QtMocHelpers::ForceCompleteMetaTypes<" + tagType + '>';
QByteArray tagType = QByteArrayLiteral("void");
if (!requireCompleteness)
tagType = "qt_meta_tag_" + qualifiedClassNameIdentifier + "_t";
fprintf(out, " return QtMocHelpers::metaObjectData<%s, %s>(%s, qt_stringData,\n"
" qt_methods, qt_properties, qt_enums%s);\n"
"}\n",
Expand Down
4 changes: 2 additions & 2 deletions tests/auto/tools/mochelpers/tst_mochelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ void tst_MocHelpers::uintArray()
using Dummy = QString;
using QtMocHelpers::NoType;
using namespace QtMocConstants;
constexpr auto mo = QtMocHelpers::metaObjectData<void, void>(PropertyAccessInStaticMetaCall,
constexpr auto mo = QtMocHelpers::metaObjectData<tst_MocHelpers, tst_MocHelpers>(PropertyAccessInStaticMetaCall,
dummyStringData,
QtMocHelpers::UintData{
QtMocHelpers::RevisionedSignalData<void()>(1, 2, QtMocConstants::AccessPublic, 0x509,
Expand Down Expand Up @@ -747,7 +747,7 @@ void tst_MocHelpers::uintArray()
checkMethods(data, metaTypes);
checkConstructors(data, metaTypes);
QMetaType self(metaTypes[data[6] + data[8]]);
QCOMPARE(self, QMetaType::fromType<void>());
QCOMPARE(self, QMetaType::fromType<tst_MocHelpers>());
}

QTEST_MAIN(tst_MocHelpers)
Expand Down

0 comments on commit 3378987

Please sign in to comment.