lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <e137e948-e44a-455e-b3a1-717865ed15aa@nvidia.com>
Date: Fri, 6 Feb 2026 14:21:35 -0800
From: John Hubbard <jhubbard@...dia.com>
To: Gary Guo <gary@...yguo.net>, Miguel Ojeda <ojeda@...nel.org>,
 Boqun Feng <boqun@...nel.org>, Björn Roy Baron
 <bjorn3_gh@...tonmail.com>, Benno Lossin <lossin@...nel.org>,
 Andreas Hindborg <a.hindborg@...nel.org>, Alice Ryhl <aliceryhl@...gle.com>,
 Trevor Gross <tmgross@...ch.edu>, Danilo Krummrich <dakr@...nel.org>,
 Alexandre Courbot <acourbot@...dia.com>, Yury Norov <yury.norov@...il.com>,
 Nathan Chancellor <nathan@...nel.org>, Nicolas Schier <nsc@...nel.org>
Cc: linux-kernel@...r.kernel.org, rust-for-linux@...r.kernel.org,
 linux-kbuild@...r.kernel.org
Subject: Re: [PATCH 2/2] rust: add `const_assert!` macro

On 2/6/26 9:12 AM, Gary Guo wrote:
> From: Gary Guo <gary@...yguo.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@...yguo.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



Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