The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH 0/2] rust: num: casts: replace const type narrowing methods with a macro
@ 2026-08-25  2:44 Alexandre Courbot
  2026-08-25  2:44 ` [PATCH 1/2] " Alexandre Courbot
  2026-08-25  2:44 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
  0 siblings, 2 replies; 14+ messages in thread
From: Alexandre Courbot @ 2026-08-25  2:44 UTC (permalink / raw)
  To: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, rust-for-linux, linux-kernel, nova-gpu,
	Alexandre Courbot

The `casts` module includes lossless const converter functions, as it is
sometimes necessary to cast a bindgen-generated constant into a narrower
type. Such conversions are known to be lossless at compile-time, but
using `as` for them still requires a `CAST` comment and carries the risk
of the conversion becoming lossy should the value of the constant
change.

Since these functions need to be evaluated at compile-time, they take
the expression to narrow as a generic const argument, requiring the use
of the turbofish syntax by callers. Also, a dedicated function is needed
per type conversion, resulting in 9 functions generated by a single
macro. All these factors make them hard to discover and a bit cumbersome
to use.

This series replaces these functions with a single `const_as` macro that
ensures an `as` conversion is lossless at build-time. Since it is unique
and not generated, it is easy to discover, and its syntax also looks
more accessible than the turbofish one.

Patch 2 then performs the conversion of nova-core to use these
conversion helpers in the process of removing its own superseded `num`
module.

This series is based on today's `master`.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
Alexandre Courbot (2):
      rust: num: casts: replace const type narrowing methods with a macro
      gpu: nova-core: use kernel lossless integer conversion module

 drivers/gpu/nova-core/falcon.rs                    |  12 +-
 drivers/gpu/nova-core/falcon/fsp.rs                |   4 +-
 drivers/gpu/nova-core/fb.rs                        |   2 +-
 drivers/gpu/nova-core/fb/hal/gb100.rs              |   9 +-
 drivers/gpu/nova-core/firmware.rs                  |   4 +-
 drivers/gpu/nova-core/firmware/booter.rs           |   4 +-
 drivers/gpu/nova-core/firmware/fwsec.rs            |   2 +-
 drivers/gpu/nova-core/firmware/fwsec/bootloader.rs |   4 +-
 drivers/gpu/nova-core/firmware/gsp.rs              |   9 +-
 drivers/gpu/nova-core/firmware/tlv.rs              |  11 +-
 drivers/gpu/nova-core/fsp.rs                       |   8 +-
 drivers/gpu/nova-core/gsp.rs                       |   4 +-
 drivers/gpu/nova-core/gsp/cmdq.rs                  |  22 +--
 drivers/gpu/nova-core/gsp/fw.rs                    |  50 ++---
 drivers/gpu/nova-core/gsp/fw/commands.rs           |   4 +-
 drivers/gpu/nova-core/gsp/sequencer.rs             |   2 +-
 drivers/gpu/nova-core/mctp.rs                      |   8 +-
 drivers/gpu/nova-core/num.rs                       | 211 ---------------------
 drivers/gpu/nova-core/vbios.rs                     |   2 +-
 rust/kernel/num/casts.rs                           | 129 ++++++++-----
 20 files changed, 163 insertions(+), 338 deletions(-)
---
base-commit: 66498c75b4f8017f62d720d9b59675bdf3abce91
change-id: 20260825-const_as-a792dad39943

Best regards,
--  
Alexandre Courbot <acourbot@nvidia.com>


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

* [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25  2:44 [PATCH 0/2] rust: num: casts: replace const type narrowing methods with a macro Alexandre Courbot
@ 2026-08-25  2:44 ` Alexandre Courbot
  2026-08-25  7:18   ` Eliot Courtney
                     ` (2 more replies)
  2026-08-25  2:44 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
  1 sibling, 3 replies; 14+ messages in thread
From: Alexandre Courbot @ 2026-08-25  2:44 UTC (permalink / raw)
  To: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, rust-for-linux, linux-kernel, nova-gpu,
	Alexandre Courbot

The casts module features a series of const converters (e.g.
`u32_into_u16`) that narrow the type of a const expression provided that
its value can be proven to fit into the destination type at
compile-time.

These functions are numerous (9 of them), generated by a macro and thus
not easily discoverable, and cumbersome to use as they require a
turbofish and const expression between `{` and `}` braces.

Replace them all by a single `const_as!` macro that expands to a const
block verifying the lossless nature of the conversion at compile-time.
This turns e.g.:

    const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();

into

    const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);

This makes things easier to read and understand, while shifting the
burden of checking the conversion's validity from reviewers (via a CAST
comment) to the compiler.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 rust/kernel/num/casts.rs | 129 +++++++++++++++++++++++++++++------------------
 1 file changed, 79 insertions(+), 50 deletions(-)

diff --git a/rust/kernel/num/casts.rs b/rust/kernel/num/casts.rs
index 7e6c7dec747d..a4a18a6f2ba8 100644
--- a/rust/kernel/num/casts.rs
+++ b/rust/kernel/num/casts.rs
@@ -20,10 +20,8 @@
 //! - Two extension traits, [`FromSafeCast`] and [`IntoSafeCast`], providing conversion methods
 //!   similar to [`From`] and [`Into`] for conversions that are safe to perform in the kernel, but
 //!   not supported by the standard library.
-//! - Another series of const functions (e.g. [`u64_into_u8`]) supporting the conversion of a const
-//!   value from a larger type into a smaller one, provided the value fits into the destination
-//!   type. This is useful if a constant is defined as a larger type, but needs to be used as a
-//!   smaller one.
+//! - A [`const_as!`] macro, losslessly casting a constant expression between any two integer
+//!   types, with conversions that would alter the value reported as build errors.
 //! - An [`arch`] sub-module, defining more conversion functions that are only guaranteed to be
 //!   lossless for a given pointer size. These can only be used in code that is specific to a
 //!   given pointer size.
@@ -36,6 +34,9 @@
 //! // Conversion from const context.
 //! const USIZED_CONST: usize = casts::u8_as_usize(255u8);
 //!
+//! // Build-time checked narrowing conversion of a constant expression.
+//! const NARROWED_CONST: u16 = casts::const_as!(0xf00u32 => u16);
+//!
 //! // Non-const conversions.
 //! let a = u64::from_safe_cast(4096usize);
 //! let b: u64 = 4096usize.into_safe_cast();
@@ -182,57 +183,85 @@ fn into_safe_cast(self) -> T {
     }
 }
 
