get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.1/patches/2229209/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2229209,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229209/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-pwm/patch/20260427221155.2144848-3-dakr@kernel.org/",
    "project": {
        "id": 38,
        "url": "http://patchwork.ozlabs.org/api/1.1/projects/38/?format=api",
        "name": "Linux PWM development",
        "link_name": "linux-pwm",
        "list_id": "linux-pwm.vger.kernel.org",
        "list_email": "linux-pwm@vger.kernel.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20260427221155.2144848-3-dakr@kernel.org>",
    "date": "2026-04-27T22:11:00",
    "name": "[02/24] rust: types: add `ForLt` trait for higher-ranked lifetime support",
    "commit_ref": null,
    "pull_url": null,
    "state": "handled-elsewhere",
    "archived": false,
    "hash": "f527f42fd30f5b658ae050b5ecfc2f2657eaa9eb",
    "submitter": {
        "id": 89037,
        "url": "http://patchwork.ozlabs.org/api/1.1/people/89037/?format=api",
        "name": "Danilo Krummrich",
        "email": "dakr@kernel.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-pwm/patch/20260427221155.2144848-3-dakr@kernel.org/mbox/",
    "series": [
        {
            "id": 501734,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/501734/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-pwm/list/?series=501734",
            "date": "2026-04-27T22:10:58",
            "name": "rust: device: Higher-Ranked Lifetime Types for device drivers",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/501734/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2229209/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2229209/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "\n <linux-pwm+bounces-8705-incoming=patchwork.ozlabs.org@vger.kernel.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "linux-pwm@vger.kernel.org"
        ],
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=eQAgRJnW;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-pwm+bounces-8705-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)",
            "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"eQAgRJnW\"",
            "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201"
        ],
        "Received": [
            "from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4Hrj39M3z1xrS\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 08:13:25 +1000 (AEST)",
            "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id B4E20302BA7B\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 27 Apr 2026 22:12:21 +0000 (UTC)",
            "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 4B7D23A7F57;\n\tMon, 27 Apr 2026 22:12:21 +0000 (UTC)",
            "from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 0FAA43A7F4B;\n\tMon, 27 Apr 2026 22:12:20 +0000 (UTC)",
            "by smtp.kernel.org (Postfix) with ESMTPSA id ED1B3C2BCB7;\n\tMon, 27 Apr 2026 22:12:14 +0000 (UTC)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777327941; cv=none;\n b=DpqVAgAC8p95Udu+L1X7+urblH1t167TVxRmWSiBFdwvsiww6opaUIsMHHSHOfJH+bgVpdGEuMHaz3UPMKD6NeaDxHWgQfCbtQHB4znbqYynPkx4Yeif6ApAEEhiQDxgIf9RkxhtAMMpaMlozw6ABJXozqFKrjJUWK1nJb7Dz+Y=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777327941; c=relaxed/simple;\n\tbh=pZq55eZRbTUZKxw9zFnJXT0p6kpbJ6klMByaUzBGqrM=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=OF1Z4bypCXA/TalF3GOwvobnvUoLs2G3XgW/na5MaRhlJa0WYLRiTsdk7Yc4yrC9AoadGpwcl2o2dSzISOX0adV76/x2oj1pMu+ikpswBlsmwCz5BpPhT4yYMQQ0cw8pxagt1duhiqjxHACMcnaXsSS6+UT+g5EMf2eU+3K1KW0=",
        "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=eQAgRJnW; arc=none smtp.client-ip=10.30.226.201",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1777327940;\n\tbh=pZq55eZRbTUZKxw9zFnJXT0p6kpbJ6klMByaUzBGqrM=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=eQAgRJnWO09slwMNvi5KoH/ECuE3dX56H3NTQmoRISAJfYPKST2BKY3GQmasQK/+o\n\t tzRIVCG2DjKfdAZWGiNdZwQo5XxG05X4hQ/zsLS1bHhcUsIT5XR1x5ktYAQBxr1EcZ\n\t +Xkgmfv/aaByw/8SIwwTWRCrRyfuZFPuGq+HaU8/N3LVK4/vvT0SauQpeF4lJv11CY\n\t JUZdqTiCxRvxljRH4cDnmC6+40QCyzckAYdfYFGGavK1PK/341c4Ifjqqwhz1BbICq\n\t S1Zw+qc6td7rvxj+9So05Taxbb68hKXQYeigw0ZysZh2zdiEYtoMkNLFGgZOxngig/\n\t AMaqjN8lMppjw==",
        "From": "Danilo Krummrich <dakr@kernel.org>",
        "To": "gregkh@linuxfoundation.org,\n\trafael@kernel.org,\n\tacourbot@nvidia.com,\n\taliceryhl@google.com,\n\tdavid.m.ertman@intel.com,\n\tira.weiny@intel.com,\n\tleon@kernel.org,\n\tviresh.kumar@linaro.org,\n\tm.wilczynski@samsung.com,\n\tukleinek@kernel.org,\n\tbhelgaas@google.com,\n\tkwilczynski@kernel.org,\n\tabdiel.janulgue@gmail.com,\n\trobin.murphy@arm.com,\n\tmarkus.probst@posteo.de,\n\tojeda@kernel.org,\n\tboqun@kernel.org,\n\tgary@garyguo.net,\n\tbjorn3_gh@protonmail.com,\n\tlossin@kernel.org,\n\ta.hindborg@kernel.org,\n\ttmgross@umich.edu",
        "Cc": "driver-core@lists.linux.dev,\n\tlinux-kernel@vger.kernel.org,\n\tnova-gpu@lists.linux.dev,\n\tdri-devel@lists.freedesktop.org,\n\tlinux-pm@vger.kernel.org,\n\tlinux-pwm@vger.kernel.org,\n\tlinux-pci@vger.kernel.org,\n\trust-for-linux@vger.kernel.org",
        "Subject": "[PATCH 02/24] rust: types: add `ForLt` trait for higher-ranked\n lifetime support",
        "Date": "Tue, 28 Apr 2026 00:11:00 +0200",
        "Message-ID": "<20260427221155.2144848-3-dakr@kernel.org>",
        "X-Mailer": "git-send-email 2.54.0",
        "In-Reply-To": "<20260427221155.2144848-1-dakr@kernel.org>",
        "References": "<20260427221155.2144848-1-dakr@kernel.org>",
        "Precedence": "bulk",
        "X-Mailing-List": "linux-pwm@vger.kernel.org",
        "List-Id": "<linux-pwm.vger.kernel.org>",
        "List-Subscribe": "<mailto:linux-pwm+subscribe@vger.kernel.org>",
        "List-Unsubscribe": "<mailto:linux-pwm+unsubscribe@vger.kernel.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit"
    },
    "content": "From: Gary Guo <gary@garyguo.net>\n\nThere are a few cases, e.g. when dealing with data referencing each other,\none might want to write code that are generic over lifetimes. For example,\nif you want take a function that takes `&'a Foo` and gives `Bar<'a>`, you\ncan write:\n\n    f: impl for<'a> FnOnce(&'a Foo) -> Bar<'a>,\n\nHowever, it becomes tricky when you want that function to not have a fixed\n`Bar`, but have it be generic again. In this case, one needs something that\nis generic over types that are themselves generic over lifetimes.\n\n`ForLt` provides such support. It provides a trait `ForLt` which describes\na type generic over lifetime. One may use `ForLt::Of<'a>` to get an\ninstance of a type for a specific lifetime.\n\nFor the case of cross referencing, one would almost always want the\nlifetime to be covariant. Therefore this is also made a requirement for the\n`ForLt` trait, so functions with `ForLt` trait bound can assume covariance.\n\nA macro `ForLt!()` is provided to be able to obtain a type that implements\n`ForLt`. For example, `ForLt!(for<'a> Bar<'a>)` would yield a type that\n`<TheType as ForLt>::Of<'a>` is `Bar<'a>`. This also works with lifetime\nelision, e.g. `ForLt!(Bar<'_>)` or for types without lifetime at all, e.g.\n`ForLt!(u32)`.\n\nThe API design draws inspiration from the higher-kinded-types [1] crate,\nhowever different design decision has been taken (e.g. covariance\nrequirement) and the implementation is independent.\n\nLicense headers use \"Apache-2.0 OR MIT\" because I anticipate this to be\nused in pin-init crate too which is licensed as such.\n\nLink: https://docs.rs/higher-kinded-types/ [1]\n\nSigned-off-by: Gary Guo <gary@garyguo.net>\n---\n rust/Makefile               |   1 +\n rust/kernel/types.rs        |   4 +\n rust/kernel/types/for_lt.rs | 117 +++++++++++++++++\n rust/macros/for_lt.rs       | 242 ++++++++++++++++++++++++++++++++++++\n rust/macros/lib.rs          |  12 ++\n 5 files changed, 376 insertions(+)\n create mode 100644 rust/kernel/types/for_lt.rs\n create mode 100644 rust/macros/for_lt.rs",
    "diff": "diff --git a/rust/Makefile b/rust/Makefile\nindex b361bfedfdf0..c5a9a3339416 100644\n--- a/rust/Makefile\n+++ b/rust/Makefile\n@@ -110,6 +110,7 @@ syn-cfgs := \\\n     feature=\"parsing\" \\\n     feature=\"printing\" \\\n     feature=\"proc-macro\" \\\n+    feature=\"visit\" \\\n     feature=\"visit-mut\"\n \n syn-flags := \\\ndiff --git a/rust/kernel/types.rs b/rust/kernel/types.rs\nindex 4329d3c2c2e5..3119401dcb9f 100644\n--- a/rust/kernel/types.rs\n+++ b/rust/kernel/types.rs\n@@ -11,6 +11,10 @@\n };\n use pin_init::{PinInit, Wrapper, Zeroable};\n \n+#[doc(hidden)]\n+pub mod for_lt;\n+pub use for_lt::ForLt;\n+\n /// Used to transfer ownership to and from foreign (non-Rust) languages.\n ///\n /// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and\ndiff --git a/rust/kernel/types/for_lt.rs b/rust/kernel/types/for_lt.rs\nnew file mode 100644\nindex 000000000000..4983cc761f80\n--- /dev/null\n+++ b/rust/kernel/types/for_lt.rs\n@@ -0,0 +1,117 @@\n+// SPDX-License-Identifier: Apache-2.0 OR MIT\n+\n+//! Provide implementation and test of the `ForLt` trait and macro.\n+//!\n+//! This module is hidden and user should just use `ForLt!` directly.\n+\n+use core::marker::PhantomData;\n+\n+/// Representation of types generic over a lifetime.\n+///\n+/// The type must be covariant over the generic lifetime, i.e. the lifetime parameter\n+/// can be soundly shorterned.\n+///\n+/// The lifetime involved must be covariant.\n+///\n+/// # Macro\n+///\n+/// It is not recommended to implement this trait directly. `ForLt!` macro is provided to obtain a\n+/// type that implements this trait.\n+///\n+/// The full syntax is\n+/// ```\n+/// # use kernel::types::ForLt;\n+/// # fn expect_lt<F: ForLt>() {}\n+/// # struct TypeThatUse<'a>(&'a ());\n+/// # expect_lt::<\n+/// ForLt!(for<'a> TypeThatUse<'a>)\n+/// # >();\n+/// ```\n+/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>`\n+/// is `TypeThatUse<'b>`.\n+///\n+/// You may also use a short-hand syntax which works similar to lifetime elision.\n+/// The macro also accepts types that does not involved lifetime at all.\n+/// ```\n+/// # use kernel::types::ForLt;\n+/// # fn expect_lt<F: ForLt>() {}\n+/// # struct TypeThatUse<'a>(&'a ());\n+/// # expect_lt::<\n+/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`\n+/// # >();\n+/// # expect_lt::<\n+/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`\n+/// # >();\n+/// # expect_lt::<\n+/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`\n+/// # >();\n+/// ```\n+///\n+/// The macro will attempt to prove that the type is indeed covariant over the lifetime supplied.\n+/// When it cannot be syntactically proven, it will emit checks to ask the Rust compiler to prove\n+/// it.\n+/// ```ignore,compile_fail\n+/// # use kernel::types::ForLt;\n+/// # fn expect_lt<F: ForLt>() {}\n+/// # expect_lt::<\n+/// ForLt!(fn(&u32)) // Contravariant, will fail compilation.\n+/// # >();\n+/// ```\n+///\n+/// There is a limitation if the type refer to generic parameters; if the macro cannot prove the\n+/// covariance syntactically, the emitted checks will fail the compilation as it needs to refer to\n+/// the generic parameter but is in a separate item.\n+/// ```\n+/// # use kernel::types::ForLt;\n+/// fn expect_lt<F: ForLt>() {}\n+/// # #[allow(clippy::unnecessary_safety_comment, reason = \"false positive\")]\n+/// fn generic_fn<T: 'static>() {\n+///     // Syntactically proven by the macro\n+///     expect_lt::<ForLt!(&T)>();\n+///     // Syntactically proven by the macro\n+///     expect_lt::<ForLt!(&KBox<T>)>();\n+///     // Cannot be syntactically proven, need to check covariance of `KBox`\n+///     // expect_lt::<ForLt!(&KBox<&T>)>();\n+/// }\n+/// ```\n+///\n+/// # Safety\n+///\n+/// `Self::Of<'a>` must be covariant over the lifetime `'a`.\n+pub unsafe trait ForLt {\n+    /// The type parameterized by the lifetime.\n+    type Of<'a>;\n+\n+    /// Cast a reference to a shorter lifetime.\n+    #[inline(always)]\n+    fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Self::Of<'short> {\n+        // SAFETY: This is sound as this trait guarantees covariance.\n+        unsafe { core::mem::transmute(long) }\n+    }\n+}\n+pub use macros::ForLt;\n+\n+/// This is intended to be an \"unsafe-to-refer-to\" type.\n+///\n+/// Must only be used by the `ForLt!` macro.\n+///\n+/// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro.\n+///\n+/// `WF` is a type that the macro can use to assert some specific type is well-formed.\n+///\n+/// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove\n+/// additional properties.\n+#[doc(hidden)]\n+pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);\n+\n+// This is a helper trait for implementation `ForLt` to be able to use HRTB.\n+#[doc(hidden)]\n+pub trait WithLt<'a> {\n+    type Of;\n+}\n+\n+// SAFETY: In `ForLt!` macro, a covariance proof is generated when naming `UnsafeForLtImpl`\n+// and it will fail to evaluate if the type is not covariant.\n+unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for UnsafeForLtImpl<T, WF, 0> {\n+    type Of<'a> = <T as WithLt<'a>>::Of;\n+}\ndiff --git a/rust/macros/for_lt.rs b/rust/macros/for_lt.rs\nnew file mode 100644\nindex 000000000000..df2027789713\n--- /dev/null\n+++ b/rust/macros/for_lt.rs\n@@ -0,0 +1,242 @@\n+// SPDX-License-Identifier: Apache-2.0 OR MIT\n+\n+use proc_macro2::{\n+    Span,\n+    TokenStream, //\n+};\n+use quote::{\n+    format_ident,\n+    quote, //\n+};\n+use syn::{\n+    parse::{\n+        Parse,\n+        ParseStream, //\n+    },\n+    visit::Visit,\n+    visit_mut::VisitMut,\n+    Lifetime,\n+    Result,\n+    Token,\n+    Type, //\n+};\n+\n+pub(crate) enum HigherRankedType {\n+    Explicit {\n+        _for_token: Token![for],\n+        _lt_token: Token![<],\n+        lifetime: Lifetime,\n+        _gt_token: Token![>],\n+        ty: Type,\n+    },\n+    Implicit {\n+        ty: Type,\n+    },\n+}\n+\n+impl Parse for HigherRankedType {\n+    fn parse(input: ParseStream<'_>) -> Result<Self> {\n+        if input.peek(Token![for]) {\n+            Ok(Self::Explicit {\n+                _for_token: input.parse()?,\n+                _lt_token: input.parse()?,\n+                lifetime: input.parse()?,\n+                _gt_token: input.parse()?,\n+                ty: input.parse()?,\n+            })\n+        } else {\n+            Ok(Self::Implicit { ty: input.parse()? })\n+        }\n+    }\n+}\n+\n+trait TypeExt {\n+    fn expand_elided_lifetime(&self, explicit_lt: &Lifetime) -> Type;\n+    fn replace_lifetime(&self, src: &Lifetime, dst: &Lifetime) -> Type;\n+    fn has_lifetime(&self, lt: &Lifetime) -> bool;\n+}\n+\n+impl TypeExt for Type {\n+    fn expand_elided_lifetime(&self, explicit_lt: &Lifetime) -> Type {\n+        struct ElidedLifetimeExpander<'a>(&'a Lifetime);\n+\n+        impl VisitMut for ElidedLifetimeExpander<'_> {\n+            fn visit_lifetime_mut(&mut self, lifetime: &mut Lifetime) {\n+                // Expand explicit `'_`\n+                if lifetime.ident == \"_\" {\n+                    *lifetime = self.0.clone();\n+                }\n+            }\n+\n+            fn visit_type_reference_mut(&mut self, reference: &mut syn::TypeReference) {\n+                syn::visit_mut::visit_type_reference_mut(self, reference);\n+\n+                if reference.lifetime.is_none() {\n+                    reference.lifetime = Some(self.0.clone());\n+                }\n+            }\n+        }\n+\n+        let mut ret = self.clone();\n+        ElidedLifetimeExpander(explicit_lt).visit_type_mut(&mut ret);\n+        ret\n+    }\n+\n+    fn replace_lifetime(&self, src: &Lifetime, dst: &Lifetime) -> Type {\n+        struct LifetimeReplacer<'a>(&'a Lifetime, &'a Lifetime);\n+\n+        impl VisitMut for LifetimeReplacer<'_> {\n+            fn visit_lifetime_mut(&mut self, lifetime: &mut Lifetime) {\n+                if lifetime.ident == self.0.ident {\n+                    *lifetime = self.1.clone();\n+                }\n+            }\n+        }\n+\n+        let mut ret = self.clone();\n+        LifetimeReplacer(src, dst).visit_type_mut(&mut ret);\n+        ret\n+    }\n+\n+    fn has_lifetime(&self, lt: &Lifetime) -> bool {\n+        struct HasLifetime<'a>(&'a Lifetime, bool);\n+\n+        impl Visit<'_> for HasLifetime<'_> {\n+            fn visit_lifetime(&mut self, lifetime: &Lifetime) {\n+                if lifetime.ident == self.0.ident {\n+                    self.1 = true;\n+                }\n+            }\n+        }\n+\n+        let mut visitor = HasLifetime(lt, false);\n+        visitor.visit_type(self);\n+        visitor.1\n+    }\n+}\n+\n+struct Prover<'a>(&'a Lifetime, Vec<&'a Type>);\n+\n+impl<'a> Prover<'a> {\n+    /// Prove that `ty` is covariant over `'lt`.\n+    ///\n+    /// This also needs to prove that it'll be wellformed for any instance of `'lt`.\n+    /// It can be assumed that `ty` will be wellformed if `'lt` is substituted to `'static`.\n+    fn prove(&mut self, ty: &'a Type) {\n+        match ty {\n+            Type::Paren(ty) => self.prove(&ty.elem),\n+            Type::Group(ty) => self.prove(&ty.elem),\n+\n+            // No lifetime involved\n+            Type::Never(_) => {}\n+\n+            // `[T; N]` and `[T]` is covariant over `T`.\n+            Type::Array(ty) => self.prove(&ty.elem),\n+            Type::Slice(ty) => self.prove(&ty.elem),\n+\n+            Type::Tuple(ty) => {\n+                for elem in &ty.elems {\n+                    self.prove(elem);\n+                }\n+            }\n+\n+            // `*const T` is covariant over `T`\n+            Type::Ptr(ty) if ty.const_token.is_some() => self.prove(&ty.elem),\n+\n+            // `&T` is covariant over `T` and lifetime.\n+            //\n+            // Note that if we encounter `&'other_lt T`, then we still need to make sure the type\n+            // is wellformed if `T` involves `&'lt`, so we defer to the compiler.\n+            //\n+            // This is to block cases like `ForLt!(for<'a> &'static &'a u32)`, as the presence of\n+            // the type implies `'a: 'static` but this is unsound.\n+            Type::Reference(ty)\n+                if ty.mutability.is_none() && ty.lifetime.as_ref() == Some(self.0) =>\n+            {\n+                self.prove(&ty.elem)\n+            }\n+\n+            // `&[mut] T` is covariant over lifetime.\n+            // In case we have `&[mut] NoLifetime`, we don't need to do additional checks.\n+            Type::Reference(ty) if !ty.elem.has_lifetime(self.0) => (),\n+\n+            // No mention of lifetime at all, no need to perform compiler check.\n+            ty if !ty.has_lifetime(self.0) => (),\n+\n+            // Otherwise, we need to emit checks so that compiler can determine if the types are\n+            // actually covariant.\n+            ty => self.1.push(ty),\n+        }\n+    }\n+}\n+\n+pub(crate) fn for_lt(input: HigherRankedType) -> TokenStream {\n+    let (ty, lifetime) = match input {\n+        HigherRankedType::Explicit { lifetime, ty, .. } => (ty, lifetime),\n+        HigherRankedType::Implicit { ty } => {\n+            // If there's no explicit `for<'a>` binder, inject a synthetic `'__elided` lifetime\n+            // and expand elided sites.\n+            let lifetime = Lifetime {\n+                apostrophe: Span::mixed_site(),\n+                ident: format_ident!(\"__elided\", span = Span::mixed_site()),\n+            };\n+            (ty.expand_elided_lifetime(&lifetime), lifetime)\n+        }\n+    };\n+\n+    let mut prover = Prover(&lifetime, Vec::new());\n+    prover.prove(&ty);\n+\n+    let mut proof = Vec::new();\n+\n+    // Emit proofs for every type that requires additional compiler help in proving covariance.\n+    for (idx, required_proof) in prover.1.into_iter().enumerate() {\n+        // Insert a proof that the type is well-formed.\n+        //\n+        // This is intended to workaround a Rust compiler soundness bug related to HRTB.\n+        // https://github.com/rust-lang/rust/issues/152489\n+        //\n+        // This needs to be a struct instead of fn to avoid the implied WF bounds.\n+        let wf_proof_name = format_ident!(\"ProveWf{idx}\");\n+        proof.push(quote!(\n+            struct #wf_proof_name<#lifetime>(\n+                ::core::marker::PhantomData<&#lifetime ()>, #required_proof\n+            );\n+        ));\n+\n+        // Insert a proof that the type is covariant.\n+        let cov_proof_name = format_ident!(\"prove_covariant_{idx}\");\n+        proof.push(quote!(\n+            fn #cov_proof_name<'__short, '__long: '__short>(\n+                long: #wf_proof_name<'__long>\n+            ) -> #wf_proof_name<'__short> {\n+                long\n+            }\n+        ));\n+    }\n+\n+    // Make sure that the type is wellformed when substituting lifetime with `'static`.\n+    //\n+    // Currently the Rust compiler doesn't check this, see the above ProveWf documentation.\n+    //\n+    // We prefer to use this way of proving WF-ness as it can work when generics are involved.\n+    let ty_static = ty.replace_lifetime(\n+        &lifetime,\n+        &Lifetime {\n+            apostrophe: Span::mixed_site(),\n+            ident: format_ident!(\"static\"),\n+        },\n+    );\n+\n+    quote!(\n+        ::kernel::types::for_lt::UnsafeForLtImpl::<\n+            dyn for<#lifetime> ::kernel::types::for_lt::WithLt<#lifetime, Of = #ty>,\n+            #ty_static,\n+            {\n+                #(#proof)*\n+\n+                0\n+            }\n+        >\n+    )\n+}\ndiff --git a/rust/macros/lib.rs b/rust/macros/lib.rs\nindex 2cfd59e0f9e7..e5f6f8318112 100644\n--- a/rust/macros/lib.rs\n+++ b/rust/macros/lib.rs\n@@ -17,6 +17,7 @@\n mod concat_idents;\n mod export;\n mod fmt;\n+mod for_lt;\n mod helpers;\n mod kunit;\n mod module;\n@@ -489,3 +490,14 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStream) -> TokenStream {\n         .unwrap_or_else(|e| e.into_compile_error())\n         .into()\n }\n+\n+/// Obtain a type that implements `ForLt` for the given higher-ranked type.\n+///\n+/// Please refer to the documentation of [`ForLt`] trait.\n+///\n+/// [`ForLt`]: trait.ForLt.html\n+#[proc_macro]\n+#[allow(non_snake_case)] // The macro shares the name with the trait.\n+pub fn ForLt(input: TokenStream) -> TokenStream {\n+    for_lt::for_lt(parse_macro_input!(input)).into()\n+}\n",
    "prefixes": [
        "02/24"
    ]
}