Logging: mark qt_assert()/qt_assert_x()/qFatal() as nothrow
These functions are not supposed to return, not even by exception. qt_message() _can_ throw, but we're fine with the compiler calling std::terminate() then, since the backtrace will still include the assertion location. This behaviour is ensured by a new macro, QT_TERMINATE_ON_EXCEPTION, which expands to something like try { expr; } catch(...) { std::terminate(); } if the compiler doesn't support Q_DECL_NOEXCEPT (but maybe Q_DECL_NOTHROW), and to something like just expr; otherwise (including in the QT_NO_EXCEPTION case). The real macro preserves scopes in all cases, and aims to work even if <exception> isn't included in the TU it's used in, so is a little bit more complex than that. Change-Id: Ie6a2b7776e6aa77e57bd9aea6e184e5fa1cec81c Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
7ef395224e
commit
c856e37c5f
@ -1913,10 +1913,19 @@ void qBadAlloc()
|
|||||||
QT_THROW(std::bad_alloc());
|
QT_THROW(std::bad_alloc());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* \internal
|
||||||
|
Allows you to call std::terminate() without including <exception>.
|
||||||
|
Called internally from QT_TERMINATE_ON_EXCEPTION
|
||||||
|
*/
|
||||||
|
Q_NORETURN void qTerminate() Q_DECL_NOTHROW
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The Q_ASSERT macro calls this function when the test fails.
|
The Q_ASSERT macro calls this function when the test fails.
|
||||||
*/
|
*/
|
||||||
void qt_assert(const char *assertion, const char *file, int line)
|
void qt_assert(const char *assertion, const char *file, int line) Q_DECL_NOTHROW
|
||||||
{
|
{
|
||||||
qFatal("ASSERT: \"%s\" in file %s, line %d", assertion, file, line);
|
qFatal("ASSERT: \"%s\" in file %s, line %d", assertion, file, line);
|
||||||
}
|
}
|
||||||
@ -1924,7 +1933,7 @@ void qt_assert(const char *assertion, const char *file, int line)
|
|||||||
/*
|
/*
|
||||||
The Q_ASSERT_X macro calls this function when the test fails.
|
The Q_ASSERT_X macro calls this function when the test fails.
|
||||||
*/
|
*/
|
||||||
void qt_assert_x(const char *where, const char *what, const char *file, int line)
|
void qt_assert_x(const char *where, const char *what, const char *file, int line) Q_DECL_NOTHROW
|
||||||
{
|
{
|
||||||
qFatal("ASSERT failure in %s: \"%s\", file %s, line %d", where, what, file, line);
|
qFatal("ASSERT failure in %s: \"%s\", file %s, line %d", where, what, file, line);
|
||||||
}
|
}
|
||||||
@ -3033,6 +3042,38 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
|
|||||||
\sa Q_DECL_NOEXCEPT, Q_DECL_NOEXCEPT_EXPR
|
\sa Q_DECL_NOEXCEPT, Q_DECL_NOEXCEPT_EXPR
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\macro QT_TERMINATE_ON_EXCEPTION(expr)
|
||||||
|
\relates <QtGlobal>
|
||||||
|
\internal
|
||||||
|
|
||||||
|
In general, use of the Q_DECL_NOEXCEPT macro is preferred over
|
||||||
|
Q_DECL_NOTHROW, because it exhibits well-defined behavior and
|
||||||
|
supports the more powerful Q_DECL_NOEXCEPT_EXPR variant. However,
|
||||||
|
use of Q_DECL_NOTHROW has the advantage that Windows builds
|
||||||
|
benefit on a wide range or compiler versions that do not yet
|
||||||
|
support the C++11 noexcept feature.
|
||||||
|
|
||||||
|
It may therefore be beneficial to use Q_DECL_NOTHROW and emulate
|
||||||
|
the C++11 behavior manually with an embedded try/catch.
|
||||||
|
|
||||||
|
Qt provides the QT_TERMINATE_ON_EXCEPTION(expr) macro for this
|
||||||
|
purpose. It either expands to \c expr (if Qt is compiled without
|
||||||
|
exception support or the compiler supports C++11 noexcept
|
||||||
|
semantics) or to
|
||||||
|
\code
|
||||||
|
try { expr; } catch(...) { qTerminate(); }
|
||||||
|
\endocde
|
||||||
|
otherwise.
|
||||||
|
|
||||||
|
Since this macro expands to just \c expr if the compiler supports
|
||||||
|
C++11 noexcept, expecting the compiler to take over responsibility
|
||||||
|
of calling std::terminate() in that case, it should not be used
|
||||||
|
outside Q_DECL_NOTHROW functions.
|
||||||
|
|
||||||
|
\sa Q_DECL_NOEXCEPT, Q_DECL_NOTHROW, qTerminate()
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\macro Q_DECL_NOEXCEPT
|
\macro Q_DECL_NOEXCEPT
|
||||||
\relates <QtGlobal>
|
\relates <QtGlobal>
|
||||||
|
@ -546,11 +546,18 @@ inline void qt_noop(void) {}
|
|||||||
# define QT_CATCH(A) else
|
# define QT_CATCH(A) else
|
||||||
# define QT_THROW(A) qt_noop()
|
# define QT_THROW(A) qt_noop()
|
||||||
# define QT_RETHROW qt_noop()
|
# define QT_RETHROW qt_noop()
|
||||||
|
# define QT_TERMINATE_ON_EXCEPTION(expr) do { expr; } while (0)
|
||||||
#else
|
#else
|
||||||
# define QT_TRY try
|
# define QT_TRY try
|
||||||
# define QT_CATCH(A) catch (A)
|
# define QT_CATCH(A) catch (A)
|
||||||
# define QT_THROW(A) throw A
|
# define QT_THROW(A) throw A
|
||||||
# define QT_RETHROW throw
|
# define QT_RETHROW throw
|
||||||
|
Q_NORETURN Q_CORE_EXPORT void qTerminate() Q_DECL_NOTHROW;
|
||||||
|
# ifdef Q_COMPILER_NOEXCEPT
|
||||||
|
# define QT_TERMINATE_ON_EXCEPTION(expr) do { expr; } while (0)
|
||||||
|
# else
|
||||||
|
# define QT_TERMINATE_ON_EXCEPTION(expr) do { try { expr; } catch (...) { qTerminate(); } } while (0)
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Q_CORE_EXPORT const char *qVersion();
|
Q_CORE_EXPORT const char *qVersion();
|
||||||
@ -593,7 +600,7 @@ Q_CORE_EXPORT QString qt_error_string(int errorCode = -1);
|
|||||||
#ifndef Q_CC_MSVC
|
#ifndef Q_CC_MSVC
|
||||||
Q_NORETURN
|
Q_NORETURN
|
||||||
#endif
|
#endif
|
||||||
Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line);
|
Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line) Q_DECL_NOTHROW;
|
||||||
|
|
||||||
#if !defined(Q_ASSERT)
|
#if !defined(Q_ASSERT)
|
||||||
# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
|
# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
|
||||||
@ -610,7 +617,7 @@ Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line);
|
|||||||
#ifndef Q_CC_MSVC
|
#ifndef Q_CC_MSVC
|
||||||
Q_NORETURN
|
Q_NORETURN
|
||||||
#endif
|
#endif
|
||||||
Q_CORE_EXPORT void qt_assert_x(const char *where, const char *what, const char *file, int line);
|
Q_CORE_EXPORT void qt_assert_x(const char *where, const char *what, const char *file, int line) Q_DECL_NOTHROW;
|
||||||
|
|
||||||
#if !defined(Q_ASSERT_X)
|
#if !defined(Q_ASSERT_X)
|
||||||
# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
|
# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
|
||||||
|
@ -240,11 +240,11 @@ QDebug QMessageLogger::critical()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef qFatal
|
#undef qFatal
|
||||||
void QMessageLogger::fatal(const char *msg, ...)
|
void QMessageLogger::fatal(const char *msg, ...) Q_DECL_NOTHROW
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, msg); // use variable arg list
|
va_start(ap, msg); // use variable arg list
|
||||||
qt_message(QtFatalMsg, context, msg, ap);
|
QT_TERMINATE_ON_EXCEPTION(qt_message(QtFatalMsg, context, msg, ap));
|
||||||
#ifndef Q_CC_MSVC
|
#ifndef Q_CC_MSVC
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
#endif
|
#endif
|
||||||
|
@ -117,7 +117,7 @@ public:
|
|||||||
#ifndef Q_CC_MSVC
|
#ifndef Q_CC_MSVC
|
||||||
Q_NORETURN
|
Q_NORETURN
|
||||||
#endif
|
#endif
|
||||||
void fatal(const char *msg, ...)
|
void fatal(const char *msg, ...) Q_DECL_NOTHROW
|
||||||
#if defined(Q_CC_GNU) && !defined(__INSURE__)
|
#if defined(Q_CC_GNU) && !defined(__INSURE__)
|
||||||
__attribute__ ((format (printf, 2, 3)))
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user