-/// Implements lossless conversion of a constant from a larger type into a smaller one.
-macro_rules! impl_const_into {
-    ($from:ty => { $($into:ty),* }) => {
-        $(
-        $crate::macros::paste! {
-            #[doc = ::core::concat!(
-                "Performs a build-time safe conversion of a [`",
-                ::core::stringify!($from),
-                "`] constant value into a [`",
-                ::core::stringify!($into),
-                "`].")]
-            ///
-            /// This checks at compile-time that the conversion is lossless, and triggers a build
-            /// error if it isn't.
-            ///
-            /// # Examples
-            ///
-            /// ```
-            /// use kernel::num::casts;
-            ///
-            /// // Succeeds because the value of the source fits into the destination's type.
-            #[doc = ::core::concat!(
-                "assert_eq!(casts::",
-                ::core::stringify!($from),
-                "_into_",
-                ::core::stringify!($into),
-                "::<1",
-                ::core::stringify!($from),
-                ">(), 1",
-                ::core::stringify!($into),
-                ");")]
-            /// ```
-            #[inline]
-            pub const fn [<$from _into_ $into>]<const N: $from>() -> $into {
-                // Make sure that the target type is smaller than the source one.
-                $crate::static_assert!($from::BITS >= $into::BITS);
-                // CAST: we statically enforced above that `$from` is larger than `$into`, so the
-                // `as` conversion will be lossless.
-                $crate::const_assert!(N >= $into::MIN as $from && N <= $into::MAX as $from);
+/// Losslessly casts a constant expression into a target integer type, or fails the build.
+///
+/// This is a checked replacement for the `as` keyword on constant expressions: the conversion is
+/// evaluated at build time, and a build error is triggered if the source value does not fit into
+/// the destination type. Since the compiler verifies that the conversion is lossless, a `CAST`
+/// comment is not needed.
+///
+/// The argument is a constant expression.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::num::casts;
+///
+/// // Narrows the type of a constant in const context.
+/// const CAP_ID: u16 = casts::const_as!(0x0010u32 => u16);
+/// assert_eq!(CAP_ID, 0x0010u16);
+///
+/// // Widens the type of a constant, outside of const context.
+/// let v: u64 = casts::const_as!(42u16 => u64);
+/// assert_eq!(v, 42u64);
+///
+/// // Signed conversions work as well...
+/// assert_eq!(casts::const_as!(-42i32 => i16), -42i16);
+///
+/// // ...and so do cross-signedness conversions as long as the value fits.
+/// assert_eq!(casts::const_as!(258i32 => u16), 258u16);
+/// ```
+///
+/// A value that does not fit into the destination type fails to build:
+///
+/// ```ignore,compile_fail
+/// # use kernel::num::casts;
+/// // Fails to build: `0x10000` does not fit into a `u16`.
+/// const ID: u16 = casts::const_as!(0x10000u32 => u16);
+/// ```
+///
+/// Conversions that alter the value also fail to build:
+///
+/// ```ignore,compile_fail
+/// # use kernel::num::casts;
+/// // Fails to build: `-1i64 as u64` yields `u64::MAX`.
+/// const V: u64 = casts::const_as!(-1i64 => u64);
+/// ```
+///
+/// Runtime values are rejected:
+///
+/// ```ignore,compile_fail
+/// # use kernel::num::casts;
+/// fn f(v: u32) -> u16 {
+///     // Fails to build: `v` is not a constant expression.
+///     casts::const_as!(v => u16)
+/// }
+/// ```
+#[macro_export]
+#[doc(hidden)]
+macro_rules! const_as {
+    ($v:expr => $into:ty) => {
+        const {
+            #[allow(unused_comparisons, unused_assignments, clippy::as_underscore)]
+            {
+                let v = $v;
+                let r = v as $into;
+                // Pin `back` to `v`'s type so `as _` casts back to the source type.
+                let mut back = v;
+                back = r as _;
 
-                N as $into
+                ::core::assert!(
+                    back == v && (v < 0) == (r < 0),
+                    "value does not fit into the target type"
+                );
+
+                r
             }
         }
-        )*
     };
 }
-
-impl_const_into!(usize => { u8, u16, u32 });
-impl_const_into!(u64 => { u8, u16, u32 });
-impl_const_into!(u32 => { u8, u16 });
-impl_const_into!(u16 => { u8 });
+#[doc(inline)]
+pub use const_as;
 
 /// Conversions that are only lossless for the current architecture.
 ///

-- 
2.55.0


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

