diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 51 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/thir.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/typeck_results.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/builder/matches/match_pair.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/mod.rs | 11 |
5 files changed, 64 insertions, 31 deletions
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index f5e0f01e4c5..17e13ec0a37 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -1000,13 +1000,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // 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 // stores the result of calling `deref()`/`deref_mut()` so can't be captured). + // Deref patterns on boxes don't borrow, so we ignore them here. // HACK: this could be a fake pattern corresponding to a deref inserted by match // ergonomics, in which case `pat.hir_id` will be the id of the 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 bk = ty::BorrowKind::from_mutbl(mutability); - self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk); + if let hir::ByRef::Yes(mutability) = + self.cx.typeck_results().deref_pat_borrow_mode(place.place.ty(), subpattern) + { + let bk = ty::BorrowKind::from_mutbl(mutability); + self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk); + } } PatKind::Never => { // A `!` pattern always counts as an immutable read of the discriminant, @@ -1691,18 +1693,19 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx place_with_id = match adjust.kind { adjustment::PatAdjust::BuiltinDeref => self.cat_deref(pat.hir_id, place_with_id)?, adjustment::PatAdjust::OverloadedDeref => { - // This adjustment corresponds to an overloaded deref; it borrows the scrutinee to - // call `Deref::deref` or `DerefMut::deref_mut`. Invoke the callback before setting - // `place_with_id` to the temporary storing the result of the deref. + // This adjustment corresponds to an overloaded deref; unless it's on a box, it + // borrows the scrutinee to call `Deref::deref` or `DerefMut::deref_mut`. Invoke + // the callback before setting `place_with_id` to the temporary storing the + // result of the deref. // HACK(dianne): giving the callback a fake deref pattern makes sure it behaves the - // same as it would if this were an explicit deref pattern. + // same as it would if this were an explicit deref pattern (including for boxes). op(&place_with_id, &hir::Pat { kind: PatKind::Deref(pat), ..*pat })?; let target_ty = match adjusts.peek() { Some(&&next_adjust) => next_adjust.source, // At the end of the deref chain, we get `pat`'s scrutinee. None => self.pat_ty_unadjusted(pat)?, }; - self.pat_deref_temp(pat.hir_id, pat, target_ty)? + self.pat_deref_place(pat.hir_id, place_with_id, pat, target_ty)? } }; } @@ -1810,7 +1813,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } PatKind::Deref(subpat) => { let ty = self.pat_ty_adjusted(subpat)?; - let place = self.pat_deref_temp(pat.hir_id, subpat, ty)?; + let place = self.pat_deref_place(pat.hir_id, place_with_id, subpat, ty)?; self.cat_pattern(place, subpat, op)?; } @@ -1863,21 +1866,27 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } - /// Represents the place of the temp that stores the scrutinee of a deref pattern's interior. - fn pat_deref_temp( + /// Represents the place matched on by a deref pattern's interior. + fn pat_deref_place( &self, hir_id: HirId, + base_place: PlaceWithHirId<'tcx>, inner: &hir::Pat<'_>, target_ty: Ty<'tcx>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> { - let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(inner); - let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; - let re_erased = self.cx.tcx().lifetimes.re_erased; - let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability); - // A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ... - let base = self.cat_rvalue(hir_id, ty); - // ... and the inner pattern matches on the place behind that reference. - self.cat_deref(hir_id, base) + match self.cx.typeck_results().deref_pat_borrow_mode(base_place.place.ty(), inner) { + // Deref patterns on boxes are lowered using a built-in deref. + hir::ByRef::No => self.cat_deref(hir_id, base_place), + // For other types, we create a temporary to match on. + hir::ByRef::Yes(mutability) => { + let re_erased = self.cx.tcx().lifetimes.re_erased; + let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability); + // A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ... + let base = self.cat_rvalue(hir_id, ty); + // ... and the inner pattern matches on the place behind that reference. + self.cat_deref(hir_id, base) + } + } } fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index c168142fb1e..086ec529f33 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -799,7 +799,12 @@ pub enum PatKind<'tcx> { /// Deref pattern, written `box P` for now. DerefPattern { subpattern: Box<Pat<'tcx>>, - mutability: hir::Mutability, + /// Whether the pattern scrutinee needs to be borrowed in order to call `Deref::deref` or + /// `DerefMut::deref_mut`, and if so, which. This is `ByRef::No` for deref patterns on + /// boxes; they are lowered using a built-in deref rather than a method call, thus they + /// don't borrow the scrutinee. + #[type_visitable(ignore)] + borrow: ByRef, }, /// One of the following: diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 4c5c669771f..8c5827d36df 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -475,6 +475,21 @@ impl<'tcx> TypeckResults<'tcx> { has_ref_mut } + /// How should a deref pattern find the place for its inner pattern to match on? + /// + /// In most cases, if the pattern recursively contains a `ref mut` binding, we find the inner + /// pattern's scrutinee by calling `DerefMut::deref_mut`, and otherwise we call `Deref::deref`. + /// However, for boxes we can use a built-in deref instead, which doesn't borrow the scrutinee; + /// in this case, we return `ByRef::No`. + pub fn deref_pat_borrow_mode(&self, pointer_ty: Ty<'_>, inner: &hir::Pat<'_>) -> ByRef { + if pointer_ty.is_box() { + ByRef::No + } else { + let mutable = self.pat_has_ref_mut_binding(inner); + ByRef::Yes(if mutable { Mutability::Mut } else { Mutability::Not }) + } + } + /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured /// by the closure. pub fn closure_min_captures_flattened( diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index d66b38c5b00..3a7854a5e11 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use rustc_hir::ByRef; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; @@ -260,7 +261,13 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::Deref { ref subpattern } => { + PatKind::Deref { ref subpattern } + | PatKind::DerefPattern { ref subpattern, borrow: ByRef::No } => { + if cfg!(debug_assertions) && matches!(pattern.kind, PatKind::DerefPattern { .. }) { + // Only deref patterns on boxes can be lowered using a built-in deref. + debug_assert!(pattern.ty.is_box()); + } + MatchPairTree::for_pattern( place_builder.deref(), subpattern, @@ -271,7 +278,7 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::DerefPattern { ref subpattern, mutability } => { + PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(mutability) } => { // Create a new temporary for each deref pattern. // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? let temp = cx.temp( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8f058efdfac..8e69ff568b9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -111,10 +111,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let kind = match adjust.kind { PatAdjust::BuiltinDeref => PatKind::Deref { subpattern: thir_pat }, PatAdjust::OverloadedDeref => { - let mutable = self.typeck_results.pat_has_ref_mut_binding(pat); - let mutability = - if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; - PatKind::DerefPattern { subpattern: thir_pat, mutability } + let borrow = self.typeck_results.deref_pat_borrow_mode(adjust.source, pat); + PatKind::DerefPattern { subpattern: thir_pat, borrow } } }; Box::new(Pat { span, ty: adjust.source, kind }) @@ -308,9 +306,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } hir::PatKind::Deref(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 } + let borrow = self.typeck_results.deref_pat_borrow_mode(ty, subpattern); + PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), borrow } } hir::PatKind::Ref(subpattern, _) => { // Track the default binding mode for the Rust 2024 migration suggestion. |
