summaryrefslogtreecommitdiff
path: root/rust/kernel/build_assert.rs
diff options
context:
space:
mode:
authorGary Guo <gary@garyguo.net>2022-11-10 19:41:38 +0300
committerMiguel Ojeda <ojeda@kernel.org>2022-12-04 03:59:16 +0300
commit0f595bab9d1c1a10c6ab5ff3f9140cfc26600349 (patch)
tree848a0f13def8d161ca436769396231263e188b8b /rust/kernel/build_assert.rs
parentecaa6ddff2fd843c0236a931bcc62bf239956617 (diff)
downloadlinux-0f595bab9d1c1a10c6ab5ff3f9140cfc26600349.tar.xz
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>
Diffstat (limited to 'rust/kernel/build_assert.rs')
-rw-r--r--rust/kernel/build_assert.rs82
1 files changed, 82 insertions, 0 deletions
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..659542393c09
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -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);
+ }
+ }};
+}