rust: build_assert: add `build_{error,assert}!` macros
Add the `build_error!` and `build_assert!` macros which leverage the previously introduced `build_error` crate. Do so in a new module, called `build_assert`. The former fails the build if the code path calling it can possibly be executed. The latter asserts that a boolean expression is `true` at compile time. In particular, `build_assert!` can be used in some contexts where `static_assert!` cannot: fn f1<const N: usize>() { static_assert!(N > 1);` // Error. build_assert!(N > 1); // Build-time check. assert!(N > 1); // Run-time check. } #[inline] fn f2(n: usize) { static_assert!(n > 1); // Error. build_assert!(n > 1); // Build-time check. assert!(n > 1); // Run-time check. } Signed-off-by: Gary Guo <gary@garyguo.net> Reviewed-by: Wei Liu <wei.liu@kernel.org> [Reworded, adapted for upstream and applied latest changes] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
Родитель
ecaa6ddff2
Коммит
0f595bab9d
|
@ -0,0 +1,82 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! Build-time assert.
|
||||
|
||||
/// Fails the build if the code path calling `build_error!` can possibly be executed.
|
||||
///
|
||||
/// If the macro is executed in const context, `build_error!` will panic.
|
||||
/// If the compiler or optimizer cannot guarantee that `build_error!` can never
|
||||
/// be called, a build error will be triggered.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use kernel::build_error;
|
||||
/// #[inline]
|
||||
/// fn foo(a: usize) -> usize {
|
||||
/// a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK.
|
||||
/// // foo(usize::MAX); // Fails to compile.
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! build_error {
|
||||
() => {{
|
||||
$crate::build_error("")
|
||||
}};
|
||||
($msg:expr) => {{
|
||||
$crate::build_error($msg)
|
||||
}};
|
||||
}
|
||||
|
||||
/// Asserts that a boolean expression is `true` at compile time.
|
||||
///
|
||||
/// If the condition is evaluated to `false` in const context, `build_assert!`
|
||||
/// will panic. If the compiler or optimizer cannot guarantee the condition will
|
||||
/// be evaluated to `true`, a build error will be triggered.
|
||||
///
|
||||
/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// These examples show that different types of [`assert!`] will trigger errors
|
||||
/// at different stage of compilation. It is preferred to err as early as
|
||||
/// possible, so [`static_assert!`] should be used whenever possible.
|
||||
/// ```ignore
|
||||
/// fn foo() {
|
||||
/// static_assert!(1 > 1); // Compile-time error
|
||||
/// build_assert!(1 > 1); // Build-time error
|
||||
/// assert!(1 > 1); // Run-time error
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// When the condition refers to generic parameters or parameters of an inline function,
|
||||
/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
|
||||
/// ```
|
||||
/// fn foo<const N: usize>() {
|
||||
/// // `static_assert!(N > 1);` is not allowed
|
||||
/// build_assert!(N > 1); // Build-time check
|
||||
/// assert!(N > 1); // Run-time check
|
||||
/// }
|
||||
///
|
||||
/// #[inline]
|
||||
/// fn bar(n: usize) {
|
||||
/// // `static_assert!(n > 1);` is not allowed
|
||||
/// build_assert!(n > 1); // Build-time check
|
||||
/// assert!(n > 1); // Run-time check
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! build_assert {
|
||||
($cond:expr $(,)?) => {{
|
||||
if !$cond {
|
||||
$crate::build_error(concat!("assertion failed: ", stringify!($cond)));
|
||||
}
|
||||
}};
|
||||
($cond:expr, $msg:expr) => {{
|
||||
if !$cond {
|
||||
$crate::build_error($msg);
|
||||
}
|
||||
}};
|
||||
}
|
|
@ -23,6 +23,7 @@ compile_error!("Missing kernel configuration for conditional compilation");
|
|||
#[cfg(not(test))]
|
||||
#[cfg(not(testlib))]
|
||||
mod allocator;
|
||||
mod build_assert;
|
||||
pub mod error;
|
||||
pub mod prelude;
|
||||
pub mod print;
|
||||
|
@ -35,6 +36,9 @@ pub mod str;
|
|||
pub use bindings;
|
||||
pub use macros;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use build_error::build_error;
|
||||
|
||||
/// Prefix to appear before log messages printed from within the `kernel` crate.
|
||||
const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ pub use alloc::{boxed::Box, vec::Vec};
|
|||
|
||||
pub use macros::{module, vtable};
|
||||
|
||||
pub use super::build_assert;
|
||||
|
||||
pub use super::{dbg, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
|
||||
|
||||
pub use super::static_assert;
|
||||
|
|
Загрузка…
Ссылка в новой задаче