Adapt to the C++ SIC introduced by P0021: noexcept overloading
C++17 adopts P0021R1[1], which makes noexcept be part of the function pointer's type and thus be overloadable. It contains some provisions for allowing a noexcept function pointer to cast implicitly to a non- noexcept function pointer, but that fails in the presence of templates and additional overloads that could match the type in question. Fortunately, the paper proposed a test macro, so we can change our sources now and be compatible with both C++14 and C++17 rules. This first failed with Clang 4.0 trunk. This source incompatibility is not our fault, it's the language's doing. [1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html Task-number: QTBUG-58054 Change-Id: I2bc52f3c7a574209b213fffd14988cf0b875be63 Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
parent
635d0ae007
commit
5a1b4832a2
@ -149,6 +149,20 @@ namespace QtPrivate {
|
||||
(o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
|
||||
}
|
||||
};
|
||||
#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
|
||||
template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
|
||||
struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) noexcept> {
|
||||
static void call(SlotRet (Obj::*f)(SlotArgs...) noexcept, Obj *o, void **arg) {
|
||||
(o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
|
||||
}
|
||||
};
|
||||
template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
|
||||
struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const noexcept> {
|
||||
static void call(SlotRet (Obj::*f)(SlotArgs...) const noexcept, Obj *o, void **arg) {
|
||||
(o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...)>
|
||||
{
|
||||
@ -187,6 +201,47 @@ namespace QtPrivate {
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
|
||||
template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) noexcept>
|
||||
{
|
||||
typedef Obj Object;
|
||||
typedef List<Args...> Arguments;
|
||||
typedef Ret ReturnType;
|
||||
typedef Ret (Obj::*Function) (Args...) noexcept;
|
||||
template <class Base> struct ChangeClass { typedef Ret (Base:: *Type)(Args...) noexcept; };
|
||||
enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
|
||||
template <typename SignalArgs, typename R>
|
||||
static void call(Function f, Obj *o, void **arg) {
|
||||
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
|
||||
}
|
||||
};
|
||||
template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) const noexcept>
|
||||
{
|
||||
typedef Obj Object;
|
||||
typedef List<Args...> Arguments;
|
||||
typedef Ret ReturnType;
|
||||
typedef Ret (Obj::*Function) (Args...) const noexcept;
|
||||
template <class Base> struct ChangeClass { typedef Ret (Base:: *Type)(Args...) const noexcept; };
|
||||
enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
|
||||
template <typename SignalArgs, typename R>
|
||||
static void call(Function f, Obj *o, void **arg) {
|
||||
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename... Args> struct FunctionPointer<Ret (*) (Args...) noexcept>
|
||||
{
|
||||
typedef List<Args...> Arguments;
|
||||
typedef Ret ReturnType;
|
||||
typedef Ret (*Function) (Args...) noexcept;
|
||||
enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false};
|
||||
template <typename SignalArgs, typename R>
|
||||
static void call(Function f, void *, void **arg) {
|
||||
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, arg);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename Function, int N> struct Functor
|
||||
{
|
||||
template <typename SignalArgs, typename R>
|
||||
|
@ -3,5 +3,8 @@ TARGET = ../tst_qobject
|
||||
QT = core-private network testlib
|
||||
SOURCES = ../tst_qobject.cpp
|
||||
|
||||
# Force C++17 if available (needed due to P0012R1)
|
||||
contains(QT_CONFIG, c++1z): CONFIG += c++1z
|
||||
|
||||
!winrt: TEST_HELPER_INSTALLS = ../signalbug/signalbug
|
||||
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
|
||||
|
@ -120,6 +120,7 @@ private slots:
|
||||
void connectCxx0x();
|
||||
void connectToStaticCxx0x();
|
||||
void connectCxx0xTypeMatching();
|
||||
void connectCxx17Noexcept();
|
||||
void connectConvert();
|
||||
void connectWithReference();
|
||||
void connectManyArguments();
|
||||
@ -4757,10 +4758,13 @@ class LotsOfSignalsAndSlots: public QObject
|
||||
|
||||
public slots:
|
||||
void slot_v() {}
|
||||
void slot_v_noexcept() Q_DECL_NOTHROW {}
|
||||
void slot_vi(int) {}
|
||||
void slot_vi_noexcept() Q_DECL_NOTHROW {}
|
||||
void slot_vii(int, int) {}
|
||||
void slot_viii(int, int, int) {}
|
||||
int slot_i() { return 0; }
|
||||
int slot_i_noexcept() Q_DECL_NOTHROW { return 0; }
|
||||
int slot_ii(int) { return 0; }
|
||||
int slot_iii(int, int) { return 0; }
|
||||
int slot_iiii(int, int, int) { return 0; }
|
||||
@ -4774,13 +4778,18 @@ class LotsOfSignalsAndSlots: public QObject
|
||||
void slot_vPFvvE(fptr) {}
|
||||
|
||||
void const_slot_v() const {};
|
||||
void const_slot_v_noexcept() const Q_DECL_NOTHROW {}
|
||||
void const_slot_vi(int) const {};
|
||||
void const_slot_vi_noexcept(int) const Q_DECL_NOTHROW {}
|
||||
|
||||
static void static_slot_v() {}
|
||||
static void static_slot_v_noexcept() Q_DECL_NOTHROW {}
|
||||
static void static_slot_vi(int) {}
|
||||
static void static_slot_vi_noexcept(int) Q_DECL_NOTHROW {}
|
||||
static void static_slot_vii(int, int) {}
|
||||
static void static_slot_viii(int, int, int) {}
|
||||
static int static_slot_i() { return 0; }
|
||||
static int static_slot_i_noexcept() Q_DECL_NOTHROW { return 0; }
|
||||
static int static_slot_ii(int) { return 0; }
|
||||
static int static_slot_iii(int, int) { return 0; }
|
||||
static int static_slot_iiii(int, int, int) { return 0; }
|
||||
@ -4943,6 +4952,32 @@ void tst_QObject::connectCxx0xTypeMatching()
|
||||
|
||||
}
|
||||
|
||||
void receiverFunction_noexcept() Q_DECL_NOTHROW {}
|
||||
struct Functor_noexcept { void operator()() Q_DECL_NOTHROW {} };
|
||||
void tst_QObject::connectCxx17Noexcept()
|
||||
{
|
||||
// this is about connecting signals to slots with the Q_DECL_NOTHROW qualifier
|
||||
// as semantics changed due to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html
|
||||
typedef LotsOfSignalsAndSlots Foo;
|
||||
Foo obj;
|
||||
|
||||
QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_v_noexcept);
|
||||
QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_i_noexcept);
|
||||
QObject::connect(&obj, &Foo::signal_v, &obj, &Foo::slot_vi_noexcept);
|
||||
|
||||
QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_v_noexcept);
|
||||
QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_i_noexcept);
|
||||
QObject::connect(&obj, &Foo::signal_vii, &Foo::static_slot_vi_noexcept);
|
||||
|
||||
QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_vi_noexcept));
|
||||
QVERIFY(QObject::connect(&obj, &Foo::signal_vi, &obj, &Foo::const_slot_v_noexcept));
|
||||
|
||||
QObject::connect(&obj, &Foo::signal_v, receiverFunction_noexcept);
|
||||
|
||||
Functor_noexcept fn;
|
||||
QObject::connect(&obj, &Foo::signal_v, fn);
|
||||
}
|
||||
|
||||
class StringVariant : public QObject
|
||||
{ Q_OBJECT
|
||||
signals:
|
||||
|
@ -2,3 +2,6 @@ CONFIG += testcase
|
||||
TARGET = tst_qtimer
|
||||
QT = core testlib
|
||||
SOURCES = tst_qtimer.cpp
|
||||
|
||||
# Force C++17 if available
|
||||
contains(QT_CONFIG, c++1z): CONFIG += c++1z
|
||||
|
@ -766,6 +766,11 @@ class StaticEventLoop
|
||||
{
|
||||
public:
|
||||
static void quitEventLoop()
|
||||
{
|
||||
quitEventLoop_noexcept();
|
||||
}
|
||||
|
||||
static void quitEventLoop_noexcept() Q_DECL_NOTHROW
|
||||
{
|
||||
QVERIFY(!_e.isNull());
|
||||
_e->quit();
|
||||
@ -787,6 +792,9 @@ void tst_QTimer::singleShotToFunctors()
|
||||
QTimer::singleShot(0, &StaticEventLoop::quitEventLoop);
|
||||
QCOMPARE(_e->exec(), 0);
|
||||
|
||||
QTimer::singleShot(0, &StaticEventLoop::quitEventLoop_noexcept);
|
||||
QCOMPARE(_e->exec(), 0);
|
||||
|
||||
QThread t1;
|
||||
QObject c1;
|
||||
c1.moveToThread(&t1);
|
||||
|
Loading…
Reference in New Issue
Block a user