-
Notifications
You must be signed in to change notification settings - Fork 475
Description
This issue is meant to document the known imprecision for potential future cleanup.
Description
We currently have a few functions returning RPIT (return-position impl Trait) abstract (or opaque) types with + 'a
bound. While the intended lifetime relationship is that the abstract type lives at most as long as 'a
, the signature actually implies the opposite: the abstract type outlives 'a
.
To elaborate, one concrete example is XArray
's iter
implementation:
Lines 104 to 118 in 0303584
fn iter(&self) -> impl Iterator<Item = NonNull<T::PointedTo>> + '_ { | |
let mut index = 0; | |
// SAFETY: `self.xa` is always valid by the type invariant. | |
iter::once(unsafe { | |
bindings::xa_find(self.xa.get(), &mut index, usize::MAX, bindings::XA_PRESENT) | |
}) | |
.chain(iter::from_fn(move || { | |
// SAFETY: `self.xa` is always valid by the type invariant. | |
Some(unsafe { | |
bindings::xa_find_after(self.xa.get(), &mut index, usize::MAX, bindings::XA_PRESENT) | |
}) | |
})) | |
.map_while(|ptr| NonNull::new(ptr.cast())) | |
} |
Here, the return type uses + '_
, which promises that the RPIT abstract type outlives the lifetime of &self
. However, this is not semantically accurate since the concrete iterator type returned should not outlive the lifetime of &self
to which it refers. The reason it works in this specific case is that the lifetime of the returned abstract type happens to be exactly equal to the lifetime of &self
.
Such mismatches could be correctly expressed using use<..>
bounds. For the XArray
case, the signature could eventually become:
fn iter(&self) -> impl Iterator<Item = NonNull<T::PointedTo>> + use<'_, T> {
// ...
}
Unfortunately, use<..>
bounds are only available starting with Rust 1.82, while the current MSRV for Rust-for-Linux is 1.78.0. As a result, this fix cannot be adopted yet.
No immediate action is required, but these cases may be revisited once the MSRV is updated to Rust 1.82.
Remaining cases
linux/rust/pin-init/examples/mutex.rs
Lines 165 to 173 in 0303584
impl WaitEntry { #[inline] fn insert_new(list: &ListHead) -> impl PinInit<Self> + '_ { pin_init!(Self { thread: thread::current(), wait_list <- ListHead::insert_prev(list), }) } } linux/rust/pin-init/examples/linked_list.rs
Lines 41 to 57 in 0303584
#[inline] pub fn insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ { try_pin_init!(&this in Self { prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}), next: list.next.replace(unsafe { Link::new_unchecked(this)}), pin: PhantomPinned, }? Infallible) } #[inline] pub fn insert_prev(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ { try_pin_init!(&this in Self { next: list.prev.next().replace(unsafe { Link::new_unchecked(this)}), prev: list.prev.replace(unsafe { Link::new_unchecked(this)}), pin: PhantomPinned, }? Infallible) }
References
- The original Zulip discussion: https://rust-for-linux.zulipchat.com/#narrow/channel/288089/topic/x/near/525716247
- The Rust RFC Book -
lifetime_capture_rules_2024
: https://rust-lang.github.io/rfcs/3498-lifetime-capture-rules-2024.html - The Rust Edition Guide - RPIT lifetime capture rules: https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html
- The Rust Reference - Trait and lifetime bounds: https://doc.rust-lang.org/reference/trait-bounds.html#r-bound.use