public inbox for rust-for-linux@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] rust: move `static_assert` into `build_assert`
@ 2026-02-06 17:12 Gary Guo
  2026-02-06 17:12 ` [PATCH 2/2] rust: add `const_assert!` macro Gary Guo
  0 siblings, 1 reply; 16+ messages in thread
From: Gary Guo @ 2026-02-06 17:12 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich
  Cc: linux-kernel, rust-for-linux

From: Gary Guo <gary@garyguo.net>

Conceptually, `static_assert` is also a build-time assertion that occurs
earlier in the pipeline. Conslidate the implementation so that we can use
this as the canonical place to add more useful build-time assertions.

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 rust/kernel/build_assert.rs  | 40 +++++++++++++++++++++++++++++++++---
 rust/kernel/lib.rs           |  1 -
 rust/kernel/prelude.rs       |  4 +---
 rust/kernel/static_assert.rs | 39 -----------------------------------
 4 files changed, 38 insertions(+), 46 deletions(-)
 delete mode 100644 rust/kernel/static_assert.rs

diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
index f8124dbc663f..d464494d430a 100644
--- a/rust/kernel/build_assert.rs
+++ b/rust/kernel/build_assert.rs
@@ -1,10 +1,46 @@
 // SPDX-License-Identifier: GPL-2.0
 
-//! Build-time assert.
+//! Various assertions that happen during build-time.
 
 #[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].
+///
+/// [`_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)?);
+    };
+}
+
 /// 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.
