Skip to content

Commit 2a1dd8b

Browse files
joshlfjswrenn
authored andcommitted
[pointer] Fix Ptr[Inner] variance
Previously, `Ptr<'a, T>` and `PtrInner<'a, T>` documented themselves to be covariant in both `'a` and `T`. This was true for `PtrInner`, but not for `Ptr`, which used GATs, which are invariant. This is also not the desired variance: for `Exclusive` aliasing, the desired variance matches that of `&mut` references - namely, covariant in `'a` but invariant in `T`. This commit fixes this by making `Ptr<'a, T>` and `PtrInner<'a, T>` unconditionally covariant in `'a` and invariant in `T`. gherrit-pr-id: I29f8429d9d7b14026313f030f8dc1e895a98ad56
1 parent 9322a2c commit 2a1dd8b

File tree

9 files changed

+124
-19
lines changed

9 files changed

+124
-19
lines changed

src/pointer/inner.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ mod _def {
2222
use super::*;
2323
/// The inner pointer stored inside a [`Ptr`][crate::Ptr].
2424
///
25-
/// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
25+
/// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `T`.
2626
///
2727
/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
2828
pub(crate) struct PtrInner<'a, T>
@@ -42,14 +42,13 @@ mod _def {
4242
/// address space.
4343
/// 5. If `ptr`'s referent is not zero sized,`A` is guaranteed to live
4444
/// for at least `'a`.
45-
// SAFETY: `NonNull<T>` is covariant over `T` [1].
46-
//
47-
// [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html
4845
ptr: NonNull<T>,
49-
// SAFETY: `&'a T` is covariant over `'a` [1].
46+
// SAFETY: `&'a UnsafeCell<T>` is covariant in `'a` and invariant in `T`
47+
// [1]. We use this construction rather than the equivalent `&mut T`,
48+
// because our MSRV of 1.65 prohibits `&mut` types in const contexts.
5049
//
5150
// [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance
52-
_marker: PhantomData<&'a T>,
51+
_marker: PhantomData<&'a core::cell::UnsafeCell<T>>,
5352
}
5453

5554
impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {}

src/pointer/invariant.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,6 @@ pub trait Aliasing: Sealed {
5858
/// Is `Self` [`Exclusive`]?
5959
#[doc(hidden)]
6060
const IS_EXCLUSIVE: bool;
61-
62-
/// A type which has the correct variance over `'a` and `T` for this
63-
/// aliasing invariant. `Ptr` stores a `<I::Aliasing as
64-
/// Aliasing>::Variance<'a, T>` to inherit this variance.
65-
#[doc(hidden)]
66-
type Variance<'a, T: 'a + ?Sized>;
6761
}
6862

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

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

src/pointer/ptr.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ mod def {
3737
/// - `ptr` conforms to the alignment invariant of
3838
/// [`I::Alignment`](invariant::Alignment).
3939
///
40-
/// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
40+
/// `Ptr<'a, T>` is [covariant] in `'a` and invariant in `T`.
4141
///
4242
/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
4343
pub struct Ptr<'a, V, I>
@@ -54,9 +54,8 @@ mod def {
5454
/// [`I::Aliasing`](invariant::Aliasing).
5555
/// 2. `ptr` conforms to the alignment invariant of
5656
/// [`I::Alignment`](invariant::Alignment).
57-
// SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`.
57+
// SAFETY: `PtrInner<'a, T>` is covariant in `'a` and invariant in `T`.
5858
ptr: PtrInner<'a, V::Inner>,
59-
_variance: PhantomData<<I::Aliasing as Aliasing>::Variance<'a, V::Inner>>,
6059
_invariants: PhantomData<I>,
6160
}
6261

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

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

118117
/// Converts this `Ptr<T>` to a [`PtrInner<T>`].
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../ui-nightly/ptr-is-invariant-over-v.rs
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error: lifetime may not live long enough
2+
--> tests/ui-msrv/ptr-is-invariant-over-v.rs:10:5
3+
|
4+
6 | fn _when_exclusive<'big: 'small, 'small>(
5+
| ---- ------ lifetime `'small` defined here
6+
| |
7+
| lifetime `'big` defined here
8+
...
9+
10 | _small = big;
10+
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
11+
|
12+
= help: consider adding the following bound: `'small: 'big`
13+
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
14+
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
15+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
16+
17+
error: lifetime may not live long enough
18+
--> tests/ui-msrv/ptr-is-invariant-over-v.rs:17:5
19+
|
20+
13 | fn _when_shared<'big: 'small, 'small>(
21+
| ---- ------ lifetime `'small` defined here
22+
| |
23+
| lifetime `'big` defined here
24+
...
25+
17 | _small = big;
26+
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
27+
|
28+
= help: consider adding the following bound: `'small: 'big`
29+
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
30+
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
31+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use zerocopy::pointer::{
2+
invariant::{Aligned, Exclusive, Shared, Valid},
3+
Ptr,
4+
};
5+
6+
fn _when_exclusive<'big: 'small, 'small>(
7+
big: Ptr<'small, Valid<&'big u32>, (Exclusive, Aligned)>,
8+
mut _small: Ptr<'small, Valid<&'small u32>, (Exclusive, Aligned)>,
9+
) {
10+
_small = big;
11+
}
12+
13+
fn _when_shared<'big: 'small, 'small>(
14+
big: Ptr<'small, Valid<&'big u32>, (Shared, Aligned)>,
15+
mut _small: Ptr<'small, Valid<&'small u32>, (Shared, Aligned)>,
16+
) {
17+
_small = big;
18+
}
19+
20+
fn main() {}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error: lifetime may not live long enough
2+
--> tests/ui-nightly/ptr-is-invariant-over-v.rs:10:5
3+
|
4+
6 | fn _when_exclusive<'big: 'small, 'small>(
5+
| ---- ------ lifetime `'small` defined here
6+
| |
7+
| lifetime `'big` defined here
8+
...
9+
10 | _small = big;
10+
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
11+
|
12+
= help: consider adding the following bound: `'small: 'big`
13+
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
14+
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
15+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
16+
17+
error: lifetime may not live long enough
18+
--> tests/ui-nightly/ptr-is-invariant-over-v.rs:17:5
19+
|
20+
13 | fn _when_shared<'big: 'small, 'small>(
21+
| ---- ------ lifetime `'small` defined here
22+
| |
23+
| lifetime `'big` defined here
24+
...
25+
17 | _small = big;
26+
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
27+
|
28+
= help: consider adding the following bound: `'small: 'big`
29+
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
30+
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
31+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../ui-nightly/ptr-is-invariant-over-v.rs
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error: lifetime may not live long enough
2+
--> tests/ui-stable/ptr-is-invariant-over-v.rs:10:5
3+
|
4+
6 | fn _when_exclusive<'big: 'small, 'small>(
5+
| ---- ------ lifetime `'small` defined here
6+
| |
7+
| lifetime `'big` defined here
8+
...
9+
10 | _small = big;
10+
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
11+
|
12+
= help: consider adding the following bound: `'small: 'big`
13+
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (invariant::Exclusive, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
14+
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
15+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
16+
17+
error: lifetime may not live long enough
18+
--> tests/ui-stable/ptr-is-invariant-over-v.rs:17:5
19+
|
20+
13 | fn _when_shared<'big: 'small, 'small>(
21+
| ---- ------ lifetime `'small` defined here
22+
| |
23+
| lifetime `'big` defined here
24+
...
25+
17 | _small = big;
26+
| ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big`
27+
|
28+
= help: consider adding the following bound: `'small: 'big`
29+
= note: requirement occurs because of the type `Ptr<'_, Valid<&u32>, (Shared, Aligned)>`, which makes the generic argument `Valid<&u32>` invariant
30+
= note: the struct `Ptr<'a, V, I>` is invariant over the parameter `V`
31+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

0 commit comments

Comments
 (0)