@@ -71,7 +71,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
71
71
ccx : & CrateCtxt < ' a , ' tcx > ,
72
72
drop_impl_did : DefId ,
73
73
drop_impl_ty : Ty < ' tcx > ,
74
- self_type_did : DefId ) -> Result < ( ) , ( ) >
74
+ self_type_did : DefId )
75
+ -> Result < ( ) , ( ) >
75
76
{
76
77
let tcx = ccx. tcx ;
77
78
let drop_impl_node_id = tcx. map . as_local_node_id ( drop_impl_did) . unwrap ( ) ;
@@ -123,7 +124,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
123
124
drop_impl_did : DefId ,
124
125
dtor_predicates : & ty:: GenericPredicates < ' tcx > ,
125
126
self_type_did : DefId ,
126
- self_to_impl_substs : & Substs < ' tcx > ) -> Result < ( ) , ( ) > {
127
+ self_to_impl_substs : & Substs < ' tcx > )
128
+ -> Result < ( ) , ( ) >
129
+ {
127
130
128
131
// Here is an example, analogous to that from
129
132
// `compare_impl_method`.
@@ -350,7 +353,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
350
353
cx : & mut DropckContext < ' a , ' b , ' gcx , ' tcx > ,
351
354
context : TypeContext ,
352
355
ty : Ty < ' tcx > ,
353
- depth : usize ) -> Result < ( ) , Error < ' tcx > >
356
+ depth : usize )
357
+ -> Result < ( ) , Error < ' tcx > >
354
358
{
355
359
let tcx = cx. rcx . tcx ;
356
360
// Issue #22443: Watch out for overflow. While we are careful to
@@ -402,16 +406,27 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
402
406
// unbounded type parameter `T`, we must resume the recursive
403
407
// analysis on `T` (since it would be ignored by
404
408
// type_must_outlive).
405
- if has_dtor_of_interest ( tcx, ty) {
406
- debug ! ( "iterate_over_potentially_unsafe_regions_in_type \
407
- {}ty: {} - is a dtorck type!",
408
- ( 0 ..depth) . map( |_| ' ' ) . collect:: <String >( ) ,
409
- ty) ;
410
-
411
- cx. rcx . type_must_outlive ( infer:: SubregionOrigin :: SafeDestructor ( cx. span ) ,
412
- ty, tcx. mk_region ( ty:: ReScope ( cx. parent_scope ) ) ) ;
413
-
414
- return Ok ( ( ) ) ;
409
+ let dropck_kind = has_dtor_of_interest ( tcx, ty) ;
410
+ debug ! ( "iterate_over_potentially_unsafe_regions_in_type \
411
+ ty: {:?} dropck_kind: {:?}", ty, dropck_kind) ;
412
+ match dropck_kind {
413
+ DropckKind :: NoBorrowedDataAccessedInMyDtor => {
414
+ // The maximally blind attribute.
415
+ }
416
+ DropckKind :: BorrowedDataMustStrictlyOutliveSelf => {
417
+ cx. rcx . type_must_outlive ( infer:: SubregionOrigin :: SafeDestructor ( cx. span ) ,
418
+ ty, tcx. mk_region ( ty:: ReScope ( cx. parent_scope ) ) ) ;
419
+ return Ok ( ( ) ) ;
420
+ }
421
+ DropckKind :: RevisedSelf ( revised_ty) => {
422
+ cx. rcx . type_must_outlive ( infer:: SubregionOrigin :: SafeDestructor ( cx. span ) ,
423
+ revised_ty, tcx. mk_region ( ty:: ReScope ( cx. parent_scope ) ) ) ;
424
+ // Do not return early from this case; we want
425
+ // to recursively process the internal structure of Self
426
+ // (because even though the Drop for Self has been asserted
427
+ // safe, the types instantiated for the generics of Self
428
+ // may themselves carry dropck constraints.)
429
+ }
415
430
}
416
431
417
432
debug ! ( "iterate_over_potentially_unsafe_regions_in_type \
@@ -492,16 +507,140 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
492
507
}
493
508
}
494
509
510
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
511
+ enum DropckKind < ' tcx > {
512
+ /// The "safe" kind; i.e. conservatively assume any borrow
513
+ /// accessed by dtor, and therefore such data must strictly
514
+ /// outlive self.
515
+ ///
516
+ /// Equivalent to RevisedTy with no change to the self type.
517
+ BorrowedDataMustStrictlyOutliveSelf ,
518
+
519
+ /// The nearly completely-unsafe kind.
520
+ ///
521
+ /// Equivalent to RevisedSelf with *all* parameters remapped to ()
522
+ /// (maybe...?)
523
+ NoBorrowedDataAccessedInMyDtor ,
524
+
525
+ /// Assume all borrowed data access by dtor occurs as if Self has the
526
+ /// type carried by this variant. In practice this means that some
527
+ /// of the type parameters are remapped to `()` (and some lifetime
528
+ /// parameters remapped to `'static`), because the developer has asserted
529
+ /// that the destructor will not access their contents.
530
+ RevisedSelf ( Ty < ' tcx > ) ,
531
+ }
532
+
533
+ /// Returns the classification of what kind of check should be applied
534
+ /// to `ty`, which may include a revised type where some of the type
535
+ /// parameters are re-mapped to `()` to reflect the destructor's
536
+ /// "purity" with respect to their actual contents.
495
537
fn has_dtor_of_interest < ' a , ' gcx , ' tcx > ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
496
- ty : Ty < ' tcx > ) -> bool {
538
+ ty : Ty < ' tcx > )
539
+ -> DropckKind < ' tcx > {
497
540
match ty. sty {
498
- ty:: TyAdt ( def, _) => {
499
- def. is_dtorck ( tcx)
541
+ ty:: TyAdt ( adt_def, substs) => {
542
+ if !adt_def. is_dtorck ( tcx) {
543
+ return DropckKind :: NoBorrowedDataAccessedInMyDtor ;
544
+ }
545
+
546
+ // Find the `impl<..> Drop for _` to inspect any
547
+ // attributes attached to the impl's generics.
548
+ let dtor_method = adt_def. destructor ( )
549
+ . expect ( "dtorck type without destructor impossible" ) ;
550
+ let method = tcx. impl_or_trait_item ( dtor_method) ;
551
+ let impl_id: DefId = method. container ( ) . id ( ) ;
552
+ let revised_ty = revise_self_ty ( tcx, adt_def, impl_id, substs) ;
553
+ return DropckKind :: RevisedSelf ( revised_ty) ;
500
554
}
501
555
ty:: TyTrait ( ..) | ty:: TyProjection ( ..) | ty:: TyAnon ( ..) => {
502
556
debug ! ( "ty: {:?} isn't known, and therefore is a dropck type" , ty) ;
503
- true
557
+ return DropckKind :: BorrowedDataMustStrictlyOutliveSelf ;
504
558
} ,
505
- _ => false
559
+ _ => {
560
+ return DropckKind :: NoBorrowedDataAccessedInMyDtor ;
561
+ }
506
562
}
507
563
}
564
+
565
+ // Constructs new Ty just like the type defined by `adt_def` coupled
566
+ // with `substs`, except each type and lifetime parameter marked as
567
+ // `#[may_dangle]` in the Drop impl (identified by `impl_id`) is
568
+ // respectively mapped to `()` or `'static`.
569
+ //
570
+ // For example: If the `adt_def` maps to:
571
+ //
572
+ // enum Foo<'a, X, Y> { ... }
573
+ //
574
+ // and the `impl_id` maps to:
575
+ //
576
+ // impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... }
577
+ //
578
+ // then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>`
579
+ fn revise_self_ty < ' a , ' gcx , ' tcx > ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
580
+ adt_def : ty:: AdtDef < ' tcx > ,
581
+ impl_id : DefId ,
582
+ substs : & Substs < ' tcx > )
583
+ -> Ty < ' tcx > {
584
+ // Get generics for `impl Drop` to query for `#[may_dangle]` attr.
585
+ let impl_bindings = tcx. lookup_generics ( impl_id) ;
586
+
587
+ // Get Substs attached to Self on `impl Drop`; process in parallel
588
+ // with `substs`, replacing dangling entries as appropriate.
589
+ let self_substs = {
590
+ let impl_self_ty: Ty < ' tcx > = tcx. lookup_item_type ( impl_id) . ty ;
591
+ if let ty:: TyAdt ( self_adt_def, self_substs) = impl_self_ty. sty {
592
+ assert_eq ! ( adt_def, self_adt_def) ;
593
+ self_substs
594
+ } else {
595
+ bug ! ( "Self in `impl Drop for _` must be an Adt." ) ;
596
+ }
597
+ } ;
598
+
599
+ // Walk `substs` + `self_substs`, build new substs appropriate for
600
+ // `adt_def`; each non-dangling param reuses entry from `substs`.
601
+ //
602
+ // Note: The manner we map from a right-hand side (i.e. Region or
603
+ // Ty) for a given `def` to generic parameter associated with that
604
+ // right-hand side is tightly coupled to `Drop` impl constraints.
605
+ //
606
+ // E.g. we know such a Ty must be `TyParam`, because a destructor
607
+ // for `struct Foo<X>` is defined via `impl<Y> Drop for Foo<Y>`,
608
+ // and never by (for example) `impl<Z> Drop for Foo<Vec<Z>>`.
609
+ let substs = Substs :: for_item (
610
+ tcx,
611
+ adt_def. did ,
612
+ |def, _| {
613
+ let r_orig = substs. region_for_def ( def) ;
614
+ let impl_self_orig = self_substs. region_for_def ( def) ;
615
+ let r = if let ty:: Region :: ReEarlyBound ( ref ebr) = * impl_self_orig {
616
+ if impl_bindings. region_param ( ebr) . pure_wrt_drop {
617
+ tcx. mk_region ( ty:: ReStatic )
618
+ } else {
619
+ r_orig
620
+ }
621
+ } else {
622
+ bug ! ( "substs for an impl must map regions to ReEarlyBound" ) ;
623
+ } ;
624
+ debug ! ( "has_dtor_of_interest mapping def {:?} orig {:?} to {:?}" ,
625
+ def, r_orig, r) ;
626
+ r
627
+ } ,
628
+ |def, _| {
629
+ let t_orig = substs. type_for_def ( def) ;
630
+ let impl_self_orig = self_substs. type_for_def ( def) ;
631
+ let t = if let ty:: TypeVariants :: TyParam ( ref pt) = impl_self_orig. sty {
632
+ if impl_bindings. type_param ( pt) . pure_wrt_drop {
633
+ tcx. mk_nil ( )
634
+ } else {
635
+ t_orig
636
+ }
637
+ } else {
638
+ bug ! ( "substs for an impl must map types to TyParam" ) ;
639
+ } ;
640
+ debug ! ( "has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}" ,
641
+ def, t_orig, t_orig. sty, t, t. sty) ;
642
+ t
643
+ } ) ;
644
+
645
+ return tcx. mk_adt ( adt_def, & substs) ;
646
+ }
0 commit comments