Skip to content

Commit 84feab3

Browse files
committedDec 15, 2017
Auto merge of #46537 - pnkfelix:two-phase-borrows, r=arielb1
[MIR-borrowck] Two phase borrows This adds limited support for two-phase borrows as described in http://smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/ The support is off by default; you opt into it via the flag `-Z two-phase-borrows` I have written "*limited* support" above because there are simple variants of the simple `v.push(v.len())` example that one would think should work but currently do not, such as the one documented in the test compile-fail/borrowck/two-phase-reservation-sharing-interference-2.rs (To be clear, that test is not describing something that is unsound. It is just providing an explicit example of a limitation in the implementation given in this PR. I have ideas on how to fix, but I want to land the work that is in this PR first, so that I can stop repeatedly rebasing this branch.)
2 parents 9331031 + 159037e commit 84feab3

25 files changed

+1182
-255
lines changed
 

‎src/librustc/mir/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,7 @@ impl<'tcx> Debug for Statement<'tcx> {
11371137

11381138
/// A path to a value; something that can be evaluated without
11391139
/// changing or disturbing program state.
1140-
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
1140+
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
11411141
pub enum Place<'tcx> {
11421142
/// local variable
11431143
Local(Local),
@@ -1151,7 +1151,7 @@ pub enum Place<'tcx> {
11511151

11521152
/// The def-id of a static, along with its normalized type (which is
11531153
/// stored to avoid requiring normalization when reading MIR).
1154-
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
1154+
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
11551155
pub struct Static<'tcx> {
11561156
pub def_id: DefId,
11571157
pub ty: Ty<'tcx>,

‎src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
10281028
"emit EndRegion as part of MIR; enable transforms that solely process EndRegion"),
10291029
borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
10301030
"select which borrowck is used (`ast`, `mir`, or `compare`)"),
1031+
two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
1032+
"use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"),
10311033
time_passes: bool = (false, parse_bool, [UNTRACKED],
10321034
"measure time of each rustc pass"),
10331035
count_llvm_insns: bool = (false, parse_bool,

‎src/librustc_data_structures/indexed_set.rs

+20
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use std::borrow::{Borrow, BorrowMut, ToOwned};
1112
use std::fmt;
1213
use std::iter;
1314
use std::marker::PhantomData;
@@ -73,6 +74,25 @@ pub struct IdxSet<T: Idx> {
7374
bits: [Word],
7475
}
7576

77+
impl<T: Idx> Borrow<IdxSet<T>> for IdxSetBuf<T> {
78+
fn borrow(&self) -> &IdxSet<T> {
79+
&*self
80+
}
81+
}
82+
83+
impl<T: Idx> BorrowMut<IdxSet<T>> for IdxSetBuf<T> {
84+
fn borrow_mut(&mut self) -> &mut IdxSet<T> {
85+
&mut *self
86+
}
87+
}
88+
89+
impl<T: Idx> ToOwned for IdxSet<T> {
90+
type Owned = IdxSetBuf<T>;
91+
fn to_owned(&self) -> Self::Owned {
92+
IdxSet::to_owned(self)
93+
}
94+
}
95+
7696
impl<T: Idx> fmt::Debug for IdxSetBuf<T> {
7797
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
7898
w.debug_list()

‎src/librustc_driver/pretty.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -423,24 +423,28 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
423423
pprust_hir::NodeName(_) => Ok(()),
424424
pprust_hir::NodeItem(item) => {
425425
s.s.space()?;
426-
s.synth_comment(item.id.to_string())
426+
s.synth_comment(format!("node_id: {} hir local_id: {}",
427+
item.id, item.hir_id.local_id.0))
427428
}
428429
pprust_hir::NodeSubItem(id) => {
429430
s.s.space()?;
430431
s.synth_comment(id.to_string())
431432
}
432433
pprust_hir::NodeBlock(blk) => {
433434
s.s.space()?;
434-
s.synth_comment(format!("block {}", blk.id))
435+
s.synth_comment(format!("block node_id: {} hir local_id: {}",
436+
blk.id, blk.hir_id.local_id.0))
435437
}
436438
pprust_hir::NodeExpr(expr) => {
437439
s.s.space()?;
438-
s.synth_comment(expr.id.to_string())?;
440+
s.synth_comment(format!("node_id: {} hir local_id: {}",
441+
expr.id, expr.hir_id.local_id.0))?;
439442
s.pclose()
440443
}
441444
pprust_hir::NodePat(pat) => {
442445
s.s.space()?;
443-
s.synth_comment(format!("pat {}", pat.id))
446+
s.synth_comment(format!("pat node_id: {} hir local_id: {}",
447+
pat.id, pat.hir_id.local_id.0))
444448
}
445449
}
446450
}

