Skip to content

Commit c95dd55

Browse files
committed
Harden the pre-tyctxt query system against accidental recomputation
1 parent 2cd2070 commit c95dd55

File tree

5 files changed

+43
-19
lines changed

5 files changed

+43
-19
lines changed

compiler/rustc_driver/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ fn run_compiler(
310310
if let Some(ppm) = &sess.opts.pretty {
311311
if ppm.needs_ast_map() {
312312
let expanded_crate = queries.expansion()?.peek().0.clone();
313-
queries.global_ctxt()?.peek_mut().enter(|tcx| {
313+
queries.global_ctxt()?.enter(|tcx| {
314314
pretty::print_after_hir_lowering(
315315
tcx,
316316
compiler.input(),
@@ -371,7 +371,7 @@ fn run_compiler(
371371
return early_exit();
372372
}
373373

374-
queries.global_ctxt()?.peek_mut().enter(|tcx| {
374+
queries.global_ctxt()?.enter(|tcx| {
375375
let result = tcx.analysis(());
376376
if sess.opts.unstable_opts.save_analysis {
377377
let crate_name = tcx.crate_name(LOCAL_CRATE);

compiler/rustc_interface/src/queries.rs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,43 +19,68 @@ use rustc_session::{output::find_crate_name, Session};
1919
use rustc_span::symbol::sym;
2020
use rustc_span::Symbol;
2121
use std::any::Any;
22-
use std::cell::{Ref, RefCell, RefMut};
22+
use std::cell::{Ref, RefCell};
2323
use std::rc::Rc;
2424
use std::sync::Arc;
2525

2626
/// Represent the result of a query.
2727
///
28-
/// This result can be stolen with the [`take`] method and generated with the [`compute`] method.
28+
/// This result can be stolen once with the [`take`] method and generated with the [`compute`] method.
2929
///
3030
/// [`take`]: Self::take
3131
/// [`compute`]: Self::compute
3232
pub struct Query<T> {
33-
result: RefCell<Option<Result<T>>>,
33+
result: RefCell<Option<Option<Result<T>>>>,
3434
}
3535

3636
impl<T> Query<T> {
3737
fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
38-
self.result.borrow_mut().get_or_insert_with(f).as_ref().map(|_| self).map_err(|&err| err)
38+
self.result
39+
.borrow_mut()
40+
.get_or_insert_with(|| Some(f()))
41+
.as_ref()
42+
.expect("query already taken")
43+
.as_ref()
44+
.map(|_| self)
45+
.map_err(|&err| err)
3946
}
4047

4148
/// Takes ownership of the query result. Further attempts to take or peek the query
4249
/// result will panic unless it is generated by calling the `compute` method.
4350
pub fn take(&self) -> T {
44-
self.result.borrow_mut().take().expect("missing query result").unwrap()
51+
self.result
52+
.borrow_mut()
53+
.as_mut()
54+
.expect("query never computed")
55+
.take()
56+
.expect("query already taken")
57+
.unwrap()
4558
}
4659

4760
/// Borrows the query result using the RefCell. Panics if the result is stolen.
4861
pub fn peek(&self) -> Ref<'_, T> {
4962
Ref::map(self.result.borrow(), |r| {
50-
r.as_ref().unwrap().as_ref().expect("missing query result")
63+
r.as_ref()
64+
.unwrap()
65+
.as_ref()
66+
.expect("query never computed")
67+
.as_ref()
68+
.expect("query already taken")
5169
})
5270
}
71+
}
5372

54-
/// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
55-
pub fn peek_mut(&self) -> RefMut<'_, T> {
56-
RefMut::map(self.result.borrow_mut(), |r| {
57-
r.as_mut().unwrap().as_mut().expect("missing query result")
58-
})
73+
impl<'tcx> Query<QueryContext<'tcx>> {
74+
pub fn enter<T>(&self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
75+
self.result
76+
.borrow_mut()
77+
.as_mut()
78+
.unwrap()
79+
.as_mut()
80+
.expect("query never computed")
81+
.as_mut()
82+
.expect("query already taken")
83+
.enter(f)
5984
}
6085
}
6186

@@ -237,7 +262,7 @@ impl<'tcx> Queries<'tcx> {
237262

238263
pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
239264
self.ongoing_codegen.compute(|| {
240-
self.global_ctxt()?.peek_mut().enter(|tcx| {
265+
self.global_ctxt()?.enter(|tcx| {
241266
tcx.analysis(()).ok();
242267

243268
// Don't do code generation if there were any errors
@@ -296,7 +321,6 @@ impl<'tcx> Queries<'tcx> {
296321
let dep_graph = self.dep_graph()?.peek().clone();
297322
let (crate_hash, prepare_outputs) = self
298323
.global_ctxt()?
299-
.peek_mut()
300324
.enter(|tcx| (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone()));
301325
let ongoing_codegen = self.ongoing_codegen()?.take();
302326

@@ -381,7 +405,7 @@ impl Compiler {
381405

382406
// NOTE: intentionally does not compute the global context if it hasn't been built yet,
383407
// since that likely means there was a parse error.
384-
if let Some(Ok(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() {
408+
if let Some(Some(Ok(gcx))) = &mut *queries.global_ctxt.result.borrow_mut() {
385409
// We assume that no queries are run past here. If there are new queries
386410
// after this point, they'll show up as "<unknown>" in self-profiling data.
387411
{

src/librustdoc/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ fn main_args(at_args: &[String]) -> MainResult {
817817
sess.fatal("Compilation failed, aborting rustdoc");
818818
}
819819

820-
let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).peek_mut();
820+
let global_ctxt = abort_on_err(queries.global_ctxt(), sess);
821821

822822
global_ctxt.enter(|tcx| {
823823
let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {

src/test/run-make-fulldeps/obtain-borrowck/driver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl rustc_driver::Callbacks for CompilerCalls {
6262
queries: &'tcx Queries<'tcx>,
6363
) -> Compilation {
6464
compiler.session().abort_if_errors();
65-
queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
65+
queries.global_ctxt().unwrap().enter(|tcx| {
6666
// Collect definition ids of MIR bodies.
6767
let hir = tcx.hir();
6868
let mut bodies = Vec::new();

src/tools/miri/src/bin/miri.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
6161
) -> Compilation {
6262
compiler.session().abort_if_errors();
6363

64-
queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
64+
queries.global_ctxt().unwrap().enter(|tcx| {
6565
init_late_loggers(tcx);
6666
if !tcx.sess.crate_types().contains(&CrateType::Executable) {
6767
tcx.sess.fatal("miri only makes sense on bin crates");

0 commit comments

Comments
 (0)