diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 07674144bc4..f9c750e1289 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -2185,13 +2185,6 @@ SetupResult TaskTreePrivate::start(RuntimeContainer *container) container->m_successBit = startAction == SetupResult::StopWithSuccess; } } - if (startAction == SetupResult::Continue - && (containerNode.m_children.empty() - || (containerNode.m_loop && !invokeLoopHandler(container)))) { - if (isProgressive(container)) - advanceProgress(containerNode.m_taskCount); - startAction = toSetupResult(container->m_successBit); - } return continueStart(container, startAction); } @@ -2225,14 +2218,14 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container) const int childCount = int(containerNode.m_children.size()); if (container->m_iterationCount == 0) { + if (container->m_shouldIterate && !invokeLoopHandler(container)) { + if (isProgressive(container)) + advanceProgress(containerNode.m_taskCount); + return toSetupResult(container->m_successBit); + } container->m_iterations.emplace_back( std::make_unique(container->m_iterationCount, container)); ++container->m_iterationCount; - } else if (containerNode.m_parallelLimit == 0) { - container->deleteFinishedIterations(); - if (container->m_iterations.empty()) - return toSetupResult(container->m_successBit); - return SetupResult::Continue; } GuardLocker locker(container->m_startGuard); @@ -2241,17 +2234,20 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container) || container->m_runningChildren < containerNode.m_parallelLimit) { container->deleteFinishedIterations(); if (container->m_nextToStart == childCount) { - if (container->m_shouldIterate && invokeLoopHandler(container)) { + if (invokeLoopHandler(container)) { container->m_nextToStart = 0; container->m_iterations.emplace_back( std::make_unique(container->m_iterationCount, container)); ++container->m_iterationCount; + } else if (container->m_iterations.empty()) { + return toSetupResult(container->m_successBit); } else { - if (container->m_iterations.empty()) - return toSetupResult(container->m_successBit); return SetupResult::Continue; } } + if (containerNode.m_children.size() == 0) // Empty loop body. + continue; + RuntimeIteration *iteration = container->m_iterations.back().get(); RuntimeTask *newTask = new RuntimeTask{containerNode.m_children.at(container->m_nextToStart), iteration}; diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index cfe47dd2f13..d9badac13c4 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -43,7 +43,8 @@ enum class Handler { Sync, BarrierAdvance, Timeout, - Storage + Storage, + Iteration }; Q_ENUM_NS(Handler); @@ -2971,6 +2972,27 @@ void tst_Tasking::testTree_data() << TestData{storage, root, {}, 1, DoneWith::Success, 0}; } + { + // Check if LoopUntil is executed with empty loop body. + const For root { + LoopUntil([storage](int iteration) { + storage->m_log.append({iteration, Handler::Iteration}); + return iteration < 3; + }), + storage + }; + + const Log log { + {0, Handler::Iteration}, + {1, Handler::Iteration}, + {2, Handler::Iteration}, + {3, Handler::Iteration} // The last iteration returns false + }; + + QTest::newRow("EmptyLoopUntil") + << TestData{storage, root, log, 0, DoneWith::Success, 0}; + } + { // Check if task tree finishes with the right progress value when onGroupSetup(false). const Group root {