summaryrefslogtreecommitdiff
path: root/rust/kernel
diff options
context:
space:
mode:
authorGary Guo <gary@garyguo.net>2026-05-25 22:21:09 +0200
committerDanilo Krummrich <dakr@kernel.org>2026-05-27 16:24:59 +0200
commite189bdb687a56bcf389798f1d3a2f261fff2ef54 (patch)
tree18af7c3cb113eca7a60168d76b23521b22fca62f /rust/kernel
parentbb1cf43f2fa85beba82a0d9bbea21013cf94d7a0 (diff)
rust: types: add `ForLt` trait for higher-ranked lifetime support
There are a few cases, e.g. when dealing with data referencing each other, one might want to write code that is generic over lifetimes. For example, if you want to take a function that takes `&'a Foo` and gives `Bar<'a>`, you can write: f: impl for<'a> FnOnce(&'a Foo) -> Bar<'a>, However, it becomes tricky when you want that function to not have a fixed `Bar`, but have it be generic again. In this case, one needs something that is generic over types that are themselves generic over lifetimes. `ForLt` provides such support. It provides a trait `ForLt` which describes a type generic over a lifetime. One may use `ForLt::Of<'a>` to get an instance of a type for a specific lifetime. For the case of cross referencing, one would almost always want the lifetime to be covariant. Therefore this is also made a requirement for the `ForLt` trait, so functions with `ForLt` trait bound can assume covariance. A macro `ForLt!()` is provided to be able to obtain a type that implements `ForLt`. For example, `ForLt!(for<'a> Bar<'a>)` would yield a type that `<TheType as ForLt>::Of<'a>` is `Bar<'a>`. This also works with lifetime elision, e.g. `ForLt!(Bar<'_>)` or for types without lifetime at all, e.g. `ForLt!(u32)`. The API design draws inspiration from the higher-kinded-types [1] crate, however a different design decision has been taken (e.g. covariance requirement) and the implementation is independent. License headers use "Apache-2.0 OR MIT" because I anticipate this to be used in pin-init crate too which is licensed as such. Link: https://docs.rs/higher-kinded-types/ [1] Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Eliot Courtney <ecourtney@nvidia.com> Signed-off-by: Gary Guo <gary@garyguo.net> Acked-by: Miguel Ojeda <ojeda@kernel.org> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Link: https://patch.msgid.link/20260525202921.124698-23-dakr@kernel.org [ Handle macro_rules! invocations in the ForLt! proc macro's covariance and WF checks. Since proc macros cannot expand macro_rules!, add a visit_macro() implementation to conservatively assume macro invocations may contain lifetimes, forcing them through the compiler-assisted covariance proof. Fix a few typos in the documentation and in the commit message, add empty lines before samples, add missing periods and consistently use markdown. - Danilo ] Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Diffstat (limited to 'rust/kernel')
-rw-r--r--rust/kernel/types.rs4
-rw-r--r--rust/kernel/types/for_lt.rs122
2 files changed, 126 insertions, 0 deletions
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 9cf9f869d195..ac316fd7b538 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -11,6 +11,10 @@ use core::{
};
use pin_init::{PinInit, Wrapper, Zeroable};
+#[doc(hidden)]
+pub mod for_lt;
+pub use for_lt::ForLt;
+
/// Used to transfer ownership to and from foreign (non-Rust) languages.
///
/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and
diff --git a/rust/kernel/types/for_lt.rs b/rust/kernel/types/for_lt.rs
new file mode 100644
index 000000000000..d44323c28e8d
--- /dev/null
+++ b/rust/kernel/types/for_lt.rs
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! Provide implementation and test of the `ForLt` trait and macro.
+//!
+//! This module is hidden and user should just use `ForLt!` 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.
+///
+/// The lifetime involved must be covariant.
+///
+/// # 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)`.
+/// # >();
+/// ```
+///
+/// The macro will attempt to prove that the type is indeed covariant over the lifetime supplied.
+/// When it cannot be syntactically proven, it will emit checks to ask the Rust compiler to prove
+/// it.
+///
+/// ```ignore,compile_fail
+/// # use kernel::types::ForLt;
+/// # fn expect_lt<F: ForLt>() {}
+/// # expect_lt::<
+/// ForLt!(fn(&u32)) // Contravariant, will fail compilation.
+/// # >();
+/// ```
+///
+/// There is a limitation if the type refers to generic parameters; if the macro cannot prove the
+/// covariance syntactically, the emitted checks will fail the compilation as it needs to refer to
+/// the generic parameter but is in a separate item.
+///
+/// ```
+/// # use kernel::types::ForLt;
+/// fn expect_lt<F: ForLt>() {}
+/// # #[allow(clippy::unnecessary_safety_comment, reason = "false positive")]
+/// fn generic_fn<T: 'static>() {
+/// // Syntactically proven by the macro
+/// expect_lt::<ForLt!(&T)>();
+/// // Syntactically proven by the macro
+/// expect_lt::<ForLt!(&KBox<T>)>();
+/// // Cannot be syntactically proven, need to check covariance of `KBox`
+/// // expect_lt::<ForLt!(&KBox<&T>)>();
+/// }
+/// ```
+///
+/// # Safety
+///
+/// `Self::Of<'a>` must be covariant over the lifetime `'a`.
+pub unsafe trait ForLt {
+ /// The type parameterized by the lifetime.
+ type Of<'a>: 'a;
+
+ /// 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> {
+ // SAFETY: This is sound as this trait guarantees covariance.
+ unsafe { core::mem::transmute(long) }
+ }
+}
+pub use macros::ForLt;
+
+/// This is intended to be an "unsafe-to-refer-to" type.
+///
+/// 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.
+///
+/// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove
+/// additional properties.
+#[doc(hidden)]
+pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
+
+// 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 `ForLt!` macro, a covariance proof is generated when naming `UnsafeForLtImpl`
+// and it will fail to evaluate if the type is not covariant.
+unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for UnsafeForLtImpl<T, WF, 0> {
+ type Of<'a> = <T as WithLt<'a>>::Of;
+}