mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 01:04:03 +00:00
Borrow guard patterns for the body of the guard
This commit is contained in:
parent
7db4c0277d
commit
d08efdec1c
@ -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)]
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user