Skip to content

Commit

Permalink
When using NLL, implicitly borrow match bindings for any guard,
Browse files Browse the repository at this point in the history
deref'ing such borrows within that guard.

Review feedback: Add comment noting a point where we may or may not
need to add a cast when we finish the work on #27282.

Review feedback: Pass a newtype'd `ArmHasGuard` rather than a raw boolean.

Review feedback: toggle "ref binding in guards" semantics via specific
method. (This should ease a follow-up PR that just unconditionally
adopts the new semantics.)
  • Loading branch information
pnkfelix committed May 3, 2018
1 parent b00db7c commit a72790d
Show file tree
Hide file tree
Showing 5 changed files with 373 additions and 38 deletions.
8 changes: 8 additions & 0 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1467,6 +1467,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.borrowck_mode().use_mir()
}

/// If true, pattern variables for use in guards on match arms
/// will be bound as references to the data, and occurrences of
/// those variables in the guard expression will implicitly
/// dereference those bindings. (See rust-lang/rust#27282.)
pub fn all_pat_vars_are_implicit_refs_within_guards(self) -> bool {
self.borrowck_mode().use_mir()
}

/// If true, we should enable two-phase borrows checks. This is
/// done with either `-Ztwo-phase-borrows` or with
/// `#![feature(nll)]`.
Expand Down
9 changes: 6 additions & 3 deletions src/librustc_mir/build/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
// except according to those terms.

use build::{BlockAnd, BlockAndExtension, Builder};
use build::ForGuard::OutsideGuard;
use build::matches::ArmHasGuard;
use hair::*;
use rustc::mir::*;
use rustc::hir;
Expand Down Expand Up @@ -113,7 +115,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// Declare the bindings, which may create a visibility scope.
let remainder_span = remainder_scope.span(this.hir.tcx(),
&this.hir.region_scope_tree);
let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern);
let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern,
ArmHasGuard(false));

// Evaluate the initializer, if present.
if let Some(init) = initializer {
Expand All @@ -135,8 +138,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}

this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
this.storage_live_binding(block, node, span);
this.schedule_drop_for_binding(node, span);
this.storage_live_binding(block, node, span, OutsideGuard);
this.schedule_drop_for_binding(node, span, OutsideGuard);
})
}

Expand Down
15 changes: 13 additions & 2 deletions src/librustc_mir/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//! See docs in build/expr/mod.rs
use build::{BlockAnd, BlockAndExtension, Builder};
use build::ForGuard::{OutsideGuard, WithinGuard};
use build::expr::category::Category;
use hair::*;
use rustc::mir::*;
Expand Down Expand Up @@ -86,8 +87,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
block.and(Place::Local(Local::new(1)))
}
ExprKind::VarRef { id } => {
let index = this.var_indices[&id];
block.and(Place::Local(index))
let place = if this.is_bound_var_in_guard(id) {
let index = this.var_local_id(id, WithinGuard);
if this.hir.tcx().all_pat_vars_are_implicit_refs_within_guards() {
Place::Local(index).deref()
} else {
Place::Local(index)
}
} else {
let index = this.var_local_id(id, OutsideGuard);
Place::Local(index)
};
block.and(place)
}
ExprKind::StaticRef { id } => {
block.and(Place::Static(Box::new(Static { def_id: id, ty: expr.ty })))
Expand Down
Loading

0 comments on commit a72790d

Please sign in to comment.