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.
This commit is contained in:
parent
869f05a521
commit
018784afc9
@ -918,6 +918,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
|
||||
identify_regions: bool = (false, parse_bool, [UNTRACKED],
|
||||
"make unnamed regions display as '# (where # is some non-ident unique id)"),
|
||||
borrowck_mir: bool = (false, parse_bool, [UNTRACKED],
|
||||
"implicitly treat functions as if they have `#[rustc_mir_borrowck]` attribute"),
|
||||
time_passes: bool = (false, parse_bool, [UNTRACKED],
|
||||
"measure time of each rustc pass"),
|
||||
count_llvm_insns: bool = (false, parse_bool,
|
||||
|
@ -159,6 +159,36 @@ impl<T: Idx> IdxSet<T> {
|
||||
pub fn each_bit<F>(&self, max_bits: usize, f: F) where F: FnMut(T) {
|
||||
each_bit(self, max_bits, f)
|
||||
}
|
||||
|
||||
/// Removes all elements from this set.
|
||||
pub fn reset_to_empty(&mut self) {
|
||||
for word in self.words_mut() { *word = 0; }
|
||||
}
|
||||
|
||||
pub fn elems(&self, universe_size: usize) -> Elems<T> {
|
||||
Elems { i: 0, set: self, universe_size: universe_size }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Elems<'a, T: Idx> { i: usize, set: &'a IdxSet<T>, universe_size: usize }
|
||||
|
||||
impl<'a, T: Idx> Iterator for Elems<'a, T> {
|
||||
type Item = T;
|
||||
fn next(&mut self) -> Option<T> {
|
||||
if self.i >= self.universe_size { return None; }
|
||||
let mut i = self.i;
|
||||
loop {
|
||||
if i >= self.universe_size {
|
||||
self.i = i; // (mark iteration as complete.)
|
||||
return None;
|
||||
}
|
||||
if self.set.contains(&T::new(i)) {
|
||||
self.i = i + 1; // (next element to start at.)
|
||||
return Some(T::new(i));
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn each_bit<T: Idx, F>(words: &IdxSet<T>, max_bits: usize, mut f: F) where F: FnMut(T) {
|
||||
|
@ -970,6 +970,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
// We compute "constant qualifications" between MIR_CONST and MIR_VALIDATED.
|
||||
|
||||
// What we need to run borrowck etc.
|
||||
passes.push_pass(MIR_CONST, mir::transform::borrow_check::BorrowckMir);
|
||||
passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
|
||||
passes.push_pass(MIR_VALIDATED,
|
||||
mir::transform::simplify_branches::SimplifyBranches::new("initial"));
|
||||
|
@ -15,7 +15,7 @@ use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_data_structures::bitslice::{bitwise, BitwiseOperator};
|
||||
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::mir::{self, Mir, BasicBlock, Location};
|
||||
use rustc::mir::{self, Mir, BasicBlock, BasicBlockData, Location, Statement, Terminator};
|
||||
use rustc::session::Session;
|
||||
|
||||
use std::fmt::{self, Debug};
|
||||
@ -47,7 +47,19 @@ pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD> where BD: BitDenotation
|
||||
}
|
||||
|
||||
pub trait Dataflow<BD: BitDenotation> {
|
||||
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug;
|
||||
/// Sets up and runs the dataflow problem, using `p` to render results if
|
||||
/// implementation so chooses.
|
||||
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug {
|
||||
let _ = p; // default implementation does not instrument process.
|
||||
self.build_sets();
|
||||
self.propagate();
|
||||
}
|
||||
|
||||
/// Sets up the entry, gen, and kill sets for this instance of a dataflow problem.
|
||||
fn build_sets(&mut self);
|
||||
|
||||
/// Finds a fixed-point solution to this instance of a dataflow problem.
|
||||
fn propagate(&mut self);
|
||||
}
|
||||
|
||||
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>
|
||||
self.flow_state.propagate();
|
||||
self.post_dataflow_instrumentation(|c,i| p(c,i)).unwrap();
|
||||
}
|
||||
|
||||
fn build_sets(&mut self) { self.flow_state.build_sets(); }
|
||||
fn propagate(&mut self) { self.flow_state.propagate(); }
|
||||
}
|
||||
|
||||
pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem> {
|
||||
@ -254,6 +269,93 @@ impl<E:Idx> Bits<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// DataflowResultsConsumer abstracts over walking the MIR with some
|
||||
/// already constructed dataflow results.
|
||||
///
|
||||
/// It abstracts over the FlowState and also completely hides the
|
||||
/// underlying flow analysis results, because it needs to handle cases
|
||||
/// where we are combining the results of *multiple* flow analyses
|
||||
/// (e.g. borrows + inits + uninits).
|
||||
pub trait DataflowResultsConsumer<'a, 'tcx: 'a> {
|
||||
type FlowState;
|
||||
|
||||
// Observation Hooks: override (at least one of) these to get analysis feedback.
|
||||
fn visit_block_entry(&mut self,
|
||||
_bb: BasicBlock,
|
||||
_flow_state: &Self::FlowState) {}
|
||||
|
||||
fn visit_statement_entry(&mut self,
|
||||
_loc: Location,
|
||||
_stmt: &Statement<'tcx>,
|
||||
_flow_state: &Self::FlowState) {}
|
||||
|
||||
fn visit_terminator_entry(&mut self,
|
||||
_loc: Location,
|
||||
_term: &Terminator<'tcx>,
|
||||
_flow_state: &Self::FlowState) {}
|
||||
|
||||
// Main entry point: this drives the processing of results.
|
||||
|
||||
fn analyze_results(&mut self, flow_uninit: &mut Self::FlowState) {
|
||||
let flow = flow_uninit;
|
||||
for bb in self.mir().basic_blocks().indices() {
|
||||
self.reset_to_entry_of(bb, flow);
|
||||
self.process_basic_block(bb, flow);
|
||||
}
|
||||
}
|
||||
|
||||
fn process_basic_block(&mut self, bb: BasicBlock, flow_state: &mut Self::FlowState) {
|
||||
let BasicBlockData { ref statements, ref terminator, is_cleanup: _ } =
|
||||
self.mir()[bb];
|
||||
let mut location = Location { block: bb, statement_index: 0 };
|
||||
for stmt in statements.iter() {
|
||||
self.reconstruct_statement_effect(location, flow_state);
|
||||
self.visit_statement_entry(location, stmt, flow_state);
|
||||
self.apply_local_effect(location, flow_state);
|
||||
location.statement_index += 1;
|
||||
}
|
||||
|
||||
if let Some(ref term) = *terminator {
|
||||
self.reconstruct_terminator_effect(location, flow_state);
|
||||
self.visit_terminator_entry(location, term, flow_state);
|
||||
|
||||
// We don't need to apply the effect of the terminator,
|
||||
// since we are only visiting dataflow state on control
|
||||
// flow entry to the various nodes. (But we still need to
|
||||
// reconstruct the effect, because the visit method might
|
||||
// inspect it.)
|
||||
}
|
||||
}
|
||||
|
||||
// Delegated Hooks: Provide access to the MIR and process the flow state.
|
||||
|
||||
fn mir(&self) -> &'a Mir<'tcx>;
|
||||
|
||||
// reset the state bitvector to represent the entry to block `bb`.
|
||||
fn reset_to_entry_of(&mut self,
|
||||
bb: BasicBlock,
|
||||
flow_state: &mut Self::FlowState);
|
||||
|
||||
// build gen + kill sets for statement at `loc`.
|
||||
fn reconstruct_statement_effect(&mut self,
|
||||
loc: Location,
|
||||
flow_state: &mut Self::FlowState);
|
||||
|
||||
// build gen + kill sets for terminator for `loc`.
|
||||
fn reconstruct_terminator_effect(&mut self,
|
||||
loc: Location,
|
||||
flow_state: &mut Self::FlowState);
|
||||
|
||||
// apply current gen + kill sets to `flow_state`.
|
||||
//
|
||||
// (`bb` and `stmt_idx` parameters can be ignored if desired by
|
||||
// client. For the terminator, the `stmt_idx` will be the number
|
||||
// of statements in the block.)
|
||||
fn apply_local_effect(&mut self,
|
||||
loc: Location,
|
||||
flow_state: &mut Self::FlowState);
|
||||
}
|
||||
|
||||
pub struct DataflowAnalysis<'a, 'tcx: 'a, O>
|
||||
where O: BitDenotation
|
||||
{
|
||||
@ -269,6 +371,8 @@ impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O>
|
||||
DataflowResults(self.flow_state)
|
||||
}
|
||||
|
||||
pub fn flow_state(&self) -> &DataflowState<O> { &self.flow_state }
|
||||
|
||||
pub fn mir(&self) -> &'a Mir<'tcx> { self.mir }
|
||||
}
|
||||
|
||||
@ -278,10 +382,14 @@ impl<O: BitDenotation> DataflowResults<O> {
|
||||
pub fn sets(&self) -> &AllSets<O::Idx> {
|
||||
&self.0.sets
|
||||
}
|
||||
|
||||
pub fn operator(&self) -> &O {
|
||||
&self.0.operator
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This type shouldn't be public, but the graphviz::MirWithFlowState trait
|
||||
// references it in a method signature. Look into using `pub(crate)` to address this.
|
||||
/// State of a dataflow analysis; couples a collection of bit sets
|
||||
/// with operator used to initialize and merge bits during analysis.
|
||||
pub struct DataflowState<O: BitDenotation>
|
||||
{
|
||||
/// All the sets for the analysis. (Factored into its
|
||||
|
@ -108,6 +108,12 @@ impl<'tcx> fmt::Debug for MovePath<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for MovePath<'tcx> {
|
||||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(w, "{:?}", self.lvalue)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MoveData<'tcx> {
|
||||
pub move_paths: IndexVec<MovePathIndex, MovePath<'tcx>>,
|
||||
|
1270
src/librustc_mir/transform/borrow_check.rs
Normal file
1270
src/librustc_mir/transform/borrow_check.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,7 @@ pub mod simplify;
|
||||
pub mod erase_regions;
|
||||
pub mod no_landing_pads;
|
||||
pub mod type_check;
|
||||
pub mod borrow_check;
|
||||
pub mod rustc_peek;
|
||||
pub mod elaborate_drops;
|
||||
pub mod add_call_guards;
|
||||
|
Loading…
x
Reference in New Issue
Block a user