]> git.lizzy.rs Git - rust.git/blob - src/librustc_session/config.rs
Rollup merge of #67354 - VirrageS:blame-wrong-line, r=estebank
[rust.git] / src / librustc_session / config.rs
1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
3
4 pub use crate::options::*;
5
6 use crate::lint;
7 use crate::utils::NativeLibraryKind;
8 use crate::{early_error, early_warn, Session};
9 use crate::search_paths::SearchPath;
10
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
13
14 use rustc_target::spec::{Target, TargetTriple};
15
16 use syntax_pos::source_map::{FileName, FilePathMapping};
17 use syntax_pos::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
18 use syntax_pos::symbol::{sym, Symbol};
19 use rustc_feature::UnstableFeatures;
20 use crate::parse::CrateConfig;
21
22 use rustc_errors::emitter::HumanReadableErrorType;
23 use rustc_errors::{ColorConfig, FatalError, Handler};
24
25 use getopts;
26
27 use std::collections::{BTreeMap, BTreeSet};
28 use std::collections::btree_map::{
29     Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
30 };
31 use std::fmt;
32 use std::str::{self, FromStr};
33 use std::iter::{self, FromIterator};
34 use std::path::{Path, PathBuf};
35
36 pub struct Config {
37     pub target: Target,
38     pub ptr_width: u32,
39 }
40
41 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
42 pub enum Sanitizer {
43     Address,
44     Leak,
45     Memory,
46     Thread,
47 }
48
49 impl fmt::Display for Sanitizer {
50     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51         match *self {
52             Sanitizer::Address => "address".fmt(f),
53             Sanitizer::Leak => "leak".fmt(f),
54             Sanitizer::Memory => "memory".fmt(f),
55             Sanitizer::Thread => "thread".fmt(f),
56         }
57     }
58 }
59
60 impl FromStr for Sanitizer {
61     type Err = ();
62     fn from_str(s: &str) -> Result<Sanitizer, ()> {
63         match s {
64             "address" => Ok(Sanitizer::Address),
65             "leak" => Ok(Sanitizer::Leak),
66             "memory" => Ok(Sanitizer::Memory),
67             "thread" => Ok(Sanitizer::Thread),
68             _ => Err(()),
69         }
70     }
71 }
72
73 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
74 pub enum OptLevel {
75     No,         // -O0
76     Less,       // -O1
77     Default,    // -O2
78     Aggressive, // -O3
79     Size,       // -Os
80     SizeMin,    // -Oz
81 }
82
83 impl_stable_hash_via_hash!(OptLevel);
84
85 /// This is what the `LtoCli` values get mapped to after resolving defaults and
86 /// and taking other command line options into account.
87 #[derive(Clone, PartialEq)]
88 pub enum Lto {
89     /// Don't do any LTO whatsoever
90     No,
91
92     /// Do a full crate graph LTO with ThinLTO
93     Thin,
94
95     /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
96     /// units).
97     ThinLocal,
98
99     /// Do a full crate graph LTO with "fat" LTO
100     Fat,
101 }
102
103 /// The different settings that the `-C lto` flag can have.
104 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
105 pub enum LtoCli {
106     /// `-C lto=no`
107     No,
108     /// `-C lto=yes`
109     Yes,
110     /// `-C lto`
111     NoParam,
112     /// `-C lto=thin`
113     Thin,
114     /// `-C lto=fat`
115     Fat,
116     /// No `-C lto` flag passed
117     Unspecified,
118 }
119
120 #[derive(Clone, PartialEq, Hash)]
121 pub enum LinkerPluginLto {
122     LinkerPlugin(PathBuf),
123     LinkerPluginAuto,
124     Disabled
125 }
126
127 impl LinkerPluginLto {
128     pub fn enabled(&self) -> bool {
129         match *self {
130             LinkerPluginLto::LinkerPlugin(_) |
131             LinkerPluginLto::LinkerPluginAuto => true,
132             LinkerPluginLto::Disabled => false,
133         }
134     }
135 }
136
137 #[derive(Clone, PartialEq, Hash)]
138 pub enum SwitchWithOptPath {
139     Enabled(Option<PathBuf>),
140     Disabled,
141 }
142
143 impl SwitchWithOptPath {
144     pub fn enabled(&self) -> bool {
145         match *self {
146             SwitchWithOptPath::Enabled(_) => true,
147             SwitchWithOptPath::Disabled => false,
148         }
149     }
150 }
151
152 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
153 pub enum SymbolManglingVersion {
154     Legacy,
155     V0,
156 }
157
158 impl_stable_hash_via_hash!(SymbolManglingVersion);
159
160 #[derive(Clone, Copy, PartialEq, Hash)]
161 pub enum DebugInfo {
162     None,
163     Limited,
164     Full,
165 }
166
167 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
168 pub enum OutputType {
169     Bitcode,
170     Assembly,
171     LlvmAssembly,
172     Mir,
173     Metadata,
174     Object,
175     Exe,
176     DepInfo,
177 }
178
179 impl_stable_hash_via_hash!(OutputType);
180
181 impl OutputType {
182     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
183         match *self {
184             OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
185             OutputType::Bitcode
186             | OutputType::Assembly
187             | OutputType::LlvmAssembly
188             | OutputType::Mir
189             | OutputType::Object => false,
190         }
191     }
192
193     fn shorthand(&self) -> &'static str {
194         match *self {
195             OutputType::Bitcode => "llvm-bc",
196             OutputType::Assembly => "asm",
197             OutputType::LlvmAssembly => "llvm-ir",
198             OutputType::Mir => "mir",
199             OutputType::Object => "obj",
200             OutputType::Metadata => "metadata",
201             OutputType::Exe => "link",
202             OutputType::DepInfo => "dep-info",
203         }
204     }
205
206     fn from_shorthand(shorthand: &str) -> Option<Self> {
207         Some(match shorthand {
208             "asm" => OutputType::Assembly,
209             "llvm-ir" => OutputType::LlvmAssembly,
210             "mir" => OutputType::Mir,
211             "llvm-bc" => OutputType::Bitcode,
212             "obj" => OutputType::Object,
213             "metadata" => OutputType::Metadata,
214             "link" => OutputType::Exe,
215             "dep-info" => OutputType::DepInfo,
216             _ => return None,
217         })
218     }
219
220     fn shorthands_display() -> String {
221         format!(
222             "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
223             OutputType::Bitcode.shorthand(),
224             OutputType::Assembly.shorthand(),
225             OutputType::LlvmAssembly.shorthand(),
226             OutputType::Mir.shorthand(),
227             OutputType::Object.shorthand(),
228             OutputType::Metadata.shorthand(),
229             OutputType::Exe.shorthand(),
230             OutputType::DepInfo.shorthand(),
231         )
232     }
233
234     pub fn extension(&self) -> &'static str {
235         match *self {
236             OutputType::Bitcode => "bc",
237             OutputType::Assembly => "s",
238             OutputType::LlvmAssembly => "ll",
239             OutputType::Mir => "mir",
240             OutputType::Object => "o",
241             OutputType::Metadata => "rmeta",
242             OutputType::DepInfo => "d",
243             OutputType::Exe => "",
244         }
245     }
246 }
247
248 /// The type of diagnostics output to generate.
249 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
250 pub enum ErrorOutputType {
251     /// Output meant for the consumption of humans.
252     HumanReadable(HumanReadableErrorType),
253     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
254     Json {
255         /// Render the JSON in a human readable way (with indents and newlines).
256         pretty: bool,
257         /// The JSON output includes a `rendered` field that includes the rendered
258         /// human output.
259         json_rendered: HumanReadableErrorType,
260     },
261 }
262
263 impl Default for ErrorOutputType {
264     fn default() -> Self {
265         Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
266     }
267 }
268
269 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
270 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
271 /// dependency tracking for command-line arguments.
272 #[derive(Clone, Hash)]
273 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
274
275 impl_stable_hash_via_hash!(OutputTypes);
276
277 impl OutputTypes {
278     pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
279         OutputTypes(BTreeMap::from_iter(
280             entries.iter().map(|&(k, ref v)| (k, v.clone())),
281         ))
282     }
283
284     pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
285         self.0.get(key)
286     }
287
288     pub fn contains_key(&self, key: &OutputType) -> bool {
289         self.0.contains_key(key)
290     }
291
292     pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
293         self.0.keys()
294     }
295
296     pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
297         self.0.values()
298     }
299
300     pub fn len(&self) -> usize {
301         self.0.len()
302     }
303
304     // Returns `true` if any of the output types require codegen or linking.
305     pub fn should_codegen(&self) -> bool {
306         self.0.keys().any(|k| match *k {
307             OutputType::Bitcode
308             | OutputType::Assembly
309             | OutputType::LlvmAssembly
310             | OutputType::Mir
311             | OutputType::Object
312             | OutputType::Exe => true,
313             OutputType::Metadata | OutputType::DepInfo => false,
314         })
315     }
316 }
317
318 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
319 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
320 /// would break dependency tracking for command-line arguments.
321 #[derive(Clone)]
322 pub struct Externs(BTreeMap<String, ExternEntry>);
323
324 #[derive(Clone, Debug)]
325 pub struct ExternEntry {
326     pub location: ExternLocation,
327     /// Indicates this is a "private" dependency for the
328     /// `exported_private_dependencies` lint.
329     ///
330     /// This can be set with the `priv` option like
331     /// `--extern priv:name=foo.rlib`.
332     pub is_private_dep: bool,
333     /// Add the extern entry to the extern prelude.
334     ///
335     /// This can be disabled with the `noprelude` option like
336     /// `--extern noprelude:name`.
337     pub add_prelude: bool,
338 }
339
340 #[derive(Clone, Debug)]
341 pub enum ExternLocation {
342     /// Indicates to look for the library in the search paths.
343     ///
344     /// Added via `--extern name`.
345     FoundInLibrarySearchDirectories,
346     /// The locations where this extern entry must be found.
347     ///
348     /// The `CrateLoader` is responsible for loading these and figuring out
349     /// which one to use.
350     ///
351     /// Added via `--extern prelude_name=some_file.rlib`
352     ExactPaths(BTreeSet<String>),
353 }
354
355 impl Externs {
356     pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
357         Externs(data)
358     }
359
360     pub fn get(&self, key: &str) -> Option<&ExternEntry> {
361         self.0.get(key)
362     }
363
364     pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
365         self.0.iter()
366     }
367 }
368
369 impl ExternEntry {
370     fn new(location: ExternLocation) -> ExternEntry {
371         ExternEntry { location, is_private_dep: false, add_prelude: false }
372     }
373
374     pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
375         match &self.location {
376             ExternLocation::ExactPaths(set) => Some(set.iter()),
377             _ => None,
378         }
379     }
380 }
381
382 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
383 pub enum PrintRequest {
384     FileNames,
385     Sysroot,
386     CrateName,
387     Cfg,
388     TargetList,
389     TargetCPUs,
390     TargetFeatures,
391     RelocationModels,
392     CodeModels,
393     TlsModels,
394     TargetSpec,
395     NativeStaticLibs,
396 }
397
398 #[derive(Copy, Clone)]
399 pub enum BorrowckMode {
400     Mir,
401     Migrate,
402 }
403
404 impl BorrowckMode {
405     /// Returns whether we should run the MIR-based borrow check, but also fall back
406     /// on the AST borrow check if the MIR-based one errors.
407     pub fn migrate(self) -> bool {
408         match self {
409             BorrowckMode::Mir => false,
410             BorrowckMode::Migrate => true,
411         }
412     }
413 }
414
415 pub enum Input {
416     /// Load source code from a file.
417     File(PathBuf),
418     /// Load source code from a string.
419     Str {
420         /// A string that is shown in place of a filename.
421         name: FileName,
422         /// An anonymous string containing the source code.
423         input: String,
424     },
425 }
426
427 impl Input {
428     pub fn filestem(&self) -> &str {
429         match *self {
430             Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
431             Input::Str { .. } => "rust_out",
432         }
433     }
434
435     pub fn get_input(&mut self) -> Option<&mut String> {
436         match *self {
437             Input::File(_) => None,
438             Input::Str { ref mut input, .. } => Some(input),
439         }
440     }
441
442     pub fn source_name(&self) -> FileName {
443         match *self {
444             Input::File(ref ifile) => ifile.clone().into(),
445             Input::Str { ref name, .. } => name.clone(),
446         }
447     }
448 }
449
450 #[derive(Clone, Hash)]
451 pub struct OutputFilenames {
452     pub out_directory: PathBuf,
453     pub out_filestem: String,
454     pub single_output_file: Option<PathBuf>,
455     pub extra: String,
456     pub outputs: OutputTypes,
457 }
458
459 impl_stable_hash_via_hash!(OutputFilenames);
460
461 pub const RUST_CGU_EXT: &str = "rcgu";
462
463 impl OutputFilenames {
464     pub fn path(&self, flavor: OutputType) -> PathBuf {
465         self.outputs
466             .get(&flavor)
467             .and_then(|p| p.to_owned())
468             .or_else(|| self.single_output_file.clone())
469             .unwrap_or_else(|| self.temp_path(flavor, None))
470     }
471
472     /// Gets the path where a compilation artifact of the given type for the
473     /// given codegen unit should be placed on disk. If codegen_unit_name is
474     /// None, a path distinct from those of any codegen unit will be generated.
475     pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
476         let extension = flavor.extension();
477         self.temp_path_ext(extension, codegen_unit_name)
478     }
479
480     /// Like temp_path, but also supports things where there is no corresponding
481     /// OutputType, like noopt-bitcode or lto-bitcode.
482     pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
483         let base = self.out_directory.join(&self.filestem());
484
485         let mut extension = String::new();
486
487         if let Some(codegen_unit_name) = codegen_unit_name {
488             extension.push_str(codegen_unit_name);
489         }
490
491         if !ext.is_empty() {
492             if !extension.is_empty() {
493                 extension.push_str(".");
494                 extension.push_str(RUST_CGU_EXT);
495                 extension.push_str(".");
496             }
497
498             extension.push_str(ext);
499         }
500
501         let path = base.with_extension(&extension[..]);
502         path
503     }
504
505     pub fn with_extension(&self, extension: &str) -> PathBuf {
506         self.out_directory
507             .join(&self.filestem())
508             .with_extension(extension)
509     }
510
511     pub fn filestem(&self) -> String {
512         format!("{}{}", self.out_filestem, self.extra)
513     }
514 }
515
516 pub fn host_triple() -> &'static str {
517     // Get the host triple out of the build environment. This ensures that our
518     // idea of the host triple is the same as for the set of libraries we've
519     // actually built.  We can't just take LLVM's host triple because they
520     // normalize all ix86 architectures to i386.
521     //
522     // Instead of grabbing the host triple (for the current host), we grab (at
523     // compile time) the target triple that this rustc is built with and
524     // calling that (at runtime) the host triple.
525     (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
526 }
527
528 impl Default for Options {
529     fn default() -> Options {
530         Options {
531             crate_types: Vec::new(),
532             optimize: OptLevel::No,
533             debuginfo: DebugInfo::None,
534             lint_opts: Vec::new(),
535             lint_cap: None,
536             describe_lints: false,
537             output_types: OutputTypes(BTreeMap::new()),
538             search_paths: vec![],
539             maybe_sysroot: None,
540             target_triple: TargetTriple::from_triple(host_triple()),
541             test: false,
542             incremental: None,
543             debugging_opts: basic_debugging_options(),
544             prints: Vec::new(),
545             borrowck_mode: BorrowckMode::Migrate,
546             cg: basic_codegen_options(),
547             error_format: ErrorOutputType::default(),
548             externs: Externs(BTreeMap::new()),
549             crate_name: None,
550             alt_std_name: None,
551             libs: Vec::new(),
552             unstable_features: UnstableFeatures::Disallow,
553             debug_assertions: true,
554             actually_rustdoc: false,
555             cli_forced_codegen_units: None,
556             cli_forced_thinlto_off: false,
557             remap_path_prefix: Vec::new(),
558             edition: DEFAULT_EDITION,
559             json_artifact_notifications: false,
560             pretty: None,
561         }
562     }
563 }
564
565 impl Options {
566     /// Returns `true` if there is a reason to build the dep graph.
567     pub fn build_dep_graph(&self) -> bool {
568         self.incremental.is_some() || self.debugging_opts.dump_dep_graph
569             || self.debugging_opts.query_dep_graph
570     }
571
572     #[inline(always)]
573     pub fn enable_dep_node_debug_strs(&self) -> bool {
574         cfg!(debug_assertions)
575             && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
576     }
577
578     pub fn file_path_mapping(&self) -> FilePathMapping {
579         FilePathMapping::new(self.remap_path_prefix.clone())
580     }
581
582     /// Returns `true` if there will be an output file generated.
583     pub fn will_create_output_file(&self) -> bool {
584         !self.debugging_opts.parse_only && // The file is just being parsed
585             !self.debugging_opts.ls // The file is just being queried
586     }
587
588     #[inline]
589     pub fn share_generics(&self) -> bool {
590         match self.debugging_opts.share_generics {
591             Some(setting) => setting,
592             None => {
593                 match self.optimize {
594                     OptLevel::No   |
595                     OptLevel::Less |
596                     OptLevel::Size |
597                     OptLevel::SizeMin => true,
598                     OptLevel::Default    |
599                     OptLevel::Aggressive => false,
600                 }
601             }
602         }
603     }
604 }
605
606 // The type of entry function, so users can have their own entry functions
607 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
608 pub enum EntryFnType {
609     Main,
610     Start,
611 }
612
613 impl_stable_hash_via_hash!(EntryFnType);
614
615 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
616 pub enum CrateType {
617     Executable,
618     Dylib,
619     Rlib,
620     Staticlib,
621     Cdylib,
622     ProcMacro,
623 }
624
625 impl_stable_hash_via_hash!(CrateType);
626
627 #[derive(Clone, Hash)]
628 pub enum Passes {
629     Some(Vec<String>),
630     All,
631 }
632
633 impl Passes {
634     pub fn is_empty(&self) -> bool {
635         match *self {
636             Passes::Some(ref v) => v.is_empty(),
637             Passes::All => false,
638         }
639     }
640 }
641
642 pub const fn default_lib_output() -> CrateType {
643     CrateType::Rlib
644 }
645
646 pub fn default_configuration(sess: &Session) -> CrateConfig {
647     let end = &sess.target.target.target_endian;
648     let arch = &sess.target.target.arch;
649     let wordsz = &sess.target.target.target_pointer_width;
650     let os = &sess.target.target.target_os;
651     let env = &sess.target.target.target_env;
652     let vendor = &sess.target.target.target_vendor;
653     let min_atomic_width = sess.target.target.min_atomic_width();
654     let max_atomic_width = sess.target.target.max_atomic_width();
655     let atomic_cas = sess.target.target.options.atomic_cas;
656
657     let mut ret = FxHashSet::default();
658     ret.reserve(6); // the minimum number of insertions
659     // Target bindings.
660     ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
661     if let Some(ref fam) = sess.target.target.options.target_family {
662         ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
663         if fam == "windows" || fam == "unix" {
664             ret.insert((Symbol::intern(fam), None));
665         }
666     }
667     ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
668     ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
669     ret.insert((
670         Symbol::intern("target_pointer_width"),
671         Some(Symbol::intern(wordsz)),
672     ));
673     ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
674     ret.insert((
675         Symbol::intern("target_vendor"),
676         Some(Symbol::intern(vendor)),
677     ));
678     if sess.target.target.options.has_elf_tls {
679         ret.insert((sym::target_thread_local, None));
680     }
681     for &i in &[8, 16, 32, 64, 128] {
682         if i >= min_atomic_width && i <= max_atomic_width {
683             let mut insert_atomic = |s| {
684                 ret.insert((
685                     sym::target_has_atomic_load_store,
686                     Some(Symbol::intern(s)),
687                 ));
688                 if atomic_cas {
689                     ret.insert((
690                         sym::target_has_atomic,
691                         Some(Symbol::intern(s))
692                     ));
693                 }
694             };
695             let s = i.to_string();
696             insert_atomic(&s);
697             if &s == wordsz {
698               insert_atomic("ptr");
699             }
700         }
701     }
702     if let Some(s) = &sess.opts.debugging_opts.sanitizer {
703         let symbol = Symbol::intern(&s.to_string());
704         ret.insert((sym::sanitize, Some(symbol)));
705     }
706     if sess.opts.debug_assertions {
707         ret.insert((Symbol::intern("debug_assertions"), None));
708     }
709     if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
710         ret.insert((sym::proc_macro, None));
711     }
712     ret
713 }
714
715 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
716 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
717 /// but the symbol interner is not yet set up then, so we must convert it later.
718 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
719     cfg.into_iter()
720        .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
721        .collect()
722 }
723
724 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
725     // Combine the configuration requested by the session (command line) with
726     // some default and generated configuration items.
727     let default_cfg = default_configuration(sess);
728     // If the user wants a test runner, then add the test cfg.
729     if sess.opts.test {
730         user_cfg.insert((sym::test, None));
731     }
732     user_cfg.extend(default_cfg.iter().cloned());
733     user_cfg
734 }
735
736 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
737     let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
738         sp.struct_fatal(&format!("Error loading target specification: {}", e))
739           .help("Use `--print target-list` for a list of built-in targets")
740           .emit();
741         FatalError.raise();
742     });
743
744     let ptr_width = match &target.target_pointer_width[..] {
745         "16" => 16,
746         "32" => 32,
747         "64" => 64,
748         w => sp.fatal(&format!(
749             "target specification was invalid: \
750              unrecognized target-pointer-width {}",
751             w
752         )).raise(),
753     };
754
755     Config {
756         target,
757         ptr_width,
758     }
759 }
760
761 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
762 pub enum OptionStability {
763     Stable,
764     Unstable,
765 }
766
767 pub struct RustcOptGroup {
768     pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
769     pub name: &'static str,
770     pub stability: OptionStability,
771 }
772
773 impl RustcOptGroup {
774     pub fn is_stable(&self) -> bool {
775         self.stability == OptionStability::Stable
776     }
777
778     pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
779     where
780         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
781     {
782         RustcOptGroup {
783             name,
784             apply: Box::new(f),
785             stability: OptionStability::Stable,
786         }
787     }
788
789     pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
790     where
791         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
792     {
793         RustcOptGroup {
794             name,
795             apply: Box::new(f),
796             stability: OptionStability::Unstable,
797         }
798     }
799 }
800
801 // The `opt` local module holds wrappers around the `getopts` API that
802 // adds extra rustc-specific metadata to each option; such metadata
803 // is exposed by .  The public
804 // functions below ending with `_u` are the functions that return
805 // *unstable* options, i.e., options that are only enabled when the
806 // user also passes the `-Z unstable-options` debugging flag.
807 mod opt {
808     // The `fn flag*` etc below are written so that we can use them
809     // in the future; do not warn about them not being used right now.
810     #![allow(dead_code)]
811
812     use getopts;
813     use super::RustcOptGroup;
814
815     pub type R = RustcOptGroup;
816     pub type S = &'static str;
817
818     fn stable<F>(name: S, f: F) -> R
819     where
820         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
821     {
822         RustcOptGroup::stable(name, f)
823     }
824
825     fn unstable<F>(name: S, f: F) -> R
826     where
827         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
828     {
829         RustcOptGroup::unstable(name, f)
830     }
831
832     fn longer(a: S, b: S) -> S {
833         if a.len() > b.len() {
834             a
835         } else {
836             b
837         }
838     }
839
840     pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
841         stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
842     }
843     pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
844         stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
845     }
846     pub fn flag_s(a: S, b: S, c: S) -> R {
847         stable(longer(a, b), move |opts| opts.optflag(a, b, c))
848     }
849     pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
850         stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
851     }
852     pub fn flagmulti_s(a: S, b: S, c: S) -> R {
853         stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
854     }
855
856     pub fn opt(a: S, b: S, c: S, d: S) -> R {
857         unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
858     }
859     pub fn multi(a: S, b: S, c: S, d: S) -> R {
860         unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
861     }
862     pub fn flag(a: S, b: S, c: S) -> R {
863         unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
864     }
865     pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
866         unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
867     }
868     pub fn flagmulti(a: S, b: S, c: S) -> R {
869         unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
870     }
871 }
872
873 /// Returns the "short" subset of the rustc command line options,
874 /// including metadata for each option, such as whether the option is
875 /// part of the stable long-term interface for rustc.
876 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
877     vec![
878         opt::flag_s("h", "help", "Display this message"),
879         opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
880         opt::multi_s(
881             "L",
882             "",
883             "Add a directory to the library search path. The
884                              optional KIND can be one of dependency, crate, native,
885                              framework, or all (the default).",
886             "[KIND=]PATH",
887         ),
888         opt::multi_s(
889             "l",
890             "",
891             "Link the generated crate(s) to the specified native
892                              library NAME. The optional KIND can be one of
893                              static, framework, or dylib (the default).",
894             "[KIND=]NAME",
895         ),
896         make_crate_type_option(),
897         opt::opt_s(
898             "",
899             "crate-name",
900             "Specify the name of the crate being built",
901             "NAME",
902         ),
903         opt::opt_s(
904             "",
905             "edition",
906             "Specify which edition of the compiler to use when compiling code.",
907             EDITION_NAME_LIST,
908         ),
909         opt::multi_s(
910             "",
911             "emit",
912             "Comma separated list of types of output for \
913              the compiler to emit",
914             "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
915         ),
916         opt::multi_s(
917             "",
918             "print",
919             "Compiler information to print on stdout",
920             "[crate-name|file-names|sysroot|cfg|target-list|\
921              target-cpus|target-features|relocation-models|\
922              code-models|tls-models|target-spec-json|native-static-libs]",
923         ),
924         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
925         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
926         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
927         opt::opt_s(
928             "",
929             "out-dir",
930             "Write output to compiler-chosen filename \
931              in <dir>",
932             "DIR",
933         ),
934         opt::opt_s(
935             "",
936             "explain",
937             "Provide a detailed explanation of an error \
938              message",
939             "OPT",
940         ),
941         opt::flag_s("", "test", "Build a test harness"),
942         opt::opt_s(
943             "",
944             "target",
945             "Target triple for which the code is compiled",
946             "TARGET",
947         ),
948         opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
949         opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
950         opt::multi_s("D", "deny", "Set lint denied", "OPT"),
951         opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
952         opt::multi_s(
953             "",
954             "cap-lints",
955             "Set the most restrictive lint level. \
956              More restrictive lints are capped at this \
957              level",
958             "LEVEL",
959         ),
960         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
961         opt::flag_s("V", "version", "Print version info and exit"),
962         opt::flag_s("v", "verbose", "Use verbose output"),
963     ]
964 }
965
966 /// Returns all rustc command line options, including metadata for
967 /// each option, such as whether the option is part of the stable
968 /// long-term interface for rustc.
969 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
970     let mut opts = rustc_short_optgroups();
971     opts.extend(vec![
972         opt::multi_s(
973             "",
974             "extern",
975             "Specify where an external rust library is located",
976             "NAME[=PATH]",
977         ),
978         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
979         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
980         opt::opt_s(
981             "",
982             "error-format",
983             "How errors and other messages are produced",
984             "human|json|short",
985         ),
986         opt::multi_s(
987             "",
988             "json",
989             "Configure the JSON output of the compiler",
990             "CONFIG",
991         ),
992         opt::opt_s(
993             "",
994             "color",
995             "Configure coloring of output:
996                                  auto   = colorize, if output goes to a tty (default);
997                                  always = always colorize output;
998                                  never  = never colorize output",
999             "auto|always|never",
1000         ),
1001         opt::opt(
1002             "",
1003             "pretty",
1004             "Pretty-print the input instead of compiling;
1005                   valid types are: `normal` (un-annotated source),
1006                   `expanded` (crates expanded), or
1007                   `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1008             "TYPE",
1009         ),
1010         opt::multi_s(
1011             "",
1012             "remap-path-prefix",
1013             "Remap source names in all output (compiler messages and output files)",
1014             "FROM=TO",
1015         ),
1016     ]);
1017     opts
1018 }
1019
1020 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1021                             error_format: ErrorOutputType)
1022                             -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1023     let mut lint_opts = vec![];
1024     let mut describe_lints = false;
1025
1026     for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1027         for lint_name in matches.opt_strs(level.as_str()) {
1028             if lint_name == "help" {
1029                 describe_lints = true;
1030             } else {
1031                 lint_opts.push((lint_name.replace("-", "_"), level));
1032             }
1033         }
1034     }
1035
1036     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1037         lint::Level::from_str(&cap)
1038             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1039     });
1040     (lint_opts, describe_lints, lint_cap)
1041 }
1042
1043 /// Parses the `--color` flag.
1044 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1045     match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1046         Some("auto") => ColorConfig::Auto,
1047         Some("always") => ColorConfig::Always,
1048         Some("never") => ColorConfig::Never,
1049
1050         None => ColorConfig::Auto,
1051
1052         Some(arg) => early_error(
1053             ErrorOutputType::default(),
1054             &format!(
1055                 "argument for `--color` must be auto, \
1056                  always or never (instead was `{}`)",
1057                 arg
1058             ),
1059         ),
1060     }
1061 }
1062
1063 /// Parse the `--json` flag.
1064 ///
1065 /// The first value returned is how to render JSON diagnostics, and the second
1066 /// is whether or not artifact notifications are enabled.
1067 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1068     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1069         HumanReadableErrorType::Default;
1070     let mut json_color = ColorConfig::Never;
1071     let mut json_artifact_notifications = false;
1072     for option in matches.opt_strs("json") {
1073         // For now conservatively forbid `--color` with `--json` since `--json`
1074         // won't actually be emitting any colors and anything colorized is
1075         // embedded in a diagnostic message anyway.
1076         if matches.opt_str("color").is_some() {
1077             early_error(
1078                 ErrorOutputType::default(),
1079                 "cannot specify the `--color` option with `--json`",
1080             );
1081         }
1082
1083         for sub_option in option.split(',') {
1084             match sub_option {
1085                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1086                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1087                 "artifacts" => json_artifact_notifications = true,
1088                 s => {
1089                     early_error(
1090                         ErrorOutputType::default(),
1091                         &format!("unknown `--json` option `{}`", s),
1092                     )
1093                 }
1094             }
1095         }
1096     }
1097     (json_rendered(json_color), json_artifact_notifications)
1098 }
1099
1100 /// Parses the `--error-format` flag.
1101 pub fn parse_error_format(
1102     matches: &getopts::Matches,
1103     color: ColorConfig,
1104     json_rendered: HumanReadableErrorType,
1105 ) -> ErrorOutputType {
1106     // We need the `opts_present` check because the driver will send us Matches
1107     // with only stable options if no unstable options are used. Since error-format
1108     // is unstable, it will not be present. We have to use `opts_present` not
1109     // `opt_present` because the latter will panic.
1110     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1111         match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1112             None |
1113             Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1114             Some("human-annotate-rs") => {
1115                 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1116             },
1117             Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1118             Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1119             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1120
1121             Some(arg) => early_error(
1122                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1123                 &format!(
1124                     "argument for `--error-format` must be `human`, `json` or \
1125                      `short` (instead was `{}`)",
1126                     arg
1127                 ),
1128             ),
1129         }
1130     } else {
1131         ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1132     };
1133
1134     match error_format {
1135         ErrorOutputType::Json { .. } => {}
1136
1137         // Conservatively require that the `--json` argument is coupled with
1138         // `--error-format=json`. This means that `--json` is specified we
1139         // should actually be emitting JSON blobs.
1140         _ if matches.opt_strs("json").len() > 0 => {
1141             early_error(
1142                 ErrorOutputType::default(),
1143                 "using `--json` requires also using `--error-format=json`",
1144             );
1145         }
1146
1147         _ => {}
1148     }
1149
1150     return error_format;
1151 }
1152
1153 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1154     let edition = match matches.opt_str("edition") {
1155         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
1156             early_error(
1157                 ErrorOutputType::default(),
1158                 &format!(
1159                     "argument for `--edition` must be one of: \
1160                      {}. (instead was `{}`)",
1161                     EDITION_NAME_LIST,
1162                     arg
1163                 ),
1164             ),
1165         ),
1166         None => DEFAULT_EDITION,
1167     };
1168
1169     if !edition.is_stable() && !nightly_options::is_nightly_build() {
1170         early_error(
1171                 ErrorOutputType::default(),
1172                 &format!(
1173                     "edition {} is unstable and only \
1174                      available for nightly builds of rustc.",
1175                     edition,
1176                 )
1177         )
1178     }
1179
1180     edition
1181 }
1182
1183 fn check_debug_option_stability(
1184     debugging_opts: &DebuggingOptions,
1185     error_format: ErrorOutputType,
1186     json_rendered: HumanReadableErrorType,
1187 ) {
1188     if !debugging_opts.unstable_options {
1189         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1190             early_error(
1191                 ErrorOutputType::Json { pretty: false, json_rendered },
1192                 "`--error-format=pretty-json` is unstable",
1193             );
1194         }
1195         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1196             error_format {
1197             early_error(
1198                 ErrorOutputType::Json { pretty: false, json_rendered },
1199                 "`--error-format=human-annotate-rs` is unstable",
1200             );
1201         }
1202     }
1203 }
1204
1205 fn parse_output_types(
1206     debugging_opts: &DebuggingOptions,
1207     matches: &getopts::Matches,
1208     error_format: ErrorOutputType,
1209 ) -> OutputTypes {
1210     let mut output_types = BTreeMap::new();
1211     if !debugging_opts.parse_only {
1212         for list in matches.opt_strs("emit") {
1213             for output_type in list.split(',') {
1214                 let mut parts = output_type.splitn(2, '=');
1215                 let shorthand = parts.next().unwrap();
1216                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
1217                     early_error(
1218                         error_format,
1219                         &format!(
1220                             "unknown emission type: `{}` - expected one of: {}",
1221                             shorthand,
1222                             OutputType::shorthands_display(),
1223                         ),
1224                     ),
1225                 );
1226                 let path = parts.next().map(PathBuf::from);
1227                 output_types.insert(output_type, path);
1228             }
1229         }
1230     };
1231     if output_types.is_empty() {
1232         output_types.insert(OutputType::Exe, None);
1233     }
1234     OutputTypes(output_types)
1235 }
1236
1237 fn should_override_cgus_and_disable_thinlto(
1238     output_types: &OutputTypes,
1239     matches: &getopts::Matches,
1240     error_format: ErrorOutputType,
1241     mut codegen_units: Option<usize>,
1242 ) -> (bool, Option<usize>) {
1243     let mut disable_thinlto = false;
1244     // Issue #30063: if user requests LLVM-related output to one
1245     // particular path, disable codegen-units.
1246     let incompatible: Vec<_> = output_types.0
1247         .iter()
1248         .map(|ot_path| ot_path.0)
1249         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1250         .map(|ot| ot.shorthand())
1251         .collect();
1252     if !incompatible.is_empty() {
1253         match codegen_units {
1254             Some(n) if n > 1 => {
1255                 if matches.opt_present("o") {
1256                     for ot in &incompatible {
1257                         early_warn(
1258                             error_format,
1259                             &format!(
1260                                 "`--emit={}` with `-o` incompatible with \
1261                                  `-C codegen-units=N` for N > 1",
1262                                 ot
1263                             ),
1264                         );
1265                     }
1266                     early_warn(error_format, "resetting to default -C codegen-units=1");
1267                     codegen_units = Some(1);
1268                     disable_thinlto = true;
1269                 }
1270             }
1271             _ => {
1272                 codegen_units = Some(1);
1273                 disable_thinlto = true;
1274             }
1275         }
1276     }
1277
1278     if codegen_units == Some(0) {
1279         early_error(
1280             error_format,
1281             "value for codegen units must be a positive non-zero integer",
1282         );
1283     }
1284
1285     (disable_thinlto, codegen_units)
1286 }
1287
1288 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1289     if debugging_opts.threads == 0 {
1290         early_error(
1291             error_format,
1292             "value for threads must be a positive non-zero integer",
1293         );
1294     }
1295
1296     if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1297         early_error(
1298             error_format,
1299             "optimization fuel is incompatible with multiple threads",
1300         );
1301     }
1302 }
1303
1304 fn select_incremental_path(
1305     debugging_opts: &DebuggingOptions,
1306     cg: &CodegenOptions,
1307     error_format: ErrorOutputType,
1308 ) -> Option<PathBuf> {
1309     match (&debugging_opts.incremental, &cg.incremental) {
1310         (Some(path1), Some(path2)) => {
1311             if path1 != path2 {
1312                 early_error(
1313                     error_format,
1314                     &format!(
1315                         "conflicting paths for `-Z incremental` and \
1316                          `-C incremental` specified: {} versus {}",
1317                         path1, path2
1318                     ),
1319                 );
1320             } else {
1321                 Some(path1)
1322             }
1323         }
1324         (Some(path), None) => Some(path),
1325         (None, Some(path)) => Some(path),
1326         (None, None) => None,
1327     }.map(|m| PathBuf::from(m))
1328 }
1329
1330 fn collect_print_requests(
1331     cg: &mut CodegenOptions,
1332     dopts: &mut DebuggingOptions,
1333     matches: &getopts::Matches,
1334     error_format: ErrorOutputType,
1335 ) -> Vec<PrintRequest> {
1336     let mut prints = Vec::<PrintRequest>::new();
1337     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1338         prints.push(PrintRequest::TargetCPUs);
1339         cg.target_cpu = None;
1340     };
1341     if cg.target_feature == "help" {
1342         prints.push(PrintRequest::TargetFeatures);
1343         cg.target_feature = String::new();
1344     }
1345     if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1346         prints.push(PrintRequest::RelocationModels);
1347         cg.relocation_model = None;
1348     }
1349     if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1350         prints.push(PrintRequest::CodeModels);
1351         cg.code_model = None;
1352     }
1353     if dopts
1354         .tls_model
1355         .as_ref()
1356         .map_or(false, |s| s == "help")
1357     {
1358         prints.push(PrintRequest::TlsModels);
1359         dopts.tls_model = None;
1360     }
1361
1362     prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1363         "crate-name" => PrintRequest::CrateName,
1364         "file-names" => PrintRequest::FileNames,
1365         "sysroot" => PrintRequest::Sysroot,
1366         "cfg" => PrintRequest::Cfg,
1367         "target-list" => PrintRequest::TargetList,
1368         "target-cpus" => PrintRequest::TargetCPUs,
1369         "target-features" => PrintRequest::TargetFeatures,
1370         "relocation-models" => PrintRequest::RelocationModels,
1371         "code-models" => PrintRequest::CodeModels,
1372         "tls-models" => PrintRequest::TlsModels,
1373         "native-static-libs" => PrintRequest::NativeStaticLibs,
1374         "target-spec-json" => {
1375             if dopts.unstable_options {
1376                 PrintRequest::TargetSpec
1377             } else {
1378                 early_error(
1379                     error_format,
1380                     "the `-Z unstable-options` flag must also be passed to \
1381                      enable the target-spec-json print option",
1382                 );
1383             }
1384         }
1385         req => early_error(error_format, &format!("unknown print request `{}`", req)),
1386     }));
1387
1388     prints
1389 }
1390
1391 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1392     match matches.opt_str("target") {
1393         Some(target) if target.ends_with(".json") => {
1394             let path = Path::new(&target);
1395             TargetTriple::from_path(&path).unwrap_or_else(|_|
1396                 early_error(error_format, &format!("target file {:?} does not exist", path)))
1397         }
1398         Some(target) => TargetTriple::TargetTriple(target),
1399         _ => TargetTriple::from_triple(host_triple()),
1400     }
1401 }
1402
1403 fn parse_opt_level(
1404     matches: &getopts::Matches,
1405     cg: &CodegenOptions,
1406     error_format: ErrorOutputType,
1407 ) -> OptLevel {
1408     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1409     // to use them interchangeably. However, because they're technically different flags,
1410     // we need to work out manually which should take precedence if both are supplied (i.e.
1411     // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1412     // comparing them. Note that if a flag is not found, its position will be `None`, which
1413     // always compared less than `Some(_)`.
1414     let max_o = matches.opt_positions("O").into_iter().max();
1415     let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
1416         if let Some("opt-level") = s.splitn(2, '=').next() {
1417             Some(i)
1418         } else {
1419             None
1420         }
1421     }).max();
1422     if max_o > max_c {
1423         OptLevel::Default
1424     } else {
1425         match cg.opt_level.as_ref().map(String::as_ref) {
1426             None => OptLevel::No,
1427             Some("0") => OptLevel::No,
1428             Some("1") => OptLevel::Less,
1429             Some("2") => OptLevel::Default,
1430             Some("3") => OptLevel::Aggressive,
1431             Some("s") => OptLevel::Size,
1432             Some("z") => OptLevel::SizeMin,
1433             Some(arg) => {
1434                 early_error(
1435                     error_format,
1436                     &format!(
1437                         "optimization level needs to be \
1438                             between 0-3, s or z (instead was `{}`)",
1439                         arg
1440                     ),
1441                 );
1442             }
1443         }
1444     }
1445 }
1446
1447 fn select_debuginfo(
1448     matches: &getopts::Matches,
1449     cg: &CodegenOptions,
1450     error_format: ErrorOutputType,
1451 ) -> DebugInfo {
1452     let max_g = matches.opt_positions("g").into_iter().max();
1453     let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
1454         if let Some("debuginfo") = s.splitn(2, '=').next() {
1455             Some(i)
1456         } else {
1457             None
1458         }
1459     }).max();
1460     if max_g > max_c {
1461         DebugInfo::Full
1462     } else {
1463         match cg.debuginfo {
1464             None | Some(0) => DebugInfo::None,
1465             Some(1) => DebugInfo::Limited,
1466             Some(2) => DebugInfo::Full,
1467             Some(arg) => {
1468                 early_error(
1469                     error_format,
1470                     &format!(
1471                         "debug info level needs to be between \
1472                          0-2 (instead was `{}`)",
1473                         arg
1474                     ),
1475                 );
1476             }
1477         }
1478     }
1479 }
1480
1481 fn parse_libs(
1482     matches: &getopts::Matches,
1483     error_format: ErrorOutputType,
1484 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1485     matches
1486         .opt_strs("l")
1487         .into_iter()
1488         .map(|s| {
1489             // Parse string of the form "[KIND=]lib[:new_name]",
1490             // where KIND is one of "dylib", "framework", "static".
1491             let mut parts = s.splitn(2, '=');
1492             let kind = parts.next().unwrap();
1493             let (name, kind) = match (parts.next(), kind) {
1494                 (None, name) => (name, None),
1495                 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1496                 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1497                 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1498                 (Some(name), "static-nobundle") => {
1499                     (name, Some(NativeLibraryKind::NativeStaticNobundle))
1500                 }
1501                 (_, s) => {
1502                     early_error(
1503                         error_format,
1504                         &format!(
1505                             "unknown library kind `{}`, expected \
1506                              one of dylib, framework, or static",
1507                             s
1508                         ),
1509                     );
1510                 }
1511             };
1512             if kind == Some(NativeLibraryKind::NativeStaticNobundle) &&
1513                 !nightly_options::is_nightly_build() {
1514                 early_error(
1515                     error_format,
1516                     &format!(
1517                         "the library kind 'static-nobundle' is only \
1518                          accepted on the nightly compiler"
1519                     ),
1520                 );
1521             }
1522             let mut name_parts = name.splitn(2, ':');
1523             let name = name_parts.next().unwrap();
1524             let new_name = name_parts.next();
1525             (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1526         })
1527         .collect()
1528 }
1529
1530 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1531     match dopts.borrowck.as_ref().map(|s| &s[..]) {
1532         None | Some("migrate") => BorrowckMode::Migrate,
1533         Some("mir") => BorrowckMode::Mir,
1534         Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1535     }
1536 }
1537
1538 pub fn parse_externs(
1539     matches: &getopts::Matches,
1540     debugging_opts: &DebuggingOptions,
1541     error_format: ErrorOutputType,
1542 ) -> Externs {
1543     let is_unstable_enabled = debugging_opts.unstable_options;
1544     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1545     for arg in matches.opt_strs("extern") {
1546         let mut parts = arg.splitn(2, '=');
1547         let name = parts
1548             .next()
1549             .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1550         let path = parts.next().map(|s| s.to_string());
1551
1552         let mut name_parts = name.splitn(2, ':');
1553         let first_part = name_parts.next();
1554         let second_part = name_parts.next();
1555         let (options, name) = match (first_part, second_part) {
1556             (Some(opts), Some(name)) => (Some(opts), name),
1557             (Some(name), None) => (None, name),
1558             (None, None) => early_error(error_format, "--extern name must not be empty"),
1559             _ => unreachable!(),
1560         };
1561
1562         let entry = externs.entry(name.to_owned());
1563
1564         use std::collections::btree_map::Entry;
1565
1566         let entry = if let Some(path) = path {
1567             // --extern prelude_name=some_file.rlib
1568             match entry {
1569                 Entry::Vacant(vacant) => {
1570                     let files = BTreeSet::from_iter(iter::once(path));
1571                     vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1572                 }
1573                 Entry::Occupied(occupied) => {
1574                     let ext_ent = occupied.into_mut();
1575                     match ext_ent {
1576                         ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1577                             files.insert(path);
1578                         }
1579                         ExternEntry {
1580                             location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1581                             ..
1582                         } => {
1583                             // Exact paths take precedence over search directories.
1584                             let files = BTreeSet::from_iter(iter::once(path));
1585                             *location = ExternLocation::ExactPaths(files);
1586                         }
1587                     }
1588                     ext_ent
1589                 }
1590             }
1591         } else {
1592             // --extern prelude_name
1593             match entry {
1594                 Entry::Vacant(vacant) => {
1595                     vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1596                 }
1597                 Entry::Occupied(occupied) => {
1598                     // Ignore if already specified.
1599                     occupied.into_mut()
1600                 }
1601             }
1602         };
1603
1604         let mut is_private_dep = false;
1605         let mut add_prelude = true;
1606         if let Some(opts) = options {
1607             if !is_unstable_enabled {
1608                 early_error(
1609                     error_format,
1610                     "the `-Z unstable-options` flag must also be passed to \
1611                      enable `--extern options",
1612                 );
1613             }
1614             for opt in opts.split(',') {
1615                 match opt {
1616                     "priv" => is_private_dep = true,
1617                     "noprelude" => {
1618                         if let ExternLocation::ExactPaths(_) = &entry.location {
1619                             add_prelude = false;
1620                         } else {
1621                             early_error(
1622                                 error_format,
1623                                 "the `noprelude` --extern option requires a file path",
1624                             );
1625                         }
1626                     }
1627                     _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1628                 }
1629             }
1630         }
1631
1632         // Crates start out being not private, and go to being private `priv`
1633         // is specified.
1634         entry.is_private_dep |= is_private_dep;
1635         // If any flag is missing `noprelude`, then add to the prelude.
1636         entry.add_prelude |= add_prelude;
1637     }
1638     Externs(externs)
1639 }
1640
1641 fn parse_remap_path_prefix(
1642     matches: &getopts::Matches,
1643     error_format: ErrorOutputType
1644 ) -> Vec<(PathBuf, PathBuf)> {
1645     matches
1646         .opt_strs("remap-path-prefix")
1647         .into_iter()
1648         .map(|remap| {
1649             let mut parts = remap.rsplitn(2, '='); // reverse iterator
1650             let to = parts.next();
1651             let from = parts.next();
1652             match (from, to) {
1653                 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1654                 _ => early_error(
1655                     error_format,
1656                     "--remap-path-prefix must contain '=' between FROM and TO",
1657                 ),
1658             }
1659         })
1660         .collect()
1661 }
1662
1663 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1664     let color = parse_color(matches);
1665
1666     let edition = parse_crate_edition(matches);
1667
1668     let (json_rendered, json_artifact_notifications) = parse_json(matches);
1669
1670     let error_format = parse_error_format(matches, color, json_rendered);
1671
1672     let unparsed_crate_types = matches.opt_strs("crate-type");
1673     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1674         .unwrap_or_else(|e| early_error(error_format, &e[..]));
1675
1676     let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1677
1678     let mut debugging_opts = build_debugging_options(matches, error_format);
1679     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1680
1681     let output_types = parse_output_types(&debugging_opts, matches, error_format);
1682
1683     let mut cg = build_codegen_options(matches, error_format);
1684     let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
1685         &output_types,
1686         matches,
1687         error_format,
1688         cg.codegen_units,
1689     );
1690
1691     check_thread_count(&debugging_opts, error_format);
1692
1693     let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
1694
1695     if debugging_opts.profile && incremental.is_some() {
1696         early_error(
1697             error_format,
1698             "can't instrument with gcov profiling when compiling incrementally",
1699         );
1700     }
1701
1702     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1703         early_error(
1704             error_format,
1705             "options `-C profile-generate` and `-C profile-use` are exclusive",
1706         );
1707     }
1708
1709     let prints = collect_print_requests(
1710         &mut cg,
1711         &mut debugging_opts,
1712         matches,
1713         error_format,
1714     );
1715
1716     let cg = cg;
1717
1718     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1719     let target_triple = parse_target_triple(matches, error_format);
1720     let opt_level = parse_opt_level(matches, &cg, error_format);
1721     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1722     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1723     // for more details.
1724     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1725     let debuginfo = select_debuginfo(matches, &cg, error_format);
1726
1727     let mut search_paths = vec![];
1728     for s in &matches.opt_strs("L") {
1729         search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1730     }
1731
1732     let libs = parse_libs(matches, error_format);
1733
1734     let test = matches.opt_present("test");
1735
1736     let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1737
1738     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1739         early_warn(
1740             error_format,
1741             "-C remark requires \"-C debuginfo=n\" to show source locations",
1742         );
1743     }
1744
1745     let externs = parse_externs(matches, &debugging_opts, error_format);
1746
1747     let crate_name = matches.opt_str("crate-name");
1748
1749     let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1750
1751     let pretty = parse_pretty(matches, &debugging_opts, error_format);
1752
1753     Options {
1754         crate_types,
1755         optimize: opt_level,
1756         debuginfo,
1757         lint_opts,
1758         lint_cap,
1759         describe_lints,
1760         output_types,
1761         search_paths,
1762         maybe_sysroot: sysroot_opt,
1763         target_triple,
1764         test,
1765         incremental,
1766         debugging_opts,
1767         prints,
1768         borrowck_mode,
1769         cg,
1770         error_format,
1771         externs,
1772         crate_name,
1773         alt_std_name: None,
1774         libs,
1775         unstable_features: UnstableFeatures::from_environment(),
1776         debug_assertions,
1777         actually_rustdoc: false,
1778         cli_forced_codegen_units: codegen_units,
1779         cli_forced_thinlto_off: disable_thinlto,
1780         remap_path_prefix,
1781         edition,
1782         json_artifact_notifications,
1783         pretty,
1784     }
1785 }
1786
1787 fn parse_pretty(
1788     matches: &getopts::Matches,
1789     debugging_opts: &DebuggingOptions,
1790     efmt: ErrorOutputType,
1791 ) -> Option<PpMode> {
1792     let pretty = if debugging_opts.unstable_options {
1793         matches.opt_default("pretty", "normal").map(|a| {
1794             // stable pretty-print variants only
1795             parse_pretty_inner(efmt, &a, false)
1796         })
1797     } else {
1798         None
1799     };
1800
1801     return if pretty.is_none() {
1802         debugging_opts.unpretty.as_ref().map(|a| {
1803             // extended with unstable pretty-print variants
1804             parse_pretty_inner(efmt, &a, true)
1805         })
1806     } else {
1807         pretty
1808     };
1809
1810     fn parse_pretty_inner(
1811         efmt: ErrorOutputType,
1812         name: &str,
1813         extended: bool,
1814     ) -> PpMode {
1815         use PpMode::*;
1816         use PpSourceMode::*;
1817         let first = match (name, extended) {
1818             ("normal", _) => PpmSource(PpmNormal),
1819             ("identified", _) => PpmSource(PpmIdentified),
1820             ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1821             ("expanded", _) => PpmSource(PpmExpanded),
1822             ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1823             ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1824             ("hir", true) => PpmHir(PpmNormal),
1825             ("hir,identified", true) => PpmHir(PpmIdentified),
1826             ("hir,typed", true) => PpmHir(PpmTyped),
1827             ("hir-tree", true) => PpmHirTree(PpmNormal),
1828             ("mir", true) => PpmMir,
1829             ("mir-cfg", true) => PpmMirCFG,
1830             _ => {
1831                 if extended {
1832                     early_error(efmt, &format!("argument to `unpretty` must be one of `normal`, \
1833                                         `expanded`, `identified`, `expanded,identified`, \
1834                                         `expanded,hygiene`, `everybody_loops`, \
1835                                         `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1836                                         `mir` or `mir-cfg`; got {}",
1837                                         name));
1838                 } else {
1839                     early_error(efmt, &format!("argument to `pretty` must be one of `normal`, \
1840                                         `expanded`, `identified`, or `expanded,identified`; got {}",
1841                                         name));
1842                 }
1843             }
1844         };
1845         first
1846     }
1847 }
1848
1849 pub fn make_crate_type_option() -> RustcOptGroup {
1850     opt::multi_s(
1851         "",
1852         "crate-type",
1853         "Comma separated list of types of crates
1854                                 for the compiler to emit",
1855         "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1856     )
1857 }
1858
1859 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1860     let mut crate_types: Vec<CrateType> = Vec::new();
1861     for unparsed_crate_type in &list_list {
1862         for part in unparsed_crate_type.split(',') {
1863             let new_part = match part {
1864                 "lib" => default_lib_output(),
1865                 "rlib" => CrateType::Rlib,
1866                 "staticlib" => CrateType::Staticlib,
1867                 "dylib" => CrateType::Dylib,
1868                 "cdylib" => CrateType::Cdylib,
1869                 "bin" => CrateType::Executable,
1870                 "proc-macro" => CrateType::ProcMacro,
1871                 _ => return Err(format!("unknown crate type: `{}`", part))
1872             };
1873             if !crate_types.contains(&new_part) {
1874                 crate_types.push(new_part)
1875             }
1876         }
1877     }
1878
1879     Ok(crate_types)
1880 }
1881
1882 pub mod nightly_options {
1883     use getopts;
1884     use rustc_feature::UnstableFeatures;
1885     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1886     use crate::early_error;
1887
1888     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1889         is_nightly_build()
1890             && matches
1891                 .opt_strs("Z")
1892                 .iter()
1893                 .any(|x| *x == "unstable-options")
1894     }
1895
1896     pub fn is_nightly_build() -> bool {
1897         UnstableFeatures::from_environment().is_nightly_build()
1898     }
1899
1900     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1901         let has_z_unstable_option = matches
1902             .opt_strs("Z")
1903             .iter()
1904             .any(|x| *x == "unstable-options");
1905         let really_allows_unstable_options =
1906             UnstableFeatures::from_environment().is_nightly_build();
1907
1908         for opt in flags.iter() {
1909             if opt.stability == OptionStability::Stable {
1910                 continue;
1911             }
1912             if !matches.opt_present(opt.name) {
1913                 continue;
1914             }
1915             if opt.name != "Z" && !has_z_unstable_option {
1916                 early_error(
1917                     ErrorOutputType::default(),
1918                     &format!(
1919                         "the `-Z unstable-options` flag must also be passed to enable \
1920                          the flag `{}`",
1921                         opt.name
1922                     ),
1923                 );
1924             }
1925             if really_allows_unstable_options {
1926                 continue;
1927             }
1928             match opt.stability {
1929                 OptionStability::Unstable => {
1930                     let msg = format!(
1931                         "the option `{}` is only accepted on the \
1932                          nightly compiler",
1933                         opt.name
1934                     );
1935                     early_error(ErrorOutputType::default(), &msg);
1936                 }
1937                 OptionStability::Stable => {}
1938             }
1939         }
1940     }
1941 }
1942
1943 impl fmt::Display for CrateType {
1944     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1945         match *self {
1946             CrateType::Executable => "bin".fmt(f),
1947             CrateType::Dylib => "dylib".fmt(f),
1948             CrateType::Rlib => "rlib".fmt(f),
1949             CrateType::Staticlib => "staticlib".fmt(f),
1950             CrateType::Cdylib => "cdylib".fmt(f),
1951             CrateType::ProcMacro => "proc-macro".fmt(f),
1952         }
1953     }
1954 }
1955
1956 #[derive(Copy, Clone, PartialEq, Debug)]
1957 pub enum PpSourceMode {
1958     PpmNormal,
1959     PpmEveryBodyLoops,
1960     PpmExpanded,
1961     PpmIdentified,
1962     PpmExpandedIdentified,
1963     PpmExpandedHygiene,
1964     PpmTyped,
1965 }
1966
1967 #[derive(Copy, Clone, PartialEq, Debug)]
1968 pub enum PpMode {
1969     PpmSource(PpSourceMode),
1970     PpmHir(PpSourceMode),
1971     PpmHirTree(PpSourceMode),
1972     PpmMir,
1973     PpmMirCFG,
1974 }
1975
1976 impl PpMode {
1977     pub fn needs_ast_map(&self) -> bool {
1978         use PpMode::*;
1979         use PpSourceMode::*;
1980         match *self {
1981             PpmSource(PpmNormal) |
1982             PpmSource(PpmEveryBodyLoops) |
1983             PpmSource(PpmIdentified) => false,
1984
1985             PpmSource(PpmExpanded) |
1986             PpmSource(PpmExpandedIdentified) |
1987             PpmSource(PpmExpandedHygiene) |
1988             PpmHir(_) |
1989             PpmHirTree(_) |
1990             PpmMir |
1991             PpmMirCFG => true,
1992             PpmSource(PpmTyped) => panic!("invalid state"),
1993         }
1994     }
1995
1996     pub fn needs_analysis(&self) -> bool {
1997         use PpMode::*;
1998         match *self {
1999             PpmMir | PpmMirCFG => true,
2000             _ => false,
2001         }
2002     }
2003 }
2004
2005 /// Command-line arguments passed to the compiler have to be incorporated with
2006 /// the dependency tracking system for incremental compilation. This module
2007 /// provides some utilities to make this more convenient.
2008 ///
2009 /// The values of all command-line arguments that are relevant for dependency
2010 /// tracking are hashed into a single value that determines whether the
2011 /// incremental compilation cache can be re-used or not. This hashing is done
2012 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2013 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2014 /// the hash of which is order dependent, but we might not want the order of
2015 /// arguments to make a difference for the hash).
2016 ///
2017 /// However, since the value provided by `Hash::hash` often *is* suitable,
2018 /// especially for primitive types, there is the
2019 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2020 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2021 /// we have an opt-in scheme here, so one is hopefully forced to think about
2022 /// how the hash should be calculated when adding a new command-line argument.
2023 crate mod dep_tracking {
2024     use crate::lint;
2025     use crate::utils::NativeLibraryKind;
2026     use std::collections::BTreeMap;
2027     use std::hash::Hash;
2028     use std::path::PathBuf;
2029     use std::collections::hash_map::DefaultHasher;
2030     use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2031                 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2032                 SymbolManglingVersion};
2033     use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2034     use syntax_pos::edition::Edition;
2035     use rustc_feature::UnstableFeatures;
2036
2037     pub trait DepTrackingHash {
2038         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2039     }
2040
2041     macro_rules! impl_dep_tracking_hash_via_hash {
2042         ($t:ty) => (
2043             impl DepTrackingHash for $t {
2044                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2045                     Hash::hash(self, hasher);
2046                 }
2047             }
2048         )
2049     }
2050
2051     macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2052         ($t:ty) => (
2053             impl DepTrackingHash for Vec<$t> {
2054                 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2055                     let mut elems: Vec<&$t> = self.iter().collect();
2056                     elems.sort();
2057                     Hash::hash(&elems.len(), hasher);
2058                     for (index, elem) in elems.iter().enumerate() {
2059                         Hash::hash(&index, hasher);
2060                         DepTrackingHash::hash(*elem, hasher, error_format);
2061                     }
2062                 }
2063             }
2064         );
2065     }
2066
2067     impl_dep_tracking_hash_via_hash!(bool);
2068     impl_dep_tracking_hash_via_hash!(usize);
2069     impl_dep_tracking_hash_via_hash!(u64);
2070     impl_dep_tracking_hash_via_hash!(String);
2071     impl_dep_tracking_hash_via_hash!(PathBuf);
2072     impl_dep_tracking_hash_via_hash!(lint::Level);
2073     impl_dep_tracking_hash_via_hash!(Option<bool>);
2074     impl_dep_tracking_hash_via_hash!(Option<usize>);
2075     impl_dep_tracking_hash_via_hash!(Option<String>);
2076     impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2077     impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2078     impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2079     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2080     impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2081     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2082     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2083     impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2084     impl_dep_tracking_hash_via_hash!(CrateType);
2085     impl_dep_tracking_hash_via_hash!(MergeFunctions);
2086     impl_dep_tracking_hash_via_hash!(PanicStrategy);
2087     impl_dep_tracking_hash_via_hash!(RelroLevel);
2088     impl_dep_tracking_hash_via_hash!(Passes);
2089     impl_dep_tracking_hash_via_hash!(OptLevel);
2090     impl_dep_tracking_hash_via_hash!(LtoCli);
2091     impl_dep_tracking_hash_via_hash!(DebugInfo);
2092     impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2093     impl_dep_tracking_hash_via_hash!(OutputTypes);
2094     impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2095     impl_dep_tracking_hash_via_hash!(Sanitizer);
2096     impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2097     impl_dep_tracking_hash_via_hash!(TargetTriple);
2098     impl_dep_tracking_hash_via_hash!(Edition);
2099     impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2100     impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2101     impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2102
2103     impl_dep_tracking_hash_for_sortable_vec_of!(String);
2104     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2105     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2106     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2107     impl_dep_tracking_hash_for_sortable_vec_of!((
2108         String,
2109         Option<String>,
2110         Option<NativeLibraryKind>
2111     ));
2112     impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2113     impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2114
2115     impl<T1, T2> DepTrackingHash for (T1, T2)
2116     where
2117         T1: DepTrackingHash,
2118         T2: DepTrackingHash,
2119     {
2120         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2121             Hash::hash(&0, hasher);
2122             DepTrackingHash::hash(&self.0, hasher, error_format);
2123             Hash::hash(&1, hasher);
2124             DepTrackingHash::hash(&self.1, hasher, error_format);
2125         }
2126     }
2127
2128     impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2129     where
2130         T1: DepTrackingHash,
2131         T2: DepTrackingHash,
2132         T3: DepTrackingHash,
2133     {
2134         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2135             Hash::hash(&0, hasher);
2136             DepTrackingHash::hash(&self.0, hasher, error_format);
2137             Hash::hash(&1, hasher);
2138             DepTrackingHash::hash(&self.1, hasher, error_format);
2139             Hash::hash(&2, hasher);
2140             DepTrackingHash::hash(&self.2, hasher, error_format);
2141         }
2142     }
2143
2144     // This is a stable hash because BTreeMap is a sorted container
2145     pub fn stable_hash(
2146         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2147         hasher: &mut DefaultHasher,
2148         error_format: ErrorOutputType,
2149     ) {
2150         for (key, sub_hash) in sub_hashes {
2151             // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2152             // the keys, as they are just plain strings
2153             Hash::hash(&key.len(), hasher);
2154             Hash::hash(key, hasher);
2155             sub_hash.hash(hasher, error_format);
2156         }
2157     }
2158 }