Re: [PATCH v8 03/12] rust: num: add cv! macro to create values from constant expressions

"Eliot Courtney" <[email protected]>
Newsgroups dev.linux.lists.nova-gpu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.rust-for-linux
Message-ID <[email protected]>
On Fri Aug 28, 2026 at 12:40 PM JST, Alexandre Courbot wrote:
[...]
>> Using an associated const by itself appears to work - I tried this which
>> is very similar to Alice's suggested approach above:
>>
>> ```
>> macro_rules! const_assert {
>>     ($condition:expr $(,$arg:literal)?) => {
>>         const { ::core::assert!($condition $(,$arg)?) };
>>     };
>> }
>
> Any reason this cannot use the `const_assert` already in the kernel
> crate?

No reason. I prototyped this in a single file so I had some misc shims.
This is just me copy pasting badly.

>
>>
>> trait FromConst<const V: i128>: Sized {
>>     const VALUE: Self;
>> }
>>
>> macro_rules! cv {
>>     (@widen $v:expr) => {{
>>         #[allow(unused_comparisons, unused_assignments)]
>>         {
>>             let v = $v;
>>             let r = v as i128;
>>             let mut back = v;
>>             back = r as _;
>>
>>             ::core::assert!(
>>                 back == v && (v < 0) == (r < 0),
>>                 "value cannot be losslessly widened to `i128`"
>>             );
>>
>>             r
>>         }
>>     }};
>>     ($v:expr => $t:ty) => {
>>         <$t as FromConst<{ cv!(@widen $v) }>>::VALUE
>
> nit for the actual posting: make sure to fully qualify `cv` when calling
> it recursively (and make sure all symbols are fully qualified).
>
>>     };
>>     ($v:expr) => {
>>         <_ as FromConst<{ cv!(@widen $v) }>>::VALUE
>>     };
>> }
>>
>> macro_rules! impl_from_const_int {
>>     ($($t:ty)*) => {$(
>>         impl<const V: i128> FromConst<V> for $t {
>>             const VALUE: Self = {
>>                 const_assert!(
>>                     V >= <$t>::MIN as i128 && V <= <$t>::MAX as i128,
>>                     "Constant cannot be represented by the target type."
>>                 );
>>                 V as $t
>>             };
>>         }
>>
>>         impl<const V: i128> FromConst<V> for NonZero<$t> {
>>             const VALUE: Self = {
>>                 const_assert!(
>>                     V >= <$t>::MIN as i128 && V <= <$t>::MAX as i128,
>>                     "Constant cannot be represented by the underlying type."
>>                 );
>
> Let's also have a `const_assert!(V != 0, ...)` to provide a better
> error message than "unwrap on None" if users call this with 0.

Sounds good~

>
>>                 NonZero::new(V as $t).unwrap()
>>             };
>>         }
>>     )*};
>> }
>> impl_from_const_int!(u8 u16 u32 u64 usize i8 i16 i32 i64 isize);
>>
>> impl<const V: i128> FromConst<V> for Alignment {
>>     const VALUE: Self = {
>>         const_assert!(V > 0 && V <= usize::MAX as i128);
>>         // The unwrap fails the build if `V` is not a power of two.
>>         Alignment::new_checked(V as usize).unwrap()
>>     };
>> }
>>
>> const A: u8 = cv!(200u32);
>> const B: NonZero<u8> = cv!(5);
>> const C: Alignment = cv!(4096);
>> const D: u8 = cv!(200u32 => u8);
>> ```
>
> That looks like it could work! IIUC it even supports something like
> `cv!(x => NonZero<u8>)`. The only limitation is see is that this cannot
> take expressions using generic parameters, but we can probably work
> around that.

Yeah agreed. One workaround is just to list each primitive type in the
macro, although it doesn't work if you define a type alias or something.
I think that's reasonable and not too complex. FWIW I found one
potential user that would want to be able to reference generics in cv!.
In drm::Device:
`num_ioctls: T::IOCTLS.len() as i32,`
wants to be `cv!(T::IOCTLS.len() => i32),` which needs this.

>
> I guess you'll want to split this out into its own series so it doesn't
> remain hidden within the ranges/bitmap work. Basically as a replacement
> for the `const_as` I was driving [1]. I'll recycle the `const_as` series
> to just switch to the kernel converters, and will follow-up with using
> `cv!` once it lands.
>
> Since this is going to be a multi-cycle effort we should probably keep
> the legacy `*_into_*` functions around for now and remove them in
> another patch once all users are converted.
>
> [1] https://lore.kernel.org/[email protected]

Yes I'll split it out. Thanks!
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.