Re: [PATCH 2/2] rust: num: add `cv!` macro to create values from constant expressions
From: Gary Guo
Date: Mon Aug 31 2026 - 09:22:55 EST
On Mon Aug 31, 2026 at 8:20 AM BST, Eliot Courtney wrote:
> On Fri Aug 28, 2026 at 9:03 PM JST, Gary Guo wrote:
>> Currently, constructing a `NonZero` or `Bounded` from a constant is
>> verbose. The former would require `const { NonZero::new(...).unwrap() }`
>> and the latter require turbofish. Similarly, the `num::casts` exposes
>> methods that cast numbers using turbofish syntax, which is unergonomic and
>> unnecessarily causes the value to flow into the type system, which is very
>> restrictive without `generic_const_exprs`.
>>
>> Implement a macro `cv!` (short for constant value) which converts a const
>> integer to types that implements `FromConst` trait and validate them during
>> const evaluation.
>>
>> The usage is of form
>>
>> cv!(<expression>)
>>
>> for inferred type and
>>
>> cv!(<expression> => <type>)
>>
>> for explicit type specification.
>>
>> As we do not have const trait implementation yet, dark magic is used. The
>> dark magic is documented in the code, but in essence it defines inherent
>> `__from_const` impls on types, which can be marked const, and rely on
>> Rust's method resolution algorithm to pick the correct function. Multiple
>> helpers are defined to aid type inference to work properly.
>>
>> As a result, this allows construction of primitive integers, `NonZero`,
>> `Bounded`, `Alignment` using a single `cv!` macro. This macro does not have
>> `generic_const_exprs` restrictions (e.g. in a function with `const N: u32`
>> generic parameter, you may use `cv!(N + 1)`), it supports full type
>> inference and it has nice error messages in some common error scenario:
>>
>> error[E0080]: evaluation panicked: constant is zero
>> --> example.rs:22:25
>> |
>> 22 | const X: NonZero<u32> = cv!(0);
>> | ^^^^^^ evaluation of `X::{constant#0}` failed inside this call
>>
>> error[E0277]: `kernel::page::Page` cannot be converted from constant
>> --> example.rs:22:17
>> |
>> 22 | const X: Page = cv!(0);
>> | ^^^^^^ the trait `kernel::num::FromConst` is not implemented for `kernel::page::Page`
>>
>> Of course, this trick is not full const trait impl. So the following code cannot work properly:
>>
>> fn generic<T: FromConst>() -> T {
>> cv!(0)
>> }
>>
>> That said, useful error message is still produced in this context.
>>
>> error[E0080]: evaluation panicked: `cv!()` cannot be used with generic types yet
>> --> example.rs:23:5
>> |
>> 22 | cv!(0)
>> | ^^^^^^ evaluation of `generic::<u32>::{constant#0}` failed inside this call
>>
>> Co-developed-by: Eliot Courtney <ecourtney@xxxxxxxxxx>
>> Signed-off-by: Eliot Courtney <ecourtney@xxxxxxxxxx>
>> Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
>> ---
>> I used part of
>> https://lore.kernel.org/rust-for-linux/20260827-chid-v8-3-bc74c77d0214@xxxxxxxxxx
>> so I added Co-developed-by tags of Eliot. Eliot, please let me know if this
>> is okay.
>> ---
>
> Yes, co-developed-by/signed-off-by lgtm, no worries.
>
> I had also considered using auto deref method resolution to solve this,
> but I think it's a little overcomplicated, so I just posted the
> associated const version instead. AFAICT this gives us the ability to
> use const generic expressions on non-primitive types and type aliases of
> primitive types, over associated const cv!. Currently there are no
> (prospective) users for that ability.
>
> I think also that this version is not a strict superset of the
> functionality of the associated const based cv!. For example, associated
> const cv! has better errors in some cases and can do things like this,
> in the T: Trait case you noted (plus some edge cases around i128/u128
> handling):
>
> ```fn zero<T: FromConst<0>>() -> T { cv!(0) }```
True, although I think we should also not encourage users doing this for now, as
we don't want to make this signature of `FromConst` being the long term version
and it'd be good if we can swap the impl at any time.
I do wonder if we should have the `FromConst` trait being aspirational const
trait so it has the signature (and documentation) that looks like what is in
this series, and perhaps have the `FromConst<const N: i128>` being a hidden,
differently named trait, e.g. `FromConstImpl`. Might need some work to ensure
diagnostics will stay good, though.
>
> For the above reasons, plus what Alex mentioned, I prefer the simpler
> associated const version for now, particularly since we could
> transparently switch them later.
Yes, I think it's better to have assoc const version for now, unless we got a
user that actually need the extended capability of using it with const generic
expression, then we can make the switch. The good thing is that we know how to
achieve it nicely now.
That said, there are a few tweaks in this version that improve diagnostics (e.g.
having explicit panic messages in places, diagnostics attributes) which might
worth incorporating into your next version.
Best,
Gary