@@ -474,16 +474,9 @@ struct Foo<'a, 'b, A, B, C, D, E, F, G, H> {
474
474
475
475
476
476
477
-
478
- ## Dropck
479
-
480
- TODO
481
-
482
-
483
477
## PhantomData
484
478
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
487
480
types or lifetimes are logically associated with a struct, but not actually
488
481
part of a field. This most commonly occurs with lifetimes. For instance, the ` Iter `
489
482
for ` &'a [T] ` is (approximately) defined as follows:
@@ -498,7 +491,8 @@ pub struct Iter<'a, T: 'a> {
498
491
However because ` 'a ` is unused within the struct's body, it's * unbound* .
499
492
Because of the troubles this has historically caused, unbound lifetimes and
500
493
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.
502
496
503
497
We do this using * PhantomData* , which is a special marker type. PhantomData
504
498
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> {
516
510
}
517
511
```
518
512
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
+
521
557
522
558
523
559
0 commit comments