about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorAman Arora <me@aman-arora.com>2021-09-01 03:00:50 -0400
committerAman Arora <me@aman-arora.com>2021-09-03 04:38:28 -0400
commit153aa71c14d39ee1cb7f989d89b1f2891fdfcb6d (patch)
tree7fccf522968f7d872775dfaa79f549fe30f698b2 /compiler
parentc2a408840ad18f74280805535f0b7193528ff3df (diff)
downloadrust-153aa71c14d39ee1cb7f989d89b1f2891fdfcb6d.tar.gz
rust-153aa71c14d39ee1cb7f989d89b1f2891fdfcb6d.zip
2229: Don't move out of drop type
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs34
1 files changed, 33 insertions, 1 deletions
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index a25d0f80644..2758b23a762 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -399,7 +399,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             };
 
+            // This restriction needs to be applied after we have handled adjustments for `move`
+            // closures. We want to make sure any adjustment that might make us move the place into
+            // the closure gets handled.
+            let (place, capture_kind) =
+                restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
+
             capture_info.capture_kind = capture_kind;
+
             let capture_info = if let Some(existing) = processed.get(&place) {
                 determine_capture_info(*existing, capture_info)
             } else {
@@ -626,7 +633,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.tcx.struct_span_lint_hir(
                 lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
                 closure_hir_id,
-                closure_head_span,
+                 closure_head_span,
                 |lint| {
                     let mut diagnostics_builder = lint.build(
                         format!(
@@ -1835,6 +1842,31 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
         self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow);
     }
 }
+
+/// Rust doesn't permit moving fields out of a type that implements drop
+fn restrict_precision_for_drop_types<'a, 'tcx>(
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    mut place: Place<'tcx>,
+    mut curr_mode: ty::UpvarCapture<'tcx>,
+    span: Span,
+) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span);
+
+    if let (false, UpvarCapture::ByValue(..)) = (is_copy_type, curr_mode) {
+        for i in 0..place.projections.len() {
+            match place.ty_before_projection(i).kind() {
+                ty::Adt(def, _) if def.destructor(fcx.tcx).is_some() => {
+                    truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i);
+                    break;
+                }
+                _ => {}
+            }
+        }
+    }
+
+    (place, curr_mode)
+}
+
 /// Truncate `place` so that an `unsafe` block isn't required to capture it.
 /// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
 ///   them completely.