]> git.lizzy.rs Git - rust.git/blob - src/librustc_driver/driver.rs
Auto merge of #43750 - tbu-:pr_fn_unreachable, r=sfackler
[rust.git] / src / librustc_driver / driver.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use rustc::hir::{self, map as hir_map};
12 use rustc::hir::lowering::lower_crate;
13 use rustc::ich::Fingerprint;
14 use rustc_data_structures::stable_hasher::StableHasher;
15 use rustc_mir as mir;
16 use rustc::session::{Session, CompileResult};
17 use rustc::session::CompileIncomplete;
18 use rustc::session::config::{self, Input, OutputFilenames, OutputType};
19 use rustc::session::search_paths::PathKind;
20 use rustc::lint;
21 use rustc::middle::{self, stability, reachable};
22 #[cfg(feature="llvm")]
23 use rustc::middle::dependency_format;
24 use rustc::middle::privacy::AccessLevels;
25 use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes};
26 use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
27 use rustc::traits;
28 use rustc::util::common::{ErrorReported, time};
29 use rustc::util::nodemap::NodeSet;
30 use rustc_allocator as allocator;
31 use rustc_borrowck as borrowck;
32 use rustc_incremental::{self, IncrementalHashesMap};
33 use rustc_resolve::{MakeGlobMap, Resolver};
34 use rustc_metadata::creader::CrateLoader;
35 use rustc_metadata::cstore::{self, CStore};
36 #[cfg(feature="llvm")]
37 use rustc_trans::back::{link, write};
38 #[cfg(feature="llvm")]
39 use rustc_trans as trans;
40 use rustc_typeck as typeck;
41 use rustc_privacy;
42 use rustc_plugin::registry::Registry;
43 use rustc_plugin as plugin;
44 use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats};
45 use rustc_const_eval::{self, check_match};
46 use super::Compilation;
47
48 use serialize::json;
49
50 use std::env;
51 use std::ffi::{OsString, OsStr};
52 use std::fs;
53 use std::io::{self, Write};
54 use std::iter;
55 use std::path::{Path, PathBuf};
56 use std::rc::Rc;
57 use syntax::{ast, diagnostics, visit};
58 use syntax::attr;
59 use syntax::ext::base::ExtCtxt;
60 use syntax::parse::{self, PResult};
61 use syntax::symbol::Symbol;
62 use syntax::util::node_count::NodeCounter;
63 use syntax;
64 use syntax_ext;
65 use arena::DroplessArena;
66
67 use derive_registrar;
68
69 pub fn compile_input(sess: &Session,
70                      cstore: &CStore,
71                      input: &Input,
72                      outdir: &Option<PathBuf>,
73                      output: &Option<PathBuf>,
74                      addl_plugins: Option<Vec<String>>,
75                      control: &CompileController) -> CompileResult {
76     #[cfg(feature="llvm")]
77     use rustc_trans::back::write::OngoingCrateTranslation;
78     #[cfg(not(feature="llvm"))]
79     type OngoingCrateTranslation = ();
80
81     macro_rules! controller_entry_point {
82         ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{
83             let state = &mut $make_state;
84             let phase_result: &CompileResult = &$phase_result;
85             if phase_result.is_ok() || control.$point.run_callback_on_error {
86                 (control.$point.callback)(state);
87             }
88
89             if control.$point.stop == Compilation::Stop {
90                 // FIXME: shouldn't this return Err(CompileIncomplete::Stopped)
91                 // if there are no errors?
92                 return $tsess.compile_status();
93             }
94         }}
95     }
96
97     // We need nested scopes here, because the intermediate results can keep
98     // large chunks of memory alive and we want to free them as soon as
99     // possible to keep the peak memory usage low
100     let (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = {
101         let krate = match phase_1_parse_input(control, sess, input) {
102             Ok(krate) => krate,
103             Err(mut parse_error) => {
104                 parse_error.emit();
105                 return Err(CompileIncomplete::Errored(ErrorReported));
106             }
107         };
108
109         let (krate, registry) = {
110             let mut compile_state = CompileState::state_after_parse(input,
111                                                                     sess,
112                                                                     outdir,
113                                                                     output,
114                                                                     krate,
115                                                                     &cstore);
116             controller_entry_point!(after_parse,
117                                     sess,
118                                     compile_state,
119                                     Ok(()));
120
121             (compile_state.krate.unwrap(), compile_state.registry)
122         };
123
124         let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
125         let crate_name =
126             ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
127         let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
128             phase_2_configure_and_expand(
129                 sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map,
130                 |expanded_crate| {
131                     let mut state = CompileState::state_after_expand(
132                         input, sess, outdir, output, &cstore, expanded_crate, &crate_name,
133                     );
134                     controller_entry_point!(after_expand, sess, state, Ok(()));
135                     Ok(())
136                 }
137             )?
138         };
139
140         write_out_deps(sess, &outputs, &crate_name);
141         if sess.opts.output_types.contains_key(&OutputType::DepInfo) &&
142             sess.opts.output_types.keys().count() == 1 {
143             return Ok(())
144         }
145
146         let arena = DroplessArena::new();
147         let arenas = GlobalArenas::new();
148
149         // Construct the HIR map
150         let hir_map = time(sess.time_passes(),
151                            "indexing hir",
152                            || hir_map::map_crate(&mut hir_forest, defs));
153
154         {
155             let _ignore = hir_map.dep_graph.in_ignore();
156             controller_entry_point!(after_hir_lowering,
157                                     sess,
158                                     CompileState::state_after_hir_lowering(input,
159                                                                   sess,
160                                                                   outdir,
161                                                                   output,
162                                                                   &arena,
163                                                                   &arenas,
164                                                                   &cstore,
165                                                                   &hir_map,
166                                                                   &analysis,
167                                                                   &resolutions,
168                                                                   &expanded_crate,
169                                                                   &hir_map.krate(),
170                                                                   &crate_name),
171                                     Ok(()));
172         }
173
174         time(sess.time_passes(), "attribute checking", || {
175             hir::check_attr::check_crate(sess, &expanded_crate);
176         });
177
178         let opt_crate = if control.keep_ast {
179             Some(&expanded_crate)
180         } else {
181             drop(expanded_crate);
182             None
183         };
184
185         phase_3_run_analysis_passes(sess,
186                                     hir_map,
187                                     analysis,
188                                     resolutions,
189                                     &arena,
190                                     &arenas,
191                                     &crate_name,
192                                     |tcx, analysis, incremental_hashes_map, result| {
193             {
194                 // Eventually, we will want to track plugins.
195                 let _ignore = tcx.dep_graph.in_ignore();
196
197                 let mut state = CompileState::state_after_analysis(input,
198                                                                    sess,
199                                                                    outdir,
200                                                                    output,
201                                                                    opt_crate,
202                                                                    tcx.hir.krate(),
203                                                                    &analysis,
204                                                                    tcx,
205                                                                    &crate_name);
206                 (control.after_analysis.callback)(&mut state);
207
208                 if control.after_analysis.stop == Compilation::Stop {
209                     return result.and_then(|_| Err(CompileIncomplete::Stopped));
210                 }
211             }
212
213             result?;
214
215             if log_enabled!(::log::LogLevel::Info) {
216                 println!("Pre-trans");
217                 tcx.print_debug_stats();
218             }
219
220             #[cfg(feature="llvm")]
221             let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map,
222                                                   &outputs);
223
224             if log_enabled!(::log::LogLevel::Info) {
225                 println!("Post-trans");
226                 tcx.print_debug_stats();
227             }
228
229             if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
230                 if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) {
231                     sess.err(&format!("could not emit MIR: {}", e));
232                     sess.abort_if_errors();
233                 }
234             }
235
236             #[cfg(not(feature="llvm"))]
237             {
238                 let _ = incremental_hashes_map;
239                 sess.err(&format!("LLVM is not supported by this rustc"));
240                 sess.abort_if_errors();
241                 unreachable!();
242             }
243
244             #[cfg(feature="llvm")]
245             Ok((outputs, trans))
246         })??
247     };
248
249     #[cfg(not(feature="llvm"))]
250     {
251         let _ = outputs;
252         let _ = trans;
253         unreachable!();
254     }
255
256     #[cfg(feature="llvm")]
257     {
258         if sess.opts.debugging_opts.print_type_sizes {
259             sess.code_stats.borrow().print_type_sizes();
260         }
261
262         let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
263
264         controller_entry_point!(after_llvm,
265                                 sess,
266                                 CompileState::state_after_llvm(input, sess, outdir, output, &trans),
267                                 phase5_result);
268         phase5_result?;
269
270         phase_6_link_output(sess, &trans, &outputs);
271
272         // Now that we won't touch anything in the incremental compilation directory
273         // any more, we can finalize it (which involves renaming it)
274         rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
275
276         if sess.opts.debugging_opts.perf_stats {
277             sess.print_perf_stats();
278         }
279
280         controller_entry_point!(
281             compilation_done,
282             sess,
283             CompileState::state_when_compilation_done(input, sess, outdir, output),
284             Ok(())
285         );
286
287         Ok(())
288     }
289 }
290
291 fn keep_hygiene_data(sess: &Session) -> bool {
292     sess.opts.debugging_opts.keep_hygiene_data
293 }
294
295
296 /// The name used for source code that doesn't originate in a file
297 /// (e.g. source from stdin or a string)
298 pub fn anon_src() -> String {
299     "<anon>".to_string()
300 }
301
302 pub fn source_name(input: &Input) -> String {
303     match *input {
304         // FIXME (#9639): This needs to handle non-utf8 paths
305         Input::File(ref ifile) => ifile.to_str().unwrap().to_string(),
306         Input::Str { ref name, .. } => name.clone(),
307     }
308 }
309
310 /// CompileController is used to customise compilation, it allows compilation to
311 /// be stopped and/or to call arbitrary code at various points in compilation.
312 /// It also allows for various flags to be set to influence what information gets
313 /// collected during compilation.
314 ///
315 /// This is a somewhat higher level controller than a Session - the Session
316 /// controls what happens in each phase, whereas the CompileController controls
317 /// whether a phase is run at all and whether other code (from outside the
318 /// the compiler) is run between phases.
319 ///
320 /// Note that if compilation is set to stop and a callback is provided for a
321 /// given entry point, the callback is called before compilation is stopped.
322 ///
323 /// Expect more entry points to be added in the future.
324 pub struct CompileController<'a> {
325     pub after_parse: PhaseController<'a>,
326     pub after_expand: PhaseController<'a>,
327     pub after_hir_lowering: PhaseController<'a>,
328     pub after_analysis: PhaseController<'a>,
329     pub after_llvm: PhaseController<'a>,
330     pub compilation_done: PhaseController<'a>,
331
332     // FIXME we probably want to group the below options together and offer a
333     // better API, rather than this ad-hoc approach.
334     pub make_glob_map: MakeGlobMap,
335     // Whether the compiler should keep the ast beyond parsing.
336     pub keep_ast: bool,
337     // -Zcontinue-parse-after-error
338     pub continue_parse_after_error: bool,
339 }
340
341 impl<'a> CompileController<'a> {
342     pub fn basic() -> CompileController<'a> {
343         CompileController {
344             after_parse: PhaseController::basic(),
345             after_expand: PhaseController::basic(),
346             after_hir_lowering: PhaseController::basic(),
347             after_analysis: PhaseController::basic(),
348             after_llvm: PhaseController::basic(),
349             compilation_done: PhaseController::basic(),
350             make_glob_map: MakeGlobMap::No,
351             keep_ast: false,
352             continue_parse_after_error: false,
353         }
354     }
355 }
356
357 pub struct PhaseController<'a> {
358     pub stop: Compilation,
359     // If true then the compiler will try to run the callback even if the phase
360     // ends with an error. Note that this is not always possible.
361     pub run_callback_on_error: bool,
362     pub callback: Box<Fn(&mut CompileState) + 'a>,
363 }
364
365 impl<'a> PhaseController<'a> {
366     pub fn basic() -> PhaseController<'a> {
367         PhaseController {
368             stop: Compilation::Continue,
369             run_callback_on_error: false,
370             callback: box |_| {},
371         }
372     }
373 }
374
375 /// State that is passed to a callback. What state is available depends on when
376 /// during compilation the callback is made. See the various constructor methods
377 /// (`state_*`) in the impl to see which data is provided for any given entry point.
378 pub struct CompileState<'a, 'tcx: 'a> {
379     pub input: &'a Input,
380     pub session: &'tcx Session,
381     pub krate: Option<ast::Crate>,
382     pub registry: Option<Registry<'a>>,
383     pub cstore: Option<&'a CStore>,
384     pub crate_name: Option<&'a str>,
385     pub output_filenames: Option<&'a OutputFilenames>,
386     pub out_dir: Option<&'a Path>,
387     pub out_file: Option<&'a Path>,
388     pub arena: Option<&'tcx DroplessArena>,
389     pub arenas: Option<&'tcx GlobalArenas<'tcx>>,
390     pub expanded_crate: Option<&'a ast::Crate>,
391     pub hir_crate: Option<&'a hir::Crate>,
392     pub hir_map: Option<&'a hir_map::Map<'tcx>>,
393     pub resolutions: Option<&'a Resolutions>,
394     pub analysis: Option<&'a ty::CrateAnalysis>,
395     pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
396     #[cfg(feature="llvm")]
397     pub trans: Option<&'a trans::CrateTranslation>,
398 }
399
400 impl<'a, 'tcx> CompileState<'a, 'tcx> {
401     fn empty(input: &'a Input,
402              session: &'tcx Session,
403              out_dir: &'a Option<PathBuf>)
404              -> Self {
405         CompileState {
406             input: input,
407             session: session,
408             out_dir: out_dir.as_ref().map(|s| &**s),
409             out_file: None,
410             arena: None,
411             arenas: None,
412             krate: None,
413             registry: None,
414             cstore: None,
415             crate_name: None,
416             output_filenames: None,
417             expanded_crate: None,
418             hir_crate: None,
419             hir_map: None,
420             resolutions: None,
421             analysis: None,
422             tcx: None,
423             #[cfg(feature="llvm")]
424             trans: None,
425         }
426     }
427
428     fn state_after_parse(input: &'a Input,
429                          session: &'tcx Session,
430                          out_dir: &'a Option<PathBuf>,
431                          out_file: &'a Option<PathBuf>,
432                          krate: ast::Crate,
433                          cstore: &'a CStore)
434                          -> Self {
435         CompileState {
436             // Initialize the registry before moving `krate`
437             registry: Some(Registry::new(&session, krate.span)),
438             krate: Some(krate),
439             cstore: Some(cstore),
440             out_file: out_file.as_ref().map(|s| &**s),
441             ..CompileState::empty(input, session, out_dir)
442         }
443     }
444
445     fn state_after_expand(input: &'a Input,
446                           session: &'tcx Session,
447                           out_dir: &'a Option<PathBuf>,
448                           out_file: &'a Option<PathBuf>,
449                           cstore: &'a CStore,
450                           expanded_crate: &'a ast::Crate,
451                           crate_name: &'a str)
452                           -> Self {
453         CompileState {
454             crate_name: Some(crate_name),
455             cstore: Some(cstore),
456             expanded_crate: Some(expanded_crate),
457             out_file: out_file.as_ref().map(|s| &**s),
458             ..CompileState::empty(input, session, out_dir)
459         }
460     }
461
462     fn state_after_hir_lowering(input: &'a Input,
463                                 session: &'tcx Session,
464                                 out_dir: &'a Option<PathBuf>,
465                                 out_file: &'a Option<PathBuf>,
466                                 arena: &'tcx DroplessArena,
467                                 arenas: &'tcx GlobalArenas<'tcx>,
468                                 cstore: &'a CStore,
469                                 hir_map: &'a hir_map::Map<'tcx>,
470                                 analysis: &'a ty::CrateAnalysis,
471                                 resolutions: &'a Resolutions,
472                                 krate: &'a ast::Crate,
473                                 hir_crate: &'a hir::Crate,
474                                 crate_name: &'a str)
475                                 -> Self {
476         CompileState {
477             crate_name: Some(crate_name),
478             arena: Some(arena),
479             arenas: Some(arenas),
480             cstore: Some(cstore),
481             hir_map: Some(hir_map),
482             analysis: Some(analysis),
483             resolutions: Some(resolutions),
484             expanded_crate: Some(krate),
485             hir_crate: Some(hir_crate),
486             out_file: out_file.as_ref().map(|s| &**s),
487             ..CompileState::empty(input, session, out_dir)
488         }
489     }
490
491     fn state_after_analysis(input: &'a Input,
492                             session: &'tcx Session,
493                             out_dir: &'a Option<PathBuf>,
494                             out_file: &'a Option<PathBuf>,
495                             krate: Option<&'a ast::Crate>,
496                             hir_crate: &'a hir::Crate,
497                             analysis: &'a ty::CrateAnalysis,
498                             tcx: TyCtxt<'a, 'tcx, 'tcx>,
499                             crate_name: &'a str)
500                             -> Self {
501         CompileState {
502             analysis: Some(analysis),
503             tcx: Some(tcx),
504             expanded_crate: krate,
505             hir_crate: Some(hir_crate),
506             crate_name: Some(crate_name),
507             out_file: out_file.as_ref().map(|s| &**s),
508             ..CompileState::empty(input, session, out_dir)
509         }
510     }
511
512     #[cfg(feature="llvm")]
513     fn state_after_llvm(input: &'a Input,
514                         session: &'tcx Session,
515                         out_dir: &'a Option<PathBuf>,
516                         out_file: &'a Option<PathBuf>,
517                         trans: &'a trans::CrateTranslation)
518                         -> Self {
519         CompileState {
520             trans: Some(trans),
521             out_file: out_file.as_ref().map(|s| &**s),
522             ..CompileState::empty(input, session, out_dir)
523         }
524     }
525
526     #[cfg(feature="llvm")]
527     fn state_when_compilation_done(input: &'a Input,
528                                    session: &'tcx Session,
529                                    out_dir: &'a Option<PathBuf>,
530                                    out_file: &'a Option<PathBuf>)
531                                    -> Self {
532         CompileState {
533             out_file: out_file.as_ref().map(|s| &**s),
534             ..CompileState::empty(input, session, out_dir)
535         }
536     }
537 }
538
539 pub fn phase_1_parse_input<'a>(control: &CompileController,
540                                sess: &'a Session,
541                                input: &Input)
542                                -> PResult<'a, ast::Crate> {
543     sess.diagnostic().set_continue_after_error(control.continue_parse_after_error);
544
545     let krate = time(sess.time_passes(), "parsing", || {
546         match *input {
547             Input::File(ref file) => {
548                 parse::parse_crate_from_file(file, &sess.parse_sess)
549             }
550             Input::Str { ref input, ref name } => {
551                 parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess)
552             }
553         }
554     })?;
555
556     sess.diagnostic().set_continue_after_error(true);
557
558     if sess.opts.debugging_opts.ast_json_noexpand {
559         println!("{}", json::as_json(&krate));
560     }
561
562     if sess.opts.debugging_opts.input_stats {
563         println!("Lines of code:             {}", sess.codemap().count_lines());
564         println!("Pre-expansion node count:  {}", count_nodes(&krate));
565     }
566
567     if let Some(ref s) = sess.opts.debugging_opts.show_span {
568         syntax::show_span::run(sess.diagnostic(), s, &krate);
569     }
570
571     if sess.opts.debugging_opts.hir_stats {
572         hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS");
573     }
574
575     Ok(krate)
576 }
577
578 fn count_nodes(krate: &ast::Crate) -> usize {
579     let mut counter = NodeCounter::new();
580     visit::walk_crate(&mut counter, krate);
581     counter.count
582 }
583
584 // For continuing compilation after a parsed crate has been
585 // modified
586
587 pub struct ExpansionResult {
588     pub expanded_crate: ast::Crate,
589     pub defs: hir_map::Definitions,
590     pub analysis: ty::CrateAnalysis,
591     pub resolutions: Resolutions,
592     pub hir_forest: hir_map::Forest,
593 }
594
595 /// Run the "early phases" of the compiler: initial `cfg` processing,
596 /// loading compiler plugins (including those from `addl_plugins`),
597 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
598 /// harness if one is to be provided, injection of a dependency on the
599 /// standard library and prelude, and name resolution.
600 ///
601 /// Returns `None` if we're aborting after handling -W help.
602 pub fn phase_2_configure_and_expand<F>(sess: &Session,
603                                        cstore: &CStore,
604                                        krate: ast::Crate,
605                                        registry: Option<Registry>,
606                                        crate_name: &str,
607                                        addl_plugins: Option<Vec<String>>,
608                                        make_glob_map: MakeGlobMap,
609                                        after_expand: F)
610                                        -> Result<ExpansionResult, CompileIncomplete>
611     where F: FnOnce(&ast::Crate) -> CompileResult,
612 {
613     let time_passes = sess.time_passes();
614
615     let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test);
616     // these need to be set "early" so that expansion sees `quote` if enabled.
617     *sess.features.borrow_mut() = features;
618
619     *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
620     *sess.crate_disambiguator.borrow_mut() = Symbol::intern(&compute_crate_disambiguator(sess));
621
622     time(time_passes, "recursion limit", || {
623         middle::recursion_limit::update_limits(sess, &krate);
624     });
625
626     krate = time(time_passes, "crate injection", || {
627         let alt_std_name = sess.opts.alt_std_name.clone();
628         syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name)
629     });
630
631     let mut addl_plugins = Some(addl_plugins);
632     let registrars = time(time_passes, "plugin loading", || {
633         plugin::load::load_plugins(sess,
634                                    &cstore,
635                                    &krate,
636                                    crate_name,
637                                    addl_plugins.take().unwrap())
638     });
639
640     let mut registry = registry.unwrap_or(Registry::new(sess, krate.span));
641
642     time(time_passes, "plugin registration", || {
643         if sess.features.borrow().rustc_diagnostic_macros {
644             registry.register_macro("__diagnostic_used",
645                                     diagnostics::plugin::expand_diagnostic_used);
646             registry.register_macro("__register_diagnostic",
647                                     diagnostics::plugin::expand_register_diagnostic);
648             registry.register_macro("__build_diagnostic_array",
649                                     diagnostics::plugin::expand_build_diagnostic_array);
650         }
651
652         for registrar in registrars {
653             registry.args_hidden = Some(registrar.args);
654             (registrar.fun)(&mut registry);
655         }
656     });
657
658     let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives();
659     let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
660                    llvm_passes, attributes, .. } = registry;
661
662     sess.track_errors(|| {
663         let mut ls = sess.lint_store.borrow_mut();
664         for pass in early_lint_passes {
665             ls.register_early_pass(Some(sess), true, pass);
666         }
667         for pass in late_lint_passes {
668             ls.register_late_pass(Some(sess), true, pass);
669         }
670
671         for (name, to) in lint_groups {
672             ls.register_group(Some(sess), true, name, to);
673         }
674
675         *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
676         *sess.plugin_attributes.borrow_mut() = attributes.clone();
677     })?;
678
679     // Lint plugins are registered; now we can process command line flags.
680     if sess.opts.describe_lints {
681         super::describe_lints(&sess.lint_store.borrow(), true);
682         return Err(CompileIncomplete::Stopped);
683     }
684
685     // Currently, we ignore the name resolution data structures for the purposes of dependency
686     // tracking. Instead we will run name resolution and include its output in the hash of each
687     // item, much like we do for macro expansion. In other words, the hash reflects not just
688     // its contents but the results of name resolution on those contents. Hopefully we'll push
689     // this back at some point.
690     let _ignore = sess.dep_graph.in_ignore();
691     let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name);
692     crate_loader.preprocess(&krate);
693     let resolver_arenas = Resolver::arenas();
694     let mut resolver = Resolver::new(sess,
695                                      &krate,
696                                      crate_name,
697                                      make_glob_map,
698                                      &mut crate_loader,
699                                      &resolver_arenas);
700     resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives;
701     syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote);
702
703     krate = time(time_passes, "expansion", || {
704         // Windows dlls do not have rpaths, so they don't know how to find their
705         // dependencies. It's up to us to tell the system where to find all the
706         // dependent dlls. Note that this uses cfg!(windows) as opposed to
707         // targ_cfg because syntax extensions are always loaded for the host
708         // compiler, not for the target.
709         //
710         // This is somewhat of an inherently racy operation, however, as
711         // multiple threads calling this function could possibly continue
712         // extending PATH far beyond what it should. To solve this for now we
713         // just don't add any new elements to PATH which are already there
714         // within PATH. This is basically a targeted fix at #17360 for rustdoc
715         // which runs rustc in parallel but has been seen (#33844) to cause
716         // problems with PATH becoming too long.
717         let mut old_path = OsString::new();
718         if cfg!(windows) {
719             old_path = env::var_os("PATH").unwrap_or(old_path);
720             let mut new_path = sess.host_filesearch(PathKind::All)
721                                    .get_dylib_search_paths();
722             for path in env::split_paths(&old_path) {
723                 if !new_path.contains(&path) {
724                     new_path.push(path);
725                 }
726             }
727             env::set_var("PATH",
728                 &env::join_paths(new_path.iter()
729                                          .filter(|p| env::join_paths(iter::once(p)).is_ok()))
730                      .unwrap());
731         }
732         let features = sess.features.borrow();
733         let cfg = syntax::ext::expand::ExpansionConfig {
734             features: Some(&features),
735             recursion_limit: sess.recursion_limit.get(),
736             trace_mac: sess.opts.debugging_opts.trace_macros,
737             should_test: sess.opts.test,
738             ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string())
739         };
740
741         let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver);
742         let err_count = ecx.parse_sess.span_diagnostic.err_count();
743
744         let krate = ecx.monotonic_expander().expand_crate(krate);
745
746         ecx.check_unused_macros();
747
748         let mut missing_fragment_specifiers: Vec<_> =
749             ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect();
750         missing_fragment_specifiers.sort();
751         for span in missing_fragment_specifiers {
752             let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
753             let msg = "missing fragment specifier";
754             sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg);
755         }
756         if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count {
757             ecx.parse_sess.span_diagnostic.abort_if_errors();
758         }
759         if cfg!(windows) {
760             env::set_var("PATH", &old_path);
761         }
762         krate
763     });
764
765     krate = time(time_passes, "maybe building test harness", || {
766         syntax::test::modify_for_testing(&sess.parse_sess,
767                                          &mut resolver,
768                                          sess.opts.test,
769                                          krate,
770                                          sess.diagnostic())
771     });
772
773     // If we're in rustdoc we're always compiling as an rlib, but that'll trip a
774     // bunch of checks in the `modify` function below. For now just skip this
775     // step entirely if we're rustdoc as it's not too useful anyway.
776     if !sess.opts.actually_rustdoc {
777         krate = time(time_passes, "maybe creating a macro crate", || {
778             let crate_types = sess.crate_types.borrow();
779             let num_crate_types = crate_types.len();
780             let is_proc_macro_crate = crate_types.contains(&config::CrateTypeProcMacro);
781             let is_test_crate = sess.opts.test;
782             syntax_ext::proc_macro_registrar::modify(&sess.parse_sess,
783                                                      &mut resolver,
784                                                      krate,
785                                                      is_proc_macro_crate,
786                                                      is_test_crate,
787                                                      num_crate_types,
788                                                      sess.diagnostic())
789         });
790     }
791
792     krate = time(time_passes, "creating allocators", || {
793         allocator::expand::modify(&sess.parse_sess,
794                                   &mut resolver,
795                                   krate,
796                                   sess.diagnostic())
797     });
798
799     after_expand(&krate)?;
800
801     if sess.opts.debugging_opts.input_stats {
802         println!("Post-expansion node count: {}", count_nodes(&krate));
803     }
804
805     if sess.opts.debugging_opts.hir_stats {
806         hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS");
807     }
808
809     if sess.opts.debugging_opts.ast_json {
810         println!("{}", json::as_json(&krate));
811     }
812
813     time(time_passes,
814          "checking for inline asm in case the target doesn't support it",
815          || no_asm::check_crate(sess, &krate));
816
817     time(time_passes,
818          "AST validation",
819          || ast_validation::check_crate(sess, &krate));
820
821     time(time_passes, "name resolution", || -> CompileResult {
822         resolver.resolve_crate(&krate);
823         Ok(())
824     })?;
825
826     if resolver.found_unresolved_macro {
827         sess.parse_sess.span_diagnostic.abort_if_errors();
828     }
829
830     // Needs to go *after* expansion to be able to check the results of macro expansion.
831     time(time_passes, "complete gated feature checking", || {
832         sess.track_errors(|| {
833             syntax::feature_gate::check_crate(&krate,
834                                               &sess.parse_sess,
835                                               &sess.features.borrow(),
836                                               &attributes,
837                                               sess.opts.unstable_features);
838         })
839     })?;
840
841     time(time_passes,
842          "early lint checks",
843          || lint::check_ast_crate(sess, &krate));
844
845     // Lower ast -> hir.
846     let hir_forest = time(time_passes, "lowering ast -> hir", || {
847         let hir_crate = lower_crate(sess, &krate, &mut resolver);
848
849         if sess.opts.debugging_opts.hir_stats {
850             hir_stats::print_hir_stats(&hir_crate);
851         }
852
853         hir_map::Forest::new(hir_crate, &sess.dep_graph)
854     });
855
856     // Discard hygiene data, which isn't required after lowering to HIR.
857     if !keep_hygiene_data(sess) {
858         syntax::ext::hygiene::clear_markings();
859     }
860
861     Ok(ExpansionResult {
862         expanded_crate: krate,
863         defs: resolver.definitions,
864         analysis: ty::CrateAnalysis {
865             access_levels: Rc::new(AccessLevels::default()),
866             reachable: Rc::new(NodeSet()),
867             name: crate_name.to_string(),
868             glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None },
869         },
870         resolutions: Resolutions {
871             freevars: resolver.freevars,
872             export_map: resolver.export_map,
873             trait_map: resolver.trait_map,
874             maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
875         },
876         hir_forest: hir_forest,
877     })
878 }
879
880 /// Run the resolution, typechecking, region checking and other
881 /// miscellaneous analysis passes on the crate. Return various
882 /// structures carrying the results of the analysis.
883 pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
884                                                hir_map: hir_map::Map<'tcx>,
885                                                mut analysis: ty::CrateAnalysis,
886                                                resolutions: Resolutions,
887                                                arena: &'tcx DroplessArena,
888                                                arenas: &'tcx GlobalArenas<'tcx>,
889                                                name: &str,
890                                                f: F)
891                                                -> Result<R, CompileIncomplete>
892     where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
893                             ty::CrateAnalysis,
894                             IncrementalHashesMap,
895                             CompileResult) -> R
896 {
897     macro_rules! try_with_f {
898         ($e: expr, ($t: expr, $a: expr, $h: expr)) => {
899             match $e {
900                 Ok(x) => x,
901                 Err(x) => {
902                     f($t, $a, $h, Err(x));
903                     return Err(x);
904                 }
905             }
906         }
907     }
908
909     let time_passes = sess.time_passes();
910
911     let lang_items = time(time_passes, "language item collection", || {
912         sess.track_errors(|| {
913             middle::lang_items::collect_language_items(&sess, &hir_map)
914         })
915     })?;
916
917     let named_region_map = time(time_passes,
918                                 "lifetime resolution",
919                                 || middle::resolve_lifetime::krate(sess, &hir_map))?;
920
921     time(time_passes,
922          "looking for entry point",
923          || middle::entry::find_entry_point(sess, &hir_map));
924
925     sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || {
926         plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map)
927     }));
928     sess.derive_registrar_fn.set(derive_registrar::find(&hir_map));
929
930     time(time_passes,
931          "loop checking",
932          || loops::check_crate(sess, &hir_map));
933
934     time(time_passes,
935               "static item recursion checking",
936               || static_recursion::check_crate(sess, &hir_map))?;
937
938     let index = stability::Index::new(&sess);
939
940     let mut local_providers = ty::maps::Providers::default();
941     borrowck::provide(&mut local_providers);
942     mir::provide(&mut local_providers);
943     reachable::provide(&mut local_providers);
944     rustc_privacy::provide(&mut local_providers);
945     #[cfg(feature="llvm")]
946     trans::provide(&mut local_providers);
947     typeck::provide(&mut local_providers);
948     ty::provide(&mut local_providers);
949     traits::provide(&mut local_providers);
950     reachable::provide(&mut local_providers);
951     rustc_const_eval::provide(&mut local_providers);
952     middle::region::provide(&mut local_providers);
953     cstore::provide_local(&mut local_providers);
954     lint::provide(&mut local_providers);
955
956     let mut extern_providers = ty::maps::Providers::default();
957     cstore::provide(&mut extern_providers);
958     #[cfg(feature="llvm")]
959     trans::provide(&mut extern_providers);
960     ty::provide_extern(&mut extern_providers);
961     traits::provide_extern(&mut extern_providers);
962     // FIXME(eddyb) get rid of this once we replace const_eval with miri.
963     rustc_const_eval::provide(&mut extern_providers);
964
965     // Setup the MIR passes that we want to run.
966     let mut passes = Passes::new();
967     passes.push_hook(mir::transform::dump_mir::DumpMir);
968
969     // Remove all `EndRegion` statements that are not involved in borrows.
970     passes.push_pass(MIR_CONST, mir::transform::clean_end_regions::CleanEndRegions);
971
972     // What we need to do constant evaluation.
973     passes.push_pass(MIR_CONST, mir::transform::simplify::SimplifyCfg::new("initial"));
974     passes.push_pass(MIR_CONST, mir::transform::type_check::TypeckMir);
975     passes.push_pass(MIR_CONST, mir::transform::rustc_peek::SanityCheck);
976
977     // We compute "constant qualifications" betwen MIR_CONST and MIR_VALIDATED.
978
979     // What we need to run borrowck etc.
980     passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
981     passes.push_pass(MIR_VALIDATED,
982                      mir::transform::simplify_branches::SimplifyBranches::new("initial"));
983     passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
984     passes.push_pass(MIR_VALIDATED, mir::transform::nll::NLL);
985
986     // borrowck runs between MIR_VALIDATED and MIR_OPTIMIZED.
987
988     // These next passes must be executed together
989     passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
990     passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
991     passes.push_pass(MIR_OPTIMIZED, mir::transform::elaborate_drops::ElaborateDrops);
992     passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
993     // AddValidation needs to run after ElaborateDrops and before EraseRegions, and it needs
994     // an AllCallEdges pass right before it.
995     passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AllCallEdges);
996     passes.push_pass(MIR_OPTIMIZED, mir::transform::add_validation::AddValidation);
997     passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
998     // No lifetime analysis based on borrowing can be done from here on out.
999
1000     // From here on out, regions are gone.
1001     passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
1002
1003     // Optimizations begin.
1004     passes.push_pass(MIR_OPTIMIZED, mir::transform::inline::Inline);
1005     passes.push_pass(MIR_OPTIMIZED, mir::transform::instcombine::InstCombine);
1006     passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator);
1007     passes.push_pass(MIR_OPTIMIZED, mir::transform::copy_prop::CopyPropagation);
1008     passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyLocals);
1009     passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
1010     passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans"));
1011
1012     TyCtxt::create_and_enter(sess,
1013                              local_providers,
1014                              extern_providers,
1015                              Rc::new(passes),
1016                              arenas,
1017                              arena,
1018                              resolutions,
1019                              named_region_map,
1020                              hir_map,
1021                              lang_items,
1022                              index,
1023                              name,
1024                              |tcx| {
1025         let incremental_hashes_map =
1026             time(time_passes,
1027                  "compute_incremental_hashes_map",
1028                  || rustc_incremental::compute_incremental_hashes_map(tcx));
1029
1030         time(time_passes,
1031              "load_dep_graph",
1032              || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map));
1033
1034         time(time_passes, "stability index", || {
1035             tcx.stability.borrow_mut().build(tcx)
1036         });
1037
1038         time(time_passes,
1039              "stability checking",
1040              || stability::check_unstable_api_usage(tcx));
1041
1042         // passes are timed inside typeck
1043         try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map));
1044
1045         time(time_passes,
1046              "const checking",
1047              || consts::check_crate(tcx));
1048
1049         analysis.access_levels =
1050             time(time_passes, "privacy checking", || rustc_privacy::check_crate(tcx));
1051
1052         time(time_passes,
1053              "intrinsic checking",
1054              || middle::intrinsicck::check_crate(tcx));
1055
1056         time(time_passes,
1057              "effect checking",
1058              || middle::effect::check_crate(tcx));
1059
1060         time(time_passes,
1061              "match checking",
1062              || check_match::check_crate(tcx));
1063
1064         // this must run before MIR dump, because
1065         // "not all control paths return a value" is reported here.
1066         //
1067         // maybe move the check to a MIR pass?
1068         time(time_passes,
1069              "liveness checking",
1070              || middle::liveness::check_crate(tcx));
1071
1072         time(time_passes,
1073              "borrow checking",
1074              || borrowck::check_crate(tcx));
1075
1076         // Avoid overwhelming user with errors if type checking failed.
1077         // I'm not sure how helpful this is, to be honest, but it avoids
1078         // a
1079         // lot of annoying errors in the compile-fail tests (basically,
1080         // lint warnings and so on -- kindck used to do this abort, but
1081         // kindck is gone now). -nmatsakis
1082         if sess.err_count() > 0 {
1083             return Ok(f(tcx, analysis, incremental_hashes_map, sess.compile_status()));
1084         }
1085
1086         analysis.reachable =
1087             time(time_passes,
1088                  "reachability checking",
1089                  || reachable::find_reachable(tcx));
1090
1091         time(time_passes, "death checking", || middle::dead::check_crate(tcx));
1092
1093         time(time_passes, "unused lib feature checking", || {
1094             stability::check_unused_or_stable_features(tcx)
1095         });
1096
1097         time(time_passes, "lint checking", || lint::check_crate(tcx));
1098
1099         return Ok(f(tcx, analysis, incremental_hashes_map, tcx.sess.compile_status()));
1100     })
1101 }
1102
1103 /// Run the translation phase to LLVM, after which the AST and analysis can
1104 /// be discarded.
1105 #[cfg(feature="llvm")]
1106 pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1107                                            analysis: ty::CrateAnalysis,
1108                                            incremental_hashes_map: IncrementalHashesMap,
1109                                            output_filenames: &OutputFilenames)
1110                                            -> write::OngoingCrateTranslation {
1111     let time_passes = tcx.sess.time_passes();
1112
1113     time(time_passes,
1114          "resolving dependency formats",
1115          || dependency_format::calculate(tcx));
1116
1117     let translation =
1118         time(time_passes,
1119              "translation",
1120              move || trans::trans_crate(tcx, analysis, incremental_hashes_map, output_filenames));
1121
1122     translation
1123 }
1124
1125 /// Run LLVM itself, producing a bitcode file, assembly file or object file
1126 /// as a side effect.
1127 #[cfg(feature="llvm")]
1128 pub fn phase_5_run_llvm_passes(sess: &Session,
1129                                trans: write::OngoingCrateTranslation)
1130                                -> (CompileResult, trans::CrateTranslation) {
1131     let trans = trans.join(sess);
1132
1133     if sess.opts.debugging_opts.incremental_info {
1134         write::dump_incremental_data(&trans);
1135     }
1136
1137     time(sess.time_passes(),
1138          "serialize work products",
1139          move || rustc_incremental::save_work_products(sess));
1140
1141     (sess.compile_status(), trans)
1142 }
1143
1144 /// Run the linker on any artifacts that resulted from the LLVM run.
1145 /// This should produce either a finished executable or library.
1146 #[cfg(feature="llvm")]
1147 pub fn phase_6_link_output(sess: &Session,
1148                            trans: &trans::CrateTranslation,
1149                            outputs: &OutputFilenames) {
1150     time(sess.time_passes(),
1151          "linking",
1152          || link::link_binary(sess, trans, outputs, &trans.crate_name.as_str()));
1153 }
1154
1155 fn escape_dep_filename(filename: &str) -> String {
1156     // Apparently clang and gcc *only* escape spaces:
1157     // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
1158     filename.replace(" ", "\\ ")
1159 }
1160
1161 fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) {
1162     let mut out_filenames = Vec::new();
1163     for output_type in sess.opts.output_types.keys() {
1164         let file = outputs.path(*output_type);
1165         match *output_type {
1166             OutputType::Exe => {
1167                 for output in sess.crate_types.borrow().iter() {
1168                     let p = ::rustc_trans_utils::link::filename_for_input(
1169                         sess,
1170                         *output,
1171                         crate_name,
1172                         outputs
1173                     );
1174                     out_filenames.push(p);
1175                 }
1176             }
1177             _ => {
1178                 out_filenames.push(file);
1179             }
1180         }
1181     }
1182
1183     // Write out dependency rules to the dep-info file if requested
1184     if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
1185         return;
1186     }
1187     let deps_filename = outputs.path(OutputType::DepInfo);
1188
1189     let result =
1190         (|| -> io::Result<()> {
1191             // Build a list of files used to compile the output and
1192             // write Makefile-compatible dependency rules
1193             let files: Vec<String> = sess.codemap()
1194                                          .files()
1195                                          .iter()
1196                                          .filter(|fmap| fmap.is_real_file())
1197                                          .filter(|fmap| !fmap.is_imported())
1198                                          .map(|fmap| escape_dep_filename(&fmap.name))
1199                                          .collect();
1200             let mut file = fs::File::create(&deps_filename)?;
1201             for path in &out_filenames {
1202                 write!(file, "{}: {}\n\n", path.display(), files.join(" "))?;
1203             }
1204
1205             // Emit a fake target for each input file to the compilation. This
1206             // prevents `make` from spitting out an error if a file is later
1207             // deleted. For more info see #28735
1208             for path in files {
1209                 writeln!(file, "{}:", path)?;
1210             }
1211             Ok(())
1212         })();
1213
1214     match result {
1215         Ok(()) => {}
1216         Err(e) => {
1217             sess.fatal(&format!("error writing dependencies to `{}`: {}",
1218                                 deps_filename.display(),
1219                                 e));
1220         }
1221     }
1222 }
1223
1224 pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
1225     // Unconditionally collect crate types from attributes to make them used
1226     let attr_types: Vec<config::CrateType> =
1227         attrs.iter()
1228              .filter_map(|a| {
1229                  if a.check_name("crate_type") {
1230                      match a.value_str() {
1231                          Some(ref n) if *n == "rlib" => {
1232                              Some(config::CrateTypeRlib)
1233                          }
1234                          Some(ref n) if *n == "dylib" => {
1235                              Some(config::CrateTypeDylib)
1236                          }
1237                          Some(ref n) if *n == "cdylib" => {
1238                              Some(config::CrateTypeCdylib)
1239                          }
1240                          Some(ref n) if *n == "lib" => {
1241                              Some(config::default_lib_output())
1242                          }
1243                          Some(ref n) if *n == "staticlib" => {
1244                              Some(config::CrateTypeStaticlib)
1245                          }
1246                          Some(ref n) if *n == "proc-macro" => {
1247                              Some(config::CrateTypeProcMacro)
1248                          }
1249                          Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
1250                          Some(_) => {
1251                              session.buffer_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
1252                                                  ast::CRATE_NODE_ID,
1253                                                  a.span,
1254                                                  "invalid `crate_type` value");
1255                              None
1256                          }
1257                          _ => {
1258                              session.struct_span_err(a.span, "`crate_type` requires a value")
1259                                  .note("for example: `#![crate_type=\"lib\"]`")
1260                                  .emit();
1261                              None
1262                          }
1263                      }
1264                  } else {
1265                      None
1266                  }
1267              })
1268              .collect();
1269
1270     // If we're generating a test executable, then ignore all other output
1271     // styles at all other locations
1272     if session.opts.test {
1273         return vec![config::CrateTypeExecutable];
1274     }
1275
1276     // Only check command line flags if present. If no types are specified by
1277     // command line, then reuse the empty `base` Vec to hold the types that
1278     // will be found in crate attributes.
1279     let mut base = session.opts.crate_types.clone();
1280     if base.is_empty() {
1281         base.extend(attr_types);
1282         if base.is_empty() {
1283             base.push(::rustc_trans_utils::link::default_output_for_target(session));
1284         }
1285         base.sort();
1286         base.dedup();
1287     }
1288
1289     base.into_iter()
1290         .filter(|crate_type| {
1291             let res = !::rustc_trans_utils::link::invalid_output_for_target(session, *crate_type);
1292
1293             if !res {
1294                 session.warn(&format!("dropping unsupported crate type `{}` for target `{}`",
1295                                       *crate_type,
1296                                       session.opts.target_triple));
1297             }
1298
1299             res
1300         })
1301         .collect()
1302 }
1303
1304 pub fn compute_crate_disambiguator(session: &Session) -> String {
1305     use std::hash::Hasher;
1306
1307     // The crate_disambiguator is a 128 bit hash. The disambiguator is fed
1308     // into various other hashes quite a bit (symbol hashes, incr. comp. hashes,
1309     // debuginfo type IDs, etc), so we don't want it to be too wide. 128 bits
1310     // should still be safe enough to avoid collisions in practice.
1311     // FIXME(mw): It seems that the crate_disambiguator is used everywhere as
1312     //            a hex-string instead of raw bytes. We should really use the
1313     //            smaller representation.
1314     let mut hasher = StableHasher::<Fingerprint>::new();
1315
1316     let mut metadata = session.opts.cg.metadata.clone();
1317     // We don't want the crate_disambiguator to dependent on the order
1318     // -C metadata arguments, so sort them:
1319     metadata.sort();
1320     // Every distinct -C metadata value is only incorporated once:
1321     metadata.dedup();
1322
1323     hasher.write(b"metadata");
1324     for s in &metadata {
1325         // Also incorporate the length of a metadata string, so that we generate
1326         // different values for `-Cmetadata=ab -Cmetadata=c` and
1327         // `-Cmetadata=a -Cmetadata=bc`
1328         hasher.write_usize(s.len());
1329         hasher.write(s.as_bytes());
1330     }
1331
1332     // If this is an executable, add a special suffix, so that we don't get
1333     // symbol conflicts when linking against a library of the same name.
1334     let is_exe = session.crate_types.borrow().contains(&config::CrateTypeExecutable);
1335
1336     format!("{}{}", hasher.finish().to_hex(), if is_exe { "-exe" } else {""})
1337 }
1338
1339 pub fn build_output_filenames(input: &Input,
1340                               odir: &Option<PathBuf>,
1341                               ofile: &Option<PathBuf>,
1342                               attrs: &[ast::Attribute],
1343                               sess: &Session)
1344                               -> OutputFilenames {
1345     match *ofile {
1346         None => {
1347             // "-" as input file will cause the parser to read from stdin so we
1348             // have to make up a name
1349             // We want to toss everything after the final '.'
1350             let dirpath = match *odir {
1351                 Some(ref d) => d.clone(),
1352                 None => PathBuf::new(),
1353             };
1354
1355             // If a crate name is present, we use it as the link name
1356             let stem = sess.opts
1357                            .crate_name
1358                            .clone()
1359                            .or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string()))
1360                            .unwrap_or(input.filestem());
1361
1362             OutputFilenames {
1363                 out_directory: dirpath,
1364                 out_filestem: stem,
1365                 single_output_file: None,
1366                 extra: sess.opts.cg.extra_filename.clone(),
1367                 outputs: sess.opts.output_types.clone(),
1368             }
1369         }
1370
1371         Some(ref out_file) => {
1372             let unnamed_output_types = sess.opts
1373                                            .output_types
1374                                            .values()
1375                                            .filter(|a| a.is_none())
1376                                            .count();
1377             let ofile = if unnamed_output_types > 1 {
1378                 sess.warn("due to multiple output types requested, the explicitly specified \
1379                            output file name will be adapted for each output type");
1380                 None
1381             } else {
1382                 Some(out_file.clone())
1383             };
1384             if *odir != None {
1385                 sess.warn("ignoring --out-dir flag due to -o flag.");
1386             }
1387
1388             let cur_dir = Path::new("");
1389
1390             OutputFilenames {
1391                 out_directory: out_file.parent().unwrap_or(cur_dir).to_path_buf(),
1392                 out_filestem: out_file.file_stem()
1393                                       .unwrap_or(OsStr::new(""))
1394                                       .to_str()
1395                                       .unwrap()
1396                                       .to_string(),
1397                 single_output_file: ofile,
1398                 extra: sess.opts.cg.extra_filename.clone(),
1399                 outputs: sess.opts.output_types.clone(),
1400             }
1401         }
1402     }
1403 }