]>
Commit | Line | Data |
---|---|---|
532ac7d7 | 1 | use crate::interface::{Compiler, Result}; |
532ac7d7 | 2 | use crate::proc_macro_decls; |
dfeec247 | 3 | use crate::util; |
532ac7d7 | 4 | |
3dfed10e | 5 | use once_cell::sync::Lazy; |
74b04a01 | 6 | use rustc_ast::mut_visit::MutVisitor; |
3dfed10e | 7 | use rustc_ast::{self as ast, visit}; |
48663c56 | 8 | use rustc_codegen_ssa::back::link::emit_metadata; |
ba9703b0 | 9 | use rustc_codegen_ssa::traits::CodegenBackend; |
f9f354fc | 10 | use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; |
3dfed10e | 11 | use rustc_data_structures::temp_dir::MaybeTempDir; |
532ac7d7 | 12 | use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; |
ba9703b0 | 13 | use rustc_errors::{ErrorReported, PResult}; |
dfeec247 XL |
14 | use rustc_expand::base::ExtCtxt; |
15 | use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; | |
ba9703b0 | 16 | use rustc_hir::definitions::Definitions; |
74b04a01 | 17 | use rustc_hir::Crate; |
dfeec247 | 18 | use rustc_lint::LintStore; |
ba9703b0 XL |
19 | use rustc_middle::arena::Arena; |
20 | use rustc_middle::dep_graph::DepGraph; | |
21 | use rustc_middle::middle; | |
22 | use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn}; | |
3dfed10e | 23 | use rustc_middle::ty::query::Providers; |
ba9703b0 XL |
24 | use rustc_middle::ty::steal::Steal; |
25 | use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; | |
532ac7d7 | 26 | use rustc_mir as mir; |
dfeec247 | 27 | use rustc_mir_build as mir_build; |
60c5eb7d | 28 | use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; |
dfeec247 | 29 | use rustc_passes::{self, hir_stats, layout_test}; |
60c5eb7d | 30 | use rustc_plugin_impl as plugin; |
532ac7d7 | 31 | use rustc_resolve::{Resolver, ResolverArenas}; |
f9f354fc | 32 | use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}; |
6c58768f | 33 | use rustc_session::lint; |
ba9703b0 XL |
34 | use rustc_session::output::{filename_for_input, filename_for_metadata}; |
35 | use rustc_session::search_paths::PathKind; | |
36 | use rustc_session::Session; | |
dfeec247 | 37 | use rustc_span::symbol::Symbol; |
ba9703b0 XL |
38 | use rustc_span::{FileName, RealFileName}; |
39 | use rustc_trait_selection::traits; | |
532ac7d7 | 40 | use rustc_typeck as typeck; |
3dfed10e | 41 | use tracing::{info, warn}; |
532ac7d7 | 42 | |
416331ca | 43 | use rustc_serialize::json; |
48663c56 | 44 | use tempfile::Builder as TempFileBuilder; |
532ac7d7 XL |
45 | |
46 | use std::any::Any; | |
dfeec247 | 47 | use std::cell::RefCell; |
532ac7d7 | 48 | use std::ffi::OsString; |
74b04a01 | 49 | use std::io::{self, BufWriter, Write}; |
416331ca | 50 | use std::path::PathBuf; |
532ac7d7 | 51 | use std::rc::Rc; |
dfeec247 | 52 | use std::{env, fs, iter, mem}; |
532ac7d7 XL |
53 | |
54 | pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { | |
dfeec247 XL |
55 | let krate = sess.time("parse_crate", || match input { |
56 | Input::File(file) => parse_crate_from_file(file, &sess.parse_sess), | |
57 | Input::Str { input, name } => { | |
58 | parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess) | |
e74abb32 | 59 | } |
532ac7d7 | 60 | })?; |
532ac7d7 | 61 | |
532ac7d7 XL |
62 | if sess.opts.debugging_opts.ast_json_noexpand { |
63 | println!("{}", json::as_json(&krate)); | |
64 | } | |
65 | ||
66 | if sess.opts.debugging_opts.input_stats { | |
dfeec247 | 67 | println!("Lines of code: {}", sess.source_map().count_lines()); |
532ac7d7 XL |
68 | println!("Pre-expansion node count: {}", count_nodes(&krate)); |
69 | } | |
70 | ||
71 | if let Some(ref s) = sess.opts.debugging_opts.show_span { | |
dfeec247 | 72 | rustc_ast_passes::show_span::run(sess.diagnostic(), s, &krate); |
532ac7d7 XL |
73 | } |
74 | ||
75 | if sess.opts.debugging_opts.hir_stats { | |
76 | hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); | |
77 | } | |
78 | ||
79 | Ok(krate) | |
80 | } | |
81 | ||
82 | fn count_nodes(krate: &ast::Crate) -> usize { | |
74b04a01 | 83 | let mut counter = rustc_ast_passes::node_count::NodeCounter::new(); |
532ac7d7 XL |
84 | visit::walk_crate(&mut counter, krate); |
85 | counter.count | |
86 | } | |
87 | ||
88 | declare_box_region_type!( | |
89 | pub BoxedResolver, | |
90 | for(), | |
e74abb32 | 91 | (&mut Resolver<'_>) -> (Result<ast::Crate>, ResolverOutputs) |
532ac7d7 XL |
92 | ); |
93 | ||
60c5eb7d | 94 | /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins, |
532ac7d7 XL |
95 | /// syntax expansion, secondary `cfg` expansion, synthesis of a test |
96 | /// harness if one is to be provided, injection of a dependency on the | |
97 | /// standard library and prelude, and name resolution. | |
98 | /// | |
99 | /// Returns `None` if we're aborting after handling -W help. | |
100 | pub fn configure_and_expand( | |
101 | sess: Lrc<Session>, | |
dfeec247 | 102 | lint_store: Lrc<LintStore>, |
e74abb32 | 103 | metadata_loader: Box<MetadataLoaderDyn>, |
532ac7d7 XL |
104 | krate: ast::Crate, |
105 | crate_name: &str, | |
532ac7d7 | 106 | ) -> Result<(ast::Crate, BoxedResolver)> { |
3dfed10e | 107 | tracing::trace!("configure_and_expand"); |
532ac7d7 XL |
108 | // Currently, we ignore the name resolution data structures for the purposes of dependency |
109 | // tracking. Instead we will run name resolution and include its output in the hash of each | |
110 | // item, much like we do for macro expansion. In other words, the hash reflects not just | |
111 | // its contents but the results of name resolution on those contents. Hopefully we'll push | |
112 | // this back at some point. | |
113 | let crate_name = crate_name.to_string(); | |
f9f354fc XL |
114 | let (result, resolver) = BoxedResolver::new(static move |mut action| { |
115 | let _ = action; | |
532ac7d7 | 116 | let sess = &*sess; |
532ac7d7 XL |
117 | let resolver_arenas = Resolver::arenas(); |
118 | let res = configure_and_expand_inner( | |
119 | sess, | |
e74abb32 | 120 | &lint_store, |
532ac7d7 XL |
121 | krate, |
122 | &crate_name, | |
123 | &resolver_arenas, | |
e74abb32 | 124 | &*metadata_loader, |
532ac7d7 XL |
125 | ); |
126 | let mut resolver = match res { | |
127 | Err(v) => { | |
128 | yield BoxedResolver::initial_yield(Err(v)); | |
129 | panic!() | |
130 | } | |
131 | Ok((krate, resolver)) => { | |
f9f354fc | 132 | action = yield BoxedResolver::initial_yield(Ok(krate)); |
532ac7d7 XL |
133 | resolver |
134 | } | |
135 | }; | |
f9f354fc | 136 | box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver), action); |
e74abb32 | 137 | resolver.into_outputs() |
532ac7d7 XL |
138 | }); |
139 | result.map(|k| (k, resolver)) | |
140 | } | |
141 | ||
532ac7d7 | 142 | impl BoxedResolver { |
e74abb32 | 143 | pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs { |
416331ca XL |
144 | match Rc::try_unwrap(resolver) { |
145 | Ok(resolver) => resolver.into_inner().complete(), | |
e74abb32 | 146 | Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()), |
532ac7d7 XL |
147 | } |
148 | } | |
149 | } | |
150 | ||
532ac7d7 | 151 | pub fn register_plugins<'a>( |
532ac7d7 | 152 | sess: &'a Session, |
e74abb32 | 153 | metadata_loader: &'a dyn MetadataLoader, |
dfeec247 | 154 | register_lints: impl Fn(&Session, &mut LintStore), |
532ac7d7 XL |
155 | mut krate: ast::Crate, |
156 | crate_name: &str, | |
dfeec247 XL |
157 | ) -> Result<(ast::Crate, Lrc<LintStore>)> { |
158 | krate = sess.time("attributes_injection", || { | |
159 | rustc_builtin_macros::cmdline_attrs::inject( | |
160 | krate, | |
161 | &sess.parse_sess, | |
162 | &sess.opts.debugging_opts.crate_attr, | |
e1599b0c | 163 | ) |
532ac7d7 XL |
164 | }); |
165 | ||
3dfed10e | 166 | let (krate, features) = rustc_expand::config::features(sess, krate); |
532ac7d7 XL |
167 | // these need to be set "early" so that expansion sees `quote` if enabled. |
168 | sess.init_features(features); | |
169 | ||
170 | let crate_types = util::collect_crate_types(sess, &krate.attrs); | |
f9f354fc | 171 | sess.init_crate_types(crate_types); |
532ac7d7 XL |
172 | |
173 | let disambiguator = util::compute_crate_disambiguator(sess); | |
f9f354fc | 174 | sess.crate_disambiguator.set(disambiguator).expect("not yet initialized"); |
532ac7d7 XL |
175 | rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); |
176 | ||
177 | if sess.opts.incremental.is_some() { | |
dfeec247 | 178 | sess.time("incr_comp_garbage_collect_session_directories", || { |
532ac7d7 XL |
179 | if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { |
180 | warn!( | |
181 | "Error while trying to garbage collect incremental \ | |
182 | compilation cache directory: {}", | |
183 | e | |
184 | ); | |
185 | } | |
186 | }); | |
187 | } | |
188 | ||
dfeec247 | 189 | sess.time("recursion_limit", || { |
74b04a01 | 190 | middle::limits::update_limits(sess, &krate); |
532ac7d7 XL |
191 | }); |
192 | ||
e74abb32 XL |
193 | let mut lint_store = rustc_lint::new_lint_store( |
194 | sess.opts.debugging_opts.no_interleave_lints, | |
195 | sess.unstable_options(), | |
196 | ); | |
60c5eb7d | 197 | register_lints(&sess, &mut lint_store); |
e74abb32 | 198 | |
dfeec247 XL |
199 | let registrars = |
200 | sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate)); | |
201 | sess.time("plugin_registration", || { | |
60c5eb7d | 202 | let mut registry = plugin::Registry { lint_store: &mut lint_store }; |
532ac7d7 | 203 | for registrar in registrars { |
60c5eb7d | 204 | registrar(&mut registry); |
532ac7d7 XL |
205 | } |
206 | }); | |
207 | ||
60c5eb7d | 208 | Ok((krate, Lrc::new(lint_store))) |
532ac7d7 XL |
209 | } |
210 | ||
ba9703b0 | 211 | fn pre_expansion_lint(sess: &Session, lint_store: &LintStore, krate: &ast::Crate) { |
dfeec247 XL |
212 | sess.time("pre_AST_expansion_lint_checks", || { |
213 | rustc_lint::check_ast_crate( | |
532ac7d7 | 214 | sess, |
e74abb32 | 215 | lint_store, |
532ac7d7 XL |
216 | &krate, |
217 | true, | |
e74abb32 | 218 | None, |
dfeec247 XL |
219 | rustc_lint::BuiltinCombinedPreExpansionLintPass::new(), |
220 | ); | |
532ac7d7 | 221 | }); |
ba9703b0 XL |
222 | } |
223 | ||
224 | fn configure_and_expand_inner<'a>( | |
225 | sess: &'a Session, | |
226 | lint_store: &'a LintStore, | |
227 | mut krate: ast::Crate, | |
228 | crate_name: &str, | |
229 | resolver_arenas: &'a ResolverArenas<'a>, | |
230 | metadata_loader: &'a MetadataLoaderDyn, | |
231 | ) -> Result<(ast::Crate, Resolver<'a>)> { | |
3dfed10e | 232 | tracing::trace!("configure_and_expand_inner"); |
ba9703b0 | 233 | pre_expansion_lint(sess, lint_store, &krate); |
532ac7d7 | 234 | |
dfeec247 XL |
235 | let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas); |
236 | rustc_builtin_macros::register_builtin_macros(&mut resolver, sess.edition()); | |
e1599b0c | 237 | |
dfeec247 | 238 | krate = sess.time("crate_injection", || { |
e1599b0c | 239 | let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s)); |
dfeec247 | 240 | let (krate, name) = rustc_builtin_macros::standard_library_imports::inject( |
e1599b0c XL |
241 | krate, |
242 | &mut resolver, | |
3dfed10e | 243 | &sess, |
e1599b0c XL |
244 | alt_std_name, |
245 | ); | |
246 | if let Some(name) = name { | |
f9f354fc | 247 | sess.parse_sess.injected_crate_name.set(name).expect("not yet initialized"); |
e1599b0c XL |
248 | } |
249 | krate | |
250 | }); | |
251 | ||
3dfed10e | 252 | util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer()); |
e74abb32 | 253 | |
532ac7d7 | 254 | // Expand all macros |
dfeec247 | 255 | krate = sess.time("macro_expand_crate", || { |
532ac7d7 XL |
256 | // Windows dlls do not have rpaths, so they don't know how to find their |
257 | // dependencies. It's up to us to tell the system where to find all the | |
258 | // dependent dlls. Note that this uses cfg!(windows) as opposed to | |
259 | // targ_cfg because syntax extensions are always loaded for the host | |
260 | // compiler, not for the target. | |
261 | // | |
262 | // This is somewhat of an inherently racy operation, however, as | |
263 | // multiple threads calling this function could possibly continue | |
264 | // extending PATH far beyond what it should. To solve this for now we | |
265 | // just don't add any new elements to PATH which are already there | |
266 | // within PATH. This is basically a targeted fix at #17360 for rustdoc | |
267 | // which runs rustc in parallel but has been seen (#33844) to cause | |
268 | // problems with PATH becoming too long. | |
269 | let mut old_path = OsString::new(); | |
270 | if cfg!(windows) { | |
271 | old_path = env::var_os("PATH").unwrap_or(old_path); | |
272 | let mut new_path = sess.host_filesearch(PathKind::All).search_path_dirs(); | |
273 | for path in env::split_paths(&old_path) { | |
274 | if !new_path.contains(&path) { | |
275 | new_path.push(path); | |
276 | } | |
277 | } | |
278 | env::set_var( | |
279 | "PATH", | |
280 | &env::join_paths( | |
dfeec247 XL |
281 | new_path.iter().filter(|p| env::join_paths(iter::once(p)).is_ok()), |
282 | ) | |
283 | .unwrap(), | |
532ac7d7 XL |
284 | ); |
285 | } | |
286 | ||
287 | // Create the config for macro expansion | |
288 | let features = sess.features_untracked(); | |
dfeec247 | 289 | let cfg = rustc_expand::expand::ExpansionConfig { |
532ac7d7 | 290 | features: Some(&features), |
f9f354fc | 291 | recursion_limit: sess.recursion_limit(), |
532ac7d7 XL |
292 | trace_mac: sess.opts.debugging_opts.trace_macros, |
293 | should_test: sess.opts.test, | |
f035d41b | 294 | span_debug: sess.opts.debugging_opts.span_debug, |
dfeec247 | 295 | ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) |
532ac7d7 XL |
296 | }; |
297 | ||
ba9703b0 | 298 | let extern_mod_loaded = |k: &ast::Crate| pre_expansion_lint(sess, lint_store, k); |
3dfed10e | 299 | let mut ecx = ExtCtxt::new(&sess, cfg, &mut resolver, Some(&extern_mod_loaded)); |
532ac7d7 XL |
300 | |
301 | // Expand macros now! | |
dfeec247 | 302 | let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); |
532ac7d7 XL |
303 | |
304 | // The rest is error reporting | |
305 | ||
dfeec247 | 306 | sess.time("check_unused_macros", || { |
532ac7d7 XL |
307 | ecx.check_unused_macros(); |
308 | }); | |
309 | ||
6c58768f XL |
310 | let mut missing_fragment_specifiers: Vec<_> = ecx |
311 | .sess | |
312 | .parse_sess | |
313 | .missing_fragment_specifiers | |
314 | .borrow() | |
315 | .iter() | |
316 | .map(|(span, node_id)| (*span, *node_id)) | |
317 | .collect(); | |
318 | missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span); | |
319 | ||
320 | let recursion_limit_hit = ecx.reduced_recursion_limit.is_some(); | |
321 | ||
322 | for (span, node_id) in missing_fragment_specifiers { | |
323 | let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; | |
324 | let msg = "missing fragment specifier"; | |
325 | resolver.lint_buffer().buffer_lint(lint, node_id, span, msg); | |
326 | } | |
532ac7d7 XL |
327 | if cfg!(windows) { |
328 | env::set_var("PATH", &old_path); | |
329 | } | |
ba9703b0 XL |
330 | |
331 | if recursion_limit_hit { | |
332 | // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed | |
333 | // with a large AST | |
334 | Err(ErrorReported) | |
335 | } else { | |
336 | Ok(krate) | |
337 | } | |
338 | })?; | |
532ac7d7 | 339 | |
dfeec247 | 340 | sess.time("maybe_building_test_harness", || { |
3dfed10e | 341 | rustc_builtin_macros::test_harness::inject(&sess, &mut resolver, &mut krate) |
532ac7d7 XL |
342 | }); |
343 | ||
60c5eb7d | 344 | if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty { |
3dfed10e | 345 | tracing::debug!("replacing bodies with loop {{}}"); |
60c5eb7d | 346 | util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate); |
532ac7d7 XL |
347 | } |
348 | ||
dfeec247 XL |
349 | let has_proc_macro_decls = sess.time("AST_validation", || { |
350 | rustc_ast_passes::ast_validation::check_crate(sess, &krate, &mut resolver.lint_buffer()) | |
532ac7d7 XL |
351 | }); |
352 | ||
f9f354fc XL |
353 | let crate_types = sess.crate_types(); |
354 | let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); | |
e1599b0c XL |
355 | |
356 | // For backwards compatibility, we don't try to run proc macro injection | |
357 | // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being | |
358 | // specified. This should only affect users who manually invoke 'rustdoc', as | |
359 | // 'cargo doc' will automatically pass the proper '--crate-type' flags. | |
360 | // However, we do emit a warning, to let such users know that they should | |
361 | // start passing '--crate-type proc-macro' | |
362 | if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate { | |
dfeec247 XL |
363 | let mut msg = sess.diagnostic().struct_warn( |
364 | &"Trying to document proc macro crate \ | |
365 | without passing '--crate-type proc-macro to rustdoc", | |
366 | ); | |
e1599b0c XL |
367 | |
368 | msg.warn("The generated documentation may be incorrect"); | |
369 | msg.emit() | |
370 | } else { | |
dfeec247 | 371 | krate = sess.time("maybe_create_a_macro_crate", || { |
532ac7d7 | 372 | let num_crate_types = crate_types.len(); |
532ac7d7 | 373 | let is_test_crate = sess.opts.test; |
dfeec247 | 374 | rustc_builtin_macros::proc_macro_harness::inject( |
3dfed10e | 375 | &sess, |
532ac7d7 XL |
376 | &mut resolver, |
377 | krate, | |
378 | is_proc_macro_crate, | |
379 | has_proc_macro_decls, | |
380 | is_test_crate, | |
381 | num_crate_types, | |
382 | sess.diagnostic(), | |
383 | ) | |
384 | }); | |
385 | } | |
386 | ||
532ac7d7 XL |
387 | // Done with macro expansion! |
388 | ||
389 | if sess.opts.debugging_opts.input_stats { | |
390 | println!("Post-expansion node count: {}", count_nodes(&krate)); | |
391 | } | |
392 | ||
393 | if sess.opts.debugging_opts.hir_stats { | |
394 | hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); | |
395 | } | |
396 | ||
397 | if sess.opts.debugging_opts.ast_json { | |
398 | println!("{}", json::as_json(&krate)); | |
399 | } | |
400 | ||
dfeec247 | 401 | resolver.resolve_crate(&krate); |
532ac7d7 XL |
402 | |
403 | // Needs to go *after* expansion to be able to check the results of macro expansion. | |
dfeec247 | 404 | sess.time("complete_gated_feature_checking", || { |
3dfed10e | 405 | rustc_ast_passes::feature_gate::check_crate(&krate, sess); |
532ac7d7 XL |
406 | }); |
407 | ||
408 | // Add all buffered lints from the `ParseSess` to the `Session`. | |
409 | sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { | |
410 | info!("{} parse sess buffered_lints", buffered_lints.len()); | |
dfeec247 XL |
411 | for early_lint in buffered_lints.drain(..) { |
412 | resolver.lint_buffer().add_early_lint(early_lint); | |
532ac7d7 XL |
413 | } |
414 | }); | |
415 | ||
416 | Ok((krate, resolver)) | |
417 | } | |
418 | ||
dfeec247 XL |
419 | pub fn lower_to_hir<'res, 'tcx>( |
420 | sess: &'tcx Session, | |
421 | lint_store: &LintStore, | |
422 | resolver: &'res mut Resolver<'_>, | |
423 | dep_graph: &'res DepGraph, | |
424 | krate: &'res ast::Crate, | |
ba9703b0 | 425 | arena: &'tcx rustc_ast_lowering::Arena<'tcx>, |
74b04a01 | 426 | ) -> Crate<'tcx> { |
ba9703b0 XL |
427 | // We're constructing the HIR here; we don't care what we will |
428 | // read, since we haven't even constructed the *input* to | |
429 | // incr. comp. yet. | |
430 | dep_graph.assert_ignored(); | |
431 | ||
e74abb32 | 432 | // Lower AST to HIR. |
dfeec247 XL |
433 | let hir_crate = rustc_ast_lowering::lower_crate( |
434 | sess, | |
dfeec247 XL |
435 | &krate, |
436 | resolver, | |
437 | rustc_parse::nt_to_tokenstream, | |
438 | arena, | |
439 | ); | |
532ac7d7 | 440 | |
dfeec247 XL |
441 | if sess.opts.debugging_opts.hir_stats { |
442 | hir_stats::print_hir_stats(&hir_crate); | |
443 | } | |
532ac7d7 | 444 | |
dfeec247 XL |
445 | sess.time("early_lint_checks", || { |
446 | rustc_lint::check_ast_crate( | |
e74abb32 XL |
447 | sess, |
448 | lint_store, | |
449 | &krate, | |
450 | false, | |
451 | Some(std::mem::take(resolver.lint_buffer())), | |
452 | rustc_lint::BuiltinCombinedEarlyLintPass::new(), | |
453 | ) | |
532ac7d7 XL |
454 | }); |
455 | ||
456 | // Discard hygiene data, which isn't required after lowering to HIR. | |
457 | if !sess.opts.debugging_opts.keep_hygiene_data { | |
dfeec247 | 458 | rustc_span::hygiene::clear_syntax_context_map(); |
532ac7d7 XL |
459 | } |
460 | ||
74b04a01 | 461 | hir_crate |
532ac7d7 XL |
462 | } |
463 | ||
464 | // Returns all the paths that correspond to generated files. | |
465 | fn generated_output_paths( | |
466 | sess: &Session, | |
467 | outputs: &OutputFilenames, | |
468 | exact_name: bool, | |
469 | crate_name: &str, | |
470 | ) -> Vec<PathBuf> { | |
471 | let mut out_filenames = Vec::new(); | |
472 | for output_type in sess.opts.output_types.keys() { | |
473 | let file = outputs.path(*output_type); | |
474 | match *output_type { | |
475 | // If the filename has been overridden using `-o`, it will not be modified | |
476 | // by appending `.rlib`, `.exe`, etc., so we can skip this transformation. | |
dfeec247 | 477 | OutputType::Exe if !exact_name => { |
f9f354fc | 478 | for crate_type in sess.crate_types().iter() { |
ba9703b0 | 479 | let p = filename_for_input(sess, *crate_type, crate_name, outputs); |
dfeec247 XL |
480 | out_filenames.push(p); |
481 | } | |
482 | } | |
532ac7d7 XL |
483 | OutputType::DepInfo if sess.opts.debugging_opts.dep_info_omit_d_target => { |
484 | // Don't add the dep-info output when omitting it from dep-info targets | |
485 | } | |
486 | _ => { | |
487 | out_filenames.push(file); | |
488 | } | |
489 | } | |
490 | } | |
491 | out_filenames | |
492 | } | |
493 | ||
494 | // Runs `f` on every output file path and returns the first non-None result, or None if `f` | |
495 | // returns None for every file path. | |
496 | fn check_output<F, T>(output_paths: &[PathBuf], f: F) -> Option<T> | |
497 | where | |
498 | F: Fn(&PathBuf) -> Option<T>, | |
499 | { | |
500 | for output_path in output_paths { | |
501 | if let Some(result) = f(output_path) { | |
502 | return Some(result); | |
503 | } | |
504 | } | |
505 | None | |
506 | } | |
507 | ||
508 | fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool { | |
509 | let input_path = input_path.canonicalize().ok(); | |
510 | if input_path.is_none() { | |
511 | return false; | |
512 | } | |
513 | let check = |output_path: &PathBuf| { | |
dfeec247 | 514 | if output_path.canonicalize().ok() == input_path { Some(()) } else { None } |
532ac7d7 XL |
515 | }; |
516 | check_output(output_paths, check).is_some() | |
517 | } | |
518 | ||
519 | fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> { | |
60c5eb7d | 520 | let check = |output_path: &PathBuf| output_path.is_dir().then(|| output_path.clone()); |
532ac7d7 XL |
521 | check_output(output_paths, check) |
522 | } | |
523 | ||
524 | fn escape_dep_filename(filename: &FileName) -> String { | |
525 | // Apparently clang and gcc *only* escape spaces: | |
526 | // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4 | |
527 | filename.to_string().replace(" ", "\\ ") | |
528 | } | |
529 | ||
f035d41b XL |
530 | // Makefile comments only need escaping newlines and `\`. |
531 | // The result can be unescaped by anything that can unescape `escape_default` and friends. | |
532 | fn escape_dep_env(symbol: Symbol) -> String { | |
533 | let s = symbol.as_str(); | |
534 | let mut escaped = String::with_capacity(s.len()); | |
535 | for c in s.chars() { | |
536 | match c { | |
537 | '\n' => escaped.push_str(r"\n"), | |
538 | '\r' => escaped.push_str(r"\r"), | |
539 | '\\' => escaped.push_str(r"\\"), | |
540 | _ => escaped.push(c), | |
541 | } | |
542 | } | |
543 | escaped | |
544 | } | |
545 | ||
e74abb32 XL |
546 | fn write_out_deps( |
547 | sess: &Session, | |
548 | boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>, | |
549 | outputs: &OutputFilenames, | |
550 | out_filenames: &[PathBuf], | |
551 | ) { | |
532ac7d7 XL |
552 | // Write out dependency rules to the dep-info file if requested |
553 | if !sess.opts.output_types.contains_key(&OutputType::DepInfo) { | |
554 | return; | |
555 | } | |
556 | let deps_filename = outputs.path(OutputType::DepInfo); | |
557 | ||
558 | let result = (|| -> io::Result<()> { | |
559 | // Build a list of files used to compile the output and | |
560 | // write Makefile-compatible dependency rules | |
dfeec247 XL |
561 | let mut files: Vec<String> = sess |
562 | .source_map() | |
532ac7d7 XL |
563 | .files() |
564 | .iter() | |
565 | .filter(|fmap| fmap.is_real_file()) | |
566 | .filter(|fmap| !fmap.is_imported()) | |
416331ca | 567 | .map(|fmap| escape_dep_filename(&fmap.unmapped_path.as_ref().unwrap_or(&fmap.name))) |
532ac7d7 | 568 | .collect(); |
416331ca XL |
569 | |
570 | if sess.binary_dep_depinfo() { | |
e74abb32 XL |
571 | boxed_resolver.borrow().borrow_mut().access(|resolver| { |
572 | for cnum in resolver.cstore().crates_untracked() { | |
573 | let source = resolver.cstore().crate_source_untracked(cnum); | |
574 | if let Some((path, _)) = source.dylib { | |
ba9703b0 XL |
575 | let file_name = FileName::Real(RealFileName::Named(path)); |
576 | files.push(escape_dep_filename(&file_name)); | |
e74abb32 XL |
577 | } |
578 | if let Some((path, _)) = source.rlib { | |
ba9703b0 XL |
579 | let file_name = FileName::Real(RealFileName::Named(path)); |
580 | files.push(escape_dep_filename(&file_name)); | |
e74abb32 XL |
581 | } |
582 | if let Some((path, _)) = source.rmeta { | |
ba9703b0 XL |
583 | let file_name = FileName::Real(RealFileName::Named(path)); |
584 | files.push(escape_dep_filename(&file_name)); | |
e74abb32 | 585 | } |
416331ca | 586 | } |
e74abb32 | 587 | }); |
416331ca XL |
588 | } |
589 | ||
74b04a01 | 590 | let mut file = BufWriter::new(fs::File::create(&deps_filename)?); |
532ac7d7 XL |
591 | for path in out_filenames { |
592 | writeln!(file, "{}: {}\n", path.display(), files.join(" "))?; | |
593 | } | |
594 | ||
595 | // Emit a fake target for each input file to the compilation. This | |
596 | // prevents `make` from spitting out an error if a file is later | |
597 | // deleted. For more info see #28735 | |
598 | for path in files { | |
599 | writeln!(file, "{}:", path)?; | |
600 | } | |
f035d41b XL |
601 | |
602 | // Emit special comments with information about accessed environment variables. | |
603 | let env_depinfo = sess.parse_sess.env_depinfo.borrow(); | |
604 | if !env_depinfo.is_empty() { | |
605 | let mut envs: Vec<_> = env_depinfo | |
606 | .iter() | |
607 | .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env))) | |
608 | .collect(); | |
609 | envs.sort_unstable(); | |
610 | writeln!(file)?; | |
611 | for (k, v) in envs { | |
612 | write!(file, "# env-dep:{}", k)?; | |
613 | if let Some(v) = v { | |
614 | write!(file, "={}", v)?; | |
615 | } | |
616 | writeln!(file)?; | |
617 | } | |
618 | } | |
619 | ||
532ac7d7 XL |
620 | Ok(()) |
621 | })(); | |
622 | ||
416331ca XL |
623 | match result { |
624 | Ok(_) => { | |
625 | if sess.opts.json_artifact_notifications { | |
dfeec247 XL |
626 | sess.parse_sess |
627 | .span_diagnostic | |
416331ca XL |
628 | .emit_artifact_notification(&deps_filename, "dep-info"); |
629 | } | |
416331ca | 630 | } |
dfeec247 XL |
631 | Err(e) => sess.fatal(&format!( |
632 | "error writing dependencies to `{}`: {}", | |
633 | deps_filename.display(), | |
634 | e | |
635 | )), | |
532ac7d7 XL |
636 | } |
637 | } | |
638 | ||
639 | pub fn prepare_outputs( | |
640 | sess: &Session, | |
641 | compiler: &Compiler, | |
642 | krate: &ast::Crate, | |
e74abb32 | 643 | boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>, |
dfeec247 | 644 | crate_name: &str, |
532ac7d7 | 645 | ) -> Result<OutputFilenames> { |
dfeec247 XL |
646 | let _timer = sess.timer("prepare_outputs"); |
647 | ||
532ac7d7 XL |
648 | // FIXME: rustdoc passes &[] instead of &krate.attrs here |
649 | let outputs = util::build_output_filenames( | |
650 | &compiler.input, | |
651 | &compiler.output_dir, | |
652 | &compiler.output_file, | |
653 | &krate.attrs, | |
532ac7d7 | 654 | sess, |
532ac7d7 XL |
655 | ); |
656 | ||
dfeec247 XL |
657 | let output_paths = |
658 | generated_output_paths(sess, &outputs, compiler.output_file.is_some(), &crate_name); | |
659 | ||
532ac7d7 XL |
660 | // Ensure the source file isn't accidentally overwritten during compilation. |
661 | if let Some(ref input_path) = compiler.input_path { | |
662 | if sess.opts.will_create_output_file() { | |
663 | if output_contains_path(&output_paths, input_path) { | |
664 | sess.err(&format!( | |
665 | "the input file \"{}\" would be overwritten by the generated \ | |
666 | executable", | |
667 | input_path.display() | |
668 | )); | |
669 | return Err(ErrorReported); | |
670 | } | |
671 | if let Some(dir_path) = output_conflicts_with_dir(&output_paths) { | |
672 | sess.err(&format!( | |
673 | "the generated executable for the input file \"{}\" conflicts with the \ | |
674 | existing directory \"{}\"", | |
675 | input_path.display(), | |
676 | dir_path.display() | |
677 | )); | |
678 | return Err(ErrorReported); | |
679 | } | |
680 | } | |
681 | } | |
682 | ||
e74abb32 | 683 | write_out_deps(sess, boxed_resolver, &outputs, &output_paths); |
532ac7d7 XL |
684 | |
685 | let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) | |
686 | && sess.opts.output_types.len() == 1; | |
687 | ||
688 | if !only_dep_info { | |
689 | if let Some(ref dir) = compiler.output_dir { | |
690 | if fs::create_dir_all(dir).is_err() { | |
e74abb32 | 691 | sess.err("failed to find or create the directory specified by `--out-dir`"); |
532ac7d7 XL |
692 | return Err(ErrorReported); |
693 | } | |
694 | } | |
695 | } | |
696 | ||
697 | Ok(outputs) | |
698 | } | |
699 | ||
3dfed10e XL |
700 | pub static DEFAULT_QUERY_PROVIDERS: Lazy<Providers> = Lazy::new(|| { |
701 | let providers = &mut Providers::default(); | |
532ac7d7 XL |
702 | providers.analysis = analysis; |
703 | proc_macro_decls::provide(providers); | |
704 | plugin::build::provide(providers); | |
ba9703b0 | 705 | rustc_middle::hir::provide(providers); |
532ac7d7 | 706 | mir::provide(providers); |
dfeec247 | 707 | mir_build::provide(providers); |
532ac7d7 XL |
708 | rustc_privacy::provide(providers); |
709 | typeck::provide(providers); | |
710 | ty::provide(providers); | |
711 | traits::provide(providers); | |
532ac7d7 | 712 | rustc_passes::provide(providers); |
dfeec247 | 713 | rustc_resolve::provide(providers); |
532ac7d7 | 714 | rustc_traits::provide(providers); |
dfeec247 | 715 | rustc_ty::provide(providers); |
60c5eb7d | 716 | rustc_metadata::provide(providers); |
532ac7d7 | 717 | rustc_lint::provide(providers); |
ba9703b0 | 718 | rustc_symbol_mangling::provide(providers); |
e74abb32 | 719 | rustc_codegen_ssa::provide(providers); |
3dfed10e XL |
720 | *providers |
721 | }); | |
532ac7d7 | 722 | |
3dfed10e XL |
723 | pub static DEFAULT_EXTERN_QUERY_PROVIDERS: Lazy<Providers> = Lazy::new(|| { |
724 | let mut extern_providers = *DEFAULT_QUERY_PROVIDERS; | |
725 | rustc_metadata::provide_extern(&mut extern_providers); | |
726 | rustc_codegen_ssa::provide_extern(&mut extern_providers); | |
727 | extern_providers | |
728 | }); | |
532ac7d7 | 729 | |
60c5eb7d | 730 | pub struct QueryContext<'tcx>(&'tcx GlobalCtxt<'tcx>); |
532ac7d7 | 731 | |
60c5eb7d | 732 | impl<'tcx> QueryContext<'tcx> { |
532ac7d7 XL |
733 | pub fn enter<F, R>(&mut self, f: F) -> R |
734 | where | |
60c5eb7d | 735 | F: FnOnce(TyCtxt<'tcx>) -> R, |
532ac7d7 | 736 | { |
3dfed10e XL |
737 | let icx = ty::tls::ImplicitCtxt::new(self.0); |
738 | ty::tls::enter_context(&icx, |_| f(icx.tcx)) | |
60c5eb7d XL |
739 | } |
740 | ||
74b04a01 | 741 | pub fn print_stats(&mut self) { |
ba9703b0 | 742 | self.enter(ty::query::print_stats) |
532ac7d7 XL |
743 | } |
744 | } | |
745 | ||
60c5eb7d XL |
746 | pub fn create_global_ctxt<'tcx>( |
747 | compiler: &'tcx Compiler, | |
dfeec247 | 748 | lint_store: Lrc<LintStore>, |
74b04a01 XL |
749 | krate: &'tcx Crate<'tcx>, |
750 | dep_graph: DepGraph, | |
e74abb32 | 751 | mut resolver_outputs: ResolverOutputs, |
532ac7d7 | 752 | outputs: OutputFilenames, |
dc9dc135 | 753 | crate_name: &str, |
f9f354fc | 754 | global_ctxt: &'tcx OnceCell<GlobalCtxt<'tcx>>, |
60c5eb7d XL |
755 | arena: &'tcx WorkerLocal<Arena<'tcx>>, |
756 | ) -> QueryContext<'tcx> { | |
757 | let sess = &compiler.session(); | |
f035d41b XL |
758 | let defs: &'tcx Definitions = arena.alloc(mem::replace( |
759 | &mut resolver_outputs.definitions, | |
760 | Definitions::new(crate_name, sess.local_crate_disambiguator()), | |
761 | )); | |
532ac7d7 | 762 | |
dfeec247 | 763 | let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); |
532ac7d7 | 764 | |
60c5eb7d | 765 | let codegen_backend = compiler.codegen_backend(); |
3dfed10e | 766 | let mut local_providers = *DEFAULT_QUERY_PROVIDERS; |
60c5eb7d | 767 | codegen_backend.provide(&mut local_providers); |
532ac7d7 | 768 | |
3dfed10e XL |
769 | let mut extern_providers = *DEFAULT_EXTERN_QUERY_PROVIDERS; |
770 | codegen_backend.provide(&mut extern_providers); | |
60c5eb7d | 771 | codegen_backend.provide_extern(&mut extern_providers); |
532ac7d7 | 772 | |
60c5eb7d XL |
773 | if let Some(callback) = compiler.override_queries { |
774 | callback(sess, &mut local_providers, &mut extern_providers); | |
775 | } | |
532ac7d7 | 776 | |
dfeec247 | 777 | let gcx = sess.time("setup_global_ctxt", || { |
f9f354fc | 778 | global_ctxt.get_or_init(|| { |
dfeec247 XL |
779 | TyCtxt::create_global_ctxt( |
780 | sess, | |
781 | lint_store, | |
782 | local_providers, | |
783 | extern_providers, | |
784 | arena, | |
785 | resolver_outputs, | |
ba9703b0 XL |
786 | krate, |
787 | defs, | |
788 | dep_graph, | |
dfeec247 XL |
789 | query_result_on_disk_cache, |
790 | &crate_name, | |
791 | &outputs, | |
792 | ) | |
793 | }) | |
794 | }); | |
532ac7d7 | 795 | |
60c5eb7d | 796 | // Do some initialization of the DepGraph that can only be done with the tcx available. |
3dfed10e XL |
797 | let icx = ty::tls::ImplicitCtxt::new(&gcx); |
798 | ty::tls::enter_context(&icx, |_| { | |
799 | icx.tcx.sess.time("dep_graph_tcx_init", || rustc_incremental::dep_graph_tcx_init(icx.tcx)); | |
532ac7d7 XL |
800 | }); |
801 | ||
60c5eb7d | 802 | QueryContext(gcx) |
532ac7d7 XL |
803 | } |
804 | ||
805 | /// Runs the resolution, type-checking, region checking and other | |
806 | /// miscellaneous analysis passes on the crate. | |
416331ca | 807 | fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { |
532ac7d7 XL |
808 | assert_eq!(cnum, LOCAL_CRATE); |
809 | ||
ba9703b0 XL |
810 | rustc_passes::hir_id_validator::check_crate(tcx); |
811 | ||
532ac7d7 | 812 | let sess = tcx.sess; |
48663c56 | 813 | let mut entry_point = None; |
532ac7d7 | 814 | |
dfeec247 XL |
815 | sess.time("misc_checking_1", || { |
816 | parallel!( | |
817 | { | |
818 | entry_point = sess | |
819 | .time("looking_for_entry_point", || rustc_passes::entry::find_entry_point(tcx)); | |
532ac7d7 | 820 | |
dfeec247 XL |
821 | sess.time("looking_for_plugin_registrar", || { |
822 | plugin::build::find_plugin_registrar(tcx) | |
823 | }); | |
532ac7d7 | 824 | |
dfeec247 XL |
825 | sess.time("looking_for_derive_registrar", || proc_macro_decls::find(tcx)); |
826 | }, | |
827 | { | |
828 | par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { | |
829 | let local_def_id = tcx.hir().local_def_id(module); | |
830 | tcx.ensure().check_mod_loops(local_def_id); | |
831 | tcx.ensure().check_mod_attrs(local_def_id); | |
832 | tcx.ensure().check_mod_unstable_api_usage(local_def_id); | |
833 | tcx.ensure().check_mod_const_bodies(local_def_id); | |
834 | }); | |
835 | } | |
836 | ); | |
532ac7d7 XL |
837 | }); |
838 | ||
839 | // passes are timed inside typeck | |
840 | typeck::check_crate(tcx)?; | |
841 | ||
dfeec247 XL |
842 | sess.time("misc_checking_2", || { |
843 | parallel!( | |
844 | { | |
845 | sess.time("match_checking", || { | |
846 | tcx.par_body_owners(|def_id| { | |
ba9703b0 | 847 | tcx.ensure().check_match(def_id.to_def_id()); |
dfeec247 | 848 | }); |
532ac7d7 | 849 | }); |
dfeec247 XL |
850 | }, |
851 | { | |
852 | sess.time("liveness_and_intrinsic_checking", || { | |
853 | par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { | |
854 | // this must run before MIR dump, because | |
855 | // "not all control paths return a value" is reported here. | |
856 | // | |
857 | // maybe move the check to a MIR pass? | |
858 | let local_def_id = tcx.hir().local_def_id(module); | |
859 | ||
860 | tcx.ensure().check_mod_liveness(local_def_id); | |
861 | tcx.ensure().check_mod_intrinsics(local_def_id); | |
862 | }); | |
532ac7d7 | 863 | }); |
dfeec247 XL |
864 | } |
865 | ); | |
532ac7d7 XL |
866 | }); |
867 | ||
dfeec247 | 868 | sess.time("MIR_borrow_checking", || { |
f9f354fc | 869 | tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); |
532ac7d7 XL |
870 | }); |
871 | ||
dfeec247 | 872 | sess.time("MIR_effect_checking", || { |
532ac7d7 | 873 | for def_id in tcx.body_owners() { |
f035d41b XL |
874 | mir::transform::check_unsafety::check_unsafety(tcx, def_id); |
875 | ||
876 | if tcx.hir().body_const_context(def_id).is_some() { | |
3dfed10e XL |
877 | tcx.ensure() |
878 | .mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(def_id)); | |
f035d41b | 879 | } |
532ac7d7 XL |
880 | } |
881 | }); | |
882 | ||
dfeec247 | 883 | sess.time("layout_testing", || layout_test::test_layout(tcx)); |
532ac7d7 XL |
884 | |
885 | // Avoid overwhelming user with errors if borrow checking failed. | |
48663c56 | 886 | // I'm not sure how helpful this is, to be honest, but it avoids a |
532ac7d7 XL |
887 | // lot of annoying errors in the compile-fail tests (basically, |
888 | // lint warnings and so on -- kindck used to do this abort, but | |
889 | // kindck is gone now). -nmatsakis | |
dc9dc135 | 890 | if sess.has_errors() { |
532ac7d7 XL |
891 | return Err(ErrorReported); |
892 | } | |
893 | ||
dfeec247 XL |
894 | sess.time("misc_checking_3", || { |
895 | parallel!( | |
896 | { | |
532ac7d7 | 897 | tcx.ensure().privacy_access_levels(LOCAL_CRATE); |
dfeec247 XL |
898 | |
899 | parallel!( | |
900 | { | |
901 | tcx.ensure().check_private_in_public(LOCAL_CRATE); | |
902 | }, | |
903 | { | |
904 | sess.time("death_checking", || rustc_passes::dead::check_crate(tcx)); | |
905 | }, | |
906 | { | |
907 | sess.time("unused_lib_feature_checking", || { | |
908 | rustc_passes::stability::check_unused_or_stable_features(tcx) | |
909 | }); | |
910 | }, | |
911 | { | |
912 | sess.time("lint_checking", || { | |
913 | rustc_lint::check_crate(tcx, || { | |
914 | rustc_lint::BuiltinCombinedLateLintPass::new() | |
915 | }); | |
916 | }); | |
917 | } | |
918 | ); | |
919 | }, | |
920 | { | |
921 | sess.time("privacy_checking_modules", || { | |
922 | par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { | |
923 | tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module)); | |
924 | }); | |
532ac7d7 | 925 | }); |
dfeec247 XL |
926 | } |
927 | ); | |
532ac7d7 XL |
928 | }); |
929 | ||
930 | Ok(()) | |
931 | } | |
932 | ||
416331ca XL |
933 | fn encode_and_write_metadata( |
934 | tcx: TyCtxt<'_>, | |
48663c56 XL |
935 | outputs: &OutputFilenames, |
936 | ) -> (middle::cstore::EncodedMetadata, bool) { | |
937 | #[derive(PartialEq, Eq, PartialOrd, Ord)] | |
938 | enum MetadataKind { | |
939 | None, | |
940 | Uncompressed, | |
dfeec247 | 941 | Compressed, |
48663c56 XL |
942 | } |
943 | ||
dfeec247 XL |
944 | let metadata_kind = tcx |
945 | .sess | |
f9f354fc | 946 | .crate_types() |
dfeec247 XL |
947 | .iter() |
948 | .map(|ty| match *ty { | |
949 | CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None, | |
48663c56 XL |
950 | |
951 | CrateType::Rlib => MetadataKind::Uncompressed, | |
952 | ||
dfeec247 XL |
953 | CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed, |
954 | }) | |
955 | .max() | |
956 | .unwrap_or(MetadataKind::None); | |
48663c56 XL |
957 | |
958 | let metadata = match metadata_kind { | |
959 | MetadataKind::None => middle::cstore::EncodedMetadata::new(), | |
dfeec247 | 960 | MetadataKind::Uncompressed | MetadataKind::Compressed => tcx.encode_metadata(), |
48663c56 XL |
961 | }; |
962 | ||
dfeec247 XL |
963 | let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata"); |
964 | ||
48663c56 XL |
965 | let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata); |
966 | if need_metadata_file { | |
967 | let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str(); | |
968 | let out_filename = filename_for_metadata(tcx.sess, crate_name, outputs); | |
969 | // To avoid races with another rustc process scanning the output directory, | |
970 | // we need to write the file somewhere else and atomically move it to its | |
971 | // final destination, with an `fs::rename` call. In order for the rename to | |
972 | // always succeed, the temporary file needs to be on the same filesystem, | |
973 | // which is why we create it inside the output directory specifically. | |
974 | let metadata_tmpdir = TempFileBuilder::new() | |
975 | .prefix("rmeta") | |
976 | .tempdir_in(out_filename.parent().unwrap()) | |
dfeec247 | 977 | .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))); |
3dfed10e | 978 | let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); |
48663c56 XL |
979 | let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir); |
980 | if let Err(e) = fs::rename(&metadata_filename, &out_filename) { | |
981 | tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); | |
982 | } | |
416331ca | 983 | if tcx.sess.opts.json_artifact_notifications { |
dfeec247 XL |
984 | tcx.sess |
985 | .parse_sess | |
986 | .span_diagnostic | |
dc9dc135 | 987 | .emit_artifact_notification(&out_filename, "metadata"); |
48663c56 XL |
988 | } |
989 | } | |
990 | ||
991 | let need_metadata_module = metadata_kind == MetadataKind::Compressed; | |
992 | ||
993 | (metadata, need_metadata_module) | |
994 | } | |
995 | ||
532ac7d7 XL |
996 | /// Runs the codegen backend, after which the AST and analysis can |
997 | /// be discarded. | |
998 | pub fn start_codegen<'tcx>( | |
999 | codegen_backend: &dyn CodegenBackend, | |
dc9dc135 | 1000 | tcx: TyCtxt<'tcx>, |
532ac7d7 XL |
1001 | outputs: &OutputFilenames, |
1002 | ) -> Box<dyn Any> { | |
3dfed10e | 1003 | info!("Pre-codegen\n{:?}", tcx.debug_stats()); |
532ac7d7 | 1004 | |
dfeec247 | 1005 | let (metadata, need_metadata_module) = encode_and_write_metadata(tcx, outputs); |
48663c56 | 1006 | |
dfeec247 | 1007 | let codegen = tcx.sess.time("codegen_crate", move || { |
e74abb32 | 1008 | codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) |
48663c56 | 1009 | }); |
532ac7d7 | 1010 | |
3dfed10e | 1011 | info!("Post-codegen\n{:?}", tcx.debug_stats()); |
532ac7d7 XL |
1012 | |
1013 | if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { | |
1014 | if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, outputs) { | |
1015 | tcx.sess.err(&format!("could not emit MIR: {}", e)); | |
1016 | tcx.sess.abort_if_errors(); | |
1017 | } | |
1018 | } | |
1019 | ||
1020 | codegen | |
1021 | } |