about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs6
-rw-r--r--src/librustc_mir/borrow_check/flows.rs7
-rw-r--r--src/librustc_mir/borrow_check/mod.rs53
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs716
-rw-r--r--src/librustc_mir/dataflow/mod.rs41
-rw-r--r--src/test/compile-fail/borrowck/two-phase-activation-sharing-interference.rs4
-rw-r--r--src/test/compile-fail/borrowck/two-phase-allow-access-during-reservation.rs6
-rw-r--r--src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs16
-rw-r--r--src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs9
9 files changed, 427 insertions, 431 deletions
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index a47ced010e6..7ab52e98a0e 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -18,7 +18,7 @@ use rustc_data_structures::sync::Lrc;
 
 use super::{Context, MirBorrowckCtxt};
 use super::{InitializationRequiringAction, PrefixSet};
-use dataflow::{ActiveBorrows, BorrowData, FlowAtLocation, MovingOutStatements};
+use dataflow::{Borrows, BorrowData, FlowAtLocation, MovingOutStatements};
 use dataflow::move_paths::MovePathIndex;
 use util::borrowck_errors::{BorrowckErrors, Origin};
 
@@ -372,10 +372,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         context: Context,
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
-        borrows: &ActiveBorrows<'cx, 'gcx, 'tcx>,
+        borrows: &Borrows<'cx, 'gcx, 'tcx>
     ) {
         let end_span = borrows.opt_region_end_span(&borrow.region);
-        let scope_tree = borrows.0.scope_tree();
+        let scope_tree = borrows.scope_tree();
         let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
             .last()
             .unwrap();
diff --git a/src/librustc_mir/borrow_check/flows.rs b/src/librustc_mir/borrow_check/flows.rs
index ba966c9d4e3..ceff380c594 100644
--- a/src/librustc_mir/borrow_check/flows.rs
+++ b/src/librustc_mir/borrow_check/flows.rs
@@ -17,13 +17,14 @@ use rustc::mir::{BasicBlock, Location};
 
 use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
 use dataflow::{EverInitializedPlaces, MovingOutStatements};
-use dataflow::{ActiveBorrows, FlowAtLocation, FlowsAtLocation};
+use dataflow::{Borrows};
+use dataflow::{FlowAtLocation, FlowsAtLocation};
 use dataflow::move_paths::HasMoveData;
 use std::fmt;
 
 // (forced to be `pub` due to its use as an associated type below.)
 pub(crate) struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
-    pub borrows: FlowAtLocation<ActiveBorrows<'b, 'gcx, 'tcx>>,
+    pub borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
     pub inits: FlowAtLocation<MaybeInitializedPlaces<'b, 'gcx, 'tcx>>,
     pub uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
     pub move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
@@ -32,7 +33,7 @@ pub(crate) struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
 
 impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> {
     pub fn new(
-        borrows: FlowAtLocation<ActiveBorrows<'b, 'gcx, 'tcx>>,
+        borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
         inits: FlowAtLocation<MaybeInitializedPlaces<'b, 'gcx, 'tcx>>,
         uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
         move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index e51b16a3736..3f111ebcb78 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -34,11 +34,10 @@ use syntax_pos::Span;
 use dataflow::{do_dataflow, DebugFormatted};
 use dataflow::FlowAtLocation;
 use dataflow::MoveDataParamEnv;
-use dataflow::{DataflowAnalysis, DataflowResultsConsumer};
+use dataflow::{DataflowResultsConsumer};
 use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
 use dataflow::{EverInitializedPlaces, MovingOutStatements};
 use dataflow::{BorrowData, Borrows, ReserveOrActivateIndex};
-use dataflow::{ActiveBorrows, Reservations};
 use dataflow::indexes::BorrowIndex;
 use dataflow::move_paths::{IllegalMoveOriginKind, MoveError};
 use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
@@ -54,8 +53,6 @@ mod error_reporting;
 mod flows;
 mod prefixes;
 
-use std::borrow::Cow;
-
 pub(crate) mod nll;
 
 pub fn provide(providers: &mut Providers) {
@@ -209,6 +206,18 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     };
     let flow_inits = flow_inits; // remove mut
 
+    let flow_borrows = FlowAtLocation::new(do_dataflow(
+        tcx,
+        mir,
+        id,
+        &attributes,
+        &dead_unwinds,
+        Borrows::new(tcx, mir, opt_regioncx.clone(), def_id, body_id),
+        |rs, i| {
+            DebugFormatted::new(&(i.kind(), rs.location(i.borrow_index())))
+        }
+    ));
+
     let movable_generator = !match tcx.hir.get(id) {
         hir::map::Node::NodeExpr(&hir::Expr {
             node: hir::ExprClosure(.., Some(hir::GeneratorMovability::Static)),
@@ -230,44 +239,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         },
         access_place_error_reported: FxHashSet(),
         reservation_error_reported: FxHashSet(),
-        nonlexical_regioncx: opt_regioncx.clone(),
+        nonlexical_regioncx: opt_regioncx,
         nonlexical_cause_info: None,
     };
 
-    let borrows = Borrows::new(tcx, mir, opt_regioncx, def_id, body_id);
-    let flow_reservations = do_dataflow(
-        tcx,
-        mir,
-        id,
-        &attributes,
-        &dead_unwinds,
-        Reservations::new(borrows),
-        |rs, i| {
-            // In principle we could make the dataflow ensure that
-            // only reservation bits show up, and assert so here.
-            //
-            // In practice it is easier to be looser; in particular,
-            // it is okay for the kill-sets to hold activation bits.
-            DebugFormatted::new(&(i.kind(), rs.location(i)))
-        },
-    );
-    let flow_active_borrows = {
-        let reservations_on_entry = flow_reservations.0.sets.entry_set_state();
-        let reservations = flow_reservations.0.operator;
-        let a = DataflowAnalysis::new_with_entry_sets(
-            mir,
-            &dead_unwinds,
-            Cow::Borrowed(reservations_on_entry),
-            ActiveBorrows::new(reservations),
-        );
-        let results = a.run(tcx, id, &attributes, |ab, i| {
-            DebugFormatted::new(&(i.kind(), ab.location(i)))
-        });
-        FlowAtLocation::new(results)
-    };
-
     let mut state = Flows::new(
-        flow_active_borrows,
+        flow_borrows,
         flow_inits,
         flow_uninits,
         flow_move_outs,
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 859618d27b3..4b63d8e2ff7 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -63,46 +63,25 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
     /// to its borrow-indexes.
     assigned_map: FxHashMap<Place<'tcx>, FxHashSet<BorrowIndex>>,
 
+    /// Locations which activate borrows.
+    /// NOTE: A given location may activate more than one borrow in the future
+    /// when more general two-phase borrow support is introduced, but for now we
+    /// only need to store one borrow index
+    activation_map: FxHashMap<Location, BorrowIndex>,
+
     /// Every borrow has a region; this maps each such regions back to
     /// its borrow-indexes.
     region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
+
+    /// Map from local to all the borrows on that local
     local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
-    region_span_map: FxHashMap<RegionKind, Span>,
-    nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
-}
 
-// Two-phase borrows actually requires two flow analyses; they need
-// to be separate because the final results of the first are used to
-// construct the gen+kill sets for the second. (The dataflow system
-// is not designed to allow the gen/kill sets to change during the
-// fixed-point iteration.)
-
-/// The `Reservations` analysis is the first of the two flow analyses
-/// tracking (phased) borrows. It computes where a borrow is reserved;
-/// i.e. where it can reach in the control flow starting from its
-/// initial `assigned = &'rgn borrowed` statement, and ending
-/// wherever `'rgn` itself ends.
-pub(crate) struct Reservations<'a, 'gcx: 'tcx, 'tcx: 'a>(pub(crate) Borrows<'a, 'gcx, 'tcx>);
-
-/// The `ActiveBorrows` analysis is the second of the two flow
-/// analyses tracking (phased) borrows. It computes where any given
-/// borrow `&assigned = &'rgn borrowed` is *active*, which starts at
-/// the first use of `assigned` after the reservation has started, and
-/// ends wherever `'rgn` itself ends.
-pub(crate) struct ActiveBorrows<'a, 'gcx: 'tcx, 'tcx: 'a>(pub(crate) Borrows<'a, 'gcx, 'tcx>);
-
-impl<'a, 'gcx, 'tcx> Reservations<'a, 'gcx, 'tcx> {
-    pub(crate) fn new(b: Borrows<'a, 'gcx, 'tcx>) -> Self { Reservations(b) }
-    pub(crate) fn location(&self, idx: ReserveOrActivateIndex) -> &Location {
-        self.0.location(idx.borrow_index())
-    }
-}
+    /// Maps regions to their corresponding source spans
+    /// Only contains ReScope()s as keys
+    region_span_map: FxHashMap<RegionKind, Span>,
 
-impl<'a, 'gcx, 'tcx> ActiveBorrows<'a, 'gcx, 'tcx> {
-    pub(crate) fn new(r: Reservations<'a, 'gcx, 'tcx>) -> Self { ActiveBorrows(r.0) }
-    pub(crate) fn location(&self, idx: ReserveOrActivateIndex) -> &Location {
-        self.0.location(idx.borrow_index())
-    }
+    /// NLL region inference context with which NLL queries should be resolved
+    nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
 }
 
 // temporarily allow some dead fields: `kind` and `region` will be
@@ -114,9 +93,15 @@ pub struct BorrowData<'tcx> {
     /// Location where the borrow reservation starts.
     /// In many cases, this will be equal to the activation location but not always.
     pub(crate) reserve_location: Location,
+    /// Point where the borrow is activated.
+    pub(crate) activate_location: Location,
+    /// What kind of borrow this is
     pub(crate) kind: mir::BorrowKind,
+    /// The region for which this borrow is live
     pub(crate) region: Region<'tcx>,
+    /// Place from which we are borrowing
     pub(crate) borrowed_place: mir::Place<'tcx>,
+    /// Place to which the borrow was stored
     pub(crate) assigned_place: mir::Place<'tcx>,
 }
 
@@ -165,9 +150,11 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
             idx_vec: IndexVec::new(),
             location_map: FxHashMap(),
             assigned_map: FxHashMap(),
+            activation_map: FxHashMap(),
             region_map: FxHashMap(),
             local_map: FxHashMap(),
-            region_span_map: FxHashMap()
+            region_span_map: FxHashMap(),
+            nonlexical_regioncx: nonlexical_regioncx.clone()
         };
         visitor.visit_mir(mir);
         return Borrows { tcx: tcx,
@@ -177,6 +164,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                          root_scope,
                          location_map: visitor.location_map,
                          assigned_map: visitor.assigned_map,
+                         activation_map: visitor.activation_map,
                          region_map: visitor.region_map,
                          local_map: visitor.local_map,
                          region_span_map: visitor.region_span_map,
@@ -188,9 +176,11 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
             idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
             location_map: FxHashMap<Location, BorrowIndex>,
             assigned_map: FxHashMap<Place<'tcx>, FxHashSet<BorrowIndex>>,
+            activation_map: FxHashMap<Location, BorrowIndex>,
             region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
             local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
             region_span_map: FxHashMap<RegionKind, Span>,
+            nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
         }
 
         impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
@@ -210,15 +200,25 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                 if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
                     if is_unsafe_place(self.tcx, self.mir, borrowed_place) { return; }
 
+                    let activate_location = self.compute_activation_location(location,
+                                                                             &assigned_place,
+                                                                             region,
+                                                                             kind);
                     let borrow = BorrowData {
+                        activate_location, kind, region,
                         reserve_location: location,
-                        kind, region,
                         borrowed_place: borrowed_place.clone(),
                         assigned_place: assigned_place.clone(),
                     };
                     let idx = self.idx_vec.push(borrow);
                     self.location_map.insert(location, idx);
 
+                    // This assert is a good sanity check until more general 2-phase borrow
+                    // support is introduced. See NOTE on the activation_map field for more
+                    assert!(!self.activation_map.contains_key(&activate_location),
+                            "More than one activation introduced at the same location.");
+                    self.activation_map.insert(activate_location, idx);
+
                     insert(&mut self.assigned_map, assigned_place, idx);
                     insert(&mut self.region_map, &region, idx);
                     if let Some(local) = root_local(borrowed_place) {
@@ -273,6 +273,246 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                 return self.super_statement(block, statement, location);
             }
         }
+
+        /// Represents what kind of usage we've seen.
+        enum PlaceUsageType {
+            /// No usage seen
+            None,
+            /// Has been seen as the argument to a StorageDead statement. This is required to
+            /// gracefully handle cases where user code has an unneeded 
+            StorageKilled,
+            /// Has been used in borrow-activating context
+            BorrowActivateUsage
+        }
+
+        /// A MIR visitor that determines if a specific place is used in a two-phase activating
+        /// manner in a given chunk of MIR.
+        struct ContainsUseOfPlace<'b, 'tcx: 'b> {
+            target: &'b Place<'tcx>,
+            use_found: bool,
+        }
+
+        impl<'b, 'tcx: 'b> ContainsUseOfPlace<'b, 'tcx> {
+            fn new(place: &'b Place<'tcx>) -> Self {
+                Self { target: place, use_found: false }
+            }
+
+            /// return whether `context` should be considered a "use" of a
+            /// place found in that context. "Uses" activate associated
+            /// borrows (at least when such uses occur while the borrow also
+            /// has a reservation at the time).
+            fn is_potential_use(context: PlaceContext) -> bool {
+                match context {
+                    // storage effects on a place do not activate it
+                    PlaceContext::StorageLive | PlaceContext::StorageDead => false,
+
+                    // validation effects do not activate a place
+                    //
+                    // FIXME: Should they? Is it just another read? Or can we
+                    // guarantee it won't dereference the stored address? How
+                    // "deep" does validation go?
+                    PlaceContext::Validate => false,
+
+                    // FIXME: This is here to not change behaviour from before
+                    // AsmOutput existed, but it's not necessarily a pure overwrite.
+                    // so it's possible this should activate the place.
+                    PlaceContext::AsmOutput |
+                    // pure overwrites of a place do not activate it. (note
+                    // PlaceContext::Call is solely about dest place)
+                    PlaceContext::Store | PlaceContext::Call => false,
+
+                    // reads of a place *do* activate it
+                    PlaceContext::Move |
+                    PlaceContext::Copy |
+                    PlaceContext::Drop |
+                    PlaceContext::Inspect |
+                    PlaceContext::Borrow { .. } |
+                    PlaceContext::Projection(..) => true,
+                }
+            }
+        }
+
+        impl<'b, 'tcx: 'b> Visitor<'tcx> for ContainsUseOfPlace<'b, 'tcx> {
+            fn visit_place(&mut self,
+                           place: &mir::Place<'tcx>,
+                           context: PlaceContext<'tcx>,
+                           location: Location) {
+                if Self::is_potential_use(context) && place == self.target {
+                    self.use_found = true;
+                    return;
+                    // There is no need to keep checking the statement, we already found a use
+                }
+
+                self.super_place(place, context, location);
+            }
+
+            /*
+            fn visit_statement(&mut self,
+                               block: BasicBlock,
+                               statement: &mir::Statement<'tcx>,
+                               location: Location) {
+                if let mir::StatementKind::StorageDead(loc) = *statement {
+                }
+
+                self.super_statement(block, statement, location);
+            }
+            */
+        }
+
+        impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {
+            /// Returns true if the borrow represented by `kind` is
+            /// allowed to be split into separate Reservation and
+            /// Activation phases.
+            fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool {
+                self.tcx.sess.two_phase_borrows() &&
+                    (kind.allows_two_phase_borrow() ||
+                     self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
+            }
+
+            /// Returns true if the given location contains an NLL-activating use of the given place
+            fn location_contains_use(&self, location: Location, place: &Place) -> bool {
+                let mut use_checker = ContainsUseOfPlace::new(place);
+                let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
+                    panic!("could not find block at location {:?}", location);
+                });
+                if location.statement_index != block.statements.len() {
+                    // This is a statement
+                    let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| {
+                        panic!("could not find statement at location {:?}");
+                    });
+                    use_checker.visit_statement(location.block, stmt, location);
+                } else {
+                    // This is a terminator
+                    match block.terminator {
+                        Some(ref term) => {
+                            use_checker.visit_terminator(location.block, term, location);
+                        }
+                        None => {
+                            // There is no way for Place to be used by the terminator if there is no
+                            // terminator
+                        }
+                    }
+                }
+
+                use_checker.use_found
+            }
+
+            /// Determines if the provided region is terminated after the provided location.
+            /// EndRegion statements terminate their enclosed region::Scope.
+            /// We also consult with the NLL region inference engine, should one be available
+            fn region_terminated_after(&self, region: Region<'tcx>, location: Location) -> bool {
+                let block_data = &self.mir[location.block];
+                if location.statement_index != block_data.statements.len() {
+                    let stmt = &block_data.statements[location.statement_index];
+                    if let mir::StatementKind::EndRegion(region_scope) = stmt.kind {
+                        if &ReScope(region_scope) == region {
+                            // We encountered an EndRegion statement that terminates the provided region
+                            return true;
+                        }
+                    }
+                }
+                if let Some(ref regioncx) = self.nonlexical_regioncx {
+                    if !regioncx.region_contains_point(region, location) {
+                        // NLL says the region has ended already
+                        return true;
+                    }
+                }
+
+                false
+            }
+
+            /// Computes the activation location of a borrow.
+            /// The general idea is to start at the beginning of the region and perform a DFS
+            /// until we exit the region, either via an explicit EndRegion or because NLL tells
+            /// us so. If we find more than one valid activation point, we currently panic the
+            /// compiler since two-phase borrows are only currently supported for compiler-
+            /// generated code. More precisely, we only allow two-phase borrows for:
+            ///   - Function calls (fn some_func(&mut self, ....))
+            ///   - *Assign operators (a += b -> fn add_assign(&mut self, other: Self))
+            /// See
+            ///   - https://github.com/rust-lang/rust/issues/48431
+            /// for detailed design notes.
+            /// See the TODO in the body of the function for notes on extending support to more
+            /// general two-phased borrows.
+            fn compute_activation_location(&self,
+                                           start_location: Location,
+                                           assigned_place: &mir::Place<'tcx>,
+                                           region: Region<'tcx>,
+                                           kind: mir::BorrowKind) -> Location {
+                debug!("Borrows::compute_activation_location({:?}, {:?}, {:?})",
+                       start_location,
+                       assigned_place,
+                       region);
+                if !self.allow_two_phase_borrow(kind) {
+                    debug!("  -> {:?}", start_location);
+                    return start_location;
+                }
+
+                // Perform the DFS.
+                // `stack` is the stack of locations still under consideration
+                // `found_use` is an Option that becomes Some when we find a use
+                let mut stack = vec![start_location];
+                let mut found_use = None;
+                while let Some(curr_loc) = stack.pop() {
+                    let block_data = &self.mir.basic_blocks()
+                        .get(curr_loc.block)
+                        .unwrap_or_else(|| {
+                            panic!("could not find block at location {:?}", curr_loc);
+                        });
+
+                    if self.region_terminated_after(region, curr_loc) {
+                        // No need to process this statement.
+                        // It's either an EndRegion (and thus couldn't use assigned_place) or not
+                        // contained in the NLL region and thus a use would be invalid
+                        continue;
+                    }
+
+                    if self.location_contains_use(curr_loc, assigned_place) {
+                        // TODO: Handle this case a little more gracefully. Perhaps collect
+                        // all uses in a vector, and find the point in the CFG that dominates
+                        // all of them?
+                        // Right now this is sufficient though since there should only be exactly
+                        // one borrow-activating use of the borrow.
+                        assert!(found_use.is_none(), "Found secondary use of place");
+                        found_use = Some(curr_loc);
+                    }
+
+                    // Push the points we should consider next.
+                    if curr_loc.statement_index < block_data.statements.len() {
+                        stack.push(curr_loc.successor_within_block());
+                    } else {
+                        stack.extend(block_data.terminator().successors().iter().map(
+                            |&basic_block| {
+                                Location {
+                                    statement_index: 0,
+                                    block: basic_block
+                                }
+                            }
+                        ))
+                    }
+                }
+
+                let found_use = found_use.expect("Did not find use of two-phase place");
+                debug!("  -> {:?}", found_use);
+                found_use
+            }
+        }
+    }
+
+    /// Returns the span for the "end point" given region. This will
+    /// return `None` if NLL is enabled, since that concept has no
+    /// meaning there.  Otherwise, return region span if it exists and
+    /// span for end of the function if it doesn't exist.
+    pub(crate) fn opt_region_end_span(&self, region: &Region) -> Option<Span> {
+        match self.nonlexical_regioncx {
+            Some(_) => None,
+            None => {
+                match self.region_span_map.get(region) {
+                    Some(span) => Some(self.tcx.sess.codemap().end_point(*span)),
+                    None => Some(self.tcx.sess.codemap().end_point(self.mir.span))
+                }
+            }
+        }
     }
 
     pub fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrows }
