diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2018-02-05 14:49:27 -0500 |
|---|---|---|
| committer | David Wood <david@davidtw.co> | 2018-02-14 18:17:54 +0000 |
| commit | 552024a52eb17b2542e87f9fc97b7b643707d759 (patch) | |
| tree | 4b5932b3eb0947c61bad5e9958640d49c2f1f165 | |
| parent | 5fd64dde2198971df0869cbf4944d3996395b826 (diff) | |
| download | rust-552024a52eb17b2542e87f9fc97b7b643707d759.tar.gz rust-552024a52eb17b2542e87f9fc97b7b643707d759.zip | |
check that types "need drop" before we access them
Also, add some comments and remove extra deref.
| -rw-r--r-- | src/librustc_mir/borrow_check/mod.rs | 40 |
1 files changed, 28 insertions, 12 deletions
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 46f94f2388f..3cdfe640006 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -711,6 +711,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) } + /// Invokes `access_place` as appropriate for dropping the value + /// at `drop_place`. Note that the *actual* `Drop` in the MIR is + /// always for a variable (e.g., `Drop(x)`) -- but we recursively + /// break this variable down into subpaths (e.g., `Drop(x.foo)`) + /// to indicate more precisely which fields might actually be + /// accessed by a destructor. fn visit_terminator_drop( &mut self, loc: Location, @@ -721,15 +727,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ) { let ty = drop_place.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - // When a struct is being dropped, we need to check whether it has a - // destructor, if it does, then we can call it, if it does not then we - // need to check the individual fields instead. - // See #47703. + // When a struct is being dropped, we need to check + // whether it has a destructor, if it does, then we can + // call it, if it does not then we need to check the + // individual fields instead. This way if `foo` has a + // destructor but `bar` does not, we will only check for + // borrows of `x.foo` and not `x.bar`. See #47703. ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { for (index, field) in def.all_fields().enumerate() { let place = drop_place.clone(); let place = place.field(Field::new(index), field.ty(self.tcx, substs)); - let place = place.deref(); self.visit_terminator_drop( loc, @@ -741,13 +748,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } }, _ => { - self.access_place( - ContextKind::Drop.new(loc), - (drop_place, span), - (Deep, Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state, - ); + // We have now refined the type of the value being + // dropped (potentially) to just the type of a + // subfield; so check whether that field's type still + // "needs drop". If so, we assume that the destructor + // may access any data it likes (i.e., a Deep Write). + let gcx = self.tcx.global_tcx(); + let erased_ty = gcx.lift(&self.tcx.erase_regions(&ty)).unwrap(); + if erased_ty.needs_drop(gcx, self.param_env) { + self.access_place( + ContextKind::Drop.new(loc), + (drop_place, span), + (Deep, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); + } }, } } |
