diff --git a/libluna/include/luna/Check.h b/libluna/include/luna/Check.h index 07c5279c..2cb1201b 100644 --- a/libluna/include/luna/Check.h +++ b/libluna/include/luna/Check.h @@ -1,6 +1,26 @@ +/** + * @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 @@ -8,32 +28,63 @@ #define STRINGIZE_VALUE_OF(x) STRINGIZE(x) #endif -// Like check(), but with a custom error message. +/** + * @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) -// Fail with an error message and location. +/** + * @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) -// Like assert(), but always enabled. +/** + * @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!")