@@ -284,18 +524,24 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
     }
 
     /// Add all borrows to the kill set, if those borrows are out of scope at `location`.
-    ///
-    /// `is_activations` tracks whether we are in the Reservations or
-    /// the ActiveBorrows flow analysis, and does not set the
-    /// activation kill bits in the former case. (Technically, we
-    /// could set those kill bits without such a guard, since they are
-    /// never gen'ed by Reservations in the first place.  But it makes
-    /// the instrumentation and graph renderings nicer to leave
-    /// activations out when of the Reservations kill sets.)
+    /// That means either they went out of either a nonlexical scope, if we care about those
+    /// at the moment, or the location represents a lexical EndRegion
     fn kill_loans_out_of_scope_at_location(&self,
                                            sets: &mut BlockSets<ReserveOrActivateIndex>,
-                                           location: Location,
-                                           is_activations: bool) {
+                                           location: Location) {
+        /*
+         XXX: bob_twinkles  reintroduce this
+        let block_data = &self.mir[location.block];
+        if location.statement_index != block_data.statements.len() {
+            let statement = &block_data.statements[location.statement_index];
+            if let mir::StatementKind::EndRegion(region_scope) = statement.kind {
+                for &borrow_index in &self.region_map[&ReScope(region_scope)] {
+                    sets.kill(&ReserveOrActivateIndex::reserved(borrow_index));
+                    sets.kill(&ReserveOrActivateIndex::active(borrow_index));
+                }
+            }
+        }
+        */
         if let Some(ref regioncx) = self.nonlexical_regioncx {
             // NOTE: The state associated with a given `location`
             // reflects the dataflow on entry to the statement. If it
@@ -312,21 +558,46 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                 let borrow_region = borrow_data.region.to_region_vid();
                 if !regioncx.region_contains_point(borrow_region, location) {
                     sets.kill(&ReserveOrActivateIndex::reserved(borrow_index));
-                    if is_activations {
-                        sets.kill(&ReserveOrActivateIndex::active(borrow_index));
-                    }
+                    sets.kill(&ReserveOrActivateIndex::active(borrow_index));
                 }
             }
         }
     }
 
