diff options
Diffstat (limited to 'compiler/rustc_interface/src/queries.rs')
-rw-r--r-- | compiler/rustc_interface/src/queries.rs | 158 |
1 files changed, 84 insertions, 74 deletions
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 39e1f2204..d5a49dd75 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -5,6 +5,7 @@ use crate::passes::{self, BoxedResolver, QueryContext}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; +use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_hir::def_id::LOCAL_CRATE; @@ -12,50 +13,60 @@ use rustc_incremental::DepGraphFuture; use rustc_lint::LintStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::ty::{GlobalCtxt, TyCtxt}; +use rustc_middle::ty::{self, GlobalCtxt, TyCtxt}; use rustc_query_impl::Queries as TcxQueries; use rustc_session::config::{self, OutputFilenames, OutputType}; use rustc_session::{output::find_crate_name, Session}; use rustc_span::symbol::sym; use rustc_span::Symbol; use std::any::Any; -use std::cell::{Ref, RefCell, RefMut}; +use std::cell::{RefCell, RefMut}; use std::rc::Rc; use std::sync::Arc; /// Represent the result of a query. /// -/// This result can be stolen with the [`take`] method and generated with the [`compute`] method. +/// This result can be stolen once with the [`steal`] method and generated with the [`compute`] method. /// -/// [`take`]: Self::take +/// [`steal`]: Steal::steal /// [`compute`]: Self::compute pub struct Query<T> { - result: RefCell<Option<Result<T>>>, + /// `None` means no value has been computed yet. + result: RefCell<Option<Result<Steal<T>>>>, } impl<T> Query<T> { - fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> { - self.result.borrow_mut().get_or_insert_with(f).as_ref().map(|_| self).map_err(|&err| err) + fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<QueryResult<'_, T>> { + RefMut::filter_map( + self.result.borrow_mut(), + |r: &mut Option<Result<Steal<T>>>| -> Option<&mut Steal<T>> { + r.get_or_insert_with(|| f().map(Steal::new)).as_mut().ok() + }, + ) + .map_err(|r| *r.as_ref().unwrap().as_ref().map(|_| ()).unwrap_err()) + .map(QueryResult) } +} + +pub struct QueryResult<'a, T>(RefMut<'a, Steal<T>>); + +impl<'a, T> std::ops::Deref for QueryResult<'a, T> { + type Target = RefMut<'a, Steal<T>>; - /// Takes ownership of the query result. Further attempts to take or peek the query - /// result will panic unless it is generated by calling the `compute` method. - pub fn take(&self) -> T { - self.result.borrow_mut().take().expect("missing query result").unwrap() + fn deref(&self) -> &Self::Target { + &self.0 } +} - /// Borrows the query result using the RefCell. Panics if the result is stolen. - pub fn peek(&self) -> Ref<'_, T> { - Ref::map(self.result.borrow(), |r| { - r.as_ref().unwrap().as_ref().expect("missing query result") - }) +impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 } +} - /// Mutably borrows the query result using the RefCell. Panics if the result is stolen. - pub fn peek_mut(&self) -> RefMut<'_, T> { - RefMut::map(self.result.borrow_mut(), |r| { - r.as_mut().unwrap().as_mut().expect("missing query result") - }) +impl<'a, 'tcx> QueryResult<'a, QueryContext<'tcx>> { + pub fn enter<T>(mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T { + (*self.0).get_mut().enter(f) } } @@ -79,7 +90,6 @@ pub struct Queries<'tcx> { register_plugins: Query<(ast::Crate, Lrc<LintStore>)>, expansion: Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>, dep_graph: Query<DepGraph>, - prepare_outputs: Query<OutputFilenames>, global_ctxt: Query<QueryContext<'tcx>>, ongoing_codegen: Query<Box<dyn Any>>, } @@ -98,7 +108,6 @@ impl<'tcx> Queries<'tcx> { register_plugins: Default::default(), expansion: Default::default(), dep_graph: Default::default(), - prepare_outputs: Default::default(), global_ctxt: Default::default(), ongoing_codegen: Default::default(), } @@ -111,24 +120,22 @@ impl<'tcx> Queries<'tcx> { self.compiler.codegen_backend() } - fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> { + fn dep_graph_future(&self) -> Result<QueryResult<'_, Option<DepGraphFuture>>> { self.dep_graph_future.compute(|| { let sess = self.session(); Ok(sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess))) }) } - pub fn parse(&self) -> Result<&Query<ast::Crate>> { - self.parse.compute(|| { - passes::parse(self.session(), &self.compiler.input) - .map_err(|mut parse_error| parse_error.emit()) - }) + pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> { + self.parse + .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit())) } - pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> { + pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> { self.register_plugins.compute(|| { - let crate_name = self.crate_name()?.peek().clone(); - let krate = self.parse()?.take(); + let crate_name = *self.crate_name()?.borrow(); + let krate = self.parse()?.steal(); let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; let (krate, lint_store) = passes::register_plugins( @@ -150,24 +157,25 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn crate_name(&self) -> Result<&Query<Symbol>> { + fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> { self.crate_name.compute(|| { Ok({ let parse_result = self.parse()?; - let krate = parse_result.peek(); + let krate = parse_result.borrow(); // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. - find_crate_name(self.session(), &krate.attrs, &self.compiler.input) + find_crate_name(self.session(), &krate.attrs) }) }) } pub fn expansion( &self, - ) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> { + ) -> Result<QueryResult<'_, (Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> + { trace!("expansion"); self.expansion.compute(|| { - let crate_name = *self.crate_name()?.peek(); - let (krate, lint_store) = self.register_plugins()?.take(); + let crate_name = *self.crate_name()?.borrow(); + let (krate, lint_store) = self.register_plugins()?.steal(); let _timer = self.session().timer("configure_and_expand"); let sess = self.session(); let mut resolver = passes::create_resolver( @@ -183,10 +191,10 @@ impl<'tcx> Queries<'tcx> { }) } - fn dep_graph(&self) -> Result<&Query<DepGraph>> { + fn dep_graph(&self) -> Result<QueryResult<'_, DepGraph>> { self.dep_graph.compute(|| { let sess = self.session(); - let future_opt = self.dep_graph_future()?.take(); + let future_opt = self.dep_graph_future()?.steal(); let dep_graph = future_opt .and_then(|future| { let (prev_graph, prev_work_products) = @@ -199,45 +207,48 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> { - self.prepare_outputs.compute(|| { - let (krate, boxed_resolver, _) = &*self.expansion()?.peek(); - let crate_name = *self.crate_name()?.peek(); - passes::prepare_outputs( - self.session(), - self.compiler, - krate, - &*boxed_resolver, - crate_name, - ) - }) - } - - pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> { + pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> { self.global_ctxt.compute(|| { - let crate_name = *self.crate_name()?.peek(); - let outputs = self.prepare_outputs()?.take(); - let dep_graph = self.dep_graph()?.peek().clone(); - let (krate, resolver, lint_store) = self.expansion()?.take(); - Ok(passes::create_global_ctxt( + let crate_name = *self.crate_name()?.borrow(); + let (krate, resolver, lint_store) = self.expansion()?.steal(); + + let outputs = passes::prepare_outputs(self.session(), &krate, &resolver, crate_name)?; + + let ty::ResolverOutputs { + untracked, + global_ctxt: untracked_resolutions, + ast_lowering: untracked_resolver_for_lowering, + } = BoxedResolver::to_resolver_outputs(resolver); + + let mut qcx = passes::create_global_ctxt( self.compiler, lint_store, - krate, - dep_graph, - resolver, - outputs, - crate_name, + self.dep_graph()?.steal(), + untracked, &self.queries, &self.gcx, &self.arena, &self.hir_arena, - )) + ); + + qcx.enter(|tcx| { + let feed = tcx.feed_unit_query(); + feed.resolver_for_lowering( + tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))), + ); + feed.resolutions(tcx.arena.alloc(untracked_resolutions)); + feed.output_filenames(tcx.arena.alloc(std::sync::Arc::new(outputs))); + feed.features_query(tcx.sess.features_untracked()); + let feed = tcx.feed_local_crate(); + feed.crate_name(crate_name); + }); + Ok(qcx) }) } - pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> { + pub fn ongoing_codegen(&'tcx self) -> Result<QueryResult<'_, Box<dyn Any>>> { self.ongoing_codegen.compute(|| { - self.global_ctxt()?.peek_mut().enter(|tcx| { + self.global_ctxt()?.enter(|tcx| { tcx.analysis(()).ok(); // Don't do code generation if there were any errors @@ -293,12 +304,10 @@ impl<'tcx> Queries<'tcx> { let sess = self.session().clone(); let codegen_backend = self.codegen_backend().clone(); - let dep_graph = self.dep_graph()?.peek().clone(); - let (crate_hash, prepare_outputs) = self - .global_ctxt()? - .peek_mut() - .enter(|tcx| (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone())); - let ongoing_codegen = self.ongoing_codegen()?.take(); + let (crate_hash, prepare_outputs, dep_graph) = self.global_ctxt()?.enter(|tcx| { + (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone(), tcx.dep_graph.clone()) + }); + let ongoing_codegen = self.ongoing_codegen()?.steal(); Ok(Linker { sess, @@ -382,6 +391,7 @@ impl Compiler { // NOTE: intentionally does not compute the global context if it hasn't been built yet, // since that likely means there was a parse error. if let Some(Ok(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() { + let gcx = gcx.get_mut(); // We assume that no queries are run past here. If there are new queries // after this point, they'll show up as "<unknown>" in self-profiling data. { |