@@ -74,8 +110,6 @@ macro_rules! build_error {
 ///     assert!(n > 1); // Run-time check
 /// }
 /// ```
-///
-/// [`static_assert!`]: crate::static_assert!
 #[macro_export]
 macro_rules! build_assert {
     ($cond:expr $(,)?) => {{
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 42120b0b45da..0cbc91695f57 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -141,7 +141,6 @@
 pub mod slice;
 #[cfg(CONFIG_SOC_BUS)]
 pub mod soc;
-mod static_assert;
 #[doc(hidden)]
 pub mod std_vendor;
 pub mod str;
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 2877e3f7b6d3..c7e91b80d301 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -29,7 +29,7 @@
 
 pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable};
 
-pub use super::{build_assert, build_error};
+pub use super::{build_assert, build_error, static_assert};
 
 // `super::std_vendor` is hidden, which makes the macro inline for some reason.
 #[doc(no_inline)]
@@ -39,8 +39,6 @@
 
 pub use super::{try_init, try_pin_init};
 
-pub use super::static_assert;
-
 pub use super::error::{code::*, Error, Result};
 
 pub use super::{str::CStrExt as _, ThisModule};
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
deleted file mode 100644
index a57ba14315a0..000000000000
--- a/rust/kernel/static_assert.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-//! Static assert.
-
-/// 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].
-///
-/// [`_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)?);
-    };
-}

base-commit: 4c87cdd0328495759f6e9f9f4e1e53ef8032a76f
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-06 17:12 [PATCH 1/2] rust: move `static_assert` into `build_assert` Gary Guo
@ 2026-02-06 17:12 ` Gary Guo
  2026-02-06 21:30   ` Benno Lossin
                     ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Gary Guo @ 2026-02-06 17:12 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: linux-kernel, rust-for-linux, 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.

The `build_assert!` doc is refined to recommend it where possible.

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 | 55 +++++++++++++++++++++++++++++++++----
 rust/kernel/num/bounded.rs  | 24 ++++++----------
 rust/kernel/prelude.rs      |  2 +-
 rust/kernel/ptr.rs          | 18 ++++++------
 scripts/Makefile.build      |  3 +-
 5 files changed, 71 insertions(+), 31 deletions(-)

diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
index d464494d430a..e40f0227e1ef 100644
--- a/rust/kernel/build_assert.rs
+++ b/rust/kernel/build_assert.rs
@@ -41,6 +41,45 @@ 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 have 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 where possible.
+///
+/// # Examples
+///
+/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
+/// Use `const_assert!` in this scenario.
+/// ```
+/// fn foo<const N: usize>() {
+///     // `static_assert!(N > 1);` is not allowed
+///     const_assert!(N > 1); // Compile-time check
+///     build_assert!(N > 1); // Build-time check
+///     assert!(N > 1); // Run-time check
+/// }
+/// ```
+///
+/// Note that `const_assert!` cannot be used when referring to function parameter, then
+/// `const_assert!` cannot be used even if the function is going to be called during const
+/// evaluation. Use `build_assert!` in this case.
+/// ```
+/// const fn foo(n: usize) {
+///     // `const_assert!(n > 1);` is not allowed
+///     build_assert!(n > 1);
+/// }
+///
+/// const _: () = foo(2); // Evaluate during const evaluation
+/// ```
+#[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.
@@ -74,7 +113,8 @@ macro_rules! build_error {
 /// 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.
+/// [`static_assert!`] or [`const_assert!`] should be preferred to `build_assert!` whenever
+/// possible.
 ///
 /// # Examples
 ///
@@ -84,24 +124,27 @@ macro_rules! build_error {
 /// ```ignore
 /// fn foo() {
 ///     static_assert!(1 > 1); // Compile-time error
+///     const_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.
+/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
+/// `build_assert!` is usable in this scenario, however you should prefer `const_assert!`.
 /// ```
 /// fn foo<const N: usize>() {
 ///     // `static_assert!(N > 1);` is not allowed
+///     const_assert!(N > 1); // Compile-time check
 ///     build_assert!(N > 1); // Build-time check
 ///     assert!(N > 1); // Run-time check
 /// }
 /// ```
 ///
-/// 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.
+/// When the condition refers to parameters of an inline function, neither [`static_assert!`] or
+/// [`const_assert!`] can be used. You may use `build_assert!` in this scenario, however you must
+/// annotate the function `#[inline(always)]`. Without this attribute, the compiler may choose to
+/// not inline the function, preventing it from optimizing out the error path.
 /// ```
 /// #[inline(always)]
 /// fn bar(n: usize) {
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..75c52b5879e3 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -29,7 +29,7 @@
 
 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 5b6a382637fe..0b6acd112c4f 100644
--- a/rust/kernel/ptr.rs
+++ b/rust/kernel/ptr.rs
@@ -2,8 +2,12 @@
 
 //! Types and functions to work with pointers and addresses.
 
-use core::mem::align_of;
-use core::num::NonZero;
+use core::{
+    mem::align_of,
+    num::NonZero, //
+};
+
+use crate::const_assert;
 
 /// Type representing an alignment, which is always a power of two.
 ///
@@ -38,12 +42,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 0c838c467c76..204e58dd1bb0 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -308,6 +308,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)`.
@@ -317,7 +318,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
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-06 17:12 ` [PATCH 2/2] rust: add `const_assert!` macro Gary Guo
@ 2026-02-06 21:30   ` Benno Lossin
  2026-02-06 21:48     ` Gary Guo
  2026-02-06 22:21   ` John Hubbard
  2026-02-13  1:16   ` Yury Norov
  2 siblings, 1 reply; 16+ messages in thread
From: Benno Lossin @ 2026-02-06 21:30 UTC (permalink / raw)
  To: Gary Guo, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Alexandre Courbot, Yury Norov, Nathan Chancellor, Nicolas Schier
  Cc: linux-kernel, rust-for-linux, linux-kbuild

On Fri Feb 6, 2026 at 6:12 PM CET, Gary Guo wrote:
> +/// 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 have 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 where possible.
> +///
> +/// # Examples
> +///
> +/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
> +/// Use `const_assert!` in this scenario.
> +/// ```
> +/// fn foo<const N: usize>() {
> +///     // `static_assert!(N > 1);` is not allowed
> +///     const_assert!(N > 1); // Compile-time check
> +///     build_assert!(N > 1); // Build-time check

I think having "Build-time check" here is a bit confusing, how about we
change it to "Link-time check"? Since a "Compile-time check" also is
done at "Build-time"

Cheers,
Benno

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-06 21:30   ` Benno Lossin
@ 2026-02-06 21:48     ` Gary Guo
  2026-02-08  5:58       ` Yury Norov
  0 siblings, 1 reply; 16+ messages in thread
From: Gary Guo @ 2026-02-06 21:48 UTC (permalink / raw)
  To: Benno Lossin, Gary Guo, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Alexandre Courbot, Yury Norov,
	Nathan Chancellor, Nicolas Schier
  Cc: linux-kernel, rust-for-linux, linux-kbuild

On Fri Feb 6, 2026 at 9:30 PM GMT, Benno Lossin wrote:
> On Fri Feb 6, 2026 at 6:12 PM CET, Gary Guo wrote:
>> +/// 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 have 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 where possible.
>> +///
>> +/// # Examples
>> +///
>> +/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
>> +/// Use `const_assert!` in this scenario.
>> +/// ```
>> +/// fn foo<const N: usize>() {
>> +///     // `static_assert!(N > 1);` is not allowed
>> +///     const_assert!(N > 1); // Compile-time check
>> +///     build_assert!(N > 1); // Build-time check
>
> I think having "Build-time check" here is a bit confusing, how about we
> change it to "Link-time check"? Since a "Compile-time check" also is
> done at "Build-time"

This is the intentional phrasing that I used for `build_assert!` when I created
it, for the reason that `build_assert!` ensure that it will fire, at latest,
link time. However, if you actually use such methods with CTFE, it will error
earlier. So it is "at latest link-time check", so I decided to just use
"build-time".

Best,
Gary

>
> Cheers,
> Benno


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-06 17:12 ` [PATCH 2/2] rust: add `const_assert!` macro Gary Guo
  2026-02-06 21:30   ` Benno Lossin
@ 2026-02-06 22:21   ` John Hubbard
  2026-02-06 22:28     ` Gary Guo
  2026-02-13  1:16   ` Yury Norov
  2 siblings, 1 reply; 16+ messages in thread
From: John Hubbard @ 2026-02-06 22:21 UTC (permalink / raw)
  To: 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
  Cc: linux-kernel, rust-for-linux, linux-kbuild

On 2/6/26 9:12 AM, 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.

This is nice. A nit below about documentation.

> 
> The `build_assert!` doc is refined to recommend it where possible.

Another piece of the puzzle...see below to continue the treasure
hunt.

> 
> 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 | 55 +++++++++++++++++++++++++++++++++----
>  rust/kernel/num/bounded.rs  | 24 ++++++----------
>  rust/kernel/prelude.rs      |  2 +-
>  rust/kernel/ptr.rs          | 18 ++++++------
>  scripts/Makefile.build      |  3 +-
>  5 files changed, 71 insertions(+), 31 deletions(-)
> 
> diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
> index d464494d430a..e40f0227e1ef 100644
> --- a/rust/kernel/build_assert.rs
> +++ b/rust/kernel/build_assert.rs
> @@ -41,6 +41,45 @@ 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 have 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 where possible.

Over what? There are 3 different assertion types. If it is actually
possible to list a clear order of preference, then let's list all
3 in order, rather than having a scattering around of "A is 
better than B", "C is sometimes worse than A", and then the
reader has to play treasure hunt to work it out. haha :)


thanks,
-- 
John Hubbard

> +///
> +/// # Examples
> +///
> +/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
> +/// Use `const_assert!` in this scenario.
> +/// ```
> +/// fn foo<const N: usize>() {
> +///     // `static_assert!(N > 1);` is not allowed
> +///     const_assert!(N > 1); // Compile-time check
> +///     build_assert!(N > 1); // Build-time check
> +///     assert!(N > 1); // Run-time check
> +/// }
> +/// ```
> +///
> +/// Note that `const_assert!` cannot be used when referring to function parameter, then
> +/// `const_assert!` cannot be used even if the function is going to be called during const
> +/// evaluation. Use `build_assert!` in this case.
> +/// ```
> +/// const fn foo(n: usize) {
> +///     // `const_assert!(n > 1);` is not allowed
> +///     build_assert!(n > 1);
> +/// }
> +///
> +/// const _: () = foo(2); // Evaluate during const evaluation
> +/// ```
> +#[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.
> @@ -74,7 +113,8 @@ macro_rules! build_error {
>  /// 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.
> +/// [`static_assert!`] or [`const_assert!`] should be preferred to `build_assert!` whenever
> +/// possible.
>  ///
>  /// # Examples
>  ///
> @@ -84,24 +124,27 @@ macro_rules! build_error {
>  /// ```ignore
>  /// fn foo() {
>  ///     static_assert!(1 > 1); // Compile-time error
> +///     const_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.
> +/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
> +/// `build_assert!` is usable in this scenario, however you should prefer `const_assert!`.
>  /// ```
>  /// fn foo<const N: usize>() {
>  ///     // `static_assert!(N > 1);` is not allowed
> +///     const_assert!(N > 1); // Compile-time check
>  ///     build_assert!(N > 1); // Build-time check
>  ///     assert!(N > 1); // Run-time check
>  /// }
>  /// ```
>  ///
> -/// 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.
> +/// When the condition refers to parameters of an inline function, neither [`static_assert!`] or
> +/// [`const_assert!`] can be used. You may use `build_assert!` in this scenario, however you must
> +/// annotate the function `#[inline(always)]`. Without this attribute, the compiler may choose to
> +/// not inline the function, preventing it from optimizing out the error path.
>  /// ```
>  /// #[inline(always)]
>  /// fn bar(n: usize) {
> 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..75c52b5879e3 100644
> --- a/rust/kernel/prelude.rs
> +++ b/rust/kernel/prelude.rs
> @@ -29,7 +29,7 @@
>  
>  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 5b6a382637fe..0b6acd112c4f 100644
> --- a/rust/kernel/ptr.rs
> +++ b/rust/kernel/ptr.rs
> @@ -2,8 +2,12 @@
>  
>  //! Types and functions to work with pointers and addresses.
>  
> -use core::mem::align_of;
> -use core::num::NonZero;
> +use core::{
> +    mem::align_of,
> +    num::NonZero, //
> +};
> +
> +use crate::const_assert;
>  
>  /// Type representing an alignment, which is always a power of two.
>  ///
> @@ -38,12 +42,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 0c838c467c76..204e58dd1bb0 100644
> --- a/scripts/Makefile.build
> +++ b/scripts/Makefile.build
> @@ -308,6 +308,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)`.
> @@ -317,7 +318,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



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-06 22:21   ` John Hubbard
@ 2026-02-06 22:28     ` Gary Guo
  2026-02-06 23:37       ` John Hubbard
  0 siblings, 1 reply; 16+ messages in thread
From: Gary Guo @ 2026-02-06 22:28 UTC (permalink / raw)
  To: John Hubbard, 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
  Cc: linux-kernel, rust-for-linux, linux-kbuild

On Fri Feb 6, 2026 at 10:21 PM GMT, John Hubbard wrote:
> On 2/6/26 9:12 AM, 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.
>
> This is nice. A nit below about documentation.
>
>> 
>> The `build_assert!` doc is refined to recommend it where possible.
>
> Another piece of the puzzle...see below to continue the treasure
> hunt.
>
>> 
>> 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 | 55 +++++++++++++++++++++++++++++++++----
>>  rust/kernel/num/bounded.rs  | 24 ++++++----------
>>  rust/kernel/prelude.rs      |  2 +-
>>  rust/kernel/ptr.rs          | 18 ++++++------
>>  scripts/Makefile.build      |  3 +-
>>  5 files changed, 71 insertions(+), 31 deletions(-)
>> 
>> diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
>> index d464494d430a..e40f0227e1ef 100644
>> --- a/rust/kernel/build_assert.rs
>> +++ b/rust/kernel/build_assert.rs
>> @@ -41,6 +41,45 @@ 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 have 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 where possible.
>
> Over what? There are 3 different assertion types. If it is actually
> possible to list a clear order of preference, then let's list all
> 3 in order, rather than having a scattering around of "A is 
> better than B", "C is sometimes worse than A", and then the
> reader has to play treasure hunt to work it out. haha :)

I am trying to avoid listing all assertion macros in all assertions macros,
that's just going to be duplications.

How about remove `#[doc(hidden)]` on `mod build_assert` and enumerate all
assertions in the module documentation and give them rankings there?

Best,
Gary

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-06 22:28     ` Gary Guo
@ 2026-02-06 23:37       ` John Hubbard
  0 siblings, 0 replies; 16+ messages in thread
From: John Hubbard @ 2026-02-06 23:37 UTC (permalink / raw)
  To: 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
  Cc: linux-kernel, rust-for-linux, linux-kbuild

On 2/6/26 2:28 PM, Gary Guo wrote:
> On Fri Feb 6, 2026 at 10:21 PM GMT, John Hubbard wrote:
>> On 2/6/26 9:12 AM, Gary Guo wrote:
>>> From: Gary Guo <gary@garyguo.net>
...
>>> +/// 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 have 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 where possible.
>>
>> Over what? There are 3 different assertion types. If it is actually
>> possible to list a clear order of preference, then let's list all
>> 3 in order, rather than having a scattering around of "A is 
>> better than B", "C is sometimes worse than A", and then the
>> reader has to play treasure hunt to work it out. haha :)
> 
> I am trying to avoid listing all assertion macros in all assertions macros,
> that's just going to be duplications.
> 
> How about remove `#[doc(hidden)]` on `mod build_assert` and enumerate all
> assertions in the module documentation and give them rankings there?
> 

Maybe yes? In any case, let's at least clarify the preference one-liner
above. Something like:

    /// [`static_assert!`] should be preferred over [`const_assert!`]
    /// because ...

(If that's even correct. I'm a little vague on the intent still.)

thanks,
-- 
John Hubbard


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-06 21:48     ` Gary Guo
@ 2026-02-08  5:58       ` Yury Norov
  2026-02-08 10:35         ` Miguel Ojeda
  0 siblings, 1 reply; 16+ messages in thread
From: Yury Norov @ 2026-02-08  5:58 UTC (permalink / raw)
  To: Gary Guo
  Cc: Benno Lossin, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Alexandre Courbot, Yury Norov, Nathan Chancellor, Nicolas Schier,
	linux-kernel, rust-for-linux, linux-kbuild

On Fri, Feb 06, 2026 at 09:48:59PM +0000, Gary Guo wrote:
> On Fri Feb 6, 2026 at 9:30 PM GMT, Benno Lossin wrote:
> > On Fri Feb 6, 2026 at 6:12 PM CET, Gary Guo wrote:
> >> +/// 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 have 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 where possible.

This is confusing. You begin with "const_assert!() is more powerful",
and finally recommend to use a less powerful option.

> >> +///
> >> +/// # Examples
> >> +///
> >> +/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
> >> +/// Use `const_assert!` in this scenario.
> >> +/// ```
> >> +/// fn foo<const N: usize>() {
> >> +///     // `static_assert!(N > 1);` is not allowed
> >> +///     const_assert!(N > 1); // Compile-time check
> >> +///     build_assert!(N > 1); // Build-time check
> >
> > I think having "Build-time check" here is a bit confusing, how about we
> > change it to "Link-time check"? Since a "Compile-time check" also is
> > done at "Build-time"
> 
> This is the intentional phrasing that I used for `build_assert!` when I created
> it, for the reason that `build_assert!` ensure that it will fire, at latest,
> link time. However, if you actually use such methods with CTFE, it will error
> earlier. So it is "at latest link-time check", so I decided to just use
> "build-time".

I don't think this compiler implementation details should sneak into
the kernel. The compiler may get changed, or whatever else, and this
all will become just non-relevant.

So, can you once more explain when static_assert!() is preferable over
const_assert!() over build_assert!(); strictly from a users' perspective?

On the C side we've got similar statically_true() and const_true()
macros, but they seemingly have a different meaning:

  /*
   * Useful shorthand for "is this condition known at compile-time?"
   *
   * Note that the condition may involve non-constant values,
   * but the compiler may know enough about the details of the
   * values to determine that the condition is statically true.
   */
  #define statically_true(x) (__builtin_constant_p(x) && (x))
  
  /*
   * Similar to statically_true() but produces a constant expression
   *
   * To be used in conjunction with macros, such as BUILD_BUG_ON_ZERO(),
   * which require their input to be a constant expression and for which
   * statically_true() would otherwise fail.
   *
   * This is a trade-off: const_true() requires all its operands to be
   * compile time constants. Else, it would always returns false even on
   * the most trivial cases like:
   *
   *   true || non_const_var
   *
   * On the opposite, statically_true() is able to fold more complex
   * tautologies and will return true on expressions such as:
   *
   *   !(non_const_var * 8 % 4)
   *
   * For the general case, statically_true() is better.
   */
  #define const_true(x) __builtin_choose_expr(__is_constexpr(x), x, false)

Is it possible to maintain consistency with C on rust side? If not,
can you take those C comments as the reference for what level of
detalization is desired? Maybe pick different names then?

Thanks,
Yury

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-08  5:58       ` Yury Norov
@ 2026-02-08 10:35         ` Miguel Ojeda
  2026-02-08 21:07           ` Yury Norov
  0 siblings, 1 reply; 16+ messages in thread
From: Miguel Ojeda @ 2026-02-08 10:35 UTC (permalink / raw)
  To: Yury Norov
  Cc: Gary Guo, Benno Lossin, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Alexandre Courbot, Yury Norov,
	Nathan Chancellor, Nicolas Schier, linux-kernel, rust-for-linux,
	linux-kbuild

On Sun, Feb 8, 2026 at 6:58 AM Yury Norov <ynorov@nvidia.com> wrote:
>
> This is confusing. You begin with "const_assert!() is more powerful",
> and finally recommend to use a less powerful option.

The goal is that users use the least powerful one that applies, not
the other way around, because the least powerful ones fail earlier and
are generally more robust.

I think the first example is intended to show the different ones, but
I think the wording can be improved -- the one in the existing
`build_assert!` docs is a bit clearer.

Gary: perhaps we could factor out the explanation/examples to the
module-level docs, and then link to it from all the three asserts.

> I don't think this compiler implementation details should sneak into
> the kernel. The compiler may get changed, or whatever else, and this
> all will become just non-relevant.

How do they sneak into the kernel? Gary is explaining why it is not
called "link time", precisely because that would expose more details,
not less.

Regardless, that "link-time" vs. "build-time" discussion is
independent of this patch, because those docs already exist in the
tree.

> On the C side we've got similar statically_true() and const_true()
> macros, but they seemingly have a different meaning:

> Is it possible to maintain consistency with C on rust side? If not,
> can you take those C comments as the reference for what level of
> detalization is desired? Maybe pick different names then?

Please explain what inconsistency you are seeing here.

Also, please note that two of the three names have been for years in
the kernel tree, and that standard C also uses `static_assert` as a
name. `const_assert` fits the pattern and it literally expands to what
it says.

Moreover, `const` in C is not the same as `const` in Rust. `constexpr`
in C is closer to `const` in Rust.

By the way, I am not sure why you suggested `const_true` for the name
of that C macro -- I think it should be `constexpr_true` instead,
which is closer to what it does, and it fits the pattern on the C side
better, too. So that would be more consistent.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-08 10:35         ` Miguel Ojeda
@ 2026-02-08 21:07           ` Yury Norov
  2026-02-09  5:16             ` Gary Guo
  2026-02-09 11:44             ` Miguel Ojeda
  0 siblings, 2 replies; 16+ messages in thread
From: Yury Norov @ 2026-02-08 21:07 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Gary Guo, Benno Lossin, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Alexandre Courbot, Yury Norov,
	Nathan Chancellor, Nicolas Schier, linux-kernel, rust-for-linux,
	linux-kbuild

On Sun, Feb 08, 2026 at 11:35:51AM +0100, Miguel Ojeda wrote:
> On Sun, Feb 8, 2026 at 6:58 AM Yury Norov <ynorov@nvidia.com> wrote:
> >
> > This is confusing. You begin with "const_assert!() is more powerful",
> > and finally recommend to use a less powerful option.
> 
> The goal is that users use the least powerful one that applies, not
> the other way around, because the least powerful ones fail earlier and
> are generally more robust.
> 
> I think the first example is intended to show the different ones, but
> I think the wording can be improved -- the one in the existing
> `build_assert!` docs is a bit clearer.

Can you please keep more context? It would be easier to refer to an
example if I have it on hand.
 
> Gary: perhaps we could factor out the explanation/examples to the
> module-level docs, and then link to it from all the three asserts.
> 
> > I don't think this compiler implementation details should sneak into
> > the kernel. The compiler may get changed, or whatever else, and this
> > all will become just non-relevant.
> 
> How do they sneak into the kernel? Gary is explaining why it is not
> called "link time", precisely because that would expose more details,
> not less.
> 
> Regardless, that "link-time" vs. "build-time" discussion is
> independent of this patch, because those docs already exist in the
> tree.

Again, more context would help. So this is the original comment from
Benno, and Gary's reply:

  > I think having "Build-time check" here is a bit confusing, how about we
  > change it to "Link-time check"? Since a "Compile-time check" also is
  > done at "Build-time"
  
  This is the intentional phrasing that I used for `build_assert!` when I created
  it, for the reason that `build_assert!` ensure that it will fire, at latest,
  link time. However, if you actually use such methods with CTFE, it will error
  earlier. So it is "at latest link-time check", so I decided to just use
  "build-time".

I agree with ""Build-time check" here is a bit confusing", and the
following indeed looks like a compiler implementation discussion. So
I concluded that the difference between build_assert and const_assert
is not visible from programmer's POV. Please correct me if I'm wrong.

> > On the C side we've got similar statically_true() and const_true()
> > macros, but they seemingly have a different meaning:
> 
> > Is it possible to maintain consistency with C on rust side? If not,
> > can you take those C comments as the reference for what level of
> > detalization is desired? Maybe pick different names then?
> 
> Please explain what inconsistency you are seeing here.

OK, maybe it's just me, but this is how I build a map between rust and C:

 - Plain BUG_ON() matches plain assert!();
 - BUILD_BUG_ON() is compiletime_assert() and matches build_assert!();
 - BUILD_BUG_ON_ZERO() - same as BUILD_BUG_ON(), but can be used in
   initialization constructions, like GENMASK(), i.e. rvalue. No direct
   analogue in Rust;
 - BUILD_BUG_ON(statically_true()) - allows runtime conditions, like
   "true || runtime_cond", and matches static_assert!() in rust;
 - BUILD_BUG_ON(const_true()) - doesn't allow runtime conditions.

I expected that const_assert!() would be an analogue for
BUILD_BUG_ON(const_true()), but it is seemingly a different thing. Or
am I wrong?
 
> Also, please note that two of the three names have been for years in
> the kernel tree, and that standard C also uses `static_assert` as a
> name. `const_assert` fits the pattern and it literally expands to what
> it says.
> 
> Moreover, `const` in C is not the same as `const` in Rust. `constexpr`
> in C is closer to `const` in Rust.
> 
> By the way, I am not sure why you suggested `const_true` for the name
> of that C macro -- I think it should be `constexpr_true` instead,
> which is closer to what it does, and it fits the pattern on the C side
> better, too. So that would be more consistent.

I suggested const_true() over the original underscored _statically_true(),
and this is an obvious improvement. If you think that 'constexpr_true()'
would add to explainability, please submit a patch. I have a weakly
negative opinion on that.

Thanks,
Yury

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-08 21:07           ` Yury Norov
@ 2026-02-09  5:16             ` Gary Guo
  2026-02-09 11:44             ` Miguel Ojeda
  1 sibling, 0 replies; 16+ messages in thread
From: Gary Guo @ 2026-02-09  5:16 UTC (permalink / raw)
  To: Yury Norov, Miguel Ojeda
  Cc: Gary Guo, Benno Lossin, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Alexandre Courbot, Yury Norov,
	Nathan Chancellor, Nicolas Schier, linux-kernel, rust-for-linux,
	linux-kbuild

On Sun Feb 8, 2026 at 9:07 PM GMT, Yury Norov wrote:
> On Sun, Feb 08, 2026 at 11:35:51AM +0100, Miguel Ojeda wrote:
>> On Sun, Feb 8, 2026 at 6:58 AM Yury Norov <ynorov@nvidia.com> wrote:
>> >
>> > This is confusing. You begin with "const_assert!() is more powerful",
>> > and finally recommend to use a less powerful option.
>> 
>> The goal is that users use the least powerful one that applies, not
>> the other way around, because the least powerful ones fail earlier and
>> are generally more robust.
>> 
>> I think the first example is intended to show the different ones, but
>> I think the wording can be improved -- the one in the existing
>> `build_assert!` docs is a bit clearer.
>
> Can you please keep more context? It would be easier to refer to an
> example if I have it on hand.
>  
>> Gary: perhaps we could factor out the explanation/examples to the
>> module-level docs, and then link to it from all the three asserts.
>> 
>> > I don't think this compiler implementation details should sneak into
>> > the kernel. The compiler may get changed, or whatever else, and this
>> > all will become just non-relevant.
>> 
>> How do they sneak into the kernel? Gary is explaining why it is not
>> called "link time", precisely because that would expose more details,
>> not less.
>> 
>> Regardless, that "link-time" vs. "build-time" discussion is
>> independent of this patch, because those docs already exist in the
>> tree.
>
> Again, more context would help. So this is the original comment from
> Benno, and Gary's reply:
>
>   > I think having "Build-time check" here is a bit confusing, how about we
>   > change it to "Link-time check"? Since a "Compile-time check" also is
>   > done at "Build-time"
>   
>   This is the intentional phrasing that I used for `build_assert!` when I created
>   it, for the reason that `build_assert!` ensure that it will fire, at latest,
>   link time. However, if you actually use such methods with CTFE, it will error
>   earlier. So it is "at latest link-time check", so I decided to just use
>   "build-time".
>
> I agree with ""Build-time check" here is a bit confusing", and the
> following indeed looks like a compiler implementation discussion. So
> I concluded that the difference between build_assert and const_assert
> is not visible from programmer's POV. Please correct me if I'm wrong.
>
>> > On the C side we've got similar statically_true() and const_true()
>> > macros, but they seemingly have a different meaning:
>> 
>> > Is it possible to maintain consistency with C on rust side? If not,
>> > can you take those C comments as the reference for what level of
>> > detalization is desired? Maybe pick different names then?
>> 
>> Please explain what inconsistency you are seeing here.
>
> OK, maybe it's just me, but this is how I build a map between rust and C:
>
>  - Plain BUG_ON() matches plain assert!();
>  - BUILD_BUG_ON() is compiletime_assert() and matches build_assert!();

These two are correct.

Notably, `build_assert!` uses the same mechanism as `BUILD_BUG_ON`, i.e.
generating a undefined symbol reference is it failed to be optimized out.

>  - BUILD_BUG_ON_ZERO() - same as BUILD_BUG_ON(), but can be used in
>    initialization constructions, like GENMASK(), i.e. rvalue. No direct
>    analogue in Rust;
>  - BUILD_BUG_ON(statically_true()) - allows runtime conditions, like
>    "true || runtime_cond", and matches static_assert!() in rust;

`static_assert!(expr)` in Rust is equivalent to `static_assert(expr)` in C. This
means that the expression is evaluated by the compiler.

There's no equivalent construct of `statically_true` and `const_true` in Rust.
Rust intentionally avoid providing the ability to observe different behaviour in
compile time and runtime. These macros simply return `false` if the
evaluatability is not met; Rust's `static_assert!()` (and C's `static_assert!`
and the `const_assert!()` will fail the compilation with a compiler error (not
an assertion failure) if the expression cannot be evaluated at compile time.

>  - BUILD_BUG_ON(const_true()) - doesn't allow runtime conditions.
>
> I expected that const_assert!() would be an analogue for
> BUILD_BUG_ON(const_true()), but it is seemingly a different thing. Or
> am I wrong?
>  

Let me give a summary of the three assertions in Rust:

`static_assert!(expr)` is equivalent to `static_assert` in C. It requires `expr`
to be a constant expression. This expression cannot refer to any generics.
When you write a `static_assert!(expr)` in a program, it is always evaluated,
regardless if the function it appears in is used or not.

`const_assert!()` has no equivalent in C, because C does not have generics.
However, you can treat it as a more powerful version of `static_assert!()`. We
need it because it has the ability to refer to generics. It also requires the
expression to be constant expression. *However*, because it can refer to
generics, it is inherently tied to a specific instance of a function. So if you
use it in a generic function and the function is not used, the assertion will
not be performed. `static_assert!` is recommend over `const_assert!` if possible
for this reason. It also has a limitation that it is only usable inside a
function (strictly speaking in Rust term, bodies).

`build_assert!()` is equivalent to our `BUILD_BUG_ON`. It is even more powerful
than `const_assert!()` because it is supposed to be able to check tautologies
that depend on runtime value (similar to C). However, as the assertion failure
mechanism is undefined symbol and linker error, it is not developer friendly so
it is recommend to avoid it and prefer other two assertions where possible.

In summary:
`static_assert!()`, `const_assert!()` and `build_assert!()` in that order has
increasing expressiveness, but decreasing robustness and the checks are
performed later in the pipeline. Hence, the suggestion to use the least powerful
one that still works.

Regarding the name:

`const_assert!()` has it's name because it is literally

    const { assert!() }

where `const {}` is a construct in Rust which says "this must be a constant
expression and evaluated at compile time". The names here refer to related Rust
constructs rather than `statically_true` and `const_true` in the C side.

Best,
Gary



>> Also, please note that two of the three names have been for years in
>> the kernel tree, and that standard C also uses `static_assert` as a
>> name. `const_assert` fits the pattern and it literally expands to what
>> it says.
>> 
>> Moreover, `const` in C is not the same as `const` in Rust. `constexpr`
>> in C is closer to `const` in Rust.
>> 
>> By the way, I am not sure why you suggested `const_true` for the name
>> of that C macro -- I think it should be `constexpr_true` instead,
>> which is closer to what it does, and it fits the pattern on the C side
>> better, too. So that would be more consistent.
>
> I suggested const_true() over the original underscored _statically_true(),
> and this is an obvious improvement. If you think that 'constexpr_true()'
> would add to explainability, please submit a patch. I have a weakly
> negative opinion on that.



>
> Thanks,
> Yury


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-08 21:07           ` Yury Norov
  2026-02-09  5:16             ` Gary Guo
@ 2026-02-09 11:44             ` Miguel Ojeda
  2026-02-12 20:16               ` Yury Norov
  1 sibling, 1 reply; 16+ messages in thread
From: Miguel Ojeda @ 2026-02-09 11:44 UTC (permalink / raw)
  To: Yury Norov
  Cc: Gary Guo, Benno Lossin, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Alexandre Courbot, Yury Norov,
	Nathan Chancellor, Nicolas Schier, linux-kernel, rust-for-linux,
	linux-kbuild

On Sun, Feb 8, 2026 at 10:07 PM Yury Norov <ynorov@nvidia.com> wrote:
>
> Can you please keep more context? It would be easier to refer to an
> example if I have it on hand.

The existing docs for `build_assert!` have a couple examples that may help:

  https://rust.docs.kernel.org/kernel/macro.build_assert.html

(Those are the kind of examples I would like to have in the module
level docs, I think they help a lot to quickly see for what each one
is used for, even if one may not know the exact Rust terminology
etc.).

> I agree with ""Build-time check" here is a bit confusing", and the
> following indeed looks like a compiler implementation discussion. So
> I concluded that the difference between build_assert and const_assert
> is not visible from programmer's POV. Please correct me if I'm wrong.

Gary has also nicely explained in detail the three Rust ones -- what I
was suggesting is to take something like that and put it in a single
explanation in the module docs, with the examples we have (or others).

In any case, to reply to this bit above: `build_assert!` allows way
more expressions than `const_assert!` does -- the ones you call
"runtime conditions". So it is very visible to the programmer.

(Not sure if I would call them "runtime conditions" though, i.e. that
sounds like a normal condition that gets checked at runtime. Hopefully
the optimizer also deleted as much code as it could...)

By the way, in C, `compiletime_assert` (if the compiler supports the
attribute, which GCC and Clang do nowadays) fails in the actual
compiler rather than the linker, so I guess it is a fair name, even if
post-optimizations. But the fallback still fails later, so in general
it isn't always at compilation time (and the docs use wording like
"break build"). I guess we could eventually rename the Rust one
`compiletime_assert` to match, especially if we get support in the
Rust compiler for something like the attribute (there are already more
`build_assert` calls than `compiletime_assert` ones in the tree,
funnily... :)

