* [PATCH v2 2/4] rust: add `const_assert!` macro
[not found] <20260316150720.1646109-1-gary@kernel.org>
@ 2026-03-16 15:07 ` Gary Guo
2026-03-16 17:34 ` Yury Norov
0 siblings, 1 reply; 3+ messages in thread
From: Gary Guo @ 2026-03-16 15:07 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Alexandre Courbot, Yury Norov,
Nathan Chancellor, Nicolas Schier
Cc: rust-for-linux, linux-kernel, linux-kbuild
From: Gary Guo <gary@garyguo.net>
The macro is a more powerful version of `static_assert!` for use inside
function contexts. This is powered by inline consts, so enable the feature
for old compiler versions that does not have it stably.
While it is possible already to write `const { assert!(...) }`, this
provides a short hand that is more uniform with other assertions. It also
formats nicer with rustfmt where it will not be formatted into multiple
lines.
Two users that would route via the Rust tree are converted.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/build_assert.rs | 24 ++++++++++++++++++++++++
rust/kernel/num/bounded.rs | 24 +++++++++---------------
rust/kernel/prelude.rs | 7 ++++++-
rust/kernel/ptr.rs | 12 ++++++------
scripts/Makefile.build | 5 +++--
5 files changed, 48 insertions(+), 24 deletions(-)
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
index d464494d430a..51c0f85a9014 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 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.
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<const N: u32> Bounded<$type, N> {
/// ```
pub const fn new<const VALUE: $type>() -> 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<T, const N: u32> Bounded<T, N>
/// 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<const M: u32>(self) -> Bounded<T, M> {
- 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 c7e91b80d301..6a54597fa0a2 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -29,7 +29,12 @@
pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable};
-pub use super::{build_assert, build_error, static_assert};
+pub use super::{
+ build_assert,
+ build_error,
+ const_assert,
+ static_assert, //
+};
// `super::std_vendor` is hidden, which makes the macro inline for some reason.
#[doc(no_inline)]
diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
index bdc2d79ff669..d05e5888e80c 100644
--- a/rust/kernel/ptr.rs
+++ b/rust/kernel/ptr.rs
@@ -11,6 +11,8 @@
};
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
@@ -44,12 +46,10 @@ impl Alignment {
/// ```
#[inline(always)]
pub const fn new<const ALIGN: usize>() -> 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 3652b85be545..960b4630cb2c 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -310,7 +310,8 @@ $(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(slice_ptr_len)`.
+# - Stable since Rust 1.79.0: `feature(inline_const)`,
+# `feature(slice_ptr_len)`,
# - 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)`.
@@ -321,7 +322,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,slice_ptr_len,strict_provenance,used_with_arg
+rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,inline_const,lint_reasons,offset_of_nested,raw_ref_op,slice_ptr_len,strict_provenance,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
--
2.51.2
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v2 2/4] rust: add `const_assert!` macro
2026-03-16 15:07 ` [PATCH v2 2/4] rust: add `const_assert!` macro Gary Guo
@ 2026-03-16 17:34 ` Yury Norov
2026-03-16 18:35 ` Miguel Ojeda
0 siblings, 1 reply; 3+ messages in thread
From: Yury Norov @ 2026-03-16 17:34 UTC (permalink / raw)
To: Gary Guo
Cc: Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Alexandre Courbot, Yury Norov, Nathan Chancellor, Nicolas Schier,
rust-for-linux, linux-kernel, linux-kbuild
On Mon, Mar 16, 2026 at 03:07:13PM +0000, Gary Guo wrote:
> From: Gary Guo <gary@garyguo.net>
>
> The macro is a more powerful version of `static_assert!` for use inside
> function contexts. This is powered by inline consts, so enable the feature
> for old compiler versions that does not have it stably.
>
> While it is possible already to write `const { assert!(...) }`, this
> provides a short hand that is more uniform with other assertions. It also
> formats nicer with rustfmt where it will not be formatted into multiple
> lines.
>
> Two users that would route via the Rust tree are converted.
>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> ---
> rust/kernel/build_assert.rs | 24 ++++++++++++++++++++++++
> rust/kernel/num/bounded.rs | 24 +++++++++---------------
> rust/kernel/prelude.rs | 7 ++++++-
> rust/kernel/ptr.rs | 12 ++++++------
> scripts/Makefile.build | 5 +++--
> 5 files changed, 48 insertions(+), 24 deletions(-)
>
> diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
> index d464494d430a..51c0f85a9014 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
This line is 101 lanes. Can you split it?
> +/// 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 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.
> 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<const N: u32> Bounded<$type, N> {
> /// ```
> pub const fn new<const VALUE: $type>() -> 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<T, const N: u32> Bounded<T, N>
> /// 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<const M: u32>(self) -> Bounded<T, M> {
> - 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 c7e91b80d301..6a54597fa0a2 100644
> --- a/rust/kernel/prelude.rs
> +++ b/rust/kernel/prelude.rs
> @@ -29,7 +29,12 @@
>
> pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable};
>
> -pub use super::{build_assert, build_error, static_assert};
> +pub use super::{
> + build_assert,
> + build_error,
> + const_assert,
> + static_assert, //
> +};
>
> // `super::std_vendor` is hidden, which makes the macro inline for some reason.
> #[doc(no_inline)]
> diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
> index bdc2d79ff669..d05e5888e80c 100644
> --- a/rust/kernel/ptr.rs
> +++ b/rust/kernel/ptr.rs
> @@ -11,6 +11,8 @@
> };
> 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
> @@ -44,12 +46,10 @@ impl Alignment {
> /// ```
> #[inline(always)]
> pub const fn new<const ALIGN: usize>() -> 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 3652b85be545..960b4630cb2c 100644
> --- a/scripts/Makefile.build
> +++ b/scripts/Makefile.build
> @@ -310,7 +310,8 @@ $(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(slice_ptr_len)`.
> +# - Stable since Rust 1.79.0: `feature(inline_const)`,
> +# `feature(slice_ptr_len)`,
> # - 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)`.
> @@ -321,7 +322,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,slice_ptr_len,strict_provenance,used_with_arg
> +rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,inline_const,lint_reasons,offset_of_nested,raw_ref_op,slice_ptr_len,strict_provenance,used_with_arg
Same here. Miguel mentioned in the other thread that newer version of
rust will make this list shorter, but once that didn't happen, let's
follow rules?
>
> # `--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
> --
> 2.51.2
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2 2/4] rust: add `const_assert!` macro
2026-03-16 17:34 ` Yury Norov
@ 2026-03-16 18:35 ` Miguel Ojeda
0 siblings, 0 replies; 3+ messages in thread
From: Miguel Ojeda @ 2026-03-16 18:35 UTC (permalink / raw)
To: Yury Norov
Cc: Gary Guo, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Alexandre Courbot, Yury Norov,
Nathan Chancellor, Nicolas Schier, rust-for-linux, linux-kernel,
linux-kbuild
On Mon, Mar 16, 2026 at 6:34 PM Yury Norov <ynorov@nvidia.com> wrote:
>
> Same here. Miguel mentioned in the other thread that newer version of
> rust will make this list shorter, but once that didn't happen, let's
> follow rules?
It is not a hard limit, and there are a couple other nearby lines even
longer than this one. The new one will be 82 columns long (including
the addition here).
To be honest, I don't think it is worth making this patch series more
involved for a single line that will be temporary (or it may not even
happen depending on the order things land).
If we want to do it, then I would suggest doing it in another patch
(and likely in another patch series too).
Cheers,
Miguel
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-03-16 18:35 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260316150720.1646109-1-gary@kernel.org>
2026-03-16 15:07 ` [PATCH v2 2/4] rust: add `const_assert!` macro Gary Guo
2026-03-16 17:34 ` Yury Norov
2026-03-16 18:35 ` Miguel Ojeda
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox