Skip to content

Commit

Permalink
Incorporate active-borrows dataflow into MIR borrow check, yielding
Browse files Browse the repository at this point in the history
two-phase `&mut`-borrow support.

This (new) support sits under `-Z two-phase-borrows` debugflag.

(Still needs tests. That's coming next.)
  • Loading branch information
pnkfelix committed Dec 13, 2017
1 parent 1334638 commit 3621645
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/librustc/session/config.rs
Expand Up @@ -1011,6 +1011,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"emit EndRegion as part of MIR; enable transforms that solely process EndRegion"),
borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
"select which borrowck is used (`ast`, `mir`, or `compare`)"),
two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
"use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"),
time_passes: bool = (false, parse_bool, [UNTRACKED],
"measure time of each rustc pass"),
count_llvm_insns: bool = (false, parse_bool,
Expand Down
24 changes: 20 additions & 4 deletions src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -701,9 +701,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
context,
(sd, place_span.0),
flow_state,
|this, _index, borrow| match (rw, borrow.kind) {
|this, index, borrow| match (rw, borrow.kind) {
(Read(_), BorrowKind::Shared) => Control::Continue,

(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut) => {
// Reading from mere reservations of mutable-borrows is OK.
if this.tcx.sess.opts.debugging_opts.two_phase_borrows &&
index.is_reservation()
{
return Control::Continue;
}

match kind {
ReadKind::Copy => {
error_reported = true;
Expand Down Expand Up @@ -1826,9 +1834,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {

// check for loan restricting path P being used. Accounts for
// borrows of P, P.a.b, etc.
for i in flow_state.borrows.elems_incoming() {
// FIXME for now, just skip the activation state.
if i.is_activation() { continue }
let mut elems_incoming = flow_state.borrows.elems_incoming();
while let Some(i) = elems_incoming.next() {
// Skip any reservation that has a corresponding current
// activation. This way, the traversal will visit each
// borrow_index at most once.
if let Some(j) = elems_incoming.peek() {
if i.is_reservation() && j.is_activation() {
assert_eq!(i.borrow_index(), j.borrow_index());
continue;
}
}

let borrowed = &data[i.borrow_index()];

Expand Down
6 changes: 4 additions & 2 deletions src/librustc_mir/dataflow/at_location.rs
Expand Up @@ -18,6 +18,8 @@ use rustc_data_structures::indexed_vec::Idx;
use dataflow::{BitDenotation, BlockSets, DataflowResults};
use dataflow::move_paths::{HasMoveData, MovePathIndex};

use std::iter;

/// A trait for "cartesian products" of multiple FlowAtLocation.
///
/// There's probably a way to auto-impl this, but I think
Expand Down Expand Up @@ -94,9 +96,9 @@ where
self.curr_state.contains(x)
}

pub fn elems_incoming(&self) -> indexed_set::Elems<BD::Idx> {
pub fn elems_incoming(&self) -> iter::Peekable<indexed_set::Elems<BD::Idx>> {
let univ = self.base_results.sets().bits_per_block();
self.curr_state.elems(univ)
self.curr_state.elems(univ).peekable()
}

pub fn with_elems_outgoing<F>(&self, f: F)
Expand Down

0 comments on commit 3621645

Please sign in to comment.