From 8ea27bb1c669e21100a6a042b0378b3346bdf671 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 14 Mar 2017 22:45:05 +0100 Subject: 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(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) Reviewed-by: Edward Welbourne --- src/corelib/global/qglobal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/corelib/global/qglobal.h') diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 0e37493182..12220e10b5 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -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(false && (cond)) # else -# define Q_ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop()) +# define Q_ASSERT(cond) ((cond) ? static_cast(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(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(0) : qt_assert_x(where, what, __FILE__, __LINE__)) # endif #endif -- cgit v1.2.3