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