* [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module
  2026-08-25  2:44 [PATCH 0/2] rust: num: casts: replace const type narrowing methods with a macro Alexandre Courbot
  2026-08-25  2:44 ` [PATCH 1/2] " Alexandre Courbot
@ 2026-08-25  2:44 ` Alexandre Courbot
  2026-08-25  5:27   ` Eliot Courtney
  1 sibling, 1 reply; 14+ messages in thread
From: Alexandre Courbot @ 2026-08-25  2:44 UTC (permalink / raw)
  To: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, rust-for-linux, linux-kernel, nova-gpu,
	Alexandre Courbot

The `kernel` crate now features a replacement for our lossless integer
conversion routines. Switch to the kernel version and remove our own.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 drivers/gpu/nova-core/falcon.rs                    |  12 +-
 drivers/gpu/nova-core/falcon/fsp.rs                |   4 +-
 drivers/gpu/nova-core/fb.rs                        |   2 +-
 drivers/gpu/nova-core/fb/hal/gb100.rs              |   9 +-
 drivers/gpu/nova-core/firmware.rs                  |   4 +-
 drivers/gpu/nova-core/firmware/booter.rs           |   4 +-
 drivers/gpu/nova-core/firmware/fwsec.rs            |   2 +-
 drivers/gpu/nova-core/firmware/fwsec/bootloader.rs |   4 +-
 drivers/gpu/nova-core/firmware/gsp.rs              |   9 +-
 drivers/gpu/nova-core/firmware/tlv.rs              |  11 +-
 drivers/gpu/nova-core/fsp.rs                       |   8 +-
 drivers/gpu/nova-core/gsp.rs                       |   4 +-
 drivers/gpu/nova-core/gsp/cmdq.rs                  |  22 +--
 drivers/gpu/nova-core/gsp/fw.rs                    |  50 ++---
 drivers/gpu/nova-core/gsp/fw/commands.rs           |   4 +-
 drivers/gpu/nova-core/gsp/sequencer.rs             |   2 +-
 drivers/gpu/nova-core/mctp.rs                      |   8 +-
 drivers/gpu/nova-core/num.rs                       | 211 ---------------------
 drivers/gpu/nova-core/vbios.rs                     |   2 +-
 19 files changed, 84 insertions(+), 288 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 65cb12d26e2b..eb54aa41e8bf 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -20,6 +20,10 @@
         },
         Io,
     },
+    num::casts::{
+        self,
+        FromSafeCast, //
+    },
     prelude::*,
     time::Delta,
 };
@@ -29,11 +33,7 @@
     driver::Bar0,
     falcon::hal::LoadMethod,
     gpu::Chipset,
-    num::{
-        self,
-        FromSafeCast, //
-    },
-    regs,
+    regs, //
 };
 
 pub(crate) mod fsp;
@@ -510,7 +510,7 @@ fn dma_wr(
         target_mem: FalconMem,
         load_offsets: FalconDmaLoadTarget,
     ) -> Result {
-        const DMA_LEN: u32 = num::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
+        const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);
 
         // DMA transfers can only be done in units of 256 bytes. Compute how many such transfers we
         // need to perform.
diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs
index 0437180b8829..2470ac511c98 100644
--- a/drivers/gpu/nova-core/falcon/fsp.rs
+++ b/drivers/gpu/nova-core/falcon/fsp.rs
@@ -16,6 +16,7 @@
         },
         Io, //
     },
+    num::casts,
     prelude::*,
     sizes::SZ_1K,
     time::Delta,
@@ -28,7 +29,6 @@
         PFalcon2Base,
         PFalconBase, //
     },
-    num,
     regs, //
 };
 
@@ -165,7 +165,7 @@ pub(crate) fn recv_msg(&mut self) -> Result<KVec<u8>> {
             Delta::from_millis(10),
             Delta::from_millis(FSP_MSG_TIMEOUT_MS),
         )
-        .map(num::u32_as_usize)?;
+        .map(casts::u32_as_usize)?;
 
         // Don't blindly allocate more than the maximum we expect from FSP.
         if msg_size > FSP_EMEM_CHANNEL_0_SIZE {
diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index 1576399389b1..8d5d9480378f 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -10,6 +10,7 @@
     dma::CoherentHandle,
     fmt,
     io::Io,
+    num::casts::FromSafeCast,
     prelude::*,
     ptr::{
         Alignable,
@@ -23,7 +24,6 @@
     firmware::gsp::GspFirmware,
     gpu::Chipset,
     gsp,
-    num::FromSafeCast,
     vgpu::VgpuState, //
 };
 
diff --git a/drivers/gpu/nova-core/fb/hal/gb100.rs b/drivers/gpu/nova-core/fb/hal/gb100.rs
index d9e4d62ae632..8fb94696c715 100644
--- a/drivers/gpu/nova-core/fb/hal/gb100.rs
+++ b/drivers/gpu/nova-core/fb/hal/gb100.rs
@@ -11,7 +11,10 @@
         },
         Io, //
     },
-    num::Bounded,
+    num::{
+        casts,
+        Bounded, //
+    },
     prelude::*,
     ptr::{
         const_align_up,
@@ -26,7 +29,6 @@
         hal::FbHal,
         regs, //
     },
-    num::usize_into_u32,
 };
 
 struct Gb100;
@@ -82,7 +84,8 @@ fn write_sysmem_flush_page_gb100(bar: Bar0<'_>, addr: Bounded<u64, 52>) {
 
 // This PMU reservation size is r570-specific.
 pub(super) const fn pmu_reserved_size_gb100() -> u32 {
-    usize_into_u32::<{ const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap() }>(
+    casts::const_as!(
+        const_align_up(SZ_8M + SZ_16M + SZ_4K, Alignment::new::<SZ_128K>()).unwrap() => u32
     )
 }
 
diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
index b49613a90bf0..19f13779bb30 100644
--- a/drivers/gpu/nova-core/firmware.rs
+++ b/drivers/gpu/nova-core/firmware.rs
@@ -9,6 +9,7 @@
 
 use kernel::{
     firmware,
+    num::casts::IntoSafeCast,
     prelude::*, //
 };
 
@@ -18,8 +19,7 @@
         FalconFirmware, //
     },
     gpu,
-    gsp::boot_firmware_files,
-    num::IntoSafeCast, //
+    gsp::boot_firmware_files, //
 };
 
 pub(crate) mod booter;
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs
index dc071edba331..aa830455b7e7 100644
--- a/drivers/gpu/nova-core/firmware/booter.rs
+++ b/drivers/gpu/nova-core/firmware/booter.rs
@@ -10,6 +10,7 @@
 use kernel::{
     device,
     dma::Coherent,
+    num::casts::IntoSafeCast,
     prelude::*, //
 };
 
@@ -32,8 +33,7 @@
         Signed,
         Unsigned, //
     },
-    gpu::Chipset,
-    num::IntoSafeCast,
+    gpu::Chipset, //
 };
 
 /// Signature for Booter firmware. Their size is encoded into the header and not known a compile
diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs
index 7a931f22f629..7f7ca3ba2298 100644
--- a/drivers/gpu/nova-core/firmware/fwsec.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec.rs
@@ -19,6 +19,7 @@
         self,
         Device, //
     },
+    num::casts::FromSafeCast,
     prelude::*,
     transmute::{
         AsBytes,
@@ -42,7 +43,6 @@
         Signed,
         Unsigned, //
     },
-    num::FromSafeCast,
     vbios::Vbios,
 };
 
diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
index ec4d92317a93..d1fb7d2d7480 100644
--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -13,6 +13,7 @@
     },
     dma::Coherent,
     io::{register::WithBase, Io},
+    num::casts::FromSafeCast,
     prelude::*,
     ptr::{
         Alignable,
@@ -45,8 +46,7 @@
         },
     },
     gpu::Chipset,
-    num::FromSafeCast, //
-    regs,
+    regs, //
 };
 
 /// Structure used by the boot-loader to load the rest of the code.
diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs
index e8f9491e84cc..e75ce6fe47d8 100644
--- a/drivers/gpu/nova-core/firmware/gsp.rs
+++ b/drivers/gpu/nova-core/firmware/gsp.rs
@@ -9,6 +9,10 @@
         DmaAddress, //
     },
     firmware,
+    num::casts::{
+        arch::FromSafeCastArch,
+        FromSafeCast, //
+    },
     prelude::*,
     scatterlist::{
         Owned,
@@ -26,8 +30,7 @@
         },
     },
     gpu::Chipset,
-    gsp::GSP_PAGE_SIZE,
-    num::FromSafeCast,
+    gsp::GSP_PAGE_SIZE, //
 };
 
 /// GSP firmware with 3-level radix page tables for the GSP bootloader.
@@ -154,7 +157,7 @@ pub(crate) fn radix3_dma_address(&self) -> DmaAddress {
 fn map_into_lvl(sg_table: &SGTable<Owned<VVec<u8>>>, mut dst: VVec<u8>) -> Result<VVec<u8>> {
     for sg_entry in sg_table.iter() {
         // Number of pages we need to map.
-        let num_pages = usize::from_safe_cast(sg_entry.dma_len()).div_ceil(GSP_PAGE_SIZE);
+        let num_pages = usize::from_safe_cast_arch(sg_entry.dma_len()).div_ceil(GSP_PAGE_SIZE);
 
         for i in 0..num_pages {
             let entry = sg_entry.dma_address()
diff --git a/drivers/gpu/nova-core/firmware/tlv.rs b/drivers/gpu/nova-core/firmware/tlv.rs
index 7b879f13a61e..6653c10e3e0a 100644
--- a/drivers/gpu/nova-core/firmware/tlv.rs
+++ b/drivers/gpu/nova-core/firmware/tlv.rs
@@ -4,14 +4,15 @@
 use kernel::{
     device,
     firmware,
+    num::casts::{
+        self,
+        IntoSafeCast, //
+    },
     prelude::*,
     str::CString, //
 };
 
-use crate::{
-    gpu,
-    num::*, //
-};
+use crate::gpu;
 
 /// Requests the GPU firmware TLV `name` suitable for `chipset`.
 pub(crate) fn request_tlv(
@@ -51,7 +52,7 @@ fn parse(hdr: &[u8]) -> Option<Self> {
             return None;
         }
         let len_arr = <[u8; 4]>::try_from(hdr.get(4..Self::SIZE)?).ok()?;
-        let length = u32_as_usize(u32::from_le_bytes(len_arr));
+        let length = casts::u32_as_usize(u32::from_le_bytes(len_arr));
         Some(Self { tag, length })
     }
 }
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index ab685fb4168f..bd8505addd25 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -11,7 +11,10 @@
     device,
     dma::Coherent,
     io::poll::read_poll_timeout,
-    num::TryIntoBounded,
+    num::{
+        casts,
+        TryIntoBounded, //
+    },
     prelude::*,
     ptr::{
         Alignable,
@@ -47,7 +50,6 @@
         NvdmHeader,
         NvdmType, //
     },
-    num,
     regs, //
 };
 
@@ -285,7 +287,7 @@ fn new<'a>(
         };
 
         let version = hal.cot_version();
-        let size = num::usize_into_u16::<{ core::mem::size_of::<NvdmPayloadCot>() }>();
+        let size = casts::const_as!(core::mem::size_of::<NvdmPayloadCot>() => u16);
 
         Ok(init!(Self {
             header: FspMessageHeader::new(NvdmType::Cot),
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 13f361406a6c..fc8648de84c2 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -17,6 +17,7 @@
         io_write,
         Io, //
     },
+    num::casts,
     pci,
     prelude::*, //
 };
@@ -48,7 +49,6 @@
         cmdq::Cmdq,
         fw::GspArgumentsPadded, //
     },
-    num,
     vgpu::VgpuManager, //
 };
 
@@ -92,7 +92,7 @@ fn init(view: CoherentView<'_, Self>, start: DmaAddress) -> Result<()> {
         for i in 0..NUM_PAGES {
             io_write!(view, .0[build: i],
                 start
-                    .checked_add(num::usize_as_u64(i) << GSP_PAGE_SHIFT)
+                    .checked_add(casts::usize_as_u64(i) << GSP_PAGE_SHIFT)
                     .ok_or(EOVERFLOW)?
             );
         }
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 6da728201281..99e775f6071e 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -23,6 +23,7 @@
         Io, //
     },
     new_mutex,
+    num::casts,
     prelude::*,
     ptr,
     sync::{
@@ -57,7 +58,6 @@
         GSP_PAGE_SHIFT,
         GSP_PAGE_SIZE, //
     },
-    num,
     sbuffer::SBufferIter, //
 };
 
@@ -162,7 +162,7 @@ fn read(
 #[repr(C, align(0x1000))]
 #[derive(Debug)]
 struct MsgqData {
-    data: [[u8; GSP_PAGE_SIZE]; num::u32_as_usize(MSGQ_NUM_PAGES)],
+    data: [[u8; GSP_PAGE_SIZE]; casts::u32_as_usize(MSGQ_NUM_PAGES)],
 }
 
 // Annoyingly we are forced to use a literal to specify the alignment of
@@ -235,8 +235,8 @@ unsafe impl FromBytes for GspMem {}
 impl DmaGspMem {
     /// Allocate a new instance and map it for `dev`.
     fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
-        const MSGQ_SIZE: u32 = num::usize_into_u32::<{ size_of::<Msgq>() }>();
-        const RX_HDR_OFF: u32 = num::usize_into_u32::<{ mem::offset_of!(Msgq, rx) }>();
+        const MSGQ_SIZE: u32 = casts::const_as!(size_of::<Msgq>() => u32);
+        const RX_HDR_OFF: u32 = casts::const_as!(mem::offset_of!(Msgq, rx) => u32);
 
         let mut gsp_mem = CoherentBox::<GspMem>::zeroed(dev, GFP_KERNEL)?;
         gsp_mem.cpuq.tx = MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES);
@@ -289,10 +289,10 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
         unsafe {
             (
                 core::slice::from_raw_parts_mut(
-                    data.add(num::u32_as_usize(tx)),
-                    num::u32_as_usize(tail_end - tx),
+                    data.add(casts::u32_as_usize(tx)),
+                    casts::u32_as_usize(tail_end - tx),
                 ),
-                core::slice::from_raw_parts_mut(data, num::u32_as_usize(wrap_end)),
+                core::slice::from_raw_parts_mut(data, casts::u32_as_usize(wrap_end)),
             )
         }
     }
@@ -307,7 +307,7 @@ fn driver_write_area_size(&self) -> usize {
         // `cpu_write_ptr`. The minimum value case is where `rx == 0` and `tx == MSGQ_NUM_PAGES -
         // 1`, which gives `0 + MSGQ_NUM_PAGES - (MSGQ_NUM_PAGES - 1) - 1 == 0`.
         let slots = (rx + MSGQ_NUM_PAGES - tx - 1) % MSGQ_NUM_PAGES;
-        num::u32_as_usize(slots) * GSP_PAGE_SIZE
+        casts::u32_as_usize(slots) * GSP_PAGE_SIZE
     }
 
     /// Returns the region of the GSP message queue that the driver is currently allowed to read
@@ -343,10 +343,10 @@ fn driver_write_area_size(&self) -> usize {
         unsafe {
             (
                 core::slice::from_raw_parts(
-                    data.add(num::u32_as_usize(rx)),
-                    num::u32_as_usize(tail_end - rx),
+                    data.add(casts::u32_as_usize(rx)),
+                    casts::u32_as_usize(tail_end - rx),
                 ),
-                core::slice::from_raw_parts(data, num::u32_as_usize(wrap_end)),
+                core::slice::from_raw_parts(data, casts::u32_as_usize(wrap_end)),
             )
         }
     }
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 05f54fee6186..c05991a72e48 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -19,6 +19,10 @@
         io_read,
         io_write, //
     },
+    num::casts::{
+        self,
+        FromSafeCast, //
+    },
     prelude::*,
     ptr::{
         Alignable,
@@ -49,15 +53,11 @@
         cmdq::Cmdq, //
         GSP_PAGE_SIZE,
     },
-    num::{
-        self,
-        FromSafeCast, //
-    },
 };
 
 /// Maximum size of a single GSP message queue element in bytes.
 pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize =
-    num::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX);
+    casts::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX);
 
 /// Empty type to group methods related to heap parameters for running the GSP firmware.
 enum GspFwHeapParams {}
@@ -110,19 +110,19 @@ pub(crate) struct LibosParams {
 impl LibosParams {
     /// Version 2 of the GSP LIBOS (Turing and GA100)
     const LIBOS2: LibosParams = LibosParams {
-        carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS2),
-        allowed_heap_size: num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB)
+        carveout_size: casts::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS2),
+        allowed_heap_size: casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MIN_MB)
             * u64::SZ_1M
-            ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB) * u64::SZ_1M,
+            ..casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS2_MAX_MB) * u64::SZ_1M,
     };
 
     /// Version 3 of the GSP LIBOS (GA102+)
     const LIBOS3: LibosParams = LibosParams {
-        carveout_size: num::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL),
-        allowed_heap_size: num::u32_as_u64(
+        carveout_size: casts::u32_as_u64(bindings::GSP_FW_HEAP_PARAM_OS_SIZE_LIBOS3_BAREMETAL),
+        allowed_heap_size: casts::u32_as_u64(
             bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MIN_MB,
         ) * u64::SZ_1M
-            ..num::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB)
+            ..casts::u32_as_u64(bindings::GSP_FW_HEAP_SIZE_OVERRIDE_LIBOS3_BAREMETAL_MAX_MB)
                 * u64::SZ_1M,
     };
 
