From bf3fc5c95cb4e6acedf242c00b7a1c3b455062bb Mon Sep 17 00:00:00 2001 From: Sona Kurazyan Date: Mon, 20 Jun 2022 15:46:00 +0200 Subject: [PATCH] QPromise: run continuation(s) on destruction If the QFuture is canceled because the associated QPromise has been destroyed, we still need to run its continuations (i.e. onCanceled handler, if it's attached), so replaced the cleanContinuation() call inside ~QPromise() with runContinuation(), which will also take care of cleaning the continuation. [ChangeLog][QtCore][Important Behavior Changes] QFuture now runs its continuations when its associated QPromise has been destroyed. Previously, if a QFuture was canceled because the associated QPromise has been destroyed, its continuations were skipped. Fixes: QTBUG-103992 Pick-to: 6.4 6.3 6.2 Change-Id: Ie05bc760c96c349aade8adb8d2fe5263aff8efac Reviewed-by: Marc Mutz --- src/corelib/thread/qpromise.h | 2 +- .../corelib/thread/qpromise/tst_qpromise.cpp | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/corelib/thread/qpromise.h b/src/corelib/thread/qpromise.h index a3ad04648bd..d0f6e6ae66e 100644 --- a/src/corelib/thread/qpromise.h +++ b/src/corelib/thread/qpromise.h @@ -39,7 +39,7 @@ public: // potential waits if (d.d && !(d.loadState() & QFutureInterfaceBase::State::Finished)) { d.cancelAndFinish(); // cancel and finalize the state - d.cleanContinuation(); + d.runContinuation(); } } diff --git a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp index 5de8ce13ab2..12206aa9fc9 100644 --- a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp +++ b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp @@ -40,6 +40,7 @@ private slots: #endif void cancelWhenReassigned(); void cancelWhenDestroyedWithoutStarting(); + void cancelWhenDestroyedRunsContinuations(); void finishWhenSwapped(); void cancelWhenMoved(); void waitUntilResumed(); @@ -494,6 +495,25 @@ void tst_QPromise::cancelWhenDestroyedWithoutStarting() QVERIFY(future.isFinished()); } +void tst_QPromise::cancelWhenDestroyedRunsContinuations() +{ + QFuture future; + bool onCanceledCalled = false; + bool thenCalled = false; + { + QPromise promise; + future = promise.future(); + future.then([&] { + thenCalled = true; + }).onCanceled([&] { + onCanceledCalled = true; + }); + } + QVERIFY(future.isFinished()); + QVERIFY(!thenCalled); + QVERIFY(onCanceledCalled); +} + void tst_QPromise::finishWhenSwapped() { #if !QT_CONFIG(cxx11_future)