> I suggested const_true() over the original underscored _statically_true(),
> and this is an obvious improvement. If you think that 'constexpr_true()'
> would add to explainability, please submit a patch. I have a weakly
> negative opinion on that.

Thanks for that context. Hmm... In that case, given the current name
was meant as an improvement over the underscored one, rather than
other reason (i.e. perhaps I was missing something), then yeah, I
think I may submit the patch. It is not important obviously, but it
never hurts to try to align these things to reduce confusion, and it
is just a few callers unlike other macros...

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-09 11:44             ` Miguel Ojeda
@ 2026-02-12 20:16               ` Yury Norov
  0 siblings, 0 replies; 16+ messages in thread
From: Yury Norov @ 2026-02-12 20:16 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Gary Guo, Benno Lossin, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Alexandre Courbot, Yury Norov,
	Nathan Chancellor, Nicolas Schier, linux-kernel, rust-for-linux,
	linux-kbuild

On Mon, Feb 09, 2026 at 12:44:19PM +0100, Miguel Ojeda wrote:
> On Sun, Feb 8, 2026 at 10:07 PM Yury Norov <ynorov@nvidia.com> wrote:
> >
> > Can you please keep more context? It would be easier to refer to an
> > example if I have it on hand.
> 
> The existing docs for `build_assert!` have a couple examples that may help:
> 
>   https://rust.docs.kernel.org/kernel/macro.build_assert.html
> 
> (Those are the kind of examples I would like to have in the module
> level docs, I think they help a lot to quickly see for what each one
> is used for, even if one may not know the exact Rust terminology
> etc.).
> 
> > I agree with ""Build-time check" here is a bit confusing", and the
> > following indeed looks like a compiler implementation discussion. So
> > I concluded that the difference between build_assert and const_assert
> > is not visible from programmer's POV. Please correct me if I'm wrong.
> 
> Gary has also nicely explained in detail the three Rust ones -- what I
> was suggesting is to take something like that and put it in a single
> explanation in the module docs, with the examples we have (or others).

