diff options
Diffstat (limited to 'compiler/rustc_mir_build/src')
| -rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_place.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/matches/mod.rs | 129 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/matches/test.rs | 101 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/build/matches/util.rs | 161 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/check_unsafety.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/errors.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/mod.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/print.rs | 2 |
8 files changed, 254 insertions, 153 deletions
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index f12e25db6fc..060b328ef48 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -685,7 +685,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temp.into(), Rvalue::Ref( tcx.lifetimes.re_erased, - BorrowKind::Fake, + BorrowKind::Fake(FakeBorrowKind::Shallow), Place { local: base_place.local, projection }, ), ); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index f46dceeeedf..d36c51f4472 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -10,10 +10,7 @@ use crate::build::scope::DropKind; use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode}; -use rustc_data_structures::{ - fx::{FxHashSet, FxIndexMap, FxIndexSet}, - stack::ensure_sufficient_stack, -}; +use rustc_data_structures::{fx::FxIndexMap, stack::ensure_sufficient_stack}; use rustc_hir::{BindingMode, ByRef}; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; @@ -211,7 +208,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// 2. Create the decision tree ([Builder::lower_match_tree]). /// 3. Determine the fake borrows that are needed from the places that were /// matched against and create the required temporaries for them - /// ([Builder::calculate_fake_borrows]). + /// ([util::collect_fake_borrows]). /// 4. Create everything else: the guards and the arms ([Builder::lower_match_arms]). /// /// ## False edges @@ -380,12 +377,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_start_span: Span, match_has_guard: bool, candidates: &mut [&mut Candidate<'pat, 'tcx>], - ) -> Vec<(Place<'tcx>, Local)> { - // The set of places that we are creating fake borrows of. If there are - // no match guards then we don't need any fake borrows, so don't track - // them. - let fake_borrows = match_has_guard - .then(|| util::FakeBorrowCollector::collect_fake_borrows(self, candidates)); + ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { + // The set of places that we are creating fake borrows of. If there are no match guards then + // we don't need any fake borrows, so don't track them. + let fake_borrows: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { + util::collect_fake_borrows( + self, + candidates, + scrutinee_span, + scrutinee_place_builder.base(), + ) + } else { + Vec::new() + }; // See the doc comment on `match_candidates` for why we have an // otherwise block. Match checking will ensure this is actually @@ -439,11 +443,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); } - if let Some(ref borrows) = fake_borrows { - self.calculate_fake_borrows(borrows, scrutinee_span) - } else { - Vec::new() - } + fake_borrows } /// Lower the bindings, guards and arm bodies of a `match` expression. @@ -459,7 +459,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span: Span, arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, outer_source_info: SourceInfo, - fake_borrow_temps: Vec<(Place<'tcx>, Local)>, + fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>, ) -> BlockAnd<()> { let arm_end_blocks: Vec<_> = arm_candidates .into_iter() @@ -543,7 +543,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, outer_source_info: SourceInfo, candidate: Candidate<'_, 'tcx>, - fake_borrow_temps: &[(Place<'tcx>, Local)], + fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, storages_alive: bool, @@ -940,7 +940,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f); } - PatKind::DerefPattern { ref subpattern } => { + PatKind::DerefPattern { ref subpattern, .. } => { self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f); } @@ -1165,6 +1165,7 @@ enum TestCase<'pat, 'tcx> { Constant { value: mir::Const<'tcx> }, Range(&'pat PatRange<'tcx>), Slice { len: usize, variable_length: bool }, + Deref { temp: Place<'tcx>, mutability: Mutability }, Or { pats: Box<[FlatPat<'pat, 'tcx>]> }, } @@ -1224,6 +1225,13 @@ enum TestKind<'tcx> { /// Test that the length of the slice is equal to `len`. Len { len: u64, op: BinOp }, + + /// Call `Deref::deref[_mut]` on the value. + Deref { + /// Temporary to store the result of `deref()`/`deref_mut()`. + temp: Place<'tcx>, + mutability: Mutability, + }, } /// A test to perform to determine which [`Candidate`] matches a value. @@ -1905,81 +1913,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { target_blocks, ); } - - /// Determine the fake borrows that are needed from a set of places that - /// have to be stable across match guards. - /// - /// Returns a list of places that need a fake borrow and the temporary - /// that's used to store the fake borrow. - /// - /// Match exhaustiveness checking is not able to handle the case where the - /// place being matched on is mutated in the guards. We add "fake borrows" - /// to the guards that prevent any mutation of the place being matched. - /// There are a some subtleties: - /// - /// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared - /// reference, the borrow isn't even tracked. As such we have to add fake - /// borrows of any prefixes of a place - /// 2. We don't want `match x { _ => (), }` to conflict with mutable - /// borrows of `x`, so we only add fake borrows for places which are - /// bound or tested by the match. - /// 3. We don't want the fake borrows to conflict with `ref mut` bindings, - /// so we use a special BorrowKind for them. - /// 4. The fake borrows may be of places in inactive variants, so it would - /// be UB to generate code for them. They therefore have to be removed - /// by a MIR pass run after borrow checking. - fn calculate_fake_borrows<'b>( - &mut self, - fake_borrows: &'b FxIndexSet<Place<'tcx>>, - temp_span: Span, - ) -> Vec<(Place<'tcx>, Local)> { - let tcx = self.tcx; - - debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows); - - let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len()); - - // Insert a Shallow borrow of the prefixes of any fake borrows. - for place in fake_borrows { - let mut cursor = place.projection.as_ref(); - while let [proj_base @ .., elem] = cursor { - cursor = proj_base; - - if let ProjectionElem::Deref = elem { - // Insert a shallow borrow after a deref. For other - // projections the borrow of prefix_cursor will - // conflict with any mutation of base. - all_fake_borrows.push(PlaceRef { local: place.local, projection: proj_base }); - } - } - - all_fake_borrows.push(place.as_ref()); - } - - // Deduplicate - let mut dedup = FxHashSet::default(); - all_fake_borrows.retain(|b| dedup.insert(*b)); - - debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows); - - all_fake_borrows - .into_iter() - .map(|matched_place_ref| { - let matched_place = Place { - local: matched_place_ref.local, - projection: tcx.mk_place_elems(matched_place_ref.projection), - }; - let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; - let fake_borrow_ty = - Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty); - let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); - fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow)); - let fake_borrow_temp = self.local_decls.push(fake_borrow_temp); - - (matched_place, fake_borrow_temp) - }) - .collect() - } } /////////////////////////////////////////////////////////////////////////// @@ -2044,7 +1977,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: Candidate<'pat, 'tcx>, parent_data: &[PatternExtraData<'tcx>], - fake_borrows: &[(Place<'tcx>, Local)], + fake_borrows: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, schedule_drops: bool, @@ -2174,8 +2107,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let re_erased = tcx.lifetimes.re_erased; let scrutinee_source_info = self.source_info(scrutinee_span); - for &(place, temp) in fake_borrows { - let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake, place); + for &(place, temp, kind) in fake_borrows { + let borrow = Rvalue::Ref(re_erased, BorrowKind::Fake(kind), place); self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow); } @@ -2198,7 +2131,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let guard_frame = self.guard_context.pop().unwrap(); debug!("Exiting guard building context with locals: {:?}", guard_frame); - for &(_, temp) in fake_borrows { + for &(_, temp, _) in fake_borrows { let cause = FakeReadCause::ForMatchGuard; self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp)); } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 690879b9488..5dd478aa422 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -42,6 +42,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::Len { len: len as u64, op } } + TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability }, + TestCase::Or { .. } => bug!("or-patterns should have already been handled"), TestCase::Irrefutable { .. } => span_bug!( @@ -143,34 +145,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } let re_erased = tcx.lifetimes.re_erased; - let ref_string = self.temp(Ty::new_imm_ref(tcx, re_erased, ty), test.span); let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_); let ref_str = self.temp(ref_str_ty, test.span); - let deref = tcx.require_lang_item(LangItem::Deref, None); - let method = trait_method(tcx, deref, sym::deref, [ty]); let eq_block = self.cfg.start_new_block(); - self.cfg.push_assign( - block, - source_info, - ref_string, - Rvalue::Ref(re_erased, BorrowKind::Shared, place), - ); - self.cfg.terminate( + // `let ref_str: &str = <String as Deref>::deref(&place);` + self.call_deref( block, - source_info, - TerminatorKind::Call { - func: Operand::Constant(Box::new(ConstOperand { - span: test.span, - user_ty: None, - const_: method, - })), - args: vec![Spanned { node: Operand::Move(ref_string), span: DUMMY_SP }], - destination: ref_str, - target: Some(eq_block), - unwind: UnwindAction::Continue, - call_source: CallSource::Misc, - fn_span: source_info.span, - }, + eq_block, + place, + Mutability::Not, + ty, + ref_str, + test.span, ); self.non_scalar_compare( eq_block, @@ -270,9 +256,66 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Operand::Move(expected), ); } + + TestKind::Deref { temp, mutability } => { + let ty = place_ty.ty; + let target = target_block(TestBranch::Success); + self.call_deref(block, target, place, mutability, ty, temp, test.span); + } } } + /// Perform `let temp = <ty as Deref>::deref(&place)`. + /// or `let temp = <ty as DerefMut>::deref_mut(&mut place)`. + pub(super) fn call_deref( + &mut self, + block: BasicBlock, + target_block: BasicBlock, + place: Place<'tcx>, + mutability: Mutability, + ty: Ty<'tcx>, + temp: Place<'tcx>, + span: Span, + ) { + let (trait_item, method) = match mutability { + Mutability::Not => (LangItem::Deref, sym::deref), + Mutability::Mut => (LangItem::DerefMut, sym::deref_mut), + }; + let borrow_kind = super::util::ref_pat_borrow_kind(mutability); + let source_info = self.source_info(span); + let re_erased = self.tcx.lifetimes.re_erased; + let trait_item = self.tcx.require_lang_item(trait_item, None); + let method = trait_method(self.tcx, trait_item, method, [ty]); + let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span); + // `let ref_src = &src_place;` + // or `let ref_src = &mut src_place;` + self.cfg.push_assign( + block, + source_info, + ref_src, + Rvalue::Ref(re_erased, borrow_kind, place), + ); + // `let temp = <Ty as Deref>::deref(ref_src);` + // or `let temp = <Ty as DerefMut>::deref_mut(ref_src);` + self.cfg.terminate( + block, + source_info, + TerminatorKind::Call { + func: Operand::Constant(Box::new(ConstOperand { + span, + user_ty: None, + const_: method, + })), + args: vec![Spanned { node: Operand::Move(ref_src), span }], + destination: temp, + target: Some(target_block), + unwind: UnwindAction::Continue, + call_source: CallSource::Misc, + fn_span: source_info.span, + }, + ); + } + /// Compare using the provided built-in comparison operator fn compare( &mut self, @@ -660,13 +703,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + (TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. }) + if test_temp == temp => + { + fully_matched = true; + Some(TestBranch::Success) + } + ( TestKind::Switch { .. } | TestKind::SwitchInt { .. } | TestKind::If | TestKind::Len { .. } | TestKind::Range { .. } - | TestKind::Eq { .. }, + | TestKind::Eq { .. } + | TestKind::Deref { .. }, _, ) => { fully_matched = false; diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index d6376b7b0dc..2f9390c22a8 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,12 +1,13 @@ use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; use crate::build::Builder; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::FxIndexMap; use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_middle::mir::*; use rustc_middle::thir::{self, *}; -use rustc_middle::ty; use rustc_middle::ty::TypeVisitableExt; +use rustc_middle::ty::{self, Ty}; +use rustc_span::Span; impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn field_match_pairs<'pat>( @@ -249,10 +250,15 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { default_irrefutable() } - PatKind::DerefPattern { .. } => { - // FIXME(deref_patterns) - // Treat it like a wildcard for now. - default_irrefutable() + PatKind::DerefPattern { ref subpattern, mutability } => { + // Create a new temporary for each deref pattern. + // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? + let temp = cx.temp( + Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), + pattern.span, + ); + subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); + TestCase::Deref { temp, mutability } } }; @@ -262,19 +268,103 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> { cx: &'a mut Builder<'b, 'tcx>, - fake_borrows: FxIndexSet<Place<'tcx>>, + /// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from + /// bindings inside deref patterns. + scrutinee_base: PlaceBase, + /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest + /// borrow (i.e. Deep > Shallow). + /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are + /// dereferences are also borrowed with the same of stronger borrow kind. + fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>, +} + +/// Determine the set of places that have to be stable across match guards. +/// +/// Returns a list of places that need a fake borrow along with a local to store it. +/// +/// Match exhaustiveness checking is not able to handle the case where the place being matched on is +/// mutated in the guards. We add "fake borrows" to the guards that prevent any mutation of the +/// place being matched. There are a some subtleties: +/// +/// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared reference, the borrow +/// isn't even tracked. As such we have to add fake borrows of any prefixes of a place. +/// 2. We don't want `match x { (Some(_), _) => (), .. }` to conflict with mutable borrows of `x.1`, so we +/// only add fake borrows for places which are bound or tested by the match. +/// 3. We don't want `match x { Some(_) => (), .. }` to conflict with mutable borrows of `(x as +/// Some).0`, so the borrows are a special shallow borrow that only affects the place and not its +/// projections. +/// ```rust +/// let mut x = (Some(0), true); +/// match x { +/// (Some(_), false) => {} +/// _ if { if let Some(ref mut y) = x.0 { *y += 1 }; true } => {} +/// _ => {} +/// } +/// ``` +/// 4. The fake borrows may be of places in inactive variants, e.g. here we need to fake borrow `x` +/// and `(x as Some).0`, but when we reach the guard `x` may not be `Some`. +/// ```rust +/// let mut x = (Some(Some(0)), true); +/// match x { +/// (Some(Some(_)), false) => {} +/// _ if { if let Some(Some(ref mut y)) = x.0 { *y += 1 }; true } => {} +/// _ => {} +/// } +/// ``` +/// So it would be UB to generate code for the fake borrows. They therefore have to be removed by +/// a MIR pass run after borrow checking. +pub(super) fn collect_fake_borrows<'tcx>( + cx: &mut Builder<'_, 'tcx>, + candidates: &[&mut Candidate<'_, 'tcx>], + temp_span: Span, + scrutinee_base: PlaceBase, +) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { + let mut collector = + FakeBorrowCollector { cx, scrutinee_base, fake_borrows: FxIndexMap::default() }; + for candidate in candidates.iter() { + collector.visit_candidate(candidate); + } + let fake_borrows = collector.fake_borrows; + debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows); + let tcx = cx.tcx; + fake_borrows + .iter() + .map(|(matched_place, borrow_kind)| { + let fake_borrow_deref_ty = matched_place.ty(&cx.local_decls, tcx).ty; + let fake_borrow_ty = + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty); + let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); + fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow)); + let fake_borrow_temp = cx.local_decls.push(fake_borrow_temp); + (*matched_place, fake_borrow_temp, *borrow_kind) + }) + .collect() } impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { - pub(super) fn collect_fake_borrows( - cx: &'a mut Builder<'b, 'tcx>, - candidates: &[&mut Candidate<'_, 'tcx>], - ) -> FxIndexSet<Place<'tcx>> { - let mut collector = Self { cx, fake_borrows: FxIndexSet::default() }; - for candidate in candidates.iter() { - collector.visit_candidate(candidate); + // Fake borrow this place and its dereference prefixes. + fn fake_borrow(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) { + if self.fake_borrows.get(&place).is_some_and(|k| *k >= kind) { + return; + } + self.fake_borrows.insert(place, kind); + // Also fake borrow the prefixes of any fake borrow. + self.fake_borrow_deref_prefixes(place, kind); + } + + // Fake borrow the prefixes of this place that are dereferences. + fn fake_borrow_deref_prefixes(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) { + for (place_ref, elem) in place.as_ref().iter_projections().rev() { + if let ProjectionElem::Deref = elem { + // Insert a shallow borrow after a deref. For other projections the borrow of + // `place_ref` will conflict with any mutation of `place.base`. + let place = place_ref.to_place(self.cx.tcx); + if self.fake_borrows.get(&place).is_some_and(|k| *k >= kind) { + return; + } + self.fake_borrows.insert(place, kind); + } } - collector.fake_borrows } fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) { @@ -300,10 +390,27 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { for flat_pat in pats.iter() { self.visit_flat_pat(flat_pat) } + } else if matches!(match_pair.test_case, TestCase::Deref { .. }) { + // The subpairs of a deref pattern are all places relative to the deref temporary, so we + // don't fake borrow them. Problem is, if we only shallowly fake-borrowed + // `match_pair.place`, this would allow: + // ``` + // let mut b = Box::new(false); + // match b { + // deref!(true) => {} // not reached because `*b == false` + // _ if { *b = true; false } => {} // not reached because the guard is `false` + // deref!(false) => {} // not reached because the guard changed it + // // UB because we reached the unreachable. + // } + // ``` + // Hence we fake borrow using a deep borrow. + if let Some(place) = match_pair.place { + self.fake_borrow(place, FakeBorrowKind::Deep); + } } else { // Insert a Shallow borrow of any place that is switched on. if let Some(place) = match_pair.place { - self.fake_borrows.insert(place); + self.fake_borrow(place, FakeBorrowKind::Shallow); } for subpair in &match_pair.subpairs { @@ -313,6 +420,14 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } fn visit_binding(&mut self, Binding { source, .. }: &Binding<'tcx>) { + if let PlaceBase::Local(l) = self.scrutinee_base + && l != source.local + { + // The base of this place is a temporary created for deref patterns. We don't emit fake + // borrows for these as they are not initialized in all branches. + return; + } + // Insert a borrows of prefixes of places that are bound and are // behind a dereference projection. // @@ -329,13 +444,13 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { // y if { y == 1 && (x = &2) == () } => y, // _ => 3, // } - if let Some(i) = source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) { - let proj_base = &source.projection[..i]; - self.fake_borrows.insert(Place { - local: source.local, - projection: self.cx.tcx.mk_place_elems(proj_base), - }); - } + // + // We don't just fake borrow the whole place because this is allowed: + // match u { + // _ if { u = true; false } => (), + // x => (), + // } + self.fake_borrow_deref_prefixes(*source, FakeBorrowKind::Shallow); } } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0c1e1d59c4f..227d19c3e43 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -513,7 +513,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_expr(&mut visitor, expr); if visitor.found { match borrow_kind { - BorrowKind::Fake | BorrowKind::Shared + BorrowKind::Fake(_) | BorrowKind::Shared if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) @@ -521,7 +521,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { BorrowKind::Mut { .. } => { self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField) } - BorrowKind::Fake | BorrowKind::Shared => {} + BorrowKind::Fake(_) | BorrowKind::Shared => {} } } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 9ddfb12bf76..f67113afd6d 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -423,7 +423,7 @@ impl Subdiagnostic for UnsafeNotInheritedLintNote { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body); let body_start = self.body_span.shrink_to_lo(); @@ -871,7 +871,7 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, - _f: F, + _f: &F, ) { diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index bcb43a00547..5c016682d8d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -264,7 +264,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } hir::PatKind::Deref(subpattern) => { - PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) } + let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern); + let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; + PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), mutability } } hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => { PatKind::Deref { subpattern: self.lower_pattern(subpattern) } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 49e48427b65..619bfbcf43d 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -688,7 +688,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::DerefPattern { subpattern } => { + PatKind::DerefPattern { subpattern, .. } => { print_indented!(self, "DerefPattern { ", depth_lvl + 1); print_indented!(self, "subpattern:", depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2); |
