]>
Commit | Line | Data |
---|---|---|
f2b60f7d | 1 | use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation}; |
532ac7d7 | 2 | use crate::interface::{Compiler, Result}; |
9ffffee4 | 3 | use crate::passes; |
532ac7d7 | 4 | |
3dfed10e | 5 | use rustc_ast as ast; |
ba9703b0 | 6 | use rustc_codegen_ssa::traits::CodegenBackend; |
5e7ed085 | 7 | use rustc_codegen_ssa::CodegenResults; |
9c376795 | 8 | use rustc_data_structures::steal::Steal; |
29967ef6 | 9 | use rustc_data_structures::svh::Svh; |
353b0b11 | 10 | use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceCell, RwLock, WorkerLocal}; |
9ffffee4 FG |
11 | use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; |
12 | use rustc_hir::definitions::Definitions; | |
dfeec247 XL |
13 | use rustc_incremental::DepGraphFuture; |
14 | use rustc_lint::LintStore; | |
9ffffee4 | 15 | use rustc_metadata::creader::CStore; |
ba9703b0 XL |
16 | use rustc_middle::arena::Arena; |
17 | use rustc_middle::dep_graph::DepGraph; | |
9ffffee4 | 18 | use rustc_middle::ty::{GlobalCtxt, TyCtxt}; |
6a06907d | 19 | use rustc_query_impl::Queries as TcxQueries; |
29967ef6 | 20 | use rustc_session::config::{self, OutputFilenames, OutputType}; |
9ffffee4 | 21 | use rustc_session::cstore::Untracked; |
ba9703b0 XL |
22 | use rustc_session::{output::find_crate_name, Session}; |
23 | use rustc_span::symbol::sym; | |
487cf647 | 24 | use rustc_span::Symbol; |
532ac7d7 | 25 | use std::any::Any; |
9c376795 | 26 | use std::cell::{RefCell, RefMut}; |
487cf647 | 27 | use std::sync::Arc; |
532ac7d7 XL |
28 | |
29 | /// Represent the result of a query. | |
fc512014 | 30 | /// |
9c376795 | 31 | /// This result can be stolen once with the [`steal`] method and generated with the [`compute`] method. |
fc512014 | 32 | /// |
9c376795 | 33 | /// [`steal`]: Steal::steal |
fc512014 | 34 | /// [`compute`]: Self::compute |
532ac7d7 | 35 | pub struct Query<T> { |
9c376795 FG |
36 | /// `None` means no value has been computed yet. |
37 | result: RefCell<Option<Result<Steal<T>>>>, | |
532ac7d7 XL |
38 | } |
39 | ||
40 | impl<T> Query<T> { | |
9c376795 FG |
41 | fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<QueryResult<'_, T>> { |
42 | RefMut::filter_map( | |
43 | self.result.borrow_mut(), | |
44 | |r: &mut Option<Result<Steal<T>>>| -> Option<&mut Steal<T>> { | |
45 | r.get_or_insert_with(|| f().map(Steal::new)).as_mut().ok() | |
46 | }, | |
47 | ) | |
48 | .map_err(|r| *r.as_ref().unwrap().as_ref().map(|_| ()).unwrap_err()) | |
49 | .map(QueryResult) | |
532ac7d7 | 50 | } |
9c376795 FG |
51 | } |
52 | ||
53 | pub struct QueryResult<'a, T>(RefMut<'a, Steal<T>>); | |
54 | ||
55 | impl<'a, T> std::ops::Deref for QueryResult<'a, T> { | |
56 | type Target = RefMut<'a, Steal<T>>; | |
532ac7d7 | 57 | |
9c376795 FG |
58 | fn deref(&self) -> &Self::Target { |
59 | &self.0 | |
532ac7d7 | 60 | } |
9c376795 | 61 | } |
532ac7d7 | 62 | |
9c376795 FG |
63 | impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> { |
64 | fn deref_mut(&mut self) -> &mut Self::Target { | |
65 | &mut self.0 | |
532ac7d7 | 66 | } |
9c376795 | 67 | } |
532ac7d7 | 68 | |
9ffffee4 FG |
69 | impl<'a, 'tcx> QueryResult<'a, &'tcx GlobalCtxt<'tcx>> { |
70 | pub fn enter<T>(&mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T { | |
9c376795 | 71 | (*self.0).get_mut().enter(f) |
532ac7d7 XL |
72 | } |
73 | } | |
74 | ||
75 | impl<T> Default for Query<T> { | |
76 | fn default() -> Self { | |
dfeec247 | 77 | Query { result: RefCell::new(None) } |
532ac7d7 XL |
78 | } |
79 | } | |
80 | ||
60c5eb7d XL |
81 | pub struct Queries<'tcx> { |
82 | compiler: &'tcx Compiler, | |
9ffffee4 | 83 | gcx_cell: OnceCell<GlobalCtxt<'tcx>>, |
6a06907d | 84 | queries: OnceCell<TcxQueries<'tcx>>, |
60c5eb7d | 85 | |
60c5eb7d | 86 | arena: WorkerLocal<Arena<'tcx>>, |
064997fb | 87 | hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>, |
60c5eb7d | 88 | |
532ac7d7 XL |
89 | dep_graph_future: Query<Option<DepGraphFuture>>, |
90 | parse: Query<ast::Crate>, | |
353b0b11 | 91 | pre_configure: Query<(ast::Crate, ast::AttrVec)>, |
487cf647 | 92 | crate_name: Query<Symbol>, |
353b0b11 | 93 | register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc<LintStore>)>, |
532ac7d7 | 94 | dep_graph: Query<DepGraph>, |
9ffffee4 FG |
95 | // This just points to what's in `gcx_cell`. |
96 | gcx: Query<&'tcx GlobalCtxt<'tcx>>, | |
532ac7d7 | 97 | ongoing_codegen: Query<Box<dyn Any>>, |
532ac7d7 XL |
98 | } |
99 | ||
60c5eb7d XL |
100 | impl<'tcx> Queries<'tcx> { |
101 | pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> { | |
102 | Queries { | |
103 | compiler, | |
9ffffee4 | 104 | gcx_cell: OnceCell::new(), |
6a06907d | 105 | queries: OnceCell::new(), |
60c5eb7d | 106 | arena: WorkerLocal::new(|_| Arena::default()), |
064997fb | 107 | hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), |
60c5eb7d XL |
108 | dep_graph_future: Default::default(), |
109 | parse: Default::default(), | |
353b0b11 | 110 | pre_configure: Default::default(), |
60c5eb7d XL |
111 | crate_name: Default::default(), |
112 | register_plugins: Default::default(), | |
60c5eb7d | 113 | dep_graph: Default::default(), |
9ffffee4 | 114 | gcx: Default::default(), |
60c5eb7d XL |
115 | ongoing_codegen: Default::default(), |
116 | } | |
117 | } | |
118 | ||
119 | fn session(&self) -> &Lrc<Session> { | |
120 | &self.compiler.sess | |
121 | } | |
122 | fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> { | |
c295e0f8 | 123 | self.compiler.codegen_backend() |
60c5eb7d XL |
124 | } |
125 | ||
9c376795 | 126 | fn dep_graph_future(&self) -> Result<QueryResult<'_, Option<DepGraphFuture>>> { |
60c5eb7d | 127 | self.dep_graph_future.compute(|| { |
136023e0 XL |
128 | let sess = self.session(); |
129 | Ok(sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess))) | |
532ac7d7 XL |
130 | }) |
131 | } | |
132 | ||
9c376795 FG |
133 | pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> { |
134 | self.parse | |
135 | .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit())) | |
532ac7d7 XL |
136 | } |
137 | ||
353b0b11 FG |
138 | pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> { |
139 | self.pre_configure.compute(|| { | |
140 | let mut krate = self.parse()?.steal(); | |
141 | ||
142 | let sess = self.session(); | |
143 | rustc_builtin_macros::cmdline_attrs::inject( | |
144 | &mut krate, | |
145 | &sess.parse_sess, | |
146 | &sess.opts.unstable_opts.crate_attr, | |
147 | ); | |
148 | ||
149 | let pre_configured_attrs = | |
150 | rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); | |
151 | Ok((krate, pre_configured_attrs)) | |
152 | }) | |
153 | } | |
154 | ||
155 | pub fn register_plugins( | |
156 | &self, | |
157 | ) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec, Lrc<LintStore>)>> { | |
60c5eb7d | 158 | self.register_plugins.compute(|| { |
9c376795 | 159 | let crate_name = *self.crate_name()?.borrow(); |
353b0b11 | 160 | let (krate, pre_configured_attrs) = self.pre_configure()?.steal(); |
532ac7d7 | 161 | |
dfeec247 | 162 | let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; |
353b0b11 | 163 | let lint_store = passes::register_plugins( |
532ac7d7 | 164 | self.session(), |
e74abb32 | 165 | &*self.codegen_backend().metadata_loader(), |
f9f354fc | 166 | self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), |
353b0b11 | 167 | &pre_configured_attrs, |
487cf647 | 168 | crate_name, |
17df50a5 | 169 | )?; |
e74abb32 XL |
170 | |
171 | // Compute the dependency graph (in the background). We want to do | |
172 | // this as early as possible, to give the DepGraph maximum time to | |
173 | // load before dep_graph() is called, but it also can't happen | |
174 | // until after rustc_incremental::prepare_session_directory() is | |
175 | // called, which happens within passes::register_plugins(). | |
176 | self.dep_graph_future().ok(); | |
177 | ||
353b0b11 | 178 | Ok((krate, pre_configured_attrs, Lrc::new(lint_store))) |
532ac7d7 XL |
179 | }) |
180 | } | |
181 | ||
9c376795 | 182 | fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> { |
60c5eb7d | 183 | self.crate_name.compute(|| { |
fc512014 | 184 | Ok({ |
353b0b11 FG |
185 | let pre_configure_result = self.pre_configure()?; |
186 | let (_, pre_configured_attrs) = &*pre_configure_result.borrow(); | |
fc512014 | 187 | // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. |
353b0b11 | 188 | find_crate_name(self.session(), pre_configured_attrs) |
e74abb32 | 189 | }) |
532ac7d7 XL |
190 | }) |
191 | } | |
192 | ||
9c376795 | 193 | fn dep_graph(&self) -> Result<QueryResult<'_, DepGraph>> { |
60c5eb7d | 194 | self.dep_graph.compute(|| { |
136023e0 | 195 | let sess = self.session(); |
9c376795 | 196 | let future_opt = self.dep_graph_future()?.steal(); |
136023e0 XL |
197 | let dep_graph = future_opt |
198 | .and_then(|future| { | |
532ac7d7 | 199 | let (prev_graph, prev_work_products) = |
136023e0 | 200 | sess.time("blocked_on_dep_graph_loading", || future.open().open(sess)); |
532ac7d7 | 201 | |
136023e0 XL |
202 | rustc_incremental::build_dep_graph(sess, prev_graph, prev_work_products) |
203 | }) | |
204 | .unwrap_or_else(DepGraph::new_disabled); | |
205 | Ok(dep_graph) | |
532ac7d7 XL |
206 | }) |
207 | } | |
208 | ||
9ffffee4 FG |
209 | pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> { |
210 | self.gcx.compute(|| { | |
9c376795 | 211 | let crate_name = *self.crate_name()?.borrow(); |
353b0b11 | 212 | let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal(); |
9c376795 | 213 | |
9ffffee4 | 214 | let sess = self.session(); |
9c376795 | 215 | |
9ffffee4 FG |
216 | let cstore = RwLock::new(Box::new(CStore::new(sess)) as _); |
217 | let definitions = RwLock::new(Definitions::new(sess.local_stable_crate_id())); | |
353b0b11 | 218 | let source_span = AppendOnlyIndexVec::new(); |
9ffffee4 FG |
219 | let _id = source_span.push(krate.spans.inner_span); |
220 | debug_assert_eq!(_id, CRATE_DEF_ID); | |
221 | let untracked = Untracked { cstore, source_span, definitions }; | |
9c376795 | 222 | |
9ffffee4 | 223 | let qcx = passes::create_global_ctxt( |
60c5eb7d | 224 | self.compiler, |
e74abb32 | 225 | lint_store, |
9c376795 FG |
226 | self.dep_graph()?.steal(), |
227 | untracked, | |
6a06907d | 228 | &self.queries, |
9ffffee4 | 229 | &self.gcx_cell, |
60c5eb7d | 230 | &self.arena, |
136023e0 | 231 | &self.hir_arena, |
9c376795 FG |
232 | ); |
233 | ||
234 | qcx.enter(|tcx| { | |
9ffffee4 FG |
235 | let feed = tcx.feed_local_crate(); |
236 | feed.crate_name(crate_name); | |
237 | ||
9c376795 | 238 | let feed = tcx.feed_unit_query(); |
353b0b11 | 239 | feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); |
9ffffee4 FG |
240 | feed.metadata_loader( |
241 | tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())), | |
9c376795 | 242 | ); |
9c376795 | 243 | feed.features_query(tcx.sess.features_untracked()); |
9c376795 FG |
244 | }); |
245 | Ok(qcx) | |
532ac7d7 XL |
246 | }) |
247 | } | |
248 | ||
9c376795 | 249 | pub fn ongoing_codegen(&'tcx self) -> Result<QueryResult<'_, Box<dyn Any>>> { |
60c5eb7d | 250 | self.ongoing_codegen.compute(|| { |
9c376795 | 251 | self.global_ctxt()?.enter(|tcx| { |
17df50a5 | 252 | tcx.analysis(()).ok(); |
532ac7d7 XL |
253 | |
254 | // Don't do code generation if there were any errors | |
255 | self.session().compile_status()?; | |
256 | ||
2b03887a FG |
257 | // If we have any delayed bugs, for example because we created TyKind::Error earlier, |
258 | // it's likely that codegen will only cause more ICEs, obscuring the original problem | |
259 | self.session().diagnostic().flush_delayed(); | |
260 | ||
5869c6ff | 261 | // Hook for UI tests. |
ba9703b0 XL |
262 | Self::check_for_rustc_errors_attr(tcx); |
263 | ||
487cf647 | 264 | Ok(passes::start_codegen(&***self.codegen_backend(), tcx)) |
532ac7d7 XL |
265 | }) |
266 | }) | |
267 | } | |
268 | ||
ba9703b0 | 269 | /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used |
5869c6ff | 270 | /// to write UI tests that actually test that compilation succeeds without reporting |
ba9703b0 XL |
271 | /// an error. |
272 | fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) { | |
5e7ed085 | 273 | let Some((def_id, _)) = tcx.entry_fn(()) else { return }; |
04454e1e | 274 | for attr in tcx.get_attrs(def_id, sym::rustc_error) { |
ba9703b0 XL |
275 | match attr.meta_item_list() { |
276 | // Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`. | |
277 | Some(list) | |
278 | if list.iter().any(|list_item| { | |
279 | matches!( | |
280 | list_item.ident().map(|i| i.name), | |
281 | Some(sym::delay_span_bug_from_inside_query) | |
282 | ) | |
283 | }) => | |
284 | { | |
285 | tcx.ensure().trigger_delay_span_bug(def_id); | |
286 | } | |
287 | ||
288 | // Bare `#[rustc_error]`. | |
289 | None => { | |
f2b60f7d | 290 | tcx.sess.emit_fatal(RustcErrorFatal { span: tcx.def_span(def_id) }); |
ba9703b0 XL |
291 | } |
292 | ||
293 | // Some other attribute. | |
294 | Some(_) => { | |
f2b60f7d FG |
295 | tcx.sess.emit_warning(RustcErrorUnexpectedAnnotation { |
296 | span: tcx.def_span(def_id), | |
297 | }); | |
ba9703b0 XL |
298 | } |
299 | } | |
300 | } | |
301 | } | |
302 | ||
60c5eb7d | 303 | pub fn linker(&'tcx self) -> Result<Linker> { |
60c5eb7d XL |
304 | let sess = self.session().clone(); |
305 | let codegen_backend = self.codegen_backend().clone(); | |
532ac7d7 | 306 | |
9c376795 | 307 | let (crate_hash, prepare_outputs, dep_graph) = self.global_ctxt()?.enter(|tcx| { |
353b0b11 FG |
308 | ( |
309 | if tcx.sess.needs_crate_hash() { Some(tcx.crate_hash(LOCAL_CRATE)) } else { None }, | |
310 | tcx.output_filenames(()).clone(), | |
311 | tcx.dep_graph.clone(), | |
312 | ) | |
9c376795 FG |
313 | }); |
314 | let ongoing_codegen = self.ongoing_codegen()?.steal(); | |
17df50a5 | 315 | |
60c5eb7d XL |
316 | Ok(Linker { |
317 | sess, | |
60c5eb7d | 318 | codegen_backend, |
17df50a5 XL |
319 | |
320 | dep_graph, | |
321 | prepare_outputs, | |
322 | crate_hash, | |
323 | ongoing_codegen, | |
532ac7d7 XL |
324 | }) |
325 | } | |
60c5eb7d XL |
326 | } |
327 | ||
328 | pub struct Linker { | |
17df50a5 | 329 | // compilation inputs |
60c5eb7d | 330 | sess: Lrc<Session>, |
17df50a5 XL |
331 | codegen_backend: Lrc<Box<dyn CodegenBackend>>, |
332 | ||
333 | // compilation outputs | |
60c5eb7d | 334 | dep_graph: DepGraph, |
487cf647 | 335 | prepare_outputs: Arc<OutputFilenames>, |
353b0b11 FG |
336 | // Only present when incr. comp. is enabled. |
337 | crate_hash: Option<Svh>, | |
60c5eb7d | 338 | ongoing_codegen: Box<dyn Any>, |
60c5eb7d XL |
339 | } |
340 | ||
341 | impl Linker { | |
342 | pub fn link(self) -> Result<()> { | |
a2a8927a XL |
343 | let (codegen_results, work_products) = self.codegen_backend.join_codegen( |
344 | self.ongoing_codegen, | |
345 | &self.sess, | |
346 | &self.prepare_outputs, | |
347 | )?; | |
29967ef6 XL |
348 | |
349 | self.sess.compile_status()?; | |
350 | ||
351 | let sess = &self.sess; | |
dfeec247 | 352 | let dep_graph = self.dep_graph; |
29967ef6 | 353 | sess.time("serialize_work_products", || { |
c295e0f8 | 354 | rustc_incremental::save_work_product_index(sess, &dep_graph, work_products) |
29967ef6 XL |
355 | }); |
356 | ||
357 | let prof = self.sess.prof.clone(); | |
dfeec247 | 358 | prof.generic_activity("drop_dep_graph").run(move || drop(dep_graph)); |
74b04a01 | 359 | |
29967ef6 XL |
360 | // Now that we won't touch anything in the incremental compilation directory |
361 | // any more, we can finalize it (which involves renaming it) | |
362 | rustc_incremental::finalize_session_directory(&self.sess, self.crate_hash); | |
363 | ||
74b04a01 XL |
364 | if !self |
365 | .sess | |
366 | .opts | |
367 | .output_types | |
368 | .keys() | |
369 | .any(|&i| i == OutputType::Exe || i == OutputType::Metadata) | |
370 | { | |
371 | return Ok(()); | |
372 | } | |
29967ef6 | 373 | |
064997fb | 374 | if sess.opts.unstable_opts.no_link { |
5e7ed085 | 375 | let encoded = CodegenResults::serialize_rlink(&codegen_results); |
29967ef6 | 376 | let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); |
f2b60f7d FG |
377 | std::fs::write(&rlink_file, encoded) |
378 | .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; | |
29967ef6 XL |
379 | return Ok(()); |
380 | } | |
381 | ||
5869c6ff | 382 | let _timer = sess.prof.verbose_generic_activity("link_crate"); |
74b04a01 | 383 | self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs) |
60c5eb7d XL |
384 | } |
385 | } | |
386 | ||
387 | impl Compiler { | |
388 | pub fn enter<F, T>(&self, f: F) -> T | |
dfeec247 XL |
389 | where |
390 | F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T, | |
60c5eb7d | 391 | { |
dfeec247 | 392 | let mut _timer = None; |
c295e0f8 | 393 | let queries = Queries::new(self); |
60c5eb7d XL |
394 | let ret = f(&queries); |
395 | ||
5869c6ff XL |
396 | // NOTE: intentionally does not compute the global context if it hasn't been built yet, |
397 | // since that likely means there was a parse error. | |
9ffffee4 | 398 | if let Some(Ok(gcx)) = &mut *queries.gcx.result.borrow_mut() { |
9c376795 | 399 | let gcx = gcx.get_mut(); |
5869c6ff XL |
400 | // We assume that no queries are run past here. If there are new queries |
401 | // after this point, they'll show up as "<unknown>" in self-profiling data. | |
402 | { | |
403 | let _prof_timer = | |
404 | queries.session().prof.generic_activity("self_profile_alloc_query_strings"); | |
6a06907d | 405 | gcx.enter(rustc_query_impl::alloc_self_profile_query_strings); |
5869c6ff XL |
406 | } |
407 | ||
cdc7bbd5 XL |
408 | self.session() |
409 | .time("serialize_dep_graph", || gcx.enter(rustc_incremental::save_dep_graph)); | |
60c5eb7d XL |
410 | } |
411 | ||
dfeec247 XL |
412 | _timer = Some(self.session().timer("free_global_ctxt")); |
413 | ||
60c5eb7d XL |
414 | ret |
415 | } | |
532ac7d7 | 416 | } |