Skip to content

Commit fbce585

Browse files
committed
Re-use Steal
1 parent 50587b0 commit fbce585

File tree

5 files changed

+70
-72
lines changed

5 files changed

+70
-72
lines changed

compiler/rustc_data_structures/src/steal.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ impl<T> Steal<T> {
4040
ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
4141
}
4242

43+
#[track_caller]
44+
pub fn get_mut(&mut self) -> &mut T {
45+
self.value.get_mut().as_mut().expect("attempt to read from stolen value")
46+
}
47+
4348
#[track_caller]
4449
pub fn steal(&self) -> T {
4550
let value_ref = &mut *self.value.try_write().expect("stealing value which is locked");

compiler/rustc_driver/src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ fn run_compiler(
309309

310310
if let Some(ppm) = &sess.opts.pretty {
311311
if ppm.needs_ast_map() {
312-
let expanded_crate = queries.expansion()?.peek().0.clone();
312+
let expanded_crate = queries.expansion()?.borrow().0.clone();
313313
queries.global_ctxt()?.enter(|tcx| {
314314
pretty::print_after_hir_lowering(
315315
tcx,
@@ -321,7 +321,7 @@ fn run_compiler(
321321
Ok(())
322322
})?;
323323
} else {
324-
let krate = queries.parse()?.take();
324+
let krate = queries.parse()?.steal();
325325
pretty::print_after_parsing(
326326
sess,
327327
compiler.input(),
@@ -343,7 +343,8 @@ fn run_compiler(
343343
}
344344

345345
{
346-
let (_, lint_store) = &*queries.register_plugins()?.peek();
346+
let plugins = queries.register_plugins()?;
347+
let (_, lint_store) = &*plugins.borrow();
347348

348349
// Lint plugins are registered; now we can process command line flags.
349350
if sess.opts.describe_lints {

compiler/rustc_interface/src/queries.rs

Lines changed: 57 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::passes::{self, BoxedResolver, QueryContext};
55
use rustc_ast as ast;
66
use rustc_codegen_ssa::traits::CodegenBackend;
77
use rustc_codegen_ssa::CodegenResults;
8+
use rustc_data_structures::steal::Steal;
89
use rustc_data_structures::svh::Svh;
910
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
1011
use rustc_hir::def_id::LOCAL_CRATE;
@@ -19,68 +20,59 @@ use rustc_session::{output::find_crate_name, Session};
1920
use rustc_span::symbol::sym;
2021
use rustc_span::Symbol;
2122
use std::any::Any;
22-
use std::cell::{Ref, RefCell};
23+
use std::cell::{RefCell, RefMut};
2324
use std::rc::Rc;
2425
use std::sync::Arc;
2526

2627
/// Represent the result of a query.
2728
///
28-
/// This result can be stolen once with the [`take`] method and generated with the [`compute`] method.
29+
/// This result can be stolen once with the [`steal`] method and generated with the [`compute`] method.
2930
///
30-
/// [`take`]: Self::take
31+
/// [`steal`]: Steal::steal
3132
/// [`compute`]: Self::compute
3233
pub struct Query<T> {
33-
result: RefCell<Result<State<T>>>,
34-
}
35-
36-
enum State<T> {
37-
NotComputedYet,
38-
Computed(T),
39-
Stolen,
34+
/// `None` means no value has been computed yet.
35+
result: RefCell<Option<Result<Steal<T>>>>,
4036
}
4137

4238
impl<T> Query<T> {
43-
fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
44-
let mut result = self.result.borrow_mut();
45-
if matches!(*result, Ok(State::NotComputedYet)) {
46-
*result = f().map(State::Computed);
47-
}
48-
result.as_ref().map(|_| self).map_err(|e| *e)
39+
fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<QueryResult<'_, T>> {
40+
RefMut::filter_map(
41+
self.result.borrow_mut(),
42+
|r: &mut Option<Result<Steal<T>>>| -> Option<&mut Steal<T>> {
43+
r.get_or_insert_with(|| f().map(Steal::new)).as_mut().ok()
44+
},
45+
)
46+
.map_err(|r| *r.as_ref().unwrap().as_ref().map(|_| ()).unwrap_err())
47+
.map(QueryResult)
4948
}
49+
}
5050

51-
/// Takes ownership of the query result. Further attempts to take or peek the query
52-
/// result will panic unless it is generated by calling the `compute` method.
53-
pub fn take(&self) -> T {
54-
match std::mem::replace(&mut *self.result.borrow_mut(), Ok(State::Stolen)).unwrap() {
55-
State::NotComputedYet => panic!("query never computed"),
56-
State::Computed(val) => val,
57-
State::Stolen => panic!("query already taken"),
58-
}
51+
pub struct QueryResult<'a, T>(RefMut<'a, Steal<T>>);
52+
53+
impl<'a, T> std::ops::Deref for QueryResult<'a, T> {
54+
type Target = RefMut<'a, Steal<T>>;
55+
56+
fn deref(&self) -> &Self::Target {
57+
&self.0
5958
}
59+
}
6060

61-
/// Borrows the query result using the RefCell. Panics if the result is stolen.
62-
pub fn peek(&self) -> Ref<'_, T> {
63-
Ref::map(self.result.borrow(), |r| match r.as_ref().unwrap() {
64-
State::NotComputedYet => panic!("query never computed"),
65-
State::Computed(val) => val,
66-
State::Stolen => panic!("query already taken"),
67-
})
61+
impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> {
62+
fn deref_mut(&mut self) -> &mut Self::Target {
63+
&mut self.0
6864
}
6965
}
7066

71-
impl<'tcx> Query<QueryContext<'tcx>> {
72-
pub fn enter<T>(&self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
73-
match self.result.borrow_mut().as_mut().unwrap() {
74-
State::NotComputedYet => panic!("query never computed"),
75-
State::Computed(qcx) => qcx.enter(f),
76-
State::Stolen => panic!("query already taken"),
77-
}
67+
impl<'a, 'tcx> QueryResult<'a, QueryContext<'tcx>> {
68+
pub fn enter<T>(mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
69+
(*self.0).get_mut().enter(f)
7870
}
7971
}
8072

8173
impl<T> Default for Query<T> {
8274
fn default() -> Self {
83-
Query { result: RefCell::new(Ok(State::NotComputedYet)) }
75+
Query { result: RefCell::new(None) }
8476
}
8577
}
8678

@@ -130,24 +122,24 @@ impl<'tcx> Queries<'tcx> {
130122
self.compiler.codegen_backend()
131123
}
132124

133-
fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
125+
fn dep_graph_future(&self) -> Result<QueryResult<'_, Option<DepGraphFuture>>> {
134126
self.dep_graph_future.compute(|| {
135127
let sess = self.session();
136128
Ok(sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess)))
137129
})
138130
}
139131

140-
pub fn parse(&self) -> Result<&Query<ast::Crate>> {
132+
pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> {
141133
self.parse.compute(|| {
142134
passes::parse(self.session(), &self.compiler.input)
143135
.map_err(|mut parse_error| parse_error.emit())
144136
})
145137
}
146138

147-
pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
139+
pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> {
148140
self.register_plugins.compute(|| {
149-
let crate_name = self.crate_name()?.peek().clone();
150-
let krate = self.parse()?.take();
141+
let crate_name = self.crate_name()?.borrow().clone();
142+
let krate = self.parse()?.steal();
151143

152144
let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
153145
let (krate, lint_store) = passes::register_plugins(
@@ -169,11 +161,11 @@ impl<'tcx> Queries<'tcx> {
169161
})
170162
}
171163

172-
pub fn crate_name(&self) -> Result<&Query<Symbol>> {
164+
pub fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> {
173165
self.crate_name.compute(|| {
174166
Ok({
175167
let parse_result = self.parse()?;
176-
let krate = parse_result.peek();
168+
let krate = parse_result.borrow();
177169
// parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
178170
find_crate_name(self.session(), &krate.attrs, &self.compiler.input)
179171
})
@@ -182,11 +174,12 @@ impl<'tcx> Queries<'tcx> {
182174

183175
pub fn expansion(
184176
&self,
185-
) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> {
177+
) -> Result<QueryResult<'_, (Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>>
178+
{
186179
trace!("expansion");
187180
self.expansion.compute(|| {
188-
let crate_name = *self.crate_name()?.peek();
189-
let (krate, lint_store) = self.register_plugins()?.take();
181+
let crate_name = *self.crate_name()?.borrow();
182+
let (krate, lint_store) = self.register_plugins()?.steal();
190183
let _timer = self.session().timer("configure_and_expand");
191184
let sess = self.session();
192185
let mut resolver = passes::create_resolver(
@@ -202,10 +195,10 @@ impl<'tcx> Queries<'tcx> {
202195
})
203196
}
204197

205-
fn dep_graph(&self) -> Result<&Query<DepGraph>> {
198+
fn dep_graph(&self) -> Result<QueryResult<'_, DepGraph>> {
206199
self.dep_graph.compute(|| {
207200
let sess = self.session();
208-
let future_opt = self.dep_graph_future()?.take();
201+
let future_opt = self.dep_graph_future()?.steal();
209202
let dep_graph = future_opt
210203
.and_then(|future| {
211204
let (prev_graph, prev_work_products) =
@@ -218,10 +211,11 @@ impl<'tcx> Queries<'tcx> {
218211
})
219212
}
220213

221-
pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
214+
pub fn prepare_outputs(&self) -> Result<QueryResult<'_, OutputFilenames>> {
222215
self.prepare_outputs.compute(|| {
223-
let (krate, boxed_resolver, _) = &*self.expansion()?.peek();
224-
let crate_name = *self.crate_name()?.peek();
216+
let expansion = self.expansion()?;
217+
let (krate, boxed_resolver, _) = &*expansion.borrow();
218+
let crate_name = *self.crate_name()?.borrow();
225219
passes::prepare_outputs(
226220
self.session(),
227221
self.compiler,
@@ -232,12 +226,12 @@ impl<'tcx> Queries<'tcx> {
232226
})
233227
}
234228

235-
pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
229+
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> {
236230
self.global_ctxt.compute(|| {
237-
let crate_name = *self.crate_name()?.peek();
238-
let outputs = self.prepare_outputs()?.take();
239-
let dep_graph = self.dep_graph()?.peek().clone();
240-
let (krate, resolver, lint_store) = self.expansion()?.take();
231+
let crate_name = *self.crate_name()?.borrow();
232+
let outputs = self.prepare_outputs()?.steal();
233+
let dep_graph = self.dep_graph()?.borrow().clone();
234+
let (krate, resolver, lint_store) = self.expansion()?.steal();
241235
Ok(passes::create_global_ctxt(
242236
self.compiler,
243237
lint_store,
@@ -254,7 +248,7 @@ impl<'tcx> Queries<'tcx> {
254248
})
255249
}
256250

257-
pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
251+
pub fn ongoing_codegen(&'tcx self) -> Result<QueryResult<'_, Box<dyn Any>>> {
258252
self.ongoing_codegen.compute(|| {
259253
self.global_ctxt()?.enter(|tcx| {
260254
tcx.analysis(()).ok();
@@ -315,7 +309,7 @@ impl<'tcx> Queries<'tcx> {
315309
let (crate_hash, prepare_outputs, dep_graph) = self.global_ctxt()?.enter(|tcx| {
316310
(tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone(), tcx.dep_graph.clone())
317311
});
318-
let ongoing_codegen = self.ongoing_codegen()?.take();
312+
let ongoing_codegen = self.ongoing_codegen()?.steal();
319313

320314
Ok(Linker {
321315
sess,
@@ -398,7 +392,8 @@ impl Compiler {
398392

399393
// NOTE: intentionally does not compute the global context if it hasn't been built yet,
400394
// since that likely means there was a parse error.
401-
if let Ok(State::Computed(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() {
395+
if let Some(Ok(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() {
396+
let gcx = gcx.get_mut();
402397
// We assume that no queries are run past here. If there are new queries
403398
// after this point, they'll show up as "<unknown>" in self-profiling data.
404399
{

src/librustdoc/doctest.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
115115
let (tests, unused_extern_reports, compiling_test_count) =
116116
interface::run_compiler(config, |compiler| {
117117
compiler.enter(|queries| {
118-
let mut global_ctxt = queries.global_ctxt()?.take();
119-
120-
let collector = global_ctxt.enter(|tcx| {
118+
let collector = queries.global_ctxt()?.enter(|tcx| {
121119
let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);
122120

123121
let opts = scrape_test_config(crate_attrs);
@@ -156,9 +154,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
156154

157155
let unused_extern_reports = collector.unused_extern_reports.clone();
158156
let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst);
159-
let ret: Result<_, ErrorGuaranteed> =
160-
Ok((collector.tests, unused_extern_reports, compiling_test_count));
161-
ret
157+
Ok((collector.tests, unused_extern_reports, compiling_test_count))
162158
})
163159
})?;
164160

src/librustdoc/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,8 @@ fn main_args(at_args: &[String]) -> MainResult {
800800
// FIXME(#83761): Resolver cloning can lead to inconsistencies between data in the
801801
// two copies because one of the copies can be modified after `TyCtxt` construction.
802802
let (resolver, resolver_caches) = {
803-
let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
803+
let expansion = abort_on_err(queries.expansion(), sess);
804+
let (krate, resolver, _) = &*expansion.borrow();
804805
let resolver_caches = resolver.borrow_mut().access(|resolver| {
805806
collect_intra_doc_links::early_resolve_intra_doc_links(
806807
resolver,

0 commit comments

Comments
 (0)