Skip to content

Commit 6fbca25

Browse files
authored
Rollup merge of #136888 - compiler-errors:never-read, r=Nadrieril
Always perform discr read for never pattern in EUV Always perform a read of `!` discriminants to ensure that it's captured by closures in expr use visitor Fixes #136852 r? Nadrieril or reassign
2 parents f7d5285 + 5a76304 commit 6fbca25

File tree

3 files changed

+82
-47
lines changed

3 files changed

+82
-47
lines changed

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+62-44
Original file line numberDiff line numberDiff line change
@@ -892,57 +892,75 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
892892

893893
let tcx = self.cx.tcx();
894894
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
895-
if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
896-
debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
897-
if let Some(bm) =
898-
self.cx.typeck_results().extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
899-
{
900-
debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
901-
902-
// pat_ty: the type of the binding being produced.
903-
let pat_ty = self.node_ty(pat.hir_id)?;
904-
debug!("walk_pat: pat_ty={:?}", pat_ty);
895+
match pat.kind {
896+
PatKind::Binding(_, canonical_id, ..) => {
897+
debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
898+
if let Some(bm) = self
899+
.cx
900+
.typeck_results()
901+
.extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
902+
{
903+
debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
905904

906-
let def = Res::Local(canonical_id);
907-
if let Ok(ref binding_place) = self.cat_res(pat.hir_id, pat.span, pat_ty, def) {
908-
self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id);
909-
}
905+
// pat_ty: the type of the binding being produced.
906+
let pat_ty = self.node_ty(pat.hir_id)?;
907+
debug!("walk_pat: pat_ty={:?}", pat_ty);
910908

911-
// Subtle: MIR desugaring introduces immutable borrows for each pattern
912-
// binding when lowering pattern guards to ensure that the guard does not
913-
// modify the scrutinee.
914-
if has_guard {
915-
self.delegate.borrow_mut().borrow(
916-
place,
917-
discr_place.hir_id,
918-
BorrowKind::Immutable,
919-
);
920-
}
909+
let def = Res::Local(canonical_id);
910+
if let Ok(ref binding_place) =
911+
self.cat_res(pat.hir_id, pat.span, pat_ty, def)
912+
{
913+
self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id);
914+
}
921915

922-
// It is also a borrow or copy/move of the value being matched.
923-
// In a cases of pattern like `let pat = upvar`, don't use the span
924-
// of the pattern, as this just looks confusing, instead use the span
925-
// of the discriminant.
926-
match bm.0 {
927-
hir::ByRef::Yes(m) => {
928-
let bk = ty::BorrowKind::from_mutbl(m);
929-
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
916+
// Subtle: MIR desugaring introduces immutable borrows for each pattern
917+
// binding when lowering pattern guards to ensure that the guard does not
918+
// modify the scrutinee.
919+
if has_guard {
920+
self.delegate.borrow_mut().borrow(
921+
place,
922+
discr_place.hir_id,
923+
BorrowKind::Immutable,
924+
);
930925
}
931-
hir::ByRef::No => {
932-
debug!("walk_pat binding consuming pat");
933-
self.consume_or_copy(place, discr_place.hir_id);
926+
927+
// It is also a borrow or copy/move of the value being matched.
928+
// In a cases of pattern like `let pat = upvar`, don't use the span
929+
// of the pattern, as this just looks confusing, instead use the span
930+
// of the discriminant.
931+
match bm.0 {
932+
hir::ByRef::Yes(m) => {
933+
let bk = ty::BorrowKind::from_mutbl(m);
934+
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
935+
}
936+
hir::ByRef::No => {
937+
debug!("walk_pat binding consuming pat");
938+
self.consume_or_copy(place, discr_place.hir_id);
939+
}
934940
}
935941
}
936942
}
937-
} else if let PatKind::Deref(subpattern) = pat.kind {
938-
// A deref pattern is a bit special: the binding mode of its inner bindings
939-
// determines whether to borrow *at the level of the deref pattern* rather than
940-
// borrowing the bound place (since that inner place is inside the temporary that
941-
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
942-
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
943-
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
944-
let bk = ty::BorrowKind::from_mutbl(mutability);
945-
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
943+
PatKind::Deref(subpattern) => {
944+
// A deref pattern is a bit special: the binding mode of its inner bindings
945+
// determines whether to borrow *at the level of the deref pattern* rather than
946+
// borrowing the bound place (since that inner place is inside the temporary that
947+
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
948+
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
949+
let mutability =
950+
if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
951+
let bk = ty::BorrowKind::from_mutbl(mutability);
952+
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
953+
}
954+
PatKind::Never => {
955+
// A `!` pattern always counts as an immutable read of the discriminant,
956+
// even in an irrefutable pattern.
957+
self.delegate.borrow_mut().borrow(
958+
place,
959+
discr_place.hir_id,
960+
BorrowKind::Immutable,
961+
);
962+
}
963+
_ => {}
946964
}
947965

948966
Ok(())

compiler/rustc_hir_typeck/src/upvar.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1991,17 +1991,18 @@ struct InferBorrowKind<'tcx> {
19911991
impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
19921992
fn fake_read(
19931993
&mut self,
1994-
place: &PlaceWithHirId<'tcx>,
1994+
place_with_id: &PlaceWithHirId<'tcx>,
19951995
cause: FakeReadCause,
19961996
diag_expr_id: HirId,
19971997
) {
1998-
let PlaceBase::Upvar(_) = place.place.base else { return };
1998+
let PlaceBase::Upvar(_) = place_with_id.place.base else { return };
19991999

20002000
// We need to restrict Fake Read precision to avoid fake reading unsafe code,
20012001
// such as deref of a raw pointer.
20022002
let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::Immutable);
20032003

2004-
let (place, _) = restrict_capture_precision(place.place.clone(), dummy_capture_kind);
2004+
let (place, _) =
2005+
restrict_capture_precision(place_with_id.place.clone(), dummy_capture_kind);
20052006

20062007
let (place, _) = restrict_repr_packed_field_ref_capture(place, dummy_capture_kind);
20072008
self.fake_reads.push((place, cause, diag_expr_id));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@ check-pass
2+
3+
// Make sure that the closure captures `s` so it can perform a read of `s`.
4+
5+
#![feature(never_patterns)]
6+
#![allow(incomplete_features)]
7+
8+
enum Void {}
9+
10+
fn by_value(s: Void) {
11+
move || {
12+
let ! = s;
13+
};
14+
}
15+
16+
fn main() {}

0 commit comments

Comments
 (0)