diff --git a/src/corelib/global/qtclasshelpermacros.h b/src/corelib/global/qtclasshelpermacros.h index e6b66ed5f2..8839e80fb9 100644 --- a/src/corelib/global/qtclasshelpermacros.h +++ b/src/corelib/global/qtclasshelpermacros.h @@ -78,6 +78,13 @@ template inline T *qGetPtrHelper(T *ptr) noexcept { return ptr; } template inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype(ptr.get()) { static_assert(noexcept(ptr.get()), "Smart d pointers for Q_DECLARE_PRIVATE must have noexcept get()"); return ptr.get(); } +class QObject; +class QObjectPrivate; +namespace QtPrivate { + template void assertObjectType(QObjectPrivate *d); + inline const QObject *getQObject(const QObjectPrivate *d); +} + #define Q_DECLARE_PRIVATE(Class) \ inline Class##Private* d_func() noexcept \ { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(d_ptr));) } \ @@ -95,7 +102,9 @@ template inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype #define Q_DECLARE_PUBLIC(Class) \ inline Class* q_func() noexcept { return static_cast(q_ptr); } \ inline const Class* q_func() const noexcept { return static_cast(q_ptr); } \ - friend class Class; + friend class Class; \ + friend const QObject *QtPrivate::getQObject(const QObjectPrivate *d); \ + template friend void QtPrivate::assertObjectType(QObjectPrivate *d); #define Q_D(Class) Class##Private * const d = d_func() #define Q_Q(Class) Class * const q = q_func() diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 3680e15ac3..650717219c 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -243,6 +243,7 @@ inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal) } namespace QtPrivate { +inline const QObject *getQObject(const QObjectPrivate *d) { return d->q_func(); } template struct FunctionStorageByValue @@ -322,7 +323,7 @@ inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate: types = QtPrivate::ConnectionTypes::types(); return QObject::connectImpl(sender, reinterpret_cast(&signal), - receiverPrivate->q_ptr, reinterpret_cast(&slot), + QtPrivate::getQObject(receiverPrivate), reinterpret_cast(&slot), new QtPrivate::QPrivateSlotObject::Value, typename SignalType::ReturnType>(slot), type, types, &SignalType::Object::staticMetaObject); diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 1b678d8851..0877637a50 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -5982,15 +5982,15 @@ class ConnectToPrivateSlotPrivate; class ConnectToPrivateSlot :public QObject { Q_OBJECT + Q_DECLARE_PRIVATE(ConnectToPrivateSlot) public: ConnectToPrivateSlot(); void test(SenderObject *obj1) ; - Q_DECLARE_PRIVATE(ConnectToPrivateSlot) }; class ConnectToPrivateSlotPrivate : public QObjectPrivate { -public: Q_DECLARE_PUBLIC(ConnectToPrivateSlot) +public: int receivedCount; QVariant receivedValue; @@ -6002,6 +6002,8 @@ public: receivedCount++; receivedValue = v; }; + + void testFromPrivate(SenderObject *obj); }; ConnectToPrivateSlot::ConnectToPrivateSlot(): QObject(*new ConnectToPrivateSlotPrivate) {} @@ -6028,6 +6030,14 @@ void ConnectToPrivateSlot::test(SenderObject* obj1) { QVERIFY(!QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot)); } +// Compile test to verify that we can use QObjectPrivate::connect in +// the code of the private class, even if Q_DECLARE_PUBLIC is used in the +// private section of the private class. +void ConnectToPrivateSlotPrivate::testFromPrivate(SenderObject *obj) +{ + QVERIFY(QObjectPrivate::connect(obj, &SenderObject::signal1, this, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot)); +} + void tst_QObject::connectPrivateSlots() { SenderObject sender;