Auto merge of #42924 - pnkfelix:mir-dataflow, r=arielb1

Shift mir-dataflow from `rustc_borrowck` to `rustc_mir` crate.

Shift mir-dataflow from `rustc_borrowck` to `rustc_mir` crate.

Turn `elaborate_drops` and `rustc_peek` implementations into MIR passes that also live in `rustc_mir` crate.

Rewire things so `rustc_driver` uses the `ElaborateDrops` from `rustc_mir` crate.

(This PR is another baby step for mir-borrowck; it is a piece of work that other people want to rebase their stuff on top of, namely developers who are doing other dataflow analyses on top of MIR.)

I have deliberately architected this PR in an attempt to minimize the number of actual code changes. The majority of the diff should be little more than changes to mod and use declarations, as well as a few visibility promotions to pub(crate) when a declaration was moved downward in the module hierarchy.

(I have no problem with other PR's that move declarations around to try to clean this up; my goal was to ensure that the diff here was as small as possible, to make the review nearly trivial.)
This commit is contained in:
bors 2017-06-30 03:56:33 +00:00
commit a4c68c62f0
13 changed files with 178 additions and 206 deletions

View File

@ -18,8 +18,6 @@ pub use self::bckerr_code::*;
pub use self::AliasableViolationKind::*;
pub use self::MovedValueUseKind::*;
pub use self::mir::elaborate_drops::ElaborateDrops;
use self::InteriorKind::*;
use rustc::hir::map as hir_map;
@ -55,8 +53,6 @@ pub mod gather_loans;
pub mod move_data;
mod mir;
#[derive(Clone, Copy)]
pub struct LoanDataFlowOperator;
@ -100,26 +96,21 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
}
let body_id = tcx.hir.body_owned_by(owner_id);
let attributes = tcx.get_attrs(owner_def_id);
let tables = tcx.typeck_tables_of(owner_def_id);
let region_maps = tcx.region_maps(owner_def_id);
let mut bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id };
let body = bccx.tcx.hir.body(body_id);
if bccx.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") {
mir::borrowck_mir(bccx, owner_id, &attributes);
} else {
// Eventually, borrowck will always read the MIR, but at the
// moment we do not. So, for now, we always force MIR to be
// constructed for a given fn, since this may result in errors
// being reported and we want that to happen.
//
// Note that `mir_validated` is a "stealable" result; the
// thief, `optimized_mir()`, forces borrowck, so we know that
// is not yet stolen.
tcx.mir_validated(owner_def_id).borrow();
}
// Eventually, borrowck will always read the MIR, but at the
// moment we do not. So, for now, we always force MIR to be
// constructed for a given fn, since this may result in errors
// being reported and we want that to happen.
//
// Note that `mir_validated` is a "stealable" result; the
// thief, `optimized_mir()`, forces borrowck, so we know that
// is not yet stolen.
tcx.mir_validated(owner_def_id).borrow();
let cfg = cfg::CFG::new(bccx.tcx, &body);
let AnalysisData { all_loans,

View File

@ -21,7 +21,6 @@
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(associated_consts)]
#![feature(nonzero)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
@ -39,7 +38,7 @@ extern crate core; // for NonZero
pub use borrowck::check_crate;
pub use borrowck::build_borrowck_dataflow_data_for_fn;
pub use borrowck::{AnalysisData, BorrowckCtxt, ElaborateDrops};
pub use borrowck::{AnalysisData, BorrowckCtxt};
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.

View File

@ -920,6 +920,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
// What we need to do constant evaluation.
passes.push_pass(MIR_CONST, mir::transform::simplify::SimplifyCfg::new("initial"));
passes.push_pass(MIR_CONST, mir::transform::type_check::TypeckMir);
passes.push_pass(MIR_CONST, mir::transform::rustc_peek::SanityCheck);
// What we need to run borrowck etc.
passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
@ -934,7 +935,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
// From here on out, regions are gone.
passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
passes.push_pass(MIR_OPTIMIZED, borrowck::ElaborateDrops);
passes.push_pass(MIR_OPTIMIZED, mir::transform::elaborate_drops::ElaborateDrops);
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));

View File