-    /// Models statement effect in Reservations and ActiveBorrows flow
-    /// analyses; `is activations` tells us if we are in the latter
-    /// case.
-    fn statement_effect_on_borrows(&self,
-                                   sets: &mut BlockSets<ReserveOrActivateIndex>,
-                                   location: Location,
-                                   is_activations: bool) {
+    fn kill_borrows_on_local(&self,
+                             sets: &mut BlockSets<ReserveOrActivateIndex>,
+                             local: &rustc::mir::Local)
+    {
+        if let Some(borrow_indexes) = self.local_map.get(local) {
+            sets.kill_all(borrow_indexes.iter()
+                          .map(|b| ReserveOrActivateIndex::reserved(*b)));
+            sets.kill_all(borrow_indexes.iter()
+                          .map(|b| ReserveOrActivateIndex::active(*b)));
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
+    type Idx = ReserveOrActivateIndex;
+    fn name() -> &'static str { "borrows" }
+    fn bits_per_block(&self) -> usize {
+        self.borrows.len() * 2
+    }
+
+    fn start_block_effect(&self, _entry_set: &mut IdxSet<ReserveOrActivateIndex>) {
+        // no borrows of code region_scopes have been taken prior to
+        // function execution, so this method has no effect on
+        // `_sets`.
+    }
+
+    fn before_statement_effect(&self, sets: &mut BlockSets<ReserveOrActivateIndex>, location: Location) {
+        debug!("Borrows::before_statement_effect sets: {:?} location: {:?}", sets, location);
+        self.kill_loans_out_of_scope_at_location(sets, location);
+    }
+
+    fn statement_effect(&self, sets: &mut BlockSets<ReserveOrActivateIndex>, location: Location) {
+        debug!("Borrows::statement_effect sets: {:?} location: {:?}", sets, location);
+
         let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
             panic!("could not find block at location {:?}", location);
         });
@@ -334,20 +605,12 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
             panic!("could not find statement at location {:?}");
         });
 
