InferBorrowKind cleanup
`adjust_upvar_deref` and friends are implemented so that they reuse existing region so new region vars don't have to be generated. Since now we don't have to generate region vars in `InferBorrowKind`, creating a new capture info would be cheap and we can just use `determine_capture_info`. syn is updated so that let_else syntax can be used in fn with `#[instrument]` attribute. `restrict_repr_packed_field_ref_capture` is changed to take place by value since cloning is needed anyway.
This commit is contained in:
parent
48258ffe5a
commit
52db6b9d02
1 changed files with 50 additions and 175 deletions
|
@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
assert_eq!(body_owner_def_id.to_def_id(), closure_def_id);
|
assert_eq!(body_owner_def_id.to_def_id(), closure_def_id);
|
||||||
let mut delegate = InferBorrowKind {
|
let mut delegate = InferBorrowKind {
|
||||||
fcx: self,
|
fcx: self,
|
||||||
closure_def_id,
|
closure_def_id: local_def_id,
|
||||||
capture_information: Default::default(),
|
capture_information: Default::default(),
|
||||||
fake_reads: Default::default(),
|
fake_reads: Default::default(),
|
||||||
};
|
};
|
||||||
|
@ -1648,7 +1648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn restrict_repr_packed_field_ref_capture<'tcx>(
|
fn restrict_repr_packed_field_ref_capture<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
place: &Place<'tcx>,
|
mut place: Place<'tcx>,
|
||||||
mut curr_borrow_kind: ty::UpvarCapture,
|
mut curr_borrow_kind: ty::UpvarCapture,
|
||||||
) -> (Place<'tcx>, ty::UpvarCapture) {
|
) -> (Place<'tcx>, ty::UpvarCapture) {
|
||||||
let pos = place.projections.iter().enumerate().position(|(i, p)| {
|
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 {
|
if let Some(pos) = pos {
|
||||||
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_borrow_kind, 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>,
|
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||||
|
|
||||||
// The def-id of the closure whose kind and upvar accesses are being inferred.
|
// 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
|
/// 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.
|
/// 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> {
|
impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
|
||||||
#[instrument(skip(self), level = "debug")]
|
fn adjust_capture_info(&mut self, place: Place<'tcx>, capture_info: ty::CaptureInfo) {
|
||||||
fn adjust_upvar_borrow_kind_for_consume(
|
match self.capture_information.get_mut(&place) {
|
||||||
&mut self,
|
Some(curr_info) => {
|
||||||
place_with_id: &PlaceWithHirId<'tcx>,
|
*curr_info = determine_capture_info(*curr_info, capture_info);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::MutBorrow);
|
None => {
|
||||||
}
|
debug!("Capturing new place {:?}, capture_info={:?}", place, capture_info);
|
||||||
}
|
self.capture_information.insert(place, capture_info);
|
||||||
|
|
||||||
#[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;
|
|
||||||
}
|
}
|
||||||
// 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> {
|
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) {
|
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
|
||||||
if let PlaceBase::Upvar(_) = place.base {
|
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);
|
// 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_repr_packed_field_ref_capture(
|
let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
|
||||||
self.fcx.tcx,
|
|
||||||
self.fcx.param_env,
|
let (place, _) = restrict_repr_packed_field_ref_capture(
|
||||||
&place,
|
self.fcx.tcx,
|
||||||
dummy_capture_kind,
|
self.fcx.param_env,
|
||||||
);
|
place,
|
||||||
self.fake_reads.push((place, cause, diag_expr_id));
|
dummy_capture_kind,
|
||||||
}
|
);
|
||||||
|
self.fake_reads.push((place, cause, diag_expr_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
|
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
|
||||||
if !self.capture_information.contains_key(&place_with_id.place) {
|
let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
|
||||||
self.init_capture_info_for_place(place_with_id, diag_expr_id);
|
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")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
@ -1935,39 +1814,35 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
|
||||||
diag_expr_id: hir::HirId,
|
diag_expr_id: hir::HirId,
|
||||||
bk: ty::BorrowKind,
|
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
|
// 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
|
// 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
|
// struct, and not when the data is being moved. Therefore we call this method here instead
|
||||||
// of in `restrict_capture_precision`.
|
// 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.tcx,
|
||||||
self.fcx.param_env,
|
self.fcx.param_env,
|
||||||
&place_with_id.place,
|
place_with_id.place.clone(),
|
||||||
dummy_capture_kind,
|
capture_kind,
|
||||||
);
|
);
|
||||||
|
|
||||||
let place_with_id = PlaceWithHirId { place, ..*place_with_id };
|
// Raw pointers don't inherit mutability
|
||||||
|
if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
|
||||||
if !self.capture_information.contains_key(&place_with_id.place) {
|
capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
|
||||||
self.init_capture_info_for_place(&place_with_id, diag_expr_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match updated_kind {
|
self.adjust_capture_info(
|
||||||
ty::UpvarCapture::ByRef(kind) => match kind {
|
place,
|
||||||
ty::ImmBorrow => {}
|
ty::CaptureInfo {
|
||||||
ty::UniqueImmBorrow => {
|
capture_kind_expr_id: Some(diag_expr_id),
|
||||||
self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id);
|
path_expr_id: Some(diag_expr_id),
|
||||||
}
|
capture_kind,
|
||||||
ty::MutBorrow => {
|
|
||||||
self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
);
|
||||||
// Just truncating the place will never cause capture kind to be updated to ByValue
|
|
||||||
ty::UpvarCapture::ByValue => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue