]> git.lizzy.rs Git - rust.git/blob - src/librustc_session/config.rs
Rollup merge of #75485 - RalfJung:pin, r=nagisa
[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, 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:
1722         //   * `-Z symbol-mangling-version=v0` - to ensure consistent and reversible name mangling.
1723         //     Note, LLVM coverage tools can analyze coverage over multiple runs, including some
1724         //     changes to source code; so mangled names must be consistent across compilations.
1725         //   * `-C link-dead-code` - so unexecuted code is still counted as zero, rather than be
1726         //     optimized out. Note that instrumenting dead code can be explicitly disabled with:
1727         //         `-Z instrument-coverage -C link-dead-code=no`.
1728         debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0;
1729         if cg.link_dead_code == None {
1730             // FIXME(richkadel): Investigate if the `instrument-coverage` implementation can
1731             // inject ["zero counters"](https://llvm.org/docs/CoverageMappingFormat.html#counter)
1732             // in the coverage map when "dead code" is removed, rather than forcing `link-dead-code`.
1733             cg.link_dead_code = Some(true);
1734         }
1735     }
1736
1737     if !cg.embed_bitcode {
1738         match cg.lto {
1739             LtoCli::No | LtoCli::Unspecified => {}
1740             LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1741                 error_format,
1742                 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1743             ),
1744         }
1745     }
1746
1747     let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1748
1749     let cg = cg;
1750
1751     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1752     let target_triple = parse_target_triple(matches, error_format);
1753     let opt_level = parse_opt_level(matches, &cg, error_format);
1754     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1755     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1756     // for more details.
1757     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1758     let debuginfo = select_debuginfo(matches, &cg, error_format);
1759
1760     let mut search_paths = vec![];
1761     for s in &matches.opt_strs("L") {
1762         search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1763     }
1764
1765     let libs = parse_libs(matches, error_format);
1766
1767     let test = matches.opt_present("test");
1768
1769     let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1770
1771     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1772         early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1773     }
1774
1775     let externs = parse_externs(matches, &debugging_opts, error_format);
1776
1777     let crate_name = matches.opt_str("crate-name");
1778
1779     let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1780
1781     let pretty = parse_pretty(matches, &debugging_opts, error_format);
1782
1783     Options {
1784         crate_types,
1785         optimize: opt_level,
1786         debuginfo,
1787         lint_opts,
1788         lint_cap,
1789         describe_lints,
1790         output_types,
1791         search_paths,
1792         maybe_sysroot: sysroot_opt,
1793         target_triple,
1794         test,
1795         incremental,
1796         debugging_opts,
1797         prints,
1798         borrowck_mode,
1799         cg,
1800         error_format,
1801         externs,
1802         crate_name,
1803         alt_std_name: None,
1804         libs,
1805         unstable_features: UnstableFeatures::from_environment(),
1806         debug_assertions,
1807         actually_rustdoc: false,
1808         cli_forced_codegen_units: codegen_units,
1809         cli_forced_thinlto_off: disable_thinlto,
1810         remap_path_prefix,
1811         edition,
1812         json_artifact_notifications,
1813         pretty,
1814     }
1815 }
1816
1817 fn parse_pretty(
1818     matches: &getopts::Matches,
1819     debugging_opts: &DebuggingOptions,
1820     efmt: ErrorOutputType,
1821 ) -> Option<PpMode> {
1822     let pretty = if debugging_opts.unstable_options {
1823         matches.opt_default("pretty", "normal").map(|a| {
1824             // stable pretty-print variants only
1825             parse_pretty_inner(efmt, &a, false)
1826         })
1827     } else {
1828         None
1829     };
1830
1831     return if pretty.is_none() {
1832         debugging_opts.unpretty.as_ref().map(|a| {
1833             // extended with unstable pretty-print variants
1834             parse_pretty_inner(efmt, &a, true)
1835         })
1836     } else {
1837         pretty
1838     };
1839
1840     fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1841         use PpMode::*;
1842         use PpSourceMode::*;
1843         let first = match (name, extended) {
1844             ("normal", _) => PpmSource(PpmNormal),
1845             ("identified", _) => PpmSource(PpmIdentified),
1846             ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1847             ("expanded", _) => PpmSource(PpmExpanded),
1848             ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1849             ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1850             ("hir", true) => PpmHir(PpmNormal),
1851             ("hir,identified", true) => PpmHir(PpmIdentified),
1852             ("hir,typed", true) => PpmHir(PpmTyped),
1853             ("hir-tree", true) => PpmHirTree(PpmNormal),
1854             ("mir", true) => PpmMir,
1855             ("mir-cfg", true) => PpmMirCFG,
1856             _ => {
1857                 if extended {
1858                     early_error(
1859                         efmt,
1860                         &format!(
1861                             "argument to `unpretty` must be one of `normal`, \
1862                                         `expanded`, `identified`, `expanded,identified`, \
1863                                         `expanded,hygiene`, `everybody_loops`, \
1864                                         `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1865                                         `mir` or `mir-cfg`; got {}",
1866                             name
1867                         ),
1868                     );
1869                 } else {
1870                     early_error(
1871                         efmt,
1872                         &format!(
1873                             "argument to `pretty` must be one of `normal`, \
1874                                         `expanded`, `identified`, or `expanded,identified`; got {}",
1875                             name
1876                         ),
1877                     );
1878                 }
1879             }
1880         };
1881         tracing::debug!("got unpretty option: {:?}", first);
1882         first
1883     }
1884 }
1885
1886 pub fn make_crate_type_option() -> RustcOptGroup {
1887     opt::multi_s(
1888         "",
1889         "crate-type",
1890         "Comma separated list of types of crates
1891                                 for the compiler to emit",
1892         "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1893     )
1894 }
1895
1896 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1897     let mut crate_types: Vec<CrateType> = Vec::new();
1898     for unparsed_crate_type in &list_list {
1899         for part in unparsed_crate_type.split(',') {
1900             let new_part = match part {
1901                 "lib" => default_lib_output(),
1902                 "rlib" => CrateType::Rlib,
1903                 "staticlib" => CrateType::Staticlib,
1904                 "dylib" => CrateType::Dylib,
1905                 "cdylib" => CrateType::Cdylib,
1906                 "bin" => CrateType::Executable,
1907                 "proc-macro" => CrateType::ProcMacro,
1908                 _ => return Err(format!("unknown crate type: `{}`", part)),
1909             };
1910             if !crate_types.contains(&new_part) {
1911                 crate_types.push(new_part)
1912             }
1913         }
1914     }
1915
1916     Ok(crate_types)
1917 }
1918
1919 pub mod nightly_options {
1920     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1921     use crate::early_error;
1922     use rustc_feature::UnstableFeatures;
1923
1924     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1925         is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1926     }
1927
1928     pub fn is_nightly_build() -> bool {
1929         UnstableFeatures::from_environment().is_nightly_build()
1930     }
1931
1932     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1933         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1934         let really_allows_unstable_options =
1935             UnstableFeatures::from_environment().is_nightly_build();
1936
1937         for opt in flags.iter() {
1938             if opt.stability == OptionStability::Stable {
1939                 continue;
1940             }
1941             if !matches.opt_present(opt.name) {
1942                 continue;
1943             }
1944             if opt.name != "Z" && !has_z_unstable_option {
1945                 early_error(
1946                     ErrorOutputType::default(),
1947                     &format!(
1948                         "the `-Z unstable-options` flag must also be passed to enable \
1949                          the flag `{}`",
1950                         opt.name
1951                     ),
1952                 );
1953             }
1954             if really_allows_unstable_options {
1955                 continue;
1956             }
1957             match opt.stability {
1958                 OptionStability::Unstable => {
1959                     let msg = format!(
1960                         "the option `{}` is only accepted on the \
1961                          nightly compiler",
1962                         opt.name
1963                     );
1964                     early_error(ErrorOutputType::default(), &msg);
1965                 }
1966                 OptionStability::Stable => {}
1967             }
1968         }
1969     }
1970 }
1971
1972 impl fmt::Display for CrateType {
1973     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1974         match *self {
1975             CrateType::Executable => "bin".fmt(f),
1976             CrateType::Dylib => "dylib".fmt(f),
1977             CrateType::Rlib => "rlib".fmt(f),
1978             CrateType::Staticlib => "staticlib".fmt(f),
1979             CrateType::Cdylib => "cdylib".fmt(f),
1980             CrateType::ProcMacro => "proc-macro".fmt(f),
1981         }
1982     }
1983 }
1984
1985 #[derive(Copy, Clone, PartialEq, Debug)]
1986 pub enum PpSourceMode {
1987     PpmNormal,
1988     PpmEveryBodyLoops,
1989     PpmExpanded,
1990     PpmIdentified,
1991     PpmExpandedIdentified,
1992     PpmExpandedHygiene,
1993     PpmTyped,
1994 }
1995
1996 #[derive(Copy, Clone, PartialEq, Debug)]
1997 pub enum PpMode {
1998     PpmSource(PpSourceMode),
1999     PpmHir(PpSourceMode),
2000     PpmHirTree(PpSourceMode),
2001     PpmMir,
2002     PpmMirCFG,
2003 }
2004
2005 impl PpMode {
2006     pub fn needs_ast_map(&self) -> bool {
2007         use PpMode::*;
2008         use PpSourceMode::*;
2009         match *self {
2010             PpmSource(PpmNormal | PpmIdentified) => false,
2011
2012             PpmSource(
2013                 PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene,
2014             )
2015             | PpmHir(_)
2016             | PpmHirTree(_)
2017             | PpmMir
2018             | PpmMirCFG => true,
2019             PpmSource(PpmTyped) => panic!("invalid state"),
2020         }
2021     }
2022
2023     pub fn needs_analysis(&self) -> bool {
2024         use PpMode::*;
2025         match *self {
2026             PpmMir | PpmMirCFG => true,
2027             _ => false,
2028         }
2029     }
2030 }
2031
2032 /// Command-line arguments passed to the compiler have to be incorporated with
2033 /// the dependency tracking system for incremental compilation. This module
2034 /// provides some utilities to make this more convenient.
2035 ///
2036 /// The values of all command-line arguments that are relevant for dependency
2037 /// tracking are hashed into a single value that determines whether the
2038 /// incremental compilation cache can be re-used or not. This hashing is done
2039 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2040 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2041 /// the hash of which is order dependent, but we might not want the order of
2042 /// arguments to make a difference for the hash).
2043 ///
2044 /// However, since the value provided by `Hash::hash` often *is* suitable,
2045 /// especially for primitive types, there is the
2046 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2047 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2048 /// we have an opt-in scheme here, so one is hopefully forced to think about
2049 /// how the hash should be calculated when adding a new command-line argument.
2050 crate mod dep_tracking {
2051     use super::{
2052         CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
2053         OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
2054         SymbolManglingVersion,
2055     };
2056     use crate::lint;
2057     use crate::utils::NativeLibKind;
2058     use rustc_feature::UnstableFeatures;
2059     use rustc_span::edition::Edition;
2060     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2061     use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
2062     use std::collections::hash_map::DefaultHasher;
2063     use std::collections::BTreeMap;
2064     use std::hash::Hash;
2065     use std::path::PathBuf;
2066
2067     pub trait DepTrackingHash {
2068         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2069     }
2070
2071     macro_rules! impl_dep_tracking_hash_via_hash {
2072         ($t:ty) => {
2073             impl DepTrackingHash for $t {
2074                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2075                     Hash::hash(self, hasher);
2076                 }
2077             }
2078         };
2079     }
2080
2081     macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2082         ($t:ty) => {
2083             impl DepTrackingHash for Vec<$t> {
2084                 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2085                     let mut elems: Vec<&$t> = self.iter().collect();
2086                     elems.sort();
2087                     Hash::hash(&elems.len(), hasher);
2088                     for (index, elem) in elems.iter().enumerate() {
2089                         Hash::hash(&index, hasher);
2090                         DepTrackingHash::hash(*elem, hasher, error_format);
2091                     }
2092                 }
2093             }
2094         };
2095     }
2096
2097     impl_dep_tracking_hash_via_hash!(bool);
2098     impl_dep_tracking_hash_via_hash!(usize);
2099     impl_dep_tracking_hash_via_hash!(u64);
2100     impl_dep_tracking_hash_via_hash!(String);
2101     impl_dep_tracking_hash_via_hash!(PathBuf);
2102     impl_dep_tracking_hash_via_hash!(lint::Level);
2103     impl_dep_tracking_hash_via_hash!(Option<bool>);
2104     impl_dep_tracking_hash_via_hash!(Option<usize>);
2105     impl_dep_tracking_hash_via_hash!(Option<String>);
2106     impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2107     impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2108     impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2109     impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2110     impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
2111     impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2112     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2113     impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2114     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2115     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2116     impl_dep_tracking_hash_via_hash!(CrateType);
2117     impl_dep_tracking_hash_via_hash!(MergeFunctions);
2118     impl_dep_tracking_hash_via_hash!(PanicStrategy);
2119     impl_dep_tracking_hash_via_hash!(RelroLevel);
2120     impl_dep_tracking_hash_via_hash!(Passes);
2121     impl_dep_tracking_hash_via_hash!(OptLevel);
2122     impl_dep_tracking_hash_via_hash!(LtoCli);
2123     impl_dep_tracking_hash_via_hash!(DebugInfo);
2124     impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2125     impl_dep_tracking_hash_via_hash!(OutputTypes);
2126     impl_dep_tracking_hash_via_hash!(NativeLibKind);
2127     impl_dep_tracking_hash_via_hash!(SanitizerSet);
2128     impl_dep_tracking_hash_via_hash!(CFGuard);
2129     impl_dep_tracking_hash_via_hash!(TargetTriple);
2130     impl_dep_tracking_hash_via_hash!(Edition);
2131     impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2132     impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2133     impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2134     impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2135
2136     impl_dep_tracking_hash_for_sortable_vec_of!(String);
2137     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2138     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2139     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2140     impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
2141     impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2142
2143     impl<T1, T2> DepTrackingHash for (T1, T2)
2144     where
2145         T1: DepTrackingHash,
2146         T2: DepTrackingHash,
2147     {
2148         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2149             Hash::hash(&0, hasher);
2150             DepTrackingHash::hash(&self.0, hasher, error_format);
2151             Hash::hash(&1, hasher);
2152             DepTrackingHash::hash(&self.1, hasher, error_format);
2153         }
2154     }
2155
2156     impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2157     where
2158         T1: DepTrackingHash,
2159         T2: DepTrackingHash,
2160         T3: DepTrackingHash,
2161     {
2162         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2163             Hash::hash(&0, hasher);
2164             DepTrackingHash::hash(&self.0, hasher, error_format);
2165             Hash::hash(&1, hasher);
2166             DepTrackingHash::hash(&self.1, hasher, error_format);
2167             Hash::hash(&2, hasher);
2168             DepTrackingHash::hash(&self.2, hasher, error_format);
2169         }
2170     }
2171
2172     // This is a stable hash because BTreeMap is a sorted container
2173     pub fn stable_hash(
2174         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2175         hasher: &mut DefaultHasher,
2176         error_format: ErrorOutputType,
2177     ) {
2178         for (key, sub_hash) in sub_hashes {
2179             // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2180             // the keys, as they are just plain strings
2181             Hash::hash(&key.len(), hasher);
2182             Hash::hash(key, hasher);
2183             sub_hash.hash(hasher, error_format);
2184         }
2185     }
2186 }