1 use crate::interface::{Compiler, Result};
2 use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
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;
12 use rustc::hir::def_id::LOCAL_CRATE;
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 rustc_serialize::json;
19 use std::cell::{Ref, RefMut, RefCell};
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;
30 /// Represent the result of a query.
31 /// This result can be stolen with the `take` method and returned with the `give` method.
33 result: RefCell<Option<Result<T>>>,
37 fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
38 let mut result = self.result.borrow_mut();
42 result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err)
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 {
51 .expect("missing query result")
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));
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")
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")
77 impl<T> Default for Query<T> {
78 fn default() -> Self {
80 result: RefCell::new(None),
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>>,
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()))
113 pub fn parse(&self) -> Result<&Query<ast::Crate>> {
114 self.queries.parse.compute(|| {
115 passes::parse(self.session(), &self.input).map_err(
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();
129 passes::register_plugins(
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()),
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(
163 self.cstore().clone(),
167 ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver)))))
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(),
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())
182 DepGraph::new(prev_graph, prev_work_products)
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(
198 &*self.dep_graph()?.peek(),
202 expansion_result.give((krate, Rc::new(None)));
203 Ok((hir, BoxedResolver::to_expansion_result(resolver)))
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)
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)))
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(
237 expansion.defs.steal(),
238 expansion.resolutions.steal(),
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();
252 // Don't do code generation if there were any errors
253 self.session().compile_status()?;
255 Ok(passes::start_codegen(
256 &***self.codegen_backend(),
265 pub fn link(&self) -> Result<&Query<()>> {
266 self.queries.link.compute(|| {
267 let sess = self.session();
269 let ongoing_codegen = self.ongoing_codegen()?.take();
271 self.codegen_backend().join_codegen_and_link(
274 &*self.dep_graph()?.peek(),
275 &*self.prepare_outputs()?.peek(),
276 ).map_err(|_| ErrorReported)?;
282 pub fn compile(&self) -> Result<()> {
283 self.prepare_outputs()?;
285 if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
286 && self.session().opts.output_types.len() == 1
293 // Drop AST after creating GlobalCtxt to free memory
294 mem::drop(self.expansion()?.take());
296 self.ongoing_codegen()?;
298 // Drop GlobalCtxt after starting codegen to free memory
299 mem::drop(self.global_ctxt()?.take());
301 self.link().map(|_| ())