-        // Do kills introduced by NLL before setting up any potential
-        // gens. (See NOTE in kill_loans_out_of_scope_at_location.)
-        self.kill_loans_out_of_scope_at_location(sets, location, is_activations);
-
-        if is_activations {
-            // INVARIANT: `sets.on_entry` accurately captures
-            // reservations on entry to statement (b/c
-            // accumulates_intrablock_state is overridden for
-            // ActiveBorrows).
-            //
-            // Now compute the activations generated by uses within
-            // the statement based on that reservation state.
-            let mut find = FindPlaceUses { sets, assigned_map: &self.assigned_map };
-            find.visit_statement(location.block, stmt, location);
+        // Handle activations
+        match self.activation_map.get(&location) {
+            Some(&activated) => {
+                sets.gen(&ReserveOrActivateIndex::active(activated))
+            }
+            None => {}
         }
 
         match stmt.kind {
@@ -357,9 +620,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                     assert!(self.nonlexical_regioncx.is_none());
                     for idx in borrow_indexes {
                         sets.kill(&ReserveOrActivateIndex::reserved(*idx));
-                        if is_activations {
-                            sets.kill(&ReserveOrActivateIndex::active(*idx));
-                        }
+                        sets.kill(&ReserveOrActivateIndex::active(*idx));
                     }
                 } else {
                     // (if there is no entry, then there are no borrows to be tracked)
@@ -372,7 +633,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                 if let Place::Local(ref local) = *lhs {
                     // FIXME: Handle the case in which we're assigning over
                     // a projection (`foo.bar`).
-                    self.kill_borrows_on_local(sets, local, is_activations);
+                    self.kill_borrows_on_local(sets, local);
                 }
 
                 // NOTE: if/when the Assign case is revised to inspect
@@ -396,18 +657,17 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                     }).contains(&index));
                     sets.gen(&ReserveOrActivateIndex::reserved(*index));
 
