Skip to content

Commit 018784a

Browse files
committed
MIR based borrow check (opt-in).
One can either use `-Z borrowck-mir` or add the `#[rustc_mir_borrowck]` attribute to opt into MIR based borrow checking. Note that regardless of whether one opts in or not, AST-based borrow check will still run as well. The errors emitted from AST-based borrow check will include a "(Ast)" suffix in their error message, while the errors emitted from MIR-based borrow check will include a "(Mir)" suffix. post-rebase: removed check for intra-statement mutual conflict; replaced with assertion checking that at most one borrow is generated per statement. post-rebase: removed dead code: `IdxSet::pairs` and supporting stuff.
1 parent 869f05a commit 018784a

File tree

7 files changed

+1422
-4
lines changed

7 files changed

+1422
-4
lines changed

src/librustc/session/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
918918
"when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
919919
identify_regions: bool = (false, parse_bool, [UNTRACKED],
920920
"make unnamed regions display as '# (where # is some non-ident unique id)"),
921+
borrowck_mir: bool = (false, parse_bool, [UNTRACKED],
922+
"implicitly treat functions as if they have `#[rustc_mir_borrowck]` attribute"),
921923
time_passes: bool = (false, parse_bool, [UNTRACKED],
922924
"measure time of each rustc pass"),
923925
count_llvm_insns: bool = (false, parse_bool,

src/librustc_data_structures/indexed_set.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,36 @@ impl<T: Idx> IdxSet<T> {
159159
pub fn each_bit<F>(&self, max_bits: usize, f: F) where F: FnMut(T) {
160160
each_bit(self, max_bits, f)
161161
}
162+
163+
/// Removes all elements from this set.
164+
pub fn reset_to_empty(&mut self) {
165+
for word in self.words_mut() { *word = 0; }
166+
}
167+
168+
pub fn elems(&self, universe_size: usize) -> Elems<T> {
169+
Elems { i: 0, set: self, universe_size: universe_size }
170+
}
171+
}
172+
173+
pub struct Elems<'a, T: Idx> { i: usize, set: &'a IdxSet<T>, universe_size: usize }
174+
175+
impl<'a, T: Idx> Iterator for Elems<'a, T> {
176+
type Item = T;
177+
fn next(&mut self) -> Option<T> {
178+
if self.i >= self.universe_size { return None; }
179+
let mut i = self.i;
180+
loop {
181+
if i >= self.universe_size {
182+
self.i = i; // (mark iteration as complete.)
183+
return None;
184+
}
185+
if self.set.contains(&T::new(i)) {
186+
self.i = i + 1; // (next element to start at.)
187+
return Some(T::new(i));
188+
}
189+
i = i + 1;
190+
}
191+
}
162192
}
163193

164194
fn each_bit<T: Idx, F>(words: &IdxSet<T>, max_bits: usize, mut f: F) where F: FnMut(T) {

src/librustc_driver/driver.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
970970
// We compute "constant qualifications" between MIR_CONST and MIR_VALIDATED.
971971

972972
// What we need to run borrowck etc.
973+
passes.push_pass(MIR_CONST, mir::transform::borrow_check::BorrowckMir);
973974
passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
974975
passes.push_pass(MIR_VALIDATED,
975976
mir::transform::simplify_branches::SimplifyBranches::new("initial"));

src/librustc_mir/dataflow/mod.rs

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_data_structures::indexed_vec::Idx;
1515
use rustc_data_structures::bitslice::{bitwise, BitwiseOperator};
1616

1717
use rustc::ty::{self, TyCtxt};
18-
use rustc::mir::{self, Mir, BasicBlock, Location};
18+
use rustc::mir::{self, Mir, BasicBlock, BasicBlockData, Location, Statement, Terminator};
1919
use rustc::session::Session;
2020

2121
use std::fmt::{self, Debug};
@@ -47,7 +47,19 @@ pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD> where BD: BitDenotation
4747
}
4848

4949
pub trait Dataflow<BD: BitDenotation> {
50-
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug;
50+
/// Sets up and runs the dataflow problem, using `p` to render results if
51+
/// implementation so chooses.
52+
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug {
53+
let _ = p; // default implementation does not instrument process.
54+
self.build_sets();
55+
self.propagate();
56+
}
57+
58+
/// Sets up the entry, gen, and kill sets for this instance of a dataflow problem.
59+
fn build_sets(&mut self);
60+
61+
/// Finds a fixed-point solution to this instance of a dataflow problem.
62+
fn propagate(&mut self);
5163
}
5264

5365
impl<'a, 'tcx: 'a, BD> Dataflow<BD> for DataflowBuilder<'a, 'tcx, BD>
@@ -59,6 +71,9 @@ impl<'a, 'tcx: 'a, BD> Dataflow<BD> for DataflowBuilder<'a, 'tcx, BD>
5971
self.flow_state.propagate();
6072
self.post_dataflow_instrumentation(|c,i| p(c,i)).unwrap();
6173
}
74+
75+
fn build_sets(&mut self) { self.flow_state.build_sets(); }
76+
fn propagate(&mut self) { self.flow_state.propagate(); }
6277
}
6378

6479
pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem> {
@@ -254,6 +269,93 @@ impl<E:Idx> Bits<E> {
254269
}
255270
}
256271

