Skip to content

[pointer] Fix Ptr[Inner] variance #2351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions src/pointer/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ mod _def {
use super::*;
/// The inner pointer stored inside a [`Ptr`][crate::Ptr].
///
/// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
/// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `T`.
///
/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
pub(crate) struct PtrInner<'a, T>
Expand All @@ -42,14 +42,13 @@ mod _def {
/// address space.
/// 5. If `ptr`'s referent is not zero sized,`A` is guaranteed to live
/// for at least `'a`.
// SAFETY: `NonNull<T>` is covariant over `T` [1].
//
// [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html
ptr: NonNull<T>,
// SAFETY: `&'a T` is covariant over `'a` [1].
// SAFETY: `&'a UnsafeCell<T>` is covariant in `'a` and invariant in `T`
// [1]. We use this construction rather than the equivalent `&mut T`,
// because our MSRV of 1.65 prohibits `&mut` types in const contexts.
//
// [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance
_marker: PhantomData<&'a T>,
_marker: PhantomData<&'a core::cell::UnsafeCell<T>>,
}

impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {}
Expand Down
8 changes: 0 additions & 8 deletions src/pointer/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,6 @@ pub trait Aliasing: Sealed {
/// Is `Self` [`Exclusive`]?
#[doc(hidden)]
const IS_EXCLUSIVE: bool;

/// A type which has the correct variance over `'a` and `T` for this
/// aliasing invariant. `Ptr` stores a `<I::Aliasing as
/// Aliasing>::Variance<'a, T>` to inherit this variance.
#[doc(hidden)]
type Variance<'a, T: 'a + ?Sized>;
}

/// The alignment invariant of a [`Ptr`][super::Ptr].
Expand Down Expand Up @@ -132,7 +126,6 @@ impl<T: ?Sized> Validity for Uninit<T> {
pub enum Shared {}
impl Aliasing for Shared {
const IS_EXCLUSIVE: bool = false;
type Variance<'a, T: 'a + ?Sized> = &'a T;
}
impl Reference for Shared {}

Expand All @@ -144,7 +137,6 @@ impl Reference for Shared {}
pub enum Exclusive {}
impl Aliasing for Exclusive {
const IS_EXCLUSIVE: bool = true;
type Variance<'a, T: 'a + ?Sized> = &'a mut T;
}
impl Reference for Exclusive {}

Expand Down
9 changes: 4 additions & 5 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ mod def {
/// - `ptr` conforms to the alignment invariant of
/// [`I::Alignment`](invariant::Alignment).
///
/// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
/// `Ptr<'a, T>` is [covariant] in `'a` and invariant in `T`.
///
/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
pub struct Ptr<'a, V, I>
Expand All @@ -54,9 +54,8 @@ mod def {
/// [`I::Aliasing`](invariant::Aliasing).
/// 2. `ptr` conforms to the alignment invariant of
/// [`I::Alignment`](invariant::Alignment).
// SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`.
// SAFETY: `PtrInner<'a, T>` is covariant in `'a` and invariant in `T`.
ptr: PtrInner<'a, V::Inner>,
_variance: PhantomData<<I::Aliasing as Aliasing>::Variance<'a, V::Inner>>,
_invariants: PhantomData<I>,
}

Expand Down Expand Up @@ -94,7 +93,7 @@ mod def {
let ptr = unsafe { PtrInner::new(ptr) };
// SAFETY: The caller has promised (in 6 - 8) to satisfy all safety
// invariants of `Ptr`.
Self { ptr, _variance: PhantomData, _invariants: PhantomData }
Self { ptr, _invariants: PhantomData }
}

/// Constructs a new `Ptr` from a [`PtrInner`].
Expand All @@ -112,7 +111,7 @@ mod def {
pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, V::Inner>) -> Ptr<'a, V, I> {
// SAFETY: The caller has promised to satisfy all safety invariants
// of `Ptr`.
Self { ptr, _variance: PhantomData, _invariants: PhantomData }
Self { ptr, _invariants: PhantomData }
}

/// Converts this `Ptr<T>` to a [`PtrInner<T>`].
Expand Down
1 change: 1 addition & 0 deletions tests/ui-msrv/ptr-is-invariant-over-v.rs
31 changes: 31 additions & 0 deletions tests/ui-msrv/ptr-is-invariant-over-v.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error: lifetime may not live long enough
--> tests/ui-msrv/ptr-is-invariant-over-v.rs:10:5
|
6 | fn _when_exclusive<'big: 'small, 'small>(
| ---- ------ lifetime `'small` defined here
| |
| lifetime `'big` defined here
...
10 | _small = big;
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
|
= help: consider adding the following bound: `'small: 'big`
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
--> tests/ui-msrv/ptr-is-invariant-over-v.rs:17:5
|
13 | fn _when_shared<'big: 'small, 'small>(
| ---- ------ lifetime `'small` defined here
| |
| lifetime `'big` defined here
...
17 | _small = big;
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
|
= help: consider adding the following bound: `'small: 'big`
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
20 changes: 20 additions & 0 deletions tests/ui-nightly/ptr-is-invariant-over-v.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use zerocopy::pointer::{
invariant::{Aligned, Exclusive, Shared, Valid},
Ptr,
};

fn _when_exclusive<'big: 'small, 'small>(
big: Ptr<'small, Valid<&'big u32>, (Exclusive, Aligned)>,
mut _small: Ptr<'small, Valid<&'small u32>, (Exclusive, Aligned)>,
) {
_small = big;
}

fn _when_shared<'big: 'small, 'small>(
big: Ptr<'small, Valid<&'big u32>, (Shared, Aligned)>,
mut _small: Ptr<'small, Valid<&'small u32>, (Shared, Aligned)>,
) {
_small = big;
}

fn main() {}
31 changes: 31 additions & 0 deletions tests/ui-nightly/ptr-is-invariant-over-v.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error: lifetime may not live long enough
--> tests/ui-nightly/ptr-is-invariant-over-v.rs:10:5
|
6 | fn _when_exclusive<'big: 'small, 'small>(
| ---- ------ lifetime `'small` defined here
| |
| lifetime `'big` defined here
...
10 | _small = big;
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
|
= help: consider adding the following bound: `'small: 'big`
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
--> tests/ui-nightly/ptr-is-invariant-over-v.rs:17:5
|
13 | fn _when_shared<'big: 'small, 'small>(
| ---- ------ lifetime `'small` defined here
| |
| lifetime `'big` defined here
...
17 | _small = big;
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
|
= help: consider adding the following bound: `'small: 'big`
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
1 change: 1 addition & 0 deletions tests/ui-stable/ptr-is-invariant-over-v.rs
31 changes: 31 additions & 0 deletions tests/ui-stable/ptr-is-invariant-over-v.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error: lifetime may not live long enough
--> tests/ui-stable/ptr-is-invariant-over-v.rs:10:5
|
6 | fn _when_exclusive<'big: 'small, 'small>(
| ---- ------ lifetime `'small` defined here
| |
| lifetime `'big` defined here
...
10 | _small = big;
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
|
= help: consider adding the following bound: `'small: 'big`
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
--> tests/ui-stable/ptr-is-invariant-over-v.rs:17:5
|
13 | fn _when_shared<'big: 'small, 'small>(
| ---- ------ lifetime `'small` defined here
| |
| lifetime `'big` defined here
...
17 | _small = big;
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
|
= help: consider adding the following bound: `'small: 'big`
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Loading