1
Fork 0
This commit is contained in:
Michael Goulet 2025-02-11 21:05:52 +00:00
parent ffefb13443
commit 5a76304db6
2 changed files with 67 additions and 52 deletions

View file

@ -892,61 +892,75 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
let tcx = self.cx.tcx(); let tcx = self.cx.tcx();
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| { self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
if let PatKind::Binding(_, canonical_id, ..) = pat.kind { match pat.kind {
debug!("walk_pat: binding place={:?} pat={:?}", place, pat); PatKind::Binding(_, canonical_id, ..) => {
if let Some(bm) = debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
self.cx.typeck_results().extract_binding_mode(tcx.sess, pat.hir_id, pat.span) if let Some(bm) = self
{ .cx
debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); .typeck_results()
.extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
{
debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
// pat_ty: the type of the binding being produced. // pat_ty: the type of the binding being produced.
let pat_ty = self.node_ty(pat.hir_id)?; let pat_ty = self.node_ty(pat.hir_id)?;
debug!("walk_pat: pat_ty={:?}", pat_ty); debug!("walk_pat: pat_ty={:?}", pat_ty);
let def = Res::Local(canonical_id); let def = Res::Local(canonical_id);
if let Ok(ref binding_place) = self.cat_res(pat.hir_id, pat.span, pat_ty, def) { if let Ok(ref binding_place) =
self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id); self.cat_res(pat.hir_id, pat.span, pat_ty, def)
} {
self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id);
// Subtle: MIR desugaring introduces immutable borrows for each pattern
// binding when lowering pattern guards to ensure that the guard does not
// modify the scrutinee.
if has_guard {
self.delegate.borrow_mut().borrow(
place,
discr_place.hir_id,
BorrowKind::Immutable,
);
}
// It is also a borrow or copy/move of the value being matched.
// In a cases of pattern like `let pat = upvar`, don't use the span
// of the pattern, as this just looks confusing, instead use the span
// of the discriminant.
match bm.0 {
hir::ByRef::Yes(m) => {
let bk = ty::BorrowKind::from_mutbl(m);
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
} }
hir::ByRef::No => {
debug!("walk_pat binding consuming pat"); // Subtle: MIR desugaring introduces immutable borrows for each pattern
self.consume_or_copy(place, discr_place.hir_id); // binding when lowering pattern guards to ensure that the guard does not
// modify the scrutinee.
if has_guard {
self.delegate.borrow_mut().borrow(
place,
discr_place.hir_id,
BorrowKind::Immutable,
);
}
// It is also a borrow or copy/move of the value being matched.
// In a cases of pattern like `let pat = upvar`, don't use the span
// of the pattern, as this just looks confusing, instead use the span
// of the discriminant.
match bm.0 {
hir::ByRef::Yes(m) => {
let bk = ty::BorrowKind::from_mutbl(m);
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
}
hir::ByRef::No => {
debug!("walk_pat binding consuming pat");
self.consume_or_copy(place, discr_place.hir_id);
}
} }
} }
} }
} else if let PatKind::Deref(subpattern) = pat.kind { PatKind::Deref(subpattern) => {
// A deref pattern is a bit special: the binding mode of its inner bindings // A deref pattern is a bit special: the binding mode of its inner bindings
// determines whether to borrow *at the level of the deref pattern* rather than // determines whether to borrow *at the level of the deref pattern* rather than
// borrowing the bound place (since that inner place is inside the temporary that // borrowing the bound place (since that inner place is inside the temporary that
// stores the result of calling `deref()`/`deref_mut()` so can't be captured). // stores the result of calling `deref()`/`deref_mut()` so can't be captured).
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern); let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; let mutability =
let bk = ty::BorrowKind::from_mutbl(mutability); if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk); let bk = ty::BorrowKind::from_mutbl(mutability);
} else if let PatKind::Never = pat.kind { self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
// A `!` pattern always counts as an immutable read of the discriminant, }
// even in an irrefutable pattern. PatKind::Never => {
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, BorrowKind::Immutable); // A `!` pattern always counts as an immutable read of the discriminant,
// even in an irrefutable pattern.
self.delegate.borrow_mut().borrow(
place,
discr_place.hir_id,
BorrowKind::Immutable,
);
}
_ => {}
} }
Ok(()) Ok(())

View file

@ -1991,17 +1991,18 @@ struct InferBorrowKind<'tcx> {
impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
fn fake_read( fn fake_read(
&mut self, &mut self,
place: &PlaceWithHirId<'tcx>, place_with_id: &PlaceWithHirId<'tcx>,
cause: FakeReadCause, cause: FakeReadCause,
diag_expr_id: HirId, diag_expr_id: HirId,
) { ) {
let PlaceBase::Upvar(_) = place.place.base else { return }; let PlaceBase::Upvar(_) = place_with_id.place.base else { return };
// We need to restrict Fake Read precision to avoid fake reading unsafe code, // We need to restrict Fake Read precision to avoid fake reading unsafe code,
// such as deref of a raw pointer. // such as deref of a raw pointer.
let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::Immutable); let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::Immutable);
let (place, _) = restrict_capture_precision(place.place.clone(), dummy_capture_kind); let (place, _) =
restrict_capture_precision(place_with_id.place.clone(), dummy_capture_kind);
let (place, _) = restrict_repr_packed_field_ref_capture(place, dummy_capture_kind); let (place, _) = restrict_repr_packed_field_ref_capture(place, dummy_capture_kind);
self.fake_reads.push((place, cause, diag_expr_id)); self.fake_reads.push((place, cause, diag_expr_id));