Skip to content

Commit 0fd7917

Browse files
authored
Rollup merge of rust-lang#98533 - jyn514:drop-tracking-debugging, r=eholk
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}) ``` r? `@eholk`
2 parents abc6b22 + 3164c2a commit 0fd7917

File tree

6 files changed

+60
-20
lines changed

6 files changed

+60
-20
lines changed

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ fn test_debugging_options_tracking_hash() {
649649
untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
650650
untracked!(dont_buffer_diagnostics, true);
651651
untracked!(dump_dep_graph, true);
652+
untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string()));
652653
untracked!(dump_mir, Some(String::from("abc")));
653654
untracked!(dump_mir_dataflow, true);
654655
untracked!(dump_mir_dir, String::from("abc"));

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,8 @@ options! {
12461246
dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
12471247
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
12481248
(default: no)"),
1249+
dump_drop_tracking_cfg: Option<String> = (None, parse_opt_string, [UNTRACKED],
1250+
"dump drop-tracking control-flow graph as a `.dot` file (default: no)"),
12491251
dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
12501252
"dump MIR state to file.
12511253
`val` is used to select which passes and functions to dump. For example:

compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ rustc_index::newtype_index! {
109109
}
110110

111111
/// Identifies a value whose drop state we need to track.
112-
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
112+
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
113113
enum TrackedValue {
114114
/// Represents a named variable, such as a let binding, parameter, or upvar.
115115
///
@@ -121,6 +121,21 @@ enum TrackedValue {
121121
Temporary(HirId),
122122
}
123123

124+
impl Debug for TrackedValue {
125+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126+
ty::tls::with_opt(|opt_tcx| {
127+
if let Some(tcx) = opt_tcx {
128+
write!(f, "{}", tcx.hir().node_to_string(self.hir_id()))
129+
} else {
130+
match self {
131+
Self::Variable(hir_id) => write!(f, "Variable({:?})", hir_id),
132+
Self::Temporary(hir_id) => write!(f, "Temporary({:?})", hir_id),
133+
}
134+
}
135+
})
136+
}
137+
}
138+
124139
impl TrackedValue {
125140
fn hir_id(&self) -> HirId {
126141
match self {
@@ -148,7 +163,7 @@ enum TrackedValueConversionError {
148163
/// Place projects are not currently supported.
149164
///
150165
/// The reasoning around these is kind of subtle, so we choose to be more
151-
/// conservative around these for now. There is not reason in theory we
166+
/// conservative around these for now. There is no reason in theory we
152167
/// cannot support these, we just have not implemented it yet.
153168
PlaceProjectionsNotSupported,
154169
}

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ pub(super) fn build_control_flow_graph<'tcx>(
3333
intravisit::walk_body(&mut drop_range_visitor, body);
3434

3535
drop_range_visitor.drop_ranges.process_deferred_edges();
36+
if let Some(filename) = &tcx.sess.opts.debugging_opts.dump_drop_tracking_cfg {
37+
super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
38+
}
3639

3740
(drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
3841
}
@@ -126,13 +129,14 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
126129
/// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
127130
/// expressions. This method consumes a little deeper into the expression when needed.
128131
fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
129-
debug!("consuming expr {:?}, count={:?}", expr.hir_id, self.expr_index);
132+
debug!("consuming expr {:?}, count={:?}", expr.kind, self.expr_index);
130133
let places = self
131134
.places
132135
.consumed
133136
.get(&expr.hir_id)
134137
.map_or(vec![], |places| places.iter().cloned().collect());
135138
for place in places {
139+
trace!(?place, "consuming place");
136140
for_each_consumable(self.hir, place, |value| self.record_drop(value));
137141
}
138142
}

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs

+28-14
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,43 @@
22
//! flow graph when needed for debugging.
33
44
use rustc_graphviz as dot;
5+
use rustc_middle::ty::TyCtxt;
56

67
use super::{DropRangesBuilder, PostOrderId};
78

89
/// Writes the CFG for DropRangesBuilder to a .dot file for visualization.
910
///
1011
/// It is not normally called, but is kept around to easily add debugging
1112
/// code when needed.
12-
#[allow(dead_code)]
13-
pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) {
14-
dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap();
13+
pub(super) fn write_graph_to_file(
14+
drop_ranges: &DropRangesBuilder,
15+
filename: &str,
16+
tcx: TyCtxt<'_>,
17+
) {
18+
dot::render(
19+
&DropRangesGraph { drop_ranges, tcx },
20+
&mut std::fs::File::create(filename).unwrap(),
21+
)
22+
.unwrap();
1523
}
1624

17-
impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
25+
struct DropRangesGraph<'a, 'tcx> {
26+
drop_ranges: &'a DropRangesBuilder,
27+
tcx: TyCtxt<'tcx>,
28+
}
29+
30+
impl<'a> dot::GraphWalk<'a> for DropRangesGraph<'_, '_> {
1831
type Node = PostOrderId;
1932

2033
type Edge = (PostOrderId, PostOrderId);
2134

2235
fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> {
23-
self.nodes.iter_enumerated().map(|(i, _)| i).collect()
36+
self.drop_ranges.nodes.iter_enumerated().map(|(i, _)| i).collect()
2437
}
2538

2639
fn edges(&'a self) -> dot::Edges<'a, Self::Edge> {
27-
self.nodes
40+
self.drop_ranges
41+
.nodes
2842
.iter_enumerated()
2943
.flat_map(|(i, node)| {
3044
if node.successors.len() == 0 {
@@ -45,7 +59,7 @@ impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
4559
}
4660
}
4761

48-
impl<'a> dot::Labeller<'a> for DropRangesBuilder {
62+
impl<'a> dot::Labeller<'a> for DropRangesGraph<'_, '_> {
4963
type Node = PostOrderId;
5064

5165
type Edge = (PostOrderId, PostOrderId);
@@ -61,15 +75,15 @@ impl<'a> dot::Labeller<'a> for DropRangesBuilder {
6175
fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> {
6276
dot::LabelText::LabelStr(
6377
format!(
64-
"{:?}, local_id: {}",
65-
n,
66-
self.post_order_map
78+
"{n:?}: {}",
79+
self.drop_ranges
80+
.post_order_map
6781
.iter()
6882
.find(|(_hir_id, &post_order_id)| post_order_id == *n)
69-
.map_or("<unknown>".into(), |(hir_id, _)| format!(
70-
"{}",
71-
hir_id.local_id.index()
72-
))
83+
.map_or("<unknown>".into(), |(hir_id, _)| self
84+
.tcx
85+
.hir()
86+
.node_to_string(*hir_id))
7387
)
7488
.into(),
7589
)

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ impl<'tcx> ExprUseDelegate<'tcx> {
7575
if !self.places.consumed.contains_key(&consumer) {
7676
self.places.consumed.insert(consumer, <_>::default());
7777
}
78+
debug!(?consumer, ?target, "mark_consumed");
7879
self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
7980
}
8081

@@ -136,13 +137,16 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
136137
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
137138
diag_expr_id: HirId,
138139
) {
139-
let parent = match self.tcx.hir().find_parent_node(place_with_id.hir_id) {
140+
let hir = self.tcx.hir();
141+
let parent = match hir.find_parent_node(place_with_id.hir_id) {
140142
Some(parent) => parent,
141143
None => place_with_id.hir_id,
142144
};
143145
debug!(
144-
"consume {:?}; diag_expr_id={:?}, using parent {:?}",
145-
place_with_id, diag_expr_id, parent
146+
"consume {:?}; diag_expr_id={}, using parent {}",
147+
place_with_id,
148+
hir.node_to_string(diag_expr_id),
149+
hir.node_to_string(parent)
146150
);
147151
place_with_id
148152
.try_into()

0 commit comments

Comments
 (0)