diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs index d464494d430a..50b0fc0a80fc 100644 --- a/rust/kernel/build_assert.rs +++ b/rust/kernel/build_assert.rs @@ -41,6 +41,30 @@ macro_rules! static_assert { }; } +/// 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. +/// +/// # Examples +/// +/// ``` +/// fn foo() { +/// const_assert!(N > 1); +/// } +/// +/// fn bar() { +/// const_assert!(size_of::() > 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. diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index fa81acbdc8c2..54d0ce3ba595 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -255,9 +255,7 @@ impl Bounded<$type, N> { /// ``` pub const fn new() -> Self { // Statically assert that `VALUE` fits within the set number of bits. - const { - assert!(fits_within!(VALUE, $type, N)); - } + const_assert!(fits_within!(VALUE, $type, N)); // SAFETY: `fits_within` confirmed that `VALUE` can be represented within // `N` bits. @@ -287,12 +285,10 @@ impl Bounded /// The caller must ensure that `value` can be represented within `N` bits. const unsafe fn __new(value: T) -> Self { // Enforce the type invariants. - const { - // `N` cannot be zero. - assert!(N != 0); - // The backing type is at least as large as `N` bits. - assert!(N <= T::BITS); - } + // `N` cannot be zero. + const_assert!(N != 0); + // The backing type is at least as large as `N` bits. + const_assert!(N <= T::BITS); // INVARIANT: The caller ensures `value` fits within `N` bits. Self(value) @@ -406,12 +402,10 @@ pub fn get(self) -> T { /// assert_eq!(larger_v, v); /// ``` pub const fn extend(self) -> Bounded { - const { - assert!( - M >= N, - "Requested number of bits is less than the current representation." - ); - } + const_assert!( + M >= N, + "Requested number of bits is less than the current representation." + ); // SAFETY: The value did fit within `N` bits, so it will all the more fit within // the larger `M` bits. diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 2e9454472818..6a54597fa0a2 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -32,6 +32,7 @@ pub use super::{ build_assert, build_error, + const_assert, static_assert, // }; diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs index 5b6a382637fe..512e2eabe3ad 100644 --- a/rust/kernel/ptr.rs +++ b/rust/kernel/ptr.rs @@ -5,6 +5,8 @@ use core::mem::align_of; use core::num::NonZero; +use crate::const_assert; + /// Type representing an alignment, which is always a power of two. /// /// It is used to validate that a given value is a valid alignment, and to perform masking and @@ -38,12 +40,10 @@ impl Alignment { /// ``` #[inline(always)] pub const fn new() -> Self { - const { - assert!( - ALIGN.is_power_of_two(), - "Provided alignment is not a power of two." - ); - } + const_assert!( + ALIGN.is_power_of_two(), + "Provided alignment is not a power of two." + ); // INVARIANT: `align` is a power of two. // SAFETY: `align` is a power of two, and thus non-zero. diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 32e209bc7985..0328afd5ee96 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -310,6 +310,7 @@ $(obj)/%.lst: $(obj)/%.c FORCE # The features in this list are the ones allowed for non-`rust/` code. # +# - Stable since Rust 1.79.0: `feature(inline_const)`. # - Stable since Rust 1.81.0: `feature(lint_reasons)`. # - Stable since Rust 1.82.0: `feature(asm_const)`, # `feature(offset_of_nested)`, `feature(raw_ref_op)`. @@ -319,7 +320,7 @@ $(obj)/%.lst: $(obj)/%.c FORCE # # Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on # the unstable features in use. -rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg +rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,inline_const,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg # `--out-dir` is required to avoid temporaries being created by `rustc` in the # current working directory, which may be not accessible in the out-of-tree