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