]> git.lizzy.rs Git - rust.git/blob - src/librustc_interface/queries.rs
Rollup merge of #60766 - vorner:weak-into-raw, r=sfackler
[rust.git] / src / librustc_interface / queries.rs
1 use crate::interface::{Compiler, Result};
2 use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
3
4 use rustc_incremental::DepGraphFuture;
5 use rustc_data_structures::sync::Lrc;
6 use rustc::session::config::{Input, OutputFilenames, OutputType};
7 use rustc::session::Session;
8 use rustc::util::common::{time, ErrorReported};
9 use rustc::util::profiling::ProfileCategory;
10 use rustc::lint;
11 use rustc::hir;
12 use rustc::hir::def_id::LOCAL_CRATE;
13 use rustc::ty;
14 use rustc::ty::steal::Steal;
15 use rustc::dep_graph::DepGraph;
16 use rustc_passes::hir_stats;
17 use rustc_plugin::registry::Registry;
18 use serialize::json;
19 use std::cell::{Ref, RefMut, RefCell};
20 use std::ops::Deref;
21 use std::rc::Rc;
22 use std::sync::mpsc;
23 use std::any::Any;
24 use std::mem;
25 use syntax::parse::{self, PResult};
26 use syntax::util::node_count::NodeCounter;
27 use syntax::{self, ast, attr, diagnostics, visit};
28 use syntax_pos::hygiene;
29
30 /// Represent the result of a query.
31 /// This result can be stolen with the `take` method and returned with the `give` method.
32 pub struct Query<T> {
33     result: RefCell<Option<Result<T>>>,
34 }
35
36 impl<T> Query<T> {
37     fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
38         let mut result = self.result.borrow_mut();
39         if result.is_none() {
40             *result = Some(f());
41         }
42         result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err)
43     }
44
45     /// Takes ownership of the query result. Further attempts to take or peek the query
46     /// result will panic unless it is returned by calling the `give` method.
47     pub fn take(&self) -> T {
48         self.result
49             .borrow_mut()
50             .take()
51             .expect("missing query result")
52             .unwrap()
53     }
54
55     /// Returns a stolen query result. Panics if there's already a result.
56     pub fn give(&self, value: T) {
57         let mut result = self.result.borrow_mut();
58         assert!(result.is_none(), "a result already exists");
59         *result = Some(Ok(value));
60     }
61
62     /// Borrows the query result using the RefCell. Panics if the result is stolen.
63     pub fn peek(&self) -> Ref<'_, T> {
64         Ref::map(self.result.borrow(), |r| {
65             r.as_ref().unwrap().as_ref().expect("missing query result")
66         })
67     }
68
69     /// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
70     pub fn peek_mut(&self) -> RefMut<'_, T> {
71         RefMut::map(self.result.borrow_mut(), |r| {
72             r.as_mut().unwrap().as_mut().expect("missing query result")
73         })
74     }
75 }
76
77 impl<T> Default for Query<T> {
78     fn default() -> Self {
79         Query {
80             result: RefCell::new(None),
81         }
82     }
83 }
84
85 #[derive(Default)]
86 pub(crate) struct Queries {
87     dep_graph_future: Query<Option<DepGraphFuture>>,
88     parse: Query<ast::Crate>,
89     crate_name: Query<String>,
90     register_plugins: Query<(ast::Crate, PluginInfo)>,
91     expansion: Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>,
92     dep_graph: Query<DepGraph>,
93     lower_to_hir: Query<(Steal<hir::map::Forest>, ExpansionResult)>,
94     prepare_outputs: Query<OutputFilenames>,
95     codegen_channel: Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
96                             Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>,
97     global_ctxt: Query<BoxedGlobalCtxt>,
98     ongoing_codegen: Query<Box<dyn Any>>,
99     link: Query<()>,
100 }
101
102 impl Compiler {
103     pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
104         self.queries.dep_graph_future.compute(|| {
105             Ok(if self.session().opts.build_dep_graph() {
106                 Some(rustc_incremental::load_dep_graph(self.session()))
107             } else {
108                 None
109             })
110         })
111     }
112
113     pub fn parse(&self) -> Result<&Query<ast::Crate>> {
114         self.queries.parse.compute(|| {
115             passes::parse(self.session(), &self.input).map_err(
116                 |mut parse_error| {
117                     parse_error.emit();
118                     ErrorReported
119                 },
120             )
121         })
122     }
123
124     pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> {
125         self.queries.register_plugins.compute(|| {
126             let crate_name = self.crate_name()?.peek().clone();
127             let krate = self.parse()?.take();
128
129             passes::register_plugins(
130                 self,
131                 self.session(),
132                 self.cstore(),
133                 krate,
134                 &crate_name,
135             )
136         })
137     }
138
139     pub fn crate_name(&self) -> Result<&Query<String>> {
140         self.queries.crate_name.compute(|| {
141             let parse_result = self.parse()?;
142             let krate = parse_result.peek();
143             let result = match self.crate_name {
144                 Some(ref crate_name) => crate_name.clone(),
145                 None => rustc_codegen_utils::link::find_crate_name(
146                     Some(self.session()),
147                     &krate.attrs,
148                     &self.input
149                 ),
150             };
151             Ok(result)
152         })
153     }
154
155     pub fn expansion(
156         &self
157     ) -> Result<&Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>> {
158         self.queries.expansion.compute(|| {
159             let crate_name = self.crate_name()?.peek().clone();
160             let (krate, plugin_info) = self.register_plugins()?.take();
161             passes::configure_and_expand(
162                 self.sess.clone(),
163                 self.cstore().clone(),
164                 krate,
165                 &crate_name,
166                 plugin_info,
167             ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver)))))
168         })
169     }
170
171     pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
172         self.queries.dep_graph.compute(|| {
173             Ok(match self.dep_graph_future()?.take() {
174                 None => DepGraph::new_disabled(),
175                 Some(future) => {
176                     let (prev_graph, prev_work_products) =
177                         time(self.session(), "blocked while dep-graph loading finishes", || {
178                             future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
179                                 message: format!("could not decode incremental cache: {:?}", e),
180                             }).open(self.session())
181                         });
182                     DepGraph::new(prev_graph, prev_work_products)
183                 }
184             })
185         })
186     }
187
188     pub fn lower_to_hir(&self) -> Result<&Query<(Steal<hir::map::Forest>, ExpansionResult)>> {
189         self.queries.lower_to_hir.compute(|| {
190             let expansion_result = self.expansion()?;
191             let (krate, resolver) = expansion_result.take();
192             let resolver_ref = &*resolver;
193             let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| {
194                 passes::lower_to_hir(
195                     self.session(),
196                     self.cstore(),
197                     resolver,
198                     &*self.dep_graph()?.peek(),
199                     &krate
200                 )
201             })?);
202             expansion_result.give((krate, Rc::new(None)));
203             Ok((hir, BoxedResolver::to_expansion_result(resolver)))
204         })
205     }
206
207     pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
208         self.queries.prepare_outputs.compute(|| {
209             self.lower_to_hir()?;
210             let krate = self.expansion()?;
211             let krate = krate.peek();
212             let crate_name = self.crate_name()?;
213             let crate_name = crate_name.peek();
214             passes::prepare_outputs(self.session(), self, &krate.0, &*crate_name)
215         })
216     }
217
218     pub fn codegen_channel(&self) -> Result<&Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
219                                                     Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>> {
220         self.queries.codegen_channel.compute(|| {
221             let (tx, rx) = mpsc::channel();
222             Ok((Steal::new(tx), Steal::new(rx)))
223         })
224     }
225
226     pub fn global_ctxt(&self) -> Result<&Query<BoxedGlobalCtxt>> {
227         self.queries.global_ctxt.compute(|| {
228             let crate_name = self.crate_name()?.peek().clone();
229             let outputs = self.prepare_outputs()?.peek().clone();
230             let hir = self.lower_to_hir()?;
231             let hir = hir.peek();
232             let (ref hir_forest, ref expansion) = *hir;
233             let tx = self.codegen_channel()?.peek().0.steal();
234             Ok(passes::create_global_ctxt(
235                 self,
236                 hir_forest.steal(),
237                 expansion.defs.steal(),
238                 expansion.resolutions.steal(),
239                 outputs,
240                 tx,
241                 &crate_name))
242         })
243     }
244
245     pub fn ongoing_codegen(&self) -> Result<&Query<Box<dyn Any>>> {
246         self.queries.ongoing_codegen.compute(|| {
247             let rx = self.codegen_channel()?.peek().1.steal();
248             let outputs = self.prepare_outputs()?;
249             self.global_ctxt()?.peek_mut().enter(|tcx| {
250                 tcx.analysis(LOCAL_CRATE).ok();
251
252                 // Don't do code generation if there were any errors
253                 self.session().compile_status()?;
254
255                 Ok(passes::start_codegen(
256                     &***self.codegen_backend(),
257                     tcx,
258                     rx,
259                     &*outputs.peek()
260                 ))
261             })
262         })
263     }
264
265     pub fn link(&self) -> Result<&Query<()>> {
266         self.queries.link.compute(|| {
267             let sess = self.session();
268
269             let ongoing_codegen = self.ongoing_codegen()?.take();
270
271             self.codegen_backend().join_codegen_and_link(
272                 ongoing_codegen,
273                 sess,
274                 &*self.dep_graph()?.peek(),
275                 &*self.prepare_outputs()?.peek(),
276             ).map_err(|_| ErrorReported)?;
277
278             Ok(())
279         })
280     }
281
282     pub fn compile(&self) -> Result<()> {
283         self.prepare_outputs()?;
284
285         if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
286             && self.session().opts.output_types.len() == 1
287         {
288             return Ok(())
289         }
290
291         self.global_ctxt()?;
292
293         // Drop AST after creating GlobalCtxt to free memory
294         mem::drop(self.expansion()?.take());
295
296         self.ongoing_codegen()?;
297
298         // Drop GlobalCtxt after starting codegen to free memory
299         mem::drop(self.global_ctxt()?.take());
300
301         self.link().map(|_| ())
302     }
303 }