diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 591c2fc5a8145..470405babb379 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert_eq!(body_owner_def_id.to_def_id(), closure_def_id); let mut delegate = InferBorrowKind { fcx: self, - closure_def_id, + closure_def_id: local_def_id, capture_information: Default::default(), fake_reads: Default::default(), }; @@ -1648,7 +1648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn restrict_repr_packed_field_ref_capture<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - place: &Place<'tcx>, + mut place: Place<'tcx>, mut curr_borrow_kind: ty::UpvarCapture, ) -> (Place<'tcx>, ty::UpvarCapture) { let pos = place.projections.iter().enumerate().position(|(i, p)| { @@ -1681,8 +1681,6 @@ fn restrict_repr_packed_field_ref_capture<'tcx>( } }); - let mut place = place.clone(); - if let Some(pos) = pos { truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_borrow_kind, pos); } @@ -1729,7 +1727,7 @@ struct InferBorrowKind<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, // The def-id of the closure whose kind and upvar accesses are being inferred. - closure_def_id: DefId, + closure_def_id: LocalDefId, /// For each Place that is captured by the closure, we track the minimal kind of /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access. @@ -1762,170 +1760,51 @@ struct InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { - #[instrument(skip(self), level = "debug")] - fn adjust_upvar_borrow_kind_for_consume( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - ) { - let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { - return; - }; - - debug!(?upvar_id); - - let capture_info = ty::CaptureInfo { - capture_kind_expr_id: Some(diag_expr_id), - path_expr_id: Some(diag_expr_id), - capture_kind: ty::UpvarCapture::ByValue, - }; - - let curr_info = self.capture_information[&place_with_id.place]; - let updated_info = determine_capture_info(curr_info, capture_info); - - self.capture_information[&place_with_id.place] = updated_info; - } - - /// Indicates that `place_with_id` is being directly mutated (e.g., assigned - /// to). If the place is based on a by-ref upvar, this implies that - /// the upvar must be borrowed using an `&mut` borrow. - #[instrument(skip(self), level = "debug")] - fn adjust_upvar_borrow_kind_for_mut( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - ) { - if let PlaceBase::Upvar(_) = place_with_id.place.base { - // Raw pointers don't inherit mutability - if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { - return; + fn adjust_capture_info(&mut self, place: Place<'tcx>, capture_info: ty::CaptureInfo) { + match self.capture_information.get_mut(&place) { + Some(curr_info) => { + *curr_info = determine_capture_info(*curr_info, capture_info); } - self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::MutBorrow); - } - } - - #[instrument(skip(self), level = "debug")] - fn adjust_upvar_borrow_kind_for_unique( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - ) { - if let PlaceBase::Upvar(_) = place_with_id.place.base { - if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { - // Raw pointers don't inherit mutability. - return; + None => { + debug!("Capturing new place {:?}, capture_info={:?}", place, capture_info); + self.capture_information.insert(place, capture_info); } - // for a borrowed pointer to be unique, its base must be unique - self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::UniqueImmBorrow); - } - } - - fn adjust_upvar_deref( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - borrow_kind: ty::BorrowKind, - ) { - assert!(match borrow_kind { - ty::MutBorrow => true, - ty::UniqueImmBorrow => true, - - // imm borrows never require adjusting any kinds, so we don't wind up here - ty::ImmBorrow => false, - }); - - // if this is an implicit deref of an - // upvar, then we need to modify the - // borrow_kind of the upvar to make sure it - // is inferred to mutable if necessary - self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind); - } - - /// We infer the borrow_kind with which to borrow upvars in a stack closure. - /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`, - /// moving from left to right as needed (but never right to left). - /// Here the argument `mutbl` is the borrow_kind that is required by - /// some particular use. - #[instrument(skip(self), level = "debug")] - fn adjust_upvar_borrow_kind( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - kind: ty::BorrowKind, - ) { - let curr_capture_info = self.capture_information[&place_with_id.place]; - - debug!(?curr_capture_info); - - if let ty::UpvarCapture::ByValue = curr_capture_info.capture_kind { - // It's already captured by value, we don't need to do anything here - return; - } else if let ty::UpvarCapture::ByRef(_) = curr_capture_info.capture_kind { - let capture_info = ty::CaptureInfo { - capture_kind_expr_id: Some(diag_expr_id), - path_expr_id: Some(diag_expr_id), - capture_kind: ty::UpvarCapture::ByRef(kind), - }; - let updated_info = determine_capture_info(curr_capture_info, capture_info); - self.capture_information[&place_with_id.place] = updated_info; - }; - } - - #[instrument(skip(self, diag_expr_id), level = "debug")] - fn init_capture_info_for_place( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - ) { - if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { - assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id); - - // Initialize to ImmBorrow - // We will escalate the CaptureKind based on any uses we see or in `process_collected_capture_information`. - let capture_kind = ty::UpvarCapture::ByRef(ty::ImmBorrow); - - let expr_id = Some(diag_expr_id); - let capture_info = ty::CaptureInfo { - capture_kind_expr_id: expr_id, - path_expr_id: expr_id, - capture_kind, - }; - - debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info); - - self.capture_information.insert(place_with_id.place.clone(), capture_info); - } else { - debug!("Not upvar"); } } } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) { - if let PlaceBase::Upvar(_) = place.base { - // We need to restrict Fake Read precision to avoid fake reading unsafe code, - // such as deref of a raw pointer. - let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); - - let (place, _) = restrict_capture_precision(place, dummy_capture_kind); - - let (place, _) = restrict_repr_packed_field_ref_capture( - self.fcx.tcx, - self.fcx.param_env, - &place, - dummy_capture_kind, - ); - self.fake_reads.push((place, cause, diag_expr_id)); - } + let PlaceBase::Upvar(_) = place.base else { return }; + + // We need to restrict Fake Read precision to avoid fake reading unsafe code, + // such as deref of a raw pointer. + let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); + + let (place, _) = restrict_capture_precision(place, dummy_capture_kind); + + let (place, _) = restrict_repr_packed_field_ref_capture( + self.fcx.tcx, + self.fcx.param_env, + place, + dummy_capture_kind, + ); + self.fake_reads.push((place, cause, diag_expr_id)); } #[instrument(skip(self), level = "debug")] fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { - if !self.capture_information.contains_key(&place_with_id.place) { - self.init_capture_info_for_place(place_with_id, diag_expr_id); - } + let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return }; + assert_eq!(self.closure_def_id, upvar_id.closure_expr_id); - self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id); + self.adjust_capture_info( + place_with_id.place.clone(), + ty::CaptureInfo { + capture_kind_expr_id: Some(diag_expr_id), + path_expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByValue, + }, + ); } #[instrument(skip(self), level = "debug")] @@ -1935,39 +1814,35 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { diag_expr_id: hir::HirId, bk: ty::BorrowKind, ) { + let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return }; + assert_eq!(self.closure_def_id, upvar_id.closure_expr_id); + // The region here will get discarded/ignored - let dummy_capture_kind = ty::UpvarCapture::ByRef(bk); + let capture_kind = ty::UpvarCapture::ByRef(bk); // We only want repr packed restriction to be applied to reading references into a packed // struct, and not when the data is being moved. Therefore we call this method here instead // of in `restrict_capture_precision`. - let (place, updated_kind) = restrict_repr_packed_field_ref_capture( + let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture( self.fcx.tcx, self.fcx.param_env, - &place_with_id.place, - dummy_capture_kind, + place_with_id.place.clone(), + capture_kind, ); - let place_with_id = PlaceWithHirId { place, ..*place_with_id }; - - if !self.capture_information.contains_key(&place_with_id.place) { - self.init_capture_info_for_place(&place_with_id, diag_expr_id); + // Raw pointers don't inherit mutability + if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { + capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); } - match updated_kind { - ty::UpvarCapture::ByRef(kind) => match kind { - ty::ImmBorrow => {} - ty::UniqueImmBorrow => { - self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id); - } - ty::MutBorrow => { - self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id); - } + self.adjust_capture_info( + place, + ty::CaptureInfo { + capture_kind_expr_id: Some(diag_expr_id), + path_expr_id: Some(diag_expr_id), + capture_kind, }, - - // Just truncating the place will never cause capture kind to be updated to ByValue - ty::UpvarCapture::ByValue => unreachable!(), - } + ); } #[instrument(skip(self), level = "debug")]