/** * @file Check.h * @author apio (cloudapio.eu) * @brief Always-enabled assertions. * * @copyright Copyright (c) 2022-2023, the Luna authors. * */ #pragma once #include /** * @brief Called when a libluna assertion fails. Some targets already have implementations of this function, but * otherwise it must be implemented by the user. * * In the kernel, the implementation is in src/Log.cpp. * For POSIX systems, libluna provides an implementation in src/ImplPOSIX.cpp. * * @param location The source location at which the assertion failure occurred. * @param expr The expression or custom error message to display. * @return bool Unused, since the function never returns. */ [[noreturn]] extern bool __check_failed(SourceLocation location, const char* expr); #ifndef STRINGIZE_VALUE_OF #define STRINGIZE(x) #x #define STRINGIZE_VALUE_OF(x) STRINGIZE(x) #endif /** * @brief Verify an expression is true, or crash at runtime with a custom error message. */ #define expect(expr, message) \ do { \ if (!(expr)) [[unlikely]] { __check_failed(SourceLocation::current(), message); } \ } while (0) /** * @brief Verify an expression is true, or crash at runtime with a custom error message, indicating a different source * location (useful for reporting caller errors, see Result::release_value() for an example). */ #define expect_at(expr, location, message) \ do { \ if (!(expr)) [[unlikely]] { __check_failed(location, message); } \ } while (0) /** * @brief Crash at runtime with a custom error message. */ #define fail(message) __check_failed(SourceLocation::current(), message) /** * @brief Crash at runtime with a custom error message, indicating a different source location (useful for * reporting caller errors, see Result::release_value() for an example). */ #define fail_at(location, message) __check_failed(location, message) /** * @brief Verify an expression is true, or crash at runtime. */ #define check(expr) \ do { \ if (!(expr)) [[unlikely]] { __check_failed(SourceLocation::current(), #expr); } \ } while (0) /** * @brief Verify an expression is true, or crash at runtime, indicating a different source location (useful for * reporting caller errors, see Result::release_value() for an example). */ #define check_at(expr, location) \ do { \ if (!(expr)) [[unlikely]] { __check_failed(location, #expr); } \ } while (0) /** * @brief Mark a code section as unreachable, which will crash if reached. * * Often it may be more performant to use the compiler's __builtin_unreachable() for this purpose (when the code is * clearly unreachable but the compiler cannot figure it out on its own, see the implementation of _exit() in libc), if * there is just no possible way for execution flow to reach this code segment, but the compiler builtin results in * undefined behavior if reached. Therefore, if a bug may cause this unreachable code to be reached, you may prefer to * use this macro as it has well-defined behavior (crashes at runtime). */ #define unreachable() __check_failed(SourceLocation::current(), "Reached unreachable code") /** * @brief Mark a code section as unimplemented, which will crash if reached. */ #define todo() __check_failed(SourceLocation::current(), "Reached a TODO!")