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