From 8754bf03f59203eef5ff189b1b8c1f54b2a31f87 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 19 Dec 2011 13:10:40 +0100 Subject: [PATCH] Better error reporting in case of connection failure. Use Q_STATIC_ASSERT_X give a better error message. If C++11 is used, you get the string in the error. Else, clicking on the QStaticFailure error still shows you the string in the qobject.h source code) And report better failure if the return types do not match. (Without the static assert, you would still have a compilation error, but in an unrelated place, with no reference to the actual connect() call. The error was thrown from the virtual call QSlotObject::call, without saying where it was instantiated) Previously the error was relying on the existence of a type inside CheckCompatibleArguments, but the Q_STATIC_ASSERT requires a bool (hence the introduction of CheckCompatibleArguments::value) There also was a typo in the return value of AreArgumentsCompatible::dummy that made that code not work, and that error not be reported. (Instead, the error was reported when QObjectSlot::call is instantiated) Specialization of AreArgumentsCompatible for the void type have been added because if the return value of a signal or slot is void, the connection should work. Change-Id: I5a93ec787ce2a4b94a26630ca31d5001cd294e4d Reviewed-by: Bradley T. Hughes --- src/corelib/kernel/qobject.h | 19 ++++++++++++---- src/corelib/kernel/qobject_impl.h | 36 +++++++++++++++++-------------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index dbe5fc02a49..22572c072e2 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -212,7 +212,12 @@ public: reinterpret_cast(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast(0)); //compilation error if the arguments does not match. - typedef typename QtPrivate::CheckCompatibleArguments::IncompatibleSignalSlotArguments EnsureCompatibleArguments; + Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), + "The slot requires more arguments than the signal provides."); + Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), + "Signal and slot arguments are not compatible."); + Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible::value), + "Return type of the slot is not compatible with the return type of the signal."); const int *types = 0; if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) @@ -234,8 +239,12 @@ public: typedef QtPrivate::FunctionPointer SlotType; //compilation error if the arguments does not match. - typedef typename QtPrivate::CheckCompatibleArguments::IncompatibleSignalSlotArguments EnsureCompatibleArguments; - typedef typename QtPrivate::QEnableIf<(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount))>::Type EnsureArgumentsCount; + Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), + "The slot requires more arguments than the signal provides."); + Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), + "Signal and slot arguments are not compatible."); + Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible::value), + "Return type of the slot is not compatible with the return type of the signal."); return connectImpl(sender, reinterpret_cast(&signal), sender, 0, new QStaticSlotObject(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast(0)); //compilation error if the arguments does not match. - typedef typename QtPrivate::CheckCompatibleArguments::IncompatibleSignalSlotArguments EnsureCompatibleArguments; + Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), + "Signal and slot arguments are not compatible."); + return disconnectImpl(sender, reinterpret_cast(&signal), receiver, reinterpret_cast(&slot), &SignalType::Object::staticMetaObject); } diff --git a/src/corelib/kernel/qobject_impl.h b/src/corelib/kernel/qobject_impl.h index 660294b9564..1ddc95fc44a 100644 --- a/src/corelib/kernel/qobject_impl.h +++ b/src/corelib/kernel/qobject_impl.h @@ -441,36 +441,40 @@ namespace QtPrivate { /* Logic that check if the arguments of the slot matches the argument of the signal. To be used like this: - CheckCompatibleArguments::Arguments, FunctionPointer::Arguments>::IncompatibleSignalSlotArguments - The IncompatibleSignalSlotArguments type do not exist if the argument are incompatible and can - then produce error message. + Q_STATIC_ASSERT(CheckCompatibleArguments::Arguments, FunctionPointer::Arguments>::value) */ - template struct CheckCompatibleArgumentsHelper {}; - template struct CheckCompatibleArgumentsHelper : T {}; template struct AreArgumentsCompatible { static int test(A2); static char test(...); - static A2 dummy(); + static A1 dummy(); enum { value = sizeof(test(dummy())) == sizeof(int) }; }; template struct AreArgumentsCompatible { enum { value = false }; }; template struct AreArgumentsCompatible { enum { value = true }; }; + // void as a return value + template struct AreArgumentsCompatible { enum { value = true }; }; + template struct AreArgumentsCompatible { enum { value = true }; }; + template<> struct AreArgumentsCompatible { enum { value = true }; }; #ifndef Q_COMPILER_VARIADIC_TEMPLATES - template struct CheckCompatibleArguments{}; - template <> struct CheckCompatibleArguments { typedef bool IncompatibleSignalSlotArguments; }; - template struct CheckCompatibleArguments { typedef bool IncompatibleSignalSlotArguments; }; + template struct CheckCompatibleArguments { enum { value = false }; }; + template <> struct CheckCompatibleArguments { enum { value = true }; }; + template struct CheckCompatibleArguments { enum { value = true }; }; template struct CheckCompatibleArguments, List > - : CheckCompatibleArgumentsHelper, AreArgumentsCompatible< - typename RemoveConstRef::Type, typename RemoveConstRef::Type>::value > {}; + { + enum { value = AreArgumentsCompatible::Type, typename RemoveConstRef::Type>::value + && CheckCompatibleArguments::value }; + }; #else - template struct CheckCompatibleArguments{}; - template <> struct CheckCompatibleArguments, List<>> { typedef bool IncompatibleSignalSlotArguments; }; - template struct CheckCompatibleArguments> { typedef bool IncompatibleSignalSlotArguments; }; + template struct CheckCompatibleArguments { enum { value = false }; }; + template <> struct CheckCompatibleArguments, List<>> { enum { value = true }; }; + template struct CheckCompatibleArguments> { enum { value = true }; }; template struct CheckCompatibleArguments, List> - : CheckCompatibleArgumentsHelper, List>, AreArgumentsCompatible< - typename RemoveConstRef::Type, typename RemoveConstRef::Type>::value > {}; + { + enum { value = AreArgumentsCompatible::Type, typename RemoveConstRef::Type>::value + && CheckCompatibleArguments, List>::value }; + }; #endif