From: "Eliot Courtney" <ecourtney@nvidia.com>
To: "Alexandre Courbot" <acourbot@nvidia.com>,
"Eliot Courtney" <ecourtney@nvidia.com>
Cc: "Yury Norov" <yury.norov@gmail.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Tamir Duberstein" <tamird@kernel.org>,
"Onur Özkan" <work@onurozkan.dev>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"John Hubbard" <jhubbard@nvidia.com>,
"Alistair Popple" <apopple@nvidia.com>,
"Timur Tabi" <ttabi@nvidia.com>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org,
dri-devel <dri-devel-bounces@lists.freedesktop.org>
Subject: Re: [PATCH v3 1/3] rust: num: add cv! macro to create values from constant expressions
Date: Thu, 17 Sep 2026 16:59:03 +0900 [thread overview]
Message-ID: <DLHFKT44IHW9.2QWQB0O0LJHJJ@nvidia.com> (raw)
In-Reply-To: <DLFPWSS3LZSN.12G96EM0FI18C@nvidia.com>
On Tue Sep 15, 2026 at 4:39 PM JST, Alexandre Courbot wrote:
> On Wed Sep 2, 2026 at 6:16 PM JST, Eliot Courtney wrote:
>> Currently, using NonZero/Bounded constants is quite verbose. It's
>> unfortunate because it disincentivizes using it in interface boundaries.
>> Introduce a macro to make it nicer to use. The macro `cv!` (for constant
>> value) takes a const integer expression and widens it to i128 (at build
>> time only) before passing it as a const generic value to a new trait
>> `FromConst`. The value is then converted and appears in the
>> associated constant `FromConst::VALUE`. The trait is implemented by
>> NonZero, Bounded, and Alignment and lets values of each be constructed
>> from constants without a verbose turbofish syntax.
>> For example, `const { NonZero::new(1).unwrap() }` can be written as
>> `cv!(1)`.
>>
>> Suggested-by: Gary Guo <gary@garyguo.net>
>> Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
>
> I don't think we have any user but nova-core at the moment, and it
> benefits from this in several series (patch 3 here, but also ID pool and
> later r000). Miguel, is this ok if we take it (i.e. the next revision)
> through drm-rust-next?
Will send the next version based on drm-rust-next, but Miguel please let
us know if it's ok to take through drm-rust-next. Thanks!
>
> Some nits below.
>
>> ---
>> rust/kernel/num.rs | 138 +++++++++++++++++++++++++++++++++++++++++++++
>> rust/kernel/num/bounded.rs | 19 +++++++
>> rust/kernel/ptr.rs | 14 +++++
>> 3 files changed, 171 insertions(+)
>>
>> diff --git a/rust/kernel/num.rs b/rust/kernel/num.rs
>> index dbe848e30efe..9435459376a4 100644
>> --- a/rust/kernel/num.rs
>> +++ b/rust/kernel/num.rs
>> @@ -2,6 +2,7 @@
>>
>> //! Additional numerical features for the kernel.
>>
>> +use crate::const_assert;
>> use core::ops;
>>
>> pub mod bounded;
>> @@ -9,6 +10,143 @@
>>
>> pub use bounded::*;
>
> Can we move the new code at the bottom of the file? I'd like to keep the
> `Integer` definition on top.
Done.
>
>>
>> +/// Creates a value from an integer constant expression, with validity checked at build time.
>> +///
>> +/// This works for any type that implements [`FromConst`], with the target type inferred from
>
> I am wondering about `FromConst`, do we want to make it public, or hide
> (and possibly seal) it?
>
> Basically as it is anyone can implement a new type that works with
> `cv!`. If that's by design, then good, and I don't see any potential
> issue with that, but IIUC we also agree that this is a temporary
> workaround so we might not want to allow extensibility if it isn't
> future-proof.
>
> If we decide to make `FromConst` more discreet without sealing it (which
> sounds like a good middle ground to me), then we should remove mentions
> of it from the public docs and mark it as `#[doc(hidden)]`.
I think it's useful to make it public and it was my intention to let
anyone implement a newtype that works with cv!. Drivers may have some
type which has constants that is specific to their use case that they
want to use. Also, if we expect more abstractions to initially appear in
drivers then the good ones get moved into common code it's nice to let
them use cv! from the beginning.
>
>> +/// the context, or named explicitly with `cv!(value => Type)`.
>> +///
>> +/// # Examples
>> +///
>> +/// ```
>> +/// use core::num::NonZero;
>> +/// use kernel::num::Bounded;
>> +/// use kernel::num::cv;
>> +/// use kernel::ptr::Alignment;
>> +///
>> +/// let v: NonZero<usize> = cv!(8);
>> +/// assert_eq!(v.get(), 8);
>> +///
>> +/// // Any integer constant expression works, not only literals.
>> +/// let m: NonZero<usize> = cv!(usize::MAX);
>> +/// assert_eq!(m.get(), usize::MAX);
>> +///
>> +/// let b: Bounded<u32, 4> = cv!(15);
>> +/// assert_eq!(b.get(), 15);
>> +///
>> +/// let a: Alignment = cv!(4096);
>> +/// assert_eq!(a.as_usize(), 4096);
>> +///
>> +/// // Checked narrowing of integer constants, including in `const` items.
>> +/// const SMALL: u8 = cv!(200u32);
>> +/// assert_eq!(SMALL, 200);
>> +///
>> +/// const N: NonZero<u8> = cv!(5);
>> +/// assert_eq!(N.get(), 5);
>> +///
>> +/// // The target type can be given explicitly.
>> +/// let e = cv!(200u32 => u8);
>> +/// assert_eq!(e, 200);
>> +///
>> +/// // With an explicit primitive target, the expression can use generic parameters.
>> +/// const fn as_u64<const KEY: u16>() -> u64 {
>> +/// cv!(KEY => u64)
>> +/// }
>> +/// assert_eq!(as_u64::<0x40>(), 0x40);
>
> These examples are excellent.
thank you~~
>
>> +/// ```
>> +#[macro_export]
>> +#[doc(hidden)]
>> +macro_rules! cv {
>> + (@cast $v:expr => $t:ty) => {
>> + const {
>> + #[allow(unused_comparisons, unused_assignments, clippy::as_underscore)]
>
> You may want to add `clippy::unnecessary_cast`, in case one does
> `cv!(v => u32)` where `v` is already a `u32` (which would happen in
> macro or generic code).
I believe clippy ignores unnecessary_cast when it's generated from a
macro. At least I couldn't get the warning to trigger.
>
>> + {
>> + let v = $v;
>> + let r = v as $t;
>> + // Pin `back` to `v`'s type so `as _` casts back to the source type.
>> + let mut back = v;
>> + back = r as _;
>> +
>> + ::core::assert!(
>> + back == v && (v < 0) == (r < 0),
>> + "value does not fit into the target type"
>> + );
>> +
>> + r
>> + }
>> + }
>> + };
>> + ($v:expr => u8) => { $crate::cv!(@cast $v => u8) };
>> + ($v:expr => u16) => { $crate::cv!(@cast $v => u16) };
>> + ($v:expr => u32) => { $crate::cv!(@cast $v => u32) };
>> + ($v:expr => u64) => { $crate::cv!(@cast $v => u64) };
>> + ($v:expr => u128) => { $crate::cv!(@cast $v => u128) };
>> + ($v:expr => usize) => { $crate::cv!(@cast $v => usize) };
>> + ($v:expr => i8) => { $crate::cv!(@cast $v => i8) };
>> + ($v:expr => i16) => { $crate::cv!(@cast $v => i16) };
>> + ($v:expr => i32) => { $crate::cv!(@cast $v => i32) };
>> + ($v:expr => i64) => { $crate::cv!(@cast $v => i64) };
>> + ($v:expr => i128) => { $crate::cv!(@cast $v => i128) };
>> + ($v:expr => isize) => { $crate::cv!(@cast $v => isize) };
>> + ($v:expr => $t:ty) => {
>> + <$t as $crate::num::FromConst<{ $crate::cv!(@cast $v => i128) }>>::VALUE
>> + };
>> + ($v:expr) => {
>> + <_ as $crate::num::FromConst<{ $crate::cv!(@cast $v => i128) }>>::VALUE
>> + };
>
> Can we document the arms a little bit? In particular the `=> u8`...
> business. No need to document every single one, one comment for the
> group is fine.
Done.
>
>> +}
>> +#[doc(inline)]
>> +pub use cv;
>> +
>> +/// Types that can be created from an integer constant expression validated at build time.
>> +///
>> +/// Implement this trait to make a type usable with [`cv!`]. Use the [`cv`] macro, not this trait
>> +/// directly, for creating values.
>> +#[diagnostic::on_unimplemented(message = "`{Self}` cannot be converted from a constant")]
>> +pub trait FromConst<const V: i128>: Sized {
>> + /// The value that corresponds to the constant `V`.
>> + ///
>> + /// Fails the build if `V` is not a valid value for `Self`.
>> + const VALUE: Self;
>> +}
>> +
>> +/// Implements [`FromConst`] for primitive integer types and their [`NonZero`](core::num::NonZero)
>> +/// versions.
>> +macro_rules! impl_from_const {
>> + ($($type:ty)*) => {
>> + $(
>> + impl<const V: i128> FromConst<V> for $type {
>> + const VALUE: Self = {
>> + const_assert!(
>> + V >= <$type>::MIN as i128 && V <= <$type>::MAX as i128,
>> + "constant cannot be represented by the target type"
>> + );
>> +
>> + V as $type
>> + };
>> + }
>> +
>> + impl<const V: i128> FromConst<V> for core::num::NonZero<$type> {
>> + const VALUE: Self = {
>> + const_assert!(
>> + V >= <$type>::MIN as i128 && V <= <$type>::MAX as i128,
>> + "constant cannot be represented by the underlying type"
>> + );
>> +
>> + match core::num::NonZero::new(V as $type) {
>> + Some(value) => value,
>> + None => panic!("constant cannot be zero"),
>> + }
>> + };
>> + }
>> + )*
>> + };
>> +}
>> +
>> +impl_from_const!(
>> + u8 u16 u32 u64 usize
>> + i8 i16 i32 i64 isize
>> +);
>> +
>> /// Designates unsigned primitive types.
>> pub enum Unsigned {}
>>
>> diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
>> index 2a2b0a4bca5e..f720eb44e7d3 100644
>> --- a/rust/kernel/num/bounded.rs
>> +++ b/rust/kernel/num/bounded.rs
>> @@ -14,6 +14,7 @@
>>
>> use kernel::{
>> num::{
>> + FromConst,
>> Integer,
>> Unsigned, //
>> },
>> @@ -272,6 +273,24 @@ pub const fn new<const VALUE: $type>() -> Self {
>> unsafe { Self::__new(VALUE) }
>> }
>> }
>> +
>> + impl<const N: u32, const V: i128> FromConst<V> for Bounded<$type, N> {
>> + const VALUE: Self = {
>> + const_assert!(
>> + V >= <$type>::MIN as i128 && V <= <$type>::MAX as i128,
>> + "constant cannot be represented by the underlying type"
>> + );
>
> Is it possible to leverage `cv!` on the primitive type to avoid this
> `const_assert`, which is basically a copy/paste of the one in `num.rs`?
>
> As a bonus you would also get a value of the right type and don't need
> to use `as` twice below.
Yeah good idea. It seems like this doens't work since by the time you
get inside the macro, it's already treating it as a $ty and that can't
match the primitive arms of cv!. But we can use FromConst::VALUE
directly, that's maybe a bit nicer.
>
>> + // Statically assert that `V` fits within the set number of bits.
>> + const_assert!(
>> + fits_within!(V as $type, $type, N),
>> + "constant cannot be represented within the given number of bits"
>> + );
>> +
>> + // SAFETY: the asserts above confirmed that `V` can be represented within `N`
>> + // bits.
>> + unsafe { Self::__new(V as $type) }
>> + };
>> + }
>> )*
>> };
>> }
>> diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
>> index 82acb531b17b..ac1662c3c8af 100644
>> --- a/rust/kernel/ptr.rs
>> +++ b/rust/kernel/ptr.rs
>> @@ -166,6 +166,20 @@ pub const fn mask(self) -> usize {
>> }
>> }
>>
>> +impl<const V: i128> crate::num::FromConst<V> for Alignment {
>> + const VALUE: Self = {
>> + const_assert!(
>> + V > 0 && V <= usize::MAX as i128,
>> + "constant cannot be represented as an Alignment"
>> + );
>
> Same here if that works. Otherwise let's add a `CAST:` comment to the
> `as` statement below using this `const_assert` above as justification.
>
> (also realized this could probably be done for the `NonZero` block as
> well)
Did the same using FromConst<> directly here. I did add two CAST:
comments on the base FromConst<V> for <primitive> though that are
unavoidable.
next prev parent reply other threads:[~2026-09-17 7:59 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-02 9:16 [PATCH v3 0/3] rust: introduce cv! macro for safe const conversions of integer-like types Eliot Courtney
2026-09-02 9:16 ` [PATCH v3 1/3] rust: num: add cv! macro to create values from constant expressions Eliot Courtney
2026-09-02 13:21 ` Gary Guo
2026-09-15 7:39 ` Alexandre Courbot
2026-09-17 7:59 ` Eliot Courtney [this message]
2026-09-17 8:53 ` Gary Guo
2026-09-02 9:16 ` [PATCH v3 2/3] rust: prelude: add `num::cv` Eliot Courtney
2026-09-15 7:40 ` Alexandre Courbot
2026-09-02 9:16 ` [PATCH v3 3/3] gpu: nova-core: use cv! for constant casts Eliot Courtney
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DLHFKT44IHW9.2QWQB0O0LJHJJ@nvidia.com \
--to=ecourtney@nvidia.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=apopple@nvidia.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel-bounces@lists.freedesktop.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=nova-gpu@lists.linux.dev \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=ttabi@nvidia.com \
--cc=work@onurozkan.dev \
--cc=yury.norov@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®