Skip to content

Commit d08efde

Browse files
committed
Borrow guard patterns for the body of the guard
1 parent 7db4c02 commit d08efde

File tree

4 files changed

+57
-26
lines changed

4 files changed

+57
-26
lines changed

compiler/rustc_hir/src/hir.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,20 @@ pub enum Guard<'hir> {
13231323
IfLet(&'hir Let<'hir>),
13241324
}
13251325

1326+
impl<'hir> Guard<'hir> {
1327+
/// Returns the body of the guard
1328+
///
1329+
/// In other words, returns the e in either of the following:
1330+
///
1331+
/// - `if e`
1332+
/// - `if let x = e`
1333+
pub fn body(&self) -> &'hir Expr<'hir> {
1334+
match self {
1335+
Guard::If(e) | Guard::IfLet(_, e) => e,
1336+
}
1337+
}
1338+
}
1339+
13261340
#[derive(Debug, HashStable_Generic)]
13271341
pub struct ExprField<'hir> {
13281342
#[stable_hasher(ignore)]

compiler/rustc_typeck/src/check/generator_interior.rs

+26-13
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,13 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
285285
self.visit_pat(pat);
286286
if let Some(ref g) = guard {
287287
self.guard_bindings.push(<_>::default());
288-
ArmPatCollector {
289-
guard_bindings_set: &mut self.guard_bindings_set,
290-
guard_bindings: self
291-
.guard_bindings
292-
.last_mut()
293-
.expect("should have pushed at least one earlier"),
288+
{
289+
ArmPatCollector {
290+
interior_visitor: self,
291+
scope: Scope { id: g.body().hir_id.local_id, data: ScopeData::Node },
292+
}
293+
.visit_pat(pat);
294294
}
295-
.visit_pat(pat);
296295

297296
match g {
298297
Guard::If(ref e) => {
@@ -459,17 +458,31 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
459458
}
460459
}
461460

462-
struct ArmPatCollector<'a> {
463-
guard_bindings_set: &'a mut HirIdSet,
464-
guard_bindings: &'a mut SmallVec<[HirId; 4]>,
461+
struct ArmPatCollector<'a, 'b, 'tcx> {
462+
interior_visitor: &'a mut InteriorVisitor<'b, 'tcx>,
463+
scope: Scope,
465464
}
466465

467-
impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
466+
impl<'a, 'b, 'tcx> Visitor<'tcx> for ArmPatCollector<'a, 'b, 'tcx> {
468467
fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
469468
intravisit::walk_pat(self, pat);
470469
if let PatKind::Binding(_, id, ..) = pat.kind {
471-
self.guard_bindings.push(id);
472-
self.guard_bindings_set.insert(id);
470+
self.interior_visitor
471+
.guard_bindings
472+
.last_mut()
473+
.expect("should have pushed at least one earlier")
474+
.push(id);
475+
self.interior_visitor.guard_bindings_set.insert(id);
476+
477+
let ty = self.interior_visitor.fcx.typeck_results.borrow().node_type(id);
478+
let ty = self.interior_visitor.fcx.tcx.mk_ref(
479+
// Use `ReErased` as `resolve_interior` is going to replace all the regions anyway.
480+
self.interior_visitor.fcx.tcx.mk_region(ty::ReErased),
481+
ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
482+
);
483+
// FIXME: use the right span
484+
let span = rustc_span::DUMMY_SP;
485+
self.interior_visitor.record(ty, id, Some(self.scope), None, span, true);
473486
}
474487
}
475488
}

compiler/rustc_typeck/src/expr_use_visitor.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc_middle::hir::place::ProjectionKind;
1717
use rustc_middle::mir::FakeReadCause;
1818
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
1919
use rustc_target::abi::VariantIdx;
20+
use ty::BorrowKind::ImmBorrow;
2021

2122
use crate::mem_categorization as mc;
2223

@@ -621,7 +622,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
621622
FakeReadCause::ForMatchedPlace(closure_def_id),
622623
discr_place.hir_id,
623624
);
624-
self.walk_pat(discr_place, arm.pat);
625+
self.walk_pat(discr_place, arm.pat, arm.guard.is_some());
625626

626627
if let Some(hir::Guard::If(e)) = arm.guard {
627628
self.consume_expr(e)
@@ -645,12 +646,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
645646
FakeReadCause::ForLet(closure_def_id),
646647
discr_place.hir_id,
647648
);
648-
self.walk_pat(discr_place, pat);
649+
self.walk_pat(discr_place, pat, false);
649650
}
650651

651652
/// The core driver for walking a pattern
652-
fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
653-
debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
653+
fn walk_pat(
654+
&mut self,
655+
discr_place: &PlaceWithHirId<'tcx>,
656+
pat: &hir::Pat<'_>,
657+
has_guard: bool,
658+
) {
659+
debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard);
654660

655661
let tcx = self.tcx();
656662
let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
@@ -671,6 +677,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
671677
delegate.bind(binding_place, binding_place.hir_id);
672678
}
673679

680+
// Subtle: MIR desugaring introduces immutable borrows for each pattern
681+
// binding when lowering pattern guards to ensure that the guard does not
682+
// modify the scrutinee.
683+
if has_guard {
684+
delegate.borrow(place, discr_place.hir_id, ImmBorrow);
685+
}
686+
674687
// It is also a borrow or copy/move of the value being matched.
675688
// In a cases of pattern like `let pat = upvar`, don't use the span
676689
// of the pattern, as this just looks confusing, instead use the span

src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs

-9
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,6 @@
22
// edition:2018
33
// compile-flags: -Zdrop-tracking
44

5-
// This test is derived from
6-
// https://github.com/rust-lang/rust/issues/72651#issuecomment-668720468
7-
8-
// This test demonstrates that, in `async fn g()`,
9-
// indeed a temporary borrow `y` from `x` is live
10-
// while `f().await` is being evaluated.
11-
// Thus, `&'_ u8` should be included in type signature
12-
// of the underlying generator.
13-
145
#![feature(generators)]
156

167
fn main() {

0 commit comments

Comments
 (0)