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