-                    if is_activations {
-                        // Issue #46746: Two-phase borrows handles
-                        // stmts of form `Tmp = &mut Borrow` ...
-                        match lhs {
-                            Place::Local(..) | Place::Static(..) => {} // okay
-                            Place::Projection(..) => {
-                                // ... can assign into projections,
-                                // e.g. `box (&mut _)`. Current
-                                // conservative solution: force
-                                // immediate activation here.
-                                sets.gen(&ReserveOrActivateIndex::active(*index));
-                            }
+                    // Issue #46746: Two-phase borrows handles
+                    // stmts of form `Tmp = &mut Borrow` ...
+                    // XXX bob_twinkles experiment with removing this
+                    match lhs {
+                        Place::Local(..) | Place::Static(..) => {} // okay
+                        Place::Projection(..) => {
+                            // ... can assign into projections,
+                            // e.g. `box (&mut _)`. Current
+                            // conservative solution: force
+                            // immediate activation here.
+                            sets.gen(&ReserveOrActivateIndex::active(*index));
                         }
                     }
                 }
@@ -416,7 +676,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
             mir::StatementKind::StorageDead(local) => {
                 // Make sure there are no remaining borrows for locals that
                 // are gone out of scope.
-                self.kill_borrows_on_local(sets, &local, is_activations)
+                self.kill_borrows_on_local(sets, &local)
             }
 
             mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => {
@@ -427,7 +687,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                         if let Place::Local(ref local) = *output {
                             // FIXME: Handle the case in which we're assigning over
                             // a projection (`foo.bar`).
-                            self.kill_borrows_on_local(sets, local, is_activations);
+                            self.kill_borrows_on_local(sets, local);
                         }
                     }
                 }
@@ -441,47 +701,26 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn kill_borrows_on_local(&self,
-                             sets: &mut BlockSets<ReserveOrActivateIndex>,
-                             local: &rustc::mir::Local,
-                             is_activations: bool)
-    {
-        if let Some(borrow_indexes) = self.local_map.get(local) {
-            sets.kill_all(borrow_indexes.iter()
-                            .map(|b| ReserveOrActivateIndex::reserved(*b)));
-            if is_activations {
-                sets.kill_all(borrow_indexes.iter()
-                                .map(|b| ReserveOrActivateIndex::active(*b)));
-            }
-        }
+    fn before_terminator_effect(&self, sets: &mut BlockSets<ReserveOrActivateIndex>, location: Location) {
+        debug!("Borrows::before_terminator_effect sets: {:?} location: {:?}", sets, location);
+        self.kill_loans_out_of_scope_at_location(sets, location);
     }
 
-    /// Models terminator effect in Reservations and ActiveBorrows
-    /// flow analyses; `is activations` tells us if we are in the
-    /// latter case.
-    fn terminator_effect_on_borrows(&self,
-                                    sets: &mut BlockSets<ReserveOrActivateIndex>,
-                                    location: Location,
-                                    is_activations: bool) {
+    fn terminator_effect(&self, sets: &mut BlockSets<ReserveOrActivateIndex>, location: Location) {
+        debug!("Borrows::terminator_effect sets: {:?} location: {:?}", sets, location);
+
         let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
             panic!("could not find block at location {:?}", location);
         });
 
-        // Do kills introduced by NLL before setting up any potential
-        // gens. (See NOTE in kill_loans_out_of_scope_at_location.)
-        self.kill_loans_out_of_scope_at_location(sets, location, is_activations);
-
         let term = block.terminator();
-        if is_activations {
-            // INVARIANT: `sets.on_entry` accurately captures
-            // reservations on entry to terminator (b/c
-            // accumulates_intrablock_state is overridden for
-            // ActiveBorrows).
-            //
-            // Now compute effect of the terminator on the activations
-            // themselves in the ActiveBorrows state.
-            let mut find = FindPlaceUses { sets, assigned_map: &self.assigned_map };
-            find.visit_terminator(location.block, term, location);
+
+        // Handle activations
+        match self.activation_map.get(&location) {
+            Some(&activated) => {
+                sets.gen(&ReserveOrActivateIndex::active(activated))
+            }
+            None => {}
         }
 
         match term.kind {
@@ -504,9 +743,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
                                 self.scope_tree.is_subscope_of(*scope, root_scope)
                             {
                                 sets.kill(&ReserveOrActivateIndex::reserved(borrow_index));
-                                if is_activations {
-                                    sets.kill(&ReserveOrActivateIndex::active(borrow_index));
-                                }
+                                sets.kill(&ReserveOrActivateIndex::active(borrow_index));
                             }
                         }
                     }
@@ -525,161 +762,6 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
             mir::TerminatorKind::Unreachable => {}
         }
     }
