]> git.lizzy.rs Git - rust.git/blob - src/librustc_session/config.rs
Auto merge of #71292 - marmeladema:queries-local-def-id, r=eddyb
[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 diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
621         HandlerFlags {
622             can_emit_warnings,
623             treat_err_as_bug: self.treat_err_as_bug,
624             dont_buffer_diagnostics: self.dont_buffer_diagnostics,
625             report_delayed_bugs: self.report_delayed_bugs,
626             macro_backtrace: self.macro_backtrace,
627             deduplicate_diagnostics: self.deduplicate_diagnostics,
628         }
629     }
630 }
631
632 // The type of entry function, so users can have their own entry functions
633 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
634 pub enum EntryFnType {
635     Main,
636     Start,
637 }
638
639 impl_stable_hash_via_hash!(EntryFnType);
640
641 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
642 pub enum CrateType {
643     Executable,
644     Dylib,
645     Rlib,
646     Staticlib,
647     Cdylib,
648     ProcMacro,
649 }
650
651 impl_stable_hash_via_hash!(CrateType);
652
653 #[derive(Clone, Hash)]
654 pub enum Passes {
655     Some(Vec<String>),
656     All,
657 }
658
659 impl Passes {
660     pub fn is_empty(&self) -> bool {
661         match *self {
662             Passes::Some(ref v) => v.is_empty(),
663             Passes::All => false,
664         }
665     }
666 }
667
668 pub const fn default_lib_output() -> CrateType {
669     CrateType::Rlib
670 }
671
672 pub fn default_configuration(sess: &Session) -> CrateConfig {
673     let end = &sess.target.target.target_endian;
674     let arch = &sess.target.target.arch;
675     let wordsz = &sess.target.target.target_pointer_width;
676     let os = &sess.target.target.target_os;
677     let env = &sess.target.target.target_env;
678     let vendor = &sess.target.target.target_vendor;
679     let min_atomic_width = sess.target.target.min_atomic_width();
680     let max_atomic_width = sess.target.target.max_atomic_width();
681     let atomic_cas = sess.target.target.options.atomic_cas;
682
683     let mut ret = FxHashSet::default();
684     ret.reserve(6); // the minimum number of insertions
685     // Target bindings.
686     ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
687     if let Some(ref fam) = sess.target.target.options.target_family {
688         ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
689         if fam == "windows" || fam == "unix" {
690             ret.insert((Symbol::intern(fam), None));
691         }
692     }
693     ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
694     ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
695     ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
696     ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
697     ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
698     if sess.target.target.options.has_elf_tls {
699         ret.insert((sym::target_thread_local, None));
700     }
701     for &i in &[8, 16, 32, 64, 128] {
702         if i >= min_atomic_width && i <= max_atomic_width {
703             let mut insert_atomic = |s| {
704                 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
705                 if atomic_cas {
706                     ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
707                 }
708             };
709             let s = i.to_string();
710             insert_atomic(&s);
711             if &s == wordsz {
712                 insert_atomic("ptr");
713             }
714         }
715     }
716     if let Some(s) = &sess.opts.debugging_opts.sanitizer {
717         let symbol = Symbol::intern(&s.to_string());
718         ret.insert((sym::sanitize, Some(symbol)));
719     }
720     if sess.opts.debug_assertions {
721         ret.insert((Symbol::intern("debug_assertions"), None));
722     }
723     if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
724         ret.insert((sym::proc_macro, None));
725     }
726     ret
727 }
728
729 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
730 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
731 /// but the symbol interner is not yet set up then, so we must convert it later.
732 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
733     cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
734 }
735
736 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
737     // Combine the configuration requested by the session (command line) with
738     // some default and generated configuration items.
739     let default_cfg = default_configuration(sess);
740     // If the user wants a test runner, then add the test cfg.
741     if sess.opts.test {
742         user_cfg.insert((sym::test, None));
743     }
744     user_cfg.extend(default_cfg.iter().cloned());
745     user_cfg
746 }
747
748 pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config {
749     let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
750         early_error(
751             error_format,
752             &format!(
753                 "Error loading target specification: {}. \
754             Use `--print target-list` for a list of built-in targets",
755                 e
756             ),
757         )
758     });
759
760     let ptr_width = match &target.target_pointer_width[..] {
761         "16" => 16,
762         "32" => 32,
763         "64" => 64,
764         w => early_error(
765             error_format,
766             &format!(
767                 "target specification was invalid: \
768              unrecognized target-pointer-width {}",
769                 w
770             ),
771         ),
772     };
773
774     Config { target, ptr_width }
775 }
776
777 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
778 pub enum OptionStability {
779     Stable,
780     Unstable,
781 }
782
783 pub struct RustcOptGroup {
784     pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
785     pub name: &'static str,
786     pub stability: OptionStability,
787 }
788
789 impl RustcOptGroup {
790     pub fn is_stable(&self) -> bool {
791         self.stability == OptionStability::Stable
792     }
793
794     pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
795     where
796         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
797     {
798         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
799     }
800
801     pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
802     where
803         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
804     {
805         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
806     }
807 }
808
809 // The `opt` local module holds wrappers around the `getopts` API that
810 // adds extra rustc-specific metadata to each option; such metadata
811 // is exposed by .  The public
812 // functions below ending with `_u` are the functions that return
813 // *unstable* options, i.e., options that are only enabled when the
814 // user also passes the `-Z unstable-options` debugging flag.
815 mod opt {
816     // The `fn flag*` etc below are written so that we can use them
817     // in the future; do not warn about them not being used right now.
818     #![allow(dead_code)]
819
820     use super::RustcOptGroup;
821
822     pub type R = RustcOptGroup;
823     pub type S = &'static str;
824
825     fn stable<F>(name: S, f: F) -> R
826     where
827         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
828     {
829         RustcOptGroup::stable(name, f)
830     }
831
832     fn unstable<F>(name: S, f: F) -> R
833     where
834         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
835     {
836         RustcOptGroup::unstable(name, f)
837     }
838
839     fn longer(a: S, b: S) -> S {
840         if a.len() > b.len() { a } else { b }
841     }
842
843     pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
844         stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
845     }
846     pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
847         stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
848     }
849     pub fn flag_s(a: S, b: S, c: S) -> R {
850         stable(longer(a, b), move |opts| opts.optflag(a, b, c))
851     }
852     pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
853         stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
854     }
855     pub fn flagmulti_s(a: S, b: S, c: S) -> R {
856         stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
857     }
858
859     pub fn opt(a: S, b: S, c: S, d: S) -> R {
860         unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
861     }
862     pub fn multi(a: S, b: S, c: S, d: S) -> R {
863         unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
864     }
865     pub fn flag(a: S, b: S, c: S) -> R {
866         unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
867     }
868     pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
869         unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
870     }
871     pub fn flagmulti(a: S, b: S, c: S) -> R {
872         unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
873     }
874 }
875
876 /// Returns the "short" subset of the rustc command line options,
877 /// including metadata for each option, such as whether the option is
878 /// part of the stable long-term interface for rustc.
879 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
880     vec![
881         opt::flag_s("h", "help", "Display this message"),
882         opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
883         opt::multi_s(
884             "L",
885             "",
886             "Add a directory to the library search path. The
887                              optional KIND can be one of dependency, crate, native,
888                              framework, or all (the default).",
889             "[KIND=]PATH",
890         ),
891         opt::multi_s(
892             "l",
893             "",
894             "Link the generated crate(s) to the specified native
895                              library NAME. The optional KIND can be one of
896                              static, framework, or dylib (the default).",
897             "[KIND=]NAME",
898         ),
899         make_crate_type_option(),
900         opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
901         opt::opt_s(
902             "",
903             "edition",
904             "Specify which edition of the compiler to use when compiling code.",
905             EDITION_NAME_LIST,
906         ),
907         opt::multi_s(
908             "",
909             "emit",
910             "Comma separated list of types of output for \
911              the compiler to emit",
912             "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
913         ),
914         opt::multi_s(
915             "",
916             "print",
917             "Compiler information to print on stdout",
918             "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
919              target-cpus|target-features|relocation-models|\
920              code-models|tls-models|target-spec-json|native-static-libs]",
921         ),
922         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
923         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
924         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
925         opt::opt_s(
926             "",
927             "out-dir",
928             "Write output to compiler-chosen filename \
929              in <dir>",
930             "DIR",
931         ),
932         opt::opt_s(
933             "",
934             "explain",
935             "Provide a detailed explanation of an error \
936              message",
937             "OPT",
938         ),
939         opt::flag_s("", "test", "Build a test harness"),
940         opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
941         opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
942         opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
943         opt::multi_s("D", "deny", "Set lint denied", "OPT"),
944         opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
945         opt::multi_s(
946             "",
947             "cap-lints",
948             "Set the most restrictive lint level. \
949              More restrictive lints are capped at this \
950              level",
951             "LEVEL",
952         ),
953         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
954         opt::flag_s("V", "version", "Print version info and exit"),
955         opt::flag_s("v", "verbose", "Use verbose output"),
956     ]
957 }
958
959 /// Returns all rustc command line options, including metadata for
960 /// each option, such as whether the option is part of the stable
961 /// long-term interface for rustc.
962 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
963     let mut opts = rustc_short_optgroups();
964     opts.extend(vec![
965         opt::multi_s(
966             "",
967             "extern",
968             "Specify where an external rust library is located",
969             "NAME[=PATH]",
970         ),
971         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
972         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
973         opt::opt_s(
974             "",
975             "error-format",
976             "How errors and other messages are produced",
977             "human|json|short",
978         ),
979         opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
980         opt::opt_s(
981             "",
982             "color",
983             "Configure coloring of output:
984                                  auto   = colorize, if output goes to a tty (default);
985                                  always = always colorize output;
986                                  never  = never colorize output",
987             "auto|always|never",
988         ),
989         opt::opt(
990             "",
991             "pretty",
992             "Pretty-print the input instead of compiling;
993                   valid types are: `normal` (un-annotated source),
994                   `expanded` (crates expanded), or
995                   `expanded,identified` (fully parenthesized, AST nodes with IDs).",
996             "TYPE",
997         ),
998         opt::multi_s(
999             "",
1000             "remap-path-prefix",
1001             "Remap source names in all output (compiler messages and output files)",
1002             "FROM=TO",
1003         ),
1004     ]);
1005     opts
1006 }
1007
1008 pub fn get_cmd_lint_options(
1009     matches: &getopts::Matches,
1010     error_format: ErrorOutputType,
1011 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1012     let mut lint_opts_with_position = vec![];
1013     let mut describe_lints = false;
1014
1015     for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1016         for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1017             let arg_pos = if let lint::Forbid = level {
1018                 // HACK: forbid is always specified last, so it can't be overridden.
1019                 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1020                 // fixed and `forbid` works as expected.
1021                 usize::max_value()
1022             } else {
1023                 passed_arg_pos
1024             };
1025             if lint_name == "help" {
1026                 describe_lints = true;
1027             } else {
1028                 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1029             }
1030         }
1031     }
1032
1033     lint_opts_with_position.sort_by_key(|x| x.0);
1034     let lint_opts = lint_opts_with_position
1035         .iter()
1036         .cloned()
1037         .map(|(_, lint_name, level)| (lint_name, level))
1038         .collect();
1039
1040     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1041         lint::Level::from_str(&cap)
1042             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1043     });
1044     (lint_opts, describe_lints, lint_cap)
1045 }
1046
1047 /// Parses the `--color` flag.
1048 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1049     match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1050         Some("auto") => ColorConfig::Auto,
1051         Some("always") => ColorConfig::Always,
1052         Some("never") => ColorConfig::Never,
1053
1054         None => ColorConfig::Auto,
1055
1056         Some(arg) => early_error(
1057             ErrorOutputType::default(),
1058             &format!(
1059                 "argument for `--color` must be auto, \
1060                  always or never (instead was `{}`)",
1061                 arg
1062             ),
1063         ),
1064     }
1065 }
1066
1067 /// Parse the `--json` flag.
1068 ///
1069 /// The first value returned is how to render JSON diagnostics, and the second
1070 /// is whether or not artifact notifications are enabled.
1071 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1072     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1073         HumanReadableErrorType::Default;
1074     let mut json_color = ColorConfig::Never;
1075     let mut json_artifact_notifications = false;
1076     for option in matches.opt_strs("json") {
1077         // For now conservatively forbid `--color` with `--json` since `--json`
1078         // won't actually be emitting any colors and anything colorized is
1079         // embedded in a diagnostic message anyway.
1080         if matches.opt_str("color").is_some() {
1081             early_error(
1082                 ErrorOutputType::default(),
1083                 "cannot specify the `--color` option with `--json`",
1084             );
1085         }
1086
1087         for sub_option in option.split(',') {
1088             match sub_option {
1089                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1090                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1091                 "artifacts" => json_artifact_notifications = true,
1092                 s => early_error(
1093                     ErrorOutputType::default(),
1094                     &format!("unknown `--json` option `{}`", s),
1095                 ),
1096             }
1097         }
1098     }
1099     (json_rendered(json_color), json_artifact_notifications)
1100 }
1101
1102 /// Parses the `--error-format` flag.
1103 pub fn parse_error_format(
1104     matches: &getopts::Matches,
1105     color: ColorConfig,
1106     json_rendered: HumanReadableErrorType,
1107 ) -> ErrorOutputType {
1108     // We need the `opts_present` check because the driver will send us Matches
1109     // with only stable options if no unstable options are used. Since error-format
1110     // is unstable, it will not be present. We have to use `opts_present` not
1111     // `opt_present` because the latter will panic.
1112     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1113         match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1114             None | Some("human") => {
1115                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1116             }
1117             Some("human-annotate-rs") => {
1118                 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1119             }
1120             Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1121             Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1122             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1123
1124             Some(arg) => early_error(
1125                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1126                 &format!(
1127                     "argument for `--error-format` must be `human`, `json` or \
1128                      `short` (instead was `{}`)",
1129                     arg
1130                 ),
1131             ),
1132         }
1133     } else {
1134         ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1135     };
1136
1137     match error_format {
1138         ErrorOutputType::Json { .. } => {}
1139
1140         // Conservatively require that the `--json` argument is coupled with
1141         // `--error-format=json`. This means that `--json` is specified we
1142         // should actually be emitting JSON blobs.
1143         _ if !matches.opt_strs("json").is_empty() => {
1144             early_error(
1145                 ErrorOutputType::default(),
1146                 "using `--json` requires also using `--error-format=json`",
1147             );
1148         }
1149
1150         _ => {}
1151     }
1152
1153     error_format
1154 }
1155
1156 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1157     let edition = match matches.opt_str("edition") {
1158         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1159             early_error(
1160                 ErrorOutputType::default(),
1161                 &format!(
1162                     "argument for `--edition` must be one of: \
1163                      {}. (instead was `{}`)",
1164                     EDITION_NAME_LIST, arg
1165                 ),
1166             )
1167         }),
1168         None => DEFAULT_EDITION,
1169     };
1170
1171     if !edition.is_stable() && !nightly_options::is_nightly_build() {
1172         early_error(
1173             ErrorOutputType::default(),
1174             &format!(
1175                 "edition {} is unstable and only \
1176                      available for nightly builds of rustc.",
1177                 edition,
1178             ),
1179         )
1180     }
1181
1182     edition
1183 }
1184
1185 fn check_debug_option_stability(
1186     debugging_opts: &DebuggingOptions,
1187     error_format: ErrorOutputType,
1188     json_rendered: HumanReadableErrorType,
1189 ) {
1190     if !debugging_opts.unstable_options {
1191         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1192             early_error(
1193                 ErrorOutputType::Json { pretty: false, json_rendered },
1194                 "`--error-format=pretty-json` is unstable",
1195             );
1196         }
1197         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1198             error_format
1199         {
1200             early_error(
1201                 ErrorOutputType::Json { pretty: false, json_rendered },
1202                 "`--error-format=human-annotate-rs` is unstable",
1203             );
1204         }
1205     }
1206 }
1207
1208 fn parse_output_types(
1209     debugging_opts: &DebuggingOptions,
1210     matches: &getopts::Matches,
1211     error_format: ErrorOutputType,
1212 ) -> OutputTypes {
1213     let mut output_types = BTreeMap::new();
1214     if !debugging_opts.parse_only {
1215         for list in matches.opt_strs("emit") {
1216             for output_type in list.split(',') {
1217                 let mut parts = output_type.splitn(2, '=');
1218                 let shorthand = parts.next().unwrap();
1219                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1220                     early_error(
1221                         error_format,
1222                         &format!(
1223                             "unknown emission type: `{}` - expected one of: {}",
1224                             shorthand,
1225                             OutputType::shorthands_display(),
1226                         ),
1227                     )
1228                 });
1229                 let path = parts.next().map(PathBuf::from);
1230                 output_types.insert(output_type, path);
1231             }
1232         }
1233     };
1234     if output_types.is_empty() {
1235         output_types.insert(OutputType::Exe, None);
1236     }
1237     OutputTypes(output_types)
1238 }
1239
1240 fn should_override_cgus_and_disable_thinlto(
1241     output_types: &OutputTypes,
1242     matches: &getopts::Matches,
1243     error_format: ErrorOutputType,
1244     mut codegen_units: Option<usize>,
1245 ) -> (bool, Option<usize>) {
1246     let mut disable_thinlto = false;
1247     // Issue #30063: if user requests LLVM-related output to one
1248     // particular path, disable codegen-units.
1249     let incompatible: Vec<_> = output_types
1250         .0
1251         .iter()
1252         .map(|ot_path| ot_path.0)
1253         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1254         .map(|ot| ot.shorthand())
1255         .collect();
1256     if !incompatible.is_empty() {
1257         match codegen_units {
1258             Some(n) if n > 1 => {
1259                 if matches.opt_present("o") {
1260                     for ot in &incompatible {
1261                         early_warn(
1262                             error_format,
1263                             &format!(
1264                                 "`--emit={}` with `-o` incompatible with \
1265                                  `-C codegen-units=N` for N > 1",
1266                                 ot
1267                             ),
1268                         );
1269                     }
1270                     early_warn(error_format, "resetting to default -C codegen-units=1");
1271                     codegen_units = Some(1);
1272                     disable_thinlto = true;
1273                 }
1274             }
1275             _ => {
1276                 codegen_units = Some(1);
1277                 disable_thinlto = true;
1278             }
1279         }
1280     }
1281
1282     if codegen_units == Some(0) {
1283         early_error(error_format, "value for codegen units must be a positive non-zero integer");
1284     }
1285
1286     (disable_thinlto, codegen_units)
1287 }
1288
1289 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1290     if debugging_opts.threads == 0 {
1291         early_error(error_format, "value for threads must be a positive non-zero integer");
1292     }
1293
1294     if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1295         early_error(error_format, "optimization fuel is incompatible with multiple threads");
1296     }
1297 }
1298
1299 fn collect_print_requests(
1300     cg: &mut CodegenOptions,
1301     dopts: &mut DebuggingOptions,
1302     matches: &getopts::Matches,
1303     error_format: ErrorOutputType,
1304 ) -> Vec<PrintRequest> {
1305     let mut prints = Vec::<PrintRequest>::new();
1306     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1307         prints.push(PrintRequest::TargetCPUs);
1308         cg.target_cpu = None;
1309     };
1310     if cg.target_feature == "help" {
1311         prints.push(PrintRequest::TargetFeatures);
1312         cg.target_feature = String::new();
1313     }
1314     if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1315         prints.push(PrintRequest::CodeModels);
1316         cg.code_model = None;
1317     }
1318
1319     prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1320         "crate-name" => PrintRequest::CrateName,
1321         "file-names" => PrintRequest::FileNames,
1322         "sysroot" => PrintRequest::Sysroot,
1323         "target-libdir" => PrintRequest::TargetLibdir,
1324         "cfg" => PrintRequest::Cfg,
1325         "target-list" => PrintRequest::TargetList,
1326         "target-cpus" => PrintRequest::TargetCPUs,
1327         "target-features" => PrintRequest::TargetFeatures,
1328         "relocation-models" => PrintRequest::RelocationModels,
1329         "code-models" => PrintRequest::CodeModels,
1330         "tls-models" => PrintRequest::TlsModels,
1331         "native-static-libs" => PrintRequest::NativeStaticLibs,
1332         "target-spec-json" => {
1333             if dopts.unstable_options {
1334                 PrintRequest::TargetSpec
1335             } else {
1336                 early_error(
1337                     error_format,
1338                     "the `-Z unstable-options` flag must also be passed to \
1339                      enable the target-spec-json print option",
1340                 );
1341             }
1342         }
1343         req => early_error(error_format, &format!("unknown print request `{}`", req)),
1344     }));
1345
1346     prints
1347 }
1348
1349 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1350     match matches.opt_str("target") {
1351         Some(target) if target.ends_with(".json") => {
1352             let path = Path::new(&target);
1353             TargetTriple::from_path(&path).unwrap_or_else(|_| {
1354                 early_error(error_format, &format!("target file {:?} does not exist", path))
1355             })
1356         }
1357         Some(target) => TargetTriple::TargetTriple(target),
1358         _ => TargetTriple::from_triple(host_triple()),
1359     }
1360 }
1361
1362 fn parse_opt_level(
1363     matches: &getopts::Matches,
1364     cg: &CodegenOptions,
1365     error_format: ErrorOutputType,
1366 ) -> OptLevel {
1367     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1368     // to use them interchangeably. However, because they're technically different flags,
1369     // we need to work out manually which should take precedence if both are supplied (i.e.
1370     // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1371     // comparing them. Note that if a flag is not found, its position will be `None`, which
1372     // always compared less than `Some(_)`.
1373     let max_o = matches.opt_positions("O").into_iter().max();
1374     let max_c = matches
1375         .opt_strs_pos("C")
1376         .into_iter()
1377         .flat_map(
1378             |(i, s)| {
1379                 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1380             },
1381         )
1382         .max();
1383     if max_o > max_c {
1384         OptLevel::Default
1385     } else {
1386         match cg.opt_level.as_ref() {
1387             "0" => OptLevel::No,
1388             "1" => OptLevel::Less,
1389             "2" => OptLevel::Default,
1390             "3" => OptLevel::Aggressive,
1391             "s" => OptLevel::Size,
1392             "z" => OptLevel::SizeMin,
1393             arg => {
1394                 early_error(
1395                     error_format,
1396                     &format!(
1397                         "optimization level needs to be \
1398                             between 0-3, s or z (instead was `{}`)",
1399                         arg
1400                     ),
1401                 );
1402             }
1403         }
1404     }
1405 }
1406
1407 fn select_debuginfo(
1408     matches: &getopts::Matches,
1409     cg: &CodegenOptions,
1410     error_format: ErrorOutputType,
1411 ) -> DebugInfo {
1412     let max_g = matches.opt_positions("g").into_iter().max();
1413     let max_c = matches
1414         .opt_strs_pos("C")
1415         .into_iter()
1416         .flat_map(
1417             |(i, s)| {
1418                 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1419             },
1420         )
1421         .max();
1422     if max_g > max_c {
1423         DebugInfo::Full
1424     } else {
1425         match cg.debuginfo {
1426             0 => DebugInfo::None,
1427             1 => DebugInfo::Limited,
1428             2 => DebugInfo::Full,
1429             arg => {
1430                 early_error(
1431                     error_format,
1432                     &format!(
1433                         "debug info level needs to be between \
1434                          0-2 (instead was `{}`)",
1435                         arg
1436                     ),
1437                 );
1438             }
1439         }
1440     }
1441 }
1442
1443 fn parse_libs(
1444     matches: &getopts::Matches,
1445     error_format: ErrorOutputType,
1446 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1447     matches
1448         .opt_strs("l")
1449         .into_iter()
1450         .map(|s| {
1451             // Parse string of the form "[KIND=]lib[:new_name]",
1452             // where KIND is one of "dylib", "framework", "static".
1453             let mut parts = s.splitn(2, '=');
1454             let kind = parts.next().unwrap();
1455             let (name, kind) = match (parts.next(), kind) {
1456                 (None, name) => (name, None),
1457                 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1458                 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1459                 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1460                 (Some(name), "static-nobundle") => {
1461                     (name, Some(NativeLibraryKind::NativeStaticNobundle))
1462                 }
1463                 (_, s) => {
1464                     early_error(
1465                         error_format,
1466                         &format!(
1467                             "unknown library kind `{}`, expected \
1468                              one of dylib, framework, or static",
1469                             s
1470                         ),
1471                     );
1472                 }
1473             };
1474             if kind == Some(NativeLibraryKind::NativeStaticNobundle)
1475                 && !nightly_options::is_nightly_build()
1476             {
1477                 early_error(
1478                     error_format,
1479                     "the library kind 'static-nobundle' is only \
1480                      accepted on the nightly compiler",
1481                 );
1482             }
1483             let mut name_parts = name.splitn(2, ':');
1484             let name = name_parts.next().unwrap();
1485             let new_name = name_parts.next();
1486             (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1487         })
1488         .collect()
1489 }
1490
1491 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1492     match dopts.borrowck.as_ref() {
1493         "migrate" => BorrowckMode::Migrate,
1494         "mir" => BorrowckMode::Mir,
1495         m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1496     }
1497 }
1498
1499 pub fn parse_externs(
1500     matches: &getopts::Matches,
1501     debugging_opts: &DebuggingOptions,
1502     error_format: ErrorOutputType,
1503 ) -> Externs {
1504     let is_unstable_enabled = debugging_opts.unstable_options;
1505     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1506     for arg in matches.opt_strs("extern") {
1507         let mut parts = arg.splitn(2, '=');
1508         let name = parts
1509             .next()
1510             .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1511         let path = parts.next().map(|s| s.to_string());
1512
1513         let mut name_parts = name.splitn(2, ':');
1514         let first_part = name_parts.next();
1515         let second_part = name_parts.next();
1516         let (options, name) = match (first_part, second_part) {
1517             (Some(opts), Some(name)) => (Some(opts), name),
1518             (Some(name), None) => (None, name),
1519             (None, None) => early_error(error_format, "--extern name must not be empty"),
1520             _ => unreachable!(),
1521         };
1522
1523         let entry = externs.entry(name.to_owned());
1524
1525         use std::collections::btree_map::Entry;
1526
1527         let entry = if let Some(path) = path {
1528             // --extern prelude_name=some_file.rlib
1529             match entry {
1530                 Entry::Vacant(vacant) => {
1531                     let files = BTreeSet::from_iter(iter::once(path));
1532                     vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1533                 }
1534                 Entry::Occupied(occupied) => {
1535                     let ext_ent = occupied.into_mut();
1536                     match ext_ent {
1537                         ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1538                             files.insert(path);
1539                         }
1540                         ExternEntry {
1541                             location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1542                             ..
1543                         } => {
1544                             // Exact paths take precedence over search directories.
1545                             let files = BTreeSet::from_iter(iter::once(path));
1546                             *location = ExternLocation::ExactPaths(files);
1547                         }
1548                     }
1549                     ext_ent
1550                 }
1551             }
1552         } else {
1553             // --extern prelude_name
1554             match entry {
1555                 Entry::Vacant(vacant) => {
1556                     vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1557                 }
1558                 Entry::Occupied(occupied) => {
1559                     // Ignore if already specified.
1560                     occupied.into_mut()
1561                 }
1562             }
1563         };
1564
1565         let mut is_private_dep = false;
1566         let mut add_prelude = true;
1567         if let Some(opts) = options {
1568             if !is_unstable_enabled {
1569                 early_error(
1570                     error_format,
1571                     "the `-Z unstable-options` flag must also be passed to \
1572                      enable `--extern options",
1573                 );
1574             }
1575             for opt in opts.split(',') {
1576                 match opt {
1577                     "priv" => is_private_dep = true,
1578                     "noprelude" => {
1579                         if let ExternLocation::ExactPaths(_) = &entry.location {
1580                             add_prelude = false;
1581                         } else {
1582                             early_error(
1583                                 error_format,
1584                                 "the `noprelude` --extern option requires a file path",
1585                             );
1586                         }
1587                     }
1588                     _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1589                 }
1590             }
1591         }
1592
1593         // Crates start out being not private, and go to being private `priv`
1594         // is specified.
1595         entry.is_private_dep |= is_private_dep;
1596         // If any flag is missing `noprelude`, then add to the prelude.
1597         entry.add_prelude |= add_prelude;
1598     }
1599     Externs(externs)
1600 }
1601
1602 fn parse_remap_path_prefix(
1603     matches: &getopts::Matches,
1604     error_format: ErrorOutputType,
1605 ) -> Vec<(PathBuf, PathBuf)> {
1606     matches
1607         .opt_strs("remap-path-prefix")
1608         .into_iter()
1609         .map(|remap| {
1610             let mut parts = remap.rsplitn(2, '='); // reverse iterator
1611             let to = parts.next();
1612             let from = parts.next();
1613             match (from, to) {
1614                 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1615                 _ => early_error(
1616                     error_format,
1617                     "--remap-path-prefix must contain '=' between FROM and TO",
1618                 ),
1619             }
1620         })
1621         .collect()
1622 }
1623
1624 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1625     let color = parse_color(matches);
1626
1627     let edition = parse_crate_edition(matches);
1628
1629     let (json_rendered, json_artifact_notifications) = parse_json(matches);
1630
1631     let error_format = parse_error_format(matches, color, json_rendered);
1632
1633     let unparsed_crate_types = matches.opt_strs("crate-type");
1634     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1635         .unwrap_or_else(|e| early_error(error_format, &e[..]));
1636
1637     let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1638
1639     let mut debugging_opts = build_debugging_options(matches, error_format);
1640     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1641
1642     let output_types = parse_output_types(&debugging_opts, matches, error_format);
1643
1644     let mut cg = build_codegen_options(matches, error_format);
1645     let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1646         &output_types,
1647         matches,
1648         error_format,
1649         cg.codegen_units,
1650     );
1651
1652     check_thread_count(&debugging_opts, error_format);
1653
1654     let incremental = cg.incremental.as_ref().map(PathBuf::from);
1655
1656     if debugging_opts.profile && incremental.is_some() {
1657         early_error(
1658             error_format,
1659             "can't instrument with gcov profiling when compiling incrementally",
1660         );
1661     }
1662     if debugging_opts.profile {
1663         match codegen_units {
1664             Some(1) => {}
1665             None => codegen_units = Some(1),
1666             Some(_) => early_error(
1667                 error_format,
1668                 "can't instrument with gcov profiling with multiple codegen units",
1669             ),
1670         }
1671     }
1672
1673     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1674         early_error(
1675             error_format,
1676             "options `-C profile-generate` and `-C profile-use` are exclusive",
1677         );
1678     }
1679
1680     if !cg.bitcode_in_rlib {
1681         match cg.lto {
1682             LtoCli::No | LtoCli::Unspecified => {}
1683             LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1684                 error_format,
1685                 "options `-C bitcode-in-rlib=no` and `-C lto` are incompatible",
1686             ),
1687         }
1688     }
1689
1690     let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1691
1692     let cg = cg;
1693
1694     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1695     let target_triple = parse_target_triple(matches, error_format);
1696     let opt_level = parse_opt_level(matches, &cg, error_format);
1697     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1698     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1699     // for more details.
1700     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1701     let debuginfo = select_debuginfo(matches, &cg, error_format);
1702
1703     let mut search_paths = vec![];
1704     for s in &matches.opt_strs("L") {
1705         search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1706     }
1707
1708     let libs = parse_libs(matches, error_format);
1709
1710     let test = matches.opt_present("test");
1711
1712     let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1713
1714     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1715         early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1716     }
1717
1718     let externs = parse_externs(matches, &debugging_opts, error_format);
1719
1720     let crate_name = matches.opt_str("crate-name");
1721
1722     let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1723
1724     let pretty = parse_pretty(matches, &debugging_opts, error_format);
1725
1726     Options {
1727         crate_types,
1728         optimize: opt_level,
1729         debuginfo,
1730         lint_opts,
1731         lint_cap,
1732         describe_lints,
1733         output_types,
1734         search_paths,
1735         maybe_sysroot: sysroot_opt,
1736         target_triple,
1737         test,
1738         incremental,
1739         debugging_opts,
1740         prints,
1741         borrowck_mode,
1742         cg,
1743         error_format,
1744         externs,
1745         crate_name,
1746         alt_std_name: None,
1747         libs,
1748         unstable_features: UnstableFeatures::from_environment(),
1749         debug_assertions,
1750         actually_rustdoc: false,
1751         cli_forced_codegen_units: codegen_units,
1752         cli_forced_thinlto_off: disable_thinlto,
1753         remap_path_prefix,
1754         edition,
1755         json_artifact_notifications,
1756         pretty,
1757     }
1758 }
1759
1760 fn parse_pretty(
1761     matches: &getopts::Matches,
1762     debugging_opts: &DebuggingOptions,
1763     efmt: ErrorOutputType,
1764 ) -> Option<PpMode> {
1765     let pretty = if debugging_opts.unstable_options {
1766         matches.opt_default("pretty", "normal").map(|a| {
1767             // stable pretty-print variants only
1768             parse_pretty_inner(efmt, &a, false)
1769         })
1770     } else {
1771         None
1772     };
1773
1774     return if pretty.is_none() {
1775         debugging_opts.unpretty.as_ref().map(|a| {
1776             // extended with unstable pretty-print variants
1777             parse_pretty_inner(efmt, &a, true)
1778         })
1779     } else {
1780         pretty
1781     };
1782
1783     fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1784         use PpMode::*;
1785         use PpSourceMode::*;
1786         let first = match (name, extended) {
1787             ("normal", _) => PpmSource(PpmNormal),
1788             ("identified", _) => PpmSource(PpmIdentified),
1789             ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1790             ("expanded", _) => PpmSource(PpmExpanded),
1791             ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1792             ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1793             ("hir", true) => PpmHir(PpmNormal),
1794             ("hir,identified", true) => PpmHir(PpmIdentified),
1795             ("hir,typed", true) => PpmHir(PpmTyped),
1796             ("hir-tree", true) => PpmHirTree(PpmNormal),
1797             ("mir", true) => PpmMir,
1798             ("mir-cfg", true) => PpmMirCFG,
1799             _ => {
1800                 if extended {
1801                     early_error(
1802                         efmt,
1803                         &format!(
1804                             "argument to `unpretty` must be one of `normal`, \
1805                                         `expanded`, `identified`, `expanded,identified`, \
1806                                         `expanded,hygiene`, `everybody_loops`, \
1807                                         `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1808                                         `mir` or `mir-cfg`; got {}",
1809                             name
1810                         ),
1811                     );
1812                 } else {
1813                     early_error(
1814                         efmt,
1815                         &format!(
1816                             "argument to `pretty` must be one of `normal`, \
1817                                         `expanded`, `identified`, or `expanded,identified`; got {}",
1818                             name
1819                         ),
1820                     );
1821                 }
1822             }
1823         };
1824         first
1825     }
1826 }
1827
1828 pub fn make_crate_type_option() -> RustcOptGroup {
1829     opt::multi_s(
1830         "",
1831         "crate-type",
1832         "Comma separated list of types of crates
1833                                 for the compiler to emit",
1834         "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1835     )
1836 }
1837
1838 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1839     let mut crate_types: Vec<CrateType> = Vec::new();
1840     for unparsed_crate_type in &list_list {
1841         for part in unparsed_crate_type.split(',') {
1842             let new_part = match part {
1843                 "lib" => default_lib_output(),
1844                 "rlib" => CrateType::Rlib,
1845                 "staticlib" => CrateType::Staticlib,
1846                 "dylib" => CrateType::Dylib,
1847                 "cdylib" => CrateType::Cdylib,
1848                 "bin" => CrateType::Executable,
1849                 "proc-macro" => CrateType::ProcMacro,
1850                 _ => return Err(format!("unknown crate type: `{}`", part)),
1851             };
1852             if !crate_types.contains(&new_part) {
1853                 crate_types.push(new_part)
1854             }
1855         }
1856     }
1857
1858     Ok(crate_types)
1859 }
1860
1861 pub mod nightly_options {
1862     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1863     use crate::early_error;
1864     use rustc_feature::UnstableFeatures;
1865
1866     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1867         is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1868     }
1869
1870     pub fn is_nightly_build() -> bool {
1871         UnstableFeatures::from_environment().is_nightly_build()
1872     }
1873
1874     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1875         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1876         let really_allows_unstable_options =
1877             UnstableFeatures::from_environment().is_nightly_build();
1878
1879         for opt in flags.iter() {
1880             if opt.stability == OptionStability::Stable {
1881                 continue;
1882             }
1883             if !matches.opt_present(opt.name) {
1884                 continue;
1885             }
1886             if opt.name != "Z" && !has_z_unstable_option {
1887                 early_error(
1888                     ErrorOutputType::default(),
1889                     &format!(
1890                         "the `-Z unstable-options` flag must also be passed to enable \
1891                          the flag `{}`",
1892                         opt.name
1893                     ),
1894                 );
1895             }
1896             if really_allows_unstable_options {
1897                 continue;
1898             }
1899             match opt.stability {
1900                 OptionStability::Unstable => {
1901                     let msg = format!(
1902                         "the option `{}` is only accepted on the \
1903                          nightly compiler",
1904                         opt.name
1905                     );
1906                     early_error(ErrorOutputType::default(), &msg);
1907                 }
1908                 OptionStability::Stable => {}
1909             }
1910         }
1911     }
1912 }
1913
1914 impl fmt::Display for CrateType {
1915     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1916         match *self {
1917             CrateType::Executable => "bin".fmt(f),
1918             CrateType::Dylib => "dylib".fmt(f),
1919             CrateType::Rlib => "rlib".fmt(f),
1920             CrateType::Staticlib => "staticlib".fmt(f),
1921             CrateType::Cdylib => "cdylib".fmt(f),
1922             CrateType::ProcMacro => "proc-macro".fmt(f),
1923         }
1924     }
1925 }
1926
1927 #[derive(Copy, Clone, PartialEq, Debug)]
1928 pub enum PpSourceMode {
1929     PpmNormal,
1930     PpmEveryBodyLoops,
1931     PpmExpanded,
1932     PpmIdentified,
1933     PpmExpandedIdentified,
1934     PpmExpandedHygiene,
1935     PpmTyped,
1936 }
1937
1938 #[derive(Copy, Clone, PartialEq, Debug)]
1939 pub enum PpMode {
1940     PpmSource(PpSourceMode),
1941     PpmHir(PpSourceMode),
1942     PpmHirTree(PpSourceMode),
1943     PpmMir,
1944     PpmMirCFG,
1945 }
1946
1947 impl PpMode {
1948     pub fn needs_ast_map(&self) -> bool {
1949         use PpMode::*;
1950         use PpSourceMode::*;
1951         match *self {
1952             PpmSource(PpmNormal | PpmEveryBodyLoops | PpmIdentified) => false,
1953
1954             PpmSource(PpmExpanded | PpmExpandedIdentified | 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, SourceFileHashAlgorithm, SwitchWithOptPath,
1994         SymbolManglingVersion,
1995     };
1996     use crate::lint;
1997     use crate::utils::NativeLibraryKind;
1998     use rustc_feature::UnstableFeatures;
1999     use rustc_span::edition::Edition;
2000     use rustc_target::spec::{MergeFunctions, PanicStrategy, RelocModel};
2001     use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
2002     use std::collections::hash_map::DefaultHasher;
2003     use std::collections::BTreeMap;
2004     use std::hash::Hash;
2005     use std::path::PathBuf;
2006
2007     pub trait DepTrackingHash {
2008         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2009     }
2010
2011     macro_rules! impl_dep_tracking_hash_via_hash {
2012         ($t:ty) => {
2013             impl DepTrackingHash for $t {
2014                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2015                     Hash::hash(self, hasher);
2016                 }
2017             }
2018         };
2019     }
2020
2021     macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2022         ($t:ty) => {
2023             impl DepTrackingHash for Vec<$t> {
2024                 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2025                     let mut elems: Vec<&$t> = self.iter().collect();
2026                     elems.sort();
2027                     Hash::hash(&elems.len(), hasher);
2028                     for (index, elem) in elems.iter().enumerate() {
2029                         Hash::hash(&index, hasher);
2030                         DepTrackingHash::hash(*elem, hasher, error_format);
2031                     }
2032                 }
2033             }
2034         };
2035     }
2036
2037     impl_dep_tracking_hash_via_hash!(bool);
2038     impl_dep_tracking_hash_via_hash!(usize);
2039     impl_dep_tracking_hash_via_hash!(u64);
2040     impl_dep_tracking_hash_via_hash!(String);
2041     impl_dep_tracking_hash_via_hash!(PathBuf);
2042     impl_dep_tracking_hash_via_hash!(lint::Level);
2043     impl_dep_tracking_hash_via_hash!(Option<bool>);
2044     impl_dep_tracking_hash_via_hash!(Option<usize>);
2045     impl_dep_tracking_hash_via_hash!(Option<String>);
2046     impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2047     impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2048     impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2049     impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2050     impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2051     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2052     impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2053     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2054     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2055     impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2056     impl_dep_tracking_hash_via_hash!(CrateType);
2057     impl_dep_tracking_hash_via_hash!(MergeFunctions);
2058     impl_dep_tracking_hash_via_hash!(PanicStrategy);
2059     impl_dep_tracking_hash_via_hash!(RelroLevel);
2060     impl_dep_tracking_hash_via_hash!(Passes);
2061     impl_dep_tracking_hash_via_hash!(OptLevel);
2062     impl_dep_tracking_hash_via_hash!(LtoCli);
2063     impl_dep_tracking_hash_via_hash!(DebugInfo);
2064     impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2065     impl_dep_tracking_hash_via_hash!(OutputTypes);
2066     impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2067     impl_dep_tracking_hash_via_hash!(Sanitizer);
2068     impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2069     impl_dep_tracking_hash_via_hash!(CFGuard);
2070     impl_dep_tracking_hash_via_hash!(TargetTriple);
2071     impl_dep_tracking_hash_via_hash!(Edition);
2072     impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2073     impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2074     impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2075     impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2076
2077     impl_dep_tracking_hash_for_sortable_vec_of!(String);
2078     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2079     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2080     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2081     impl_dep_tracking_hash_for_sortable_vec_of!((
2082         String,
2083         Option<String>,
2084         Option<NativeLibraryKind>
2085     ));
2086     impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2087     impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2088
2089     impl<T1, T2> DepTrackingHash for (T1, T2)
2090     where
2091         T1: DepTrackingHash,
2092         T2: DepTrackingHash,
2093     {
2094         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2095             Hash::hash(&0, hasher);
2096             DepTrackingHash::hash(&self.0, hasher, error_format);
2097             Hash::hash(&1, hasher);
2098             DepTrackingHash::hash(&self.1, hasher, error_format);
2099         }
2100     }
2101
2102     impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2103     where
2104         T1: DepTrackingHash,
2105         T2: DepTrackingHash,
2106         T3: DepTrackingHash,
2107     {
2108         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2109             Hash::hash(&0, hasher);
2110             DepTrackingHash::hash(&self.0, hasher, error_format);
2111             Hash::hash(&1, hasher);
2112             DepTrackingHash::hash(&self.1, hasher, error_format);
2113             Hash::hash(&2, hasher);
2114             DepTrackingHash::hash(&self.2, hasher, error_format);
2115         }
2116     }
2117
2118     // This is a stable hash because BTreeMap is a sorted container
2119     pub fn stable_hash(
2120         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2121         hasher: &mut DefaultHasher,
2122         error_format: ErrorOutputType,
2123     ) {
2124         for (key, sub_hash) in sub_hashes {
2125             // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2126             // the keys, as they are just plain strings
2127             Hash::hash(&key.len(), hasher);
2128             Hash::hash(key, hasher);
2129             sub_hash.hash(hasher, error_format);
2130         }
2131     }
2132 }