diff options
author | Marc Mutz <marc.mutz@kdab.com> | 2017-03-14 22:45:05 +0100 |
---|---|---|
committer | Marc Mutz <marc.mutz@kdab.com> | 2017-03-16 14:11:16 +0000 |
commit | 8ea27bb1c669e21100a6a042b0378b3346bdf671 (patch) | |
tree | 41e5bb1bd479977bbe27b2ce7e2faf5ee70e5f36 /src/corelib/tools/qstring.h | |
parent | a02959bb5b43a3f9d881e5213ceedf535202b6a1 (diff) |
Make Q_ASSERT() usable in constexpr functions
We need Q_ASSERT in (C++11) constexpr functions, and the only way to
inject them in C++11 is to use the comma operator. E.g. in
QLatin1String:
constexpr QLatin1Char at(int i) const
{ return assert(1 >= 0), assert(i < size()), m_data[i]; }
The main problem with our existing Q_ASSERT is that while it is a
ternary expression in active mode, it was a statement in passive
mode. This is easily fixed by dropping the do-while loop and leaving
just its parenthesized exit condition. Add a cast to void, too,
ensuring that Q_ASSERT has type void in both passive and active modes.
But even in C++14 constexpr functions, which accept several
statements, Q_ASSERT needs to have a path through its conditionals
that is constexpr, but neither qt_assert(_x) nor qt_noop() are
constexpr. Nor can they be in C++11 (no void returns in C++11
constexpr functions). I fixed this by replacing qt_noop() with
static_cast<void>(0). The void cast is required so both 2nd and 3rd
arguments to the ternary are void (mixing void and non-void branches
in the ternary is only allowed if the void leg is a
throw-expression[1]).
As a drive-by, adjust to style guide, remove overparenthesization and
reverse the conditional in the ternary.
Apply it to QLatin1String where we had the problem that constexpr
functions had a narrow constract.
[1] should probably be extended to any [[noreturn]] void function,
e.g. std::terminate().
[ChangeLog][QtCore][QtGlobal] Q_ASSERT() and Q_ASSERT_X() now always
expand to expressions of type void that are usable in constexpr
contexts. This makes them usable in both C++11 and C++14 constexpr
functions.
Change-Id: I09c396bc0034ac344cfaadc6f8cbeb1b7b0cbabc
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/corelib/tools/qstring.h')
-rw-r--r-- | src/corelib/tools/qstring.h | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 37f32c8c43..d4a4f23c93 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -100,7 +100,8 @@ public: Q_DECL_CONSTEXPR bool isNull() const Q_DECL_NOTHROW { return !data(); } Q_DECL_CONSTEXPR bool isEmpty() const Q_DECL_NOTHROW { return !size(); } - Q_DECL_CONSTEXPR QLatin1Char at(int i) const { return QLatin1Char(m_data[i]); } + Q_DECL_CONSTEXPR QLatin1Char at(int i) const + { return Q_ASSERT(i >= 0), Q_ASSERT(i < size()), QLatin1Char(m_data[i]); } Q_DECL_CONSTEXPR QLatin1Char operator[](int i) const { return at(i); } using value_type = const char; @@ -125,13 +126,13 @@ public: const_reverse_iterator crend() const Q_DECL_NOTHROW { return const_reverse_iterator(begin()); } Q_DECL_CONSTEXPR QLatin1String mid(int pos) const - { return QLatin1String(m_data + pos, m_size - pos); } + { return Q_ASSERT(pos >= 0), Q_ASSERT(pos <= size()), QLatin1String(m_data + pos, m_size - pos); } Q_DECL_CONSTEXPR QLatin1String mid(int pos, int n) const - { return QLatin1String(m_data + pos, n); } + { return Q_ASSERT(pos >= 0), Q_ASSERT(n >= 0), Q_ASSERT(pos + n <= size()), QLatin1String(m_data + pos, n); } Q_DECL_CONSTEXPR QLatin1String left(int n) const - { return QLatin1String(m_data, n); } + { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QLatin1String(m_data, n); } Q_DECL_CONSTEXPR QLatin1String right(int n) const - { return QLatin1String(m_data + m_size - n, n); } + { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QLatin1String(m_data + m_size - n, n); } inline bool operator==(const QString &s) const Q_DECL_NOTHROW; inline bool operator!=(const QString &s) const Q_DECL_NOTHROW; |