@@ -681,13 +681,13 @@ fn id8(name: &str) -> u64 {
         let init_inner = init!(bindings::LibosMemoryRegionInitArgument {
             id8: id8(name),
             pa: obj.dma_address(),
-            size: num::usize_as_u64(obj.size()),
-            kind: num::u32_into_u8::<
-                { bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS },
-            >(),
-            loc: num::u32_into_u8::<
-                { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM },
-            >(),
+            size: casts::usize_as_u64(obj.size()),
+            kind: casts::const_as!(
+                bindings::LibosMemoryRegionKind_LIBOS_MEMORY_REGION_CONTIGUOUS => u8
+            ),
+            loc: casts::const_as!(
+                bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM => u8
+            ),
             ..Zeroable::init_zeroed()
         });
 
@@ -715,12 +715,12 @@ pub(crate) fn new(msgq_size: u32, rx_hdr_offset: u32, msg_count: u32) -> Self {
         Self(bindings::msgqTxHeader {
             version: 0,
             size: msgq_size,
-            msgSize: num::usize_into_u32::<GSP_PAGE_SIZE>(),
+            msgSize: casts::const_as!(GSP_PAGE_SIZE => u32),
             msgCount: msg_count,
             writePtr: 0,
             flags: 1,
             rxHdrOff: rx_hdr_offset,
-            entryOff: num::usize_into_u32::<GSP_PAGE_SIZE>(),
+            entryOff: casts::const_as!(GSP_PAGE_SIZE => u32),
         })
     }
 
@@ -851,7 +851,7 @@ pub(crate) fn set_checksum(&mut self, checksum: u32) {
     /// Returns the length of the message's payload.
     pub(crate) fn payload_length(&self) -> usize {
         // `rpc.length` includes the length of the RPC message header.
-        num::u32_as_usize(self.inner.rpc.length)
+        casts::u32_as_usize(self.inner.rpc.length)
             .saturating_sub(size_of::<bindings::rpc_message_header_v>())
     }
 
@@ -947,9 +947,9 @@ impl MessageQueueInitArguments {
     fn new(cmdq: &Cmdq) -> impl Init<Self> + '_ {
         init!(MessageQueueInitArguments {
             sharedMemPhysAddr: cmdq.dma_addr,
-            pageTableEntryCount: num::usize_into_u32::<{ Cmdq::NUM_PTES }>(),
-            cmdQueueOffset: num::usize_as_u64(Cmdq::CMDQ_OFFSET),
-            statQueueOffset: num::usize_as_u64(Cmdq::STATQ_OFFSET),
+            pageTableEntryCount: casts::const_as!(Cmdq::NUM_PTES => u32),
+            cmdQueueOffset: casts::usize_as_u64(Cmdq::CMDQ_OFFSET),
+            statQueueOffset: casts::usize_as_u64(Cmdq::STATQ_OFFSET),
             ..Zeroable::init_zeroed()
         })
     }
@@ -969,7 +969,7 @@ impl GspAcrBootGspRmParams {
     fn new(target: GspDmaTarget, wpr_meta_addr: u64) -> impl Init<Self> {
         let params = init!(Self {
             target: target as u32,
-            gspRmDescSize: num::usize_into_u32::<{ size_of::<GspFwWprMeta>() }>(),
+            gspRmDescSize: casts::const_as!(size_of::<GspFwWprMeta>() => u32),
             gspRmDescOffset: wpr_meta_addr,
             bIsGspRmBoot: 1,
             wprCarveoutOffset: 0,
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index 6dc31d1bf5ae..201594fa437b 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -5,6 +5,7 @@
 
 use kernel::{
     device,
+    num::casts::IntoSafeCast,
     pci,
     prelude::*,
     transmute::{
@@ -15,8 +16,7 @@
 
 use crate::{
     gpu::Chipset,
-    gsp::GSP_PAGE_SIZE,
-    num::IntoSafeCast, //
+    gsp::GSP_PAGE_SIZE, //
 };
 
 use super::bindings;
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index bcad1421953a..fed881ba80b0 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -11,6 +11,7 @@
         poll::read_poll_timeout,
         Io, //
     },
+    num::casts::FromSafeCast,
     prelude::*,
     time::{
         delay::fsleep,
@@ -35,7 +36,6 @@
         GspBootContext,
         LibosMemoryRegionInitArgument, //
     },
-    num::FromSafeCast,
     sbuffer::SBufferIter,
 };
 
diff --git a/drivers/gpu/nova-core/mctp.rs b/drivers/gpu/nova-core/mctp.rs
index 90c642c91a72..67f64ac2b8d1 100644
--- a/drivers/gpu/nova-core/mctp.rs
+++ b/drivers/gpu/nova-core/mctp.rs
@@ -9,14 +9,12 @@
 
 use kernel::{
     bitfield,
+    num::casts,
     pci::Vendor,
     prelude::*, //
 };
 
-use crate::{
-    bounded_enum,
-    num, //
-};
+use crate::bounded_enum;
 
 bounded_enum! {
     /// NVDM message type identifiers carried over MCTP.
@@ -76,7 +74,7 @@ impl NvdmHeader {
     /// Builds an NVDM header for the given message type.
     pub(crate) fn new(nvdm_type: NvdmType) -> Self {
         Self::zeroed()
-            .with_const_msg_type::<{ num::u8_as_u32(MSG_TYPE_VENDOR_PCI) }>()
+            .with_const_msg_type::<{ casts::u8_as_u32(MSG_TYPE_VENDOR_PCI) }>()
             .with_vendor_id(Vendor::NVIDIA.as_raw())
             .with_nvdm_type(nvdm_type)
     }
diff --git a/drivers/gpu/nova-core/num.rs b/drivers/gpu/nova-core/num.rs
index 6eb174d136ab..3921ef6f238e 100644
--- a/drivers/gpu/nova-core/num.rs
+++ b/drivers/gpu/nova-core/num.rs
@@ -5,217 +5,6 @@
 //! This is essentially a staging module for code to mature until it can be moved to the `kernel`
 //! crate.
 
-use kernel::{
-    macros::paste,
-    prelude::*, //
-};
-
-/// Implements safe `as` conversion functions from a given type into a series of target types.
-///
-/// These functions can be used in place of `as`, with the guarantee that they will be lossless.
-macro_rules! impl_safe_as {
-    ($from:ty as { $($into:ty),* }) => {
-        $(
-        paste! {
-            #[doc = ::core::concat!(
-                "Losslessly converts a [`",
-                ::core::stringify!($from),
-                "`] into a [`",
-                ::core::stringify!($into),
-                "`].")]
-            ///
-            /// This conversion is allowed as it is always lossless. Prefer this over the `as`
-            /// keyword to ensure no lossy casts are performed.
-            ///
-            /// This is for use from a `const` context. For non `const` use, prefer the
-            /// [`FromSafeCast`] and [`IntoSafeCast`] traits.
-            ///
-            /// # Examples
-            ///
-            /// ```
-            /// use crate::num;
-            ///
-            #[doc = ::core::concat!(
-                "assert_eq!(num::",
-                ::core::stringify!($from),
-                "_as_",
-                ::core::stringify!($into),
-                "(1",
-                ::core::stringify!($from),
-                "), 1",
-                ::core::stringify!($into),
-                ");")]
-            /// ```
-            #[allow(unused)]
-            #[inline(always)]
-            pub(crate) const fn [<$from _as_ $into>](value: $from) -> $into {
-                ::kernel::build_assert::static_assert!(size_of::<$into>() >= size_of::<$from>());
-
-                value as $into
-            }
-        }
-        )*
-    };
-}
-
-impl_safe_as!(u8 as { u16, u32, u64, usize });
-impl_safe_as!(u16 as { u32, u64, usize });
-impl_safe_as!(u32 as { u64, usize } );
-// `u64` and `usize` have the same size on 64-bit platforms.
-#[cfg(CONFIG_64BIT)]
-impl_safe_as!(u64 as { usize } );
-
-// A `usize` fits into a `u64` on 32 and 64-bit platforms.
-#[cfg(any(CONFIG_32BIT, CONFIG_64BIT))]
-impl_safe_as!(usize as { u64 });
-
-// A `usize` fits into a `u32` on 32-bit platforms.
-#[cfg(CONFIG_32BIT)]
-impl_safe_as!(usize as { u32 });
-
-/// Extension trait providing guaranteed lossless cast to `Self` from `T`.
-///
-/// The standard library's `From` implementations do not cover conversions that are not portable or
-/// future-proof. For instance, even though it is safe today, `From<usize>` is not implemented for
-/// [`u64`] because of the possibility to support larger-than-64bit architectures in the future.
-///
-/// The workaround is to either deal with the error handling of [`TryFrom`] for an operation that
-/// technically cannot fail, or to use the `as` keyword, which can silently strip data if the
-/// destination type is smaller than the source.
-///
-/// Both options are hardly acceptable for the kernel. It is also a much more architecture
-/// dependent environment, supporting only 32 and 64 bit architectures, with some modules
-/// explicitly depending on a specific bus width that could greatly benefit from infallible
-/// conversion operations.
-///
-/// Thus this extension trait that provides, for the architecture the kernel is built for, safe
-/// conversion between types for which such cast is lossless.
-///
-/// In other words, this trait is implemented if, for the current build target and with `t: T`, the
-/// `t as Self` operation is completely lossless.
-///
-/// Prefer this over the `as` keyword to ensure no lossy casts are performed.
-///
-/// If you need to perform a conversion in `const` context, use [`u64_as_usize`], [`u32_as_usize`],
-/// [`usize_as_u64`], etc.
-///
-/// # Examples
-///
-/// ```
-/// use crate::num::FromSafeCast;
-///
-/// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize);
-/// ```
-pub(crate) trait FromSafeCast<T> {
-    /// Create a `Self` from `value`. This operation is guaranteed to be lossless.
-    fn from_safe_cast(value: T) -> Self;
-}
-
-impl FromSafeCast<usize> for u64 {
-    fn from_safe_cast(value: usize) -> Self {
-        usize_as_u64(value)
-    }
-}
-
-#[cfg(CONFIG_32BIT)]
-impl FromSafeCast<usize> for u32 {
-    fn from_safe_cast(value: usize) -> Self {
-        usize_as_u32(value)
-    }
-}
-
-impl FromSafeCast<u32> for usize {
-    fn from_safe_cast(value: u32) -> Self {
-        u32_as_usize(value)
-    }
-}
-
-#[cfg(CONFIG_64BIT)]
-impl FromSafeCast<u64> for usize {
-    fn from_safe_cast(value: u64) -> Self {
-        u64_as_usize(value)
-    }
-}
-
-/// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`FromSafeCast`] what [`Into`]
-/// is to [`From`].
-///
-/// See the documentation of [`FromSafeCast`] for the motivation.
-///
-/// # Examples
-///
-/// ```
-/// use crate::num::IntoSafeCast;
-///
-/// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize);
-/// ```
-pub(crate) trait IntoSafeCast<T> {
-    /// Convert `self` into a `T`. This operation is guaranteed to be lossless.
-    fn into_safe_cast(self) -> T;
-}
-
-/// Reverse operation for types implementing [`FromSafeCast`].
-impl<S, T> IntoSafeCast<T> for S
-where
-    T: FromSafeCast<S>,
-{
-    fn into_safe_cast(self) -> T {
-        T::from_safe_cast(self)
-    }
-}
-
-/// Implements lossless conversion of a constant from a larger type into a smaller one.
-macro_rules! impl_const_into {
-    ($from:ty => { $($into:ty),* }) => {
-        $(
-        paste! {
-            #[doc = ::core::concat!(
-                "Performs a build-time safe conversion of a [`",
-                ::core::stringify!($from),
-                "`] constant value into a [`",
-                ::core::stringify!($into),
-                "`].")]
-            ///
-            /// This checks at compile-time that the conversion is lossless, and triggers a build
-            /// error if it isn't.
-            ///
-            /// # Examples
-            ///
-            /// ```
-            /// use crate::num;
-            ///
-            /// // Succeeds because the value of the source fits into the destination's type.
-            #[doc = ::core::concat!(
-                "assert_eq!(num::",
-                ::core::stringify!($from),
-                "_into_",
-                ::core::stringify!($into),
-                "::<1",
-                ::core::stringify!($from),
-                ">(), 1",
-                ::core::stringify!($into),
-                ");")]
-            /// ```
-            #[allow(unused)]
-            pub(crate) const fn [<$from _into_ $into>]<const N: $from>() -> $into {
-                // Make sure that the target type is smaller than the source one.
-                static_assert!($from::BITS >= $into::BITS);
-                // CAST: we statically enforced above that `$from` is larger than `$into`, so the
-                // `as` conversion will be lossless.
-                build_assert!(N >= $into::MIN as $from && N <= $into::MAX as $from);
-
-                N as $into
-            }
-        }
-        )*
-    };
-}
-
-impl_const_into!(usize => { u8, u16, u32 });
-impl_const_into!(u64 => { u8, u16, u32 });
-impl_const_into!(u32 => { u8, u16 });
-impl_const_into!(u16 => { u8 });
-
 /// Creates an enum type associated to a [`Bounded`](kernel::num::Bounded), with a [`From`]
 /// conversion to the associated `Bounded` and either a [`TryFrom`] or `From` conversion from the
 /// associated `Bounded`.
diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs
index c03650ee5226..7a2ee29cbb91 100644
--- a/drivers/gpu/nova-core/vbios.rs
+++ b/drivers/gpu/nova-core/vbios.rs
@@ -5,6 +5,7 @@
 use kernel::{
     device,
     io::Io,
+    num::casts::FromSafeCast,
     prelude::*,
     ptr::{
         Alignable,
@@ -23,7 +24,6 @@
         FalconUCodeDescV2,
         FalconUCodeDescV3, //
     },
-    num::FromSafeCast,
 };
 
 /// BIOS Image Type from PCI Data Structure code_type field.

-- 
2.55.0


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

* Re: [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module
  2026-08-25  2:44 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
@ 2026-08-25  5:27   ` Eliot Courtney
  0 siblings, 0 replies; 14+ messages in thread
From: Eliot Courtney @ 2026-08-25  5:27 UTC (permalink / raw)
  To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 11:44 AM JST, Alexandre Courbot wrote:
> The `kernel` crate now features a replacement for our lossless integer
> conversion routines. Switch to the kernel version and remove our own.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---

nit: casts:: prefix feels noisy to me in actual usages - just import
const_as!, etc and use them directly?

Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>


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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25  2:44 ` [PATCH 1/2] " Alexandre Courbot
@ 2026-08-25  7:18   ` Eliot Courtney
  2026-08-25  8:25   ` Miguel Ojeda
  2026-08-25 12:04   ` Gary Guo
  2 siblings, 0 replies; 14+ messages in thread
From: Eliot Courtney @ 2026-08-25  7:18 UTC (permalink / raw)
  To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 11:44 AM JST, Alexandre Courbot wrote:
> The casts module features a series of const converters (e.g.
> `u32_into_u16`) that narrow the type of a const expression provided that
> its value can be proven to fit into the destination type at
> compile-time.
>
> These functions are numerous (9 of them), generated by a macro and thus
> not easily discoverable, and cumbersome to use as they require a
> turbofish and const expression between `{` and `}` braces.
>
> Replace them all by a single `const_as!` macro that expands to a const
> block verifying the lossless nature of the conversion at compile-time.
> This turns e.g.:
>
>     const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
>
> into
>
>     const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);
>
> This makes things easier to read and understand, while shifting the
> burden of checking the conversion's validity from reviewers (via a CAST
> comment) to the compiler.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
>  rust/kernel/num/casts.rs | 129 +++++++++++++++++++++++++++++------------------
>  1 file changed, 79 insertions(+), 50 deletions(-)
>
> diff --git a/rust/kernel/num/casts.rs b/rust/kernel/num/casts.rs
> index 7e6c7dec747d..a4a18a6f2ba8 100644
> --- a/rust/kernel/num/casts.rs
> +++ b/rust/kernel/num/casts.rs
> @@ -20,10 +20,8 @@
>  //! - Two extension traits, [`FromSafeCast`] and [`IntoSafeCast`], providing conversion methods
>  //!   similar to [`From`] and [`Into`] for conversions that are safe to perform in the kernel, but
>  //!   not supported by the standard library.
> -//! - Another series of const functions (e.g. [`u64_into_u8`]) supporting the conversion of a const
> -//!   value from a larger type into a smaller one, provided the value fits into the destination
> -//!   type. This is useful if a constant is defined as a larger type, but needs to be used as a
> -//!   smaller one.
> +//! - A [`const_as!`] macro, losslessly casting a constant expression between any two integer
> +//!   types, with conversions that would alter the value reported as build errors.
>  //! - An [`arch`] sub-module, defining more conversion functions that are only guaranteed to be
>  //!   lossless for a given pointer size. These can only be used in code that is specific to a
>  //!   given pointer size.

Can we add guidance somewhere in this file on when to use const_as! vs
when to use the u8_as_usize etc ones, when both could work? e.g. use
const_as! if you can, otherwise use the function version, or, use the
function version if it's sufficient (types alone are enough to prove)
otherwise use the macro.

[...]
> +#[macro_export]
> +#[doc(hidden)]
> +macro_rules! const_as {
> +    ($v:expr => $into:ty) => {
> +        const {
> +            #[allow(unused_comparisons, unused_assignments, clippy::as_underscore)]
> +            {
> +                let v = $v;
> +                let r = v as $into;
> +                // Pin `back` to `v`'s type so `as _` casts back to the source type.
> +                let mut back = v;
> +                back = r as _;
>  
> -                N as $into
> +                ::core::assert!(
> +                    back == v && (v < 0) == (r < 0),
> +                    "value does not fit into the target type"
> +                );

What about giving some text on what doesn't fit where? e.g.
::core::concat!("`", ::core::stringify!($v), "` does not fit into `", ::core::stringify!($into), "`")


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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25  2:44 ` [PATCH 1/2] " Alexandre Courbot
  2026-08-25  7:18   ` Eliot Courtney
@ 2026-08-25  8:25   ` Miguel Ojeda
  2026-08-25 12:01     ` Gary Guo
                       ` (2 more replies)
  2026-08-25 12:04   ` Gary Guo
  2 siblings, 3 replies; 14+ messages in thread
From: Miguel Ojeda @ 2026-08-25  8:25 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan, John Hubbard, Alistair Popple, Timur Tabi,
	Eliot Courtney, Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue, Aug 25, 2026 at 4:45 AM Alexandre Courbot <acourbot@nvidia.com> wrote:
>
>     const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
>
> into
>
>     const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);

Hmm... I have been following the discussion and listening to both
sides of the argument.

The macro interface looks obvious enough, and we could consider adding
it to the prelude.

Having said that, macros have a cost too when they introduce new
"syntax", so since the beginning we have tried to minimize their use
to where we feel is worth it.

The former line above is not perfect by any means, but it is
nevertheless syntax that one needs to already know. Personally
speaking, I don't care if I have to write the former or the latter, to
be honest, so I am OK with both ways. But I worked with C++ TMP in the
past, so my eyes may be desensitized. :)

Apart from readability concerns, we are saving here a few characters;
getting possibly different codegen (forced textual inline), and maybe
having better or worse compiler-side time/memory/disk numbers. Is that
about it? It would be good to measure any actual difference.

What I wouldn't want is a raw `as`, because the point of the saga we
started a long time ago is to introduce better tools that allow us to
get rid of the almighty `as` into weaker (i.e. safer) options, even if
some uses of `as` may be "obviously right".

Cheers,
Miguel

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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25  8:25   ` Miguel Ojeda
@ 2026-08-25 12:01     ` Gary Guo
  2026-08-25 14:26       ` Alexandre Courbot
  2026-08-25 13:54     ` Alexandre Courbot
  2026-08-25 14:02     ` Danilo Krummrich
  2 siblings, 1 reply; 14+ messages in thread
From: Gary Guo @ 2026-08-25 12:01 UTC (permalink / raw)
  To: Miguel Ojeda, Alexandre Courbot
  Cc: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan, John Hubbard, Alistair Popple, Timur Tabi,
	Eliot Courtney, Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 9:25 AM BST, Miguel Ojeda wrote:
> On Tue, Aug 25, 2026 at 4:45 AM Alexandre Courbot <acourbot@nvidia.com> wrote:
>>
>>     const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
>>
>> into
>>
>>     const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);
>
> Hmm... I have been following the discussion and listening to both
> sides of the argument.
>
> The macro interface looks obvious enough, and we could consider adding
> it to the prelude.
>
> Having said that, macros have a cost too when they introduce new
> "syntax", so since the beginning we have tried to minimize their use
> to where we feel is worth it.
>
> The former line above is not perfect by any means, but it is
> nevertheless syntax that one needs to already know. Personally
> speaking, I don't care if I have to write the former or the latter, to
> be honest, so I am OK with both ways. But I worked with C++ TMP in the
> past, so my eyes may be desensitized. :)

What I have issue with is to have things that do not belong to the type system
in const generics. Expressive power is really limited in it, so any
expressions involving generic parameter, for example, won't be usable inside the
turbofish. It also doesn't work for custom types, so the approach does not
generalize.

