diff options
| author | Eric Holk <ericholk@microsoft.com> | 2022-05-17 15:36:39 -0700 |
|---|---|---|
| committer | Eric Holk <ericholk@microsoft.com> | 2022-05-19 16:23:28 -0700 |
| commit | d08efdec1c0e3c8135a547b2853af49a7f107f7e (patch) | |
| tree | 5bdeda55400cdd98c6efbb6c5385f7a3fe7393bb | |
| parent | 7db4c0277de996531c2e794ba16bb6746af65fef (diff) | |
| download | rust-d08efdec1c0e3c8135a547b2853af49a7f107f7e.tar.gz rust-d08efdec1c0e3c8135a547b2853af49a7f107f7e.zip | |
Borrow guard patterns for the body of the guard
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/generator_interior.rs | 39 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/expr_use_visitor.rs | 21 | ||||
| -rw-r--r-- | src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs | 9 |
4 files changed, 57 insertions, 26 deletions
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 81d544c7b96..5bd6632640f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1323,6 +1323,20 @@ pub enum Guard<'hir> { IfLet(&'hir Let<'hir>), } +impl<'hir> Guard<'hir> { + /// Returns the body of the guard + /// + /// In other words, returns the e in either of the following: + /// + /// - `if e` + /// - `if let x = e` + pub fn body(&self) -> &'hir Expr<'hir> { + match self { + Guard::If(e) | Guard::IfLet(_, e) => e, + } + } +} + #[derive(Debug, HashStable_Generic)] pub struct ExprField<'hir> { #[stable_hasher(ignore)] diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 92a2584a6de..d530504489a 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -285,14 +285,13 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { self.visit_pat(pat); if let Some(ref g) = guard { self.guard_bindings.push(<_>::default()); - ArmPatCollector { - guard_bindings_set: &mut self.guard_bindings_set, - guard_bindings: self - .guard_bindings - .last_mut() - .expect("should have pushed at least one earlier"), + { + ArmPatCollector { + interior_visitor: self, + scope: Scope { id: g.body().hir_id.local_id, data: ScopeData::Node }, + } + .visit_pat(pat); } - .visit_pat(pat); match g { Guard::If(ref e) => { @@ -459,17 +458,31 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { } } -struct ArmPatCollector<'a> { - guard_bindings_set: &'a mut HirIdSet, - guard_bindings: &'a mut SmallVec<[HirId; 4]>, +struct ArmPatCollector<'a, 'b, 'tcx> { + interior_visitor: &'a mut InteriorVisitor<'b, 'tcx>, + scope: Scope, } -impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> { +impl<'a, 'b, 'tcx> Visitor<'tcx> for ArmPatCollector<'a, 'b, 'tcx> { fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { intravisit::walk_pat(self, pat); if let PatKind::Binding(_, id, ..) = pat.kind { - self.guard_bindings.push(id); - self.guard_bindings_set.insert(id); + self.interior_visitor + .guard_bindings + .last_mut() + .expect("should have pushed at least one earlier") + .push(id); + self.interior_visitor.guard_bindings_set.insert(id); + + let ty = self.interior_visitor.fcx.typeck_results.borrow().node_type(id); + let ty = self.interior_visitor.fcx.tcx.mk_ref( + // Use `ReErased` as `resolve_interior` is going to replace all the regions anyway. + self.interior_visitor.fcx.tcx.mk_region(ty::ReErased), + ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }, + ); + // FIXME: use the right span + let span = rustc_span::DUMMY_SP; + self.interior_visitor.record(ty, id, Some(self.scope), None, span, true); } } } diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 6de6b6ee479..ad44adb68c6 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -17,6 +17,7 @@ use rustc_middle::hir::place::ProjectionKind; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; +use ty::BorrowKind::ImmBorrow; use crate::mem_categorization as mc; @@ -621,7 +622,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { FakeReadCause::ForMatchedPlace(closure_def_id), discr_place.hir_id, ); - self.walk_pat(discr_place, arm.pat); + self.walk_pat(discr_place, arm.pat, arm.guard.is_some()); if let Some(hir::Guard::If(e)) = arm.guard { self.consume_expr(e) @@ -645,12 +646,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { FakeReadCause::ForLet(closure_def_id), discr_place.hir_id, ); - self.walk_pat(discr_place, pat); + self.walk_pat(discr_place, pat, false); } /// The core driver for walking a pattern - fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { - debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat); + fn walk_pat( + &mut self, + discr_place: &PlaceWithHirId<'tcx>, + pat: &hir::Pat<'_>, + has_guard: bool, + ) { + debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard); let tcx = self.tcx(); let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; @@ -671,6 +677,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { delegate.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 { + delegate.borrow(place, discr_place.hir_id, ImmBorrow); + } + // 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 diff --git a/src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs b/src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs index c818963e466..646365e4359 100644 --- a/src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs +++ b/src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs @@ -2,15 +2,6 @@ // edition:2018 // compile-flags: -Zdrop-tracking -// This test is derived from -// https://github.com/rust-lang/rust/issues/72651#issuecomment-668720468 - -// This test demonstrates that, in `async fn g()`, -// indeed a temporary borrow `y` from `x` is live -// while `f().await` is being evaluated. -// Thus, `&'_ u8` should be included in type signature -// of the underlying generator. - #![feature(generators)] fn main() { |
