From: Danilo Krummrich <dakr@kernel.org>
To: gregkh@linuxfoundation.org, rafael@kernel.org, dakr@kernel.org,
ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net,
bjorn3_gh@protonmail.com, lossin@kernel.org,
a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu,
acourbot@nvidia.com, ecourtney@nvidia.com,
m.wilczynski@samsung.com, david.m.ertman@intel.com,
ira.weiny@intel.com, leon@kernel.org,
daniel.almeida@collabora.com, bhelgaas@google.com,
kwilczynski@kernel.org
Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org,
nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org,
linux-pwm@vger.kernel.org, rust-for-linux@vger.kernel.org
Subject: [PATCH v2 2/7] rust: types: introduce ForLt base trait for CovariantForLt
Date: Wed, 3 Jun 2026 03:10:13 +0200 [thread overview]
Message-ID: <20260603011020.2073650-3-dakr@kernel.org> (raw)
In-Reply-To: <20260603011020.2073650-1-dakr@kernel.org>
Add a new ForLt trait as a base for CovariantForLt:
- ForLt (non-unsafe): represents a type generic over a lifetime, with
no covariance guarantee. Provides unsafe fn cast_ref_unchecked()
for callers that can justify lifetime shortening via a round-trip
safety argument.
- CovariantForLt (unsafe): becomes a subtrait of ForLt that
additionally proves the type is covariant over its lifetime
parameter, providing a safe cast_ref() method.
This split allows non-covariant types (e.g. types behind a Mutex) to
implement ForLt and participate in DevresLt / registration data patterns
where the round-trip argument suffices, without requiring a covariance
proof that would fail to compile.
The internal macro backend is split accordingly: ForLt! emits ForLtImpl
(no covariance proof), CovariantForLt! emits CovariantForLtImpl (with
compile-time covariance proof).
No existing callers change; they all use CovariantForLt.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/types.rs | 1 +
rust/kernel/types/for_lt.rs | 101 ++++++++++++++++++++++++++++++------
rust/macros/for_lt.rs | 50 ++++++++++++++----
rust/macros/lib.rs | 19 ++++++-
4 files changed, 145 insertions(+), 26 deletions(-)
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index cbe6907042d3..c1ed05d1046c 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -14,6 +14,7 @@
#[doc(hidden)]
pub mod for_lt;
pub use for_lt::CovariantForLt;
+pub use for_lt::ForLt;
/// Used to transfer ownership to and from foreign (non-Rust) languages.
///
diff --git a/rust/kernel/types/for_lt.rs b/rust/kernel/types/for_lt.rs
index ef510ab6c092..e1774b03dd1f 100644
--- a/rust/kernel/types/for_lt.rs
+++ b/rust/kernel/types/for_lt.rs
@@ -1,17 +1,74 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
-//! Provide implementation and test of the `CovariantForLt` trait and macro.
+//! Provide implementation and test of the `ForLt` and `CovariantForLt` traits and macros.
//!
-//! This module is hidden and user should just use `CovariantForLt!` directly.
+//! This module is hidden and users should just use `ForLt!` / `CovariantForLt!` directly.
use core::marker::PhantomData;
/// Representation of types generic over a lifetime.
///
-/// The type must be covariant over the generic lifetime, i.e. the lifetime parameter
-/// can be soundly shortened.
+/// # Macro
+///
+/// It is not recommended to implement this trait directly. `ForLt!` macro is provided to obtain a
+/// type that implements this trait.
+///
+/// The full syntax is
+///
+/// ```
+/// # use kernel::types::ForLt;
+/// # fn expect_lt<F: ForLt>() {}
+/// # struct TypeThatUse<'a>(&'a ());
+/// # expect_lt::<
+/// ForLt!(for<'a> TypeThatUse<'a>)
+/// # >();
+/// ```
+///
+/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>`
+/// is `TypeThatUse<'b>`.
+///
+/// You may also use a short-hand syntax which works similar to lifetime elision.
+/// The macro also accepts types that do not involve a lifetime at all.
+///
+/// ```
+/// # use kernel::types::ForLt;
+/// # fn expect_lt<F: ForLt>() {}
+/// # struct TypeThatUse<'a>(&'a ());
+/// # expect_lt::<
+/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`.
+/// # >();
+/// # expect_lt::<
+/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`.
+/// # >();
+/// # expect_lt::<
+/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`.
+/// # >();
+/// ```
+pub trait ForLt {
+ /// The type parameterized by the lifetime.
+ type Of<'a>: 'a;
+
+ /// Cast a reference to a shorter lifetime.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the lifetime shortening is sound for their use case,
+ /// e.g. because the `'long` reference originated from a `'short`-to-`'static` transmute
+ /// and this is the reverse leg of that round-trip.
+ #[inline(always)]
+ unsafe fn cast_ref_unchecked<'r, 'short: 'r, 'long: 'short>(
+ long: &'r Self::Of<'long>,
+ ) -> &'r Self::Of<'short> {
+ // SAFETY: Caller guarantees the lifetime shortening is sound.
+ unsafe { core::mem::transmute(long) }
+ }
+}
+pub use macros::ForLt;
+
+/// [`trait@ForLt`] subtrait for types that are covariant over their lifetime parameter.
///
-/// The lifetime involved must be covariant.
+/// Provides a safe [`cast_ref`](CovariantForLt::cast_ref) method for types that are proven to be
+/// covariant. The `CovariantForLt!` macro syntax is the same as `ForLt!`.
///
/// # Macro
///
@@ -84,10 +141,7 @@
/// # Safety
///
/// `Self::Of<'a>` must be covariant over the lifetime `'a`.
-pub unsafe trait CovariantForLt {
- /// The type parameterized by the lifetime.
- type Of<'a>: 'a;
-
+pub unsafe trait CovariantForLt: ForLt {
/// Cast a reference to a shorter lifetime.
#[inline(always)]
fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Self::Of<'short> {
@@ -97,27 +151,44 @@ fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Sel
}
pub use macros::CovariantForLt;
-/// Helper type for the `CovariantForLt!` macro.
+/// Helper type for the `ForLt!` macro.
///
-/// Must only be used by the `CovariantForLt!` macro.
+/// Must only be used by the `ForLt!` macro.
///
/// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro.
///
/// `WF` is a type that the macro can use to assert some specific type is well-formed.
+#[doc(hidden)]
+pub struct ForLtImpl<T: ?Sized, WF>(PhantomData<(WF, T)>);
+
+/// Helper type for the `CovariantForLt!` macro.
+///
+/// Must only be used by the `CovariantForLt!` macro.
+///
+/// `T` and `WF` are the same as in [`ForLtImpl`].
///
/// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove
/// additional properties.
#[doc(hidden)]
pub struct CovariantForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
-// This is a helper trait for implementation `CovariantForLt` to be able to use HRTB.
+// This is a helper trait for implementation `ForLt` to be able to use HRTB.
#[doc(hidden)]
pub trait WithLt<'a> {
type Of: 'a;
}
-// SAFETY: In `CovariantForLt!` macro, a covariance proof is generated when naming
-// `CovariantForLtImpl` and it will fail to evaluate if the type is not covariant.
-unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> CovariantForLt for CovariantForLtImpl<T, WF, 0> {
+impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for ForLtImpl<T, WF> {
+ type Of<'a> = <T as WithLt<'a>>::Of;
+}
+
+impl<T: ?Sized + for<'a> WithLt<'a>, WF, const N: usize> ForLt for CovariantForLtImpl<T, WF, N> {
type Of<'a> = <T as WithLt<'a>>::Of;
}
+
+// SAFETY: In `CovariantForLt!` macro, a covariance proof is generated in the `N` const generic
+// and it will fail to evaluate if the type is not covariant.
+unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF, const N: usize> CovariantForLt
+ for CovariantForLtImpl<T, WF, N>
+{
+}
diff --git a/rust/macros/for_lt.rs b/rust/macros/for_lt.rs
index 3cb094d00548..ad9809563fab 100644
--- a/rust/macros/for_lt.rs
+++ b/rust/macros/for_lt.rs
@@ -176,8 +176,10 @@ fn prove(&mut self, ty: &'a Type) {
}
}
-pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
- let (ty, lifetime) = match input {
+/// Resolve the higher-ranked type into a concrete `(ty, lifetime)` pair, expanding elided
+/// lifetimes as needed. Shared by both `for_lt` and `covariant_for_lt`.
+fn resolve_hrt(input: HigherRankedType) -> (Type, Lifetime) {
+ match input {
HigherRankedType::Explicit { lifetime, ty, .. } => (ty, lifetime),
HigherRankedType::Implicit { ty } => {
// If there's no explicit `for<'a>` binder, inject a synthetic `'__elided` lifetime
@@ -188,7 +190,41 @@ pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
};
(ty.expand_elided_lifetime(&lifetime), lifetime)
}
- };
+ }
+}
+
+/// Produce the `'static`-substituted type for the WF check. Shared by both macros.
+fn ty_static(ty: &Type, lifetime: &Lifetime) -> Type {
+ ty.replace_lifetime(
+ lifetime,
+ &Lifetime {
+ apostrophe: Span::mixed_site(),
+ ident: format_ident!("static"),
+ },
+ )
+}
+
+pub(crate) fn for_lt(input: HigherRankedType) -> TokenStream {
+ let (ty, lifetime) = resolve_hrt(input);
+
+ // Make sure that the type is wellformed when substituting lifetime with `'static`.
+ //
+ // Currently the Rust compiler doesn't check this, see the `ProveWf` documentation in
+ // `covariant_for_lt` below.
+ //
+ // We prefer to use this way of proving WF-ness as it can work when generics are involved.
+ let ty_static = ty_static(&ty, &lifetime);
+
+ quote!(
+ ::kernel::types::for_lt::ForLtImpl::<
+ dyn for<#lifetime> ::kernel::types::for_lt::WithLt<#lifetime, Of = #ty>,
+ #ty_static,
+ >
+ )
+}
+
+pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
+ let (ty, lifetime) = resolve_hrt(input);
let mut prover = Prover(&lifetime, Vec::new());
prover.prove(&ty);
@@ -226,13 +262,7 @@ fn #cov_proof_name<'__short, '__long: '__short>(
// Currently the Rust compiler doesn't check this, see the above `ProveWf` documentation.
//
// We prefer to use this way of proving WF-ness as it can work when generics are involved.
- let ty_static = ty.replace_lifetime(
- &lifetime,
- &Lifetime {
- apostrophe: Span::mixed_site(),
- ident: format_ident!("static"),
- },
- );
+ let ty_static = ty_static(&ty, &lifetime);
quote!(
::kernel::types::for_lt::CovariantForLtImpl::<
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 2167cb270928..e970769609f3 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -491,11 +491,28 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStream) -> TokenStream {
.into()
}
-/// Obtain a type that implements [`CovariantForLt`] for the given higher-ranked type.
+/// Obtain a type that implements [`ForLt`] for the given higher-ranked type.
+///
+/// Please refer to the documentation of the [`ForLt`] trait.
+///
+/// [`ForLt`]: trait.ForLt.html
+#[proc_macro]
+#[allow(non_snake_case)]
+pub fn ForLt(input: TokenStream) -> TokenStream {
+ for_lt::for_lt(parse_macro_input!(input)).into()
+}
+
+/// Obtain a type that implements [`CovariantForLt`] (and [`ForLt`]) for the given higher-ranked
+/// type.
+///
+/// Unlike [`ForLt!`], this macro additionally proves that the type is covariant over the lifetime,
+/// providing a safe [`CovariantForLt::cast_ref`] method.
///
/// Please refer to the documentation of the [`CovariantForLt`] trait.
///
/// [`CovariantForLt`]: trait.CovariantForLt.html
+/// [`CovariantForLt::cast_ref`]: trait.CovariantForLt.html#method.cast_ref
+/// [`ForLt`]: trait.ForLt.html
#[proc_macro]
#[allow(non_snake_case)]
pub fn CovariantForLt(input: TokenStream) -> TokenStream {
--
2.54.0
next prev parent reply other threads:[~2026-06-03 1:10 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-03 1:10 [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt Danilo Krummrich
2026-06-03 1:10 ` [PATCH v2 1/7] rust: types: rename ForLt to CovariantForLt Danilo Krummrich
2026-06-03 11:59 ` Gary Guo
2026-06-03 1:10 ` Danilo Krummrich [this message]
2026-06-03 12:04 ` [PATCH v2 2/7] rust: types: introduce ForLt base trait for CovariantForLt Gary Guo
2026-06-03 1:10 ` [PATCH v2 3/7] rust: auxiliary: add registration_data_with() for ForLt types Danilo Krummrich
2026-06-03 12:05 ` Gary Guo
2026-06-03 1:10 ` [PATCH v2 4/7] rust: auxiliary: sample: demonstrate ForLt with invariant Mutex type Danilo Krummrich
2026-06-03 1:10 ` [PATCH v2 5/7] rust: devres: add DevresLt for ForLt-aware device resource access Danilo Krummrich
2026-06-03 1:10 ` [PATCH v2 6/7] rust: pci: return DevresLt from Bar::into_devres() Danilo Krummrich
2026-06-03 1:10 ` [PATCH v2 7/7] rust: io: mem: return DevresLt from IoMem/ExclusiveIoMem::into_devres() Danilo Krummrich
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=20260603011020.2073650-3-dakr@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=david.m.ertman@intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=driver-core@lists.linux.dev \
--cc=ecourtney@nvidia.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=ira.weiny@intel.com \
--cc=kwilczynski@kernel.org \
--cc=leon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pwm@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=m.wilczynski@samsung.com \
--cc=nova-gpu@lists.linux.dev \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.