From fbafac20afd6a6e90c9c57b89ebd427a04bae42c Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Tue, 22 Aug 2023 18:48:48 +0200 Subject: [PATCH] Constrain QCoreApplication::requestPermission to compatible functors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 6.5 versions of the overload not taking a context/receiver object were constrained by requiring a functor to be free function or lambda. 207aae5560aa2865ec55ddb9ecbb50048060c0c0 removed that constraint, which might be source incomaptible if wrapper functions in user code forward the constraint using Expression SFINAE. Those wrappers would no longer be removed from the overload set based on the same criteria as the function they wrap. We can't constrain the new functions based on the same predicate as before, as after the simplification we have only one overload with, and one without context object. But we can still remove overloads for incompatible functors. Add the respective scenario to the QPermission test as a compile-time test. Found during 6.6 header review. Change-Id: Id21391b4a6b78a29de2f8fa04374f4262e5fafa7 Reviewed-by: MÃ¥rten Nordheim (cherry picked from commit d027b0c8162ac888de233cf3a41e3254ba2d7cc8) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/kernel/qcoreapplication.h | 18 ++++++++++---- .../kernel/qpermission/tst_qpermission.cpp | 24 +++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index 8bebd761ca3..dbded9e0b11 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -60,6 +60,10 @@ class Q_CORE_EXPORT QCoreApplication Q_DECLARE_PRIVATE(QCoreApplication) friend class QEventLoopLocker; +#if QT_CONFIG(permissions) + using RequestPermissionPrototype = void(*)(QPermission); +#endif + public: enum { ApplicationFlags = QT_VERSION }; @@ -122,21 +126,25 @@ public: # else // requestPermission with context or receiver object; need to require here that receiver is the // right type to avoid ambiguity with the private implementation function. - template + template ::value, + bool> = true> void requestPermission(const QPermission &permission, const typename QtPrivate::ContextTypeForFunctor::ContextType *receiver, Functor &&func) { - using Prototype = void(*)(QPermission); - QtPrivate::AssertCompatibleFunctions(); requestPermission(permission, - QtPrivate::makeCallableObject(std::forward(func)), + QtPrivate::makeCallableObject(std::forward(func)), receiver); } # endif // Q_QDOC // requestPermission to a functor or function pointer (without context) - template + template ::value, + bool> = true> void requestPermission(const QPermission &permission, Functor &&func) { requestPermission(permission, nullptr, std::forward(func)); diff --git a/tests/auto/corelib/kernel/qpermission/tst_qpermission.cpp b/tests/auto/corelib/kernel/qpermission/tst_qpermission.cpp index 146c1b26608..8f257eba8bb 100644 --- a/tests/auto/corelib/kernel/qpermission/tst_qpermission.cpp +++ b/tests/auto/corelib/kernel/qpermission/tst_qpermission.cpp @@ -146,6 +146,19 @@ void tst_QPermission::conversionMaintainsState() const } } +template requestPermission(std::declval(), + std::declval()))> + > +void wrapRequestPermission(const QPermission &p, Func &&f) +{ + qApp->requestPermission(p, std::forward(f)); +} + +template +using CompatibleTest = decltype(wrapRequestPermission(std::declval(), std::declval())); + + // Compile test for context-less functor overloads void tst_QPermission::functorWithoutContext() { @@ -161,6 +174,17 @@ void tst_QPermission::functorWithoutContext() qApp->requestPermission(dummy, [](const QPermission &permission){ QVERIFY(permission.value()); }); + wrapRequestPermission(dummy, [](const QPermission &permission){ + QVERIFY(permission.value()); + }); + + auto compatible = [](const QPermission &) {}; + using Compatible = decltype(compatible); + auto incompatible = [](const QString &) {}; + using Incompatible = decltype(incompatible); + + static_assert(qxp::is_detected_v); + static_assert(!qxp::is_detected_v); } void tst_QPermission::functorWithContextInThread()