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