Use a valid name for graphviz graphs

This commit is contained in:
Matthew Jasper 2019-03-17 10:36:10 +00:00
parent 52e885628e
commit 64303189f0
10 changed files with 85 additions and 40 deletions

View File

@ -633,10 +633,20 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
let body = tcx.hir().body(body_id); let body = tcx.hir().body(body_id);
let cfg = cfg::CFG::new(tcx, &body); let cfg = cfg::CFG::new(tcx, &body);
let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
let hir_id = code.id();
// We have to disassemble the hir_id because name must be ASCII
// alphanumeric. This does not appear in the rendered graph, so it does not
// have to be user friendly.
let name = format!(
"hir_id_{}_{}_{}",
hir_id.owner.address_space().index(),
hir_id.owner.as_array_index(),
hir_id.local_id.index(),
);
let lcfg = LabelledCFG { let lcfg = LabelledCFG {
tcx, tcx,
cfg: &cfg, cfg: &cfg,
name: format!("node_{}", code.id()), name,
labelled_edges, labelled_edges,
}; };

View File

@ -156,7 +156,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
let mut flow_inits = FlowAtLocation::new(do_dataflow( let mut flow_inits = FlowAtLocation::new(do_dataflow(
tcx, tcx,
mir, mir,
id, def_id,
&attributes, &attributes,
&dead_unwinds, &dead_unwinds,
MaybeInitializedPlaces::new(tcx, mir, &mdpe), MaybeInitializedPlaces::new(tcx, mir, &mdpe),
@ -191,7 +191,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
let flow_borrows = FlowAtLocation::new(do_dataflow( let flow_borrows = FlowAtLocation::new(do_dataflow(
tcx, tcx,
mir, mir,
id, def_id,
&attributes, &attributes,
&dead_unwinds, &dead_unwinds,
Borrows::new(tcx, mir, regioncx.clone(), &borrow_set), Borrows::new(tcx, mir, regioncx.clone(), &borrow_set),
@ -200,7 +200,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
let flow_uninits = FlowAtLocation::new(do_dataflow( let flow_uninits = FlowAtLocation::new(do_dataflow(
tcx, tcx,
mir, mir,
id, def_id,
&attributes, &attributes,
&dead_unwinds, &dead_unwinds,
MaybeUninitializedPlaces::new(tcx, mir, &mdpe), MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
@ -209,7 +209,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
let flow_ever_inits = FlowAtLocation::new(do_dataflow( let flow_ever_inits = FlowAtLocation::new(do_dataflow(
tcx, tcx,
mir, mir,
id, def_id,
&attributes, &attributes,
&dead_unwinds, &dead_unwinds,
EverInitializedPlaces::new(tcx, mir, &mdpe), EverInitializedPlaces::new(tcx, mir, &mdpe),

View File

@ -1,6 +1,6 @@
//! Hook into libgraphviz for rendering dataflow graphs for MIR. //! Hook into libgraphviz for rendering dataflow graphs for MIR.
use rustc::hir::HirId; use rustc::hir::def_id::DefId;
use rustc::mir::{BasicBlock, Mir}; use rustc::mir::{BasicBlock, Mir};
use std::fs; use std::fs;
@ -8,13 +8,15 @@ use std::io;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::path::Path; use std::path::Path;
use crate::util::graphviz_safe_def_name;
use super::{BitDenotation, DataflowState}; use super::{BitDenotation, DataflowState};
use super::DataflowBuilder; use super::DataflowBuilder;
use super::DebugFormatted; use super::DebugFormatted;
pub trait MirWithFlowState<'tcx> { pub trait MirWithFlowState<'tcx> {
type BD: BitDenotation<'tcx>; type BD: BitDenotation<'tcx>;
fn hir_id(&self) -> HirId; fn def_id(&self) -> DefId;
fn mir(&self) -> &Mir<'tcx>; fn mir(&self) -> &Mir<'tcx>;
fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>; fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>;
} }
@ -23,7 +25,7 @@ impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
where BD: BitDenotation<'tcx> where BD: BitDenotation<'tcx>
{ {
type BD = BD; type BD = BD;
fn hir_id(&self) -> HirId { self.hir_id } fn def_id(&self) -> DefId { self.def_id }
fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() } fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> { &self.flow_state.flow_state } fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> { &self.flow_state.flow_state }
} }
@ -47,8 +49,8 @@ pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
let g = Graph { mbcx, phantom: PhantomData, render_idx }; let g = Graph { mbcx, phantom: PhantomData, render_idx };
let mut v = Vec::new(); let mut v = Vec::new();
dot::render(&g, &mut v)?; dot::render(&g, &mut v)?;
debug!("print_borrowck_graph_to path: {} hir_id: {}", debug!("print_borrowck_graph_to path: {} def_id: {:?}",
path.display(), mbcx.hir_id); path.display(), mbcx.def_id);
fs::write(path, v) fs::write(path, v)
} }
@ -69,9 +71,8 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
type Node = Node; type Node = Node;
type Edge = Edge; type Edge = Edge;
fn graph_id(&self) -> dot::Id<'_> { fn graph_id(&self) -> dot::Id<'_> {
dot::Id::new(format!("graph_for_node_{}", let name = graphviz_safe_def_name(self.mbcx.def_id());
self.mbcx.hir_id())) dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
.unwrap()
} }
fn node_id(&self, n: &Node) -> dot::Id<'_> { fn node_id(&self, n: &Node) -> dot::Id<'_> {

View File

@ -4,7 +4,7 @@ use rustc_data_structures::bit_set::{BitSet, BitSetOperator, HybridBitSet};
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::work_queue::WorkQueue; use rustc_data_structures::work_queue::WorkQueue;
use rustc::hir::HirId; use rustc::hir::def_id::DefId;
use rustc::ty::{self, TyCtxt}; use rustc::ty::{self, TyCtxt};
use rustc::mir::{self, Mir, BasicBlock, BasicBlockData, Location, Statement, Terminator}; use rustc::mir::{self, Mir, BasicBlock, BasicBlockData, Location, Statement, Terminator};
use rustc::mir::traversal; use rustc::mir::traversal;
@ -39,7 +39,7 @@ pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD>
where where
BD: BitDenotation<'tcx> BD: BitDenotation<'tcx>
{ {
hir_id: HirId, def_id: DefId,
flow_state: DataflowAnalysis<'a, 'tcx, BD>, flow_state: DataflowAnalysis<'a, 'tcx, BD>,
print_preflow_to: Option<String>, print_preflow_to: Option<String>,
print_postflow_to: Option<String>, print_postflow_to: Option<String>,
@ -117,7 +117,7 @@ pub struct MoveDataParamEnv<'gcx, 'tcx> {
pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>, pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
mir: &'a Mir<'tcx>, mir: &'a Mir<'tcx>,
hir_id: HirId, def_id: DefId,
attributes: &[ast::Attribute], attributes: &[ast::Attribute],
dead_unwinds: &BitSet<BasicBlock>, dead_unwinds: &BitSet<BasicBlock>,
bd: BD, bd: BD,
@ -127,14 +127,14 @@ pub(crate) fn do_dataflow<'a, 'gcx, 'tcx, BD, P>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
P: Fn(&BD, BD::Idx) -> DebugFormatted P: Fn(&BD, BD::Idx) -> DebugFormatted
{ {
let flow_state = DataflowAnalysis::new(mir, dead_unwinds, bd); let flow_state = DataflowAnalysis::new(mir, dead_unwinds, bd);
flow_state.run(tcx, hir_id, attributes, p) flow_state.run(tcx, def_id, attributes, p)
} }
impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation<'tcx> impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation<'tcx>
{ {
pub(crate) fn run<P>(self, pub(crate) fn run<P>(self,
tcx: TyCtxt<'a, 'gcx, 'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>,
hir_id: HirId, def_id: DefId,
attributes: &[ast::Attribute], attributes: &[ast::Attribute],
p: P) -> DataflowResults<'tcx, BD> p: P) -> DataflowResults<'tcx, BD>
where P: Fn(&BD, BD::Idx) -> DebugFormatted where P: Fn(&BD, BD::Idx) -> DebugFormatted
@ -159,7 +159,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitD
name_found(tcx.sess, attributes, "borrowck_graphviz_postflow"); name_found(tcx.sess, attributes, "borrowck_graphviz_postflow");
let mut mbcx = DataflowBuilder { let mut mbcx = DataflowBuilder {
hir_id, def_id,
print_preflow_to, print_postflow_to, flow_state: self, print_preflow_to, print_postflow_to, flow_state: self,
}; };

View File

@ -28,7 +28,7 @@ impl MirPass for ElaborateDrops {
{ {
debug!("elaborate_drops({:?} @ {:?})", src, mir.span); debug!("elaborate_drops({:?} @ {:?})", src, mir.span);
let id = tcx.hir().as_local_hir_id(src.def_id()).unwrap(); let def_id = src.def_id();
let param_env = tcx.param_env(src.def_id()).with_reveal_all(); let param_env = tcx.param_env(src.def_id()).with_reveal_all();
let move_data = match MoveData::gather_moves(mir, tcx) { let move_data = match MoveData::gather_moves(mir, tcx) {
Ok(move_data) => move_data, Ok(move_data) => move_data,
@ -50,13 +50,13 @@ impl MirPass for ElaborateDrops {
move_data, move_data,
param_env, param_env,
}; };
let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env); let dead_unwinds = find_dead_unwinds(tcx, mir, def_id, &env);
let flow_inits = let flow_inits =
do_dataflow(tcx, mir, id, &[], &dead_unwinds, do_dataflow(tcx, mir, def_id, &[], &dead_unwinds,
MaybeInitializedPlaces::new(tcx, mir, &env), MaybeInitializedPlaces::new(tcx, mir, &env),
|bd, p| DebugFormatted::new(&bd.move_data().move_paths[p])); |bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
let flow_uninits = let flow_uninits =
do_dataflow(tcx, mir, id, &[], &dead_unwinds, do_dataflow(tcx, mir, def_id, &[], &dead_unwinds,
MaybeUninitializedPlaces::new(tcx, mir, &env), MaybeUninitializedPlaces::new(tcx, mir, &env),
|bd, p| DebugFormatted::new(&bd.move_data().move_paths[p])); |bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
@ -80,7 +80,7 @@ impl MirPass for ElaborateDrops {
fn find_dead_unwinds<'a, 'tcx>( fn find_dead_unwinds<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>, mir: &Mir<'tcx>,
id: hir::HirId, def_id: hir::def_id::DefId,
env: &MoveDataParamEnv<'tcx, 'tcx>) env: &MoveDataParamEnv<'tcx, 'tcx>)
-> BitSet<BasicBlock> -> BitSet<BasicBlock>
{ {
@ -89,7 +89,7 @@ fn find_dead_unwinds<'a, 'tcx>(
// reach cleanup blocks, which can't have unwind edges themselves. // reach cleanup blocks, which can't have unwind edges themselves.
let mut dead_unwinds = BitSet::new_empty(mir.basic_blocks().len()); let mut dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
let flow_inits = let flow_inits =
do_dataflow(tcx, mir, id, &[], &dead_unwinds, do_dataflow(tcx, mir, def_id, &[], &dead_unwinds,
MaybeInitializedPlaces::new(tcx, mir, &env), MaybeInitializedPlaces::new(tcx, mir, &env),
|bd, p| DebugFormatted::new(&bd.move_data().move_paths[p])); |bd, p| DebugFormatted::new(&bd.move_data().move_paths[p]));
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {

View File

@ -383,13 +383,13 @@ fn locals_live_across_suspend_points(
FxHashMap<BasicBlock, liveness::LiveVarSet>, FxHashMap<BasicBlock, liveness::LiveVarSet>,
) { ) {
let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len()); let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
let hir_id = tcx.hir().as_local_hir_id(source.def_id()).unwrap(); let def_id = source.def_id();
// Calculate when MIR locals have live storage. This gives us an upper bound of their // Calculate when MIR locals have live storage. This gives us an upper bound of their
// lifetimes. // lifetimes.
let storage_live_analysis = MaybeStorageLive::new(mir); let storage_live_analysis = MaybeStorageLive::new(mir);
let storage_live = let storage_live =
do_dataflow(tcx, mir, hir_id, &[], &dead_unwinds, storage_live_analysis, do_dataflow(tcx, mir, def_id, &[], &dead_unwinds, storage_live_analysis,
|bd, p| DebugFormatted::new(&bd.mir().local_decls[p])); |bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
// Find the MIR locals which do not use StorageLive/StorageDead statements. // Find the MIR locals which do not use StorageLive/StorageDead statements.
@ -403,7 +403,7 @@ fn locals_live_across_suspend_points(
let borrowed_locals = if !movable { let borrowed_locals = if !movable {
let analysis = HaveBeenBorrowedLocals::new(mir); let analysis = HaveBeenBorrowedLocals::new(mir);
let result = let result =
do_dataflow(tcx, mir, hir_id, &[], &dead_unwinds, analysis, do_dataflow(tcx, mir, def_id, &[], &dead_unwinds, analysis,
|bd, p| DebugFormatted::new(&bd.mir().local_decls[p])); |bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
Some((analysis, result)) Some((analysis, result))
} else { } else {

View File

@ -3,7 +3,7 @@ use syntax::ast;
use syntax_pos::Span; use syntax_pos::Span;
use rustc::ty::{self, TyCtxt}; use rustc::ty::{self, TyCtxt};
use rustc::hir; use rustc::hir::def_id::DefId;
use rustc::mir::{self, Mir, Location}; use rustc::mir::{self, Mir, Location};
use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::bit_set::BitSet;
use crate::transform::{MirPass, MirSource}; use crate::transform::{MirPass, MirSource};
@ -27,7 +27,6 @@ impl MirPass for SanityCheck {
fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource<'tcx>, mir: &mut Mir<'tcx>) { src: MirSource<'tcx>, mir: &mut Mir<'tcx>) {
let def_id = src.def_id(); let def_id = src.def_id();
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
if !tcx.has_attr(def_id, "rustc_mir") { if !tcx.has_attr(def_id, "rustc_mir") {
debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
return; return;
@ -41,26 +40,26 @@ impl MirPass for SanityCheck {
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len()); let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
let flow_inits = let flow_inits =
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, do_dataflow(tcx, mir, def_id, &attributes, &dead_unwinds,
MaybeInitializedPlaces::new(tcx, mir, &mdpe), MaybeInitializedPlaces::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i])); |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]));
let flow_uninits = let flow_uninits =
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, do_dataflow(tcx, mir, def_id, &attributes, &dead_unwinds,
MaybeUninitializedPlaces::new(tcx, mir, &mdpe), MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i])); |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]));
let flow_def_inits = let flow_def_inits =
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds, do_dataflow(tcx, mir, def_id, &attributes, &dead_unwinds,
DefinitelyInitializedPlaces::new(tcx, mir, &mdpe), DefinitelyInitializedPlaces::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&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() { if has_rustc_mir_with(&attributes, "rustc_peek_maybe_init").is_some() {
sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_inits); sanity_check_via_rustc_peek(tcx, mir, def_id, &attributes, &flow_inits);
} }
if has_rustc_mir_with(&attributes, "rustc_peek_maybe_uninit").is_some() { if has_rustc_mir_with(&attributes, "rustc_peek_maybe_uninit").is_some() {
sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_uninits); sanity_check_via_rustc_peek(tcx, mir, def_id, &attributes, &flow_uninits);
} }
if has_rustc_mir_with(&attributes, "rustc_peek_definite_init").is_some() { if has_rustc_mir_with(&attributes, "rustc_peek_definite_init").is_some() {
sanity_check_via_rustc_peek(tcx, mir, id, &attributes, &flow_def_inits); sanity_check_via_rustc_peek(tcx, mir, def_id, &attributes, &flow_def_inits);
} }
if has_rustc_mir_with(&attributes, "stop_after_dataflow").is_some() { if has_rustc_mir_with(&attributes, "stop_after_dataflow").is_some() {
tcx.sess.fatal("stop_after_dataflow ended compilation"); tcx.sess.fatal("stop_after_dataflow ended compilation");
@ -86,12 +85,12 @@ impl MirPass for SanityCheck {
/// errors are not intended to be used for unit tests.) /// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>, mir: &Mir<'tcx>,
id: hir::HirId, def_id: DefId,
_attributes: &[ast::Attribute], _attributes: &[ast::Attribute],
results: &DataflowResults<'tcx, O>) results: &DataflowResults<'tcx, O>)
where O: BitDenotation<'tcx, Idx=MovePathIndex> + HasMoveData<'tcx> where O: BitDenotation<'tcx, Idx=MovePathIndex> + HasMoveData<'tcx>
{ {
debug!("sanity_check_via_rustc_peek id: {:?}", id); debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id);
// FIXME: this is not DRY. Figure out way to abstract this and // FIXME: this is not DRY. Figure out way to abstract this and
// `dataflow::build_sets`. (But note it is doing non-standard // `dataflow::build_sets`. (But note it is doing non-standard
// stuff, so such generalization may not be realistic.) // stuff, so such generalization may not be realistic.)

View File

@ -1,6 +1,7 @@
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::mir::*; use rustc::mir::*;
use rustc::ty::TyCtxt; use rustc::ty::TyCtxt;
use rustc_data_structures::indexed_vec::Idx;
use std::fmt::Debug; use std::fmt::Debug;
use std::io::{self, Write}; use std::io::{self, Write};
@ -20,6 +21,17 @@ pub fn write_mir_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>,
Ok(()) Ok(())
} }
// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
// it does not have to be user friendly.
pub fn graphviz_safe_def_name(def_id: DefId) -> String {
format!(
"{}_{}_{}",
def_id.krate.index(),
def_id.index.address_space().index(),
def_id.index.as_array_index(),
)
}
/// Write a graphviz DOT graph of the MIR. /// Write a graphviz DOT graph of the MIR.
pub fn write_mir_fn_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>, pub fn write_mir_fn_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>,
def_id: DefId, def_id: DefId,
@ -27,7 +39,7 @@ pub fn write_mir_fn_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>,
w: &mut W) -> io::Result<()> w: &mut W) -> io::Result<()>
where W: Write where W: Write
{ {
writeln!(w, "digraph Mir_{} {{", tcx.hir().as_local_hir_id(def_id).unwrap())?; writeln!(w, "digraph Mir_{} {{", graphviz_safe_def_name(def_id))?;
// Global graph properties // Global graph properties
writeln!(w, r#" graph [fontname="monospace"];"#)?; writeln!(w, r#" graph [fontname="monospace"];"#)?;

View File

@ -15,7 +15,7 @@ pub mod collect_writes;
pub use self::alignment::is_disaligned; pub use self::alignment::is_disaligned;
pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere};
pub use self::graphviz::{write_mir_graphviz}; pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz};
pub use self::graphviz::write_node_label as write_graphviz_node_label; pub use self::graphviz::write_node_label as write_graphviz_node_label;
/// If possible, suggest replacing `ref` with `ref mut`. /// If possible, suggest replacing `ref` with `ref mut`.

View File

@ -0,0 +1,23 @@
// Test graphviz output
// compile-flags: -Z dump-mir-graphviz
// ignore-tidy-linelength
fn main() {}
// END RUST SOURCE
// START rustc.main.mir_map.0.dot
// digraph Mir_0_0_3 { // The name here MUST be an ASCII identifier.
// graph [fontname="monospace"];
// node [fontname="monospace"];
// edge [fontname="monospace"];
// label=<fn main() -&gt; ()<br align="left"/>>;
// bb0 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = ()<br/></td></tr><tr><td align="left">goto</td></tr></table>
// >];
// bb1 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">1</td></tr><tr><td align="left">resume</td></tr></table>
// >];
// bb2 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">2</td></tr><tr><td align="left">return</td></tr></table>
// >];
// bb0 -> bb2 [label=""];
// }
// END rustc.main.mir_map.0.dot