diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index a12efad25ab..62202178288 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -3759,6 +3759,14 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, QObjectPrivate::ConnectionDataPointer connections(scd); if (signal_index < 0) { + // wildcard disconnect - warn if this disconnects destroyed() + if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) { + qWarning("QObject::disconnect: wildcard call disconnects from destroyed signal of" + " %s::%s", sender->metaObject()->className(), + sender->objectName().isEmpty() + ? "unnamed" + : sender->objectName().toLocal8Bit().data()); + } // remove from all connection lists for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) { if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType)) diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 609229b1ae7..c68d8e83166 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -389,6 +389,15 @@ void tst_QObject::disconnect() QVERIFY(!r2.called(2)); QVERIFY(!r1.called(2)); QVERIFY(!r2.called(2)); + + // breaking a connection to QObject::destroyed can be dangerous if Qt + // or other parts of the application depend on that signal to clean up + // data structures. We want to warn if this happens as a side effect of + // a wildcard disconnect call. + QObject::connect(&s, &QObject::destroyed, &r1, &ReceiverObject::slot1); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("wildcard call disconnects from destroyed" + " signal of SenderObject::")); + QVERIFY(s.disconnect()); } class AutoConnectSender : public QObject diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index a04ab9f6cb4..a00a96c925e 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -828,7 +828,8 @@ void tst_QWidget_window::tst_dnd_events() // Some dnd implementation rely on running internal event loops, so we have to use // the following queued signal hack to simulate mouse clicks in the widget. - QObject::connect(&dndWidget, &DnDEventRecorder::dragMoveReceived, this, [=]() { + auto connection = QObject::connect(&dndWidget, &DnDEventRecorder::dragMoveReceived, this, + [=]() { QTest::mouseRelease(window, Qt::LeftButton); }, Qt::QueuedConnection); @@ -839,7 +840,7 @@ void tst_QWidget_window::tst_dnd_events() QCOMPARE(dndWidget._dndEvents, expectedDndEvents); dndWidget._dndEvents.clear(); - dndWidget.disconnect(); + dndWidget.disconnect(connection); int step = 0; QObject::connect(&dndWidget, &DnDEventRecorder::dragMoveReceived, this, [window, &step]() { switch (step++) {