Skip to content

Commit fabbd4e

Browse files
committed
progress
1 parent c3c9d91 commit fabbd4e

File tree

1 file changed

+47
-11
lines changed

1 file changed

+47
-11
lines changed

lifetimes.md

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -474,16 +474,9 @@ struct Foo<'a, 'b, A, B, C, D, E, F, G, H> {
474474

475475

476476

477-
478-
## Dropck
479-
480-
TODO
481-
482-
483477
## PhantomData
484478

485-
486-
However when working with unsafe code, we can often end up in a situation where
479+
When working with unsafe code, we can often end up in a situation where
487480
types or lifetimes are logically associated with a struct, but not actually
488481
part of a field. This most commonly occurs with lifetimes. For instance, the `Iter`
489482
for `&'a [T]` is (approximately) defined as follows:
@@ -498,7 +491,8 @@ pub struct Iter<'a, T: 'a> {
498491
However because `'a` is unused within the struct's body, it's *unbound*.
499492
Because of the troubles this has historically caused, unbound lifetimes and
500493
types are *illegal* in struct definitions. Therefore we must somehow refer
501-
to these types in the body.
494+
to these types in the body. Correctly doing this is necessary to have
495+
correct variance and drop checking.
502496

503497
We do this using *PhantomData*, which is a special marker type. PhantomData
504498
consumes no space, but simulates a field of the given type for the purpose of
@@ -516,8 +510,50 @@ pub struct Iter<'a, T: 'a> {
516510
}
517511
```
518512

519-
However PhantomData is also necessary to signal important information to
520-
*dropck*. (TODO)
513+
514+
515+
516+
## Dropck
517+
518+
When a type is going out of scope, Rust will try to Drop it. Drop executes
519+
arbitrary code, and in fact allows us to "smuggle" arbitrary code execution
520+
into many places. As such additional soundness checks (dropck) are necessary to
521+
ensure that a type T can be safely instantiated and dropped. It turns out that we
522+
*really* don't need to care about dropck in practice, as it often "just works".
523+
524+
However the one exception is with PhantomData. Given a struct like Vec:
525+
526+
```
527+
struct Vec<T> {
528+
data: *const T, // *const for covariance!
529+
len: usize,
530+
cap: usize,
531+
}
532+
```
533+
534+
dropck will generously determine that Vec<T> does not contain any values of
535+
type T. This will unfortunately allow people to construct unsound Drop
536+
implementations that access data that has already been dropped. In order to
537+
tell dropck that we *do* own values of type T and may call destructors of that
538+
type, we must add extra PhantomData:
539+
540+
```
541+
struct Vec<T> {
542+
data: *const T, // *const for covariance!
543+
len: usize,
544+
cap: usize,
545+
_marker: marker::PhantomData<T>,
546+
}
547+
```
548+
549+
Raw pointers that own an allocation is such a pervasive pattern that the
550+
standard library made a utility for itself called `Unique<T>` which:
551+
552+
* wraps a `*const T`,
553+
* includes a PhantomData<T>,
554+
* auto-derives Send/Sync as if T was contained
555+
* marks the pointer as NonZero for the null-pointer optimization
556+
521557

522558

523559

0 commit comments

Comments
 (0)