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