moc: deprecate use of int to return QFlags values

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<ClassWithFlagsAccessAsInteger::Flag>' 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<QFlags<ClassWithFlagsAccessAsInteger::Flag>, unsigned int>' requested here

See-also: https://lists.qt-project.org/pipermail/development/2024-September/045636.html
Change-Id: I526db07389040483fc2efffd66895430a55ec62b
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Thiago Macieira 2024-09-10 10:22:16 -07:00
parent 4f47ee4de4
commit 39bb305416
3 changed files with 43 additions and 7 deletions

View File

@ -446,6 +446,33 @@ constexpr auto metaObjectData(uint flags, const Methods &methods, const Properti
#define QT_MOC_HAS_UINTDATA 1
template <typename T> inline std::enable_if_t<std::is_enum_v<T>> assignFlags(void *v, T t) noexcept
{
*static_cast<T *>(v) = t;
}
template <typename T> inline std::enable_if_t<QtPrivate::IsQFlags<T>::value> assignFlags(void *v, T t) noexcept
{
*static_cast<T *>(v) = t;
}
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
template <typename T>
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<T> &f, int i) noexcept
{
f = QFlag(i);
}
template <typename T, typename I>
inline std::enable_if_t<QtPrivate::IsQFlags<T>::value && sizeof(T) == sizeof(int) && std::is_integral_v<I>>
assignFlags(void *v, I i) noexcept
{
assignFlagsFromInteger(*static_cast<T *>(v), i);
}
#endif // Qt 7
} // namespace QtMocHelpers
QT_END_NAMESPACE

View File

@ -1535,9 +1535,11 @@ void Generator::generateStaticMetacall()
else if (p.gspec == PropertyDef::ReferenceSpec)
fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(&%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<int*>(_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<int*>(_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());

View File

@ -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))