about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoshua Nelson <jnelson@cloudflare.com>2022-06-26 06:19:32 -0500
committerJoshua Nelson <jnelson@cloudflare.com>2022-06-26 06:27:24 -0500
commit483ee1f14770343122e9fadfffc054a119587dbf (patch)
treeae744f82c1c9265644b784bb0864f8c5a20ccd10
parent0e1a6fb463e7075572cee841525bf44a864da807 (diff)
downloadrust-483ee1f14770343122e9fadfffc054a119587dbf.tar.gz
rust-483ee1f14770343122e9fadfffc054a119587dbf.zip
Add a `-Zdump-drop-tracking-cfg` debugging flag
This is useful for debugging drop-tracking; previously, you had to recompile
rustc from source and manually add a call to `write_graph_to_file`. This
makes the option more discoverable and configurable at runtime.

I also took the liberty of making the labels for the CFG nodes much easier to read:
previously, they looked like `id(2), local_id: 48`, now they look like
```
expr from_config (hir_id=HirId { owner: DefId(0:10 ~ default_struct_update[79f9]::foo), local_id: 2})
```
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs3
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs46
4 files changed, 33 insertions, 19 deletions
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 30a29ed6ed3..dd7ef360cc1 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -649,6 +649,7 @@ fn test_debugging_options_tracking_hash() {
     untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(dont_buffer_diagnostics, true);
     untracked!(dump_dep_graph, true);
+    untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string()));
     untracked!(dump_mir, Some(String::from("abc")));
     untracked!(dump_mir_dataflow, true);
     untracked!(dump_mir_dir, String::from("abc"));
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 441e1f9f6a2..2638faa9d6a 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1245,6 +1245,8 @@ options! {
     dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
         "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
         (default: no)"),
+    dump_drop_tracking_cfg: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "dump drop-tracking control-flow graph as a `.dot` file (default: no)"),
     dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "dump MIR state to file.
         `val` is used to select which passes and functions to dump. For example:
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
index dbc309b29ff..0af866359e8 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
@@ -33,6 +33,9 @@ pub(super) fn build_control_flow_graph<'tcx>(
     intravisit::walk_body(&mut drop_range_visitor, body);
 
     drop_range_visitor.drop_ranges.process_deferred_edges();
+    if let Some(filename) = &tcx.sess.opts.debugging_opts.dump_drop_tracking_cfg {
+        super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
+    }
 
     (drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
 }
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
index 20aad7aedf7..afca7f7b531 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
@@ -2,6 +2,7 @@
 //! flow graph when needed for debugging.
 
 use rustc_graphviz as dot;
+use rustc_middle::ty::TyCtxt;
 
 use super::{DropRangesBuilder, PostOrderId};
 
@@ -9,22 +10,35 @@ use super::{DropRangesBuilder, PostOrderId};
 ///
 /// It is not normally called, but is kept around to easily add debugging
 /// code when needed.
-#[allow(dead_code)]
-pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) {
-    dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap();
+pub(super) fn write_graph_to_file(
+    drop_ranges: &DropRangesBuilder,
+    filename: &str,
+    tcx: TyCtxt<'_>,
+) {
+    dot::render(
+        &DropRangesGraph { drop_ranges, tcx },
+        &mut std::fs::File::create(filename).unwrap(),
+    )
+    .unwrap();
 }
 
-impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
+struct DropRangesGraph<'a, 'tcx> {
+    drop_ranges: &'a DropRangesBuilder,
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'a> dot::GraphWalk<'a> for DropRangesGraph<'_, '_> {
     type Node = PostOrderId;
 
     type Edge = (PostOrderId, PostOrderId);
 
     fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> {
-        self.nodes.iter_enumerated().map(|(i, _)| i).collect()
+        self.drop_ranges.nodes.iter_enumerated().map(|(i, _)| i).collect()
     }
 
     fn edges(&'a self) -> dot::Edges<'a, Self::Edge> {
-        self.nodes
+        self.drop_ranges
+            .nodes
             .iter_enumerated()
             .flat_map(|(i, node)| {
                 if node.successors.len() == 0 {
@@ -45,7 +59,7 @@ impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
     }
 }
 
-impl<'a> dot::Labeller<'a> for DropRangesBuilder {
+impl<'a> dot::Labeller<'a> for DropRangesGraph<'_, '_> {
     type Node = PostOrderId;
 
     type Edge = (PostOrderId, PostOrderId);
@@ -60,18 +74,12 @@ impl<'a> dot::Labeller<'a> for DropRangesBuilder {
 
     fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> {
         dot::LabelText::LabelStr(
-            format!(
-                "{:?}, local_id: {}",
-                n,
-                self.post_order_map
-                    .iter()
-                    .find(|(_hir_id, &post_order_id)| post_order_id == *n)
-                    .map_or("<unknown>".into(), |(hir_id, _)| format!(
-                        "{}",
-                        hir_id.local_id.index()
-                    ))
-            )
-            .into(),
+            self.drop_ranges
+                .post_order_map
+                .iter()
+                .find(|(_hir_id, &post_order_id)| post_order_id == *n)
+                .map_or("<unknown>".into(), |(hir_id, _)| self.tcx.hir().node_to_string(*hir_id))
+                .into(),
         )
     }
 }