‎src/librustc_mir/borrow_check/error_reporting.rs

+11-14
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
use syntax_pos::Span;
1212
use rustc::middle::region::ScopeTree;
1313
use rustc::mir::{BorrowKind, Field, Local, Location, Operand};
14-
use rustc::mir::{Place, ProjectionElem, Rvalue, StatementKind};
14+
use rustc::mir::{Place, ProjectionElem, Rvalue, Statement, StatementKind};
1515
use rustc::ty::{self, RegionKind};
1616
use rustc_data_structures::indexed_vec::Idx;
1717

1818
use std::rc::Rc;
1919

2020
use super::{MirBorrowckCtxt, Context};
2121
use super::{InitializationRequiringAction, PrefixSet};
22-
use dataflow::{BorrowData, Borrows, FlowAtLocation, MovingOutStatements};
22+
use dataflow::{ActiveBorrows, BorrowData, FlowAtLocation, MovingOutStatements};
2323
use dataflow::move_paths::MovePathIndex;
2424
use util::borrowck_errors::{BorrowckErrors, Origin};
2525

@@ -96,7 +96,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
9696
Some(name) => format!("`{}`", name),
9797
None => "value".to_owned(),
9898
};
99-
let borrow_msg = match self.describe_place(&borrow.place) {
99+
let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
100100
Some(name) => format!("`{}`", name),
101101
None => "value".to_owned(),
102102
};
@@ -124,7 +124,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
124124
span,
125125
&self.describe_place(place).unwrap_or("_".to_owned()),
126126
self.retrieve_borrow_span(borrow),
127-
&self.describe_place(&borrow.place).unwrap_or("_".to_owned()),
127+
&self.describe_place(&borrow.borrowed_place).unwrap_or("_".to_owned()),
128128
Origin::Mir,
129129
);
130130

@@ -143,12 +143,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
143143
use rustc::hir::ExprClosure;
144144
use rustc::mir::AggregateKind;
145145

146-
let local = if let StatementKind::Assign(Place::Local(local), _) =
147-
self.mir[location.block].statements[location.statement_index].kind
148-
{
149-
local
150-
} else {
151-
return None;
146+
let local = match self.mir[location.block].statements.get(location.statement_index) {
147+
Some(&Statement { kind: StatementKind::Assign(Place::Local(local), _), .. }) => local,
148+
_ => return None,
152149
};
153150

154151
for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
@@ -324,11 +321,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
324321
_: Context,
325322
borrow: &BorrowData<'tcx>,
326323
drop_span: Span,
327-
borrows: &Borrows<'cx, 'gcx, 'tcx>
324+
borrows: &ActiveBorrows<'cx, 'gcx, 'tcx>
328325
) {
329326
let end_span = borrows.opt_region_end_span(&borrow.region);
330-
let scope_tree = borrows.scope_tree();
331-
let root_place = self.prefixes(&borrow.place, PrefixSet::All).last().unwrap();
327+
let scope_tree = borrows.0.scope_tree();
328+
let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All).last().unwrap();
332329

