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