From 39bb305416dd89785af431d76a08154f246c34f6 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 10 Sep 2024 10:22:16 -0700 Subject: [PATCH] moc: deprecate use of int to return QFlags values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code appears to be legacy from Qt 3's way of handling properties of enum types, because back then there was no QFlags and QVariant had a limited set of types it could use. To support flags and enum types, QObject::property() and setProperty() were coded to pass ints if the property had the isEnumType() flag set. This code was ported to the new (static) QMetaObject format in Qt 4 before QVariant gained support for user types. When QVariant gained support for user types, support for enums was changed to use the actual enum type in the property accessors, which compiles for non-scoped enums (C++11). This commit causes such code to produce a warning, to warn users that they need to update their API. I have found no use of this in Qt or Qt Creator code, but users may have something ported from Qt 3 that simply still worked. We do have one setter taking int in QtWidgets (QGroupBox::setAlignment), which isn't getting deprecated by this change because QFlags can still be constructed (without warning) from integers, through QFlag. GCC warning: qtmochelpers.h: In instantiation of ‘std::enable_if_t<...> QtMocHelpers::assignFlags(void*, I) [with ...]’: moc_flags-property-integer-access.cpp:92:49: required from here uint from a Q_PROPERTY that is a Q_FLAG is deprecated; please update to return the actual property's type [-Wdeprecated-declarations] qtmochelpers.h:104:13: note: declared here Clang warning: qtmochelpers.h:113:5: warning: 'assignFlagsFromInteger' is deprecated: Returning int/uint from a Q_PROPERTY that is a Q_FLAG is deprecated; please update to return the actual property's type [-Wdeprecated-declarations] moc_flags-property-integer-access.cpp:92:31: note: in instantiation of function template specialization 'QtMocHelpers::assignFlags, unsigned int>' requested here See-also: https://lists.qt-project.org/pipermail/development/2024-September/045636.html Change-Id: I526db07389040483fc2efffd66895430a55ec62b Reviewed-by: Fabian Kosmale --- src/corelib/kernel/qtmochelpers.h | 27 +++++++++++++++++++++++++++ src/tools/moc/generator.cpp | 11 +++++------ tests/auto/tools/moc/CMakeLists.txt | 12 +++++++++++- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/corelib/kernel/qtmochelpers.h b/src/corelib/kernel/qtmochelpers.h index 8ee9d6940f1..e4eba1a1375 100644 --- a/src/corelib/kernel/qtmochelpers.h +++ b/src/corelib/kernel/qtmochelpers.h @@ -446,6 +446,33 @@ constexpr auto metaObjectData(uint flags, const Methods &methods, const Properti #define QT_MOC_HAS_UINTDATA 1 +template inline std::enable_if_t> assignFlags(void *v, T t) noexcept +{ + *static_cast(v) = t; +} + +template inline std::enable_if_t::value> assignFlags(void *v, T t) noexcept +{ + *static_cast(v) = t; +} + +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) +template +Q_DECL_DEPRECATED_X("Returning int/uint from a Q_PROPERTY that is a Q_FLAG is deprecated; " + "please update to return the actual property's type") +inline void assignFlagsFromInteger(QFlags &f, int i) noexcept +{ + f = QFlag(i); +} + +template +inline std::enable_if_t::value && sizeof(T) == sizeof(int) && std::is_integral_v> +assignFlags(void *v, I i) noexcept +{ + assignFlagsFromInteger(*static_cast(v), i); +} +#endif // Qt 7 + } // namespace QtMocHelpers QT_END_NAMESPACE diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 6d8f98b51b4..efd8ced3bc1 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1535,9 +1535,11 @@ void Generator::generateStaticMetacall() else if (p.gspec == PropertyDef::ReferenceSpec) fprintf(out, " case %d: _a[0] = const_cast(reinterpret_cast(&%s%s())); break;\n", propindex, prefix.constData(), p.read.constData()); +#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) else if (auto eflags = cdef->enumDeclarations.value(p.type); eflags & EnumIsFlag) - fprintf(out, " case %d: *reinterpret_cast(_v) = QFlag(%s%s()); break;\n", - propindex, prefix.constData(), p.read.constData()); + fprintf(out, " case %d: QtMocHelpers::assignFlags<%s>(_v, %s%s()); break;\n", + propindex, p.type.constData(), prefix.constData(), p.read.constData()); +#endif else if (p.read == "default") fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s().value(); break;\n", propindex, p.type.constData(), prefix.constData(), p.bind.constData()); @@ -1567,10 +1569,7 @@ void Generator::generateStaticMetacall() if (p.inPrivateClass.size()) { prefix += p.inPrivateClass + "->"; } - if (auto eflags = cdef->enumDeclarations.value(p.type); eflags & EnumIsFlag) { - fprintf(out, " case %d: %s%s(QFlag(*reinterpret_cast(_v))); break;\n", - propindex, prefix.constData(), p.write.constData()); - } else if (p.write == "default") { + if (p.write == "default") { fprintf(out, " case %d: {\n", propindex); fprintf(out, " %s%s().setValue(*reinterpret_cast< %s*>(_v));\n", prefix.constData(), p.bind.constData(), p.type.constData()); diff --git a/tests/auto/tools/moc/CMakeLists.txt b/tests/auto/tools/moc/CMakeLists.txt index 92d022c5559..d4491b103b8 100644 --- a/tests/auto/tools/moc/CMakeLists.txt +++ b/tests/auto/tools/moc/CMakeLists.txt @@ -93,7 +93,17 @@ qt_internal_extend_target(tst_moc CONDITION CMAKE_CROSSCOMPILING ) if (${PROJECT_VERSION_MAJOR} LESS 7) - qt_internal_extend_target(tst_moc SOURCES flags-property-integer-access.h) + # This file intentional produces a warning, so we use qt_wrap_cpp so we can + # suppress it. + qt_wrap_cpp(flags_property_moc flags-property-integer-access.h) + qt_internal_extend_target(tst_moc SOURCES ${flags_property_moc}) + if (CLANG OR GCC) + set(Wno_deprecated "-Wno-deprecated-declarations") + elseif (MSVC) + # warning isn't triggering + set(Wno_deprecated "-wd4996") + endif() + set_source_files_properties(${flags_property_moc} COMPILE_FLAGS "${Wno_deprecated}") endif() if (UNIX AND (CLANG OR GCC OR QCC))