diff options
| author | Liam <byteslice@airmail.cc> | 2022-06-07 18:05:32 -0400 | 
|---|---|---|
| committer | Liam <byteslice@airmail.cc> | 2022-06-13 20:09:00 -0400 | 
| commit | 58fea44eb5bfe268c1ddd2ea063744eb7bbe7e44 (patch) | |
| tree | 52b3e426fa061171cab80a7b61ab6e52aa163966 | |
| parent | 084d7d6b014443be7625fb9d8f1ddd309a22f6f4 (diff) | |
common: Don't test ASSERT conditions inline
| -rw-r--r-- | src/common/assert.cpp | 10 | ||||
| -rw-r--r-- | src/common/assert.h | 58 | 
2 files changed, 36 insertions, 32 deletions
| diff --git a/src/common/assert.cpp b/src/common/assert.cpp index a27a025ae..b20c19123 100644 --- a/src/common/assert.cpp +++ b/src/common/assert.cpp @@ -6,9 +6,13 @@  #include "common/settings.h" -void assert_handle_failure() { -    if (Settings::values.use_debug_asserts) { -        Crash(); +void assert_check_condition(bool cond, std::function<void()>&& on_failure) { +    if (!cond) { +        on_failure(); + +        if (Settings::values.use_debug_asserts) { +            Crash(); +        }      }  } diff --git a/src/common/assert.h b/src/common/assert.h index 478bfa856..fb7808657 100644 --- a/src/common/assert.h +++ b/src/common/assert.h @@ -4,57 +4,57 @@  #pragma once +#include <functional> +  #include "common/logging/log.h"  // Sometimes we want to try to continue even after hitting an assert.  // However touching this file yields a global recompilation as this header is included almost  // everywhere. So let's just move the handling of the failed assert to a single cpp file. -void assert_handle_failure(); - -[[noreturn]] void unreachable_impl();  // For asserts we'd like to keep all the junk executed when an assert happens away from the  // important code in the function. One way of doing this is to put all the relevant code inside a -// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to -// specify __declspec on lambda functions, so what we do instead is define a noinline wrapper -// template that calls the lambda. This seems to generate an extra instruction at the call-site -// compared to the ideal implementation (which wouldn't support ASSERT_MSG parameters), but is good -// enough for our purposes. -template <typename Fn> -#if defined(_MSC_VER) -[[msvc::noinline]] -#elif defined(__GNUC__) -[[gnu::cold, gnu::noinline]] -#endif -static void -assert_noinline_call(const Fn& fn) { -    fn(); -    assert_handle_failure(); -} +// lambda and force the compiler to not inline it. +void assert_check_condition(bool cond, std::function<void()>&& on_failure); + +[[noreturn]] void unreachable_impl();  #define ASSERT(_a_)                                                                                \ -    do                                                                                             \ -        if (!(_a_)) {                                                                              \ -            assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); });                \ +    do {                                                                                           \ +        if (std::is_constant_evaluated()) {                                                        \ +            if (!(_a_)) {                                                                          \ +                /* Will trigger compile error here */                                              \ +                assert_check_condition(bool(_a_),                                                  \ +                                       [] { LOG_CRITICAL(Debug, "Assertion Failed!"); });          \ +            }                                                                                      \ +        } else {                                                                                   \ +            assert_check_condition(bool(_a_), [] { LOG_CRITICAL(Debug, "Assertion Failed!"); });   \          }                                                                                          \ -    while (0) +    } while (0)  #define ASSERT_MSG(_a_, ...)                                                                       \ -    do                                                                                             \ -        if (!(_a_)) {                                                                              \ -            assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \ +    do {                                                                                           \ +        if (std::is_constant_evaluated()) {                                                        \ +            if (!(_a_)) {                                                                          \ +                /* Will trigger compile error here */                                              \ +                assert_check_condition(bool(_a_),                                                  \ +                                       [] { LOG_CRITICAL(Debug, "Assertion Failed!"); });          \ +            }                                                                                      \ +        } else {                                                                                   \ +            assert_check_condition(                                                                \ +                bool(_a_), [&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); });       \          }                                                                                          \ -    while (0) +    } while (0)  #define UNREACHABLE()                                                                              \      do {                                                                                           \ -        assert_noinline_call([] { LOG_CRITICAL(Debug, "Unreachable code!"); });                    \ +        LOG_CRITICAL(Debug, "Unreachable code!");                                                  \          unreachable_impl();                                                                        \      } while (0)  #define UNREACHABLE_MSG(...)                                                                       \      do {                                                                                           \ -        assert_noinline_call([&] { LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); });     \ +        LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__);                                    \          unreachable_impl();                                                                        \      } while (0) | 
