]> git.lizzy.rs Git - rust.git/blob - src/librustc_session/config.rs
Rollup merge of #67230 - chansuke:remove-irrelevant-passage, r=Dylan-DPC
[rust.git] / src / librustc_session / config.rs
1 // ignore-tidy-filelength
2
3 //! Contains infrastructure for configuring the compiler, including parsing
4 //! command-line options.
5
6 use crate::lint;
7 use crate::utils::NativeLibraryKind;
8 use crate::{early_error, early_warn, Session};
9 use crate::search_paths::SearchPath;
10
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
13
14 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
15 use rustc_target::spec::{Target, TargetTriple};
16
17 use syntax_pos::source_map::{FileName, FilePathMapping};
18 use syntax_pos::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
19 use syntax_pos::symbol::{sym, Symbol};
20 use rustc_feature::UnstableFeatures;
21 use crate::parse::CrateConfig;
22
23 use rustc_errors::emitter::HumanReadableErrorType;
24 use rustc_errors::{ColorConfig, FatalError, Handler};
25
26 use getopts;
27
28 use std::collections::{BTreeMap, BTreeSet};
29 use std::collections::btree_map::{
30     Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
31 };
32 use std::fmt;
33 use std::str::{self, FromStr};
34 use std::hash::Hasher;
35 use std::collections::hash_map::DefaultHasher;
36 use std::iter::{self, FromIterator};
37 use std::path::{Path, PathBuf};
38
39 pub struct Config {
40     pub target: Target,
41     pub ptr_width: u32,
42 }
43
44 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
45 pub enum Sanitizer {
46     Address,
47     Leak,
48     Memory,
49     Thread,
50 }
51
52 impl fmt::Display for Sanitizer {
53     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54         match *self {
55             Sanitizer::Address => "address".fmt(f),
56             Sanitizer::Leak => "leak".fmt(f),
57             Sanitizer::Memory => "memory".fmt(f),
58             Sanitizer::Thread => "thread".fmt(f),
59         }
60     }
61 }
62
63 impl FromStr for Sanitizer {
64     type Err = ();
65     fn from_str(s: &str) -> Result<Sanitizer, ()> {
66         match s {
67             "address" => Ok(Sanitizer::Address),
68             "leak" => Ok(Sanitizer::Leak),
69             "memory" => Ok(Sanitizer::Memory),
70             "thread" => Ok(Sanitizer::Thread),
71             _ => Err(()),
72         }
73     }
74 }
75
76 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
77 pub enum OptLevel {
78     No,         // -O0
79     Less,       // -O1
80     Default,    // -O2
81     Aggressive, // -O3
82     Size,       // -Os
83     SizeMin,    // -Oz
84 }
85
86 impl_stable_hash_via_hash!(OptLevel);
87
88 /// This is what the `LtoCli` values get mapped to after resolving defaults and
89 /// and taking other command line options into account.
90 #[derive(Clone, PartialEq)]
91 pub enum Lto {
92     /// Don't do any LTO whatsoever
93     No,
94
95     /// Do a full crate graph LTO with ThinLTO
96     Thin,
97
98     /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
99     /// units).
100     ThinLocal,
101
102     /// Do a full crate graph LTO with "fat" LTO
103     Fat,
104 }
105
106 /// The different settings that the `-C lto` flag can have.
107 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
108 pub enum LtoCli {
109     /// `-C lto=no`
110     No,
111     /// `-C lto=yes`
112     Yes,
113     /// `-C lto`
114     NoParam,
115     /// `-C lto=thin`
116     Thin,
117     /// `-C lto=fat`
118     Fat,
119     /// No `-C lto` flag passed
120     Unspecified,
121 }
122
123 #[derive(Clone, PartialEq, Hash)]
124 pub enum LinkerPluginLto {
125     LinkerPlugin(PathBuf),
126     LinkerPluginAuto,
127     Disabled
128 }
129
130 impl LinkerPluginLto {
131     pub fn enabled(&self) -> bool {
132         match *self {
133             LinkerPluginLto::LinkerPlugin(_) |
134             LinkerPluginLto::LinkerPluginAuto => true,
135             LinkerPluginLto::Disabled => false,
136         }
137     }
138 }
139
140 #[derive(Clone, PartialEq, Hash)]
141 pub enum SwitchWithOptPath {
142     Enabled(Option<PathBuf>),
143     Disabled,
144 }
145
146 impl SwitchWithOptPath {
147     pub fn enabled(&self) -> bool {
148         match *self {
149             SwitchWithOptPath::Enabled(_) => true,
150             SwitchWithOptPath::Disabled => false,
151         }
152     }
153 }
154
155 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
156 pub enum SymbolManglingVersion {
157     Legacy,
158     V0,
159 }
160
161 impl_stable_hash_via_hash!(SymbolManglingVersion);
162
163 #[derive(Clone, Copy, PartialEq, Hash)]
164 pub enum DebugInfo {
165     None,
166     Limited,
167     Full,
168 }
169
170 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
171 pub enum OutputType {
172     Bitcode,
173     Assembly,
174     LlvmAssembly,
175     Mir,
176     Metadata,
177     Object,
178     Exe,
179     DepInfo,
180 }
181
182 impl_stable_hash_via_hash!(OutputType);
183
184 impl OutputType {
185     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
186         match *self {
187             OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
188             OutputType::Bitcode
189             | OutputType::Assembly
190             | OutputType::LlvmAssembly
191             | OutputType::Mir
192             | OutputType::Object => false,
193         }
194     }
195
196     fn shorthand(&self) -> &'static str {
197         match *self {
198             OutputType::Bitcode => "llvm-bc",
199             OutputType::Assembly => "asm",
200             OutputType::LlvmAssembly => "llvm-ir",
201             OutputType::Mir => "mir",
202             OutputType::Object => "obj",
203             OutputType::Metadata => "metadata",
204             OutputType::Exe => "link",
205             OutputType::DepInfo => "dep-info",
206         }
207     }
208
209     fn from_shorthand(shorthand: &str) -> Option<Self> {
210         Some(match shorthand {
211             "asm" => OutputType::Assembly,
212             "llvm-ir" => OutputType::LlvmAssembly,
213             "mir" => OutputType::Mir,
214             "llvm-bc" => OutputType::Bitcode,
215             "obj" => OutputType::Object,
216             "metadata" => OutputType::Metadata,
217             "link" => OutputType::Exe,
218             "dep-info" => OutputType::DepInfo,
219             _ => return None,
220         })
221     }
222
223     fn shorthands_display() -> String {
224         format!(
225             "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
226             OutputType::Bitcode.shorthand(),
227             OutputType::Assembly.shorthand(),
228             OutputType::LlvmAssembly.shorthand(),
229             OutputType::Mir.shorthand(),
230             OutputType::Object.shorthand(),
231             OutputType::Metadata.shorthand(),
232             OutputType::Exe.shorthand(),
233             OutputType::DepInfo.shorthand(),
234         )
235     }
236
237     pub fn extension(&self) -> &'static str {
238         match *self {
239             OutputType::Bitcode => "bc",
240             OutputType::Assembly => "s",
241             OutputType::LlvmAssembly => "ll",
242             OutputType::Mir => "mir",
243             OutputType::Object => "o",
244             OutputType::Metadata => "rmeta",
245             OutputType::DepInfo => "d",
246             OutputType::Exe => "",
247         }
248     }
249 }
250
251 /// The type of diagnostics output to generate.
252 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
253 pub enum ErrorOutputType {
254     /// Output meant for the consumption of humans.
255     HumanReadable(HumanReadableErrorType),
256     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
257     Json {
258         /// Render the JSON in a human readable way (with indents and newlines).
259         pretty: bool,
260         /// The JSON output includes a `rendered` field that includes the rendered
261         /// human output.
262         json_rendered: HumanReadableErrorType,
263     },
264 }
265
266 impl Default for ErrorOutputType {
267     fn default() -> Self {
268         Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
269     }
270 }
271
272 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
273 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
274 /// dependency tracking for command-line arguments.
275 #[derive(Clone, Hash)]
276 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
277
278 impl_stable_hash_via_hash!(OutputTypes);
279
280 impl OutputTypes {
281     pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
282         OutputTypes(BTreeMap::from_iter(
283             entries.iter().map(|&(k, ref v)| (k, v.clone())),
284         ))
285     }
286
287     pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
288         self.0.get(key)
289     }
290
291     pub fn contains_key(&self, key: &OutputType) -> bool {
292         self.0.contains_key(key)
293     }
294
295     pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
296         self.0.keys()
297     }
298
299     pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
300         self.0.values()
301     }
302
303     pub fn len(&self) -> usize {
304         self.0.len()
305     }
306
307     // Returns `true` if any of the output types require codegen or linking.
308     pub fn should_codegen(&self) -> bool {
309         self.0.keys().any(|k| match *k {
310             OutputType::Bitcode
311             | OutputType::Assembly
312             | OutputType::LlvmAssembly
313             | OutputType::Mir
314             | OutputType::Object
315             | OutputType::Exe => true,
316             OutputType::Metadata | OutputType::DepInfo => false,
317         })
318     }
319 }
320
321 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
322 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
323 /// would break dependency tracking for command-line arguments.
324 #[derive(Clone)]
325 pub struct Externs(BTreeMap<String, ExternEntry>);
326
327 #[derive(Clone, Debug)]
328 pub struct ExternEntry {
329     pub location: ExternLocation,
330     /// Indicates this is a "private" dependency for the
331     /// `exported_private_dependencies` lint.
332     ///
333     /// This can be set with the `priv` option like
334     /// `--extern priv:name=foo.rlib`.
335     pub is_private_dep: bool,
336     /// Add the extern entry to the extern prelude.
337     ///
338     /// This can be disabled with the `noprelude` option like
339     /// `--extern noprelude:name`.
340     pub add_prelude: bool,
341 }
342
343 #[derive(Clone, Debug)]
344 pub enum ExternLocation {
345     /// Indicates to look for the library in the search paths.
346     ///
347     /// Added via `--extern name`.
348     FoundInLibrarySearchDirectories,
349     /// The locations where this extern entry must be found.
350     ///
351     /// The `CrateLoader` is responsible for loading these and figuring out
352     /// which one to use.
353     ///
354     /// Added via `--extern prelude_name=some_file.rlib`
355     ExactPaths(BTreeSet<String>),
356 }
357
358 impl Externs {
359     pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
360         Externs(data)
361     }
362
363     pub fn get(&self, key: &str) -> Option<&ExternEntry> {
364         self.0.get(key)
365     }
366
367     pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
368         self.0.iter()
369     }
370 }
371
372 impl ExternEntry {
373     fn new(location: ExternLocation) -> ExternEntry {
374         ExternEntry { location, is_private_dep: false, add_prelude: false }
375     }
376
377     pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
378         match &self.location {
379             ExternLocation::ExactPaths(set) => Some(set.iter()),
380             _ => None,
381         }
382     }
383 }
384
385 macro_rules! hash_option {
386     ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
387     ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
388         if $sub_hashes.insert(stringify!($opt_name),
389                               $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
390             panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
391         }
392     });
393 }
394
395 macro_rules! top_level_options {
396     (pub struct Options { $(
397         $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
398     )* } ) => (
399         #[derive(Clone)]
400         pub struct Options {
401             $(pub $opt: $t),*
402         }
403
404         impl Options {
405             pub fn dep_tracking_hash(&self) -> u64 {
406                 let mut sub_hashes = BTreeMap::new();
407                 $({
408                     hash_option!($opt,
409                                  &self.$opt,
410                                  &mut sub_hashes,
411                                  [$dep_tracking_marker $($warn_val,
412                                                          $warn_text,
413                                                          self.error_format)*]);
414                 })*
415                 let mut hasher = DefaultHasher::new();
416                 dep_tracking::stable_hash(sub_hashes,
417                                           &mut hasher,
418                                           self.error_format);
419                 hasher.finish()
420             }
421         }
422     );
423 }
424
425 // The top-level command-line options struct.
426 //
427 // For each option, one has to specify how it behaves with regard to the
428 // dependency tracking system of incremental compilation. This is done via the
429 // square-bracketed directive after the field type. The options are:
430 //
431 // [TRACKED]
432 // A change in the given field will cause the compiler to completely clear the
433 // incremental compilation cache before proceeding.
434 //
435 // [UNTRACKED]
436 // Incremental compilation is not influenced by this option.
437 //
438 // If you add a new option to this struct or one of the sub-structs like
439 // `CodegenOptions`, think about how it influences incremental compilation. If in
440 // doubt, specify [TRACKED], which is always "correct" but might lead to
441 // unnecessary re-compilation.
442 top_level_options!(
443     pub struct Options {
444         // The crate config requested for the session, which may be combined
445         // with additional crate configurations during the compile process.
446         crate_types: Vec<CrateType> [TRACKED],
447         optimize: OptLevel [TRACKED],
448         // Include the `debug_assertions` flag in dependency tracking, since it
449         // can influence whether overflow checks are done or not.
450         debug_assertions: bool [TRACKED],
451         debuginfo: DebugInfo [TRACKED],
452         lint_opts: Vec<(String, lint::Level)> [TRACKED],
453         lint_cap: Option<lint::Level> [TRACKED],
454         describe_lints: bool [UNTRACKED],
455         output_types: OutputTypes [TRACKED],
456         search_paths: Vec<SearchPath> [UNTRACKED],
457         libs: Vec<(String, Option<String>, Option<NativeLibraryKind>)> [TRACKED],
458         maybe_sysroot: Option<PathBuf> [UNTRACKED],
459
460         target_triple: TargetTriple [TRACKED],
461
462         test: bool [TRACKED],
463         error_format: ErrorOutputType [UNTRACKED],
464
465         // If `Some`, enable incremental compilation, using the given
466         // directory to store intermediate results.
467         incremental: Option<PathBuf> [UNTRACKED],
468
469         debugging_opts: DebuggingOptions [TRACKED],
470         prints: Vec<PrintRequest> [UNTRACKED],
471         // Determines which borrow checker(s) to run. This is the parsed, sanitized
472         // version of `debugging_opts.borrowck`, which is just a plain string.
473         borrowck_mode: BorrowckMode [UNTRACKED],
474         cg: CodegenOptions [TRACKED],
475         externs: Externs [UNTRACKED],
476         crate_name: Option<String> [TRACKED],
477         // An optional name to use as the crate for std during std injection,
478         // written `extern crate name as std`. Defaults to `std`. Used by
479         // out-of-tree drivers.
480         alt_std_name: Option<String> [TRACKED],
481         // Indicates how the compiler should treat unstable features.
482         unstable_features: UnstableFeatures [TRACKED],
483
484         // Indicates whether this run of the compiler is actually rustdoc. This
485         // is currently just a hack and will be removed eventually, so please
486         // try to not rely on this too much.
487         actually_rustdoc: bool [TRACKED],
488
489         // Specifications of codegen units / ThinLTO which are forced as a
490         // result of parsing command line options. These are not necessarily
491         // what rustc was invoked with, but massaged a bit to agree with
492         // commands like `--emit llvm-ir` which they're often incompatible with
493         // if we otherwise use the defaults of rustc.
494         cli_forced_codegen_units: Option<usize> [UNTRACKED],
495         cli_forced_thinlto_off: bool [UNTRACKED],
496
497         // Remap source path prefixes in all output (messages, object files, debug, etc.).
498         remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
499
500         edition: Edition [TRACKED],
501
502         // `true` if we're emitting JSON blobs about each artifact produced
503         // by the compiler.
504         json_artifact_notifications: bool [TRACKED],
505
506         pretty: Option<PpMode> [UNTRACKED],
507     }
508 );
509
510 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
511 pub enum PrintRequest {
512     FileNames,
513     Sysroot,
514     CrateName,
515     Cfg,
516     TargetList,
517     TargetCPUs,
518     TargetFeatures,
519     RelocationModels,
520     CodeModels,
521     TlsModels,
522     TargetSpec,
523     NativeStaticLibs,
524 }
525
526 #[derive(Copy, Clone)]
527 pub enum BorrowckMode {
528     Mir,
529     Migrate,
530 }
531
532 impl BorrowckMode {
533     /// Returns whether we should run the MIR-based borrow check, but also fall back
534     /// on the AST borrow check if the MIR-based one errors.
535     pub fn migrate(self) -> bool {
536         match self {
537             BorrowckMode::Mir => false,
538             BorrowckMode::Migrate => true,
539         }
540     }
541 }
542
543 pub enum Input {
544     /// Load source code from a file.
545     File(PathBuf),
546     /// Load source code from a string.
547     Str {
548         /// A string that is shown in place of a filename.
549         name: FileName,
550         /// An anonymous string containing the source code.
551         input: String,
552     },
553 }
554
555 impl Input {
556     pub fn filestem(&self) -> &str {
557         match *self {
558             Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
559             Input::Str { .. } => "rust_out",
560         }
561     }
562
563     pub fn get_input(&mut self) -> Option<&mut String> {
564         match *self {
565             Input::File(_) => None,
566             Input::Str { ref mut input, .. } => Some(input),
567         }
568     }
569
570     pub fn source_name(&self) -> FileName {
571         match *self {
572             Input::File(ref ifile) => ifile.clone().into(),
573             Input::Str { ref name, .. } => name.clone(),
574         }
575     }
576 }
577
578 #[derive(Clone, Hash)]
579 pub struct OutputFilenames {
580     pub out_directory: PathBuf,
581     pub out_filestem: String,
582     pub single_output_file: Option<PathBuf>,
583     pub extra: String,
584     pub outputs: OutputTypes,
585 }
586
587 impl_stable_hash_via_hash!(OutputFilenames);
588
589 pub const RUST_CGU_EXT: &str = "rcgu";
590
591 impl OutputFilenames {
592     pub fn path(&self, flavor: OutputType) -> PathBuf {
593         self.outputs
594             .get(&flavor)
595             .and_then(|p| p.to_owned())
596             .or_else(|| self.single_output_file.clone())
597             .unwrap_or_else(|| self.temp_path(flavor, None))
598     }
599
600     /// Gets the path where a compilation artifact of the given type for the
601     /// given codegen unit should be placed on disk. If codegen_unit_name is
602     /// None, a path distinct from those of any codegen unit will be generated.
603     pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
604         let extension = flavor.extension();
605         self.temp_path_ext(extension, codegen_unit_name)
606     }
607
608     /// Like temp_path, but also supports things where there is no corresponding
609     /// OutputType, like noopt-bitcode or lto-bitcode.
610     pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
611         let base = self.out_directory.join(&self.filestem());
612
613         let mut extension = String::new();
614
615         if let Some(codegen_unit_name) = codegen_unit_name {
616             extension.push_str(codegen_unit_name);
617         }
618
619         if !ext.is_empty() {
620             if !extension.is_empty() {
621                 extension.push_str(".");
622                 extension.push_str(RUST_CGU_EXT);
623                 extension.push_str(".");
624             }
625
626             extension.push_str(ext);
627         }
628
629         let path = base.with_extension(&extension[..]);
630         path
631     }
632
633     pub fn with_extension(&self, extension: &str) -> PathBuf {
634         self.out_directory
635             .join(&self.filestem())
636             .with_extension(extension)
637     }
638
639     pub fn filestem(&self) -> String {
640         format!("{}{}", self.out_filestem, self.extra)
641     }
642 }
643
644 pub fn host_triple() -> &'static str {
645     // Get the host triple out of the build environment. This ensures that our
646     // idea of the host triple is the same as for the set of libraries we've
647     // actually built.  We can't just take LLVM's host triple because they
648     // normalize all ix86 architectures to i386.
649     //
650     // Instead of grabbing the host triple (for the current host), we grab (at
651     // compile time) the target triple that this rustc is built with and
652     // calling that (at runtime) the host triple.
653     (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
654 }
655
656 impl Default for Options {
657     fn default() -> Options {
658         Options {
659             crate_types: Vec::new(),
660             optimize: OptLevel::No,
661             debuginfo: DebugInfo::None,
662             lint_opts: Vec::new(),
663             lint_cap: None,
664             describe_lints: false,
665             output_types: OutputTypes(BTreeMap::new()),
666             search_paths: vec![],
667             maybe_sysroot: None,
668             target_triple: TargetTriple::from_triple(host_triple()),
669             test: false,
670             incremental: None,
671             debugging_opts: basic_debugging_options(),
672             prints: Vec::new(),
673             borrowck_mode: BorrowckMode::Migrate,
674             cg: basic_codegen_options(),
675             error_format: ErrorOutputType::default(),
676             externs: Externs(BTreeMap::new()),
677             crate_name: None,
678             alt_std_name: None,
679             libs: Vec::new(),
680             unstable_features: UnstableFeatures::Disallow,
681             debug_assertions: true,
682             actually_rustdoc: false,
683             cli_forced_codegen_units: None,
684             cli_forced_thinlto_off: false,
685             remap_path_prefix: Vec::new(),
686             edition: DEFAULT_EDITION,
687             json_artifact_notifications: false,
688             pretty: None,
689         }
690     }
691 }
692
693 impl Options {
694     /// Returns `true` if there is a reason to build the dep graph.
695     pub fn build_dep_graph(&self) -> bool {
696         self.incremental.is_some() || self.debugging_opts.dump_dep_graph
697             || self.debugging_opts.query_dep_graph
698     }
699
700     #[inline(always)]
701     pub fn enable_dep_node_debug_strs(&self) -> bool {
702         cfg!(debug_assertions)
703             && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
704     }
705
706     pub fn file_path_mapping(&self) -> FilePathMapping {
707         FilePathMapping::new(self.remap_path_prefix.clone())
708     }
709
710     /// Returns `true` if there will be an output file generated.
711     pub fn will_create_output_file(&self) -> bool {
712         !self.debugging_opts.parse_only && // The file is just being parsed
713             !self.debugging_opts.ls // The file is just being queried
714     }
715
716     #[inline]
717     pub fn share_generics(&self) -> bool {
718         match self.debugging_opts.share_generics {
719             Some(setting) => setting,
720             None => {
721                 match self.optimize {
722                     OptLevel::No   |
723                     OptLevel::Less |
724                     OptLevel::Size |
725                     OptLevel::SizeMin => true,
726                     OptLevel::Default    |
727                     OptLevel::Aggressive => false,
728                 }
729             }
730         }
731     }
732 }
733
734 // The type of entry function, so users can have their own entry functions
735 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
736 pub enum EntryFnType {
737     Main,
738     Start,
739 }
740
741 impl_stable_hash_via_hash!(EntryFnType);
742
743 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
744 pub enum CrateType {
745     Executable,
746     Dylib,
747     Rlib,
748     Staticlib,
749     Cdylib,
750     ProcMacro,
751 }
752
753 impl_stable_hash_via_hash!(CrateType);
754
755 #[derive(Clone, Hash)]
756 pub enum Passes {
757     Some(Vec<String>),
758     All,
759 }
760
761 impl Passes {
762     pub fn is_empty(&self) -> bool {
763         match *self {
764             Passes::Some(ref v) => v.is_empty(),
765             Passes::All => false,
766         }
767     }
768 }
769
770 /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
771 /// macro is to define an interface that can be programmatically used by the option parser
772 /// to initialize the struct without hardcoding field names all over the place.
773 ///
774 /// The goal is to invoke this macro once with the correct fields, and then this macro generates all
775 /// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
776 /// generated code to parse an option into its respective field in the struct. There are a few
777 /// hand-written parsers for parsing specific types of values in this module.
778 macro_rules! options {
779     ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
780      $buildfn:ident, $prefix:expr, $outputname:expr,
781      $stat:ident, $mod_desc:ident, $mod_set:ident,
782      $($opt:ident : $t:ty = (
783         $init:expr,
784         $parse:ident,
785         [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
786         $desc:expr)
787      ),* ,) =>
788 (
789     #[derive(Clone)]
790     pub struct $struct_name { $(pub $opt: $t),* }
791
792     pub fn $defaultfn() -> $struct_name {
793         $struct_name { $($opt: $init),* }
794     }
795
796     pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
797     {
798         let mut op = $defaultfn();
799         for option in matches.opt_strs($prefix) {
800             let mut iter = option.splitn(2, '=');
801             let key = iter.next().unwrap();
802             let value = iter.next();
803             let option_to_lookup = key.replace("-", "_");
804             let mut found = false;
805             for &(candidate, setter, opt_type_desc, _) in $stat {
806                 if option_to_lookup != candidate { continue }
807                 if !setter(&mut op, value) {
808                     match (value, opt_type_desc) {
809                         (Some(..), None) => {
810                             early_error(error_format, &format!("{} option `{}` takes no \
811                                                                 value", $outputname, key))
812                         }
813                         (None, Some(type_desc)) => {
814                             early_error(error_format, &format!("{0} option `{1}` requires \
815                                                                 {2} ({3} {1}=<value>)",
816                                                                $outputname, key,
817                                                                type_desc, $prefix))
818                         }
819                         (Some(value), Some(type_desc)) => {
820                             early_error(error_format, &format!("incorrect value `{}` for {} \
821                                                                 option `{}` - {} was expected",
822                                                                value, $outputname,
823                                                                key, type_desc))
824                         }
825                         (None, None) => panic!()
826                     }
827                 }
828                 found = true;
829                 break;
830             }
831             if !found {
832                 early_error(error_format, &format!("unknown {} option: `{}`",
833                                                    $outputname, key));
834             }
835         }
836         return op;
837     }
838
839     impl dep_tracking::DepTrackingHash for $struct_name {
840         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
841             let mut sub_hashes = BTreeMap::new();
842             $({
843                 hash_option!($opt,
844                              &self.$opt,
845                              &mut sub_hashes,
846                              [$dep_tracking_marker $($dep_warn_val,
847                                                      $dep_warn_text,
848                                                      error_format)*]);
849             })*
850             dep_tracking::stable_hash(sub_hashes, hasher, error_format);
851         }
852     }
853
854     pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
855     pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
856         &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
857
858     #[allow(non_upper_case_globals, dead_code)]
859     mod $mod_desc {
860         pub const parse_bool: Option<&str> = None;
861         pub const parse_opt_bool: Option<&str> =
862             Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
863         pub const parse_string: Option<&str> = Some("a string");
864         pub const parse_string_push: Option<&str> = Some("a string");
865         pub const parse_pathbuf_push: Option<&str> = Some("a path");
866         pub const parse_opt_string: Option<&str> = Some("a string");
867         pub const parse_opt_pathbuf: Option<&str> = Some("a path");
868         pub const parse_list: Option<&str> = Some("a space-separated list of strings");
869         pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
870         pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
871         pub const parse_threads: Option<&str> = Some("a number");
872         pub const parse_uint: Option<&str> = Some("a number");
873         pub const parse_passes: Option<&str> =
874             Some("a space-separated list of passes, or `all`");
875         pub const parse_opt_uint: Option<&str> =
876             Some("a number");
877         pub const parse_panic_strategy: Option<&str> =
878             Some("either `unwind` or `abort`");
879         pub const parse_relro_level: Option<&str> =
880             Some("one of: `full`, `partial`, or `off`");
881         pub const parse_sanitizer: Option<&str> =
882             Some("one of: `address`, `leak`, `memory` or `thread`");
883         pub const parse_sanitizer_list: Option<&str> =
884             Some("comma separated list of sanitizers");
885         pub const parse_sanitizer_memory_track_origins: Option<&str> = None;
886         pub const parse_linker_flavor: Option<&str> =
887             Some(::rustc_target::spec::LinkerFlavor::one_of());
888         pub const parse_optimization_fuel: Option<&str> =
889             Some("crate=integer");
890         pub const parse_unpretty: Option<&str> =
891             Some("`string` or `string=string`");
892         pub const parse_treat_err_as_bug: Option<&str> =
893             Some("either no value or a number bigger than 0");
894         pub const parse_lto: Option<&str> =
895             Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
896                   `fat`, or omitted");
897         pub const parse_linker_plugin_lto: Option<&str> =
898             Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
899                   or the path to the linker plugin");
900         pub const parse_switch_with_opt_path: Option<&str> =
901             Some("an optional path to the profiling data output directory");
902         pub const parse_merge_functions: Option<&str> =
903             Some("one of: `disabled`, `trampolines`, or `aliases`");
904         pub const parse_symbol_mangling_version: Option<&str> =
905             Some("either `legacy` or `v0` (RFC 2603)");
906     }
907
908     #[allow(dead_code)]
909     mod $mod_set {
910         use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
911             SymbolManglingVersion};
912         use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
913         use std::path::PathBuf;
914         use std::str::FromStr;
915
916         $(
917             pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
918                 $parse(&mut cg.$opt, v)
919             }
920         )*
921
922         fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
923             match v {
924                 Some(..) => false,
925                 None => { *slot = true; true }
926             }
927         }
928
929         fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
930             match v {
931                 Some(s) => {
932                     match s {
933                         "n" | "no" | "off" => {
934                             *slot = Some(false);
935                         }
936                         "y" | "yes" | "on" => {
937                             *slot = Some(true);
938                         }
939                         _ => { return false; }
940                     }
941
942                     true
943                 },
944                 None => { *slot = Some(true); true }
945             }
946         }
947
948         fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
949             match v {
950                 Some(s) => { *slot = Some(s.to_string()); true },
951                 None => false,
952             }
953         }
954
955         fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
956             match v {
957                 Some(s) => { *slot = Some(PathBuf::from(s)); true },
958                 None => false,
959             }
960         }
961
962         fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
963             match v {
964                 Some(s) => { *slot = s.to_string(); true },
965                 None => false,
966             }
967         }
968
969         fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
970             match v {
971                 Some(s) => { slot.push(s.to_string()); true },
972                 None => false,
973             }
974         }
975
976         fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
977             match v {
978                 Some(s) => { slot.push(PathBuf::from(s)); true },
979                 None => false,
980             }
981         }
982
983         fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
984                       -> bool {
985             match v {
986                 Some(s) => {
987                     slot.extend(s.split_whitespace().map(|s| s.to_string()));
988                     true
989                 },
990                 None => false,
991             }
992         }
993
994         fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
995                       -> bool {
996             match v {
997                 Some(s) => {
998                     let v = s.split_whitespace().map(|s| s.to_string()).collect();
999                     *slot = Some(v);
1000                     true
1001                 },
1002                 None => false,
1003             }
1004         }
1005
1006         fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
1007                       -> bool {
1008             match v {
1009                 Some(s) => {
1010                     let v = s.split(',').map(|s| s.to_string()).collect();
1011                     *slot = Some(v);
1012                     true
1013                 },
1014                 None => false,
1015             }
1016         }
1017
1018         fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
1019             match v.and_then(|s| s.parse().ok()) {
1020                 Some(0) => { *slot = ::num_cpus::get(); true },
1021                 Some(i) => { *slot = i; true },
1022                 None => false
1023             }
1024         }
1025
1026         fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
1027             match v.and_then(|s| s.parse().ok()) {
1028                 Some(i) => { *slot = i; true },
1029                 None => false
1030             }
1031         }
1032
1033         fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1034             match v {
1035                 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
1036                 None => { *slot = None; false }
1037             }
1038         }
1039
1040         fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
1041             match v {
1042                 Some("all") => {
1043                     *slot = Passes::All;
1044                     true
1045                 }
1046                 v => {
1047                     let mut passes = vec![];
1048                     if parse_list(&mut passes, v) {
1049                         *slot = Passes::Some(passes);
1050                         true
1051                     } else {
1052                         false
1053                     }
1054                 }
1055             }
1056         }
1057
1058         fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
1059             match v {
1060                 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
1061                 Some("abort") => *slot = Some(PanicStrategy::Abort),
1062                 _ => return false
1063             }
1064             true
1065         }
1066
1067         fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1068             match v {
1069                 Some(s) => {
1070                     match s.parse::<RelroLevel>() {
1071                         Ok(level) => *slot = Some(level),
1072                         _ => return false
1073                     }
1074                 },
1075                 _ => return false
1076             }
1077             true
1078         }
1079
1080         fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1081             if let Some(Ok(s)) =  v.map(str::parse) {
1082                 *slot = Some(s);
1083                 true
1084             } else {
1085                 false
1086             }
1087         }
1088
1089         fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
1090             if let Some(v) = v {
1091                 for s in v.split(',').map(str::parse) {
1092                     if let Ok(s) = s {
1093                         if !slot.contains(&s) {
1094                             slot.push(s);
1095                         }
1096                     } else {
1097                         return false;
1098                     }
1099                 }
1100                 true
1101             } else {
1102                 false
1103             }
1104         }
1105
1106         fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
1107             match v.map(|s| s.parse()) {
1108                 None => {
1109                     *slot = 2;
1110                     true
1111                 }
1112                 Some(Ok(i)) if i <= 2 => {
1113                     *slot = i;
1114                     true
1115                 }
1116                 _ => {
1117                     false
1118                 }
1119             }
1120         }
1121
1122         fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1123             match v.and_then(LinkerFlavor::from_str) {
1124                 Some(lf) => *slote = Some(lf),
1125                 _ => return false,
1126             }
1127             true
1128         }
1129
1130         fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1131             match v {
1132                 None => false,
1133                 Some(s) => {
1134                     let parts = s.split('=').collect::<Vec<_>>();
1135                     if parts.len() != 2 { return false; }
1136                     let crate_name = parts[0].to_string();
1137                     let fuel = parts[1].parse::<u64>();
1138                     if fuel.is_err() { return false; }
1139                     *slot = Some((crate_name, fuel.unwrap()));
1140                     true
1141                 }
1142             }
1143         }
1144
1145         fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1146             match v {
1147                 None => false,
1148                 Some(s) if s.split('=').count() <= 2 => {
1149                     *slot = Some(s.to_string());
1150                     true
1151                 }
1152                 _ => false,
1153             }
1154         }
1155
1156         fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1157             match v {
1158                 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1159                 None => { *slot = Some(1); true }
1160             }
1161         }
1162
1163         fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1164             if v.is_some() {
1165                 let mut bool_arg = None;
1166                 if parse_opt_bool(&mut bool_arg, v) {
1167                     *slot = if bool_arg.unwrap() {
1168                         LtoCli::Yes
1169                     } else {
1170                         LtoCli::No
1171                     };
1172                     return true
1173                 }
1174             }
1175
1176             *slot = match v {
1177                 None => LtoCli::NoParam,
1178                 Some("thin") => LtoCli::Thin,
1179                 Some("fat") => LtoCli::Fat,
1180                 Some(_) => return false,
1181             };
1182             true
1183         }
1184
1185         fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1186             if v.is_some() {
1187                 let mut bool_arg = None;
1188                 if parse_opt_bool(&mut bool_arg, v) {
1189                     *slot = if bool_arg.unwrap() {
1190                         LinkerPluginLto::LinkerPluginAuto
1191                     } else {
1192                         LinkerPluginLto::Disabled
1193                     };
1194                     return true
1195                 }
1196             }
1197
1198             *slot = match v {
1199                 None => LinkerPluginLto::LinkerPluginAuto,
1200                 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1201             };
1202             true
1203         }
1204
1205         fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1206             *slot = match v {
1207                 None => SwitchWithOptPath::Enabled(None),
1208                 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1209             };
1210             true
1211         }
1212
1213         fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1214             match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1215                 Some(mergefunc) => *slot = Some(mergefunc),
1216                 _ => return false,
1217             }
1218             true
1219         }
1220
1221         fn parse_symbol_mangling_version(
1222             slot: &mut SymbolManglingVersion,
1223             v: Option<&str>,
1224         ) -> bool {
1225             *slot = match v {
1226                 Some("legacy") => SymbolManglingVersion::Legacy,
1227                 Some("v0") => SymbolManglingVersion::V0,
1228                 _ => return false,
1229             };
1230             true
1231         }
1232     }
1233 ) }
1234
1235 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1236           build_codegen_options, "C", "codegen",
1237           CG_OPTIONS, cg_type_desc, cgsetters,
1238     ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1239         "this option is deprecated and does nothing"),
1240     linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1241         "system linker to link outputs with"),
1242     link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1243         "a single extra argument to append to the linker invocation (can be used several times)"),
1244     link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1245         "extra arguments to append to the linker invocation (space separated)"),
1246     link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1247         "don't let linker strip dead code (turning it on can be used for code coverage)"),
1248     lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1249         "perform LLVM link-time optimizations"),
1250     target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1251         "select target processor (`rustc --print target-cpus` for details)"),
1252     target_feature: String = (String::new(), parse_string, [TRACKED],
1253         "target specific attributes. (`rustc --print target-features` for details). \
1254         This feature is unsafe."),
1255     passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1256         "a list of extra LLVM passes to run (space separated)"),
1257     llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1258         "a list of arguments to pass to LLVM (space separated)"),
1259     save_temps: bool = (false, parse_bool, [UNTRACKED],
1260         "save all temporary output files during compilation"),
1261     rpath: bool = (false, parse_bool, [UNTRACKED],
1262         "set rpath values in libs/exes"),
1263     overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1264         "use overflow checks for integer arithmetic"),
1265     no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1266         "don't pre-populate the pass manager with a list of passes"),
1267     no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1268         "don't run the loop vectorization optimization passes"),
1269     no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1270         "don't run LLVM's SLP vectorization pass"),
1271     soft_float: bool = (false, parse_bool, [TRACKED],
1272         "use soft float ABI (*eabihf targets only)"),
1273     prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1274         "prefer dynamic linking to static linking"),
1275     no_integrated_as: bool = (false, parse_bool, [TRACKED],
1276         "use an external assembler rather than LLVM's integrated one"),
1277     no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1278         "disable the use of the redzone"),
1279     relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1280         "choose the relocation model to use (`rustc --print relocation-models` for details)"),
1281     code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1282         "choose the code model to use (`rustc --print code-models` for details)"),
1283     metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1284         "metadata to mangle symbol names with"),
1285     extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1286         "extra data to put in each output filename"),
1287     codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1288         "divide crate into N units to optimize in parallel"),
1289     remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1290         "print remarks for these optimization passes (space separated, or \"all\")"),
1291     no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1292         "the `--no-stack-check` flag is deprecated and does nothing"),
1293     debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1294         "debug info emission level, 0 = no debug info, 1 = line tables only, \
1295          2 = full debug info with variable and type information"),
1296     opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1297         "optimize with possible levels 0-3, s, or z"),
1298     force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1299         "force use of the frame pointers"),
1300     debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1301         "explicitly enable the `cfg(debug_assertions)` directive"),
1302     inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1303         "set the threshold for inlining a function (default: 225)"),
1304     panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1305         [TRACKED], "panic strategy to compile crate with"),
1306     incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1307         "enable incremental compilation"),
1308     default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1309         "allow the linker to link its default libraries"),
1310     linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1311                                            "linker flavor"),
1312     linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1313         parse_linker_plugin_lto, [TRACKED],
1314         "generate build artifacts that are compatible with linker-based LTO."),
1315     profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1316         parse_switch_with_opt_path, [TRACKED],
1317         "compile the program with profiling instrumentation"),
1318     profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1319         "use the given `.profdata` file for profile-guided optimization"),
1320 }
1321
1322 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1323           build_debugging_options, "Z", "debugging",
1324           DB_OPTIONS, db_type_desc, dbsetters,
1325     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1326         "the backend to use"),
1327     verbose: bool = (false, parse_bool, [UNTRACKED],
1328         "in general, enable more debug printouts"),
1329     span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1330         "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1331     identify_regions: bool = (false, parse_bool, [UNTRACKED],
1332         "make unnamed regions display as '# (where # is some non-ident unique id)"),
1333     borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1334         "select which borrowck is used (`mir` or `migrate`)"),
1335     time_passes: bool = (false, parse_bool, [UNTRACKED],
1336         "measure time of each rustc pass"),
1337     time: bool = (false, parse_bool, [UNTRACKED],
1338         "measure time of rustc processes"),
1339     time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1340         "measure time of each LLVM pass"),
1341     input_stats: bool = (false, parse_bool, [UNTRACKED],
1342         "gather statistics about the input"),
1343     asm_comments: bool = (false, parse_bool, [TRACKED],
1344         "generate comments into the assembly (may change behavior)"),
1345     verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1346         "verify LLVM IR"),
1347     borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1348         "gather borrowck statistics"),
1349     no_landing_pads: bool = (false, parse_bool, [TRACKED],
1350         "omit landing pads for unwinding"),
1351     fewer_names: bool = (false, parse_bool, [TRACKED],
1352         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1353     meta_stats: bool = (false, parse_bool, [UNTRACKED],
1354         "gather metadata statistics"),
1355     print_link_args: bool = (false, parse_bool, [UNTRACKED],
1356         "print the arguments passed to the linker"),
1357     print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1358         "prints the LLVM optimization passes being run"),
1359     ast_json: bool = (false, parse_bool, [UNTRACKED],
1360         "print the AST as JSON and halt"),
1361     // We default to 1 here since we want to behave like
1362     // a sequential compiler for now. This'll likely be adjusted
1363     // in the future. Note that -Zthreads=0 is the way to get
1364     // the num_cpus behavior.
1365     threads: usize = (1, parse_threads, [UNTRACKED],
1366         "use a thread pool with N threads"),
1367     ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1368         "print the pre-expansion AST as JSON and halt"),
1369     ls: bool = (false, parse_bool, [UNTRACKED],
1370         "list the symbols defined by a library crate"),
1371     save_analysis: bool = (false, parse_bool, [UNTRACKED],
1372         "write syntax and type analysis (in JSON format) information, in \
1373          addition to normal output"),
1374     print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1375         "prints region inference graph. \
1376          Use with RUST_REGION_GRAPH=help for more info"),
1377     parse_only: bool = (false, parse_bool, [UNTRACKED],
1378         "parse only; do not compile, assemble, or link"),
1379     dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1380         "load proc macros for both target and host, but only link to the target"),
1381     no_codegen: bool = (false, parse_bool, [TRACKED],
1382         "run all passes except codegen; no output"),
1383     treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1384         "treat error number `val` that occurs as bug"),
1385     report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1386         "immediately print bugs registered with `delay_span_bug`"),
1387     external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1388         "show macro backtraces even for non-local macros"),
1389     teach: bool = (false, parse_bool, [TRACKED],
1390         "show extended diagnostic help"),
1391     terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1392         "set the current terminal width"),
1393     panic_abort_tests: bool = (false, parse_bool, [TRACKED],
1394         "support compiling tests with panic=abort"),
1395     continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1396         "attempt to recover from parse errors (experimental)"),
1397     dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1398         "print tasks that execute and the color their dep node gets (requires debug build)"),
1399     incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1400         "enable incremental compilation (experimental)"),
1401     incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1402         "enable incremental compilation support for queries (experimental)"),
1403     incremental_info: bool = (false, parse_bool, [UNTRACKED],
1404         "print high-level information about incremental reuse (or the lack thereof)"),
1405     incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1406         "dump hash information in textual format to stdout"),
1407     incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1408         "verify incr. comp. hashes of green query instances"),
1409     incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1410         "ignore spans during ICH computation -- used for testing"),
1411     instrument_mcount: bool = (false, parse_bool, [TRACKED],
1412         "insert function instrument code for mcount-based tracing"),
1413     dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1414         "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1415     query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1416         "enable queries of the dependency graph for regression testing"),
1417     no_analysis: bool = (false, parse_bool, [UNTRACKED],
1418         "parse and expand the source, but run no analysis"),
1419     unstable_options: bool = (false, parse_bool, [UNTRACKED],
1420         "adds unstable command line options to rustc interface"),
1421     force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1422         "force overflow checks on or off"),
1423     trace_macros: bool = (false, parse_bool, [UNTRACKED],
1424         "for every macro invocation, print its name and arguments"),
1425     debug_macros: bool = (false, parse_bool, [TRACKED],
1426         "emit line numbers debug info inside macros"),
1427     generate_arange_section: bool = (true, parse_bool, [TRACKED],
1428         "generate DWARF address ranges for faster lookups"),
1429     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1430         "don't clear the hygiene data after analysis"),
1431     keep_ast: bool = (false, parse_bool, [UNTRACKED],
1432         "keep the AST after lowering it to HIR"),
1433     show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1434         "show spans for compiler debugging (expr|pat|ty)"),
1435     print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1436         "print layout information for each type encountered"),
1437     print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1438         "print the result of the monomorphization collection pass"),
1439     mir_opt_level: usize = (1, parse_uint, [TRACKED],
1440         "set the MIR optimization level (0-3, default: 1)"),
1441     mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1442         "emit noalias metadata for mutable references (default: no)"),
1443     dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1444         "dump MIR state to file.
1445         `val` is used to select which passes and functions to dump. For example:
1446         `all` matches all passes and functions,
1447         `foo` matches all passes for functions whose name contains 'foo',
1448         `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1449         `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1450
1451     dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1452         "the directory the MIR is dumped into"),
1453     dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1454         "in addition to `.mir` files, create graphviz `.dot` files"),
1455     dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1456         "if set, exclude the pass number when dumping MIR (used in tests)"),
1457     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1458         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1459     perf_stats: bool = (false, parse_bool, [UNTRACKED],
1460         "print some performance-related statistics"),
1461     query_stats: bool = (false, parse_bool, [UNTRACKED],
1462         "print some statistics about the query system"),
1463     hir_stats: bool = (false, parse_bool, [UNTRACKED],
1464         "print some statistics about AST and HIR"),
1465     always_encode_mir: bool = (false, parse_bool, [TRACKED],
1466         "encode MIR of all functions into the crate metadata"),
1467     json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1468         "describes how to render the `rendered` field of json diagnostics"),
1469     unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1470         "take the breaks off const evaluation. NOTE: this is unsound"),
1471     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1472         "pass `-install_name @rpath/...` to the macOS linker"),
1473     sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1474                                     "use a sanitizer"),
1475     sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
1476         "Enable recovery for selected sanitizers"),
1477     sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
1478         "Enable origins tracking in MemorySanitizer"),
1479     fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1480         "set the optimization fuel quota for a crate"),
1481     print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1482         "make rustc print the total optimization fuel used by a crate"),
1483     force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1484         "force all crates to be `rustc_private` unstable"),
1485     pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1486         "a single extra argument to prepend the linker invocation (can be used several times)"),
1487     pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1488         "extra arguments to prepend to the linker invocation (space separated)"),
1489     profile: bool = (false, parse_bool, [TRACKED],
1490                      "insert profiling code"),
1491     disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1492         "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1493     relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1494         "choose which RELRO level to use"),
1495     nll_facts: bool = (false, parse_bool, [UNTRACKED],
1496                        "dump facts from NLL analysis into side files"),
1497     nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1498         "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1499     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1500         "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1501     polonius: bool = (false, parse_bool, [UNTRACKED],
1502         "enable polonius-based borrow-checker"),
1503     codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1504         "generate a graphical HTML report of time spent in codegen and LLVM"),
1505     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1506         "enable ThinLTO when possible"),
1507     inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1508         "control whether `#[inline]` functions are in all CGUs"),
1509     tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1510         "choose the TLS model to use (`rustc --print tls-models` for details)"),
1511     saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1512         "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1513          the max/min integer respectively, and NaN is mapped to 0"),
1514     human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1515         "generate human-readable, predictable names for codegen units"),
1516     dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1517         "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1518          themselves"),
1519     unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1520         "present the input source, unstable (and less-pretty) variants;
1521         valid types are any of the types for `--pretty`, as well as:
1522         `expanded`, `expanded,identified`,
1523         `expanded,hygiene` (with internal representations),
1524         `everybody_loops` (all function bodies replaced with `loop {}`),
1525         `hir` (the HIR), `hir,identified`,
1526         `hir,typed` (HIR with types for each node),
1527         `hir-tree` (dump the raw HIR),
1528         `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1529     run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1530         "run `dsymutil` and delete intermediate object files"),
1531     ui_testing: bool = (false, parse_bool, [UNTRACKED],
1532         "format compiler diagnostics in a way that's better suitable for UI testing"),
1533     embed_bitcode: bool = (false, parse_bool, [TRACKED],
1534         "embed LLVM bitcode in object files"),
1535     strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1536         "tell the linker to strip debuginfo when building without debuginfo enabled."),
1537     share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1538         "make the current crate share its generic instantiations"),
1539     chalk: bool = (false, parse_bool, [TRACKED],
1540         "enable the experimental Chalk-based trait solving engine"),
1541     no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1542         "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1543     no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1544         "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1545     no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1546         "don't interleave execution of lints; allows benchmarking individual lints"),
1547     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1548         "inject the given attribute in the crate"),
1549     self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1550         parse_switch_with_opt_path, [UNTRACKED],
1551         "run the self profiler and output the raw event data"),
1552     self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1553         "specifies which kinds of events get recorded by the self profiler"),
1554     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1555         "emits a section containing stack size metadata"),
1556     plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1557           "whether to use the PLT when calling into shared libraries;
1558           only has effect for PIC code on systems with ELF binaries
1559           (default: PLT is disabled if full relro is enabled)"),
1560     merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1561         "control the operation of the MergeFunctions LLVM pass, taking
1562          the same values as the target option of the same name"),
1563     allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1564         "only allow the listed language features to be enabled in code (space separated)"),
1565     symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1566         parse_symbol_mangling_version, [TRACKED],
1567         "which mangling version to use for symbol names"),
1568     binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
1569         "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
1570     insert_sideeffect: bool = (false, parse_bool, [TRACKED],
1571         "fix undefined behavior when a thread doesn't eventually make progress \
1572          (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
1573 }
1574
1575 pub const fn default_lib_output() -> CrateType {
1576     CrateType::Rlib
1577 }
1578
1579 pub fn default_configuration(sess: &Session) -> CrateConfig {
1580     let end = &sess.target.target.target_endian;
1581     let arch = &sess.target.target.arch;
1582     let wordsz = &sess.target.target.target_pointer_width;
1583     let os = &sess.target.target.target_os;
1584     let env = &sess.target.target.target_env;
1585     let vendor = &sess.target.target.target_vendor;
1586     let min_atomic_width = sess.target.target.min_atomic_width();
1587     let max_atomic_width = sess.target.target.max_atomic_width();
1588     let atomic_cas = sess.target.target.options.atomic_cas;
1589
1590     let mut ret = FxHashSet::default();
1591     ret.reserve(6); // the minimum number of insertions
1592     // Target bindings.
1593     ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1594     if let Some(ref fam) = sess.target.target.options.target_family {
1595         ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1596         if fam == "windows" || fam == "unix" {
1597             ret.insert((Symbol::intern(fam), None));
1598         }
1599     }
1600     ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1601     ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1602     ret.insert((
1603         Symbol::intern("target_pointer_width"),
1604         Some(Symbol::intern(wordsz)),
1605     ));
1606     ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1607     ret.insert((
1608         Symbol::intern("target_vendor"),
1609         Some(Symbol::intern(vendor)),
1610     ));
1611     if sess.target.target.options.has_elf_tls {
1612         ret.insert((sym::target_thread_local, None));
1613     }
1614     for &i in &[8, 16, 32, 64, 128] {
1615         if i >= min_atomic_width && i <= max_atomic_width {
1616             let mut insert_atomic = |s| {
1617                 ret.insert((
1618                     sym::target_has_atomic_load_store,
1619                     Some(Symbol::intern(s)),
1620                 ));
1621                 if atomic_cas {
1622                     ret.insert((
1623                         sym::target_has_atomic,
1624                         Some(Symbol::intern(s))
1625                     ));
1626                 }
1627             };
1628             let s = i.to_string();
1629             insert_atomic(&s);
1630             if &s == wordsz {
1631               insert_atomic("ptr");
1632             }
1633         }
1634     }
1635     if let Some(s) = &sess.opts.debugging_opts.sanitizer {
1636         let symbol = Symbol::intern(&s.to_string());
1637         ret.insert((sym::sanitize, Some(symbol)));
1638     }
1639     if sess.opts.debug_assertions {
1640         ret.insert((Symbol::intern("debug_assertions"), None));
1641     }
1642     if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1643         ret.insert((sym::proc_macro, None));
1644     }
1645     ret
1646 }
1647
1648 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1649 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1650 /// but the symbol interner is not yet set up then, so we must convert it later.
1651 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
1652     cfg.into_iter()
1653        .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1654        .collect()
1655 }
1656
1657 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1658     // Combine the configuration requested by the session (command line) with
1659     // some default and generated configuration items.
1660     let default_cfg = default_configuration(sess);
1661     // If the user wants a test runner, then add the test cfg.
1662     if sess.opts.test {
1663         user_cfg.insert((sym::test, None));
1664     }
1665     user_cfg.extend(default_cfg.iter().cloned());
1666     user_cfg
1667 }
1668
1669 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1670     let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1671         sp.struct_fatal(&format!("Error loading target specification: {}", e))
1672           .help("Use `--print target-list` for a list of built-in targets")
1673           .emit();
1674         FatalError.raise();
1675     });
1676
1677     let ptr_width = match &target.target_pointer_width[..] {
1678         "16" => 16,
1679         "32" => 32,
1680         "64" => 64,
1681         w => sp.fatal(&format!(
1682             "target specification was invalid: \
1683              unrecognized target-pointer-width {}",
1684             w
1685         )).raise(),
1686     };
1687
1688     Config {
1689         target,
1690         ptr_width,
1691     }
1692 }
1693
1694 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1695 pub enum OptionStability {
1696     Stable,
1697     Unstable,
1698 }
1699
1700 pub struct RustcOptGroup {
1701     pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1702     pub name: &'static str,
1703     pub stability: OptionStability,
1704 }
1705
1706 impl RustcOptGroup {
1707     pub fn is_stable(&self) -> bool {
1708         self.stability == OptionStability::Stable
1709     }
1710
1711     pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1712     where
1713         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1714     {
1715         RustcOptGroup {
1716             name,
1717             apply: Box::new(f),
1718             stability: OptionStability::Stable,
1719         }
1720     }
1721
1722     pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1723     where
1724         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1725     {
1726         RustcOptGroup {
1727             name,
1728             apply: Box::new(f),
1729             stability: OptionStability::Unstable,
1730         }
1731     }
1732 }
1733
1734 // The `opt` local module holds wrappers around the `getopts` API that
1735 // adds extra rustc-specific metadata to each option; such metadata
1736 // is exposed by .  The public
1737 // functions below ending with `_u` are the functions that return
1738 // *unstable* options, i.e., options that are only enabled when the
1739 // user also passes the `-Z unstable-options` debugging flag.
1740 mod opt {
1741     // The `fn flag*` etc below are written so that we can use them
1742     // in the future; do not warn about them not being used right now.
1743     #![allow(dead_code)]
1744
1745     use getopts;
1746     use super::RustcOptGroup;
1747
1748     pub type R = RustcOptGroup;
1749     pub type S = &'static str;
1750
1751     fn stable<F>(name: S, f: F) -> R
1752     where
1753         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1754     {
1755         RustcOptGroup::stable(name, f)
1756     }
1757
1758     fn unstable<F>(name: S, f: F) -> R
1759     where
1760         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1761     {
1762         RustcOptGroup::unstable(name, f)
1763     }
1764
1765     fn longer(a: S, b: S) -> S {
1766         if a.len() > b.len() {
1767             a
1768         } else {
1769             b
1770         }
1771     }
1772
1773     pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1774         stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1775     }
1776     pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1777         stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1778     }
1779     pub fn flag_s(a: S, b: S, c: S) -> R {
1780         stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1781     }
1782     pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1783         stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1784     }
1785     pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1786         stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1787     }
1788
1789     pub fn opt(a: S, b: S, c: S, d: S) -> R {
1790         unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1791     }
1792     pub fn multi(a: S, b: S, c: S, d: S) -> R {
1793         unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1794     }
1795     pub fn flag(a: S, b: S, c: S) -> R {
1796         unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1797     }
1798     pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1799         unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1800     }
1801     pub fn flagmulti(a: S, b: S, c: S) -> R {
1802         unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1803     }
1804 }
1805
1806 /// Returns the "short" subset of the rustc command line options,
1807 /// including metadata for each option, such as whether the option is
1808 /// part of the stable long-term interface for rustc.
1809 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1810     vec![
1811         opt::flag_s("h", "help", "Display this message"),
1812         opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1813         opt::multi_s(
1814             "L",
1815             "",
1816             "Add a directory to the library search path. The
1817                              optional KIND can be one of dependency, crate, native,
1818                              framework, or all (the default).",
1819             "[KIND=]PATH",
1820         ),
1821         opt::multi_s(
1822             "l",
1823             "",
1824             "Link the generated crate(s) to the specified native
1825                              library NAME. The optional KIND can be one of
1826                              static, framework, or dylib (the default).",
1827             "[KIND=]NAME",
1828         ),
1829         make_crate_type_option(),
1830         opt::opt_s(
1831             "",
1832             "crate-name",
1833             "Specify the name of the crate being built",
1834             "NAME",
1835         ),
1836         opt::opt_s(
1837             "",
1838             "edition",
1839             "Specify which edition of the compiler to use when compiling code.",
1840             EDITION_NAME_LIST,
1841         ),
1842         opt::multi_s(
1843             "",
1844             "emit",
1845             "Comma separated list of types of output for \
1846              the compiler to emit",
1847             "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1848         ),
1849         opt::multi_s(
1850             "",
1851             "print",
1852             "Compiler information to print on stdout",
1853             "[crate-name|file-names|sysroot|cfg|target-list|\
1854              target-cpus|target-features|relocation-models|\
1855              code-models|tls-models|target-spec-json|native-static-libs]",
1856         ),
1857         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1858         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1859         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1860         opt::opt_s(
1861             "",
1862             "out-dir",
1863             "Write output to compiler-chosen filename \
1864              in <dir>",
1865             "DIR",
1866         ),
1867         opt::opt_s(
1868             "",
1869             "explain",
1870             "Provide a detailed explanation of an error \
1871              message",
1872             "OPT",
1873         ),
1874         opt::flag_s("", "test", "Build a test harness"),
1875         opt::opt_s(
1876             "",
1877             "target",
1878             "Target triple for which the code is compiled",
1879             "TARGET",
1880         ),
1881         opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1882         opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1883         opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1884         opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1885         opt::multi_s(
1886             "",
1887             "cap-lints",
1888             "Set the most restrictive lint level. \
1889              More restrictive lints are capped at this \
1890              level",
1891             "LEVEL",
1892         ),
1893         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1894         opt::flag_s("V", "version", "Print version info and exit"),
1895         opt::flag_s("v", "verbose", "Use verbose output"),
1896     ]
1897 }
1898
1899 /// Returns all rustc command line options, including metadata for
1900 /// each option, such as whether the option is part of the stable
1901 /// long-term interface for rustc.
1902 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1903     let mut opts = rustc_short_optgroups();
1904     opts.extend(vec![
1905         opt::multi_s(
1906             "",
1907             "extern",
1908             "Specify where an external rust library is located",
1909             "NAME[=PATH]",
1910         ),
1911         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1912         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1913         opt::opt_s(
1914             "",
1915             "error-format",
1916             "How errors and other messages are produced",
1917             "human|json|short",
1918         ),
1919         opt::multi_s(
1920             "",
1921             "json",
1922             "Configure the JSON output of the compiler",
1923             "CONFIG",
1924         ),
1925         opt::opt_s(
1926             "",
1927             "color",
1928             "Configure coloring of output:
1929                                  auto   = colorize, if output goes to a tty (default);
1930                                  always = always colorize output;
1931                                  never  = never colorize output",
1932             "auto|always|never",
1933         ),
1934         opt::opt(
1935             "",
1936             "pretty",
1937             "Pretty-print the input instead of compiling;
1938                   valid types are: `normal` (un-annotated source),
1939                   `expanded` (crates expanded), or
1940                   `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1941             "TYPE",
1942         ),
1943         opt::multi_s(
1944             "",
1945             "remap-path-prefix",
1946             "Remap source names in all output (compiler messages and output files)",
1947             "FROM=TO",
1948         ),
1949     ]);
1950     opts
1951 }
1952
1953 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1954                             error_format: ErrorOutputType)
1955                             -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1956     let mut lint_opts = vec![];
1957     let mut describe_lints = false;
1958
1959     for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1960         for lint_name in matches.opt_strs(level.as_str()) {
1961             if lint_name == "help" {
1962                 describe_lints = true;
1963             } else {
1964                 lint_opts.push((lint_name.replace("-", "_"), level));
1965             }
1966         }
1967     }
1968
1969     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1970         lint::Level::from_str(&cap)
1971             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1972     });
1973     (lint_opts, describe_lints, lint_cap)
1974 }
1975
1976 /// Parses the `--color` flag.
1977 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1978     match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1979         Some("auto") => ColorConfig::Auto,
1980         Some("always") => ColorConfig::Always,
1981         Some("never") => ColorConfig::Never,
1982
1983         None => ColorConfig::Auto,
1984
1985         Some(arg) => early_error(
1986             ErrorOutputType::default(),
1987             &format!(
1988                 "argument for `--color` must be auto, \
1989                  always or never (instead was `{}`)",
1990                 arg
1991             ),
1992         ),
1993     }
1994 }
1995
1996 /// Parse the `--json` flag.
1997 ///
1998 /// The first value returned is how to render JSON diagnostics, and the second
1999 /// is whether or not artifact notifications are enabled.
2000 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
2001     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
2002         HumanReadableErrorType::Default;
2003     let mut json_color = ColorConfig::Never;
2004     let mut json_artifact_notifications = false;
2005     for option in matches.opt_strs("json") {
2006         // For now conservatively forbid `--color` with `--json` since `--json`
2007         // won't actually be emitting any colors and anything colorized is
2008         // embedded in a diagnostic message anyway.
2009         if matches.opt_str("color").is_some() {
2010             early_error(
2011                 ErrorOutputType::default(),
2012                 "cannot specify the `--color` option with `--json`",
2013             );
2014         }
2015
2016         for sub_option in option.split(',') {
2017             match sub_option {
2018                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
2019                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
2020                 "artifacts" => json_artifact_notifications = true,
2021                 s => {
2022                     early_error(
2023                         ErrorOutputType::default(),
2024                         &format!("unknown `--json` option `{}`", s),
2025                     )
2026                 }
2027             }
2028         }
2029     }
2030     (json_rendered(json_color), json_artifact_notifications)
2031 }
2032
2033 /// Parses the `--error-format` flag.
2034 pub fn parse_error_format(
2035     matches: &getopts::Matches,
2036     color: ColorConfig,
2037     json_rendered: HumanReadableErrorType,
2038 ) -> ErrorOutputType {
2039     // We need the `opts_present` check because the driver will send us Matches
2040     // with only stable options if no unstable options are used. Since error-format
2041     // is unstable, it will not be present. We have to use `opts_present` not
2042     // `opt_present` because the latter will panic.
2043     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
2044         match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
2045             None |
2046             Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2047             Some("human-annotate-rs") => {
2048                 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
2049             },
2050             Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
2051             Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
2052             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
2053
2054             Some(arg) => early_error(
2055                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2056                 &format!(
2057                     "argument for `--error-format` must be `human`, `json` or \
2058                      `short` (instead was `{}`)",
2059                     arg
2060                 ),
2061             ),
2062         }
2063     } else {
2064         ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
2065     };
2066
2067     match error_format {
2068         ErrorOutputType::Json { .. } => {}
2069
2070         // Conservatively require that the `--json` argument is coupled with
2071         // `--error-format=json`. This means that `--json` is specified we
2072         // should actually be emitting JSON blobs.
2073         _ if matches.opt_strs("json").len() > 0 => {
2074             early_error(
2075                 ErrorOutputType::default(),
2076                 "using `--json` requires also using `--error-format=json`",
2077             );
2078         }
2079
2080         _ => {}
2081     }
2082
2083     return error_format;
2084 }
2085
2086 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
2087     let edition = match matches.opt_str("edition") {
2088         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
2089             early_error(
2090                 ErrorOutputType::default(),
2091                 &format!(
2092                     "argument for `--edition` must be one of: \
2093                      {}. (instead was `{}`)",
2094                     EDITION_NAME_LIST,
2095                     arg
2096                 ),
2097             ),
2098         ),
2099         None => DEFAULT_EDITION,
2100     };
2101
2102     if !edition.is_stable() && !nightly_options::is_nightly_build() {
2103         early_error(
2104                 ErrorOutputType::default(),
2105                 &format!(
2106                     "edition {} is unstable and only \
2107                      available for nightly builds of rustc.",
2108                     edition,
2109                 )
2110         )
2111     }
2112
2113     edition
2114 }
2115
2116 fn check_debug_option_stability(
2117     debugging_opts: &DebuggingOptions,
2118     error_format: ErrorOutputType,
2119     json_rendered: HumanReadableErrorType,
2120 ) {
2121     if !debugging_opts.unstable_options {
2122         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2123             early_error(
2124                 ErrorOutputType::Json { pretty: false, json_rendered },
2125                 "`--error-format=pretty-json` is unstable",
2126             );
2127         }
2128         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
2129             error_format {
2130             early_error(
2131                 ErrorOutputType::Json { pretty: false, json_rendered },
2132                 "`--error-format=human-annotate-rs` is unstable",
2133             );
2134         }
2135     }
2136 }
2137
2138 fn parse_output_types(
2139     debugging_opts: &DebuggingOptions,
2140     matches: &getopts::Matches,
2141     error_format: ErrorOutputType,
2142 ) -> OutputTypes {
2143     let mut output_types = BTreeMap::new();
2144     if !debugging_opts.parse_only {
2145         for list in matches.opt_strs("emit") {
2146             for output_type in list.split(',') {
2147                 let mut parts = output_type.splitn(2, '=');
2148                 let shorthand = parts.next().unwrap();
2149                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2150                     early_error(
2151                         error_format,
2152                         &format!(
2153                             "unknown emission type: `{}` - expected one of: {}",
2154                             shorthand,
2155                             OutputType::shorthands_display(),
2156                         ),
2157                     ),
2158                 );
2159                 let path = parts.next().map(PathBuf::from);
2160                 output_types.insert(output_type, path);
2161             }
2162         }
2163     };
2164     if output_types.is_empty() {
2165         output_types.insert(OutputType::Exe, None);
2166     }
2167     OutputTypes(output_types)
2168 }
2169
2170 fn should_override_cgus_and_disable_thinlto(
2171     output_types: &OutputTypes,
2172     matches: &getopts::Matches,
2173     error_format: ErrorOutputType,
2174     mut codegen_units: Option<usize>,
2175 ) -> (bool, Option<usize>) {
2176     let mut disable_thinlto = false;
2177     // Issue #30063: if user requests LLVM-related output to one
2178     // particular path, disable codegen-units.
2179     let incompatible: Vec<_> = output_types.0
2180         .iter()
2181         .map(|ot_path| ot_path.0)
2182         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2183         .map(|ot| ot.shorthand())
2184         .collect();
2185     if !incompatible.is_empty() {
2186         match codegen_units {
2187             Some(n) if n > 1 => {
2188                 if matches.opt_present("o") {
2189                     for ot in &incompatible {
2190                         early_warn(
2191                             error_format,
2192                             &format!(
2193                                 "`--emit={}` with `-o` incompatible with \
2194                                  `-C codegen-units=N` for N > 1",
2195                                 ot
2196                             ),
2197                         );
2198                     }
2199                     early_warn(error_format, "resetting to default -C codegen-units=1");
2200                     codegen_units = Some(1);
2201                     disable_thinlto = true;
2202                 }
2203             }
2204             _ => {
2205                 codegen_units = Some(1);
2206                 disable_thinlto = true;
2207             }
2208         }
2209     }
2210
2211     if codegen_units == Some(0) {
2212         early_error(
2213             error_format,
2214             "value for codegen units must be a positive non-zero integer",
2215         );
2216     }
2217
2218     (disable_thinlto, codegen_units)
2219 }
2220
2221 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
2222     if debugging_opts.threads == 0 {
2223         early_error(
2224             error_format,
2225             "value for threads must be a positive non-zero integer",
2226         );
2227     }
2228
2229     if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
2230         early_error(
2231             error_format,
2232             "optimization fuel is incompatible with multiple threads",
2233         );
2234     }
2235 }
2236
2237 fn select_incremental_path(
2238     debugging_opts: &DebuggingOptions,
2239     cg: &CodegenOptions,
2240     error_format: ErrorOutputType,
2241 ) -> Option<PathBuf> {
2242     match (&debugging_opts.incremental, &cg.incremental) {
2243         (Some(path1), Some(path2)) => {
2244             if path1 != path2 {
2245                 early_error(
2246                     error_format,
2247                     &format!(
2248                         "conflicting paths for `-Z incremental` and \
2249                          `-C incremental` specified: {} versus {}",
2250                         path1, path2
2251                     ),
2252                 );
2253             } else {
2254                 Some(path1)
2255             }
2256         }
2257         (Some(path), None) => Some(path),
2258         (None, Some(path)) => Some(path),
2259         (None, None) => None,
2260     }.map(|m| PathBuf::from(m))
2261 }
2262
2263 fn collect_print_requests(
2264     cg: &mut CodegenOptions,
2265     dopts: &mut DebuggingOptions,
2266     matches: &getopts::Matches,
2267     error_format: ErrorOutputType,
2268 ) -> Vec<PrintRequest> {
2269     let mut prints = Vec::<PrintRequest>::new();
2270     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2271         prints.push(PrintRequest::TargetCPUs);
2272         cg.target_cpu = None;
2273     };
2274     if cg.target_feature == "help" {
2275         prints.push(PrintRequest::TargetFeatures);
2276         cg.target_feature = String::new();
2277     }
2278     if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2279         prints.push(PrintRequest::RelocationModels);
2280         cg.relocation_model = None;
2281     }
2282     if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2283         prints.push(PrintRequest::CodeModels);
2284         cg.code_model = None;
2285     }
2286     if dopts
2287         .tls_model
2288         .as_ref()
2289         .map_or(false, |s| s == "help")
2290     {
2291         prints.push(PrintRequest::TlsModels);
2292         dopts.tls_model = None;
2293     }
2294
2295     prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2296         "crate-name" => PrintRequest::CrateName,
2297         "file-names" => PrintRequest::FileNames,
2298         "sysroot" => PrintRequest::Sysroot,
2299         "cfg" => PrintRequest::Cfg,
2300         "target-list" => PrintRequest::TargetList,
2301         "target-cpus" => PrintRequest::TargetCPUs,
2302         "target-features" => PrintRequest::TargetFeatures,
2303         "relocation-models" => PrintRequest::RelocationModels,
2304         "code-models" => PrintRequest::CodeModels,
2305         "tls-models" => PrintRequest::TlsModels,
2306         "native-static-libs" => PrintRequest::NativeStaticLibs,
2307         "target-spec-json" => {
2308             if dopts.unstable_options {
2309                 PrintRequest::TargetSpec
2310             } else {
2311                 early_error(
2312                     error_format,
2313                     "the `-Z unstable-options` flag must also be passed to \
2314                      enable the target-spec-json print option",
2315                 );
2316             }
2317         }
2318         req => early_error(error_format, &format!("unknown print request `{}`", req)),
2319     }));
2320
2321     prints
2322 }
2323
2324 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
2325     match matches.opt_str("target") {
2326         Some(target) if target.ends_with(".json") => {
2327             let path = Path::new(&target);
2328             TargetTriple::from_path(&path).unwrap_or_else(|_|
2329                 early_error(error_format, &format!("target file {:?} does not exist", path)))
2330         }
2331         Some(target) => TargetTriple::TargetTriple(target),
2332         _ => TargetTriple::from_triple(host_triple()),
2333     }
2334 }
2335
2336 fn parse_opt_level(
2337     matches: &getopts::Matches,
2338     cg: &CodegenOptions,
2339     error_format: ErrorOutputType,
2340 ) -> OptLevel {
2341     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2342     // to use them interchangeably. However, because they're technically different flags,
2343     // we need to work out manually which should take precedence if both are supplied (i.e.
2344     // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2345     // comparing them. Note that if a flag is not found, its position will be `None`, which
2346     // always compared less than `Some(_)`.
2347     let max_o = matches.opt_positions("O").into_iter().max();
2348     let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2349         if let Some("opt-level") = s.splitn(2, '=').next() {
2350             Some(i)
2351         } else {
2352             None
2353         }
2354     }).max();
2355     if max_o > max_c {
2356         OptLevel::Default
2357     } else {
2358         match cg.opt_level.as_ref().map(String::as_ref) {
2359             None => OptLevel::No,
2360             Some("0") => OptLevel::No,
2361             Some("1") => OptLevel::Less,
2362             Some("2") => OptLevel::Default,
2363             Some("3") => OptLevel::Aggressive,
2364             Some("s") => OptLevel::Size,
2365             Some("z") => OptLevel::SizeMin,
2366             Some(arg) => {
2367                 early_error(
2368                     error_format,
2369                     &format!(
2370                         "optimization level needs to be \
2371                             between 0-3, s or z (instead was `{}`)",
2372                         arg
2373                     ),
2374                 );
2375             }
2376         }
2377     }
2378 }
2379
2380 fn select_debuginfo(
2381     matches: &getopts::Matches,
2382     cg: &CodegenOptions,
2383     error_format: ErrorOutputType,
2384 ) -> DebugInfo {
2385     let max_g = matches.opt_positions("g").into_iter().max();
2386     let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2387         if let Some("debuginfo") = s.splitn(2, '=').next() {
2388             Some(i)
2389         } else {
2390             None
2391         }
2392     }).max();
2393     if max_g > max_c {
2394         DebugInfo::Full
2395     } else {
2396         match cg.debuginfo {
2397             None | Some(0) => DebugInfo::None,
2398             Some(1) => DebugInfo::Limited,
2399             Some(2) => DebugInfo::Full,
2400             Some(arg) => {
2401                 early_error(
2402                     error_format,
2403                     &format!(
2404                         "debug info level needs to be between \
2405                          0-2 (instead was `{}`)",
2406                         arg
2407                     ),
2408                 );
2409             }
2410         }
2411     }
2412 }
2413
2414 fn parse_libs(
2415     matches: &getopts::Matches,
2416     error_format: ErrorOutputType,
2417 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
2418     matches
2419         .opt_strs("l")
2420         .into_iter()
2421         .map(|s| {
2422             // Parse string of the form "[KIND=]lib[:new_name]",
2423             // where KIND is one of "dylib", "framework", "static".
2424             let mut parts = s.splitn(2, '=');
2425             let kind = parts.next().unwrap();
2426             let (name, kind) = match (parts.next(), kind) {
2427                 (None, name) => (name, None),
2428                 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
2429                 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
2430                 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
2431                 (Some(name), "static-nobundle") => {
2432                     (name, Some(NativeLibraryKind::NativeStaticNobundle))
2433                 }
2434                 (_, s) => {
2435                     early_error(
2436                         error_format,
2437                         &format!(
2438                             "unknown library kind `{}`, expected \
2439                              one of dylib, framework, or static",
2440                             s
2441                         ),
2442                     );
2443                 }
2444             };
2445             if kind == Some(NativeLibraryKind::NativeStaticNobundle) &&
2446                 !nightly_options::is_nightly_build() {
2447                 early_error(
2448                     error_format,
2449                     &format!(
2450                         "the library kind 'static-nobundle' is only \
2451                          accepted on the nightly compiler"
2452                     ),
2453                 );
2454             }
2455             let mut name_parts = name.splitn(2, ':');
2456             let name = name_parts.next().unwrap();
2457             let new_name = name_parts.next();
2458             (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2459         })
2460         .collect()
2461 }
2462
2463 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2464     match dopts.borrowck.as_ref().map(|s| &s[..]) {
2465         None | Some("migrate") => BorrowckMode::Migrate,
2466         Some("mir") => BorrowckMode::Mir,
2467         Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2468     }
2469 }
2470
2471 pub fn parse_externs(
2472     matches: &getopts::Matches,
2473     debugging_opts: &DebuggingOptions,
2474     error_format: ErrorOutputType,
2475 ) -> Externs {
2476     let is_unstable_enabled = debugging_opts.unstable_options;
2477     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2478     for arg in matches.opt_strs("extern") {
2479         let mut parts = arg.splitn(2, '=');
2480         let name = parts
2481             .next()
2482             .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
2483         let path = parts.next().map(|s| s.to_string());
2484
2485         let mut name_parts = name.splitn(2, ':');
2486         let first_part = name_parts.next();
2487         let second_part = name_parts.next();
2488         let (options, name) = match (first_part, second_part) {
2489             (Some(opts), Some(name)) => (Some(opts), name),
2490             (Some(name), None) => (None, name),
2491             (None, None) => early_error(error_format, "--extern name must not be empty"),
2492             _ => unreachable!(),
2493         };
2494
2495         let entry = externs.entry(name.to_owned());
2496
2497         use std::collections::btree_map::Entry;
2498
2499         let entry = if let Some(path) = path {
2500             // --extern prelude_name=some_file.rlib
2501             match entry {
2502                 Entry::Vacant(vacant) => {
2503                     let files = BTreeSet::from_iter(iter::once(path));
2504                     vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2505                 }
2506                 Entry::Occupied(occupied) => {
2507                     let ext_ent = occupied.into_mut();
2508                     match ext_ent {
2509                         ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2510                             files.insert(path);
2511                         }
2512                         ExternEntry {
2513                             location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2514                             ..
2515                         } => {
2516                             // Exact paths take precedence over search directories.
2517                             let files = BTreeSet::from_iter(iter::once(path));
2518                             *location = ExternLocation::ExactPaths(files);
2519                         }
2520                     }
2521                     ext_ent
2522                 }
2523             }
2524         } else {
2525             // --extern prelude_name
2526             match entry {
2527                 Entry::Vacant(vacant) => {
2528                     vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2529                 }
2530                 Entry::Occupied(occupied) => {
2531                     // Ignore if already specified.
2532                     occupied.into_mut()
2533                 }
2534             }
2535         };
2536
2537         let mut is_private_dep = false;
2538         let mut add_prelude = true;
2539         if let Some(opts) = options {
2540             if !is_unstable_enabled {
2541                 early_error(
2542                     error_format,
2543                     "the `-Z unstable-options` flag must also be passed to \
2544                      enable `--extern options",
2545                 );
2546             }
2547             for opt in opts.split(',') {
2548                 match opt {
2549                     "priv" => is_private_dep = true,
2550                     "noprelude" => {
2551                         if let ExternLocation::ExactPaths(_) = &entry.location {
2552                             add_prelude = false;
2553                         } else {
2554                             early_error(
2555                                 error_format,
2556                                 "the `noprelude` --extern option requires a file path",
2557                             );
2558                         }
2559                     }
2560                     _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
2561                 }
2562             }
2563         }
2564
2565         // Crates start out being not private, and go to being private `priv`
2566         // is specified.
2567         entry.is_private_dep |= is_private_dep;
2568         // If any flag is missing `noprelude`, then add to the prelude.
2569         entry.add_prelude |= add_prelude;
2570     }
2571     Externs(externs)
2572 }
2573
2574 fn parse_remap_path_prefix(
2575     matches: &getopts::Matches,
2576     error_format: ErrorOutputType
2577 ) -> Vec<(PathBuf, PathBuf)> {
2578     matches
2579         .opt_strs("remap-path-prefix")
2580         .into_iter()
2581         .map(|remap| {
2582             let mut parts = remap.rsplitn(2, '='); // reverse iterator
2583             let to = parts.next();
2584             let from = parts.next();
2585             match (from, to) {
2586                 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2587                 _ => early_error(
2588                     error_format,
2589                     "--remap-path-prefix must contain '=' between FROM and TO",
2590                 ),
2591             }
2592         })
2593         .collect()
2594 }
2595
2596 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2597     let color = parse_color(matches);
2598
2599     let edition = parse_crate_edition(matches);
2600
2601     let (json_rendered, json_artifact_notifications) = parse_json(matches);
2602
2603     let error_format = parse_error_format(matches, color, json_rendered);
2604
2605     let unparsed_crate_types = matches.opt_strs("crate-type");
2606     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2607         .unwrap_or_else(|e| early_error(error_format, &e[..]));
2608
2609     let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2610
2611     let mut debugging_opts = build_debugging_options(matches, error_format);
2612     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2613
2614     let output_types = parse_output_types(&debugging_opts, matches, error_format);
2615
2616     let mut cg = build_codegen_options(matches, error_format);
2617     let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2618         &output_types,
2619         matches,
2620         error_format,
2621         cg.codegen_units,
2622     );
2623
2624     check_thread_count(&debugging_opts, error_format);
2625
2626     let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
2627
2628     if debugging_opts.profile && incremental.is_some() {
2629         early_error(
2630             error_format,
2631             "can't instrument with gcov profiling when compiling incrementally",
2632         );
2633     }
2634
2635     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2636         early_error(
2637             error_format,
2638             "options `-C profile-generate` and `-C profile-use` are exclusive",
2639         );
2640     }
2641
2642     let prints = collect_print_requests(
2643         &mut cg,
2644         &mut debugging_opts,
2645         matches,
2646         error_format,
2647     );
2648
2649     let cg = cg;
2650
2651     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2652     let target_triple = parse_target_triple(matches, error_format);
2653     let opt_level = parse_opt_level(matches, &cg, error_format);
2654     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2655     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2656     // for more details.
2657     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2658     let debuginfo = select_debuginfo(matches, &cg, error_format);
2659
2660     let mut search_paths = vec![];
2661     for s in &matches.opt_strs("L") {
2662         search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2663     }
2664
2665     let libs = parse_libs(matches, error_format);
2666
2667     let test = matches.opt_present("test");
2668
2669     let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2670
2671     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2672         early_warn(
2673             error_format,
2674             "-C remark requires \"-C debuginfo=n\" to show source locations",
2675         );
2676     }
2677
2678     let externs = parse_externs(matches, &debugging_opts, error_format);
2679
2680     let crate_name = matches.opt_str("crate-name");
2681
2682     let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2683
2684     let pretty = parse_pretty(matches, &debugging_opts, error_format);
2685
2686     Options {
2687         crate_types,
2688         optimize: opt_level,
2689         debuginfo,
2690         lint_opts,
2691         lint_cap,
2692         describe_lints,
2693         output_types,
2694         search_paths,
2695         maybe_sysroot: sysroot_opt,
2696         target_triple,
2697         test,
2698         incremental,
2699         debugging_opts,
2700         prints,
2701         borrowck_mode,
2702         cg,
2703         error_format,
2704         externs,
2705         crate_name,
2706         alt_std_name: None,
2707         libs,
2708         unstable_features: UnstableFeatures::from_environment(),
2709         debug_assertions,
2710         actually_rustdoc: false,
2711         cli_forced_codegen_units: codegen_units,
2712         cli_forced_thinlto_off: disable_thinlto,
2713         remap_path_prefix,
2714         edition,
2715         json_artifact_notifications,
2716         pretty,
2717     }
2718 }
2719
2720 fn parse_pretty(
2721     matches: &getopts::Matches,
2722     debugging_opts: &DebuggingOptions,
2723     efmt: ErrorOutputType,
2724 ) -> Option<PpMode> {
2725     let pretty = if debugging_opts.unstable_options {
2726         matches.opt_default("pretty", "normal").map(|a| {
2727             // stable pretty-print variants only
2728             parse_pretty_inner(efmt, &a, false)
2729         })
2730     } else {
2731         None
2732     };
2733
2734     return if pretty.is_none() {
2735         debugging_opts.unpretty.as_ref().map(|a| {
2736             // extended with unstable pretty-print variants
2737             parse_pretty_inner(efmt, &a, true)
2738         })
2739     } else {
2740         pretty
2741     };
2742
2743     fn parse_pretty_inner(
2744         efmt: ErrorOutputType,
2745         name: &str,
2746         extended: bool,
2747     ) -> PpMode {
2748         use PpMode::*;
2749         use PpSourceMode::*;
2750         let first = match (name, extended) {
2751             ("normal", _) => PpmSource(PpmNormal),
2752             ("identified", _) => PpmSource(PpmIdentified),
2753             ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
2754             ("expanded", _) => PpmSource(PpmExpanded),
2755             ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
2756             ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
2757             ("hir", true) => PpmHir(PpmNormal),
2758             ("hir,identified", true) => PpmHir(PpmIdentified),
2759             ("hir,typed", true) => PpmHir(PpmTyped),
2760             ("hir-tree", true) => PpmHirTree(PpmNormal),
2761             ("mir", true) => PpmMir,
2762             ("mir-cfg", true) => PpmMirCFG,
2763             _ => {
2764                 if extended {
2765                     early_error(efmt, &format!("argument to `unpretty` must be one of `normal`, \
2766                                         `expanded`, `identified`, `expanded,identified`, \
2767                                         `expanded,hygiene`, `everybody_loops`, \
2768                                         `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
2769                                         `mir` or `mir-cfg`; got {}",
2770                                         name));
2771                 } else {
2772                     early_error(efmt, &format!("argument to `pretty` must be one of `normal`, \
2773                                         `expanded`, `identified`, or `expanded,identified`; got {}",
2774                                         name));
2775                 }
2776             }
2777         };
2778         first
2779     }
2780 }
2781
2782 pub fn make_crate_type_option() -> RustcOptGroup {
2783     opt::multi_s(
2784         "",
2785         "crate-type",
2786         "Comma separated list of types of crates
2787                                 for the compiler to emit",
2788         "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2789     )
2790 }
2791
2792 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2793     let mut crate_types: Vec<CrateType> = Vec::new();
2794     for unparsed_crate_type in &list_list {
2795         for part in unparsed_crate_type.split(',') {
2796             let new_part = match part {
2797                 "lib" => default_lib_output(),
2798                 "rlib" => CrateType::Rlib,
2799                 "staticlib" => CrateType::Staticlib,
2800                 "dylib" => CrateType::Dylib,
2801                 "cdylib" => CrateType::Cdylib,
2802                 "bin" => CrateType::Executable,
2803                 "proc-macro" => CrateType::ProcMacro,
2804                 _ => return Err(format!("unknown crate type: `{}`", part))
2805             };
2806             if !crate_types.contains(&new_part) {
2807                 crate_types.push(new_part)
2808             }
2809         }
2810     }
2811
2812     Ok(crate_types)
2813 }
2814
2815 pub mod nightly_options {
2816     use getopts;
2817     use rustc_feature::UnstableFeatures;
2818     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2819     use crate::early_error;
2820
2821     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2822         is_nightly_build()
2823             && matches
2824                 .opt_strs("Z")
2825                 .iter()
2826                 .any(|x| *x == "unstable-options")
2827     }
2828
2829     pub fn is_nightly_build() -> bool {
2830         UnstableFeatures::from_environment().is_nightly_build()
2831     }
2832
2833     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2834         let has_z_unstable_option = matches
2835             .opt_strs("Z")
2836             .iter()
2837             .any(|x| *x == "unstable-options");
2838         let really_allows_unstable_options =
2839             UnstableFeatures::from_environment().is_nightly_build();
2840
2841         for opt in flags.iter() {
2842             if opt.stability == OptionStability::Stable {
2843                 continue;
2844             }
2845             if !matches.opt_present(opt.name) {
2846                 continue;
2847             }
2848             if opt.name != "Z" && !has_z_unstable_option {
2849                 early_error(
2850                     ErrorOutputType::default(),
2851                     &format!(
2852                         "the `-Z unstable-options` flag must also be passed to enable \
2853                          the flag `{}`",
2854                         opt.name
2855                     ),
2856                 );
2857             }
2858             if really_allows_unstable_options {
2859                 continue;
2860             }
2861             match opt.stability {
2862                 OptionStability::Unstable => {
2863                     let msg = format!(
2864                         "the option `{}` is only accepted on the \
2865                          nightly compiler",
2866                         opt.name
2867                     );
2868                     early_error(ErrorOutputType::default(), &msg);
2869                 }
2870                 OptionStability::Stable => {}
2871             }
2872         }
2873     }
2874 }
2875
2876 impl fmt::Display for CrateType {
2877     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2878         match *self {
2879             CrateType::Executable => "bin".fmt(f),
2880             CrateType::Dylib => "dylib".fmt(f),
2881             CrateType::Rlib => "rlib".fmt(f),
2882             CrateType::Staticlib => "staticlib".fmt(f),
2883             CrateType::Cdylib => "cdylib".fmt(f),
2884             CrateType::ProcMacro => "proc-macro".fmt(f),
2885         }
2886     }
2887 }
2888
2889 #[derive(Copy, Clone, PartialEq, Debug)]
2890 pub enum PpSourceMode {
2891     PpmNormal,
2892     PpmEveryBodyLoops,
2893     PpmExpanded,
2894     PpmIdentified,
2895     PpmExpandedIdentified,
2896     PpmExpandedHygiene,
2897     PpmTyped,
2898 }
2899
2900 #[derive(Copy, Clone, PartialEq, Debug)]
2901 pub enum PpMode {
2902     PpmSource(PpSourceMode),
2903     PpmHir(PpSourceMode),
2904     PpmHirTree(PpSourceMode),
2905     PpmMir,
2906     PpmMirCFG,
2907 }
2908
2909 impl PpMode {
2910     pub fn needs_ast_map(&self) -> bool {
2911         use PpMode::*;
2912         use PpSourceMode::*;
2913         match *self {
2914             PpmSource(PpmNormal) |
2915             PpmSource(PpmEveryBodyLoops) |
2916             PpmSource(PpmIdentified) => false,
2917
2918             PpmSource(PpmExpanded) |
2919             PpmSource(PpmExpandedIdentified) |
2920             PpmSource(PpmExpandedHygiene) |
2921             PpmHir(_) |
2922             PpmHirTree(_) |
2923             PpmMir |
2924             PpmMirCFG => true,
2925             PpmSource(PpmTyped) => panic!("invalid state"),
2926         }
2927     }
2928
2929     pub fn needs_analysis(&self) -> bool {
2930         use PpMode::*;
2931         match *self {
2932             PpmMir | PpmMirCFG => true,
2933             _ => false,
2934         }
2935     }
2936 }
2937
2938 /// Command-line arguments passed to the compiler have to be incorporated with
2939 /// the dependency tracking system for incremental compilation. This module
2940 /// provides some utilities to make this more convenient.
2941 ///
2942 /// The values of all command-line arguments that are relevant for dependency
2943 /// tracking are hashed into a single value that determines whether the
2944 /// incremental compilation cache can be re-used or not. This hashing is done
2945 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2946 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2947 /// the hash of which is order dependent, but we might not want the order of
2948 /// arguments to make a difference for the hash).
2949 ///
2950 /// However, since the value provided by `Hash::hash` often *is* suitable,
2951 /// especially for primitive types, there is the
2952 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2953 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2954 /// we have an opt-in scheme here, so one is hopefully forced to think about
2955 /// how the hash should be calculated when adding a new command-line argument.
2956 mod dep_tracking {
2957     use crate::lint;
2958     use crate::utils::NativeLibraryKind;
2959     use std::collections::BTreeMap;
2960     use std::hash::Hash;
2961     use std::path::PathBuf;
2962     use std::collections::hash_map::DefaultHasher;
2963     use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2964                 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2965                 SymbolManglingVersion};
2966     use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2967     use syntax_pos::edition::Edition;
2968     use rustc_feature::UnstableFeatures;
2969
2970     pub trait DepTrackingHash {
2971         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2972     }
2973
2974     macro_rules! impl_dep_tracking_hash_via_hash {
2975         ($t:ty) => (
2976             impl DepTrackingHash for $t {
2977                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2978                     Hash::hash(self, hasher);
2979                 }
2980             }
2981         )
2982     }
2983
2984     macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2985         ($t:ty) => (
2986             impl DepTrackingHash for Vec<$t> {
2987                 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2988                     let mut elems: Vec<&$t> = self.iter().collect();
2989                     elems.sort();
2990                     Hash::hash(&elems.len(), hasher);
2991                     for (index, elem) in elems.iter().enumerate() {
2992                         Hash::hash(&index, hasher);
2993                         DepTrackingHash::hash(*elem, hasher, error_format);
2994                     }
2995                 }
2996             }
2997         );
2998     }
2999
3000     impl_dep_tracking_hash_via_hash!(bool);
3001     impl_dep_tracking_hash_via_hash!(usize);
3002     impl_dep_tracking_hash_via_hash!(u64);
3003     impl_dep_tracking_hash_via_hash!(String);
3004     impl_dep_tracking_hash_via_hash!(PathBuf);
3005     impl_dep_tracking_hash_via_hash!(lint::Level);
3006     impl_dep_tracking_hash_via_hash!(Option<bool>);
3007     impl_dep_tracking_hash_via_hash!(Option<usize>);
3008     impl_dep_tracking_hash_via_hash!(Option<String>);
3009     impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
3010     impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
3011     impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
3012     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
3013     impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
3014     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
3015     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
3016     impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
3017     impl_dep_tracking_hash_via_hash!(CrateType);
3018     impl_dep_tracking_hash_via_hash!(MergeFunctions);
3019     impl_dep_tracking_hash_via_hash!(PanicStrategy);
3020     impl_dep_tracking_hash_via_hash!(RelroLevel);
3021     impl_dep_tracking_hash_via_hash!(Passes);
3022     impl_dep_tracking_hash_via_hash!(OptLevel);
3023     impl_dep_tracking_hash_via_hash!(LtoCli);
3024     impl_dep_tracking_hash_via_hash!(DebugInfo);
3025     impl_dep_tracking_hash_via_hash!(UnstableFeatures);
3026     impl_dep_tracking_hash_via_hash!(OutputTypes);
3027     impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
3028     impl_dep_tracking_hash_via_hash!(Sanitizer);
3029     impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
3030     impl_dep_tracking_hash_via_hash!(TargetTriple);
3031     impl_dep_tracking_hash_via_hash!(Edition);
3032     impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
3033     impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
3034     impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
3035
3036     impl_dep_tracking_hash_for_sortable_vec_of!(String);
3037     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
3038     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
3039     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
3040     impl_dep_tracking_hash_for_sortable_vec_of!((
3041         String,
3042         Option<String>,
3043         Option<NativeLibraryKind>
3044     ));
3045     impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
3046     impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
3047
3048     impl<T1, T2> DepTrackingHash for (T1, T2)
3049     where
3050         T1: DepTrackingHash,
3051         T2: DepTrackingHash,
3052     {
3053         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
3054             Hash::hash(&0, hasher);
3055             DepTrackingHash::hash(&self.0, hasher, error_format);
3056             Hash::hash(&1, hasher);
3057             DepTrackingHash::hash(&self.1, hasher, error_format);
3058         }
3059     }
3060
3061     impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
3062     where
3063         T1: DepTrackingHash,
3064         T2: DepTrackingHash,
3065         T3: DepTrackingHash,
3066     {
3067         fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
3068             Hash::hash(&0, hasher);
3069             DepTrackingHash::hash(&self.0, hasher, error_format);
3070             Hash::hash(&1, hasher);
3071             DepTrackingHash::hash(&self.1, hasher, error_format);
3072             Hash::hash(&2, hasher);
3073             DepTrackingHash::hash(&self.2, hasher, error_format);
3074         }
3075     }
3076
3077     // This is a stable hash because BTreeMap is a sorted container
3078     pub fn stable_hash(
3079         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
3080         hasher: &mut DefaultHasher,
3081         error_format: ErrorOutputType,
3082     ) {
3083         for (key, sub_hash) in sub_hashes {
3084             // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
3085             // the keys, as they are just plain strings
3086             Hash::hash(&key.len(), hasher);
3087             Hash::hash(key, hasher);
3088             sub_hash.hash(hasher, error_format);
3089         }
3090     }
3091 }