333330
match root_place {
334331
&Place::Local(local) => {
@@ -357,7 +354,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
357354
_ => drop_span,
358355
};
359356

360-
match (borrow.region, &self.describe_place(&borrow.place)) {
357+
match (borrow.region, &self.describe_place(&borrow.borrowed_place)) {
361358
(RegionKind::ReScope(_), Some(name)) => {
362359
self.report_scoped_local_value_does_not_live_long_enough(
363360
name, &scope_tree, &borrow, drop_span, borrow_span, proper_span, end_span);

‎src/librustc_mir/borrow_check/flows.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ use rustc::mir::{BasicBlock, Location};
1717

1818
use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
1919
use dataflow::{EverInitializedLvals, MovingOutStatements};
20-
use dataflow::{Borrows, FlowAtLocation, FlowsAtLocation};
20+
use dataflow::{ActiveBorrows, FlowAtLocation, FlowsAtLocation};
2121
use dataflow::move_paths::HasMoveData;
2222
use std::fmt;
2323

2424
// (forced to be `pub` due to its use as an associated type below.)
25-
pub struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
26-
pub borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
25+
pub(crate) struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
26+
pub borrows: FlowAtLocation<ActiveBorrows<'b, 'gcx, 'tcx>>,
2727
pub inits: FlowAtLocation<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
2828
pub uninits: FlowAtLocation<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
2929
pub move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
@@ -32,7 +32,7 @@ pub struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
3232

3333
impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> {
3434
pub fn new(
35-
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
35+
borrows: FlowAtLocation<ActiveBorrows<'b, 'gcx, 'tcx>>,
3636
inits: FlowAtLocation<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
3737
uninits: FlowAtLocation<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
3838
move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
@@ -87,7 +87,7 @@ impl<'b, 'gcx, 'tcx> fmt::Display for Flows<'b, 'gcx, 'tcx> {
8787
s.push_str(", ");
8888
};
8989
saw_one = true;
90-
let borrow_data = &self.borrows.operator().borrows()[borrow];
90+
let borrow_data = &self.borrows.operator().borrows()[borrow.borrow_index()];
9191
s.push_str(&format!("{}", borrow_data));
9292
});
9393
s.push_str("] ");
@@ -99,7 +99,7 @@ impl<'b, 'gcx, 'tcx> fmt::Display for Flows<'b, 'gcx, 'tcx> {
9999
s.push_str(", ");
100100
};
101101
saw_one = true;
102-
let borrow_data = &self.borrows.operator().borrows()[borrow];
102+
let borrow_data = &self.borrows.operator().borrows()[borrow.borrow_index()];
103103
s.push_str(&format!("{}", borrow_data));
104104
});
105105
s.push_str("] ");

‎src/librustc_mir/borrow_check/mod.rs

+207-37
Large diffs are not rendered by default.

‎src/librustc_mir/dataflow/at_location.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ use rustc_data_structures::indexed_vec::Idx;
1818
use dataflow::{BitDenotation, BlockSets, DataflowResults};
1919
use dataflow::move_paths::{HasMoveData, MovePathIndex};
2020

21+
use std::iter;
22+
2123
/// A trait for "cartesian products" of multiple FlowAtLocation.
2224
///
2325
/// There's probably a way to auto-impl this, but I think
@@ -94,9 +96,9 @@ where
9496
self.curr_state.contains(x)
9597
}
9698

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

102104
pub fn with_elems_outgoing<F>(&self, f: F)
@@ -121,9 +123,8 @@ impl<BD> FlowsAtLocation for FlowAtLocation<BD>
121123
fn reconstruct_statement_effect(&mut self, loc: Location) {
122124
self.stmt_gen.reset_to_empty();
123125
self.stmt_kill.reset_to_empty();
124-
let mut ignored = IdxSetBuf::new_empty(0);
125126
let mut sets = BlockSets {
126-
on_entry: &mut ignored,
127+
on_entry: &mut self.curr_state,
127128
gen_set: &mut self.stmt_gen,
128129
kill_set: &mut self.stmt_kill,
129130
};
@@ -135,9 +136,8 @@ impl<BD> FlowsAtLocation for FlowAtLocation<BD>
135136
fn reconstruct_terminator_effect(&mut self, loc: Location) {
136137
self.stmt_gen.reset_to_empty();
137138
self.stmt_kill.reset_to_empty();
138-
let mut ignored = IdxSetBuf::new_empty(0);
139139
let mut sets = BlockSets {
140-
on_entry: &mut ignored,
140+
on_entry: &mut self.curr_state,
141141
gen_set: &mut self.stmt_gen,
142142
kill_set: &mut self.stmt_kill,
143143
};

‎src/librustc_mir/dataflow/graphviz.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc_data_structures::indexed_vec::Idx;
1818
use dot;
1919
use dot::IntoCow;
2020

21-
use std::fmt::Debug;
2221
use std::fs::File;
2322
use std::io;
2423
use std::io::prelude::*;
@@ -29,6 +28,7 @@ use util;
2928

3029
use super::{BitDenotation, DataflowState};
3130
use super::DataflowBuilder;
31+
use super::DebugFormatted;
3232

3333
pub trait MirWithFlowState<'tcx> {
3434
type BD: BitDenotation;
@@ -60,9 +60,9 @@ pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
6060
render_idx: P)
6161
-> io::Result<()>
6262
where BD: BitDenotation,
63-
P: Fn(&BD, BD::Idx) -> &Debug
63+
P: Fn(&BD, BD::Idx) -> DebugFormatted
6464
{
65-
let g = Graph { mbcx: mbcx, phantom: PhantomData, render_idx: render_idx };
65+
let g = Graph { mbcx, phantom: PhantomData, render_idx };
6666
let mut v = Vec::new();
6767
dot::render(&g, &mut v)?;
6868
debug!("print_borrowck_graph_to path: {} node_id: {}",
@@ -82,7 +82,7 @@ fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
8282

8383
impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
8484
where MWF: MirWithFlowState<'tcx>,
85-
P: for <'b> Fn(&'b MWF::BD, <MWF::BD as BitDenotation>::Idx) -> &'b Debug,
85+
P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
8686
{
8787
type Node = Node;
8888
type Edge = Edge;
@@ -142,7 +142,7 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
142142
const ALIGN_RIGHT: &'static str = r#"align="right""#;
143143
const FACE_MONOSPACE: &'static str = r#"FACE="Courier""#;
144144
fn chunked_present_left<W:io::Write>(w: &mut W,
145-
interpreted: &[&Debug],
145+
interpreted: &[DebugFormatted],
146146
chunk_size: usize)
147147
-> io::Result<()>
148148
{

‎src/librustc_mir/dataflow/impls/borrows.rs

+432-83
Large diffs are not rendered by default.

‎src/librustc_mir/dataflow/impls/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use util::elaborate_drops::DropFlagState;
2323

2424
use super::move_paths::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex, InitIndex};
2525
use super::move_paths::{LookupResult, InitKind};
26-
use super::{BitDenotation, BlockSets, DataflowOperator};
26+
use super::{BitDenotation, BlockSets, InitialFlow};
2727

2828
use super::drop_flag_effects_for_function_entry;
2929
use super::drop_flag_effects_for_location;
@@ -702,35 +702,35 @@ impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedLvals<'a, 'gcx, 'tcx> {
702702
// propagating, or you start at all-ones and then use Intersect as
703703
// your merge when propagating.
704704

705-
impl<'a, 'gcx, 'tcx> DataflowOperator for MaybeInitializedLvals<'a, 'gcx, 'tcx> {
705+
impl<'a, 'gcx, 'tcx> InitialFlow for MaybeInitializedLvals<'a, 'gcx, 'tcx> {
706706
#[inline]
707707
fn bottom_value() -> bool {
708708
false // bottom = uninitialized
709709
}
710710
}
711711

712-
impl<'a, 'gcx, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'gcx, 'tcx> {
712+
impl<'a, 'gcx, 'tcx> InitialFlow for MaybeUninitializedLvals<'a, 'gcx, 'tcx> {
713713
#[inline]
714714
fn bottom_value() -> bool {
715715
false // bottom = initialized (start_block_effect counters this at outset)
716716
}
717717
}
718718

719-
impl<'a, 'gcx, 'tcx> DataflowOperator for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> {
719+
impl<'a, 'gcx, 'tcx> InitialFlow for DefinitelyInitializedLvals<'a, 'gcx, 'tcx> {
720720
#[inline]
721721
fn bottom_value() -> bool {
722722
true // bottom = initialized (start_block_effect counters this at outset)
723723
}
724724
}
725725

726-
impl<'a, 'gcx, 'tcx> DataflowOperator for MovingOutStatements<'a, 'gcx, 'tcx> {
726+
impl<'a, 'gcx, 'tcx> InitialFlow for MovingOutStatements<'a, 'gcx, 'tcx> {
727727
#[inline]
728728
fn bottom_value() -> bool {
729729
false // bottom = no loans in scope by default
730730
}
731731
}
732732

733-
impl<'a, 'gcx, 'tcx> DataflowOperator for EverInitializedLvals<'a, 'gcx, 'tcx> {
733+
impl<'a, 'gcx, 'tcx> InitialFlow for EverInitializedLvals<'a, 'gcx, 'tcx> {
734734
#[inline]
735735
fn bottom_value() -> bool {
736736
false // bottom = no initialized variables by default

‎src/librustc_mir/dataflow/impls/storage_liveness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl<'a, 'tcx> BitwiseOperator for MaybeStorageLive<'a, 'tcx> {
7474
}
7575
}
7676

77-
impl<'a, 'tcx> DataflowOperator for MaybeStorageLive<'a, 'tcx> {
77+
impl<'a, 'tcx> InitialFlow for MaybeStorageLive<'a, 'tcx> {
7878
#[inline]
7979
fn bottom_value() -> bool {
8080
false // bottom = dead

‎src/librustc_mir/dataflow/mod.rs

+162-74
Large diffs are not rendered by default.

‎src/librustc_mir/dataflow/move_paths/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ pub(crate) mod indexes {
6565

6666
/// Index into Borrows.locations
6767
new_index!(BorrowIndex, "bw");
68+
69+
/// Index into Reservations/Activations bitvector
70+
new_index!(ReserveOrActivateIndex, "ra");
6871
}
6972

7073
pub use self::indexes::MovePathIndex;

‎src/librustc_mir/transform/elaborate_drops.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use dataflow::{DataflowResults};
1414
use dataflow::{on_all_children_bits, on_all_drop_children_bits};
1515
use dataflow::{drop_flag_effects_for_location, on_lookup_result_bits};
1616
use dataflow::MoveDataParamEnv;
17-
use dataflow;
17+
use dataflow::{self, do_dataflow, DebugFormatted};
1818
use rustc::hir;
1919
use rustc::ty::{self, TyCtxt};
2020
use rustc::mir::*;
@@ -59,13 +59,13 @@ impl MirPass for ElaborateDrops {
5959
};
6060
let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env);
6161
let flow_inits =
62-
dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
63-
MaybeInitializedLvals::new(tcx, mir, &env),
64-
|bd, p| &bd.move_data().move_paths[p]);
62+
do_dataflow(tcx, mir, id, &[], &dead_unwinds,
63+
MaybeInitializedLvals::new(tcx, mir, &env),
64+
|bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
6565
let flow_uninits =
66-
dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
67-
MaybeUninitializedLvals::new(tcx, mir, &env),
68-
|bd, p| &bd.move_data().move_paths[p]);
66+
do_dataflow(tcx, mir, id, &[], &dead_unwinds,
67+
MaybeUninitializedLvals::new(tcx, mir, &env),
68+
|bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
6969

7070
ElaborateDropsCtxt {
7171
tcx,
@@ -96,9 +96,9 @@ fn find_dead_unwinds<'a, 'tcx>(
9696
// reach cleanup blocks, which can't have unwind edges themselves.
9797
let mut dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
9898
let flow_inits =
99-
dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
100-
MaybeInitializedLvals::new(tcx, mir, &env),
101-
|bd, p| &bd.move_data().move_paths[p]);
99+
do_dataflow(tcx, mir, id, &[], &dead_unwinds,
100+
MaybeInitializedLvals::new(tcx, mir, &env),
101+
|bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
102102
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
103103
let location = match bb_data.terminator().kind {
104104
TerminatorKind::Drop { ref location, unwind: Some(_), .. } |

‎src/librustc_mir/transform/generator.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ use std::mem;
7878
use transform::{MirPass, MirSource};
7979
use transform::simplify;
8080
use transform::no_landing_pads::no_landing_pads;
81-
use dataflow::{self, MaybeStorageLive, state_for_location};
81+
use dataflow::{do_dataflow, DebugFormatted, MaybeStorageLive, state_for_location};
8282

8383
pub struct StateTransform;
8484

@@ -341,8 +341,8 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
341341
let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap();
342342
let analysis = MaybeStorageLive::new(mir);
343343
let storage_live =
344-
dataflow::do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
345-
|bd, p| &bd.mir().local_decls[p]);
344+
do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
345+
|bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
346346

347347
let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len()));
348348
ignored.visit_mir(mir);

‎src/librustc_mir/transform/rustc_peek.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_data_structures::indexed_set::IdxSetBuf;
1818
use rustc_data_structures::indexed_vec::Idx;
1919
use transform::{MirPass, MirSource};
2020

21-
use dataflow::do_dataflow;
21+
use dataflow::{do_dataflow, DebugFormatted};
2222
use dataflow::MoveDataParamEnv;
2323
use dataflow::BitDenotation;
2424
use dataflow::DataflowResults;
@@ -51,15 +51,15 @@ impl MirPass for SanityCheck {
5151
let flow_inits =
5252
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
5353
MaybeInitializedLvals::new(tcx, mir, &mdpe),
54-
|bd, i| &bd.move_data().move_paths[i]);
54+
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]));
5555
let flow_uninits =
5656
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
5757
MaybeUninitializedLvals::new(tcx, mir, &mdpe),
58-
|bd, i| &bd.move_data().move_paths[i]);
58+
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]));
5959
let flow_def_inits =
6060
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
6161
DefinitelyInitializedLvals::new(tcx, mir, &mdpe),
62-
|bd, i| &bd.move_data().move_paths[i]);
62+
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]));
6363

