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