Revised graphviz rendering API to avoid requiring borrowed state.

Made `do_dataflow` and related API `pub(crate)`.
This commit is contained in:
Felix S. Klock II 2017-11-24 13:00:09 +01:00
parent 691f022767
commit 93c4ffe72f
6 changed files with 60 additions and 41 deletions

View File

@ -28,7 +28,7 @@ use rustc_data_structures::indexed_vec::Idx;
use syntax::ast;
use syntax_pos::Span;
use dataflow::do_dataflow;
use dataflow::{do_dataflow, DebugFormatted};
use dataflow::MoveDataParamEnv;
use dataflow::DataflowResultsConsumer;
use dataflow::{FlowAtLocation, FlowsAtLocation};
@ -157,7 +157,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
&attributes,
&dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i],
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
));
let flow_uninits = FlowAtLocation::new(do_dataflow(
tcx,
@ -166,7 +166,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
&attributes,
&dead_unwinds,
MaybeUninitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i],
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
));
let flow_move_outs = FlowAtLocation::new(do_dataflow(
tcx,
@ -175,7 +175,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
&attributes,
&dead_unwinds,
MovingOutStatements::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().moves[i],
|bd, i| DebugFormatted::new(&bd.move_data().moves[i]),
));
let flow_ever_inits = FlowAtLocation::new(do_dataflow(
tcx,
@ -184,7 +184,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
&attributes,
&dead_unwinds,
EverInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().inits[i],
|bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
));
// If we are in non-lexical mode, compute the non-lexical lifetimes.
@ -212,7 +212,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
&attributes,
&dead_unwinds,
Borrows::new(tcx, mir, opt_regioncx, def_id, body_id),
|bd, i| bd.location(i),
|bd, i| DebugFormatted::new(bd.location(i)),
));
let mut state = Flows::new(

View File

@ -18,7 +18,6 @@ use rustc_data_structures::indexed_vec::Idx;
use dot;
use dot::IntoCow;
use std::fmt::Debug;
use std::fs::File;
use std::io;
use std::io::prelude::*;
@ -29,6 +28,7 @@ use util;
use super::{BitDenotation, DataflowState};
use super::DataflowBuilder;
use super::DebugFormatted;
pub trait MirWithFlowState<'tcx> {
type BD: BitDenotation;
@ -60,9 +60,9 @@ pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
render_idx: P)
-> io::Result<()>
where BD: BitDenotation,
P: Fn(&BD, BD::Idx) -> &Debug
P: Fn(&BD, BD::Idx) -> DebugFormatted
{
let g = Graph { mbcx: mbcx, phantom: PhantomData, render_idx: render_idx };
let g = Graph { mbcx, phantom: PhantomData, render_idx };
let mut v = Vec::new();
dot::render(&g, &mut v)?;
debug!("print_borrowck_graph_to path: {} node_id: {}",
@ -82,7 +82,7 @@ fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
where MWF: MirWithFlowState<'tcx>,
P: for <'b> Fn(&'b MWF::BD, <MWF::BD as BitDenotation>::Idx) -> &'b Debug,
P: Fn(&MWF::BD, <MWF::BD as BitDenotation>::Idx) -> DebugFormatted,
{
type Node = Node;
type Edge = Edge;
@ -142,7 +142,7 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
const ALIGN_RIGHT: &'static str = r#"align="right""#;
const FACE_MONOSPACE: &'static str = r#"FACE="Courier""#;
fn chunked_present_left<W:io::Write>(w: &mut W,
interpreted: &[&Debug],
interpreted: &[DebugFormatted],
chunk_size: usize)
-> io::Result<()>
{

View File

@ -19,7 +19,7 @@ use rustc::mir::{self, Mir, BasicBlock, BasicBlockData, Location, Statement, Ter
use rustc::session::Session;
use std::borrow::Borrow;
use std::fmt::{self, Debug};
use std::fmt;
use std::io;
use std::mem;
use std::path::PathBuf;
@ -51,10 +51,29 @@ pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD> where BD: BitDenotation
print_postflow_to: Option<String>,
}
pub trait Dataflow<BD: BitDenotation> {
/// `DebugFormatted` encapsulates the "{:?}" rendering of some
/// arbitrary value. This way: you pay cost of allocating an extra
/// string (as well as that of rendering up-front); in exchange, you
/// don't have to hand over ownership of your value or deal with
/// borrowing it.
pub(crate) struct DebugFormatted(String);
impl DebugFormatted {
pub fn new(input: &fmt::Debug) -> DebugFormatted {
DebugFormatted(format!("{:?}", input))
}
}
impl fmt::Debug for DebugFormatted {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
write!(w, "{}", self.0)
}
}
pub(crate) trait Dataflow<BD: BitDenotation> {
/// 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 {
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted {
let _ = p; // default implementation does not instrument process.
self.build_sets();
self.propagate();
@ -69,7 +88,7 @@ pub trait Dataflow<BD: BitDenotation> {
impl<'a, 'tcx: 'a, BD> Dataflow<BD> for DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation
{
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug {
fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> DebugFormatted {
self.flow_state.build_sets();
self.pre_dataflow_instrumentation(|c,i| p(c,i)).unwrap();
self.flow_state.propagate();
@ -109,7 +128,7 @@ pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
p: P)
-> DataflowResults<BD>
where BD: BitDenotation,
P: Fn(&BD, BD::Idx) -> &fmt::Debug
P: Fn(&BD, BD::Idx) -> DebugFormatted
{
let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option<String> {
if let Some(item) = has_rustc_mir_with(attrs, name) {
@ -231,7 +250,7 @@ fn dataflow_path(context: &str, prepost: &str, path: &str) -> PathBuf {
impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation
{
fn pre_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
where P: Fn(&BD, BD::Idx) -> &Debug
where P: Fn(&BD, BD::Idx) -> DebugFormatted
{
if let Some(ref path_str) = self.print_preflow_to {
let path = dataflow_path(BD::name(), "preflow", path_str);
@ -242,7 +261,7 @@ impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation
}
fn post_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
where P: Fn(&BD, BD::Idx) -> &Debug
where P: Fn(&BD, BD::Idx) -> DebugFormatted
{
if let Some(ref path_str) = self.print_postflow_to {
let path = dataflow_path(BD::name(), "postflow", path_str);
@ -403,12 +422,12 @@ impl<O: BitDenotation> DataflowState<O> {
words.each_bit(bits_per_block, f)
}
pub fn interpret_set<'c, P>(&self,
o: &'c O,
words: &IdxSet<O::Idx>,
render_idx: &P)
-> Vec<&'c Debug>
where P: Fn(&O, O::Idx) -> &Debug
pub(crate) fn interpret_set<'c, P>(&self,
o: &'c O,
words: &IdxSet<O::Idx>,
render_idx: &P)
-> Vec<DebugFormatted>
where P: Fn(&O, O::Idx) -> DebugFormatted
{
let mut v = Vec::new();
self.each_bit(words, |i| {

View File

@ -14,7 +14,7 @@ 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 dataflow::{self, do_dataflow, DebugFormatted};
use rustc::hir;
use rustc::ty::{self, TyCtxt};
use rustc::mir::*;
@ -59,13 +59,13 @@ impl MirPass for ElaborateDrops {
};
let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env);
let flow_inits =
dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &env),
|bd, p| &bd.move_data().move_paths[p]);
do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &env),
|bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
let flow_uninits =
dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeUninitializedLvals::new(tcx, mir, &env),
|bd, p| &bd.move_data().move_paths[p]);
do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeUninitializedLvals::new(tcx, mir, &env),
|bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
ElaborateDropsCtxt {
tcx,
@ -96,9 +96,9 @@ 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 =
dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &env),
|bd, p| &bd.move_data().move_paths[p]);
do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &env),
|bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
let location = match bb_data.terminator().kind {
TerminatorKind::Drop { ref location, unwind: Some(_), .. } |

View File

@ -78,7 +78,7 @@ use std::mem;
use transform::{MirPass, MirSource};
use transform::simplify;
use transform::no_landing_pads::no_landing_pads;
use dataflow::{self, MaybeStorageLive, state_for_location};
use dataflow::{do_dataflow, DebugFormatted, MaybeStorageLive, state_for_location};
pub struct StateTransform;
@ -341,8 +341,8 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap();
let analysis = MaybeStorageLive::new(mir);
let storage_live =
dataflow::do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
|bd, p| &bd.mir().local_decls[p]);
do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
|bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len()));
ignored.visit_mir(mir);

View File

@ -18,7 +18,7 @@ use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::Idx;
use transform::{MirPass, MirSource};
use dataflow::do_dataflow;
use dataflow::{do_dataflow, DebugFormatted};
use dataflow::MoveDataParamEnv;
use dataflow::BitDenotation;
use dataflow::DataflowResults;
@ -51,15 +51,15 @@ impl MirPass for SanityCheck {
let flow_inits =
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i]);
|bd, i| DebugFormatted::new(&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]);
|bd, i| DebugFormatted::new(&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]);
|bd, i| DebugFormatted::new(&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);