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