-}
-
-impl<'a, 'gcx, 'tcx> ActiveBorrows<'a, 'gcx, 'tcx> {
-    pub(crate) fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> {
-        self.0.borrows()
-    }
-
-    /// Returns the span for the "end point" given region. This will
-    /// return `None` if NLL is enabled, since that concept has no
-    /// meaning there.  Otherwise, return region span if it exists and
-    /// span for end of the function if it doesn't exist.
-    pub(crate) fn opt_region_end_span(&self, region: &Region) -> Option<Span> {
-        match self.0.nonlexical_regioncx {
-            Some(_) => None,
-            None => {
-                match self.0.region_span_map.get(region) {
-                    Some(span) => Some(self.0.tcx.sess.codemap().end_point(*span)),
-                    None => Some(self.0.tcx.sess.codemap().end_point(self.0.mir.span))
-                }
-            }
-        }
-    }
-}
-
-/// `FindPlaceUses` is a MIR visitor that updates `self.sets` for all
-/// of the borrows activated by a given statement or terminator.
-///
-/// ----
-///
-/// The `ActiveBorrows` flow analysis, when inspecting any given
-/// statement or terminator, needs to "generate" (i.e. set to 1) all
-/// of the bits for the borrows that are activated by that
-/// statement/terminator.
-///
-/// This struct will seek out all places that are assignment-targets
-/// for borrows (gathered in `self.assigned_map`; see also the
-/// `assigned_map` in `struct Borrows`), and set the corresponding
-/// gen-bits for activations of those borrows in `self.sets`
-struct FindPlaceUses<'a, 'b: 'a, 'tcx: 'a> {
-    assigned_map: &'a FxHashMap<Place<'tcx>, FxHashSet<BorrowIndex>>,
-    sets: &'a mut BlockSets<'b, ReserveOrActivateIndex>,
-}
-
-impl<'a, 'b, 'tcx> FindPlaceUses<'a, 'b, 'tcx> {
-    fn has_been_reserved(&self, b: &BorrowIndex) -> bool {
-        self.sets.on_entry.contains(&ReserveOrActivateIndex::reserved(*b))
-    }
-
-    /// return whether `context` should be considered a "use" of a
-    /// place found in that context. "Uses" activate associated
-    /// borrows (at least when such uses occur while the borrow also
-    /// has a reservation at the time).
-    fn is_potential_use(context: PlaceContext) -> bool {
-        match context {
-            // storage effects on a place do not activate it
-            PlaceContext::StorageLive | PlaceContext::StorageDead => false,
-
-            // validation effects do not activate a place
-            //
-            // FIXME: Should they? Is it just another read? Or can we
-            // guarantee it won't dereference the stored address? How
-            // "deep" does validation go?
-            PlaceContext::Validate => false,
-
-            // FIXME: This is here to not change behaviour from before
-            // AsmOutput existed, but it's not necessarily a pure overwrite.
-            // so it's possible this should activate the place.
-            PlaceContext::AsmOutput |
-            // pure overwrites of a place do not activate it. (note
-            // PlaceContext::Call is solely about dest place)
-            PlaceContext::Store | PlaceContext::Call => false,
-
-            // reads of a place *do* activate it
-            PlaceContext::Move |
-            PlaceContext::Copy |
-            PlaceContext::Drop |
-            PlaceContext::Inspect |
-            PlaceContext::Borrow { .. } |
-            PlaceContext::Projection(..) => true,
-        }
-    }
-}
-
-impl<'a, 'b, 'tcx> Visitor<'tcx> for FindPlaceUses<'a, 'b, 'tcx> {
-    fn visit_place(&mut self,
-                    place: &mir::Place<'tcx>,
-                    context: PlaceContext<'tcx>,
-                    location: Location) {
-        debug!("FindPlaceUses place: {:?} assigned from borrows: {:?} \
-                used in context: {:?} at location: {:?}",
-               place, self.assigned_map.get(place), context, location);
-        if Self::is_potential_use(context) {
-            if let Some(borrows) = self.assigned_map.get(place) {
-                for borrow_idx in borrows {
-                    debug!("checking if index {:?} for {:?} is reserved ({}) \
-                            and thus needs active gen-bit set in sets {:?}",
-                           borrow_idx, place, self.has_been_reserved(&borrow_idx), self.sets);
-                    if self.has_been_reserved(&borrow_idx) {
-                        self.sets.gen(&ReserveOrActivateIndex::active(*borrow_idx));
-                    } else {
-                        // (This can certainly happen in valid code. I
-                        // just want to know about it in the short
-                        // term.)
-                        debug!("encountered use of Place {:?} of borrow_idx {:?} \
-                                at location {:?} outside of reservation",
-                               place, borrow_idx, location);
-                    }
-                }
-            }
-        }
-
-        self.super_place(place, context, location);
-    }
-}
-
-
-impl<'a, 'gcx, 'tcx> BitDenotation for Reservations<'a, 'gcx, 'tcx> {
-    type Idx = ReserveOrActivateIndex;
-    fn name() -> &'static str { "reservations" }
-    fn bits_per_block(&self) -> usize {
-        self.0.borrows.len() * 2
-    }
-    fn start_block_effect(&self, _entry_set: &mut IdxSet<ReserveOrActivateIndex>)  {
-        // no borrows of code region_scopes have been taken prior to
-        // function execution, so this method has no effect on
-        // `_sets`.
-    }
-
-    fn before_statement_effect(&self,
-                               sets: &mut BlockSets<ReserveOrActivateIndex>,
-                               location: Location) {
-        debug!("Reservations::before_statement_effect sets: {:?} location: {:?}", sets, location);
-        self.0.kill_loans_out_of_scope_at_location(sets, location, false);
-    }
-
-    fn statement_effect(&self,
-                        sets: &mut BlockSets<ReserveOrActivateIndex>,
-                        location: Location) {
-        debug!("Reservations::statement_effect sets: {:?} location: {:?}", sets, location);
-        self.0.statement_effect_on_borrows(sets, location, false);
-    }
-
-    fn before_terminator_effect(&self,
-                                sets: &mut BlockSets<ReserveOrActivateIndex>,
-                                location: Location) {
-        debug!("Reservations::before_terminator_effect sets: {:?} location: {:?}", sets, location);
-        self.0.kill_loans_out_of_scope_at_location(sets, location, false);
-    }
-
-    fn terminator_effect(&self,
-                         sets: &mut BlockSets<ReserveOrActivateIndex>,
-                         location: Location) {
-        debug!("Reservations::terminator_effect sets: {:?} location: {:?}", sets, location);
-        self.0.terminator_effect_on_borrows(sets, location, false);
-    }
 
     fn propagate_call_return(&self,
                              _in_out: &mut IdxSet<ReserveOrActivateIndex>,
@@ -694,85 +776,17 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Reservations<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitDenotation for ActiveBorrows<'a, 'gcx, 'tcx> {
-    type Idx = ReserveOrActivateIndex;
-    fn name() -> &'static str { "active_borrows" }
-
-    /// Overriding this method; `ActiveBorrows` uses the intrablock
-    /// state in `on_entry` to track the current reservations (which
-    /// then affect the construction of the gen/kill sets for
-    /// activations).
-    fn accumulates_intrablock_state() -> bool { true }
-
-    fn bits_per_block(&self) -> usize {
-        self.0.borrows.len() * 2
-    }
-
-    fn start_block_effect(&self, _entry_sets: &mut IdxSet<ReserveOrActivateIndex>)  {
-        // no borrows of code region_scopes have been taken prior to
-        // function execution, so this method has no effect on
-        // `_sets`.
-    }
-
-    fn before_statement_effect(&self,
-                               sets: &mut BlockSets<ReserveOrActivateIndex>,
-                               location: Location) {
-        debug!("ActiveBorrows::before_statement_effect sets: {:?} location: {:?}", sets, location);
-        self.0.kill_loans_out_of_scope_at_location(sets, location, true);
-    }
-
-    fn statement_effect(&self,
-                        sets: &mut BlockSets<ReserveOrActivateIndex>,
-                        location: Location) {
-        debug!("ActiveBorrows::statement_effect sets: {:?} location: {:?}", sets, location);
-        self.0.statement_effect_on_borrows(sets, location, true);
-    }
-
-    fn before_terminator_effect(&self,
-                                sets: &mut BlockSets<ReserveOrActivateIndex>,
-                                location: Location) {
-        debug!("ActiveBorrows::before_terminator_effect sets: {:?} location: {:?}", sets, location);
-        self.0.kill_loans_out_of_scope_at_location(sets, location, true);
-    }
-
-    fn terminator_effect(&self,
-                         sets: &mut BlockSets<ReserveOrActivateIndex>,
-                         location: Location) {
-        debug!("ActiveBorrows::terminator_effect sets: {:?} location: {:?}", sets, location);
-        self.0.terminator_effect_on_borrows(sets, location, true);
-    }
-
-    fn propagate_call_return(&self,
-                             _in_out: &mut IdxSet<ReserveOrActivateIndex>,
-                             _call_bb: mir::BasicBlock,
-                             _dest_bb: mir::BasicBlock,
-                             _dest_place: &mir::Place) {
-        // there are no effects on borrows from method call return...
-        //
-        // ... but If overwriting a place can affect flow state, then
-        // latter is not true; see NOTE on Assign case in
-        // statement_effect_on_borrows.
-    }
-}
-
-impl<'a, 'gcx, 'tcx> BitwiseOperator for Reservations<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitwiseOperator for Borrows<'a, 'gcx, 'tcx> {
     #[inline]
     fn join(&self, pred1: usize, pred2: usize) -> usize {
         pred1 | pred2 // union effects of preds when computing reservations
     }
 }
 
-impl<'a, 'gcx, 'tcx> BitwiseOperator for ActiveBorrows<'a, 'gcx, 'tcx> {
-    #[inline]
-    fn join(&self, pred1: usize, pred2: usize) -> usize {
-        pred1 | pred2 // union effects of preds when computing activations
-    }
-}
-
-impl<'a, 'gcx, 'tcx> InitialFlow for Reservations<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> InitialFlow for Borrows<'a, 'gcx, 'tcx> {
     #[inline]
     fn bottom_value() -> bool {
-        false // bottom = no Rvalue::Refs are reserved by default
+        false // bottom = nothing is reserved or activated yet
     }
 }
 
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index aa7bb6f9778..f7675d611cc 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -18,7 +18,7 @@ use rustc::ty::{self, TyCtxt};
 use rustc::mir::{self, Mir, BasicBlock, BasicBlockData, Location, Statement, Terminator};
 use rustc::session::Session;
 
-use std::borrow::{Borrow, Cow};
+use std::borrow::Borrow;
 use std::fmt;
 use std::io;
 use std::mem;
@@ -31,7 +31,7 @@ pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements};
 pub use self::impls::EverInitializedPlaces;
 pub use self::impls::borrows::{Borrows, BorrowData};
 pub use self::impls::HaveBeenBorrowedLocals;
