From 19fbb338b8221530722c914c83f55a0937e2c78b Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 3 Jul 2024 15:03:08 +0200 Subject: [PATCH] Long live Q_DECLARE_SHARED_NS! We used to mark Q_DECLARE_SHARED all our value classes in Qt 4 times, but since many Qt types these days live in nested namespaces that macro, which only works in the QT_NAMESPACE, has become less useful. As we use it in more and more places and eventually add more responsibilities to it, we don't want every module to define its version by hand, like QT3D_DECLARE_SHARED did in 2016 already. So add two namespace-aware versions of Q_DECLARE_SHARED, to be used inside or outside nested namespaces. Extend the test. Despite the name, this is not a public macro. Found missing Q_D_S in API-review, so picking this to 6.8 to aid with fixing the 6.8 API. Change-Id: I367ca0d5b005b64090de44f7b7541d8639f9a4e0 Reviewed-by: Ivan Solovev (cherry picked from commit 37b2b2ea4ef3cf494d23885de186a9519763e744) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/global/qtclasshelpermacros.h | 45 +++++++++++++++++++ .../corelib/global/qglobal/tst_qglobal.cpp | 36 +++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/corelib/global/qtclasshelpermacros.h b/src/corelib/global/qtclasshelpermacros.h index 0b7f943ea73..952d3827507 100644 --- a/src/corelib/global/qtclasshelpermacros.h +++ b/src/corelib/global/qtclasshelpermacros.h @@ -141,10 +141,55 @@ namespace QtPrivate { where 'type' is the name of the type to specialize. NOTE: shared types must define a member-swap, and be defined in the same namespace as Qt for this to work. + + For types defined in a namespace within QT_NAMESPACE, use + Q_DECLARE_SHARED_NS/_EXT instead. The _NS macro needs to be placed + inside the nested namespace: + + namespace ns { + // ~~~ type defined here ~~~ + Q_DECLARE_SHARED_NS(ns, type) + } + + while the _NS_EXT macro goes into the QT_NAMESPACE, outside any + nested namespaces: + + namespace ns { + // ~~~ type defined here ~~~ + } + Q_DECLARE_SHARED_NS_EXT(ns, type) + + The latter then also works for more deeply-nested namespaces: + + Q_DECLARE_SHARED_NS_EXT(ns1::ns2, type) + + Q_DECLARE_SHARED_NS does, too, if all namespaces were opened in one statement: + + namespace ns1::ns2 { + Q_DECLARE_SHARED_NS(ns1::ns2, type); + } */ #define Q_DECLARE_SHARED(TYPE) \ +QT_DECLARE_ADL_SWAP(TYPE) \ Q_DECLARE_TYPEINFO(TYPE, Q_RELOCATABLE_TYPE); \ +/* end */ + +#define Q_DECLARE_SHARED_NS(NS, TYPE) \ +QT_DECLARE_ADL_SWAP(TYPE) \ +} /* namespace NS */ \ +Q_DECLARE_TYPEINFO(NS :: TYPE, Q_RELOCATABLE_TYPE); \ +namespace NS { \ +/* end */ + +#define Q_DECLARE_SHARED_NS_EXT(NS, TYPE) \ +namespace NS { \ +QT_DECLARE_ADL_SWAP(TYPE) \ +} /* namespace NS */ \ +Q_DECLARE_TYPEINFO(NS :: TYPE, Q_RELOCATABLE_TYPE); \ +/* end */ + +#define QT_DECLARE_ADL_SWAP(TYPE) \ inline void swap(TYPE &value1, TYPE &value2) \ noexcept(noexcept(value1.swap(value2))) \ { value1.swap(value2); } diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp index e98bdacd44a..7dd027160ed 100644 --- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp +++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp @@ -42,6 +42,27 @@ static_assert(!q_is_adl_swappable_v); MAKE_CLASS(Terry); // R.I.P. Q_DECLARE_SHARED(Terry) +namespace Discworld { +MAKE_CLASS(Librarian); +Q_DECLARE_SHARED_NS(Discworld, Librarian) +MAKE_CLASS(Baggage); +namespace AnkhMorpork { +MAKE_CLASS(Vetinari); +// Q_DECLARE_SHARED_NS only work on a single nesting level +namespace CityWatch { +MAKE_CLASS(Vimes); +} // namespace CityWatch +} // namespace AnkhMorpork +} // namespace Discworld +Q_DECLARE_SHARED_NS_EXT(Discworld, Baggage) +Q_DECLARE_SHARED_NS_EXT(Discworld::AnkhMorpork, Vetinari) +Q_DECLARE_SHARED_NS_EXT(Discworld::AnkhMorpork::CityWatch, Vimes) +// but Q_DECLARE_SHARED_NS works if all namespaces are opened in one statement: +namespace Discworld::AnkhMorpork { +MAKE_CLASS(Leonardo); +Q_DECLARE_SHARED_NS(Discworld::AnkhMorpork, Leonardo) +} // namespace Discworld::AnkhMorpork + #undef MAKE_CLASS QT_END_NAMESPACE @@ -432,12 +453,22 @@ void tst_QGlobal::qDeclareSharedMarksTheTypeRelocatable() { static_assert(!QTypeInfo::isRelocatable); static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); + static_assert( QTypeInfo::isRelocatable); } void tst_QGlobal::qDeclareSharedMakesTheTypeAdlSwappable() { static_assert(!q_is_adl_swappable_v); static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); + static_assert( q_is_adl_swappable_v); #define CHECK(Class) do { \ using C = QT_PREPEND_NAMESPACE(Class); \ @@ -451,6 +482,11 @@ void tst_QGlobal::qDeclareSharedMakesTheTypeAdlSwappable() QCOMPARE_EQ(rhs.s, "lhs"); \ } while (false) CHECK(Terry); + CHECK(Discworld::Librarian); + CHECK(Discworld::Baggage); + CHECK(Discworld::AnkhMorpork::Vetinari); + CHECK(Discworld::AnkhMorpork::Leonardo); + CHECK(Discworld::AnkhMorpork::CityWatch::Vimes); #undef CHECK }