diff options
| author | Aman Arora <me@aman-arora.com> | 2021-09-01 03:00:50 -0400 |
|---|---|---|
| committer | Aman Arora <me@aman-arora.com> | 2021-09-03 04:38:28 -0400 |
| commit | 153aa71c14d39ee1cb7f989d89b1f2891fdfcb6d (patch) | |
| tree | 7fccf522968f7d872775dfaa79f549fe30f698b2 /compiler | |
| parent | c2a408840ad18f74280805535f0b7193528ff3df (diff) | |
| download | rust-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.rs | 34 |
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. |
