According to the doc of PhantomData, one usafe of PhantomData is for unused lifetime parameters like:
struct Slice<'a, T: 'a> {
start: *mut T,
end: *mut T,
_invariant: PhantomData<&'a T>,
}
fn foo<T>(v: &mut Vec<T>) -> Slice<'_, T> {
let ptr = v.as_mut_ptr();
unsafe { Slice { start: ptr, end: ptr.add(v.len()), _invariant: PhantomData } }
}
pub fn main() {
let mut v = vec!(1, 2, 3);
let slice = foo(&mut v);
drop(v);
let s1 = unsafe { &mut *slice.start };
let s2 = slice.start;
*s1 += 1;
println!("{}", s1);
unsafe { *s2 += 1 };
println!("{}", unsafe { *s2 });
}
It causes an compile error:
error[E0505]: cannot move out of `v` because it is borrowed
--> phantom.rs:35:10
|
33 | let slice = foo(&mut v);
| ------ borrow of `v` occurs here
34 |
35 | drop(v);
| ^ move out of `v` occurs here
...
38 | let s1 = unsafe { &mut *slice.start };
| ----------------- borrow later used here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0505`.
If we don't use PhantomData, it generates no compile error.
struct Slice<T> {
start: *mut T,
end: *mut T,
}
fn foo<T>(v: &mut Vec<T>) -> Slice<T> {
let ptr = v.as_mut_ptr();
unsafe { Slice { start: ptr, end: ptr.add(v.len()) } }
}
pub fn main() {
let mut v = vec!(1, 2, 3);
let slice = foo(&mut v);
drop(v);
// drop(slice);
let s1 = unsafe { &mut *slice.start };
let s2 = slice.start;
*s1 += 1;
println!("{}", s1);
unsafe { *s2 += 1 };
println!("{}", unsafe { *s2 });
}
Borrow in foo
is important here. Without it, no compile error occurs.
use std::marker::PhantomData;
struct Slice<'a, T: 'a> {
start: *mut T,
end: *mut T,
_invariant: PhantomData<&'a T>,
}
pub fn main() {
let mut v = vec!(1, 2, 3);
let ptr = v.as_mut_ptr(); // pointer can be copied, so borrow doesn't occur.
let slice = unsafe { Slice { start: ptr, end: ptr.add(v.len()), _invariant: PhantomData } };
drop(v);
// drop(slice);
let s1 = unsafe { &mut *slice.start };
let s2 = slice.start;
*s1 += 1;
println!("{}", s1);
unsafe { *s2 += 1 };
println!("{}", unsafe { *s2 });
}