6464
if has_rustc_mir_with(&attributes, "rustc_peek_maybe_init").is_some() {
6565
sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_inits);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: lxl nll
12+
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
13+
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
14+
15+
// This is an important corner case pointed out by Niko: one is
16+
// allowed to initiate a shared borrow during a reservation, but it
17+
// *must end* before the activation occurs.
18+
//
19+
// FIXME: for clarity, diagnostics for these cases might be better off
20+
// if they specifically said "cannot activate mutable borrow of `x`"
21+
22+
#![allow(dead_code)]
23+
24+
fn read(_: &i32) { }
25+
26+
fn ok() {
27+
let mut x = 3;
28+
let y = &mut x;
29+
{ let z = &x; read(z); }
30+
*y += 1;
31+
}
32+
33+
fn not_ok() {
34+
let mut x = 3;
35+
let y = &mut x;
36+
let z = &x;
37+
*y += 1;
38+
//[lxl]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
39+
//[nll]~^^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
40+
read(z);
41+
}
42+
43+
fn should_be_ok_with_nll() {
44+
let mut x = 3;
45+
let y = &mut x;
46+
let z = &x;
47+
read(z);
48+
*y += 1;
49+
//[lxl]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
50+
// (okay with nll today)
51+
}
52+
53+
fn should_also_eventually_be_ok_with_nll() {
54+
let mut x = 3;
55+
let y = &mut x;
56+
let _z = &x;
57+
*y += 1;
58+
//[lxl]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
59+
//[nll]~^^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
60+
}
61+
62+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: lxl nll
12+
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
13+
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
14+
15+
// This is the second counter-example from Niko's blog post
16+
// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/
17+
//
18+
// It is "artificial". It is meant to illustrate directly that we
19+
// should allow an aliasing access during reservation, but *not* while
20+
// the mutable borrow is active.
21+
22+
fn main() {
23+
/*0*/ let mut i = 0;
24+
25+
/*1*/ let p = &mut i; // (reservation of `i` starts here)
26+
27+
/*2*/ let j = i; // OK: `i` is only reserved here
28+
29+
/*3*/ *p += 1; // (mutable borrow of `i` starts here, since `p` is used)
30+
31+
/*4*/ let k = i; //[lxl]~ ERROR cannot use `i` because it was mutably borrowed [E0503]
32+
//[nll]~^ ERROR cannot use `i` because it was mutably borrowed [E0503]
33+
34+
/*5*/ *p += 1;
35+
36+
let _ = (j, k, p);
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: lxl nll
12+
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
13+
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
14+
15+
// This is the third counter-example from Niko's blog post
16+
// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/
17+
//
18+
// It shows that not all nested method calls on `self` are magically
19+
// allowed by this change. In particular, a nested `&mut` borrow is
20+
// still disallowed.
21+
22+
fn main() {
23+
24+
25+
let mut vec = vec![0, 1];
26+
vec.get({
27+
28+
vec.push(2);
29+
//[lxl]~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
30+
//[nll]~^^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
31+
32+
0
33+
});
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: lxl nll
12+
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
13+
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
14+
15+
// This is similar to two-phase-reservation-sharing-interference.rs
16+
// in that it shows a reservation that overlaps with a shared borrow.
17+
//
18+
// Currently, this test fails with lexical lifetimes, but succeeds
19+
// with non-lexical lifetimes. (The reason is because the activation
20+
// of the mutable borrow ends up overlapping with a lexically-scoped
21+
// shared borrow; but a non-lexical shared borrow can end before the
22+
// activation occurs.)
23+
//
24+
// So this test is just making a note of the current behavior.
25+
26+
#![feature(rustc_attrs)]
27+
28+
#[rustc_error]
29+
fn main() { //[nll]~ ERROR compilation successful
30+
let mut v = vec![0, 1, 2];
31+
let shared = &v;
32+
33+
v.push(shared.len());
34+
//[lxl]~^ ERROR cannot borrow `v` as mutable because it is also borrowed as immutable [E0502]
35+
36+
assert_eq!(v, [0, 1, 2, 3]);
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: lxl nll
12+
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
13+
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
14+
15+
// This is a corner case that the current implementation is (probably)
16+
// treating more conservatively than is necessary. But it also does
17+
// not seem like a terribly important use case to cover.
18+
//
19+
// So this test is just making a note of the current behavior, with
20+
// the caveat that in the future, the rules may be loosened, at which
21+
// point this test might be thrown out.
22+
23+
fn main() {
24+
let mut vec = vec![0, 1];
25+
let delay: &mut Vec<_>;
26+
{
27+
let shared = &vec;
28+
29+
// we reserve here, which could (on its own) be compatible
30+
// with the shared borrow. But in the current implementation,
31+
// its an error.
32+
delay = &mut vec;
33+
//[lxl]~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
34+
//[nll]~^^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
35+
36+
shared[0];
37+
}
38+
39+
// the &mut-borrow only becomes active way down here.
40+
//
41+
// (At least in theory; part of the reason this test fails is that
42+
// the constructed MIR throws in extra &mut reborrows which
43+
// flummoxes our attmpt to delay the activation point here.)
44+
delay.push(2);
45+
}
46+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: lxl nll
12+
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
13+
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
14+
15+
// This is the first counter-example from Niko's blog post
16+
// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/
17+
// of a danger for code to crash if we just turned off the check for whether
18+
// a mutable-borrow aliases another borrow.
19+
20+
fn main() {
21+
let mut v: Vec<String> = vec![format!("Hello, ")];
22+
v[0].push_str({
23+
24+
v.push(format!("foo"));
25+
//[lxl]~^ ERROR cannot borrow `v` as mutable more than once at a time [E0499]
26+
//[nll]~^^ ERROR cannot borrow `v` as mutable more than once at a time [E0499]
27+
28+
"World!"
29+
});
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: lxl nll
12+
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
13+
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
14+
15+
// This is the "goto example" for why we want two phase borrows.
16+
17+
fn main() {
18+
let mut v = vec![0, 1, 2];
19+
v.push(v.len());
20+
assert_eq!(v, [0, 1, 2, 3]);
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: lxl nll
12+
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
13+
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
14+
15+
fn main() {
16+
let mut a = 0;
17+
let mut b = 0;
18+
let p = if maybe() {
19+
&mut a
20+
} else {
21+
&mut b
22+
};
23+
use_(p);
24+
}
25+
26+
fn maybe() -> bool { false }
27+
fn use_<T>(_: T) { }

0 commit comments

Comments
 (0)
Please sign in to comment.