]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_interface/src/queries.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_interface / src / queries.rs
CommitLineData
f2b60f7d 1use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation};
532ac7d7 2use crate::interface::{Compiler, Result};
9ffffee4 3use crate::passes;
532ac7d7 4
3dfed10e 5use rustc_ast as ast;
ba9703b0 6use rustc_codegen_ssa::traits::CodegenBackend;
5e7ed085 7use rustc_codegen_ssa::CodegenResults;
9c376795 8use rustc_data_structures::steal::Steal;
29967ef6 9use rustc_data_structures::svh::Svh;
353b0b11 10use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceCell, RwLock, WorkerLocal};
9ffffee4
FG
11use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
12use rustc_hir::definitions::Definitions;
dfeec247
XL
13use rustc_incremental::DepGraphFuture;
14use rustc_lint::LintStore;
9ffffee4 15use rustc_metadata::creader::CStore;
ba9703b0
XL
16use rustc_middle::arena::Arena;
17use rustc_middle::dep_graph::DepGraph;
9ffffee4 18use rustc_middle::ty::{GlobalCtxt, TyCtxt};
6a06907d 19use rustc_query_impl::Queries as TcxQueries;
29967ef6 20use rustc_session::config::{self, OutputFilenames, OutputType};
9ffffee4 21use rustc_session::cstore::Untracked;
ba9703b0
XL
22use rustc_session::{output::find_crate_name, Session};
23use rustc_span::symbol::sym;
487cf647 24use rustc_span::Symbol;
532ac7d7 25use std::any::Any;
9c376795 26use std::cell::{RefCell, RefMut};
487cf647 27use 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 35pub 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
40impl<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
53pub struct QueryResult<'a, T>(RefMut<'a, Steal<T>>);
54
55impl<'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
63impl<'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
69impl<'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
75impl<T> Default for Query<T> {
76 fn default() -> Self {
dfeec247 77 Query { result: RefCell::new(None) }
532ac7d7
XL
78 }
79}
80
60c5eb7d
XL
81pub 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
100impl<'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
328pub 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
341impl 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
387impl 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}