From 93c4ffe72f8e406a166e258c80723606cd7d8304 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 24 Nov 2017 13:00:09 +0100 Subject: [PATCH] Revised graphviz rendering API to avoid requiring borrowed state. Made `do_dataflow` and related API `pub(crate)`. --- src/librustc_mir/borrow_check/mod.rs | 12 ++--- src/librustc_mir/dataflow/graphviz.rs | 10 ++--- src/librustc_mir/dataflow/mod.rs | 45 +++++++++++++------ src/librustc_mir/transform/elaborate_drops.rs | 20 ++++----- src/librustc_mir/transform/generator.rs | 6 +-- src/librustc_mir/transform/rustc_peek.rs | 8 ++-- 6 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 128052e58949..8bfb5fee9f64 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -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( diff --git a/src/librustc_mir/dataflow/graphviz.rs b/src/librustc_mir/dataflow/graphviz.rs index 7ff4fbcf199e..b79e044b24f2 100644 --- a/src/librustc_mir/dataflow/graphviz.rs +++ b/src/librustc_mir/dataflow/graphviz.rs @@ -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 { 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, ::Idx) -> &'b Debug, + P: Fn(&MWF::BD, ::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: &mut W, - interpreted: &[&Debug], + interpreted: &[DebugFormatted], chunk_size: usize) -> io::Result<()> { diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 2136b41e4622..8624cbbf50ab 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -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, } -pub trait Dataflow { +/// `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 { /// Sets up and runs the dataflow problem, using `p` to render results if /// implementation so chooses. - fn dataflow

(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug { + fn dataflow

(&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 { impl<'a, 'tcx: 'a, BD> Dataflow for DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation { - fn dataflow

(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug { + fn dataflow

(&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 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 { 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

(&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

(&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 DataflowState { words.each_bit(bits_per_block, f) } - pub fn interpret_set<'c, P>(&self, - o: &'c O, - words: &IdxSet, - 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, + render_idx: &P) + -> Vec + where P: Fn(&O, O::Idx) -> DebugFormatted { let mut v = Vec::new(); self.each_bit(words, |i| { diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index b075d2637da9..106bc39d0fc5 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -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(_), .. } | diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index aaa28634eb82..455a07c04cfc 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -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); diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 08508143976e..6b8e2b073ccd 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -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);