@ -1,4 +1,4 @@
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -8,33 +8,24 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use borrowck::BorrowckCtxt;
use syntax::ast::{self, MetaItem};
use syntax_pos::DUMMY_SP;
use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location};
use rustc::mir::{self, Mir, BasicBlock, Location};
use rustc::session::Session;
use rustc::ty::{self, TyCtxt};
use rustc_mir::util::elaborate_drops::DropFlagState;
use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf};
mod abs_domain;
pub mod elaborate_drops;
mod dataflow;
mod gather_moves;
// mod graphviz;
use self::dataflow::{BitDenotation};
use self::dataflow::{DataflowOperator};
use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults};
use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use self::dataflow::{DefinitelyInitializedLvals};
use self::gather_moves::{HasMoveData, MoveData, MovePathIndex, LookupResult};
use util::elaborate_drops::DropFlagState;
use rustc_data_structures::indexed_set::{IdxSet};
use std::fmt;
fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem> {
use super::{Dataflow, DataflowBuilder, DataflowAnalysis};
use super::{BitDenotation, DataflowOperator, DataflowResults};
use super::indexes::MovePathIndex;
use super::move_paths::{MoveData, LookupResult};
pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem> {
for attr in attrs {
if attr.check_name("rustc_mir") {
let items = attr.meta_item_list();
@ -50,69 +41,11 @@ fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem>
}
pub struct MoveDataParamEnv<'tcx> {
move_data: MoveData<'tcx>,
param_env: ty::ParamEnv<'tcx>,
pub(crate) move_data: MoveData<'tcx>,
pub(crate) param_env: ty::ParamEnv<'tcx>,
}
pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
id: ast::NodeId,
attributes: &[ast::Attribute]) {
let tcx = bcx.tcx;
let def_id = tcx.hir.local_def_id(id);
debug!("borrowck_mir({:?}) UNIMPLEMENTED", def_id);
// It is safe for us to borrow `mir_validated()`: `optimized_mir`
// steals it, but it forces the `borrowck` query.
let mir = &tcx.mir_validated(def_id).borrow();
let param_env = tcx.param_env(def_id);
let move_data = MoveData::gather_moves(mir, tcx, param_env);
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let flow_inits =
do_dataflow(tcx, mir, id, attributes, &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i]);
let flow_uninits =
do_dataflow(tcx, mir, id, attributes, &dead_unwinds,
MaybeUninitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i]);
let flow_def_inits =
do_dataflow(tcx, mir, id, attributes, &dead_unwinds,
DefinitelyInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i]);
if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() {
dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &flow_inits);
}
if has_rustc_mir_with(attributes, "rustc_peek_maybe_uninit").is_some() {
dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &flow_uninits);
}
if has_rustc_mir_with(attributes, "rustc_peek_definite_init").is_some() {
dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &flow_def_inits);
}
if has_rustc_mir_with(attributes, "stop_after_dataflow").is_some() {
bcx.tcx.sess.fatal("stop_after_dataflow ended compilation");
}
let mut mbcx = MirBorrowckCtxt {
bcx: bcx,
mir: mir,
node_id: id,
move_data: &mdpe.move_data,
flow_inits: flow_inits,
flow_uninits: flow_uninits,
};
for bb in mir.basic_blocks().indices() {
mbcx.process_basic_block(bb);
}
debug!("borrowck_mir done");
}
fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub(crate) fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
node_id: ast::NodeId,
attributes: &[ast::Attribute],
@ -142,7 +75,7 @@ fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let print_postflow_to =
name_found(tcx.sess, attributes, "borrowck_graphviz_postflow");
let mut mbcx = MirBorrowckCtxtPreDataflow {
let mut mbcx = DataflowBuilder {
node_id: node_id,
print_preflow_to: print_preflow_to,
print_postflow_to: print_postflow_to,
@ -153,46 +86,7 @@ fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mbcx.flow_state.results()
}
pub struct MirBorrowckCtxtPreDataflow<'a, 'tcx: 'a, BD> where BD: BitDenotation
{
node_id: ast::NodeId,
flow_state: DataflowAnalysis<'a, 'tcx, BD>,
print_preflow_to: Option<String>,
print_postflow_to: Option<String>,
}
#[allow(dead_code)]
pub struct MirBorrowckCtxt<'b, 'a: 'b, 'tcx: 'a> {
bcx: &'b mut BorrowckCtxt<'a, 'tcx>,
mir: &'b Mir<'tcx>,
node_id: ast::NodeId,
move_data: &'b MoveData<'tcx>,
flow_inits: DataflowResults<MaybeInitializedLvals<'b, 'tcx>>,
flow_uninits: DataflowResults<MaybeUninitializedLvals<'b, 'tcx>>
}
impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> {
fn process_basic_block(&mut self, bb: BasicBlock) {
let BasicBlockData { ref statements, ref terminator, is_cleanup: _ } =
self.mir[bb];
for stmt in statements {
self.process_statement(bb, stmt);
}
self.process_terminator(bb, terminator);
}
fn process_statement(&mut self, bb: BasicBlock, stmt: &Statement<'tcx>) {
debug!("MirBorrowckCtxt::process_statement({:?}, {:?}", bb, stmt);
}
fn process_terminator(&mut self, bb: BasicBlock, term: &Option<Terminator<'tcx>>) {
debug!("MirBorrowckCtxt::process_terminator({:?}, {:?})", bb, term);
}
}
fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
path: MovePathIndex,
mut cond: F)
-> Option<MovePathIndex>
@ -253,7 +147,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
}
}
fn on_lookup_result_bits<'a, 'tcx, F>(
pub(crate) fn on_lookup_result_bits<'a, 'tcx, F>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
move_data: &MoveData<'tcx>,
@ -271,7 +165,7 @@ fn on_lookup_result_bits<'a, 'tcx, F>(
}
}
fn on_all_children_bits<'a, 'tcx, F>(
pub(crate) fn on_all_children_bits<'a, 'tcx, F>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
move_data: &MoveData<'tcx>,
@ -312,7 +206,7 @@ fn on_all_children_bits<'a, 'tcx, F>(
on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child);
}
fn on_all_drop_children_bits<'a, 'tcx, F>(
pub(crate) fn on_all_drop_children_bits<'a, 'tcx, F>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
ctxt: &MoveDataParamEnv<'tcx>,
@ -333,7 +227,7 @@ fn on_all_drop_children_bits<'a, 'tcx, F>(
})
}
fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
pub(crate) fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
ctxt: &MoveDataParamEnv<'tcx>,
@ -350,7 +244,7 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
}
}
fn drop_flag_effects_for_location<'a, 'tcx, F>(
pub(crate) fn drop_flag_effects_for_location<'a, 'tcx, F>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
ctxt: &MoveDataParamEnv<'tcx>,

View File

@ -15,7 +15,6 @@ use rustc::mir::{BasicBlock, Mir};
use rustc_data_structures::bitslice::bits_to_string;
use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;
use rustc_mir::util as mir_util;
use dot;
use dot::IntoCow;
@ -28,8 +27,10 @@ use std::marker::PhantomData;
use std::mem;
use std::path::Path;
use super::super::MirBorrowckCtxtPreDataflow;
use util;
use super::{BitDenotation, DataflowState};
use super::DataflowBuilder;
impl<O: BitDenotation> DataflowState<O> {
fn each_bit<F>(&self, words: &IdxSet<O::Idx>, mut f: F)
@ -86,7 +87,7 @@ pub trait MirWithFlowState<'tcx> {
fn flow_state(&self) -> &DataflowState<Self::BD>;
}
impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
where 'tcx: 'a, BD: BitDenotation
{
type BD = BD;
@ -103,8 +104,8 @@ struct Graph<'a, 'tcx, MWF:'a, P> where
render_idx: P,
}
pub fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
mbcx: &MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>,
pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
mbcx: &DataflowBuilder<'a, 'tcx, BD>,
path: &Path,
render_idx: P)
-> io::Result<()>
@ -220,7 +221,7 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
}
Ok(())
}
mir_util::write_graphviz_node_label(
util::write_graphviz_node_label(
*n, self.mbcx.mir(), &mut v, 4,
|w| {
let flow = self.mbcx.flow_state();

View File

@ -8,25 +8,26 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Dataflow analyses are built upon some interpretation of the
//! bitvectors attached to each basic block, represented via a
//! zero-sized structure.
use rustc::ty::TyCtxt;
use rustc::mir::{self, Mir, Location};
use rustc_data_structures::bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep.
use rustc_data_structures::bitslice::{BitwiseOperator};
use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;
use rustc_mir::util::elaborate_drops::DropFlagState;
use super::super::gather_moves::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex};
use super::super::MoveDataParamEnv;
use super::super::drop_flag_effects_for_function_entry;
use super::super::drop_flag_effects_for_location;
use super::super::on_lookup_result_bits;
use super::MoveDataParamEnv;
use util::elaborate_drops::DropFlagState;
use super::move_paths::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex};
use super::{BitDenotation, BlockSets, DataflowOperator};
// Dataflow analyses are built upon some interpretation of the
// bitvectors attached to each basic block, represented via a
// zero-sized structure.
use super::drop_flag_effects_for_function_entry;
use super::drop_flag_effects_for_location;
use super::on_lookup_result_bits;
/// `MaybeInitializedLvals` tracks all l-values that might be
/// initialized upon reaching a particular point in the control flow
@ -219,6 +220,16 @@ pub struct MovingOutStatements<'a, 'tcx: 'a> {
mdpe: &'a MoveDataParamEnv<'tcx>,
}
impl<'a, 'tcx: 'a> MovingOutStatements<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
mdpe: &'a MoveDataParamEnv<'tcx>)
-> Self
{
MovingOutStatements { tcx: tcx, mir: mir, mdpe: mdpe }
}
}
impl<'a, 'tcx> HasMoveData<'tcx> for MovingOutStatements<'a, 'tcx> {
fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
}