The type/value distinction is one of the biggest change I made to `const {}`
implementation, many features of `const {}` is possible (e.g. reference to
generic parameter freely) precisely because values don't flow to the type
system.

Yes const_generic_exprs is being worked on and it'll blur the line between type
and values. But we're not there yet, and I think it still worth having a clear
distinction and we don't put things that don't need to be in the type system
there.

>
> Apart from readability concerns, we are saving here a few characters;
> getting possibly different codegen (forced textual inline), and maybe
> having better or worse compiler-side time/memory/disk numbers. Is that
> about it? It would be good to measure any actual difference.

The macros are much better than functions in my opinion, because it compose well
with the type system. The all "foo_as_bar" methods also compose poorly with type
alias, where this macro doesn't have that issue. Also, values no longer end up
in the type system to begin with.

>
> What I wouldn't want is a raw `as`, because the point of the saga we
> started a long time ago is to introduce better tools that allow us to
> get rid of the almighty `as` into weaker (i.e. safer) options, even if
> some uses of `as` may be "obviously right".

I think that is rather a linting issue, not something that warrants extra code
in kernel. We have been requesting some extra clippy features and I think that
is the correct way to go, not add a ton of methods and macros. Yes, it wasn't
moving on clippy end, but I could add a feature to klint instead?

Do you think we still need all these extra function and macros if we
can get clippy (or klint) to enforce CAST comments?

I can imagine the following rules that would practically solve all the footgun
of `as` numerical casts without having to use awkward syntax:

* widening casts are allowed
* narrowing casts is disallowed unless CAST comment exists, except where its
  value is constant and truncation does not happen.

Best,
Gary

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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25  2:44 ` [PATCH 1/2] " Alexandre Courbot
  2026-08-25  7:18   ` Eliot Courtney
  2026-08-25  8:25   ` Miguel Ojeda
@ 2026-08-25 12:04   ` Gary Guo
  2 siblings, 0 replies; 14+ messages in thread
From: Gary Guo @ 2026-08-25 12:04 UTC (permalink / raw)
  To: Alexandre Courbot, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 3:44 AM BST, Alexandre Courbot wrote:
> The casts module features a series of const converters (e.g.
> `u32_into_u16`) that narrow the type of a const expression provided that
> its value can be proven to fit into the destination type at
> compile-time.
>
> These functions are numerous (9 of them), generated by a macro and thus
> not easily discoverable, and cumbersome to use as they require a
> turbofish and const expression between `{` and `}` braces.
>
> Replace them all by a single `const_as!` macro that expands to a const
> block verifying the lossless nature of the conversion at compile-time.
> This turns e.g.:
>
>     const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
>
> into
>
>     const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);
>
> This makes things easier to read and understand, while shifting the
> burden of checking the conversion's validity from reviewers (via a CAST
> comment) to the compiler.

Thanks, I like this much better than the methods (for reasons that I explained
in my reply to Miguel), and also that this looks nicer.

Reviewed-by: Gary Guo <gary@garyguo.net>

>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
>  rust/kernel/num/casts.rs | 129 +++++++++++++++++++++++++++++------------------
>  1 file changed, 79 insertions(+), 50 deletions(-)


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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25  8:25   ` Miguel Ojeda
  2026-08-25 12:01     ` Gary Guo
@ 2026-08-25 13:54     ` Alexandre Courbot
  2026-08-25 14:02     ` Danilo Krummrich
  2 siblings, 0 replies; 14+ messages in thread
From: Alexandre Courbot @ 2026-08-25 13:54 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan, John Hubbard, Alistair Popple, Timur Tabi,
	Eliot Courtney, Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 5:25 PM JST, Miguel Ojeda wrote:
> On Tue, Aug 25, 2026 at 4:45 AM Alexandre Courbot <acourbot@nvidia.com> wrote:
>>
>>     const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
>>
>> into
>>
>>     const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);
>
> Hmm... I have been following the discussion and listening to both
> sides of the argument.
>
> The macro interface looks obvious enough, and we could consider adding
> it to the prelude.
>
> Having said that, macros have a cost too when they introduce new
> "syntax", so since the beginning we have tried to minimize their use
> to where we feel is worth it.

Ideally we could write it like `const_as!(MEM_BLOCK_ALIGNMENT as u32)`
but unfortunately declarative macros won't let us do that. That being
said there might be a better syntax.

>
> The former line above is not perfect by any means, but it is
> nevertheless syntax that one needs to already know. Personally
> speaking, I don't care if I have to write the former or the latter, to
> be honest, so I am OK with both ways. But I worked with C++ TMP in the
> past, so my eyes may be desensitized. :)

I also don't mind the turbofish. Actually I like how it unambiguously
signals that something is evaluated at build time. But in this case the
macro seems justified to me as we are trading 9 different
macro-generated declarations for a single one that is much more obvious
to discover and use. The declaration site of the previous helpers was a
paste-party that is difficult to read and edit.

`const_as!` also has the benefit that it can probably survive the
`TryFrom` constification, as I don't believe we will want users to
sprinkle unwraps in their const blocks.

Another bonus, especially if we add it to the prelude: `const_as!` also
covers expanding conversions, so we can also replace many of the e.g.
`u8_as_u32` calls with it, with `FromSafeCast` covering the non-const
cases. This leaves the `*_as_*` family of functions only needed for
const fns that need to expand a parameter, for which there are no
in-tree users at the moment.

>
> Apart from readability concerns, we are saving here a few characters;
> getting possibly different codegen (forced textual inline), and maybe
> having better or worse compiler-side time/memory/disk numbers. Is that
> about it? It would be good to measure any actual difference.

I don't expect much difference between the two, but will try to gather
some metrics for v2.

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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25  8:25   ` Miguel Ojeda
  2026-08-25 12:01     ` Gary Guo
  2026-08-25 13:54     ` Alexandre Courbot
@ 2026-08-25 14:02     ` Danilo Krummrich
  2026-08-25 14:11       ` Gary Guo
  2026-08-25 14:30       ` Alexandre Courbot
  2 siblings, 2 replies; 14+ messages in thread
From: Danilo Krummrich @ 2026-08-25 14:02 UTC (permalink / raw)
  To: Miguel Ojeda, Alexandre Courbot
  Cc: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Daniel Almeida, Tamir Duberstein, Onur Özkan,
	John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 10:25 AM CEST, Miguel Ojeda wrote:
> On Tue, Aug 25, 2026 at 4:45 AM Alexandre Courbot <acourbot@nvidia.com> wrote:
>>
>>     const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
>>
>> into
>>
>>     const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);
>
> Having said that, macros have a cost too when they introduce new
> "syntax", so since the beginning we have tried to minimize their use
> to where we feel is worth it.
>
> The former line above is not perfect by any means, but it is
> nevertheless syntax that one needs to already know. Personally
> speaking, I don't care if I have to write the former or the latter, to
> be honest, so I am OK with both ways.

As mentioned in [1], I also think it's not great, but I also don't mind having
it as is for now.

I guess my main question is how we expect this to evolve. How do we want this to
look like once we have things like const function arguments or const trait
methods? Is it worth getting back and forth on a macro solution with this in
mind?

