kernel/build_assert.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
// SPDX-License-Identifier: GPL-2.0
//! Various assertions that happen during build-time.
//!
//! There are three types of build-time assertions that you can use:
//! - [`static_assert!`]
//! - [`const_assert!`]
//! - [`build_assert!`]
//!
//! The ones towards the bottom of the list are more expressive, while the ones towards the top of
//! the list are more robust and trigger earlier in the compilation pipeline. Therefore, you should
//! prefer the ones towards the top of the list wherever possible.
//!
//! # Choosing the correct assertion
//!
//! If you're asserting outside any bodies (e.g. initializers or function bodies), you should use
//! [`static_assert!`] as it is the only assertion that can be used in that context.
//!
//! Inside bodies, if your assertion condition does not depend on any variable or generics, you
//! should use [`static_assert!`]. If the condition depends on generics, but not variables
//! (including function arguments), you should use [`const_assert!`]. Otherwise, use
//! [`build_assert!`]. The same is true regardless if the function is `const fn`.
//!
//! ```
//! // Outside any bodies.
//! static_assert!(core::mem::size_of::<u8>() == 1);
//! // `const_assert!` and `build_assert!` cannot be used here, they will fail to compile.
//!
//! #[inline(always)]
//! fn foo<const N: usize>(v: usize) {
//! static_assert!(core::mem::size_of::<u8>() == 1); // Preferred.
//! const_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
//! build_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
//!
//! // `static_assert!(N > 1);` is not allowed.
//! const_assert!(N > 1); // Preferred.
//! build_assert!(N > 1); // Discouraged.
//!
//! // `static_assert!(v > 1);` is not allowed.
//! // `const_assert!(v > 1);` is not allowed.
//! build_assert!(v > 1); // Works.
//! }
//! ```
//!
//! # Detailed behavior
//!
//! `static_assert!()` is equivalent to `static_assert` in C. It requires `expr` to be a constant
//! expression. This expression cannot refer to any generics. A `static_assert!(expr)` in a program
//! is always evaluated, regardless if the function it appears in is used or not. This is also the
//! only usable assertion outside a body.
//!
//! `const_assert!()` has no direct C equivalence. It is a more powerful version of
//! `static_assert!()`, where it may refer to generics in a function. Note that due to the ability
//! to refer to generics, the assertion is tied to a specific instance of a function. So if it is
//! used in a generic function that is not instantiated, the assertion will not be checked. For this
//! reason, `static_assert!()` is preferred wherever possible.
//!
//! `build_assert!()` is equivalent to `BUILD_BUG_ON`. It is even more powerful than
//! `const_assert!()` because it can be used to check tautologies that depend on runtime value (this
//! is the same as `BUILD_BUG_ON`). However, the assertion failure mechanism can possibly be
//! undefined symbols and linker errors, it is not developer friendly to debug, so it is recommended
//! to avoid it and prefer other two assertions where possible.
pub use crate::{
build_assert,
build_error,
const_assert,
static_assert, //
};
#[doc(hidden)]
pub use build_error::build_error;
/// Static assert (i.e. compile-time assert).
///
/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
///
/// An optional panic message can be supplied after the expression.
/// Currently only a string literal without formatting is supported
/// due to constness limitations of the [`assert!`] macro.
///
/// The feature may be added to Rust in the future: see [RFC 2790].
///
/// You cannot refer to generics or variables with [`static_assert!`]. If you need to refer to
/// generics, use [`const_assert!`]; if you need to refer to variables, use [`build_assert!`]. See
/// the [module documentation](self).
///
/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
///
/// # Examples
///
/// ```
/// static_assert!(42 > 24);
/// static_assert!(core::mem::size_of::<u8>() == 1);
///
/// const X: &[u8] = b"bar";
/// static_assert!(X[1] == b'a');
///
/// const fn f(x: i32) -> i32 {
/// x + 2
/// }
/// static_assert!(f(40) == 42);
/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input.");
/// ```
#[macro_export]
macro_rules! static_assert {
($condition:expr $(,$arg:literal)?) => {
const _: () = ::core::assert!($condition $(,$arg)?);
};
}
/// Assertion during constant evaluation.
///
/// This is a more powerful version of [`static_assert!`] that can refer to generics inside
/// functions or implementation blocks. However, it also has a limitation where it can only appear
/// in places where statements can appear; for example, you cannot use it as an item in the module.
///
/// [`static_assert!`] should be preferred if no generics are referred to in the condition. You
/// cannot refer to variables with [`const_assert!`] (even inside `const fn`); if you need the
/// capability, use [`build_assert!`]. See the [module documentation](self).
///
/// # Examples
///
/// ```
/// fn foo<const N: usize>() {
/// const_assert!(N > 1);
/// }
///
/// fn bar<T>() {
/// const_assert!(size_of::<T>() > 0, "T cannot be ZST");
/// }
/// ```
#[macro_export]
macro_rules! const_assert {
($condition:expr $(,$arg:literal)?) => {
const { ::core::assert!($condition $(,$arg)?) };
};
}
/// 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
///
/// ```
/// #[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_assert::build_error("")
}};
($msg:expr) => {{
$crate::build_assert::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.
///
/// When a condition depends on a function argument, the function must be annotated with
/// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the
/// function, preventing it from optimizing out the error path.
///
/// If the assertion condition does not depend on any variables or generics, you should use
/// [`static_assert!`]. If the assertion condition does not depend on variables, but does depend on
/// generics, you should use [`const_assert!`]. See the [module documentation](self).
///
/// # Examples
///
/// ```
/// #[inline(always)] // Important.
/// fn bar(n: usize) {
/// build_assert!(n > 1);
/// }
///
/// fn foo() {
/// bar(2);
/// }
///
/// #[inline(always)] // Important.
/// const fn const_bar(n: usize) {
/// build_assert!(n > 1);
/// }
///
/// const _: () = const_bar(2);
/// ```
#[macro_export]
macro_rules! build_assert {
($cond:expr $(,)?) => {{
if !$cond {
$crate::build_assert::build_error(concat!("assertion failed: ", stringify!($cond)));
}
}};
($cond:expr, $msg:expr) => {{
if !$cond {
$crate::build_assert::build_error($msg);
}
}};
}