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>
bb10
parent
a02959bb5b
commit
8ea27bb1c6
|
|
@ -716,9 +716,9 @@ Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line)
|
|||
|
||||
#if !defined(Q_ASSERT)
|
||||
# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
|
||||
# define Q_ASSERT(cond) do { } while ((false) && (cond))
|
||||
# define Q_ASSERT(cond) static_cast<void>(false && (cond))
|
||||
# else
|
||||
# define Q_ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
|
||||
# define Q_ASSERT(cond) ((cond) ? static_cast<void>(0) : qt_assert(#cond, __FILE__, __LINE__))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
@ -733,9 +733,9 @@ Q_CORE_EXPORT void qt_assert_x(const char *where, const char *what, const char *
|
|||
|
||||
#if !defined(Q_ASSERT_X)
|
||||
# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
|
||||
# define Q_ASSERT_X(cond, where, what) do { } while ((false) && (cond))
|
||||
# define Q_ASSERT_X(cond, where, what) static_cast<void>(false && (cond))
|
||||
# else
|
||||
# define Q_ASSERT_X(cond, where, what) ((!(cond)) ? qt_assert_x(where, what,__FILE__,__LINE__) : qt_noop())
|
||||
# define Q_ASSERT_X(cond, where, what) ((cond) ? static_cast<void>(0) : qt_assert_x(where, what, __FILE__, __LINE__))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue