Skip to content

Commit 9e735ca

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` is removed. - `Formatter::into_results` is removed. - `write_graphviz_results` now just borrows a `Results`, instead of the awkward "take ownership of a `Results` and then return it unchanged" pattern. - `MaybeRequiresStorage` can borrow the `MaybeBorrowedLocals` results, avoiding two `clone` calls: one in `check_for_move` and one in `locals_live_across_suspend_points`. - `Results` no longer needs to derive `Clone`. 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 cbe3c1e commit 9e735ca

File tree

6 files changed

+62
-37
lines changed

6 files changed

+62
-37
lines changed

compiler/rustc_mir_dataflow/src/framework/cursor.rs

+28-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,39 @@
11
//! Random access inspection of the results of a dataflow analysis.
22
33
use std::cmp::Ordering;
4+
use std::ops::Deref;
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`. This type
13+
/// allows either. We could use `Cow` but that would require `Results` and `A` to impl `Clone`. So
14+
/// this is a greatly cut-down alternative to `Cow`.
15+
pub enum ResultsHandle<'a, 'tcx, A>
16+
where
17+
A: Analysis<'tcx>,
18+
{
19+
Borrowed(&'a 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::Owned(owned) => owned,
33+
}
34+
}
35+
}
36+
1137
/// Allows random access inspection of the results of a dataflow analysis.
1238
///
1339
/// This cursor only has linear performance within a basic block when its statements are visited in
@@ -19,7 +45,7 @@ where
1945
A: Analysis<'tcx>,
2046
{
2147
body: &'mir mir::Body<'tcx>,
22-
results: Results<'tcx, A>,
48+
results: ResultsHandle<'mir, 'tcx, A>,
2349
state: A::Domain,
2450

2551
pos: CursorPosition,
@@ -47,13 +73,8 @@ where
4773
self.body
4874
}
4975

