Skip to content

Commit a47e638

Browse files
committed
Make it possible for ResultsCursor to borrow a Results.
`ResultsCursor` currently owns its `Results`. But sometimes the `Results` is needed again afterwards. So there is `ResultsCursor::into_results` for extracting the `Results`, which leads to some awkwardness. This commit adds `ResultsHandle`, a `Cow`-like type that can either borrow or own a a `Results`. `ResultsCursor` now uses it. This is good because some `ResultsCursor`s really want to own their `Results`, while others just want to borrow it. We end with with a few more lines of code, but get some nice cleanups. - `ResultsCursor::into_results` and `Formatter::into_results` are removed. - `write_graphviz_results` now just borrows a `Results`, instead of the awkward "take ownership of a `Results` and then return it unchanged" pattern. This reinstates the cursor flexibility that was lost in #118230 -- which removed the old `ResultsRefCursor` and `ResultsCloneCursor` types -- but in a much simpler way. Hooray!
1 parent ec5d6e7 commit a47e638

File tree

5 files changed

+81
-31
lines changed

5 files changed

+81
-31
lines changed

Diff for: compiler/rustc_mir_dataflow/src/framework/cursor.rs

+44-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,55 @@
11
//! Random access inspection of the results of a dataflow analysis.
22
33
use std::cmp::Ordering;
4+
use std::ops::{Deref, DerefMut};
45

56
#[cfg(debug_assertions)]
67
use rustc_index::bit_set::BitSet;
78
use rustc_middle::mir::{self, BasicBlock, Location};
89

910
use super::{Analysis, Direction, Effect, EffectIndex, Results};
1011

12+
/// Some `ResultsCursor`s want to own a `Results`, and some want to borrow a `Results`, either
13+
/// mutable or immutably. This type allows all of the above. It's similar to `Cow`.
14+
pub enum ResultsHandle<'a, 'tcx, A>
15+
where
16+
A: Analysis<'tcx>,
17+
{
18+
Borrowed(&'a Results<'tcx, A>),
19+
BorrowedMut(&'a mut Results<'tcx, A>),
20+
Owned(Results<'tcx, A>),
21+
}
22+
23+
impl<'tcx, A> Deref for ResultsHandle<'_, 'tcx, A>
24+
where
25+
A: Analysis<'tcx>,
26+
{
27+
type Target = Results<'tcx, A>;
28+
29+
fn deref(&self) -> &Results<'tcx, A> {
30+
match self {
31+
ResultsHandle::Borrowed(borrowed) => borrowed,
32+
ResultsHandle::BorrowedMut(borrowed) => borrowed,
33+
ResultsHandle::Owned(owned) => owned,
34+
}
35+
}
36+
}
37+
38+
impl<'tcx, A> DerefMut for ResultsHandle<'_, 'tcx, A>
39+
where
40+
A: Analysis<'tcx>,
41+
{
42+
fn deref_mut(&mut self) -> &mut Results<'tcx, A> {
43+
match self {
44+
ResultsHandle::Borrowed(_borrowed) => {
45+
panic!("tried to deref_mut a `ResultsHandle::Borrowed")
46+
}
47+
ResultsHandle::BorrowedMut(borrowed) => borrowed,
48+
ResultsHandle::Owned(owned) => owned,
49+
}
50+
}
51+
}
52+
1153
/// Allows random access inspection of the results of a dataflow analysis. Use this when you want
1254
/// to inspect domain values only in certain locations; use `ResultsVisitor` if you want to inspect
1355
/// domain values in many or all locations.
@@ -23,7 +65,7 @@ where
2365
A: Analysis<'tcx>,
2466
{
2567
body: &'mir mir::Body<'tcx>,
26-
results: Results<'tcx, A>,
68+
results: ResultsHandle<'mir, 'tcx, A>,
2769
state: A::Domain,
2870

2971
pos: CursorPosition,
@@ -51,13 +93,8 @@ where
5193
self.body
5294
}
5395

54-
/// Unwraps this cursor, returning the underlying `Results`.
55-
pub fn into_results(self) -> Results<'tcx, A> {
56-
self.results
57-
}
58-
5996
/// Returns a new cursor that can inspect `results`.
60-
pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self {
97+
pub fn new(body: &'mir mir::Body<'tcx>, results: ResultsHandle<'mir, 'tcx, A>) -> Self {
6198
let bottom_value = results.analysis.bottom_value(body);
6299
ResultsCursor {
63100
body,

Diff for: compiler/rustc_mir_dataflow/src/framework/graphviz.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,16 @@ where
4747
{
4848
pub(crate) fn new(
4949
body: &'mir Body<'tcx>,
50-
results: Results<'tcx, A>,
50+
results: &'mir Results<'tcx, A>,
5151
style: OutputStyle,
5252
) -> Self {
5353
let reachable = mir::traversal::reachable_as_bitset(body);
54-
Formatter { cursor: results.into_results_cursor(body).into(), style, reachable }
54+
Formatter { cursor: results.as_results_cursor(body).into(), style, reachable }
5555
}
5656

5757
fn body(&self) -> &'mir Body<'tcx> {
5858
self.cursor.borrow().body()
5959
}
60-
61-
pub(crate) fn into_results(self) -> Results<'tcx, A> {
62-
self.cursor.into_inner().into_results()
63-
}
6460
}
6561

6662
/// A pair of a basic block and an index into that basic blocks `successors`.

Diff for: compiler/rustc_mir_dataflow/src/framework/mod.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -302,14 +302,13 @@ pub trait Analysis<'tcx> {
302302
let results = Results { analysis: self, entry_sets };
303303

304304
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
305-
let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
305+
let res = write_graphviz_results(tcx, body, &results, pass_name);
306306
if let Err(e) = res {
307307
error!("Failed to write graphviz dataflow results: {}", e);
308308
}
309-
results
310-
} else {
311-
results
312309
}
310+
311+
results
313312
}
314313
}
315314

Diff for: compiler/rustc_mir_dataflow/src/framework/results.rs

+27-8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
1717
use crate::errors::{
1818
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
1919
};
20+
use crate::framework::cursor::ResultsHandle;
2021

2122
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
2223

@@ -36,12 +37,30 @@ impl<'tcx, A> Results<'tcx, A>
3637
where
3738
A: Analysis<'tcx>,
3839
{
39-
/// Creates a `ResultsCursor` that can inspect these `Results`.
40+
/// Creates a `ResultsCursor` that can inspect these `Results`. Immutably borrows the `Results`,
41+
/// which is appropriate when the `Results` is used outside the cursor.
42+
pub fn as_results_cursor<'mir>(
43+
&'mir self,
44+
body: &'mir mir::Body<'tcx>,
45+
) -> ResultsCursor<'mir, 'tcx, A> {
46+
ResultsCursor::new(body, ResultsHandle::Borrowed(self))
47+
}
48+
49+
/// Creates a `ResultsCursor` that can mutate these `Results`. Mutably borrows the `Results`,
50+
/// which is appropriate when the `Results` is used outside the cursor.
51+
pub fn as_results_cursor_mut<'mir>(
52+
&'mir mut self,
53+
body: &'mir mir::Body<'tcx>,
54+
) -> ResultsCursor<'mir, 'tcx, A> {
55+
ResultsCursor::new(body, ResultsHandle::BorrowedMut(self))
56+
}
57+
58+
/// Creates a `ResultsCursor` that takes ownership of the `Results`.
4059
pub fn into_results_cursor<'mir>(
4160
self,
4261
body: &'mir mir::Body<'tcx>,
4362
) -> ResultsCursor<'mir, 'tcx, A> {
44-
ResultsCursor::new(body, self)
63+
ResultsCursor::new(body, ResultsHandle::Owned(self))
4564
}
4665

4766
/// Gets the dataflow state for the given block.
@@ -76,9 +95,9 @@ where
7695
pub(super) fn write_graphviz_results<'tcx, A>(
7796
tcx: TyCtxt<'tcx>,
7897
body: &mir::Body<'tcx>,
79-
results: Results<'tcx, A>,
98+
results: &Results<'tcx, A>,
8099
pass_name: Option<&'static str>,
81-
) -> (std::io::Result<()>, Results<'tcx, A>)
100+
) -> std::io::Result<()>
82101
where
83102
A: Analysis<'tcx>,
84103
A::Domain: DebugWithContext<A>,
@@ -89,7 +108,7 @@ where
89108
let def_id = body.source.def_id();
90109
let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
91110
// Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
92-
return (Ok(()), results);
111+
return Ok(());
93112
};
94113

95114
let file = try {
@@ -106,12 +125,12 @@ where
106125
create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
107126
}
108127

109-
_ => return (Ok(()), results),
128+
_ => return Ok(()),
110129
}
111130
};
112131
let mut file = match file {
113132
Ok(f) => f,
114-
Err(e) => return (Err(e), results),
133+
Err(e) => return Err(e),
115134
};
116135

117136
let style = match attrs.formatter {
@@ -134,7 +153,7 @@ where
134153
file.write_all(&buf)?;
135154
};
136155

137-
(lhs, graphviz.into_results())
156+
lhs
138157
}
139158

140159
#[derive(Default)]

Diff for: compiler/rustc_mir_transform/src/coroutine.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -676,12 +676,11 @@ fn locals_live_across_suspend_points<'tcx>(
676676

677677
let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
678678

679-
// Calculate the MIR locals that we actually need to keep storage around
680-
// for.
681-
let mut requires_storage_cursor =
679+
// Calculate the MIR locals that we need to keep storage around for.
680+
let mut requires_storage_results =
682681
MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
683-
.iterate_to_fixpoint(tcx, body, None)
684-
.into_results_cursor(body);
682+
.iterate_to_fixpoint(tcx, body, None);
683+
let mut requires_storage_cursor = requires_storage_results.as_results_cursor_mut(body);
685684

686685
// Calculate the liveness of MIR locals ignoring borrows.
687686
let mut liveness =
@@ -754,7 +753,7 @@ fn locals_live_across_suspend_points<'tcx>(
754753
body,
755754
&saved_locals,
756755
always_live_locals.clone(),
757-
requires_storage_cursor.into_results(),
756+
requires_storage_results,
758757
);
759758

760759
LivenessInfo {

0 commit comments

Comments
 (0)