From e80faf3db61ca9c701cd86876e3bce8e33226576 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 17 Oct 2016 13:00:04 +0200 Subject: QTimer: don't circumvent safety net By templating on the types and unconditionally using duration_cast to coerce the duration into a milliseconds, we violate a principal design rule of , namely that non- narrowing conversions are implicit, but narrowing conversions need duration_cast. By accepting any duration, we allow non- sensical code such as QTimer::singleShot(10us, ...) to compile, which is misleading, since it's actually a zero- timeout timer. Overloading a non-template with a template also has adverse effects: it breaks qOverload(). Fix by replacing the function templates with functions that just take std::chrono::milliseconds. This way, benign code such as QTimer::singleShot(10s, ...) QTimer::singleShot(10min, ...) QTimer::singleShot(1h, ...) work as expected, but attempts to use sub-millisecond resolution fails to compile / needs an explicit user- provided duration_cast. To allow future extension to more precise timers, forcibly inline the functions, so they don't partake in the ABI of the class and we can later support sub-millisecond resolution by simply taking micro- or nano- instead of milliseconds. Change-Id: I12c9a98bdabefcd8ec18a9eb09f87ad908d889de Reviewed-by: Thiago Macieira --- src/corelib/kernel/qtimer.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'src/corelib/kernel/qtimer.h') diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index 1567fe760c..4f934d0367 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -165,38 +165,40 @@ Q_SIGNALS: public: #if QT_HAS_INCLUDE() || defined(Q_QDOC) - template - void setInterval(std::chrono::duration value) + Q_ALWAYS_INLINE + void setInterval(std::chrono::milliseconds value) { - setInterval(std::chrono::duration_cast(value).count()); + setInterval(value.count()); } + Q_ALWAYS_INLINE std::chrono::milliseconds intervalAsDuration() const { return std::chrono::milliseconds(interval()); } + Q_ALWAYS_INLINE std::chrono::milliseconds remainingTimeAsDuration() const { return std::chrono::milliseconds(remainingTime()); } - template - static void singleShot(std::chrono::duration value, const QObject *receiver, const char *member) + Q_ALWAYS_INLINE + static void singleShot(std::chrono::milliseconds value, const QObject *receiver, const char *member) { - singleShot(int(std::chrono::duration_cast(value).count()), receiver, member); + singleShot(int(value.count()), receiver, member); } - template - static void singleShot(std::chrono::duration value, Qt::TimerType timerType, const QObject *receiver, const char *member) + Q_ALWAYS_INLINE + static void singleShot(std::chrono::milliseconds value, Qt::TimerType timerType, const QObject *receiver, const char *member) { - singleShot(int(std::chrono::duration_cast(value).count()), timerType, receiver, member); + singleShot(int(value.count()), timerType, receiver, member); } - template - void start(std::chrono::duration value) + Q_ALWAYS_INLINE + void start(std::chrono::milliseconds value) { - start(int(std::chrono::duration_cast(value).count())); + start(int(value.count())); } #endif @@ -215,15 +217,13 @@ private: const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj); #if QT_HAS_INCLUDE() - template - static Qt::TimerType defaultTypeFor(std::chrono::duration interval) - { return defaultTypeFor(int(std::chrono::duration_cast(interval).count())); } + static Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval) + { return defaultTypeFor(int(interval.count())); } - template - static void singleShotImpl(std::chrono::duration interval, Qt::TimerType timerType, + static void singleShotImpl(std::chrono::milliseconds interval, Qt::TimerType timerType, const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj) { - singleShotImpl(int(std::chrono::duration_cast(interval).count()), + singleShotImpl(int(interval.count()), timerType, receiver, slotObj); } #endif -- cgit v1.2.3