summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2020-10-30 11:21:01 +0100
committerSona Kurazyan <sona.kurazyan@qt.io>2020-10-30 17:19:26 +0100
commitff0ba7e2d7b91fd5809cb314935a1ca1a436f6c9 (patch)
treeb1a9ca252e2953c23fdd62645e231ef8f92b4ac9
parent48a13327c663a9e1409cc98936190f3d1565fcc2 (diff)
Forbid implicit conversions between QFuture and other types
- Remove the casting operator of QFuture<T> to T. It calls QFuture::result(), which may lead to undefined behavior if the user has moved the results from QFuture via QFuture::takeResult() before trying to do the conversion. - Disable implicit conversion of QFuture<T> to QFuture<void>, by making the constructor explicit. If the users really intend to do the conversion, they should do it explicitly. [ChangeLog][Source-Incompatible Changes][QFuture] Implicit conversions of QFuture<T> to T and to QFuture<void> have been disabled. Use QFuture::result() or QFuture::takeResult() where you need to convert QFuture<T> to T. Use the explicit QFuture<void>(const QFuture<T> &) constructor to convert QFuture<T> to QFuture<void>. Change-Id: I153d4137d36365b1611ac934fb3ac2eb667fdd6c Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
-rw-r--r--examples/qtconcurrent/wordcount/main.cpp2
-rw-r--r--src/corelib/thread/qfuture.h9
-rw-r--r--src/corelib/thread/qfuture.qdoc13
-rw-r--r--tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp48
-rw-r--r--tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp46
-rw-r--r--tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp4
-rw-r--r--tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp2
-rw-r--r--tests/auto/corelib/thread/qfuture/tst_qfuture.cpp34
-rw-r--r--tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp2
9 files changed, 73 insertions, 87 deletions
diff --git a/examples/qtconcurrent/wordcount/main.cpp b/examples/qtconcurrent/wordcount/main.cpp
index ae8542a761..f4de2886a8 100644
--- a/examples/qtconcurrent/wordcount/main.cpp
+++ b/examples/qtconcurrent/wordcount/main.cpp
@@ -157,7 +157,7 @@ int main(int argc, char** argv)
{
QElapsedTimer timer;
timer.start();
- WordCount total = mappedReduced(files, countWords, reduce);
+ WordCount total = mappedReduced(files, countWords, reduce).result();
mapReduceTime = timer.elapsed();
qDebug() << "MapReduce" << mapReduceTime;
}
diff --git a/src/corelib/thread/qfuture.h b/src/corelib/thread/qfuture.h
index c5966f7893..44c5331261 100644
--- a/src/corelib/thread/qfuture.h
+++ b/src/corelib/thread/qfuture.h
@@ -81,7 +81,7 @@ public:
}
template<typename U, typename V = T, typename = QtPrivate::EnableForVoid<V>>
- QFuture(const QFuture<U> &other) : d(other.d)
+ explicit QFuture(const QFuture<U> &other) : d(other.d)
{
}
@@ -96,9 +96,6 @@ public:
~QFuture() { }
QFuture(const QFuture<T> &) { }
QFuture<T> & operator=(const QFuture<T> &) { }
-
- // This is required to allow QDoc to find the declaration of operator T().
- operator T() const;
#endif
void cancel() { d.cancel(); }
@@ -150,10 +147,6 @@ QT_WARNING_POP
template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>>
bool isResultReadyAt(int resultIndex) const { return d.isResultReadyAt(resultIndex); }
- // operator T()
- template<typename U = T>
- operator typename std::enable_if_t<!std::is_same_v<U, void>, U>() const { return result(); }
-
template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>>
QList<T> results() const { return d.results(); }
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index 59f80da4af..82b7657016 100644
--- a/src/corelib/thread/qfuture.qdoc
+++ b/src/corelib/thread/qfuture.qdoc
@@ -433,19 +433,6 @@
\sa resultAt(), resultCount(), takeResult()
*/
-/*! \fn template <typename T> QFuture<T>::operator T() const
-
- Returns the first result in the future. If the result is not immediately
- available, this function will block and wait for the result to become
- available. This is a convenience method for calling result() or
- resultAt(0).
-
- \note Calling this function leads to undefined behavior if isValid()
- returns \c false for this QFuture.
-
- \sa result(), resultAt(), results(), takeResult(), isValid()
-*/
-
/*! \fn template <typename T> QList<T> QFuture<T>::results() const
Returns all results from the future. If the results are not immediately available,
diff --git a/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp b/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp
index 32023f0a66..8cce82defd 100644
--- a/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp
+++ b/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp
@@ -333,12 +333,12 @@ void testFilteredReduced(const QList<SourceObject> &sourceObjectList,
ReduceObject reduceObject)
{
const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
- sourceObjectList, filterObject, reduceObject);
+ sourceObjectList, filterObject, reduceObject).result();
QCOMPARE(result1, expectedResult);
const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject);
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
@@ -362,12 +362,13 @@ void testFilteredReduced(const QList<SourceObject> &sourceObjectList,
QtConcurrent::ReduceOptions options)
{
const ResultObject result1 = QtConcurrent::filteredReduced(
- sourceObjectList, filterObject, reduceObject, options);
+ sourceObjectList, filterObject, reduceObject, options).result();
QCOMPARE(result1, expectedResult);
- const ResultObject result2 = QtConcurrent::filteredReduced(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(), filterObject,
- reduceObject, options);
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced(sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(),
+ filterObject, reduceObject, options).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingFilteredReduced(
@@ -492,13 +493,14 @@ void testFilteredReducedThreadPool(QThreadPool *pool,
ReduceObject reduceObject)
{
const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
- pool, sourceObjectList, filterObject, reduceObject);
+ pool, sourceObjectList, filterObject, reduceObject).result();
QCOMPARE(result1, expectedResult);
QCOMPARE(threadCount(), 1); // ensure the only one thread was working
- const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
- pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject);
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced<ResultObject>(pool, sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), filterObject,
+ reduceObject).result();
QCOMPARE(result2, expectedResult);
QCOMPARE(threadCount(), 1); // ensure the only one thread was working
@@ -640,12 +642,12 @@ void testFilteredReducedInitialValue(const QList<SourceObject> &sourceObjectList
InitialObject &&initialObject)
{
const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
- sourceObjectList, filterObject, reduceObject, initialObject);
+ sourceObjectList, filterObject, reduceObject, initialObject).result();
QCOMPARE(result1, expectedResult);
const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject, initialObject);
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject, initialObject).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
@@ -671,12 +673,13 @@ void testFilteredReducedInitialValue(const QList<SourceObject> &sourceObjectList
QtConcurrent::ReduceOptions options)
{
const ResultObject result1 = QtConcurrent::filteredReduced(
- sourceObjectList, filterObject, reduceObject, initialObject, options);
+ sourceObjectList, filterObject, reduceObject, initialObject, options).result();
QCOMPARE(result1, expectedResult);
- const ResultObject result2 = QtConcurrent::filteredReduced(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject, initialObject, options);
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced(sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), filterObject, reduceObject,
+ initialObject, options).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingFilteredReduced(
@@ -810,13 +813,14 @@ void testFilteredReducedInitialValueThreadPool(QThreadPool *pool,
InitialObject &&initialObject)
{
const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
- pool, sourceObjectList, filterObject, reduceObject, initialObject);
+ pool, sourceObjectList, filterObject, reduceObject, initialObject).result();
QCOMPARE(result1, expectedResult);
QCOMPARE(threadCount(), 1); // ensure the only one thread was working
- const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
- pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject, initialObject);
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced<ResultObject>(pool, sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), filterObject,
+ reduceObject, initialObject).result();
QCOMPARE(result2, expectedResult);
QCOMPARE(threadCount(), 1); // ensure the only one thread was working
diff --git a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp
index ca2db64a85..e3b61bb109 100644
--- a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp
+++ b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp
@@ -674,11 +674,12 @@ template <typename SourceObject, typename ResultObject, typename MapObject, type
void testMappedReduced(const QList<SourceObject> &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject)
{
const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>(
- sourceObjectList, mapObject, reduceObject);
+ sourceObjectList, mapObject, reduceObject).result();
QCOMPARE(result1, expectedResult);
const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject);
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ mapObject, reduceObject).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>(
@@ -694,11 +695,12 @@ template <typename SourceObject, typename ResultObject, typename MapObject, type
void testMappedReduced(const QList<SourceObject> &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject, QtConcurrent::ReduceOptions options)
{
const ResultObject result1 = QtConcurrent::mappedReduced(
- sourceObjectList, mapObject, reduceObject, options);
+ sourceObjectList, mapObject, reduceObject, options).result();
QCOMPARE(result1, expectedResult);
- const ResultObject result2 = QtConcurrent::mappedReduced(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject, options);
+ const ResultObject result2 =
+ QtConcurrent::mappedReduced(sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ mapObject, reduceObject, options).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingMappedReduced(
@@ -796,13 +798,15 @@ void testMappedReducedThreadPool(QThreadPool *pool,
MapObject mapObject,
ReduceObject reduceObject)
{
- const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>(pool,
- sourceObjectList, mapObject, reduceObject);
+ const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>(
+ pool, sourceObjectList, mapObject, reduceObject).result();
QCOMPARE(result1, expectedResult);
QCOMPARE(threadCount(), 1); // ensure the only one thread was working
- const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>(pool,
- sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject);
+ const ResultObject result2 =
+ QtConcurrent::mappedReduced<ResultObject>(pool, sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), mapObject,
+ reduceObject).result();
QCOMPARE(result2, expectedResult);
QCOMPARE(threadCount(), 1); // ensure the only one thread was working
@@ -954,12 +958,14 @@ void testMappedReducedInitialValue(const QList<SourceObject> &sourceObjectList,
ReduceObject reduceObject,
InitialObject &&initialObject)
{
- const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>(
- sourceObjectList, mapObject, reduceObject, initialObject);
+ const ResultObject result1 =
+ QtConcurrent::mappedReduced<ResultObject>(sourceObjectList, mapObject, reduceObject,
+ initialObject).result();
QCOMPARE(result1, expectedResult);
const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject, initialObject);
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ mapObject, reduceObject, initialObject).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>(
@@ -980,11 +986,12 @@ void testMappedReducedInitialValue(const QList<SourceObject> &sourceObjectList,
QtConcurrent::ReduceOptions options)
{
const ResultObject result1 = QtConcurrent::mappedReduced(
- sourceObjectList, mapObject, reduceObject, initialObject, options);
+ sourceObjectList, mapObject, reduceObject, initialObject, options).result();
QCOMPARE(result1, expectedResult);
- const ResultObject result2 = QtConcurrent::mappedReduced(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject, initialObject, options);
+ const ResultObject result2 =
+ QtConcurrent::mappedReduced(sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ mapObject, reduceObject, initialObject, options).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingMappedReduced(
@@ -1090,13 +1097,14 @@ void testMappedReducedInitialValueThreadPool(QThreadPool *pool,
InitialObject &&initialObject)
{
const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>(
- pool, sourceObjectList, mapObject, reduceObject, initialObject);
+ pool, sourceObjectList, mapObject, reduceObject, initialObject).result();
QCOMPARE(result1, expectedResult);
QCOMPARE(threadCount(), 1); // ensure the only one thread was working
- const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>(
- pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- mapObject, reduceObject, initialObject);
+ const ResultObject result2 =
+ QtConcurrent::mappedReduced<ResultObject>(pool, sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), mapObject,
+ reduceObject, initialObject).result();
QCOMPARE(result2, expectedResult);
QCOMPARE(threadCount(), 1); // ensure the only one thread was working
diff --git a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp
index 01b7c1b895..c4d7c1d362 100644
--- a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp
+++ b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp
@@ -127,14 +127,14 @@ void tst_QtConcurrentRun::runLightFunction()
void (*f3)(QPromise<int> &) = lightOverloaded;
qDebug("starting function with promise");
- QFuture<void> future3 = run(f3);
+ QFuture<int> future3 = run(f3);
qDebug("waiting");
future3.waitForFinished();
qDebug("done");
void (*f4)(QPromise<double> &, int v) = lightOverloaded;
qDebug("starting function with promise and with arg");
- QFuture<void> future4 = run(f4, 2);
+ QFuture<double> future4 = run(f4, 2);
qDebug("waiting");
future4.waitForFinished();
qDebug("done");
diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
index 54d2182e5c..431ca4dd5a 100644
--- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
+++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
@@ -249,7 +249,7 @@ void tst_QLockFile::waitForLock()
if (!releaseEarly) // only let the thread release the lock now
semMainThreadDone.release();
- QVERIFY(ret); // waits for the thread to finish
+ QVERIFY(ret.result()); // waits for the thread to finish
}
void tst_QLockFile::staleLockFromCrashedProcess_data()
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
index 0faa8e0be7..18e11c35ad 100644
--- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
+++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
@@ -99,6 +99,7 @@ class tst_QFuture: public QObject
private slots:
void resultStore();
void future();
+ void futureToVoid();
void futureInterface();
void refcounting();
void cancel();
@@ -109,7 +110,6 @@ private slots:
void progressText();
void resultsAfterFinished();
void resultsAsList();
- void implicitConversions();
void iterators();
void iteratorsThread();
#if QT_DEPRECATED_SINCE(6, 0)
@@ -609,6 +609,19 @@ void tst_QFuture::future()
QCOMPARE(intFuture2.isFinished(), true);
}
+void tst_QFuture::futureToVoid()
+{
+ QPromise<int> p;
+ QFuture<int> future = p.future();
+
+ p.start();
+ p.setProgressValue(42);
+ p.finish();
+
+ QFuture<void> voidFuture = QFuture<void>(future);
+ QCOMPARE(voidFuture.progressValue(), 42);
+}
+
class IntResult : public QFutureInterface<int>
{
public:
@@ -1067,25 +1080,6 @@ void tst_QFuture::resultsAsList()
QCOMPARE(results, QList<int>() << 1 << 2);
}
-/*
- Test that QFuture<T> can be implicitly converted to T
-*/
-void tst_QFuture::implicitConversions()
-{
- QFutureInterface<QString> iface;
- iface.reportStarted();
-
- QFuture<QString> f(&iface);
-
- const QString input("FooBar 2000");
- iface.reportFinished(&input);
-
- const QString result = f;
- QCOMPARE(result, input);
- QCOMPARE(QString(f), input);
- QCOMPARE(static_cast<QString>(f), input);
-}
-
void tst_QFuture::iterators()
{
{
diff --git a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
index 027bd1313e..e83ea07dd4 100644
--- a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
+++ b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
@@ -864,7 +864,7 @@ void tst_QFutureWatcher::suspendEvents()
void tst_QFutureWatcher::suspended()
{
- QFutureWatcher<void> watcher;
+ QFutureWatcher<int> watcher;
QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt);
#if QT_DEPRECATED_SINCE(6, 0)
QT_WARNING_PUSH