about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs3
-rw-r--r--src/librustc_mir/lib.rs3
-rw-r--r--src/librustc_mir/util/mod.rs2
-rw-r--r--src/librustc_mir/util/pretty.rs371
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(
                     &regular_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(())