1 use interface::{Compiler, Result};
2 use passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
3 use rustc_incremental::DepGraphFuture;
4 use rustc_data_structures::sync::Lrc;
5 use rustc::session::config::{Input, OutputFilenames, OutputType};
6 use rustc::session::Session;
7 use rustc::util::common::{time, ErrorReported};
8 use rustc::util::profiling::ProfileCategory;
11 use rustc::hir::def_id::LOCAL_CRATE;
13 use rustc::ty::steal::Steal;
14 use rustc::dep_graph::DepGraph;
15 use rustc_passes::hir_stats;
16 use rustc_plugin::registry::Registry;
18 use std::cell::{Ref, RefMut, RefCell};
24 use syntax::parse::{self, PResult};
25 use syntax::util::node_count::NodeCounter;
26 use syntax::{self, ast, attr, diagnostics, visit};
27 use syntax_pos::hygiene;
29 /// Represent the result of a query.
30 /// This result can be stolen with the `take` method and returned with the `give` method.
32 result: RefCell<Option<Result<T>>>,
36 fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
37 let mut result = self.result.borrow_mut();
41 result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err)
44 /// Takes ownership of the query result. Further attempts to take or peek the query
45 /// result will panic unless it is returned by calling the `give` method.
46 pub fn take(&self) -> T {
50 .expect("missing query result")
54 /// Returns a stolen query result. Panics if there's already a result.
55 pub fn give(&self, value: T) {
56 let mut result = self.result.borrow_mut();
57 assert!(result.is_none(), "a result already exists");
58 *result = Some(Ok(value));
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| {
64 r.as_ref().unwrap().as_ref().expect("missing query result")
68 /// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
69 pub fn peek_mut(&self) -> RefMut<'_, T> {
70 RefMut::map(self.result.borrow_mut(), |r| {
71 r.as_mut().unwrap().as_mut().expect("missing query result")
76 impl<T> Default for Query<T> {
77 fn default() -> Self {
79 result: RefCell::new(None),
85 pub(crate) struct Queries {
86 dep_graph_future: Query<Option<DepGraphFuture>>,
87 parse: Query<ast::Crate>,
88 crate_name: Query<String>,
89 register_plugins: Query<(ast::Crate, PluginInfo)>,
90 expansion: Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>,
91 dep_graph: Query<DepGraph>,
92 lower_to_hir: Query<(Steal<hir::map::Forest>, ExpansionResult)>,
93 prepare_outputs: Query<OutputFilenames>,
94 codegen_channel: Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
95 Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>,
96 global_ctxt: Query<BoxedGlobalCtxt>,
97 ongoing_codegen: Query<Box<dyn Any>>,
102 pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
103 self.queries.dep_graph_future.compute(|| {
104 Ok(if self.session().opts.build_dep_graph() {
105 Some(rustc_incremental::load_dep_graph(self.session()))
112 pub fn parse(&self) -> Result<&Query<ast::Crate>> {
113 self.queries.parse.compute(|| {
114 passes::parse(self.session(), &self.input).map_err(
123 pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> {
124 self.queries.register_plugins.compute(|| {
125 let crate_name = self.crate_name()?.peek().clone();
126 let krate = self.parse()?.take();
128 passes::register_plugins(
138 pub fn crate_name(&self) -> Result<&Query<String>> {
139 self.queries.crate_name.compute(|| {
140 let parse_result = self.parse()?;
141 let krate = parse_result.peek();
142 let result = match self.crate_name {
143 Some(ref crate_name) => crate_name.clone(),
144 None => rustc_codegen_utils::link::find_crate_name(
145 Some(self.session()),
156 ) -> Result<&Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>> {
157 self.queries.expansion.compute(|| {
158 let crate_name = self.crate_name()?.peek().clone();
159 let (krate, plugin_info) = self.register_plugins()?.take();
160 passes::configure_and_expand(
162 self.cstore().clone(),
166 ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver)))))
170 pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
171 self.queries.dep_graph.compute(|| {
172 Ok(match self.dep_graph_future()?.take() {
173 None => DepGraph::new_disabled(),
175 let (prev_graph, prev_work_products) =
176 time(self.session(), "blocked while dep-graph loading finishes", || {
177 future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
178 message: format!("could not decode incremental cache: {:?}", e),
179 }).open(self.session())
181 DepGraph::new(prev_graph, prev_work_products)
187 pub fn lower_to_hir(&self) -> Result<&Query<(Steal<hir::map::Forest>, ExpansionResult)>> {
188 self.queries.lower_to_hir.compute(|| {
189 let expansion_result = self.expansion()?;
190 let (krate, resolver) = expansion_result.take();
191 let resolver_ref = &*resolver;
192 let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| {
193 passes::lower_to_hir(
197 &*self.dep_graph()?.peek(),
201 expansion_result.give((krate, Rc::new(None)));
202 Ok((hir, BoxedResolver::to_expansion_result(resolver)))
206 pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
207 self.queries.prepare_outputs.compute(|| {
208 self.lower_to_hir()?;
209 let krate = self.expansion()?;
210 let krate = krate.peek();
211 let crate_name = self.crate_name()?;
212 let crate_name = crate_name.peek();
213 passes::prepare_outputs(self.session(), self, &krate.0, &*crate_name)
217 pub fn codegen_channel(&self) -> Result<&Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
218 Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>> {
219 self.queries.codegen_channel.compute(|| {
220 let (tx, rx) = mpsc::channel();
221 Ok((Steal::new(tx), Steal::new(rx)))
225 pub fn global_ctxt(&self) -> Result<&Query<BoxedGlobalCtxt>> {
226 self.queries.global_ctxt.compute(|| {
227 let crate_name = self.crate_name()?.peek().clone();
228 let outputs = self.prepare_outputs()?.peek().clone();
229 let hir = self.lower_to_hir()?;
230 let hir = hir.peek();
231 let (ref hir_forest, ref expansion) = *hir;
232 let tx = self.codegen_channel()?.peek().0.steal();
233 Ok(passes::create_global_ctxt(
236 expansion.defs.steal(),
237 expansion.resolutions.steal(),
244 pub fn ongoing_codegen(&self) -> Result<&Query<Box<dyn Any>>> {
245 self.queries.ongoing_codegen.compute(|| {
246 let rx = self.codegen_channel()?.peek().1.steal();
247 let outputs = self.prepare_outputs()?;
248 self.global_ctxt()?.peek_mut().enter(|tcx| {
249 tcx.analysis(LOCAL_CRATE).ok();
251 // Don't do code generation if there were any errors
252 self.session().compile_status()?;
254 Ok(passes::start_codegen(
255 &***self.codegen_backend(),
264 pub fn link(&self) -> Result<&Query<()>> {
265 self.queries.link.compute(|| {
266 let sess = self.session();
268 let ongoing_codegen = self.ongoing_codegen()?.take();
270 self.codegen_backend().join_codegen_and_link(
273 &*self.dep_graph()?.peek(),
274 &*self.prepare_outputs()?.peek(),
275 ).map_err(|_| ErrorReported)?;
281 pub fn compile(&self) -> Result<()> {
282 self.prepare_outputs()?;
284 if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
285 && self.session().opts.output_types.len() == 1
292 // Drop AST after creating GlobalCtxt to free memory
293 mem::drop(self.expansion()?.take());
295 self.ongoing_codegen()?;
297 // Drop GlobalCtxt after starting codegen to free memory
298 mem::drop(self.global_ctxt()?.take());
300 self.link().map(|_| ())