Skip to content

Commit fe70ab6

Browse files
authored
[pointer] Fix Ptr[Inner] variance (#2351) (#2393)
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 8bbfec2 commit fe70ab6

8 files changed

+108
-8
lines changed

src/pointer/inner.rs

+5-6
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/ptr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ mod def {
3838
/// - `ptr` conforms to the validity invariant of
3939
/// [`I::Validity`](invariant::Validity).
4040
///
41-
/// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
41+
/// `Ptr<'a, T>` is [covariant] in `'a` and invariant in `T`.
4242
///
4343
/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
4444
pub struct Ptr<'a, T, I>
@@ -54,7 +54,7 @@ mod def {
5454
/// [`I::Alignment`](invariant::Alignment).
5555
/// 2. `ptr` conforms to the validity invariant of
5656
/// [`I::Validity`](invariant::Validity).
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, T>,
5959
_invariants: PhantomData<I>,
6060
}
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../ui-nightly/ptr-is-invariant-over-v.rs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0623]: lifetime mismatch
2+
--> tests/ui-msrv/ptr-is-invariant-over-v.rs:10:14
3+
|
4+
7 | big: Ptr<'small, &'big u32, (Exclusive, Aligned, Valid)>,
5+
| --------------------------------------------------- these two types are declared with different lifetimes...
6+
...
7+
10 | _small = big;
8+
| ^^^ ...but data from `big` flows into `big` here
9+
10+
error[E0623]: lifetime mismatch
11+
--> tests/ui-msrv/ptr-is-invariant-over-v.rs:17:14
12+
|
13+
14 | big: Ptr<'small, &'big u32, (Shared, Aligned, Valid)>,
14+
| ------------------------------------------------ these two types are declared with different lifetimes...
15+
...
16+
17 | _small = big;
17+
| ^^^ ...but data from `big` flows into `big` here
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, &'big u32, (Exclusive, Aligned, Valid)>,
8+
mut _small: Ptr<'small, &'small u32, (Exclusive, Aligned, Valid)>,
9+
) {
10+
_small = big;
11+
}
12+
13+
fn _when_shared<'big: 'small, 'small>(
14+
big: Ptr<'small, &'big u32, (Shared, Aligned, Valid)>,
15+
mut _small: Ptr<'small, &'small u32, (Shared, Aligned, Valid)>,
16+
) {
17+
_small = big;
18+
}
19+
20+
fn main() {}
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<'_, &u32, (invariant::Exclusive, Aligned, Valid)>`, which makes the generic argument `&u32` invariant
14+
= note: the struct `Ptr<'a, T, I>` is invariant over the parameter `T`
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<'_, &u32, (Shared, Aligned, Valid)>`, which makes the generic argument `&u32` invariant
30+
= note: the struct `Ptr<'a, T, I>` is invariant over the parameter `T`
31+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../ui-nightly/ptr-is-invariant-over-v.rs
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<'_, &u32, (invariant::Exclusive, Aligned, Valid)>`, which makes the generic argument `&u32` invariant
14+
= note: the struct `Ptr<'a, T, I>` is invariant over the parameter `T`
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<'_, &u32, (Shared, Aligned, Valid)>`, which makes the generic argument `&u32` invariant
30+
= note: the struct `Ptr<'a, T, I>` is invariant over the parameter `T`
31+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

0 commit comments

Comments
 (0)