diff options
Diffstat (limited to 'src/corelib/global/qassert.cpp')
-rw-r--r-- | src/corelib/global/qassert.cpp | 114 |
1 files changed, 95 insertions, 19 deletions
diff --git a/src/corelib/global/qassert.cpp b/src/corelib/global/qassert.cpp index 758c11cc57..6a29cbfa21 100644 --- a/src/corelib/global/qassert.cpp +++ b/src/corelib/global/qassert.cpp @@ -1,18 +1,55 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qassert.h" #include <QtCore/qlogging.h> +#include <cstdlib> #include <cstdio> #include <exception> #ifndef QT_NO_EXCEPTIONS #include <new> #endif +#if defined(Q_CC_MSVC) +# include <crtdbg.h> +#endif +#ifdef Q_OS_WIN +# include <qt_windows.h> +#endif + QT_BEGIN_NAMESPACE +void qAbort() +{ +#ifdef Q_OS_WIN + // std::abort() in the MSVC runtime will call _exit(3) if the abort + // behavior is _WRITE_ABORT_MSG - see also _set_abort_behavior(). This is + // the default for a debug-mode build of the runtime. Worse, MinGW's + // std::abort() implementation (in msvcrt.dll) is basically a call to + // _exit(3) too. Unfortunately, _exit() and _Exit() *do* run the static + // destructors of objects in DLLs, a violation of the C++ standard (see + // [support.start.term]). So we bypass std::abort() and directly + // terminate the application. + +# if defined(Q_CC_MSVC) + if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE)) + __fastfail(FAST_FAIL_FATAL_APP_EXIT); +# else + RaiseFailFastException(nullptr, nullptr, 0); +# endif + + // Fallback + TerminateProcess(GetCurrentProcess(), STATUS_FATAL_APP_EXIT); + + // Tell the compiler the application has stopped. + Q_UNREACHABLE_IMPL(); +#else // !Q_OS_WIN + std::abort(); +#endif +} + /*! \macro void Q_ASSERT(bool test) \relates <QtAssert> @@ -139,31 +176,52 @@ void qBadAlloc() /*! \macro void Q_ASSUME(bool expr) + \deprecated \relates <QtAssert> \since 5.0 - Causes the compiler to assume that \a expr is \c true. This macro is useful - for improving code generation, by providing the compiler with hints about - conditions that it would not otherwise know about. However, there is no - guarantee that the compiler will actually use those hints. + Causes the compiler to assume that \a expr is \c true. - This macro could be considered a "lighter" version of \l{Q_ASSERT()}. While - Q_ASSERT will abort the program's execution if the condition is \c false, - Q_ASSUME will tell the compiler not to generate code for those conditions. - Therefore, it is important that the assumptions always hold, otherwise - undefined behavior may occur. + This macro is known to produce worse code than when no assumption was + inserted in the code, with some compiler versions. The arguments passed to + it are always evaluated, even in release mode, with some compilers and not + others, so application code needs to be aware of those possible differences + in behavior. - If \a expr is a constantly \c false condition, Q_ASSUME will tell the compiler - that the current code execution cannot be reached. That is, Q_ASSUME(false) - is equivalent to Q_UNREACHABLE(). + Do not use it in new code. It is retained as-is for compatibility with old + code and will likely be removed in the next major version Qt. - In debug builds the condition is enforced by an assert to facilitate debugging. + \sa Q_ASSERT(), Q_UNREACHABLE(), Q_LIKELY() +*/ - \note Q_LIKELY() tells the compiler that the expression is likely, but not - the only possibility. Q_ASSUME tells the compiler that it is the only - possibility. +/*! + \macro QT_TERMINATE_ON_EXCEPTION(expr) + \relates <QtGlobal> + \internal - \sa Q_ASSERT(), Q_UNREACHABLE(), Q_LIKELY() + 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 + \snippet code/src_corelib_global_qglobal.cpp qterminate + 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() */ /*! @@ -195,7 +253,25 @@ void qBadAlloc() In debug builds the condition is enforced by an assert to facilitate debugging. - \sa Q_ASSERT(), Q_ASSUME(), qFatal() + \note Use the macro Q_UNREACHABLE_RETURN() to insert return statements for + compilers that need them, without causing warnings for compilers that + complain about its presence. + + \sa Q_ASSERT(), qFatal(), Q_UNREACHABLE_RETURN() */ +/*! + \macro void Q_UNREACHABLE_RETURN(...) + \relates <QtAssert> + \since 6.5 + + This is equivalent to + \code + Q_UNREACHABLE(); + return __VA_ARGS__; + \endcode + except it omits the return on compilers that would warn about it. + + \sa Q_UNREACHABLE() +*/ QT_END_NAMESPACE |