272+
/// DataflowResultsConsumer abstracts over walking the MIR with some
273+
/// already constructed dataflow results.
274+
///
275+
/// It abstracts over the FlowState and also completely hides the
276+
/// underlying flow analysis results, because it needs to handle cases
277+
/// where we are combining the results of *multiple* flow analyses
278+
/// (e.g. borrows + inits + uninits).
279+
pub trait DataflowResultsConsumer<'a, 'tcx: 'a> {
280+
type FlowState;
281+
282+
// Observation Hooks: override (at least one of) these to get analysis feedback.
283+
fn visit_block_entry(&mut self,
284+
_bb: BasicBlock,
285+
_flow_state: &Self::FlowState) {}
286+
287+
fn visit_statement_entry(&mut self,
288+
_loc: Location,
289+
_stmt: &Statement<'tcx>,
290+
_flow_state: &Self::FlowState) {}
291+
292+
fn visit_terminator_entry(&mut self,
293+
_loc: Location,
294+
_term: &Terminator<'tcx>,
295+
_flow_state: &Self::FlowState) {}
296+
297+
// Main entry point: this drives the processing of results.
298+
299+
fn analyze_results(&mut self, flow_uninit: &mut Self::FlowState) {
300+
let flow = flow_uninit;
301+
for bb in self.mir().basic_blocks().indices() {
302+
self.reset_to_entry_of(bb, flow);
303+
self.process_basic_block(bb, flow);
304+
}
305+
}
306+
307+
fn process_basic_block(&mut self, bb: BasicBlock, flow_state: &mut Self::FlowState) {
308+
let BasicBlockData { ref statements, ref terminator, is_cleanup: _ } =
309+
self.mir()[bb];
310+
let mut location = Location { block: bb, statement_index: 0 };
311+
for stmt in statements.iter() {
312+
self.reconstruct_statement_effect(location, flow_state);
313+
self.visit_statement_entry(location, stmt, flow_state);
314+
self.apply_local_effect(location, flow_state);
315+
location.statement_index += 1;
316+
}
317+
318+
if let Some(ref term) = *terminator {
319+
self.reconstruct_terminator_effect(location, flow_state);
320+
self.visit_terminator_entry(location, term, flow_state);
321+
322+
// We don't need to apply the effect of the terminator,
323+
// since we are only visiting dataflow state on control
324+
// flow entry to the various nodes. (But we still need to
325+
// reconstruct the effect, because the visit method might
326+
// inspect it.)
327+
}
328+
}
329+
330+
// Delegated Hooks: Provide access to the MIR and process the flow state.
331+
332+
fn mir(&self) -> &'a Mir<'tcx>;
333+
334+
// reset the state bitvector to represent the entry to block `bb`.
335+
fn reset_to_entry_of(&mut self,
336+
bb: BasicBlock,
337+
flow_state: &mut Self::FlowState);
338+
339+
// build gen + kill sets for statement at `loc`.
340+
fn reconstruct_statement_effect(&mut self,
341+
loc: Location,
342+
flow_state: &mut Self::FlowState);
343+
344+
// build gen + kill sets for terminator for `loc`.
345+
fn reconstruct_terminator_effect(&mut self,
346+
loc: Location,
347+
flow_state: &mut Self::FlowState);
348+
349+
// apply current gen + kill sets to `flow_state`.
350+
//
351+
// (`bb` and `stmt_idx` parameters can be ignored if desired by
352+
// client. For the terminator, the `stmt_idx` will be the number
353+
// of statements in the block.)
354+
fn apply_local_effect(&mut self,
355+
loc: Location,
356+
flow_state: &mut Self::FlowState);
357+
}
358+
257359
pub struct DataflowAnalysis<'a, 'tcx: 'a, O>
258360
where O: BitDenotation
259361
{
@@ -269,6 +371,8 @@ impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O>
269371
DataflowResults(self.flow_state)
270372
}
271373

374+
pub fn flow_state(&self) -> &DataflowState<O> { &self.flow_state }
375+
272376
pub fn mir(&self) -> &'a Mir<'tcx> { self.mir }
273377
}
274378

@@ -278,10 +382,14 @@ impl<O: BitDenotation> DataflowResults<O> {
278382
pub fn sets(&self) -> &AllSets<O::Idx> {
279383
&self.0.sets
280384
}
385+
386+
pub fn operator(&self) -> &O {
387+
&self.0.operator
388+
}
281389
}
282390

283-
// FIXME: This type shouldn't be public, but the graphviz::MirWithFlowState trait
284-
// references it in a method signature. Look into using `pub(crate)` to address this.
391+
/// State of a dataflow analysis; couples a collection of bit sets
392+
/// with operator used to initialize and merge bits during analysis.
285393
pub struct DataflowState<O: BitDenotation>
286394
{
287395
/// All the sets for the analysis. (Factored into its

src/librustc_mir/dataflow/move_paths/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ impl<'tcx> fmt::Debug for MovePath<'tcx> {
108108
}
109109
}
110110

111+
impl<'tcx> fmt::Display for MovePath<'tcx> {
112+
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
113+
write!(w, "{:?}", self.lvalue)
114+
}
115+
}
116+
111117
#[derive(Debug)]
112118
pub struct MoveData<'tcx> {
113119
pub move_paths: IndexVec<MovePathIndex, MovePath<'tcx>>,

0 commit comments

Comments
 (0)