-pub(crate) use self::impls::borrows::{ActiveBorrows, Reservations, ReserveOrActivateIndex};
+pub(crate) use self::impls::borrows::{ReserveOrActivateIndex};
 pub use self::at_location::{FlowAtLocation, FlowsAtLocation};
 pub(crate) use self::drop_flag_effects::*;
 
@@ -584,9 +584,6 @@ impl<E:Idx> AllSets<E> {
     pub fn on_entry_set_for(&self, block_idx: usize) -> &IdxSet<E> {
         self.lookup_set_for(&self.on_entry_sets, block_idx)
     }
-    pub(crate) fn entry_set_state(&self) -> &Bits<E> {
-        &self.on_entry_sets
-    }
 }
 
 /// Parameterization for the precise form of data flow that is used.
@@ -739,27 +736,17 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
                dead_unwinds: &'a IdxSet<mir::BasicBlock>,
                denotation: D) -> Self where D: InitialFlow {
         let bits_per_block = denotation.bits_per_block();
+        let usize_bits = mem::size_of::<usize>() * 8;
+        let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;
         let num_overall = Self::num_bits_overall(mir, bits_per_block);
+
+        let zeroes = Bits::new(IdxSetBuf::new_empty(num_overall));
         let on_entry = Bits::new(if D::bottom_value() {
             IdxSetBuf::new_filled(num_overall)
         } else {
             IdxSetBuf::new_empty(num_overall)
         });
 
-        Self::new_with_entry_sets(mir, dead_unwinds, Cow::Owned(on_entry), denotation)
-    }
-
-    pub(crate) fn new_with_entry_sets(mir: &'a Mir<'tcx>,
-                                      dead_unwinds: &'a IdxSet<mir::BasicBlock>,
-                                      on_entry: Cow<Bits<D::Idx>>,
-                                      denotation: D)
-                                      -> Self {
-        let bits_per_block = denotation.bits_per_block();
-        let usize_bits = mem::size_of::<usize>() * 8;
-        let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;
-        let num_overall = Self::num_bits_overall(mir, bits_per_block);
-        assert_eq!(num_overall, on_entry.bits.words().len() * usize_bits);
-        let zeroes = Bits::new(IdxSetBuf::new_empty(num_overall));
         DataflowAnalysis {
             mir,
             dead_unwinds,
@@ -769,13 +756,27 @@ impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
                     words_per_block,
                     gen_sets: zeroes.clone(),
                     kill_sets: zeroes,
-                    on_entry_sets: on_entry.into_owned(),
+                    on_entry_sets: on_entry,
                 },
                 operator: denotation,
             }
         }
     }
 
