From 0d26dc6727ffbec40764406ddc815a68f023e847 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sun, 18 Aug 2024 13:33:04 -0700 Subject: [PATCH] moc: add support for storing 64-bit enums and flags The metatype format is extended by storing the high parts of all enumerations after the (name, low part) section, for a total of 12 bytes per enumeration instead of 8. This allows 32-bit flags and enums to remain unchanged. In fact, older meta object parsers remain unchanged, aside from not knowing what this new bit in the flags field means. Because this is entirely done in the C++ constexpr side, moc knows nothing about it so it can't update the JSON output with a new field. Task-number: QTBUG-111926 Change-Id: I8a96935cf6c742259c9dfffd17e9512e4f4add19 Reviewed-by: Fabian Kosmale --- src/corelib/kernel/qtmocconstants.h | 3 ++- src/corelib/kernel/qtmochelpers.h | 26 ++++++++++++++++--- .../corelib/kernel/qvariant/tst_qvariant.cpp | 20 +++++++------- .../auto/tools/mochelpers/tst_mochelpers.cpp | 20 +++++++++++--- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/corelib/kernel/qtmocconstants.h b/src/corelib/kernel/qtmocconstants.h index 56538ca98b6..54c3f8844e7 100644 --- a/src/corelib/kernel/qtmocconstants.h +++ b/src/corelib/kernel/qtmocconstants.h @@ -29,7 +29,7 @@ namespace QtMocConstants { // and metamethods store a flag stating whether they are const // revision 11 is Qt 6.5: The metatype for void is stored in the metatypes array // revision 12 is Qt 6.6: It adds the metatype for enums -// revision 13 is Qt 6.9: It moves the location of the meta method revisions +// revision 13 is Qt 6.9: Adds support for 64-bit QFlags and moves the method revision enum { OutputRevision = 13 }; // Used by moc, qmetaobjectbuilder and qdbus enum PropertyFlags : uint { @@ -88,6 +88,7 @@ enum MetaDataFlags : uint { enum EnumFlags : uint { EnumIsFlag = 0x1, EnumIsScoped = 0x2, + EnumIs64Bit = 0x40, }; } // namespace QtMocConstants diff --git a/src/corelib/kernel/qtmochelpers.h b/src/corelib/kernel/qtmochelpers.h index e5454fbf504..8ee9d6940f1 100644 --- a/src/corelib/kernel/qtmochelpers.h +++ b/src/corelib/kernel/qtmochelpers.h @@ -83,6 +83,16 @@ template constexpr auto stringData(const char (&...strings)[Nx]) struct NoType {}; namespace detail { +template constexpr int payloadSizeForEnum() +{ + // How many uint blocks do we need to store the values of this enum and the + // string indices for the enumeration labels? We only support 8- 16-, 32- + // and 64-bit enums at the time of this writing, so this code is extra + // pedantic allowing for 48-, 96-, 128-bit, etc. + int n = int(sizeof(Enum) + sizeof(uint)) - 1; + return 1 + n / sizeof(uint); +} + template struct UintDataBlock { static constexpr uint headerSize() { return H; } @@ -207,10 +217,10 @@ struct PropertyData : detail::UintDataBlock<5, 0> }; template -struct EnumData : detail::UintDataBlock<5, 2 * N> +struct EnumData : detail::UintDataBlock<5, N * detail::payloadSizeForEnum()> { private: - static_assert(sizeof(Enum) <= sizeof(uint), "Cannot store enumeration of this size"); + static_assert(sizeof(Enum) <= 2 * sizeof(uint), "Cannot store enumeration of this size"); template struct RealEnum { using Type = T; }; template struct RealEnum> { using Type = T; }; public: @@ -219,7 +229,6 @@ public: typename RealEnum::Type value; }; - constexpr EnumData(uint nameOffset, uint aliasOffset, uint flags) { this->header[0] = nameOffset; @@ -234,7 +243,7 @@ public: this->header[2] |= QtMocConstants::EnumIsScoped; } - template constexpr auto add(const EnumEntry (&entries)[Added]) + template constexpr auto add(const EnumEntry (&entries)[Added]) const { EnumData result(this->header[0], this->header[1], this->header[2]); @@ -245,6 +254,15 @@ public: auto value = qToUnderlying(entry.value); result.payload[o++] = uint(value); } + + if constexpr (sizeof(Enum) > sizeof(uint)) { + static_assert(N == 0, "Unimplemented: merging with non-empty EnumData"); + result.header[2] |= QtMocConstants::EnumIs64Bit; + for (auto entry : entries) { + auto value = qToUnderlying(entry.value); + result.payload[o++] = uint(value >> 32); + } + } return result; } diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index fbf695f4cbf..d79e0e82f8a 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -152,12 +152,12 @@ public: enum MetaEnumTest_Enum0 { MetaEnumTest_Enum0_dummy = 2, MetaEnumTest_Enum0_value = 42, MetaEnsureSignedEnum0 = -1 }; Q_ENUM(MetaEnumTest_Enum0) enum MetaEnumTest_Enum1 : qint64 { MetaEnumTest_Enum1_value = 42, MetaEnumTest_Enum1_bigValue = (Q_INT64_C(1) << 33) + 50 }; - // Q_ENUM(MetaEnumTest_Enum1) + Q_ENUM(MetaEnumTest_Enum1) enum MetaEnumTest_Enum3 : qint64 { MetaEnumTest_Enum3_value = -47, MetaEnumTest_Enum3_bigValue = (Q_INT64_C(1) << 56) + 5, MetaEnumTest_Enum3_bigNegValue = -(Q_INT64_C(1) << 56) - 3 }; - // Q_ENUM(MetaEnumTest_Enum3) + Q_ENUM(MetaEnumTest_Enum3) enum MetaEnumTest_Enum4 : quint64 { MetaEnumTest_Enum4_value = 47, MetaEnumTest_Enum4_bigValue = (Q_INT64_C(1) << 52) + 45 }; - // Q_ENUM(MetaEnumTest_Enum4) + Q_ENUM(MetaEnumTest_Enum4) enum MetaEnumTest_Enum5 : uint { MetaEnumTest_Enum5_value = 47 }; Q_ENUM(MetaEnumTest_Enum5) enum MetaEnumTest_Enum6 : uchar { MetaEnumTest_Enum6_value = 47 }; @@ -5390,13 +5390,13 @@ void tst_QVariant::metaEnums_data() QTest::newRow(#Value) << &testVariantMetaEnum << #Value; METAENUMS_TEST(MetaEnumTest_Enum0_value); - // METAENUMS_TEST(MetaEnumTest_Enum1_value); - // METAENUMS_TEST(MetaEnumTest_Enum1_bigValue); - // METAENUMS_TEST(MetaEnumTest_Enum3_value); - // METAENUMS_TEST(MetaEnumTest_Enum3_bigValue); - // METAENUMS_TEST(MetaEnumTest_Enum3_bigNegValue); - // METAENUMS_TEST(MetaEnumTest_Enum4_value); - // METAENUMS_TEST(MetaEnumTest_Enum4_bigValue); + METAENUMS_TEST(MetaEnumTest_Enum1_value); + METAENUMS_TEST(MetaEnumTest_Enum1_bigValue); + METAENUMS_TEST(MetaEnumTest_Enum3_value); + METAENUMS_TEST(MetaEnumTest_Enum3_bigValue); + METAENUMS_TEST(MetaEnumTest_Enum3_bigNegValue); + METAENUMS_TEST(MetaEnumTest_Enum4_value); + METAENUMS_TEST(MetaEnumTest_Enum4_bigValue); METAENUMS_TEST(MetaEnumTest_Enum5_value); METAENUMS_TEST(MetaEnumTest_Enum6_value); METAENUMS_TEST(MetaEnumTest_Enum8_value); diff --git a/tests/auto/tools/mochelpers/tst_mochelpers.cpp b/tests/auto/tools/mochelpers/tst_mochelpers.cpp index 089acc73f57..035b78fa31c 100644 --- a/tests/auto/tools/mochelpers/tst_mochelpers.cpp +++ b/tests/auto/tools/mochelpers/tst_mochelpers.cpp @@ -123,11 +123,17 @@ template void enumUintData_check(const E (&values)[N]) QCOMPARE(result.payload[2 * i + 0], uint(namesAndOffsets[i].nameIndex)); QCOMPARE(result.payload[2 * i + 1], uint(values[i])); } + + if constexpr (sizeof(E) > sizeof(uint)) { + using U = std::underlying_type_t; + for (uint i = 0; i < std::size(values); ++i) + QCOMPARE(result.payload[2 * N + i], uint(U(values[i]) >> 32)); + } } enum E1 { AnEnumValue }; enum class E2 { V0 = INT_MAX, V1 = INT_MIN }; -enum class E3 : int { V = 0x1111'2222, V2 = -V }; +enum class E3 : qint64 { V = 0x1111'2222'3333'4444, V2 = -V }; void tst_MocHelpers::enumUintData() { using namespace QtMocHelpers; @@ -171,12 +177,14 @@ void tst_MocHelpers::enumUintData() .add({ { 2, E3::V }, {3, E3::V2 }, }); QCOMPARE(result.header[0], 1U); QCOMPARE(result.header[1], 1U); - QCOMPARE(result.header[2], EnumIsScoped); + QCOMPARE(result.header[2], EnumIsScoped | EnumIs64Bit); QCOMPARE(result.header[3], 2U); QCOMPARE(result.payload[0], 2U); QCOMPARE(result.payload[1], uint(E3::V)); QCOMPARE(result.payload[2], 3U); QCOMPARE(result.payload[3], uint(E3::V2)); + QCOMPARE(result.payload[4], uint(quint64(E3::V) >> 32)); + QCOMPARE(result.payload[5], uint(quint64(E3::V2) >> 32)); } QTest::setThrowOnFail(true); @@ -184,6 +192,10 @@ void tst_MocHelpers::enumUintData() enum E { E0, E1 = -1, E2 = 123, E3 = INT_MIN }; enumUintData_check({E0, E1, E2, E3}); } + { + enum E : quint64 { E0, E1 = quint64(INT_MIN), E2 = 0x1'0000'0000, E3 = quint64(LLONG_MIN) }; + enumUintData_check({E0, E1, E2, E3}); + } } template void testUintData(const Data &data) @@ -223,7 +235,7 @@ template static void checkEnums(const std::array &data) // E3: QCOMPARE(header[5 + 0], 4U); QCOMPARE(header[5 + 1], 5U); - QCOMPARE(header[5 + 2], EnumIsFlag | EnumIsScoped); + QCOMPARE(header[5 + 2], EnumIsFlag | EnumIsScoped | EnumIs64Bit); QCOMPARE(header[5 + 3], 2U); QCOMPARE_GE(header[5 + 4], 14U); payload = data.data() + header[5 + 4]; @@ -231,6 +243,8 @@ template static void checkEnums(const std::array &data) QCOMPARE(payload[1], uint(E3::V)); QCOMPARE(payload[2], 8U); QCOMPARE(payload[3], uint(E3::V2)); + QCOMPARE(payload[4], uint(quint64(E3::V) >> 32)); + QCOMPARE(payload[5], uint(quint64(E3::V2) >> 32)); // E2: QCOMPARE(header[10 + 0], 7U);