Yes he did. Thanks to you and Gary for sorting things out. I'll walk
through the #2 of this series shortly, but overall it makes sense and
looks good.

I agree, would be great to wrap explanations up in the docs.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-06 17:12 ` [PATCH 2/2] rust: add `const_assert!` macro Gary Guo
  2026-02-06 21:30   ` Benno Lossin
  2026-02-06 22:21   ` John Hubbard
@ 2026-02-13  1:16   ` Yury Norov
  2026-02-13  9:06     ` Gary Guo
  2 siblings, 1 reply; 16+ messages in thread
From: Yury Norov @ 2026-02-13  1:16 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,
	linux-kernel, rust-for-linux, linux-kbuild

On Fri, Feb 06, 2026 at 05:12:50PM +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.
> 
> The `build_assert!` doc is refined to recommend it where possible.

This is a good place to actually explain where this thing is possible.
 
> 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 | 55 +++++++++++++++++++++++++++++++++----
>  rust/kernel/num/bounded.rs  | 24 ++++++----------
>  rust/kernel/prelude.rs      |  2 +-
>  rust/kernel/ptr.rs          | 18 ++++++------
>  scripts/Makefile.build      |  3 +-
>  5 files changed, 71 insertions(+), 31 deletions(-)
> 
> diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
> index d464494d430a..e40f0227e1ef 100644
> --- a/rust/kernel/build_assert.rs
> +++ b/rust/kernel/build_assert.rs
> @@ -41,6 +41,45 @@ 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 have a limitation where it can only appear in places

"However, it also has a limitation", I guess?

> +/// where statements can appear; for example, you cannot use it as an item in the module.
> +///
> +/// [`static_assert!`] should be preferred where possible.
> +///
> +/// # Examples
> +///
> +/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
> +/// Use `const_assert!` in this scenario.
> +/// ```
> +/// fn foo<const N: usize>() {
> +///     // `static_assert!(N > 1);` is not allowed
> +///     const_assert!(N > 1); // Compile-time check
> +///     build_assert!(N > 1); // Build-time check