View File

@ -8,11 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use syntax::ast;
use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::bitslice::{bitwise, BitwiseOperator};
use rustc::ty::TyCtxt;
use rustc::ty::{TyCtxt};
use rustc::mir::{self, Mir};
use std::fmt::Debug;
@ -21,21 +23,31 @@ use std::mem;
use std::path::PathBuf;
use std::usize;
use super::MirBorrowckCtxtPreDataflow;
pub use self::sanity_check::sanity_check_via_rustc_peek;
pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements};
pub(crate) use self::drop_flag_effects::*;
mod drop_flag_effects;
mod graphviz;
mod sanity_check;
mod impls;
pub mod move_paths;
pub(crate) use self::move_paths::indexes;
pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD> where BD: BitDenotation
{
node_id: ast::NodeId,
flow_state: DataflowAnalysis<'a, 'tcx, BD>,
print_preflow_to: Option<String>,
print_postflow_to: Option<String>,
}
pub trait Dataflow<BD: BitDenotation> {
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug;
}
impl<'a, 'tcx: 'a, BD> Dataflow<BD> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
impl<'a, 'tcx: 'a, BD> Dataflow<BD> for DataflowBuilder<'a, 'tcx, BD>
where BD: BitDenotation + DataflowOperator
{
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug {
@ -135,7 +147,7 @@ fn dataflow_path(context: &str, prepost: &str, path: &str) -> PathBuf {
path
}
impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD>
where BD: BitDenotation
{
fn pre_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
@ -195,7 +207,7 @@ impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O>
pub fn mir(&self) -> &'a Mir<'tcx> { self.mir }
}
pub struct DataflowResults<O>(DataflowState<O>) where O: BitDenotation;
pub struct DataflowResults<O>(pub(crate) DataflowState<O>) where O: BitDenotation;
impl<O: BitDenotation> DataflowResults<O> {
pub fn sets(&self) -> &AllSets<O::Idx> {
@ -213,7 +225,7 @@ pub struct DataflowState<O: BitDenotation>
pub sets: AllSets<O::Idx>,
/// operator used to initialize, combine, and interpret bits.
operator: O,
pub(crate) operator: O,
}
#[derive(Debug)]
@ -240,9 +252,9 @@ pub struct AllSets<E: Idx> {
}
pub struct BlockSets<'a, E: Idx> {
on_entry: &'a mut IdxSet<E>,
gen_set: &'a mut IdxSet<E>,
kill_set: &'a mut IdxSet<E>,
pub(crate) on_entry: &'a mut IdxSet<E>,
pub(crate) gen_set: &'a mut IdxSet<E>,
pub(crate) kill_set: &'a mut IdxSet<E>,
}
impl<'a, E:Idx> BlockSets<'a, E> {

View File

@ -21,14 +21,16 @@ use std::fmt;
use std::mem;
use std::ops::{Index, IndexMut};
use super::abs_domain::{AbstractElem, Lift};
use self::abs_domain::{AbstractElem, Lift};
mod abs_domain;
// This submodule holds some newtype'd Index wrappers that are using
// NonZero to ensure that Option<Index> occupies only a single word.
// They are in a submodule to impose privacy restrictions; namely, to
// ensure that other code does not accidentally access `index.0`
// (which is likely to yield a subtle off-by-one error).
mod indexes {
pub(crate) mod indexes {
use std::fmt;
use core::nonzero::NonZero;
use rustc_data_structures::indexed_vec::Idx;
@ -65,7 +67,7 @@ mod indexes {
pub use self::indexes::MovePathIndex;
pub use self::indexes::MoveOutIndex;
impl self::indexes::MoveOutIndex {
impl MoveOutIndex {
pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex {
move_data.moves[*self].path
}
@ -128,7 +130,7 @@ pub trait HasMoveData<'tcx> {
pub struct LocationMap<T> {
/// Location-indexed (BasicBlock for outer index, index within BB
/// for inner index) map.
map: IndexVec<BasicBlock, Vec<T>>,
pub(crate) map: IndexVec<BasicBlock, Vec<T>>,
}
impl<T> Index<Location> for LocationMap<T> {
@ -188,7 +190,7 @@ pub struct MovePathLookup<'tcx> {
projections: FxHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex>
}
struct MoveDataBuilder<'a, 'tcx: 'a> {
pub(super) struct MoveDataBuilder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,

View File

@ -26,6 +26,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
#![feature(rustc_diagnostic_macros)]
#![feature(placement_in_syntax)]
#![feature(collection_placement)]
#![feature(nonzero)]
#[macro_use] extern crate log;
extern crate graphviz as dot;
@ -40,10 +41,12 @@ extern crate syntax;
extern crate syntax_pos;
extern crate rustc_const_math;
extern crate rustc_const_eval;
extern crate core; // for NonZero
pub mod diagnostics;
mod build;
pub mod dataflow;
mod hair;
mod shim;
pub mod transform;

View File

@ -8,12 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::gather_moves::{HasMoveData, MoveData, MovePathIndex, LookupResult};
use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use super::dataflow::{DataflowResults};
use super::{on_all_children_bits, on_all_drop_children_bits};
use super::{drop_flag_effects_for_location, on_lookup_result_bits};
use super::MoveDataParamEnv;
use dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex, LookupResult};
use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use dataflow::{DataflowResults};
use dataflow::{on_all_children_bits, on_all_drop_children_bits};
use dataflow::{drop_flag_effects_for_location, on_lookup_result_bits};
use dataflow::MoveDataParamEnv;
use dataflow;
use rustc::ty::{self, TyCtxt};
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource};
@ -21,9 +22,9 @@ use rustc::middle::const_val::ConstVal;
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::Idx;
use rustc_mir::util::patch::MirPatch;
use rustc_mir::util::elaborate_drops::{DropFlagState, Unwind, elaborate_drop};
use rustc_mir::util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode};
use util::patch::MirPatch;
use util::elaborate_drops::{DropFlagState, Unwind, elaborate_drop};
use util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode};
use syntax::ast;
use syntax_pos::Span;
@ -54,13 +55,13 @@ impl MirPass for ElaborateDrops {
};
let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env);
let flow_inits =
super::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &env),
|bd, p| &bd.move_data().move_paths[p]);
dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &env),
|bd, p| &bd.move_data().move_paths[p]);
let flow_uninits =
super::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeUninitializedLvals::new(tcx, mir, &env),
|bd, p| &bd.move_data().move_paths[p]);
dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeUninitializedLvals::new(tcx, mir, &env),
|bd, p| &bd.move_data().move_paths[p]);
ElaborateDropsCtxt {
tcx: tcx,
@ -91,7 +92,7 @@ fn find_dead_unwinds<'a, 'tcx>(
// reach cleanup blocks, which can't have unwind edges themselves.
let mut dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let flow_inits =
super::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &env),
|bd, p| &bd.move_data().move_paths[p]);
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
@ -242,7 +243,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
}
fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
super::move_path_children_matching(self.ctxt.move_data(), path, |p| {
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
match p {
&Projection {
elem: ProjectionElem::Field(idx, _), ..
@ -253,7 +254,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
}
fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
super::move_path_children_matching(self.ctxt.move_data(), path, |p| {
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
match p {
&Projection { elem: ProjectionElem::Deref, .. } => true,
_ => false
@ -262,7 +263,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
}
fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option<Self::Path> {
super::move_path_children_matching(self.ctxt.move_data(), path, |p| {
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
match p {
&Projection {
elem: ProjectionElem::Downcast(_, idx), ..
@ -560,7 +561,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
fn drop_flags_for_args(&mut self) {
let loc = Location { block: START_BLOCK, statement_index: 0 };
super::drop_flag_effects_for_function_entry(
dataflow::drop_flag_effects_for_function_entry(
self.tcx, self.mir, self.env, |path, ds| {
self.set_drop_flag(loc, path, ds);
}
@ -605,7 +606,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
}
}
let loc = Location { block: bb, statement_index: i };
super::drop_flag_effects_for_location(
dataflow::drop_flag_effects_for_location(
self.tcx, self.mir, self.env, loc, |path, ds| {
if ds == DropFlagState::Absent || allow_initializations {
self.set_drop_flag(loc, path, ds)

View File

@ -30,6 +30,8 @@ pub mod simplify;
pub mod erase_regions;
pub mod no_landing_pads;
pub mod type_check;
pub mod rustc_peek;
pub mod elaborate_drops;
pub mod add_call_guards;
pub mod promote_consts;
pub mod qualify_consts;

View File

@ -14,12 +14,67 @@ use syntax_pos::Span;
use rustc::ty::{self, TyCtxt};
use rustc::mir::{self, Mir};
use rustc::mir::transform::{MirPass, MirSource};
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::Idx;
use super::super::gather_moves::{MovePathIndex, LookupResult};
use super::BitDenotation;
use super::DataflowResults;
use super::super::gather_moves::HasMoveData;
use dataflow::do_dataflow;
use dataflow::MoveDataParamEnv;
use dataflow::BitDenotation;
use dataflow::DataflowResults;
use dataflow::{DefinitelyInitializedLvals, MaybeInitializedLvals, MaybeUninitializedLvals};
use dataflow::move_paths::{MovePathIndex, LookupResult};
use dataflow::move_paths::{HasMoveData, MoveData};
use dataflow;
use dataflow::has_rustc_mir_with;
pub struct SanityCheck;
impl MirPass for SanityCheck {
fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource, mir: &mut Mir<'tcx>) {
let id = src.item_id();
let def_id = tcx.hir.local_def_id(id);
if !tcx.has_attr(def_id, "rustc_mir_borrowck") {
debug!("skipping rustc_peek::SanityCheck on {}", tcx.item_path_str(def_id));
return;
} else {
debug!("running rustc_peek::SanityCheck on {}", tcx.item_path_str(def_id));
}
let attributes = tcx.get_attrs(def_id);
let param_env = tcx.param_env(def_id);
let move_data = MoveData::gather_moves(mir, tcx, param_env);
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let flow_inits =
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i]);
let flow_uninits =
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
MaybeUninitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i]);
let flow_def_inits =
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
DefinitelyInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i]);
if has_rustc_mir_with(&attributes, "rustc_peek_maybe_init").is_some() {
sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_inits);
}
if has_rustc_mir_with(&attributes, "rustc_peek_maybe_uninit").is_some() {
sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_uninits);
}
if has_rustc_mir_with(&attributes, "rustc_peek_definite_init").is_some() {
sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_def_inits);
}
if has_rustc_mir_with(&attributes, "stop_after_dataflow").is_some() {
tcx.sess.fatal("stop_after_dataflow ended compilation");
}
}
}
/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
@ -92,7 +147,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// of the argument at time immediate preceding Call to
// `rustc_peek`).
let mut sets = super::BlockSets { on_entry: &mut entry,
let mut sets = dataflow::BlockSets { on_entry: &mut entry,
gen_set: &mut gen,
kill_set: &mut kill };