diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/mod.rs | 3 | ||||
| -rw-r--r-- | src/librustc_mir/lib.rs | 3 | ||||
| -rw-r--r-- | src/librustc_mir/util/mod.rs | 2 | ||||
| -rw-r--r-- | src/librustc_mir/util/pretty.rs | 371 |
4 files changed, 246 insertions, 133 deletions
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index f0d425f3f17..a04cc113e72 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -170,7 +170,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( writeln!(out, " | Live variables on entry to {:?}: {}", bb, s)?; } - PassWhere::InCFG(location) => { + PassWhere::BeforeLocation(location) => { let s = live_variable_set( ®ular_liveness_per_location[&location], &drop_liveness_per_location[&location], @@ -178,6 +178,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( writeln!(out, " | Live variables at {:?}: {}", location, s)?; } + PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {} } Ok(()) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index af309342dc5..53f9b885ac6 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -18,12 +18,15 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(catch_expr)] #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] #![feature(i128_type)] +#![feature(inclusive_range_syntax)] #![feature(match_default_bindings)] +#![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(placement_in_syntax)] #![feature(collection_placement)] diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs index feea0e28809..eebe5a86018 100644 --- a/src/librustc_mir/util/mod.rs +++ b/src/librustc_mir/util/mod.rs @@ -15,7 +15,7 @@ pub mod patch; mod alignment; mod graphviz; -mod pretty; +pub(crate) mod pretty; pub mod liveness; pub use self::alignment::is_disaligned; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 4a009020485..8a3db0eb25b 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -14,17 +14,17 @@ use rustc::mir::*; use rustc::ty::TyCtxt; use rustc::ty::item_path; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::{Idx}; +use rustc_data_structures::indexed_vec::Idx; use std::fmt::Display; use std::fs; use std::io::{self, Write}; -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; use super::graphviz::write_mir_fn_graphviz; use transform::MirSource; const INDENT: &'static str = " "; /// Alignment for lining up comments following MIR statements -const ALIGN: usize = 40; +pub(crate) const ALIGN: usize = 40; /// An indication of where we are in the control flow graph. Used for printing /// extra information in `dump_mir` @@ -38,8 +38,11 @@ pub enum PassWhere { /// We are about to start dumping the given basic block. BeforeBlock(BasicBlock), - /// We are just about to dumpt the given statement or terminator. - InCFG(Location), + /// We are just about to dump the given statement or terminator. + BeforeLocation(Location), + + /// We just dumped the given statement or terminator. + AfterLocation(Location), } /// If the session is properly configured, dumps a human-readable @@ -56,64 +59,124 @@ pub enum PassWhere { /// - `substring1&substring2,...` -- `&`-separated list of substrings /// that can appear in the pass-name or the `item_path_str` for the given /// node-id. If any one of the substrings match, the data is dumped out. -pub fn dump_mir<'a, 'gcx, 'tcx, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - pass_num: Option<&Display>, - pass_name: &str, - disambiguator: &Display, - source: MirSource, - mir: &Mir<'tcx>, - extra_data: F) -where - F: FnMut(PassWhere, &mut Write) -> io::Result<()> +pub fn dump_mir<'a, 'gcx, 'tcx, F>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + pass_num: Option<&Display>, + pass_name: &str, + disambiguator: &Display, + source: MirSource, + mir: &Mir<'tcx>, + extra_data: F, +) where + F: FnMut(PassWhere, &mut Write) -> io::Result<()>, { if !dump_enabled(tcx, pass_name, source) { return; } - let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below + let node_path = item_path::with_forced_impl_filename_line(|| { + // see notes on #41697 below tcx.item_path_str(source.def_id) }); - dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, - disambiguator, source, mir, extra_data); + dump_matched_mir_node( + tcx, + pass_num, + pass_name, + &node_path, + disambiguator, + source, + mir, + extra_data, + ); } -pub fn dump_enabled<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - pass_name: &str, - source: MirSource) - -> bool { +pub fn dump_enabled<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + pass_name: &str, + source: MirSource, +) -> bool { let filters = match tcx.sess.opts.debugging_opts.dump_mir { None => return false, Some(ref filters) => filters, }; - let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below + let node_path = item_path::with_forced_impl_filename_line(|| { + // see notes on #41697 below tcx.item_path_str(source.def_id) }); - filters.split("&") - .any(|filter| { - filter == "all" || - pass_name.contains(filter) || - node_path.contains(filter) - }) + filters.split("&").any(|filter| { + filter == "all" || pass_name.contains(filter) || node_path.contains(filter) + }) } // #41697 -- we use `with_forced_impl_filename_line()` because // `item_path_str()` would otherwise trigger `type_of`, and this can // run while we are already attempting to evaluate `type_of`. -fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - pass_num: Option<&Display>, - pass_name: &str, - node_path: &str, - disambiguator: &Display, - source: MirSource, - mir: &Mir<'tcx>, - mut extra_data: F) -where - F: FnMut(PassWhere, &mut Write) -> io::Result<()> +fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + pass_num: Option<&Display>, + pass_name: &str, + node_path: &str, + disambiguator: &Display, + source: MirSource, + mir: &Mir<'tcx>, + mut extra_data: F, +) where + F: FnMut(PassWhere, &mut Write) -> io::Result<()>, { + let _: io::Result<()> = do catch { + let mut file = create_dump_file( + tcx, + "mir", + pass_num, + pass_name, + disambiguator, + source, + )?; + writeln!(file, "// MIR for `{}`", node_path)?; + writeln!(file, "// source = {:?}", source)?; + writeln!(file, "// pass_name = {}", pass_name)?; + writeln!(file, "// disambiguator = {}", disambiguator)?; + if let Some(ref layout) = mir.generator_layout { + writeln!(file, "// generator_layout = {:?}", layout)?; + } + writeln!(file, "")?; + extra_data(PassWhere::BeforeCFG, &mut file)?; + write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; + extra_data(PassWhere::AfterCFG, &mut file)?; + Ok(()) + }; + + if tcx.sess.opts.debugging_opts.dump_mir_graphviz { + let _: io::Result<()> = do catch { + let mut file = create_dump_file( + tcx, + "dot", + pass_num, + pass_name, + disambiguator, + source, + )?; + write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?; + Ok(()) + }; + } +} + +/// Returns the path to the filename where we should dump a given MIR. +/// Also used by other bits of code (e.g., NLL inference) that dump +/// graphviz data or other things. +fn dump_path( + tcx: TyCtxt<'_, '_, '_>, + extension: &str, + pass_num: Option<&Display>, + pass_name: &str, + disambiguator: &Display, + source: MirSource, +) -> PathBuf { let promotion_id = match source.promoted { Some(id) => format!("-{:?}", id), - None => String::new() + None => String::new(), }; let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number { @@ -126,48 +189,64 @@ where }; let mut file_path = PathBuf::new(); + if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir { let p = Path::new(file_dir); file_path.push(p); }; - let _ = fs::create_dir_all(&file_path); - let item_name = tcx.hir.def_path(source.def_id).to_filename_friendly_no_crate(); - let file_name = format!("rustc.{}{}{}.{}.{}.mir", - item_name, promotion_id, pass_num, pass_name, disambiguator); + let item_name = tcx.hir + .def_path(source.def_id) + .to_filename_friendly_no_crate(); + + let file_name = format!( + "rustc.{}{}{}.{}.{}.{}", + item_name, + promotion_id, + pass_num, + pass_name, + disambiguator, + extension, + ); + file_path.push(&file_name); - let _ = fs::File::create(&file_path).and_then(|mut file| { - writeln!(file, "// MIR for `{}`", node_path)?; - writeln!(file, "// source = {:?}", source)?; - writeln!(file, "// pass_name = {}", pass_name)?; - writeln!(file, "// disambiguator = {}", disambiguator)?; - if let Some(ref layout) = mir.generator_layout { - writeln!(file, "// generator_layout = {:?}", layout)?; - } - writeln!(file, "")?; - extra_data(PassWhere::BeforeCFG, &mut file)?; - write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; - extra_data(PassWhere::AfterCFG, &mut file)?; - Ok(()) - }); - if tcx.sess.opts.debugging_opts.dump_mir_graphviz { - file_path.set_extension("dot"); - let _ = fs::File::create(&file_path).and_then(|mut file| { - write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?; - Ok(()) - }); + file_path +} + +/// Attempts to open a file where we should dump a given MIR or other +/// bit of MIR-related data. Used by `mir-dump`, but also by other +/// bits of code (e.g., NLL inference) that dump graphviz data or +/// other things, and hence takes the extension as an argument. +pub(crate) fn create_dump_file( + tcx: TyCtxt<'_, '_, '_>, + extension: &str, + pass_num: Option<&Display>, + pass_name: &str, + disambiguator: &Display, + source: MirSource, +) -> io::Result<fs::File> { + let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, source); + if let Some(parent) = file_path.parent() { + fs::create_dir_all(parent)?; } + fs::File::create(&file_path) } /// Write out a human-readable textual representation for the given MIR. -pub fn write_mir_pretty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - single: Option<DefId>, - w: &mut Write) - -> io::Result<()> -{ - writeln!(w, "// WARNING: This output format is intended for human consumers only")?; - writeln!(w, "// and is subject to change without notice. Knock yourself out.")?; +pub fn write_mir_pretty<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + single: Option<DefId>, + w: &mut Write, +) -> io::Result<()> { + writeln!( + w, + "// WARNING: This output format is intended for human consumers only" + )?; + writeln!( + w, + "// and is subject to change without notice. Knock yourself out." + )?; let mut first = true; for def_id in dump_mir_def_ids(tcx, single) { @@ -186,7 +265,7 @@ pub fn write_mir_pretty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, writeln!(w, "")?; let src = MirSource { def_id, - promoted: Some(i) + promoted: Some(i), }; write_mir_fn(tcx, src, mir, &mut |_, _| Ok(()), w)?; } @@ -194,14 +273,15 @@ pub fn write_mir_pretty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, Ok(()) } -pub fn write_mir_fn<'a, 'gcx, 'tcx, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - extra_data: &mut F, - w: &mut Write) - -> io::Result<()> +pub fn write_mir_fn<'a, 'gcx, 'tcx, F>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + extra_data: &mut F, + w: &mut Write, +) -> io::Result<()> where - F: FnMut(PassWhere, &mut Write) -> io::Result<()> + F: FnMut(PassWhere, &mut Write) -> io::Result<()>, { write_mir_intro(tcx, src, mir, w)?; for block in mir.basic_blocks().indices() { @@ -217,14 +297,15 @@ where } /// Write out a human-readable textual representation for the given basic block. -pub fn write_basic_block<F>(tcx: TyCtxt, - block: BasicBlock, - mir: &Mir, - extra_data: &mut F, - w: &mut Write) - -> io::Result<()> +pub fn write_basic_block<F>( + tcx: TyCtxt, + block: BasicBlock, + mir: &Mir, + extra_data: &mut F, + w: &mut Write, +) -> io::Result<()> where - F: FnMut(PassWhere, &mut Write) -> io::Result<()> + F: FnMut(PassWhere, &mut Write) -> io::Result<()>, { let data = &mir[block]; @@ -234,43 +315,61 @@ where writeln!(w, "{0:1$}{2}", lbl, ALIGN, cleanup_text)?; // List of statements in the middle. - let mut current_location = Location { block: block, statement_index: 0 }; + let mut current_location = Location { + block: block, + statement_index: 0, + }; for statement in &data.statements { - extra_data(PassWhere::InCFG(current_location), w)?; + extra_data(PassWhere::BeforeLocation(current_location), w)?; let indented_mir = format!("{0}{0}{1:?};", INDENT, statement); - writeln!(w, "{0:1$} // {2}", - indented_mir, - ALIGN, - comment(tcx, statement.source_info))?; + writeln!( + w, + "{:A$} // {:?}: {}", + indented_mir, + current_location, + comment(tcx, statement.source_info), + A = ALIGN, + )?; + extra_data(PassWhere::AfterLocation(current_location), w)?; current_location.statement_index += 1; } // Terminator at the bottom. - extra_data(PassWhere::InCFG(current_location), w)?; + extra_data(PassWhere::BeforeLocation(current_location), w)?; let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); - writeln!(w, "{0:1$} // {2}", - indented_terminator, - ALIGN, - comment(tcx, data.terminator().source_info))?; + writeln!( + w, + "{:A$} // {:?}: {}", + indented_terminator, + current_location, + comment(tcx, data.terminator().source_info), + A = ALIGN, + )?; + extra_data(PassWhere::AfterLocation(current_location), w)?; writeln!(w, "{}}}", INDENT) } fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String { - format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span)) + format!( + "scope {} at {}", + scope.index(), + tcx.sess.codemap().span_to_string(span) + ) } /// Prints user-defined variables in a scope tree. /// /// Returns the total number of variables printed. -fn write_scope_tree(tcx: TyCtxt, - mir: &Mir, - scope_tree: &FxHashMap<VisibilityScope, Vec<VisibilityScope>>, - w: &mut Write, - parent: VisibilityScope, - depth: usize) - -> io::Result<()> { +fn write_scope_tree( + tcx: TyCtxt, + mir: &Mir, + scope_tree: &FxHashMap<VisibilityScope, Vec<VisibilityScope>>, + w: &mut Write, + parent: VisibilityScope, + depth: usize, +) -> io::Result<()> { let indent = depth * INDENT.len(); let children = match scope_tree.get(&parent) { @@ -300,17 +399,22 @@ fn write_scope_tree(tcx: TyCtxt, }; let indent = indent + INDENT.len(); - let indented_var = format!("{0:1$}let {2}{3:?}: {4};", - INDENT, - indent, - mut_str, - local, - var.ty); - writeln!(w, "{0:1$} // \"{2}\" in {3}", - indented_var, - ALIGN, - name, - comment(tcx, source_info))?; + let indented_var = format!( + "{0:1$}let {2}{3:?}: {4:?};", + INDENT, + indent, + mut_str, + local, + var.ty + ); + writeln!( + w, + "{0:1$} // \"{2}\" in {3}", + indented_var, + ALIGN, + name, + comment(tcx, source_info) + )?; } write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?; @@ -323,11 +427,12 @@ fn write_scope_tree(tcx: TyCtxt, /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its /// local variables (both user-defined bindings and compiler temporaries). -pub fn write_mir_intro<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - src: MirSource, - mir: &Mir, - w: &mut Write) - -> io::Result<()> { +pub fn write_mir_intro<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + src: MirSource, + mir: &Mir, + w: &mut Write, +) -> io::Result<()> { write_mir_sig(tcx, src, mir, w)?; writeln!(w, " {{")?; @@ -335,9 +440,10 @@ pub fn write_mir_intro<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, let mut scope_tree: FxHashMap<VisibilityScope, Vec<VisibilityScope>> = FxHashMap(); for (index, scope_data) in mir.visibility_scopes.iter().enumerate() { if let Some(parent) = scope_data.parent_scope { - scope_tree.entry(parent) - .or_insert(vec![]) - .push(VisibilityScope::new(index)); + scope_tree + .entry(parent) + .or_insert(vec![]) + .push(VisibilityScope::new(index)); } else { // Only the argument scope has no parent, because it's the root. assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index()); @@ -363,9 +469,7 @@ pub fn write_mir_intro<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, Ok(()) } -fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) - -> io::Result<()> -{ +fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) -> io::Result<()> { let id = tcx.hir.as_local_node_id(src.def_id).unwrap(); let body_owner_kind = tcx.hir.body_owner_kind(id); match (body_owner_kind, src.promoted) { @@ -376,7 +480,8 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) (hir::BodyOwnerKind::Static(hir::MutMutable), _) => write!(w, "static mut")?, } - item_path::with_forced_impl_filename_line(|| { // see notes on #41697 elsewhere + item_path::with_forced_impl_filename_line(|| { + // see notes on #41697 elsewhere write!(w, " {}", tcx.item_path_str(src.def_id)) })?; @@ -394,9 +499,7 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) write!(w, ") -> {}", mir.return_ty()) } - (hir::BodyOwnerKind::Const, _) | - (hir::BodyOwnerKind::Static(_), _) | - (_, Some(_)) => { + (hir::BodyOwnerKind::Const, _) | (hir::BodyOwnerKind::Static(_), _) | (_, Some(_)) => { assert_eq!(mir.arg_count, 0); write!(w, ": {} =", mir.return_ty()) } @@ -406,7 +509,13 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> { // Compiler-introduced temporary types. for temp in mir.temps_iter() { - writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?; + writeln!( + w, + "{}let mut {:?}: {};", + INDENT, + temp, + mir.local_decls[temp].ty + )?; } Ok(()) |