In the other email you say: the assertion failure mechanism is undefined
symbol and linker error.

So, maybe:

     const_assert!(N > 1); // Build-time check at compilation
     build_assert!(N > 1); // Build-time check at linkage

Because compilation is a part of build process, and referring them one
vs another may confuse. 

> +///     assert!(N > 1); // Run-time check
> +/// }
> +/// 
> +///
> +/// Note that `const_assert!` cannot be used when referring to function parameter, then
> +/// `const_assert!` cannot be used even if the function is going to be called during const
> +/// evaluation. Use `build_assert!` in this case.
> +/// ```
> +/// const fn foo(n: usize) {
> +///     // `const_assert!(n > 1);` is not allowed
> +///     build_assert!(n > 1);
> +/// }
> +///
> +/// const _: () = foo(2); // Evaluate during const evaluation
> +/// ```

This part confused me the most. But after all, parameters in rust
are never constants, and even if foo() is used with '2' only,  it
appears to be a non-constant from the const_assert!() POV.

Seemingly, there are only 3 objects in the language that can be
specified with the 'const': functions, items and generics. And
const_assert!() makes sense (doesn't break the build) only for
them.

So, the difference between const vs build assertions is that const
version is only applicable to a certain type of objects and is
supported by language. Contrary, build_assert!() is not a part
of the language and in fact is based on a linkage trick, while
allows broader set of build-time expressions.

And altogether they make sense and even nice.

Can you please consider to add the above passage to your reply in
the other email, and place them in the documentation?

With that (or without),

Reviewed-by: Yury Norov <ynorov@nvidia.com>

> +#[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.
> @@ -74,7 +113,8 @@ macro_rules! build_error {
>  /// 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.
> +/// [`static_assert!`] or [`const_assert!`] should be preferred to `build_assert!` whenever
> +/// possible.
>  ///
>  /// # Examples
>  ///
> @@ -84,24 +124,27 @@ macro_rules! build_error {
>  /// ```ignore
>  /// fn foo() {
>  ///     static_assert!(1 > 1); // Compile-time error
> +///     const_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.
> +/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
> +/// `build_assert!` is usable in this scenario, however you should prefer `const_assert!`.
>  /// ```
>  /// fn foo<const N: usize>() {
>  ///     // `static_assert!(N > 1);` is not allowed
> +///     const_assert!(N > 1); // Compile-time check
>  ///     build_assert!(N > 1); // Build-time check
>  ///     assert!(N > 1); // Run-time check
>  /// }
>  /// ```
>  ///
> -/// 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.
> +/// When the condition refers to parameters of an inline function, neither [`static_assert!`] or
> +/// [`const_assert!`] can be used. You may use `build_assert!` in this scenario, however you must
> +/// annotate the function `#[inline(always)]`. Without this attribute, the compiler may choose to
> +/// not inline the function, preventing it from optimizing out the error path.
>  /// ```
>  /// #[inline(always)]
>  /// fn bar(n: usize) {
> 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..75c52b5879e3 100644
> --- a/rust/kernel/prelude.rs
> +++ b/rust/kernel/prelude.rs
> @@ -29,7 +29,7 @@
>  
>  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 5b6a382637fe..0b6acd112c4f 100644
> --- a/rust/kernel/ptr.rs
> +++ b/rust/kernel/ptr.rs
> @@ -2,8 +2,12 @@
>  
>  //! Types and functions to work with pointers and addresses.
>  
> -use core::mem::align_of;
> -use core::num::NonZero;
> +use core::{
> +    mem::align_of,
> +    num::NonZero, //
> +};
> +
> +use crate::const_assert;
>  
>  /// Type representing an alignment, which is always a power of two.
>  ///
> @@ -38,12 +42,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 0c838c467c76..204e58dd1bb0 100644
> --- a/scripts/Makefile.build
> +++ b/scripts/Makefile.build
> @@ -308,6 +308,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)`.
> @@ -317,7 +318,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
> -- 
> 2.51.2

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-13  1:16   ` Yury Norov
@ 2026-02-13  9:06     ` Gary Guo
  2026-02-13 10:26       ` Miguel Ojeda
  0 siblings, 1 reply; 16+ messages in thread
From: Gary Guo @ 2026-02-13  9:06 UTC (permalink / raw)
  To: Yury Norov, 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,
	linux-kernel, rust-for-linux, linux-kbuild

On Fri Feb 13, 2026 at 9:16 AM CST, Yury Norov wrote:
> On Fri, Feb 06, 2026 at 05:12:50PM +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.
>> 
>> The `build_assert!` doc is refined to recommend it where possible.
>
> This is a good place to actually explain where this thing is possible.
>  
>> 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 | 55 +++++++++++++++++++++++++++++++++----
>>  rust/kernel/num/bounded.rs  | 24 ++++++----------
>>  rust/kernel/prelude.rs      |  2 +-
>>  rust/kernel/ptr.rs          | 18 ++++++------
>>  scripts/Makefile.build      |  3 +-
>>  5 files changed, 71 insertions(+), 31 deletions(-)
>> 
>> diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
>> index d464494d430a..e40f0227e1ef 100644
>> --- a/rust/kernel/build_assert.rs
>> +++ b/rust/kernel/build_assert.rs
>> @@ -41,6 +41,45 @@ 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 have a limitation where it can only appear in places
>
> "However, it also has a limitation", I guess?
>
>> +/// where statements can appear; for example, you cannot use it as an item in the module.
>> +///
>> +/// [`static_assert!`] should be preferred where possible.
>> +///
>> +/// # Examples
>> +///
>> +/// When the condition refers to generic parameters [`static_assert!`] cannot be used.
>> +/// Use `const_assert!` in this scenario.
>> +/// ```
>> +/// fn foo<const N: usize>() {
>> +///     // `static_assert!(N > 1);` is not allowed
>> +///     const_assert!(N > 1); // Compile-time check
>> +///     build_assert!(N > 1); // Build-time check
>
> In the other email you say: the assertion failure mechanism is undefined
> symbol and linker error.
>
> So, maybe:
>
>      const_assert!(N > 1); // Build-time check at compilation
>      build_assert!(N > 1); // Build-time check at linkage
>
> Because compilation is a part of build process, and referring them one
> vs another may confuse.
>
>> +///     assert!(N > 1); // Run-time check
>> +/// }
>> +/// 
>> +///
>> +/// Note that `const_assert!` cannot be used when referring to function parameter, then
>> +/// `const_assert!` cannot be used even if the function is going to be called during const
>> +/// evaluation. Use `build_assert!` in this case.
>> +/// ```
>> +/// const fn foo(n: usize) {
>> +///     // `const_assert!(n > 1);` is not allowed
>> +///     build_assert!(n > 1);
>> +/// }
>> +///
>> +/// const _: () = foo(2); // Evaluate during const evaluation
>> +/// ```
>
> This part confused me the most. But after all, parameters in rust
> are never constants, and even if foo() is used with '2' only,  it
> appears to be a non-constant from the const_assert!() POV.

Yes. For example,

    const fn foo(x: u32) -> x {
        build_assert!(x > 1);
        x
    }

require use the `build_assert!()` because it act on value `x` which may not be
constant, as `foo` can be invoked by runtime code.

Therefore, body of const functions are not const context. However, they're still
restricted to perform only operations that can be performed during const
evaluation.

For language lawyers, this is the reference:
https://doc.rust-lang.org/reference/const_eval.html

>
> Seemingly, there are only 3 objects in the language that can be
> specified with the 'const': functions, items and generics. And
> const_assert!() makes sense (doesn't break the build) only for
> them.

Very close. `const_assert!()` can act on invocation of const functions on const
values, but not values inside const functions. So in the above example,
`const_assert!(x > 1)` inside `foo` is not okay, but `const_assert!(foo(2) > 1)`
is okay.

>
> So, the difference between const vs build assertions is that const
> version is only applicable to a certain type of objects and is
> supported by language.

Correct.

> Contrary, build_assert!() is not a part
> of the language and in fact is based on a linkage trick, while
> allows broader set of build-time expressions.

The reason that I want to omit "link-time" is that our `build_assert!()` *can*
still be checked before link-time. Again with example above, user can write

    static_assert!(foo(0) == 0);

which means that now `foo` is evaluated by the compiler. When this happens,
`build_assert!()` also abort the build during compilation time, not link-time.

Best,
Gary


>
> And altogether they make sense and even nice.
>
> Can you please consider to add the above passage to your reply in
> the other email, and place them in the documentation?
>
> With that (or without),
>
> Reviewed-by: Yury Norov <ynorov@nvidia.com>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/2] rust: add `const_assert!` macro
  2026-02-13  9:06     ` Gary Guo
@ 2026-02-13 10:26       ` Miguel Ojeda
  0 siblings, 0 replies; 16+ messages in thread
From: Miguel Ojeda @ 2026-02-13 10:26 UTC (permalink / raw)
  To: Gary Guo
  Cc: Yury Norov, 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, linux-kernel, rust-for-linux,
	linux-kbuild

On Fri, Feb 13, 2026 at 10:07 AM Gary Guo <gary@garyguo.net> wrote:
>
> The reason that I want to omit "link-time" is that our `build_assert!()` *can*
> still be checked before link-time. Again with example above, user can write
>
>     static_assert!(foo(0) == 0);
>
> which means that now `foo` is evaluated by the compiler. When this happens,
> `build_assert!()` also abort the build during compilation time, not link-time.

Another reason would be that, ideally/eventually, Rust could perhaps
provide something like GCC/Clang `error`/`warning` attributes, and
thus it could fail earlier like the C side one (perhaps still at the
end of LLVM, but not as late as linking).

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-02-13 10:26 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-06 17:12 [PATCH 1/2] rust: move `static_assert` into `build_assert` Gary Guo
2026-02-06 17:12 ` [PATCH 2/2] rust: add `const_assert!` macro Gary Guo
2026-02-06 21:30   ` Benno Lossin
2026-02-06 21:48     ` Gary Guo
2026-02-08  5:58       ` Yury Norov
2026-02-08 10:35         ` Miguel Ojeda
2026-02-08 21:07           ` Yury Norov
2026-02-09  5:16             ` Gary Guo
2026-02-09 11:44             ` Miguel Ojeda
2026-02-12 20:16               ` Yury Norov
2026-02-06 22:21   ` John Hubbard
2026-02-06 22:28     ` Gary Guo
2026-02-06 23:37       ` John Hubbard
2026-02-13  1:16   ` Yury Norov
2026-02-13  9:06     ` Gary Guo
2026-02-13 10:26       ` Miguel Ojeda

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox