]> git.proxmox.com Git - rustc.git/blame - src/doc/nomicon/phantom-data.md
New upstream version 1.12.0+dfsg1
[rustc.git] / src / doc / nomicon / phantom-data.md
CommitLineData
c1a9b12d
SL
1% PhantomData
2
3When working with unsafe code, we can often end up in a situation where
4types or lifetimes are logically associated with a struct, but not actually
5part of a field. This most commonly occurs with lifetimes. For instance, the
6`Iter` for `&'a [T]` is (approximately) defined as follows:
7
8```rust,ignore
9struct Iter<'a, T: 'a> {
10 ptr: *const T,
11 end: *const T,
12}
13```
14
15However because `'a` is unused within the struct's body, it's *unbounded*.
16Because of the troubles this has historically caused, unbounded lifetimes and
17types are *forbidden* in struct definitions. Therefore we must somehow refer
18to these types in the body. Correctly doing this is necessary to have
19correct variance and drop checking.
20
21We do this using `PhantomData`, which is a special marker type. `PhantomData`
22consumes no space, but simulates a field of the given type for the purpose of
23static analysis. This was deemed to be less error-prone than explicitly telling
24the type-system the kind of variance that you want, while also providing other
25useful such as the information needed by drop check.
26
27Iter logically contains a bunch of `&'a T`s, so this is exactly what we tell
28the PhantomData to simulate:
29
30```
31use std::marker;
32
33struct Iter<'a, T: 'a> {
34 ptr: *const T,
35 end: *const T,
36 _marker: marker::PhantomData<&'a T>,
37}
38```
39
40and that's it. The lifetime will be bounded, and your iterator will be variant
41over `'a` and `T`. Everything Just Works.
42
43Another important example is Vec, which is (approximately) defined as follows:
44
45```
46struct Vec<T> {
47 data: *const T, // *const for variance!
48 len: usize,
49 cap: usize,
50}
51```
52
5bcae85e
SL
53Unlike the previous example, it *appears* that everything is exactly as we
54want. Every generic argument to Vec shows up in at least one field.
c1a9b12d
SL
55Good to go!
56
57Nope.
58
5bcae85e 59The drop checker will generously determine that `Vec<T>` does not own any values
c1a9b12d
SL
60of type T. This will in turn make it conclude that it doesn't need to worry
61about Vec dropping any T's in its destructor for determining drop check
62soundness. This will in turn allow people to create unsoundness using
63Vec's destructor.
64
65In order to tell dropck that we *do* own values of type T, and therefore may
66drop some T's when *we* drop, we must add an extra PhantomData saying exactly
67that:
68
69```
70use std::marker;
71
72struct Vec<T> {
73 data: *const T, // *const for covariance!
74 len: usize,
75 cap: usize,
76 _marker: marker::PhantomData<T>,
77}
78```
79
80Raw pointers that own an allocation is such a pervasive pattern that the
81standard library made a utility for itself called `Unique<T>` which:
82
83* wraps a `*const T` for variance
5bcae85e 84* includes a `PhantomData<T>`
c1a9b12d
SL
85* auto-derives Send/Sync as if T was contained
86* marks the pointer as NonZero for the null-pointer optimization