mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-25 04:05:49 +08:00
Fix support for auto args in constructor callbacks
Broken since 78417b5
, this bug creates an infinite recursion at runtime while trying to resolve the QPromise<T> template constructor if the given callback is either an invalid function or a valid callback but using auto args (C++14).
Related warning: C4717: recursive on all control paths, function will cause runtime stack overflow.
This commit is contained in:
parent
d43657fbd5
commit
6deec9f51f
@ -30,7 +30,7 @@ public:
|
|||||||
inline QPromiseBase(F resolver);
|
inline QPromiseBase(F resolver);
|
||||||
|
|
||||||
template<typename F,
|
template<typename F,
|
||||||
typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type = 0>
|
typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count != 1, int>::type = 0>
|
||||||
inline QPromiseBase(F resolver);
|
inline QPromiseBase(F resolver);
|
||||||
|
|
||||||
QPromiseBase(const QPromiseBase<T>& other) : m_d{other.m_d} { }
|
QPromiseBase(const QPromiseBase<T>& other) : m_d{other.m_d} { }
|
||||||
|
@ -28,9 +28,16 @@ inline QPromiseBase<T>::QPromiseBase(F callback) : m_d{new QtPromisePrivate::Pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type>
|
template<typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count != 1, int>::type>
|
||||||
inline QPromiseBase<T>::QPromiseBase(F callback) : m_d{new QtPromisePrivate::PromiseData<T>{}}
|
inline QPromiseBase<T>::QPromiseBase(F callback) : m_d{new QtPromisePrivate::PromiseData<T>{}}
|
||||||
{
|
{
|
||||||
|
// To prevent infinite recursion at runtime when resolving the QPromise template
|
||||||
|
// constructor, we don't explicitly check for ArgsOf<F>::count == 2 so that this
|
||||||
|
// method is called for ALL callbacks other than the ones with a single typed
|
||||||
|
// argument. This includes valid callbacks such as with two args, variadic or
|
||||||
|
// auto args (c++14) but also invalid callbacks which are not functions or with
|
||||||
|
// 0 or more than 2 arguments, in which case this method MUST fail to compile.
|
||||||
|
|
||||||
QtPromisePrivate::PromiseResolver<T> resolver{*this};
|
QtPromisePrivate::PromiseResolver<T> resolver{*this};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -56,9 +56,11 @@ struct ArgsTraits<>
|
|||||||
static const size_t count = 0;
|
static const size_t count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fallback implementation (type not supported).
|
// Fallback implementation, including types (T) which are not functions but
|
||||||
|
// also lambda with `auto` arguments, which are not covered but still valid
|
||||||
|
// callbacks (see the QPromiseBase<T> template constructor).
|
||||||
template<typename T, typename Enabled = void>
|
template<typename T, typename Enabled = void>
|
||||||
struct ArgsOf
|
struct ArgsOf : public ArgsTraits<>
|
||||||
{ };
|
{ };
|
||||||
|
|
||||||
// Partial specialization for null function.
|
// Partial specialization for null function.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
add_subdirectory(shared)
|
add_subdirectory(shared)
|
||||||
|
|
||||||
add_subdirectory(benchmark)
|
add_subdirectory(benchmark)
|
||||||
|
add_subdirectory(cpp14)
|
||||||
add_subdirectory(deprecations)
|
add_subdirectory(deprecations)
|
||||||
add_subdirectory(exceptions)
|
add_subdirectory(exceptions)
|
||||||
add_subdirectory(future)
|
add_subdirectory(future)
|
||||||
|
10
tests/auto/qtpromise/cpp14/CMakeLists.txt
Normal file
10
tests/auto/qtpromise/cpp14/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# https://cmake.org/cmake/help/latest/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html
|
||||||
|
# https://gcc.gnu.org/projects/cxx-status.html#cxx14
|
||||||
|
if ("cxx_generic_lambdas" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
qtpromise_add_tests(cpp14
|
||||||
|
SOURCES
|
||||||
|
tst_argsof_lambda_auto.cpp
|
||||||
|
tst_resolver_lambda_auto.cpp
|
||||||
|
)
|
||||||
|
endif()
|
33
tests/auto/qtpromise/cpp14/tst_argsof_lambda_auto.cpp
Normal file
33
tests/auto/qtpromise/cpp14/tst_argsof_lambda_auto.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Simon Brunel, https://github.com/simonbrunel
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in
|
||||||
|
* the LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QtPromise>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace QtPromisePrivate;
|
||||||
|
|
||||||
|
class tst_cpp14_argsof_lambda_auto : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void lambdaAutoArgs();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_cpp14_argsof_lambda_auto)
|
||||||
|
#include "tst_argsof_lambda_auto.moc"
|
||||||
|
|
||||||
|
void tst_cpp14_argsof_lambda_auto::lambdaAutoArgs()
|
||||||
|
{
|
||||||
|
auto lOneArg = [](auto) {};
|
||||||
|
auto lManyArgs = [](const auto&, auto, auto) {};
|
||||||
|
auto lMutable = [](const auto&, auto) mutable {};
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((ArgsOf<decltype(lOneArg)>::count == 0));
|
||||||
|
Q_STATIC_ASSERT((ArgsOf<decltype(lManyArgs)>::count == 0));
|
||||||
|
Q_STATIC_ASSERT((ArgsOf<decltype(lMutable)>::count == 0));
|
||||||
|
}
|
79
tests/auto/qtpromise/cpp14/tst_resolver_lambda_auto.cpp
Normal file
79
tests/auto/qtpromise/cpp14/tst_resolver_lambda_auto.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Simon Brunel, https://github.com/simonbrunel
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in
|
||||||
|
* the LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../shared/utils.h"
|
||||||
|
|
||||||
|
#include <QtPromise>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace QtPromise;
|
||||||
|
|
||||||
|
class tst_cpp14_resolver_lambda_auto : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void resolverTwoAutoArgs();
|
||||||
|
void resolverTwoAutoArgs_void();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_cpp14_resolver_lambda_auto)
|
||||||
|
#include "tst_resolver_lambda_auto.moc"
|
||||||
|
|
||||||
|
void tst_cpp14_resolver_lambda_auto::resolverTwoAutoArgs()
|
||||||
|
{
|
||||||
|
QPromise<int> p0{[](auto resolve, auto reject) {
|
||||||
|
Q_UNUSED(reject)
|
||||||
|
resolve(42);
|
||||||
|
}};
|
||||||
|
QPromise<int> p1{[](auto resolve, const auto& reject) {
|
||||||
|
Q_UNUSED(reject)
|
||||||
|
resolve(42);
|
||||||
|
}};
|
||||||
|
QPromise<int> p2{[](const auto& resolve, auto reject) {
|
||||||
|
Q_UNUSED(reject)
|
||||||
|
resolve(42);
|
||||||
|
}};
|
||||||
|
QPromise<int> p3{[](const auto& resolve, const auto& reject) {
|
||||||
|
Q_UNUSED(reject)
|
||||||
|
resolve(42);
|
||||||
|
}};
|
||||||
|
|
||||||
|
for (const auto& p : {p0, p1, p2, p3}) {
|
||||||
|
QCOMPARE(p.isFulfilled(), true);
|
||||||
|
QCOMPARE(waitForError(p, -1), -1);
|
||||||
|
QCOMPARE(waitForValue(p, -1), 42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_cpp14_resolver_lambda_auto::resolverTwoAutoArgs_void()
|
||||||
|
{
|
||||||
|
QPromise<void> p0{[](auto resolve, auto reject) {
|
||||||
|
Q_UNUSED(reject)
|
||||||
|
resolve();
|
||||||
|
}};
|
||||||
|
QPromise<void> p1{[](auto resolve, const auto& reject) {
|
||||||
|
Q_UNUSED(reject)
|
||||||
|
resolve();
|
||||||
|
}};
|
||||||
|
QPromise<void> p2{[](const auto& resolve, auto reject) {
|
||||||
|
Q_UNUSED(reject)
|
||||||
|
resolve();
|
||||||
|
}};
|
||||||
|
QPromise<void> p3{[](const auto& resolve, const auto& reject) {
|
||||||
|
Q_UNUSED(reject)
|
||||||
|
resolve();
|
||||||
|
}};
|
||||||
|
|
||||||
|
for (const auto& p : {p0, p1, p2, p3}) {
|
||||||
|
QCOMPARE(p.isFulfilled(), true);
|
||||||
|
QCOMPARE(waitForError(p, -1), -1);
|
||||||
|
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user