diff --git a/src/pointer/inner.rs b/src/pointer/inner.rs index 48d4e8f113..ac0938424f 100644 --- a/src/pointer/inner.rs +++ b/src/pointer/inner.rs @@ -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> @@ -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` is covariant over `T` [1]. - // - // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html ptr: NonNull, - // SAFETY: `&'a T` is covariant over `'a` [1]. + // SAFETY: `&'a UnsafeCell` 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>, } impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {} diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index c0d0cd746e..06c2733ce2 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -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 `::Variance<'a, T>` to inherit this variance. - #[doc(hidden)] - type Variance<'a, T: 'a + ?Sized>; } /// The alignment invariant of a [`Ptr`][super::Ptr]. @@ -132,7 +126,6 @@ impl Validity for Uninit { pub enum Shared {} impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; - type Variance<'a, T: 'a + ?Sized> = &'a T; } impl Reference for Shared {} @@ -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 {} diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index d09a31a582..59ec627479 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -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> @@ -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<::Variance<'a, V::Inner>>, _invariants: PhantomData, } @@ -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`]. @@ -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` to a [`PtrInner`]. diff --git a/tests/ui-msrv/ptr-is-invariant-over-v.rs b/tests/ui-msrv/ptr-is-invariant-over-v.rs new file mode 120000 index 0000000000..d29c80df7b --- /dev/null +++ b/tests/ui-msrv/ptr-is-invariant-over-v.rs @@ -0,0 +1 @@ +../ui-nightly/ptr-is-invariant-over-v.rs \ No newline at end of file diff --git a/tests/ui-msrv/ptr-is-invariant-over-v.stderr b/tests/ui-msrv/ptr-is-invariant-over-v.stderr new file mode 100644 index 0000000000..792e45aa5e --- /dev/null +++ b/tests/ui-msrv/ptr-is-invariant-over-v.stderr @@ -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 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 for more information about variance diff --git a/tests/ui-nightly/ptr-is-invariant-over-v.rs b/tests/ui-nightly/ptr-is-invariant-over-v.rs new file mode 100644 index 0000000000..cc6b6985c4 --- /dev/null +++ b/tests/ui-nightly/ptr-is-invariant-over-v.rs @@ -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() {} diff --git a/tests/ui-nightly/ptr-is-invariant-over-v.stderr b/tests/ui-nightly/ptr-is-invariant-over-v.stderr new file mode 100644 index 0000000000..180e764976 --- /dev/null +++ b/tests/ui-nightly/ptr-is-invariant-over-v.stderr @@ -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 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 for more information about variance diff --git a/tests/ui-stable/ptr-is-invariant-over-v.rs b/tests/ui-stable/ptr-is-invariant-over-v.rs new file mode 120000 index 0000000000..d29c80df7b --- /dev/null +++ b/tests/ui-stable/ptr-is-invariant-over-v.rs @@ -0,0 +1 @@ +../ui-nightly/ptr-is-invariant-over-v.rs \ No newline at end of file diff --git a/tests/ui-stable/ptr-is-invariant-over-v.stderr b/tests/ui-stable/ptr-is-invariant-over-v.stderr new file mode 100644 index 0000000000..ff1d040488 --- /dev/null +++ b/tests/ui-stable/ptr-is-invariant-over-v.stderr @@ -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 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 for more information about variance