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