2022-04-28 16:24:11 +00:00
|
|
|
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
|
|
|
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2015-01-21 01:16:47 +00:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2022-06-07 22:05:32 +00:00
|
|
|
#include <functional>
|
|
|
|
|
2015-05-12 05:52:31 +00:00
|
|
|
#include "common/logging/log.h"
|
2015-01-21 01:16:47 +00:00
|
|
|
|
2021-04-02 06:43:26 +00:00
|
|
|
// 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.
|
2022-06-07 21:02:29 +00:00
|
|
|
|
2015-02-18 04:06:48 +00:00
|
|
|
// 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
|
2022-06-07 22:05:32 +00:00
|
|
|
// lambda and force the compiler to not inline it.
|
|
|
|
void assert_check_condition(bool cond, std::function<void()>&& on_failure);
|
|
|
|
|
|
|
|
[[noreturn]] void unreachable_impl();
|
2015-02-18 04:06:48 +00:00
|
|
|
|
2016-09-18 00:38:01 +00:00
|
|
|
#define ASSERT(_a_) \
|
2022-06-07 22:05:32 +00:00
|
|
|
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!"); }); \
|
2016-09-18 00:38:01 +00:00
|
|
|
} \
|
2022-06-07 22:05:32 +00:00
|
|
|
} while (0)
|
2016-09-18 00:38:01 +00:00
|
|
|
|
|
|
|
#define ASSERT_MSG(_a_, ...) \
|
2022-06-07 22:05:32 +00:00
|
|
|
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__); }); \
|
2016-09-18 00:38:01 +00:00
|
|
|
} \
|
2022-06-07 22:05:32 +00:00
|
|
|
} while (0)
|
2015-01-21 01:16:47 +00:00
|
|
|
|
2022-06-07 21:02:29 +00:00
|
|
|
#define UNREACHABLE() \
|
|
|
|
do { \
|
2022-06-07 22:05:32 +00:00
|
|
|
LOG_CRITICAL(Debug, "Unreachable code!"); \
|
2022-06-07 21:02:29 +00:00
|
|
|
unreachable_impl(); \
|
|
|
|
} while (0)
|
|
|
|
|
2019-10-05 14:54:07 +00:00
|
|
|
#define UNREACHABLE_MSG(...) \
|
2022-06-07 21:02:29 +00:00
|
|
|
do { \
|
2022-06-07 22:05:32 +00:00
|
|
|
LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); \
|
2022-06-07 21:02:29 +00:00
|
|
|
unreachable_impl(); \
|
|
|
|
} while (0)
|
2015-01-21 01:16:47 +00:00
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
|
|
|
|
#define DEBUG_ASSERT_MSG(_a_, ...) ASSERT_MSG(_a_, __VA_ARGS__)
|
|
|
|
#else // not debug
|
2021-08-05 17:46:22 +00:00
|
|
|
#define DEBUG_ASSERT(_a_) \
|
|
|
|
do { \
|
|
|
|
} while (0)
|
|
|
|
#define DEBUG_ASSERT_MSG(_a_, _desc_, ...) \
|
|
|
|
do { \
|
|
|
|
} while (0)
|
2015-01-21 01:16:47 +00:00
|
|
|
#endif
|
|
|
|
|
2018-11-20 22:58:57 +00:00
|
|
|
#define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!")
|
2018-01-07 22:43:41 +00:00
|
|
|
#define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
|
common/assert: Add UNIMPLEMENTED_IF and UNIMPLEMENTED_IF_MSG for conditional assertions
Currently, there's no way to specify if an assertion should
conditionally occur due to unimplemented behavior. This is useful when
something is only partially implemented (e.g. due to ongoing RE work).
In particular, this would be useful within the graphics code.
The rationale behind this is it allows a dev to disable unimplemented
feature assertions (which can occur in an unrelated work area), while
still enabling regular assertions, which act as behavior guards for
conditions or states which must not occur. Previously, the only way a
dev could temporarily disable asserts, was to disable the regular
assertion macros, which has the downside of also disabling, well, the
regular assertions which hold more sanitizing value, as opposed to
unimplemented feature assertions.
2018-11-20 23:03:00 +00:00
|
|
|
|
|
|
|
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
|
|
|
|
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
|
2019-03-27 18:59:00 +00:00
|
|
|
|
|
|
|
// If the assert is ignored, execute _b_
|
|
|
|
#define ASSERT_OR_EXECUTE(_a_, _b_) \
|
|
|
|
do { \
|
|
|
|
ASSERT(_a_); \
|
|
|
|
if (!(_a_)) { \
|
|
|
|
_b_ \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
// If the assert is ignored, execute _b_
|
|
|
|
#define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \
|
|
|
|
do { \
|
|
|
|
ASSERT_MSG(_a_, __VA_ARGS__); \
|
|
|
|
if (!(_a_)) { \
|
|
|
|
_b_ \
|
|
|
|
} \
|
|
|
|
} while (0)
|