+    pub fn new_from_sets(mir: &'a Mir<'tcx>,
+                         dead_unwinds: &'a IdxSet<mir::BasicBlock>,
+                         sets: AllSets<D::Idx>,
+                         denotation: D) -> Self {
+        DataflowAnalysis {
+            mir,
+            dead_unwinds,
+            flow_state: DataflowState {
+                sets: sets,
+                operator: denotation,
+            }
+        }
+    }
+
     fn num_bits_overall(mir: &Mir, bits_per_block: usize) -> usize {
         let usize_bits = mem::size_of::<usize>() * 8;
         let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;
diff --git a/src/test/compile-fail/borrowck/two-phase-activation-sharing-interference.rs b/src/test/compile-fail/borrowck/two-phase-activation-sharing-interference.rs
index 709c00ba846..1d3d61fb3fb 100644
--- a/src/test/compile-fail/borrowck/two-phase-activation-sharing-interference.rs
+++ b/src/test/compile-fail/borrowck/two-phase-activation-sharing-interference.rs
@@ -10,10 +10,12 @@
 
 // ignore-tidy-linelength
 
-// revisions: lxl_beyond nll_beyond nll_target
+// revisions: nll_target
 
+// The following revisions are disabled due to missing support from two-phase beyond autorefs
 //[lxl_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref
 //[nll_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref -Z nll
+
 //[nll_target] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
 
 // This is an important corner case pointed out by Niko: one is
diff --git a/src/test/compile-fail/borrowck/two-phase-allow-access-during-reservation.rs b/src/test/compile-fail/borrowck/two-phase-allow-access-during-reservation.rs
index dd174981fb1..d2f4154433a 100644
--- a/src/test/compile-fail/borrowck/two-phase-allow-access-during-reservation.rs
+++ b/src/test/compile-fail/borrowck/two-phase-allow-access-during-reservation.rs
@@ -10,9 +10,13 @@
 
 // ignore-tidy-linelength
 
-// revisions: lxl_beyond nll_beyond nll_target
+// revisions: nll_target
+
+// The following revisions are disabled due to missing support for two_phase_beyond_autoref
 //[lxl_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two_phase_beyond_autoref
 //[nll_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two_phase_beyond_autoref -Z nll
+
+
 //[nll_target] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
 
 // This is the second counter-example from Niko's blog post
diff --git a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs
index f4c36157fe9..bf8e02adb1a 100644
--- a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs
+++ b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs
@@ -8,10 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// revisions: lxl nll g2p
+// revisions: lxl nll
 //[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
 //[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+
 //[g2p]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll -Z two-phase-beyond-autoref
+// the above revision is disabled until two-phase-beyond-autoref support is better
 
 // This is a test checking that when we limit two-phase borrows to
 // method receivers, we do not let other kinds of auto-ref to leak
@@ -70,10 +72,8 @@ fn overloaded_call_traits() {
     fn twice_ten_sm<F: FnMut(i32) -> i32>(f: &mut F) {
         f(f(10));
         //[lxl]~^     ERROR cannot borrow `*f` as mutable more than once at a time
-        //[lxl]~|     ERROR cannot borrow `*f` as mutable more than once at a time
-        //[nll]~^^^   ERROR cannot borrow `*f` as mutable more than once at a time
-        //[nll]~|     ERROR cannot borrow `*f` as mutable more than once at a time
-        //[g2p]~^^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
+        //[nll]~^^   ERROR cannot borrow `*f` as mutable more than once at a time
+        //[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
     }
     fn twice_ten_si<F: Fn(i32) -> i32>(f: &mut F) {
         f(f(10));
@@ -88,10 +88,8 @@ fn overloaded_call_traits() {
     fn twice_ten_om(f: &mut FnMut(i32) -> i32) {
         f(f(10));
         //[lxl]~^     ERROR cannot borrow `*f` as mutable more than once at a time
-        //[lxl]~|     ERROR cannot borrow `*f` as mutable more than once at a time
-        //[nll]~^^^   ERROR cannot borrow `*f` as mutable more than once at a time
-        //[nll]~|     ERROR cannot borrow `*f` as mutable more than once at a time
-        //[g2p]~^^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
+        //[nll]~^^   ERROR cannot borrow `*f` as mutable more than once at a time
+        //[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
     }
     fn twice_ten_oi(f: &mut Fn(i32) -> i32) {
         f(f(10));
diff --git a/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs b/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs
index b5fda4985f2..058022ad588 100644
--- a/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs
+++ b/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs
@@ -12,8 +12,12 @@
 
 // revisions: lxl_beyond nll_beyond nll_target
 
+// The following revisions are disabled due to missing support from two-phase beyond autorefs
 //[lxl_beyond]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref
+//[lxl_beyond] should-fail
 //[nll_beyond]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref -Z nll
+//[nll_beyond] should-fail
+
 //[nll_target]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
 
 // This is a corner case that the current implementation is (probably)
@@ -31,10 +35,6 @@
 // "nll_beyond" means the generalization of two-phase borrows to all
 // `&mut`-borrows (doing so makes it easier to write code for specific
 // corner cases).
-//
-// FIXME: in "nll_target", we currently see the same error reported
-// twice. This is injected by `-Z two-phase-borrows`; not sure why as
-// of yet.
 
 fn main() {
     let mut vec = vec![0, 1];
@@ -49,7 +49,6 @@ fn main() {
         //[lxl_beyond]~^   ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
         //[nll_beyond]~^^  ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
         //[nll_target]~^^^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
-        //[nll_target]~|   ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
 
         shared[0];
     }