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