[1] https://lore.kernel.org/all/DKX57FPE7DKY.1MVQBHYXKFAWT@kernel.org/

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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25 14:02     ` Danilo Krummrich
@ 2026-08-25 14:11       ` Gary Guo
  2026-08-25 14:30       ` Alexandre Courbot
  1 sibling, 0 replies; 14+ messages in thread
From: Gary Guo @ 2026-08-25 14:11 UTC (permalink / raw)
  To: Danilo Krummrich, Miguel Ojeda, Alexandre Courbot
  Cc: Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Daniel Almeida, Tamir Duberstein, Onur Özkan,
	John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 3:02 PM BST, Danilo Krummrich wrote:
> On Tue Aug 25, 2026 at 10:25 AM CEST, Miguel Ojeda wrote:
>> On Tue, Aug 25, 2026 at 4:45 AM Alexandre Courbot <acourbot@nvidia.com> wrote:
>>>
>>>     const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
>>>
>>> into
>>>
>>>     const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);
>>
>> Having said that, macros have a cost too when they introduce new
>> "syntax", so since the beginning we have tried to minimize their use
>> to where we feel is worth it.
>>
>> The former line above is not perfect by any means, but it is
>> nevertheless syntax that one needs to already know. Personally
>> speaking, I don't care if I have to write the former or the latter, to
>> be honest, so I am OK with both ways.
>
> As mentioned in [1], I also think it's not great, but I also don't mind having
> it as is for now.
>
> I guess my main question is how we expect this to evolve. How do we want this to
> look like once we have things like const function arguments or const trait
> methods? Is it worth getting back and forth on a macro solution with this in
> mind?

It's easier to evolve with macros. Once we have const trait, the cast becomes

    const { from_expr.try_into().unwrap() }

or

    const { TargetType::try_from(from_expr).unwrap() }

which we can just change the macro to expand to.

That said, whether we want raw

    const { u32::try_from(MEM_BLOCK_ALIGNMENT).unwrap() }

vs

    const_as!(MEM_BLOCK_ALIGNMENT => u32)

is a different question. We probably can have a `const_try!()` macro that
unwraps both `Option` and `Result` in const eval so write

    const_try!(u32::try_from(MEM_BLOCK_ALIGNMENT))

or

    const_try!(MEM_BLOCK_ALIGNMENT.try_into())

Regardless, the "ultimate state" is not going to be turbofish and would take a
form of expression syntax wrapped in const block.

Best,
Gary


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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25 12:01     ` Gary Guo
@ 2026-08-25 14:26       ` Alexandre Courbot
  2026-08-25 14:39         ` Gary Guo
  0 siblings, 1 reply; 14+ messages in thread
From: Alexandre Courbot @ 2026-08-25 14:26 UTC (permalink / raw)
  To: Gary Guo
  Cc: Miguel Ojeda, Yury Norov, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan, John Hubbard, Alistair Popple, Timur Tabi,
	Eliot Courtney, Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 9:01 PM JST, Gary Guo wrote:
> On Tue Aug 25, 2026 at 9:25 AM BST, Miguel Ojeda wrote:
>> What I wouldn't want is a raw `as`, because the point of the saga we
>> started a long time ago is to introduce better tools that allow us to
>> get rid of the almighty `as` into weaker (i.e. safer) options, even if
>> some uses of `as` may be "obviously right".
>
> I think that is rather a linting issue, not something that warrants extra code
> in kernel. We have been requesting some extra clippy features and I think that
> is the correct way to go, not add a ton of methods and macros. Yes, it wasn't
> moving on clippy end, but I could add a feature to klint instead?
>
> Do you think we still need all these extra function and macros if we
> can get clippy (or klint) to enforce CAST comments?
>
> I can imagine the following rules that would practically solve all the footgun
> of `as` numerical casts without having to use awkward syntax:
>
> * widening casts are allowed
> * narrowing casts is disallowed unless CAST comment exists, except where its
>   value is constant and truncation does not happen.

These rules classify casts by width, but the footguns really are about
which values are actually being converted.

In particular for value narrowing we still end up with CAST comments,
whose existence a lint can check, but not their correctness (for
instance, a bindgen-provided constant that changes in a breaking way).
`const_as!` lets us drop them altogether.

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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25 14:02     ` Danilo Krummrich
  2026-08-25 14:11       ` Gary Guo
@ 2026-08-25 14:30       ` Alexandre Courbot
  1 sibling, 0 replies; 14+ messages in thread
From: Alexandre Courbot @ 2026-08-25 14:30 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Miguel Ojeda, Yury Norov, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Daniel Almeida, Tamir Duberstein, Onur Özkan,
	John Hubbard, Alistair Popple, Timur Tabi, Eliot Courtney,
	Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 11:02 PM JST, Danilo Krummrich wrote:
> On Tue Aug 25, 2026 at 10:25 AM CEST, Miguel Ojeda wrote:
>> On Tue, Aug 25, 2026 at 4:45 AM Alexandre Courbot <acourbot@nvidia.com> wrote:
>>>
>>>     const DMA_LEN: u32 = casts::usize_into_u32::<{ MEM_BLOCK_ALIGNMENT }>();
>>>
>>> into
>>>
>>>     const DMA_LEN: u32 = casts::const_as!(MEM_BLOCK_ALIGNMENT => u32);
>>
>> Having said that, macros have a cost too when they introduce new
>> "syntax", so since the beginning we have tried to minimize their use
>> to where we feel is worth it.
>>
>> The former line above is not perfect by any means, but it is
>> nevertheless syntax that one needs to already know. Personally
>> speaking, I don't care if I have to write the former or the latter, to
>> be honest, so I am OK with both ways.
>
> As mentioned in [1], I also think it's not great, but I also don't mind having
> it as is for now.
>
> I guess my main question is how we expect this to evolve. How do we want this to
> look like once we have things like const function arguments or const trait
> methods? Is it worth getting back and forth on a macro solution with this in
> mind?

I've thought about this a bit actually. Let's imagine we have a const
`TryFrom` trait. Even with that, we probably won't want users to do e.g.
`u8::try_from(SOME_U32_CONST).unwrap()` every time they need to narrow
something (if only because it would translate into a runtime panic if
somehow moved outside of a const block).

So for the same reason we are considering `nz!` to build non-zero values
efficiently, I expect `const_as!` to remain around in some capacity,
which should make the transition invisible to users.

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

* Re: [PATCH 1/2] rust: num: casts: replace const type narrowing methods with a macro
  2026-08-25 14:26       ` Alexandre Courbot
@ 2026-08-25 14:39         ` Gary Guo
  0 siblings, 0 replies; 14+ messages in thread
From: Gary Guo @ 2026-08-25 14:39 UTC (permalink / raw)
  To: Alexandre Courbot, Gary Guo
  Cc: Miguel Ojeda, Yury Norov, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Onur Özkan, John Hubbard, Alistair Popple, Timur Tabi,
	Eliot Courtney, Zhi Wang, rust-for-linux, linux-kernel, nova-gpu

On Tue Aug 25, 2026 at 3:26 PM BST, Alexandre Courbot wrote:
> On Tue Aug 25, 2026 at 9:01 PM JST, Gary Guo wrote:
>> On Tue Aug 25, 2026 at 9:25 AM BST, Miguel Ojeda wrote:
>>> What I wouldn't want is a raw `as`, because the point of the saga we
>>> started a long time ago is to introduce better tools that allow us to
>>> get rid of the almighty `as` into weaker (i.e. safer) options, even if
>>> some uses of `as` may be "obviously right".
>>
>> I think that is rather a linting issue, not something that warrants extra code
>> in kernel. We have been requesting some extra clippy features and I think that
>> is the correct way to go, not add a ton of methods and macros. Yes, it wasn't
>> moving on clippy end, but I could add a feature to klint instead?
>>
>> Do you think we still need all these extra function and macros if we
>> can get clippy (or klint) to enforce CAST comments?
>>
>> I can imagine the following rules that would practically solve all the footgun
>> of `as` numerical casts without having to use awkward syntax:
>>
>> * widening casts are allowed
>> * narrowing casts is disallowed unless CAST comment exists, except where its
>>   value is constant and truncation does not happen.
>
> These rules classify casts by width, but the footguns really are about
> which values are actually being converted.
>
> In particular for value narrowing we still end up with CAST comments,
> whose existence a lint can check, but not their correctness (for
> instance, a bindgen-provided constant that changes in a breaking way).
> `const_as!` lets us drop them altogether.

The rule says "except where its value is constant and truncation does not
happen".

So I'd imagine just writing

    bindings::FOO as u32

and *NOT* have CAST comment, and a warning being generated if truncation
happens.

Best,
Gary

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

end of thread, other threads:[~2026-08-25 14:39 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-25  2:44 [PATCH 0/2] rust: num: casts: replace const type narrowing methods with a macro Alexandre Courbot
2026-08-25  2:44 ` [PATCH 1/2] " Alexandre Courbot
2026-08-25  7:18   ` Eliot Courtney
2026-08-25  8:25   ` Miguel Ojeda
2026-08-25 12:01     ` Gary Guo
2026-08-25 14:26       ` Alexandre Courbot
2026-08-25 14:39         ` Gary Guo
2026-08-25 13:54     ` Alexandre Courbot
2026-08-25 14:02     ` Danilo Krummrich
2026-08-25 14:11       ` Gary Guo
2026-08-25 14:30       ` Alexandre Courbot
2026-08-25 12:04   ` Gary Guo
2026-08-25  2:44 ` [PATCH 2/2] gpu: nova-core: use kernel lossless integer conversion module Alexandre Courbot
2026-08-25  5:27   ` Eliot Courtney

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