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