50-
/// Unwraps this cursor, returning the underlying `Results`.
51-
pub fn into_results(self) -> Results<'tcx, A> {
52-
self.results
53-
}
54-
5576
/// Returns a new cursor that can inspect `results`.
56-
pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self {
77+
pub fn new(body: &'mir mir::Body<'tcx>, results: ResultsHandle<'mir, 'tcx, A>) -> Self {
5778
let bottom_value = results.analysis.bottom_value(body);
5879
ResultsCursor {
5980
body,

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`.

compiler/rustc_mir_dataflow/src/framework/mod.rs

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

308308
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
309-
let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
309+
let res = write_graphviz_results(tcx, body, &results, pass_name);
310310
if let Err(e) = res {
311311
error!("Failed to write graphviz dataflow results: {}", e);
312312
}
313-
results
314-
} else {
315-
results
316313
}
314+
315+
results
317316
}
318317
}
319318

compiler/rustc_mir_dataflow/src/framework/results.rs

+20-10
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ 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
type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
2223

2324
/// A dataflow analysis that has converged to fixpoint.
24-
#[derive(Clone)]
2525
pub struct Results<'tcx, A>
2626
where
2727
A: Analysis<'tcx>,
@@ -34,12 +34,22 @@ impl<'tcx, A> Results<'tcx, A>
3434
where
3535
A: Analysis<'tcx>,
3636
{
37-
/// Creates a `ResultsCursor` that can inspect these `Results`.
37+
/// Creates a `ResultsCursor` that can inspect these `Results`. Only borrows the `Results`,
38+
/// which is appropriate when the `Results` is used outside the cursor.
39+
pub fn as_results_cursor<'mir>(
40+
&'mir self,
41+
body: &'mir mir::Body<'tcx>,
42+
) -> ResultsCursor<'mir, 'tcx, A> {
43+
ResultsCursor::new(body, ResultsHandle::Borrowed(self))
44+
}
45+
46+
/// Creates a `ResultsCursor` that can inspect these `Results`. Takes ownership of the
47+
/// `Results`, which is good when the `Results` is only used by the cursor.
3848
pub fn into_results_cursor<'mir>(
3949
self,
4050
body: &'mir mir::Body<'tcx>,
4151
) -> ResultsCursor<'mir, 'tcx, A> {
42-
ResultsCursor::new(body, self)
52+
ResultsCursor::new(body, ResultsHandle::Owned(self))
4353
}
4454

4555
/// Gets the dataflow state for the given block.
@@ -74,9 +84,9 @@ where
7484
pub(super) fn write_graphviz_results<'tcx, A>(
7585
tcx: TyCtxt<'tcx>,
7686
body: &mir::Body<'tcx>,
77-
results: Results<'tcx, A>,
87+
results: &Results<'tcx, A>,
7888
pass_name: Option<&'static str>,
79-
) -> (std::io::Result<()>, Results<'tcx, A>)
89+
) -> std::io::Result<()>
8090
where
8191
A: Analysis<'tcx>,
8292
A::Domain: DebugWithContext<A>,
@@ -87,7 +97,7 @@ where
8797
let def_id = body.source.def_id();
8898
let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
8999
// Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
90-
return (Ok(()), results);
100+
return Ok(());
91101
};
92102

93103
let file = try {
@@ -104,12 +114,12 @@ where
104114
create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
105115
}
106116

107-
_ => return (Ok(()), results),
117+
_ => return Ok(()),
108118
}
109119
};
110120
let mut file = match file {
111121
Ok(f) => f,
112-
Err(e) => return (Err(e), results),
122+
Err(e) => return Err(e),
113123
};
114124

115125
let style = match attrs.formatter {
@@ -119,7 +129,7 @@ where
119129

120130
let mut buf = Vec::new();
121131

122-
let graphviz = graphviz::Formatter::new(body, results, style);
132+
let graphviz = graphviz::Formatter::new(body, &results, style);
123133
let mut render_opts =
124134
vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())];
125135
if tcx.sess.opts.unstable_opts.graphviz_dark_mode {
@@ -132,7 +142,7 @@ where
132142
file.write_all(&buf)?;
133143
};
134144

135-
(lhs, graphviz.into_results())
145+
lhs
136146
}
137147

138148
#[derive(Default)]

compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,13 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> {
100100
/// given location; i.e. whether its storage can go away without being observed.
101101
pub struct MaybeRequiresStorage<'mir, 'tcx> {
102102
body: &'mir Body<'tcx>,
103-
borrowed_locals: Results<'tcx, MaybeBorrowedLocals>,
103+
borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>,
104104
}
105105

106106
impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
107107
pub fn new(
108108
body: &'mir Body<'tcx>,
109-
borrowed_locals: Results<'tcx, MaybeBorrowedLocals>,
109+
borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>,
110110
) -> Self {
111111
MaybeRequiresStorage { body, borrowed_locals }
112112
}
@@ -278,7 +278,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
278278
impl<'tcx> MaybeRequiresStorage<'_, 'tcx> {
279279
/// Kill locals that are fully moved and have not been borrowed.
280280
fn check_for_move(&self, trans: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
281-
let borrowed_locals = self.borrowed_locals.clone().into_results_cursor(self.body);
281+
let borrowed_locals = self.borrowed_locals.as_results_cursor(self.body);
282282
let mut visitor = MoveVisitor { trans, borrowed_locals };
283283
visitor.visit_location(self.body, loc);
284284
}

compiler/rustc_mir_transform/src/coroutine.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -673,13 +673,12 @@ fn locals_live_across_suspend_points<'tcx>(
673673
// borrowed (even if they are still active).
674674
let borrowed_locals_results =
675675
MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine"));
676-
let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
676+
let mut borrowed_locals_cursor = borrowed_locals_results.as_results_cursor(body);
677677

678-
// Calculate the MIR locals that we actually need to keep storage around
679-
// for.
680-
let mut requires_storage_cursor = MaybeRequiresStorage::new(body, borrowed_locals_results)
681-
.iterate_to_fixpoint(tcx, body, None)
682-
.into_results_cursor(body);
678+
// Calculate the MIR locals for which we need to keep storage around.
679+
let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results)
680+
.iterate_to_fixpoint(tcx, body, None);
681+
let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body);
683682

684683
// Calculate the liveness of MIR locals ignoring borrows.
685684
let mut liveness =
@@ -752,7 +751,7 @@ fn locals_live_across_suspend_points<'tcx>(
752751
body,
753752
&saved_locals,
754753
always_live_locals.clone(),
755-
requires_storage_cursor.into_results(),
754+
requires_storage_results,
756755
);
757756

758757
LivenessInfo {

0 commit comments

Comments
 (0)