@@ -711,6 +711,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
711
711
self . tcx . sess . opts . debugging_opts . two_phase_beyond_autoref )
712
712
}
713
713
714
+ /// Invokes `access_place` as appropriate for dropping the value
715
+ /// at `drop_place`. Note that the *actual* `Drop` in the MIR is
716
+ /// always for a variable (e.g., `Drop(x)`) -- but we recursively
717
+ /// break this variable down into subpaths (e.g., `Drop(x.foo)`)
718
+ /// to indicate more precisely which fields might actually be
719
+ /// accessed by a destructor.
714
720
fn visit_terminator_drop (
715
721
& mut self ,
716
722
loc : Location ,
@@ -721,15 +727,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
721
727
) {
722
728
let ty = drop_place. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
723
729
match ty. sty {
724
- // When a struct is being dropped, we need to check whether it has a
725
- // destructor, if it does, then we can call it, if it does not then we
726
- // need to check the individual fields instead.
727
- // See #47703.
730
+ // When a struct is being dropped, we need to check
731
+ // whether it has a destructor, if it does, then we can
732
+ // call it, if it does not then we need to check the
733
+ // individual fields instead. This way if `foo` has a
734
+ // destructor but `bar` does not, we will only check for
735
+ // borrows of `x.foo` and not `x.bar`. See #47703.
728
736
ty:: TyAdt ( def, substs) if def. is_struct ( ) && !def. has_dtor ( self . tcx ) => {
729
737
for ( index, field) in def. all_fields ( ) . enumerate ( ) {
730
738
let place = drop_place. clone ( ) ;
731
739
let place = place. field ( Field :: new ( index) , field. ty ( self . tcx , substs) ) ;
732
- let place = place. deref ( ) ;
733
740
734
741
self . visit_terminator_drop (
735
742
loc,
@@ -741,13 +748,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
741
748
}
742
749
} ,
743
750
_ => {
744
- self . access_place (
745
- ContextKind :: Drop . new ( loc) ,
746
- ( drop_place, span) ,
747
- ( Deep , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
748
- LocalMutationIsAllowed :: Yes ,
749
- flow_state,
750
- ) ;
751
+ // We have now refined the type of the value being
752
+ // dropped (potentially) to just the type of a
753
+ // subfield; so check whether that field's type still
754
+ // "needs drop". If so, we assume that the destructor
755
+ // may access any data it likes (i.e., a Deep Write).
756
+ let gcx = self . tcx . global_tcx ( ) ;
757
+ let erased_ty = gcx. lift ( & self . tcx . erase_regions ( & ty) ) . unwrap ( ) ;
758
+ if erased_ty. needs_drop ( gcx, self . param_env ) {
759
+ self . access_place (
760
+ ContextKind :: Drop . new ( loc) ,
761
+ ( drop_place, span) ,
762
+ ( Deep , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
763
+ LocalMutationIsAllowed :: Yes ,
764
+ flow_state,
765
+ ) ;
766
+ }
751
767
} ,
752
768
}
753
769
}
0 commit comments