]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_session/src/config.rs
Rollup merge of #89621 - digama0:patch-2, r=yaahc
[rust.git] / compiler / rustc_session / src / config.rs
1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
3
4 pub use crate::options::*;
5
6 use crate::lint;
7 use crate::search_paths::SearchPath;
8 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
9 use crate::{early_error, early_warn, Session};
10
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
13
14 use rustc_target::abi::{Align, TargetDataLayout};
15 use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TargetWarnings};
16
17 use rustc_serialize::json;
18
19 use crate::parse::CrateConfig;
20 use rustc_feature::UnstableFeatures;
21 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
22 use rustc_span::source_map::{FileName, FilePathMapping};
23 use rustc_span::symbol::{sym, Symbol};
24 use rustc_span::RealFileName;
25 use rustc_span::SourceFileHashAlgorithm;
26
27 use rustc_errors::emitter::HumanReadableErrorType;
28 use rustc_errors::{ColorConfig, HandlerFlags};
29
30 use std::collections::btree_map::{
31     Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
32 };
33 use std::collections::{BTreeMap, BTreeSet};
34 use std::fmt;
35 use std::hash::Hash;
36 use std::iter::{self, FromIterator};
37 use std::path::{Path, PathBuf};
38 use std::str::{self, FromStr};
39
40 /// The different settings that the `-C strip` flag can have.
41 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
42 pub enum Strip {
43     /// Do not strip at all.
44     None,
45
46     /// Strip debuginfo.
47     Debuginfo,
48
49     /// Strip all symbols.
50     Symbols,
51 }
52
53 /// The different settings that the `-C control-flow-guard` flag can have.
54 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
55 pub enum CFGuard {
56     /// Do not emit Control Flow Guard metadata or checks.
57     Disabled,
58
59     /// Emit Control Flow Guard metadata but no checks.
60     NoChecks,
61
62     /// Emit Control Flow Guard metadata and checks.
63     Checks,
64 }
65
66 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
67 pub enum OptLevel {
68     No,         // -O0
69     Less,       // -O1
70     Default,    // -O2
71     Aggressive, // -O3
72     Size,       // -Os
73     SizeMin,    // -Oz
74 }
75
76 impl_stable_hash_via_hash!(OptLevel);
77
78 /// This is what the `LtoCli` values get mapped to after resolving defaults and
79 /// and taking other command line options into account.
80 ///
81 /// Note that linker plugin-based LTO is a different mechanism entirely.
82 #[derive(Clone, PartialEq)]
83 pub enum Lto {
84     /// Don't do any LTO whatsoever.
85     No,
86
87     /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
88     Thin,
89
90     /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
91     /// only relevant if multiple CGUs are used.
92     ThinLocal,
93
94     /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
95     Fat,
96 }
97
98 /// The different settings that the `-C lto` flag can have.
99 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
100 pub enum LtoCli {
101     /// `-C lto=no`
102     No,
103     /// `-C lto=yes`
104     Yes,
105     /// `-C lto`
106     NoParam,
107     /// `-C lto=thin`
108     Thin,
109     /// `-C lto=fat`
110     Fat,
111     /// No `-C lto` flag passed
112     Unspecified,
113 }
114
115 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
116 /// document highlighting each span of every statement (including terminators). `Terminator` and
117 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
118 /// computed span for the block, representing the entire range, covering the block's terminator and
119 /// all of its statements.
120 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
121 pub enum MirSpanview {
122     /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
123     Statement,
124     /// `-Z dump_mir_spanview=terminator`
125     Terminator,
126     /// `-Z dump_mir_spanview=block`
127     Block,
128 }
129
130 /// The different settings that the `-Z instrument-coverage` flag can have.
131 ///
132 /// Coverage instrumentation now supports combining `-Z instrument-coverage`
133 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
134 /// and higher). Nevertheless, there are many variables, depending on options
135 /// selected, code structure, and enabled attributes. If errors are encountered,
136 /// either while compiling or when generating `llvm-cov show` reports, consider
137 /// lowering the optimization level, including or excluding `-C link-dead-code`,
138 /// or using `-Z instrument-coverage=except-unused-functions` or `-Z
139 /// instrument-coverage=except-unused-generics`.
140 ///
141 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
142 /// coverage map, it will not attempt to generate synthetic functions for unused
143 /// (and not code-generated) functions (whether they are generic or not). As a
144 /// result, non-codegenned functions will not be included in the coverage map,
145 /// and will not appear, as covered or uncovered, in coverage reports.
146 ///
147 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
148 /// unless the function has type parameters.
149 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
150 pub enum InstrumentCoverage {
151     /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
152     All,
153     /// `-Z instrument-coverage=except-unused-generics`
154     ExceptUnusedGenerics,
155     /// `-Z instrument-coverage=except-unused-functions`
156     ExceptUnusedFunctions,
157     /// `-Z instrument-coverage=off` (or `no`, etc.)
158     Off,
159 }
160
161 #[derive(Clone, PartialEq, Hash, Debug)]
162 pub enum LinkerPluginLto {
163     LinkerPlugin(PathBuf),
164     LinkerPluginAuto,
165     Disabled,
166 }
167
168 /// Used with `-Z assert-incr-state`.
169 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
170 pub enum IncrementalStateAssertion {
171     /// Found and loaded an existing session directory.
172     ///
173     /// Note that this says nothing about whether any particular query
174     /// will be found to be red or green.
175     Loaded,
176     /// Did not load an existing session directory.
177     NotLoaded,
178 }
179
180 impl LinkerPluginLto {
181     pub fn enabled(&self) -> bool {
182         match *self {
183             LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
184             LinkerPluginLto::Disabled => false,
185         }
186     }
187 }
188
189 /// The different settings that can be enabled via the `-Z location-detail` flag.
190 #[derive(Clone, PartialEq, Hash, Debug)]
191 pub struct LocationDetail {
192     pub file: bool,
193     pub line: bool,
194     pub column: bool,
195 }
196
197 impl LocationDetail {
198     pub fn all() -> Self {
199         Self { file: true, line: true, column: true }
200     }
201 }
202
203 #[derive(Clone, PartialEq, Hash, Debug)]
204 pub enum SwitchWithOptPath {
205     Enabled(Option<PathBuf>),
206     Disabled,
207 }
208
209 impl SwitchWithOptPath {
210     pub fn enabled(&self) -> bool {
211         match *self {
212             SwitchWithOptPath::Enabled(_) => true,
213             SwitchWithOptPath::Disabled => false,
214         }
215     }
216 }
217
218 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
219 #[derive(Encodable, Decodable)]
220 pub enum SymbolManglingVersion {
221     Legacy,
222     V0,
223 }
224
225 impl_stable_hash_via_hash!(SymbolManglingVersion);
226
227 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
228 pub enum DebugInfo {
229     None,
230     Limited,
231     Full,
232 }
233
234 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
235 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
236 /// uses DWARF for debug-information.
237 ///
238 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
239 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
240 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
241 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
242 /// them in the object file in such a way that the linker will skip them.
243 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
244 pub enum SplitDwarfKind {
245     /// Sections which do not require relocation are written into object file but ignored by the
246     /// linker.
247     Single,
248     /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
249     /// which is ignored by the linker.
250     Split,
251 }
252
253 impl FromStr for SplitDwarfKind {
254     type Err = ();
255
256     fn from_str(s: &str) -> Result<Self, ()> {
257         Ok(match s {
258             "single" => SplitDwarfKind::Single,
259             "split" => SplitDwarfKind::Split,
260             _ => return Err(()),
261         })
262     }
263 }
264
265 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
266 #[derive(Encodable, Decodable)]
267 pub enum OutputType {
268     Bitcode,
269     Assembly,
270     LlvmAssembly,
271     Mir,
272     Metadata,
273     Object,
274     Exe,
275     DepInfo,
276 }
277
278 impl_stable_hash_via_hash!(OutputType);
279
280 impl OutputType {
281     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
282         match *self {
283             OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
284             OutputType::Bitcode
285             | OutputType::Assembly
286             | OutputType::LlvmAssembly
287             | OutputType::Mir
288             | OutputType::Object => false,
289         }
290     }
291
292     fn shorthand(&self) -> &'static str {
293         match *self {
294             OutputType::Bitcode => "llvm-bc",
295             OutputType::Assembly => "asm",
296             OutputType::LlvmAssembly => "llvm-ir",
297             OutputType::Mir => "mir",
298             OutputType::Object => "obj",
299             OutputType::Metadata => "metadata",
300             OutputType::Exe => "link",
301             OutputType::DepInfo => "dep-info",
302         }
303     }
304
305     fn from_shorthand(shorthand: &str) -> Option<Self> {
306         Some(match shorthand {
307             "asm" => OutputType::Assembly,
308             "llvm-ir" => OutputType::LlvmAssembly,
309             "mir" => OutputType::Mir,
310             "llvm-bc" => OutputType::Bitcode,
311             "obj" => OutputType::Object,
312             "metadata" => OutputType::Metadata,
313             "link" => OutputType::Exe,
314             "dep-info" => OutputType::DepInfo,
315             _ => return None,
316         })
317     }
318
319     fn shorthands_display() -> String {
320         format!(
321             "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
322             OutputType::Bitcode.shorthand(),
323             OutputType::Assembly.shorthand(),
324             OutputType::LlvmAssembly.shorthand(),
325             OutputType::Mir.shorthand(),
326             OutputType::Object.shorthand(),
327             OutputType::Metadata.shorthand(),
328             OutputType::Exe.shorthand(),
329             OutputType::DepInfo.shorthand(),
330         )
331     }
332
333     pub fn extension(&self) -> &'static str {
334         match *self {
335             OutputType::Bitcode => "bc",
336             OutputType::Assembly => "s",
337             OutputType::LlvmAssembly => "ll",
338             OutputType::Mir => "mir",
339             OutputType::Object => "o",
340             OutputType::Metadata => "rmeta",
341             OutputType::DepInfo => "d",
342             OutputType::Exe => "",
343         }
344     }
345 }
346
347 /// The type of diagnostics output to generate.
348 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
349 pub enum ErrorOutputType {
350     /// Output meant for the consumption of humans.
351     HumanReadable(HumanReadableErrorType),
352     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
353     Json {
354         /// Render the JSON in a human readable way (with indents and newlines).
355         pretty: bool,
356         /// The JSON output includes a `rendered` field that includes the rendered
357         /// human output.
358         json_rendered: HumanReadableErrorType,
359     },
360 }
361
362 impl Default for ErrorOutputType {
363     fn default() -> Self {
364         Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
365     }
366 }
367
368 /// Parameter to control path trimming.
369 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
370 pub enum TrimmedDefPaths {
371     /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
372     #[default]
373     Never,
374     /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
375     Always,
376     /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
377     GoodPath,
378 }
379
380 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
381 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
382 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
383 /// should only depend on the output types, not the paths they're written to.
384 #[derive(Clone, Debug, Hash)]
385 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
386
387 impl OutputTypes {
388     pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
389         OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
390     }
391
392     pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
393         self.0.get(key)
394     }
395
396     pub fn contains_key(&self, key: &OutputType) -> bool {
397         self.0.contains_key(key)
398     }
399
400     pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
401         self.0.keys()
402     }
403
404     pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
405         self.0.values()
406     }
407
408     pub fn len(&self) -> usize {
409         self.0.len()
410     }
411
412     /// Returns `true` if any of the output types require codegen or linking.
413     pub fn should_codegen(&self) -> bool {
414         self.0.keys().any(|k| match *k {
415             OutputType::Bitcode
416             | OutputType::Assembly
417             | OutputType::LlvmAssembly
418             | OutputType::Mir
419             | OutputType::Object
420             | OutputType::Exe => true,
421             OutputType::Metadata | OutputType::DepInfo => false,
422         })
423     }
424
425     /// Returns `true` if any of the output types require linking.
426     pub fn should_link(&self) -> bool {
427         self.0.keys().any(|k| match *k {
428             OutputType::Bitcode
429             | OutputType::Assembly
430             | OutputType::LlvmAssembly
431             | OutputType::Mir
432             | OutputType::Metadata
433             | OutputType::Object
434             | OutputType::DepInfo => false,
435             OutputType::Exe => true,
436         })
437     }
438 }
439
440 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
441 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
442 /// would break dependency tracking for command-line arguments.
443 #[derive(Clone)]
444 pub struct Externs(BTreeMap<String, ExternEntry>);
445
446 #[derive(Clone)]
447 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
448
449 #[derive(Clone, Debug)]
450 pub struct ExternEntry {
451     pub location: ExternLocation,
452     /// Indicates this is a "private" dependency for the
453     /// `exported_private_dependencies` lint.
454     ///
455     /// This can be set with the `priv` option like
456     /// `--extern priv:name=foo.rlib`.
457     pub is_private_dep: bool,
458     /// Add the extern entry to the extern prelude.
459     ///
460     /// This can be disabled with the `noprelude` option like
461     /// `--extern noprelude:name`.
462     pub add_prelude: bool,
463 }
464
465 #[derive(Clone, Debug)]
466 pub enum ExternLocation {
467     /// Indicates to look for the library in the search paths.
468     ///
469     /// Added via `--extern name`.
470     FoundInLibrarySearchDirectories,
471     /// The locations where this extern entry must be found.
472     ///
473     /// The `CrateLoader` is responsible for loading these and figuring out
474     /// which one to use.
475     ///
476     /// Added via `--extern prelude_name=some_file.rlib`
477     ExactPaths(BTreeSet<CanonicalizedPath>),
478 }
479
480 /// Supplied source location of a dependency - for example in a build specification
481 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
482 /// a file and line, then the build system can specify that. On the other hand, it may
483 /// make more sense to have an arbitrary raw string.
484 #[derive(Clone, PartialEq)]
485 pub enum ExternDepSpec {
486     /// Raw string
487     Raw(String),
488     /// Raw data in json format
489     Json(json::Json),
490 }
491
492 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
493     fn from(from: &'a ExternDepSpec) -> Self {
494         match from {
495             ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
496             ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
497         }
498     }
499 }
500
501 impl Externs {
502     /// Used for testing.
503     pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
504         Externs(data)
505     }
506
507     pub fn get(&self, key: &str) -> Option<&ExternEntry> {
508         self.0.get(key)
509     }
510
511     pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
512         self.0.iter()
513     }
514
515     pub fn len(&self) -> usize {
516         self.0.len()
517     }
518 }
519
520 impl ExternEntry {
521     fn new(location: ExternLocation) -> ExternEntry {
522         ExternEntry { location, is_private_dep: false, add_prelude: false }
523     }
524
525     pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
526         match &self.location {
527             ExternLocation::ExactPaths(set) => Some(set.iter()),
528             _ => None,
529         }
530     }
531 }
532
533 impl ExternDepSpecs {
534     pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
535         ExternDepSpecs(data)
536     }
537
538     pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
539         self.0.get(key)
540     }
541 }
542
543 impl fmt::Display for ExternDepSpec {
544     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
545         match self {
546             ExternDepSpec::Raw(raw) => fmt.write_str(raw),
547             ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
548         }
549     }
550 }
551
552 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
553 pub enum PrintRequest {
554     FileNames,
555     Sysroot,
556     TargetLibdir,
557     CrateName,
558     Cfg,
559     TargetList,
560     TargetCPUs,
561     TargetFeatures,
562     RelocationModels,
563     CodeModels,
564     TlsModels,
565     TargetSpec,
566     NativeStaticLibs,
567     StackProtectorStrategies,
568 }
569
570 #[derive(Copy, Clone)]
571 pub enum BorrowckMode {
572     Mir,
573     Migrate,
574 }
575
576 impl BorrowckMode {
577     /// Returns whether we should run the MIR-based borrow check, but also fall back
578     /// on the AST borrow check if the MIR-based one errors.
579     pub fn migrate(self) -> bool {
580         match self {
581             BorrowckMode::Mir => false,
582             BorrowckMode::Migrate => true,
583         }
584     }
585 }
586
587 pub enum Input {
588     /// Load source code from a file.
589     File(PathBuf),
590     /// Load source code from a string.
591     Str {
592         /// A string that is shown in place of a filename.
593         name: FileName,
594         /// An anonymous string containing the source code.
595         input: String,
596     },
597 }
598
599 impl Input {
600     pub fn filestem(&self) -> &str {
601         match *self {
602             Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
603             Input::Str { .. } => "rust_out",
604         }
605     }
606
607     pub fn source_name(&self) -> FileName {
608         match *self {
609             Input::File(ref ifile) => ifile.clone().into(),
610             Input::Str { ref name, .. } => name.clone(),
611         }
612     }
613 }
614
615 #[derive(Clone, Hash, Debug)]
616 pub struct OutputFilenames {
617     pub out_directory: PathBuf,
618     filestem: String,
619     pub single_output_file: Option<PathBuf>,
620     pub temps_directory: Option<PathBuf>,
621     pub outputs: OutputTypes,
622 }
623
624 impl_stable_hash_via_hash!(OutputFilenames);
625
626 pub const RLINK_EXT: &str = "rlink";
627 pub const RUST_CGU_EXT: &str = "rcgu";
628 pub const DWARF_OBJECT_EXT: &str = "dwo";
629
630 impl OutputFilenames {
631     pub fn new(
632         out_directory: PathBuf,
633         out_filestem: String,
634         single_output_file: Option<PathBuf>,
635         temps_directory: Option<PathBuf>,
636         extra: String,
637         outputs: OutputTypes,
638     ) -> Self {
639         OutputFilenames {
640             out_directory,
641             single_output_file,
642             temps_directory,
643             outputs,
644             filestem: format!("{}{}", out_filestem, extra),
645         }
646     }
647
648     pub fn path(&self, flavor: OutputType) -> PathBuf {
649         self.outputs
650             .get(&flavor)
651             .and_then(|p| p.to_owned())
652             .or_else(|| self.single_output_file.clone())
653             .unwrap_or_else(|| self.output_path(flavor))
654     }
655
656     /// Gets the output path where a compilation artifact of the given type
657     /// should be placed on disk.
658     pub fn output_path(&self, flavor: OutputType) -> PathBuf {
659         let extension = flavor.extension();
660         self.with_directory_and_extension(&self.out_directory, &extension)
661     }
662
663     /// Gets the path where a compilation artifact of the given type for the
664     /// given codegen unit should be placed on disk. If codegen_unit_name is
665     /// None, a path distinct from those of any codegen unit will be generated.
666     pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
667         let extension = flavor.extension();
668         self.temp_path_ext(extension, codegen_unit_name)
669     }
670
671     /// Like `temp_path`, but specifically for dwarf objects.
672     pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
673         self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
674     }
675
676     /// Like `temp_path`, but also supports things where there is no corresponding
677     /// OutputType, like noopt-bitcode or lto-bitcode.
678     pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
679         let mut extension = String::new();
680
681         if let Some(codegen_unit_name) = codegen_unit_name {
682             extension.push_str(codegen_unit_name);
683         }
684
685         if !ext.is_empty() {
686             if !extension.is_empty() {
687                 extension.push('.');
688                 extension.push_str(RUST_CGU_EXT);
689                 extension.push('.');
690             }
691
692             extension.push_str(ext);
693         }
694
695         let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
696
697         self.with_directory_and_extension(&temps_directory, &extension)
698     }
699
700     pub fn with_extension(&self, extension: &str) -> PathBuf {
701         self.with_directory_and_extension(&self.out_directory, extension)
702     }
703
704     fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
705         let mut path = directory.join(&self.filestem);
706         path.set_extension(extension);
707         path
708     }
709
710     /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
711     /// mode is being used, which is the logic that this function is intended to encapsulate.
712     pub fn split_dwarf_path(
713         &self,
714         split_debuginfo_kind: SplitDebuginfo,
715         split_dwarf_kind: SplitDwarfKind,
716         cgu_name: Option<&str>,
717     ) -> Option<PathBuf> {
718         let obj_out = self.temp_path(OutputType::Object, cgu_name);
719         let dwo_out = self.temp_path_dwo(cgu_name);
720         match (split_debuginfo_kind, split_dwarf_kind) {
721             (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
722             // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
723             // (pointing at the path which is being determined here). Use the path to the current
724             // object file.
725             (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
726                 Some(obj_out)
727             }
728             // Split mode emits the DWARF into a different file, use that path.
729             (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
730                 Some(dwo_out)
731             }
732         }
733     }
734 }
735
736 pub fn host_triple() -> &'static str {
737     // Get the host triple out of the build environment. This ensures that our
738     // idea of the host triple is the same as for the set of libraries we've
739     // actually built.  We can't just take LLVM's host triple because they
740     // normalize all ix86 architectures to i386.
741     //
742     // Instead of grabbing the host triple (for the current host), we grab (at
743     // compile time) the target triple that this rustc is built with and
744     // calling that (at runtime) the host triple.
745     (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
746 }
747
748 impl Default for Options {
749     fn default() -> Options {
750         Options {
751             assert_incr_state: None,
752             crate_types: Vec::new(),
753             optimize: OptLevel::No,
754             debuginfo: DebugInfo::None,
755             lint_opts: Vec::new(),
756             lint_cap: None,
757             describe_lints: false,
758             output_types: OutputTypes(BTreeMap::new()),
759             search_paths: vec![],
760             maybe_sysroot: None,
761             target_triple: TargetTriple::from_triple(host_triple()),
762             test: false,
763             incremental: None,
764             debugging_opts: Default::default(),
765             prints: Vec::new(),
766             borrowck_mode: BorrowckMode::Migrate,
767             cg: Default::default(),
768             error_format: ErrorOutputType::default(),
769             externs: Externs(BTreeMap::new()),
770             extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
771             crate_name: None,
772             alt_std_name: None,
773             libs: Vec::new(),
774             unstable_features: UnstableFeatures::Disallow,
775             debug_assertions: true,
776             actually_rustdoc: false,
777             trimmed_def_paths: TrimmedDefPaths::default(),
778             cli_forced_codegen_units: None,
779             cli_forced_thinlto_off: false,
780             remap_path_prefix: Vec::new(),
781             real_rust_source_base_dir: None,
782             edition: DEFAULT_EDITION,
783             json_artifact_notifications: false,
784             json_unused_externs: false,
785             json_future_incompat: false,
786             pretty: None,
787             working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
788         }
789     }
790 }
791
792 impl Options {
793     /// Returns `true` if there is a reason to build the dep graph.
794     pub fn build_dep_graph(&self) -> bool {
795         self.incremental.is_some()
796             || self.debugging_opts.dump_dep_graph
797             || self.debugging_opts.query_dep_graph
798     }
799
800     pub fn file_path_mapping(&self) -> FilePathMapping {
801         FilePathMapping::new(self.remap_path_prefix.clone())
802     }
803
804     /// Returns `true` if there will be an output file generated.
805     pub fn will_create_output_file(&self) -> bool {
806         !self.debugging_opts.parse_only && // The file is just being parsed
807             !self.debugging_opts.ls // The file is just being queried
808     }
809
810     #[inline]
811     pub fn share_generics(&self) -> bool {
812         match self.debugging_opts.share_generics {
813             Some(setting) => setting,
814             None => match self.optimize {
815                 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
816                 OptLevel::Default | OptLevel::Aggressive => false,
817             },
818         }
819     }
820
821     pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
822         self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
823     }
824 }
825
826 impl DebuggingOptions {
827     pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
828         HandlerFlags {
829             can_emit_warnings,
830             treat_err_as_bug: self.treat_err_as_bug,
831             dont_buffer_diagnostics: self.dont_buffer_diagnostics,
832             report_delayed_bugs: self.report_delayed_bugs,
833             macro_backtrace: self.macro_backtrace,
834             deduplicate_diagnostics: self.deduplicate_diagnostics,
835         }
836     }
837 }
838
839 // The type of entry function, so users can have their own entry functions
840 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
841 pub enum EntryFnType {
842     Main,
843     Start,
844 }
845
846 impl_stable_hash_via_hash!(EntryFnType);
847
848 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
849 pub enum CrateType {
850     Executable,
851     Dylib,
852     Rlib,
853     Staticlib,
854     Cdylib,
855     ProcMacro,
856 }
857
858 impl_stable_hash_via_hash!(CrateType);
859
860 impl CrateType {
861     /// When generated, is this crate type an archive?
862     pub fn is_archive(&self) -> bool {
863         match *self {
864             CrateType::Rlib | CrateType::Staticlib => true,
865             CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
866                 false
867             }
868         }
869     }
870 }
871
872 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
873 pub enum Passes {
874     Some(Vec<String>),
875     All,
876 }
877
878 impl Passes {
879     pub fn is_empty(&self) -> bool {
880         match *self {
881             Passes::Some(ref v) => v.is_empty(),
882             Passes::All => false,
883         }
884     }
885
886     pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
887         match *self {
888             Passes::Some(ref mut v) => v.extend(passes),
889             Passes::All => {}
890         }
891     }
892 }
893
894 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
895 pub enum PAuthKey {
896     A,
897     B,
898 }
899
900 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
901 pub struct PacRet {
902     pub leaf: bool,
903     pub key: PAuthKey,
904 }
905
906 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
907 pub struct BranchProtection {
908     pub bti: bool,
909     pub pac_ret: Option<PacRet>,
910 }
911
912 impl Default for BranchProtection {
913     fn default() -> Self {
914         BranchProtection { bti: false, pac_ret: None }
915     }
916 }
917
918 pub const fn default_lib_output() -> CrateType {
919     CrateType::Rlib
920 }
921
922 fn default_configuration(sess: &Session) -> CrateConfig {
923     let end = &sess.target.endian;
924     let arch = &sess.target.arch;
925     let wordsz = sess.target.pointer_width.to_string();
926     let os = &sess.target.os;
927     let env = &sess.target.env;
928     let abi = &sess.target.abi;
929     let vendor = &sess.target.vendor;
930     let min_atomic_width = sess.target.min_atomic_width();
931     let max_atomic_width = sess.target.max_atomic_width();
932     let atomic_cas = sess.target.atomic_cas;
933     let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
934         sess.fatal(&err);
935     });
936
937     let mut ret = FxHashSet::default();
938     ret.reserve(7); // the minimum number of insertions
939     // Target bindings.
940     ret.insert((sym::target_os, Some(Symbol::intern(os))));
941     for fam in &sess.target.families {
942         ret.insert((sym::target_family, Some(Symbol::intern(fam))));
943         if fam == "windows" {
944             ret.insert((sym::windows, None));
945         } else if fam == "unix" {
946             ret.insert((sym::unix, None));
947         }
948     }
949     ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
950     ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
951     ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
952     ret.insert((sym::target_env, Some(Symbol::intern(env))));
953     ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
954     ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
955     if sess.target.has_thread_local {
956         ret.insert((sym::target_thread_local, None));
957     }
958     for (i, align) in [
959         (8, layout.i8_align.abi),
960         (16, layout.i16_align.abi),
961         (32, layout.i32_align.abi),
962         (64, layout.i64_align.abi),
963         (128, layout.i128_align.abi),
964     ] {
965         if i >= min_atomic_width && i <= max_atomic_width {
966             let mut insert_atomic = |s, align: Align| {
967                 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
968                 if atomic_cas {
969                     ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
970                 }
971                 if align.bits() == i {
972                     ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
973                 }
974             };
975             let s = i.to_string();
976             insert_atomic(&s, align);
977             if s == wordsz {
978                 insert_atomic("ptr", layout.pointer_align.abi);
979             }
980         }
981     }
982
983     let panic_strategy = sess.panic_strategy();
984     ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
985
986     for s in sess.opts.debugging_opts.sanitizer {
987         let symbol = Symbol::intern(&s.to_string());
988         ret.insert((sym::sanitize, Some(symbol)));
989     }
990
991     if sess.opts.debug_assertions {
992         ret.insert((sym::debug_assertions, None));
993     }
994     if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
995         ret.insert((sym::proc_macro, None));
996     }
997     ret
998 }
999
1000 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1001 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1002 /// but the symbol interner is not yet set up then, so we must convert it later.
1003 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
1004     cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
1005 }
1006
1007 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1008     // Combine the configuration requested by the session (command line) with
1009     // some default and generated configuration items.
1010     let default_cfg = default_configuration(sess);
1011     // If the user wants a test runner, then add the test cfg.
1012     if sess.opts.test {
1013         user_cfg.insert((sym::test, None));
1014     }
1015     user_cfg.extend(default_cfg.iter().cloned());
1016     user_cfg
1017 }
1018
1019 pub(super) fn build_target_config(
1020     opts: &Options,
1021     target_override: Option<Target>,
1022     sysroot: &Path,
1023 ) -> Target {
1024     let target_result = target_override.map_or_else(
1025         || Target::search(&opts.target_triple, sysroot),
1026         |t| Ok((t, TargetWarnings::empty())),
1027     );
1028     let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1029         early_error(
1030             opts.error_format,
1031             &format!(
1032                 "Error loading target specification: {}. \
1033                  Run `rustc --print target-list` for a list of built-in targets",
1034                 e
1035             ),
1036         )
1037     });
1038     for warning in target_warnings.warning_messages() {
1039         early_warn(opts.error_format, &warning)
1040     }
1041
1042     if !matches!(target.pointer_width, 16 | 32 | 64) {
1043         early_error(
1044             opts.error_format,
1045             &format!(
1046                 "target specification was invalid: \
1047              unrecognized target-pointer-width {}",
1048                 target.pointer_width
1049             ),
1050         )
1051     }
1052
1053     target
1054 }
1055
1056 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1057 pub enum OptionStability {
1058     Stable,
1059     Unstable,
1060 }
1061
1062 pub struct RustcOptGroup {
1063     pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1064     pub name: &'static str,
1065     pub stability: OptionStability,
1066 }
1067
1068 impl RustcOptGroup {
1069     pub fn is_stable(&self) -> bool {
1070         self.stability == OptionStability::Stable
1071     }
1072
1073     pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1074     where
1075         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1076     {
1077         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1078     }
1079
1080     pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1081     where
1082         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1083     {
1084         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1085     }
1086 }
1087
1088 // The `opt` local module holds wrappers around the `getopts` API that
1089 // adds extra rustc-specific metadata to each option; such metadata
1090 // is exposed by .  The public
1091 // functions below ending with `_u` are the functions that return
1092 // *unstable* options, i.e., options that are only enabled when the
1093 // user also passes the `-Z unstable-options` debugging flag.
1094 mod opt {
1095     // The `fn flag*` etc below are written so that we can use them
1096     // in the future; do not warn about them not being used right now.
1097     #![allow(dead_code)]
1098
1099     use super::RustcOptGroup;
1100
1101     pub type R = RustcOptGroup;
1102     pub type S = &'static str;
1103
1104     fn stable<F>(name: S, f: F) -> R
1105     where
1106         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1107     {
1108         RustcOptGroup::stable(name, f)
1109     }
1110
1111     fn unstable<F>(name: S, f: F) -> R
1112     where
1113         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1114     {
1115         RustcOptGroup::unstable(name, f)
1116     }
1117
1118     fn longer(a: S, b: S) -> S {
1119         if a.len() > b.len() { a } else { b }
1120     }
1121
1122     pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1123         stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1124     }
1125     pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1126         stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1127     }
1128     pub fn flag_s(a: S, b: S, c: S) -> R {
1129         stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1130     }
1131     pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1132         stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1133     }
1134
1135     pub fn opt(a: S, b: S, c: S, d: S) -> R {
1136         unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1137     }
1138     pub fn multi(a: S, b: S, c: S, d: S) -> R {
1139         unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1140     }
1141 }
1142
1143 /// Returns the "short" subset of the rustc command line options,
1144 /// including metadata for each option, such as whether the option is
1145 /// part of the stable long-term interface for rustc.
1146 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1147     vec![
1148         opt::flag_s("h", "help", "Display this message"),
1149         opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1150         opt::multi_s(
1151             "L",
1152             "",
1153             "Add a directory to the library search path. The
1154                              optional KIND can be one of dependency, crate, native,
1155                              framework, or all (the default).",
1156             "[KIND=]PATH",
1157         ),
1158         opt::multi_s(
1159             "l",
1160             "",
1161             "Link the generated crate(s) to the specified native
1162                              library NAME. The optional KIND can be one of
1163                              static, framework, or dylib (the default).
1164                              Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1165                              may be specified each with a prefix of either '+' to
1166                              enable or '-' to disable.",
1167             "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1168         ),
1169         make_crate_type_option(),
1170         opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1171         opt::opt_s(
1172             "",
1173             "edition",
1174             "Specify which edition of the compiler to use when compiling code.",
1175             EDITION_NAME_LIST,
1176         ),
1177         opt::multi_s(
1178             "",
1179             "emit",
1180             "Comma separated list of types of output for \
1181              the compiler to emit",
1182             "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1183         ),
1184         opt::multi_s(
1185             "",
1186             "print",
1187             "Compiler information to print on stdout",
1188             "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1189              target-cpus|target-features|relocation-models|code-models|\
1190              tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
1191         ),
1192         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1193         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1194         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1195         opt::opt_s(
1196             "",
1197             "out-dir",
1198             "Write output to compiler-chosen filename \
1199              in <dir>",
1200             "DIR",
1201         ),
1202         opt::opt_s(
1203             "",
1204             "explain",
1205             "Provide a detailed explanation of an error \
1206              message",
1207             "OPT",
1208         ),
1209         opt::flag_s("", "test", "Build a test harness"),
1210         opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1211         opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1212         opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1213         opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1214         opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1215         opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1216         opt::multi_s(
1217             "",
1218             "cap-lints",
1219             "Set the most restrictive lint level. \
1220              More restrictive lints are capped at this \
1221              level",
1222             "LEVEL",
1223         ),
1224         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1225         opt::flag_s("V", "version", "Print version info and exit"),
1226         opt::flag_s("v", "verbose", "Use verbose output"),
1227     ]
1228 }
1229
1230 /// Returns all rustc command line options, including metadata for
1231 /// each option, such as whether the option is part of the stable
1232 /// long-term interface for rustc.
1233 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1234     let mut opts = rustc_short_optgroups();
1235     opts.extend(vec![
1236         opt::multi_s(
1237             "",
1238             "extern",
1239             "Specify where an external rust library is located",
1240             "NAME[=PATH]",
1241         ),
1242         opt::multi_s(
1243             "",
1244             "extern-location",
1245             "Location where an external crate dependency is specified",
1246             "NAME=LOCATION",
1247         ),
1248         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1249         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1250         opt::opt_s(
1251             "",
1252             "error-format",
1253             "How errors and other messages are produced",
1254             "human|json|short",
1255         ),
1256         opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1257         opt::opt_s(
1258             "",
1259             "color",
1260             "Configure coloring of output:
1261                                  auto   = colorize, if output goes to a tty (default);
1262                                  always = always colorize output;
1263                                  never  = never colorize output",
1264             "auto|always|never",
1265         ),
1266         opt::multi_s(
1267             "",
1268             "remap-path-prefix",
1269             "Remap source names in all output (compiler messages and output files)",
1270             "FROM=TO",
1271         ),
1272     ]);
1273     opts
1274 }
1275
1276 pub fn get_cmd_lint_options(
1277     matches: &getopts::Matches,
1278     error_format: ErrorOutputType,
1279 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1280     let mut lint_opts_with_position = vec![];
1281     let mut describe_lints = false;
1282
1283     for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1284         for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1285             if lint_name == "help" {
1286                 describe_lints = true;
1287             } else {
1288                 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1289             }
1290         }
1291     }
1292
1293     lint_opts_with_position.sort_by_key(|x| x.0);
1294     let lint_opts = lint_opts_with_position
1295         .iter()
1296         .cloned()
1297         .map(|(_, lint_name, level)| (lint_name, level))
1298         .collect();
1299
1300     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1301         lint::Level::from_str(&cap)
1302             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1303     });
1304
1305     (lint_opts, describe_lints, lint_cap)
1306 }
1307
1308 /// Parses the `--color` flag.
1309 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1310     match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1311         Some("auto") => ColorConfig::Auto,
1312         Some("always") => ColorConfig::Always,
1313         Some("never") => ColorConfig::Never,
1314
1315         None => ColorConfig::Auto,
1316
1317         Some(arg) => early_error(
1318             ErrorOutputType::default(),
1319             &format!(
1320                 "argument for `--color` must be auto, \
1321                  always or never (instead was `{}`)",
1322                 arg
1323             ),
1324         ),
1325     }
1326 }
1327
1328 /// Possible json config files
1329 pub struct JsonConfig {
1330     pub json_rendered: HumanReadableErrorType,
1331     pub json_artifact_notifications: bool,
1332     pub json_unused_externs: bool,
1333     pub json_future_incompat: bool,
1334 }
1335
1336 /// Parse the `--json` flag.
1337 ///
1338 /// The first value returned is how to render JSON diagnostics, and the second
1339 /// is whether or not artifact notifications are enabled.
1340 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1341     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1342         HumanReadableErrorType::Default;
1343     let mut json_color = ColorConfig::Never;
1344     let mut json_artifact_notifications = false;
1345     let mut json_unused_externs = false;
1346     let mut json_future_incompat = false;
1347     for option in matches.opt_strs("json") {
1348         // For now conservatively forbid `--color` with `--json` since `--json`
1349         // won't actually be emitting any colors and anything colorized is
1350         // embedded in a diagnostic message anyway.
1351         if matches.opt_str("color").is_some() {
1352             early_error(
1353                 ErrorOutputType::default(),
1354                 "cannot specify the `--color` option with `--json`",
1355             );
1356         }
1357
1358         for sub_option in option.split(',') {
1359             match sub_option {
1360                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1361                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1362                 "artifacts" => json_artifact_notifications = true,
1363                 "unused-externs" => json_unused_externs = true,
1364                 "future-incompat" => json_future_incompat = true,
1365                 s => early_error(
1366                     ErrorOutputType::default(),
1367                     &format!("unknown `--json` option `{}`", s),
1368                 ),
1369             }
1370         }
1371     }
1372
1373     JsonConfig {
1374         json_rendered: json_rendered(json_color),
1375         json_artifact_notifications,
1376         json_unused_externs,
1377         json_future_incompat,
1378     }
1379 }
1380
1381 /// Parses the `--error-format` flag.
1382 pub fn parse_error_format(
1383     matches: &getopts::Matches,
1384     color: ColorConfig,
1385     json_rendered: HumanReadableErrorType,
1386 ) -> ErrorOutputType {
1387     // We need the `opts_present` check because the driver will send us Matches
1388     // with only stable options if no unstable options are used. Since error-format
1389     // is unstable, it will not be present. We have to use `opts_present` not
1390     // `opt_present` because the latter will panic.
1391     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1392         match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1393             None | Some("human") => {
1394                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1395             }
1396             Some("human-annotate-rs") => {
1397                 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1398             }
1399             Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1400             Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1401             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1402
1403             Some(arg) => early_error(
1404                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1405                 &format!(
1406                     "argument for `--error-format` must be `human`, `json` or \
1407                      `short` (instead was `{}`)",
1408                     arg
1409                 ),
1410             ),
1411         }
1412     } else {
1413         ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1414     };
1415
1416     match error_format {
1417         ErrorOutputType::Json { .. } => {}
1418
1419         // Conservatively require that the `--json` argument is coupled with
1420         // `--error-format=json`. This means that `--json` is specified we
1421         // should actually be emitting JSON blobs.
1422         _ if !matches.opt_strs("json").is_empty() => {
1423             early_error(
1424                 ErrorOutputType::default(),
1425                 "using `--json` requires also using `--error-format=json`",
1426             );
1427         }
1428
1429         _ => {}
1430     }
1431
1432     error_format
1433 }
1434
1435 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1436     let edition = match matches.opt_str("edition") {
1437         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1438             early_error(
1439                 ErrorOutputType::default(),
1440                 &format!(
1441                     "argument for `--edition` must be one of: \
1442                      {}. (instead was `{}`)",
1443                     EDITION_NAME_LIST, arg
1444                 ),
1445             )
1446         }),
1447         None => DEFAULT_EDITION,
1448     };
1449
1450     if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1451         let is_nightly = nightly_options::match_is_nightly_build(matches);
1452         let msg = if !is_nightly {
1453             format!(
1454                 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1455                 edition, LATEST_STABLE_EDITION
1456             )
1457         } else {
1458             format!("edition {} is unstable and only available with -Z unstable-options", edition)
1459         };
1460         early_error(ErrorOutputType::default(), &msg)
1461     }
1462
1463     edition
1464 }
1465
1466 fn check_debug_option_stability(
1467     debugging_opts: &DebuggingOptions,
1468     error_format: ErrorOutputType,
1469     json_rendered: HumanReadableErrorType,
1470 ) {
1471     if !debugging_opts.unstable_options {
1472         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1473             early_error(
1474                 ErrorOutputType::Json { pretty: false, json_rendered },
1475                 "`--error-format=pretty-json` is unstable",
1476             );
1477         }
1478         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1479             error_format
1480         {
1481             early_error(
1482                 ErrorOutputType::Json { pretty: false, json_rendered },
1483                 "`--error-format=human-annotate-rs` is unstable",
1484             );
1485         }
1486     }
1487 }
1488
1489 fn parse_output_types(
1490     debugging_opts: &DebuggingOptions,
1491     matches: &getopts::Matches,
1492     error_format: ErrorOutputType,
1493 ) -> OutputTypes {
1494     let mut output_types = BTreeMap::new();
1495     if !debugging_opts.parse_only {
1496         for list in matches.opt_strs("emit") {
1497             for output_type in list.split(',') {
1498                 let (shorthand, path) = match output_type.split_once('=') {
1499                     None => (output_type, None),
1500                     Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1501                 };
1502                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1503                     early_error(
1504                         error_format,
1505                         &format!(
1506                             "unknown emission type: `{}` - expected one of: {}",
1507                             shorthand,
1508                             OutputType::shorthands_display(),
1509                         ),
1510                     )
1511                 });
1512                 output_types.insert(output_type, path);
1513             }
1514         }
1515     };
1516     if output_types.is_empty() {
1517         output_types.insert(OutputType::Exe, None);
1518     }
1519     OutputTypes(output_types)
1520 }
1521
1522 fn should_override_cgus_and_disable_thinlto(
1523     output_types: &OutputTypes,
1524     matches: &getopts::Matches,
1525     error_format: ErrorOutputType,
1526     mut codegen_units: Option<usize>,
1527 ) -> (bool, Option<usize>) {
1528     let mut disable_thinlto = false;
1529     // Issue #30063: if user requests LLVM-related output to one
1530     // particular path, disable codegen-units.
1531     let incompatible: Vec<_> = output_types
1532         .0
1533         .iter()
1534         .map(|ot_path| ot_path.0)
1535         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1536         .map(|ot| ot.shorthand())
1537         .collect();
1538     if !incompatible.is_empty() {
1539         match codegen_units {
1540             Some(n) if n > 1 => {
1541                 if matches.opt_present("o") {
1542                     for ot in &incompatible {
1543                         early_warn(
1544                             error_format,
1545                             &format!(
1546                                 "`--emit={}` with `-o` incompatible with \
1547                                  `-C codegen-units=N` for N > 1",
1548                                 ot
1549                             ),
1550                         );
1551                     }
1552                     early_warn(error_format, "resetting to default -C codegen-units=1");
1553                     codegen_units = Some(1);
1554                     disable_thinlto = true;
1555                 }
1556             }
1557             _ => {
1558                 codegen_units = Some(1);
1559                 disable_thinlto = true;
1560             }
1561         }
1562     }
1563
1564     if codegen_units == Some(0) {
1565         early_error(error_format, "value for codegen units must be a positive non-zero integer");
1566     }
1567
1568     (disable_thinlto, codegen_units)
1569 }
1570
1571 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1572     if debugging_opts.threads == 0 {
1573         early_error(error_format, "value for threads must be a positive non-zero integer");
1574     }
1575
1576     if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1577         early_error(error_format, "optimization fuel is incompatible with multiple threads");
1578     }
1579 }
1580
1581 fn collect_print_requests(
1582     cg: &mut CodegenOptions,
1583     dopts: &mut DebuggingOptions,
1584     matches: &getopts::Matches,
1585     error_format: ErrorOutputType,
1586 ) -> Vec<PrintRequest> {
1587     let mut prints = Vec::<PrintRequest>::new();
1588     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1589         prints.push(PrintRequest::TargetCPUs);
1590         cg.target_cpu = None;
1591     };
1592     if cg.target_feature == "help" {
1593         prints.push(PrintRequest::TargetFeatures);
1594         cg.target_feature = String::new();
1595     }
1596
1597     prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1598         "crate-name" => PrintRequest::CrateName,
1599         "file-names" => PrintRequest::FileNames,
1600         "sysroot" => PrintRequest::Sysroot,
1601         "target-libdir" => PrintRequest::TargetLibdir,
1602         "cfg" => PrintRequest::Cfg,
1603         "target-list" => PrintRequest::TargetList,
1604         "target-cpus" => PrintRequest::TargetCPUs,
1605         "target-features" => PrintRequest::TargetFeatures,
1606         "relocation-models" => PrintRequest::RelocationModels,
1607         "code-models" => PrintRequest::CodeModels,
1608         "tls-models" => PrintRequest::TlsModels,
1609         "native-static-libs" => PrintRequest::NativeStaticLibs,
1610         "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1611         "target-spec-json" => {
1612             if dopts.unstable_options {
1613                 PrintRequest::TargetSpec
1614             } else {
1615                 early_error(
1616                     error_format,
1617                     "the `-Z unstable-options` flag must also be passed to \
1618                      enable the target-spec-json print option",
1619                 );
1620             }
1621         }
1622         req => early_error(error_format, &format!("unknown print request `{}`", req)),
1623     }));
1624
1625     prints
1626 }
1627
1628 pub fn parse_target_triple(
1629     matches: &getopts::Matches,
1630     error_format: ErrorOutputType,
1631 ) -> TargetTriple {
1632     match matches.opt_str("target") {
1633         Some(target) if target.ends_with(".json") => {
1634             let path = Path::new(&target);
1635             TargetTriple::from_path(&path).unwrap_or_else(|_| {
1636                 early_error(error_format, &format!("target file {:?} does not exist", path))
1637             })
1638         }
1639         Some(target) => TargetTriple::TargetTriple(target),
1640         _ => TargetTriple::from_triple(host_triple()),
1641     }
1642 }
1643
1644 fn parse_opt_level(
1645     matches: &getopts::Matches,
1646     cg: &CodegenOptions,
1647     error_format: ErrorOutputType,
1648 ) -> OptLevel {
1649     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1650     // to use them interchangeably. However, because they're technically different flags,
1651     // we need to work out manually which should take precedence if both are supplied (i.e.
1652     // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1653     // comparing them. Note that if a flag is not found, its position will be `None`, which
1654     // always compared less than `Some(_)`.
1655     let max_o = matches.opt_positions("O").into_iter().max();
1656     let max_c = matches
1657         .opt_strs_pos("C")
1658         .into_iter()
1659         .flat_map(|(i, s)| {
1660             // NB: This can match a string without `=`.
1661             if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1662         })
1663         .max();
1664     if max_o > max_c {
1665         OptLevel::Default
1666     } else {
1667         match cg.opt_level.as_ref() {
1668             "0" => OptLevel::No,
1669             "1" => OptLevel::Less,
1670             "2" => OptLevel::Default,
1671             "3" => OptLevel::Aggressive,
1672             "s" => OptLevel::Size,
1673             "z" => OptLevel::SizeMin,
1674             arg => {
1675                 early_error(
1676                     error_format,
1677                     &format!(
1678                         "optimization level needs to be \
1679                             between 0-3, s or z (instead was `{}`)",
1680                         arg
1681                     ),
1682                 );
1683             }
1684         }
1685     }
1686 }
1687
1688 fn select_debuginfo(
1689     matches: &getopts::Matches,
1690     cg: &CodegenOptions,
1691     error_format: ErrorOutputType,
1692 ) -> DebugInfo {
1693     let max_g = matches.opt_positions("g").into_iter().max();
1694     let max_c = matches
1695         .opt_strs_pos("C")
1696         .into_iter()
1697         .flat_map(|(i, s)| {
1698             // NB: This can match a string without `=`.
1699             if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1700         })
1701         .max();
1702     if max_g > max_c {
1703         DebugInfo::Full
1704     } else {
1705         match cg.debuginfo {
1706             0 => DebugInfo::None,
1707             1 => DebugInfo::Limited,
1708             2 => DebugInfo::Full,
1709             arg => {
1710                 early_error(
1711                     error_format,
1712                     &format!(
1713                         "debug info level needs to be between \
1714                          0-2 (instead was `{}`)",
1715                         arg
1716                     ),
1717                 );
1718             }
1719         }
1720     }
1721 }
1722
1723 crate fn parse_assert_incr_state(
1724     opt_assertion: &Option<String>,
1725     error_format: ErrorOutputType,
1726 ) -> Option<IncrementalStateAssertion> {
1727     match opt_assertion {
1728         Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1729         Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1730         Some(s) => early_error(
1731             error_format,
1732             &format!("unexpected incremental state assertion value: {}", s),
1733         ),
1734         None => None,
1735     }
1736 }
1737
1738 fn parse_native_lib_kind(
1739     matches: &getopts::Matches,
1740     kind: &str,
1741     error_format: ErrorOutputType,
1742 ) -> (NativeLibKind, Option<bool>) {
1743     let is_nightly = nightly_options::match_is_nightly_build(matches);
1744     let enable_unstable = nightly_options::is_unstable_enabled(matches);
1745
1746     let (kind, modifiers) = match kind.split_once(':') {
1747         None => (kind, None),
1748         Some((kind, modifiers)) => (kind, Some(modifiers)),
1749     };
1750
1751     let kind = match kind {
1752         "dylib" => NativeLibKind::Dylib { as_needed: None },
1753         "framework" => NativeLibKind::Framework { as_needed: None },
1754         "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1755         "static-nobundle" => {
1756             early_warn(
1757                 error_format,
1758                 "library kind `static-nobundle` has been superseded by specifying \
1759                 `-bundle` on library kind `static`. Try `static:-bundle`",
1760             );
1761             if modifiers.is_some() {
1762                 early_error(
1763                     error_format,
1764                     "linking modifier can't be used with library kind `static-nobundle`",
1765                 )
1766             }
1767             if !is_nightly {
1768                 early_error(
1769                     error_format,
1770                     "library kind `static-nobundle` are currently unstable and only accepted on \
1771                 the nightly compiler",
1772                 );
1773             }
1774             NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1775         }
1776         s => early_error(
1777             error_format,
1778             &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1779         ),
1780     };
1781     match modifiers {
1782         None => (kind, None),
1783         Some(modifiers) => {
1784             if !is_nightly {
1785                 early_error(
1786                     error_format,
1787                     "linking modifiers are currently unstable and only accepted on \
1788                 the nightly compiler",
1789                 );
1790             }
1791             if !enable_unstable {
1792                 early_error(
1793                     error_format,
1794                     "linking modifiers are currently unstable, \
1795                 the `-Z unstable-options` flag must also be passed to use it",
1796                 )
1797             }
1798             parse_native_lib_modifiers(kind, modifiers, error_format)
1799         }
1800     }
1801 }
1802
1803 fn parse_native_lib_modifiers(
1804     mut kind: NativeLibKind,
1805     modifiers: &str,
1806     error_format: ErrorOutputType,
1807 ) -> (NativeLibKind, Option<bool>) {
1808     let mut verbatim = None;
1809     for modifier in modifiers.split(',') {
1810         let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
1811             Some(m) => (m, modifier.starts_with('+')),
1812             None => early_error(
1813                 error_format,
1814                 "invalid linking modifier syntax, expected '+' or '-' prefix \
1815                     before one of: bundle, verbatim, whole-archive, as-needed",
1816             ),
1817         };
1818
1819         match (modifier, &mut kind) {
1820             ("bundle", NativeLibKind::Static { bundle, .. }) => {
1821                 *bundle = Some(value);
1822             }
1823             ("bundle", _) => early_error(
1824                 error_format,
1825                 "bundle linking modifier is only compatible with \
1826                     `static` linking kind",
1827             ),
1828
1829             ("verbatim", _) => verbatim = Some(value),
1830
1831             ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1832                 *whole_archive = Some(value);
1833             }
1834             ("whole-archive", _) => early_error(
1835                 error_format,
1836                 "whole-archive linking modifier is only compatible with \
1837                     `static` linking kind",
1838             ),
1839
1840             ("as-needed", NativeLibKind::Dylib { as_needed })
1841             | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1842                 *as_needed = Some(value);
1843             }
1844             ("as-needed", _) => early_error(
1845                 error_format,
1846                 "as-needed linking modifier is only compatible with \
1847                     `dylib` and `framework` linking kinds",
1848             ),
1849
1850             _ => early_error(
1851                 error_format,
1852                 &format!(
1853                     "unrecognized linking modifier `{}`, expected one \
1854                     of: bundle, verbatim, whole-archive, as-needed",
1855                     modifier
1856                 ),
1857             ),
1858         }
1859     }
1860
1861     (kind, verbatim)
1862 }
1863
1864 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1865     matches
1866         .opt_strs("l")
1867         .into_iter()
1868         .map(|s| {
1869             // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1870             // where KIND is one of "dylib", "framework", "static" and
1871             // where MODIFIERS are  a comma separated list of supported modifiers
1872             // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1873             // with either + or - to indicate whether it is enabled or disabled.
1874             // The last value specified for a given modifier wins.
1875             let (name, kind, verbatim) = match s.split_once('=') {
1876                 None => (s, NativeLibKind::Unspecified, None),
1877                 Some((kind, name)) => {
1878                     let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
1879                     (name.to_string(), kind, verbatim)
1880                 }
1881             };
1882
1883             let (name, new_name) = match name.split_once(':') {
1884                 None => (name, None),
1885                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1886             };
1887             NativeLib { name, new_name, kind, verbatim }
1888         })
1889         .collect()
1890 }
1891
1892 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1893     match dopts.borrowck.as_ref() {
1894         "migrate" => BorrowckMode::Migrate,
1895         "mir" => BorrowckMode::Mir,
1896         m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1897     }
1898 }
1899
1900 pub fn parse_externs(
1901     matches: &getopts::Matches,
1902     debugging_opts: &DebuggingOptions,
1903     error_format: ErrorOutputType,
1904 ) -> Externs {
1905     let is_unstable_enabled = debugging_opts.unstable_options;
1906     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1907     for arg in matches.opt_strs("extern") {
1908         let (name, path) = match arg.split_once('=') {
1909             None => (arg, None),
1910             Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1911         };
1912         let (options, name) = match name.split_once(':') {
1913             None => (None, name),
1914             Some((opts, name)) => (Some(opts), name.to_string()),
1915         };
1916
1917         let path = path.map(|p| CanonicalizedPath::new(p));
1918
1919         let entry = externs.entry(name.to_owned());
1920
1921         use std::collections::btree_map::Entry;
1922
1923         let entry = if let Some(path) = path {
1924             // --extern prelude_name=some_file.rlib
1925             match entry {
1926                 Entry::Vacant(vacant) => {
1927                     let files = BTreeSet::from_iter(iter::once(path));
1928                     vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1929                 }
1930                 Entry::Occupied(occupied) => {
1931                     let ext_ent = occupied.into_mut();
1932                     match ext_ent {
1933                         ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1934                             files.insert(path);
1935                         }
1936                         ExternEntry {
1937                             location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1938                             ..
1939                         } => {
1940                             // Exact paths take precedence over search directories.
1941                             let files = BTreeSet::from_iter(iter::once(path));
1942                             *location = ExternLocation::ExactPaths(files);
1943                         }
1944                     }
1945                     ext_ent
1946                 }
1947             }
1948         } else {
1949             // --extern prelude_name
1950             match entry {
1951                 Entry::Vacant(vacant) => {
1952                     vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1953                 }
1954                 Entry::Occupied(occupied) => {
1955                     // Ignore if already specified.
1956                     occupied.into_mut()
1957                 }
1958             }
1959         };
1960
1961         let mut is_private_dep = false;
1962         let mut add_prelude = true;
1963         if let Some(opts) = options {
1964             if !is_unstable_enabled {
1965                 early_error(
1966                     error_format,
1967                     "the `-Z unstable-options` flag must also be passed to \
1968                      enable `--extern options",
1969                 );
1970             }
1971             for opt in opts.split(',') {
1972                 match opt {
1973                     "priv" => is_private_dep = true,
1974                     "noprelude" => {
1975                         if let ExternLocation::ExactPaths(_) = &entry.location {
1976                             add_prelude = false;
1977                         } else {
1978                             early_error(
1979                                 error_format,
1980                                 "the `noprelude` --extern option requires a file path",
1981                             );
1982                         }
1983                     }
1984                     _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1985                 }
1986             }
1987         }
1988
1989         // Crates start out being not private, and go to being private `priv`
1990         // is specified.
1991         entry.is_private_dep |= is_private_dep;
1992         // If any flag is missing `noprelude`, then add to the prelude.
1993         entry.add_prelude |= add_prelude;
1994     }
1995     Externs(externs)
1996 }
1997
1998 fn parse_extern_dep_specs(
1999     matches: &getopts::Matches,
2000     debugging_opts: &DebuggingOptions,
2001     error_format: ErrorOutputType,
2002 ) -> ExternDepSpecs {
2003     let is_unstable_enabled = debugging_opts.unstable_options;
2004     let mut map = BTreeMap::new();
2005
2006     for arg in matches.opt_strs("extern-location") {
2007         if !is_unstable_enabled {
2008             early_error(
2009                 error_format,
2010                 "`--extern-location` option is unstable: set `-Z unstable-options`",
2011             );
2012         }
2013
2014         let mut parts = arg.splitn(2, '=');
2015         let name = parts.next().unwrap_or_else(|| {
2016             early_error(error_format, "`--extern-location` value must not be empty")
2017         });
2018         let loc = parts.next().unwrap_or_else(|| {
2019             early_error(
2020                 error_format,
2021                 &format!("`--extern-location`: specify location for extern crate `{}`", name),
2022             )
2023         });
2024
2025         let locparts: Vec<_> = loc.split(':').collect();
2026         let spec = match &locparts[..] {
2027             ["raw", ..] => {
2028                 // Don't want `:` split string
2029                 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
2030                     early_error(error_format, "`--extern-location`: missing `raw` location")
2031                 });
2032                 ExternDepSpec::Raw(raw.to_string())
2033             }
2034             ["json", ..] => {
2035                 // Don't want `:` split string
2036                 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
2037                     early_error(error_format, "`--extern-location`: missing `json` location")
2038                 });
2039                 let json = json::from_str(raw).unwrap_or_else(|_| {
2040                     early_error(
2041                         error_format,
2042                         &format!("`--extern-location`: malformed json location `{}`", raw),
2043                     )
2044                 });
2045                 ExternDepSpec::Json(json)
2046             }
2047             [bad, ..] => early_error(
2048                 error_format,
2049                 &format!("unknown location type `{}`: use `raw` or `json`", bad),
2050             ),
2051             [] => early_error(error_format, "missing location specification"),
2052         };
2053
2054         map.insert(name.to_string(), spec);
2055     }
2056
2057     ExternDepSpecs::new(map)
2058 }
2059
2060 fn parse_remap_path_prefix(
2061     matches: &getopts::Matches,
2062     debugging_opts: &DebuggingOptions,
2063     error_format: ErrorOutputType,
2064 ) -> Vec<(PathBuf, PathBuf)> {
2065     let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2066         .opt_strs("remap-path-prefix")
2067         .into_iter()
2068         .map(|remap| match remap.rsplit_once('=') {
2069             None => early_error(
2070                 error_format,
2071                 "--remap-path-prefix must contain '=' between FROM and TO",
2072             ),
2073             Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2074         })
2075         .collect();
2076     match &debugging_opts.remap_cwd_prefix {
2077         Some(to) => match std::env::current_dir() {
2078             Ok(cwd) => mapping.push((cwd, to.clone())),
2079             Err(_) => (),
2080         },
2081         None => (),
2082     };
2083     mapping
2084 }
2085
2086 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2087     let color = parse_color(matches);
2088
2089     let edition = parse_crate_edition(matches);
2090
2091     let JsonConfig {
2092         json_rendered,
2093         json_artifact_notifications,
2094         json_unused_externs,
2095         json_future_incompat,
2096     } = parse_json(matches);
2097
2098     let error_format = parse_error_format(matches, color, json_rendered);
2099
2100     let unparsed_crate_types = matches.opt_strs("crate-type");
2101     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2102         .unwrap_or_else(|e| early_error(error_format, &e));
2103
2104     let mut debugging_opts = DebuggingOptions::build(matches, error_format);
2105     let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2106
2107     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2108
2109     if !debugging_opts.unstable_options && json_unused_externs {
2110         early_error(
2111             error_format,
2112             "the `-Z unstable-options` flag must also be passed to enable \
2113             the flag `--json=unused-externs`",
2114         );
2115     }
2116
2117     let output_types = parse_output_types(&debugging_opts, matches, error_format);
2118
2119     let mut cg = CodegenOptions::build(matches, error_format);
2120     let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2121         &output_types,
2122         matches,
2123         error_format,
2124         cg.codegen_units,
2125     );
2126
2127     check_thread_count(&debugging_opts, error_format);
2128
2129     let incremental = cg.incremental.as_ref().map(PathBuf::from);
2130
2131     let assert_incr_state =
2132         parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
2133
2134     if debugging_opts.profile && incremental.is_some() {
2135         early_error(
2136             error_format,
2137             "can't instrument with gcov profiling when compiling incrementally",
2138         );
2139     }
2140     if debugging_opts.profile {
2141         match codegen_units {
2142             Some(1) => {}
2143             None => codegen_units = Some(1),
2144             Some(_) => early_error(
2145                 error_format,
2146                 "can't instrument with gcov profiling with multiple codegen units",
2147             ),
2148         }
2149     }
2150
2151     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2152         early_error(
2153             error_format,
2154             "options `-C profile-generate` and `-C profile-use` are exclusive",
2155         );
2156     }
2157
2158     if debugging_opts.profile_sample_use.is_some()
2159         && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2160     {
2161         early_error(
2162             error_format,
2163             "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2164         );
2165     }
2166
2167     // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2168     // precedence.
2169     match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) {
2170         (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2171             early_error(
2172                 error_format,
2173                 "incompatible values passed for `-C symbol-mangling-version` \
2174                 and `-Z symbol-mangling-version`",
2175             );
2176         }
2177         (Some(SymbolManglingVersion::V0), _) => {}
2178         (Some(_), _) if !debugging_opts.unstable_options => {
2179             early_error(
2180                 error_format,
2181                 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2182             );
2183         }
2184         (None, None) => {}
2185         (None, smv) => {
2186             early_warn(
2187                 error_format,
2188                 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2189             );
2190             cg.symbol_mangling_version = smv;
2191         }
2192         _ => {}
2193     }
2194
2195     if debugging_opts.instrument_coverage.is_some()
2196         && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
2197     {
2198         if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2199             early_error(
2200                 error_format,
2201                 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2202                 or `-C profile-generate`",
2203             );
2204         }
2205
2206         // `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2207         // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2208         // multiple runs, including some changes to source code; so mangled names must be consistent
2209         // across compilations.
2210         match cg.symbol_mangling_version {
2211             None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2212             Some(SymbolManglingVersion::Legacy) => {
2213                 early_warn(
2214                     error_format,
2215                     "-Z instrument-coverage requires symbol mangling version `v0`, \
2216                     but `-C symbol-mangling-version=legacy` was specified",
2217                 );
2218             }
2219             Some(SymbolManglingVersion::V0) => {}
2220         }
2221     }
2222
2223     if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2224         debugging_opts.graphviz_font = graphviz_font;
2225     }
2226
2227     if !cg.embed_bitcode {
2228         match cg.lto {
2229             LtoCli::No | LtoCli::Unspecified => {}
2230             LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2231                 error_format,
2232                 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2233             ),
2234         }
2235     }
2236
2237     let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2238
2239     let cg = cg;
2240
2241     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2242     let target_triple = parse_target_triple(matches, error_format);
2243     let opt_level = parse_opt_level(matches, &cg, error_format);
2244     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2245     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2246     // for more details.
2247     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2248     let debuginfo = select_debuginfo(matches, &cg, error_format);
2249
2250     let mut search_paths = vec![];
2251     for s in &matches.opt_strs("L") {
2252         search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2253     }
2254
2255     let libs = parse_libs(matches, error_format);
2256
2257     let test = matches.opt_present("test");
2258
2259     let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2260
2261     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2262         early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2263     }
2264
2265     let externs = parse_externs(matches, &debugging_opts, error_format);
2266     let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2267
2268     let crate_name = matches.opt_str("crate-name");
2269
2270     let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2271
2272     let pretty = parse_pretty(&debugging_opts, error_format);
2273
2274     if !debugging_opts.unstable_options
2275         && !target_triple.triple().contains("apple")
2276         && cg.split_debuginfo.is_some()
2277     {
2278         {
2279             early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2280         }
2281     }
2282
2283     // Try to find a directory containing the Rust `src`, for more details see
2284     // the doc comment on the `real_rust_source_base_dir` field.
2285     let tmp_buf;
2286     let sysroot = match &sysroot_opt {
2287         Some(s) => s,
2288         None => {
2289             tmp_buf = crate::filesearch::get_or_default_sysroot();
2290             &tmp_buf
2291         }
2292     };
2293     let real_rust_source_base_dir = {
2294         // This is the location used by the `rust-src` `rustup` component.
2295         let mut candidate = sysroot.join("lib/rustlib/src/rust");
2296         if let Ok(metadata) = candidate.symlink_metadata() {
2297             // Replace the symlink rustbuild creates, with its destination.
2298             // We could try to use `fs::canonicalize` instead, but that might
2299             // produce unnecessarily verbose path.
2300             if metadata.file_type().is_symlink() {
2301                 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2302                     candidate = symlink_dest;
2303                 }
2304             }
2305         }
2306
2307         // Only use this directory if it has a file we can expect to always find.
2308         if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2309     };
2310
2311     let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2312         early_error(error_format, &format!("Current directory is invalid: {}", e));
2313     });
2314
2315     let (path, remapped) =
2316         FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2317     let working_dir = if remapped {
2318         RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2319     } else {
2320         RealFileName::LocalPath(path)
2321     };
2322
2323     Options {
2324         assert_incr_state,
2325         crate_types,
2326         optimize: opt_level,
2327         debuginfo,
2328         lint_opts,
2329         lint_cap,
2330         describe_lints,
2331         output_types,
2332         search_paths,
2333         maybe_sysroot: sysroot_opt,
2334         target_triple,
2335         test,
2336         incremental,
2337         debugging_opts,
2338         prints,
2339         borrowck_mode,
2340         cg,
2341         error_format,
2342         externs,
2343         unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2344         extern_dep_specs,
2345         crate_name,
2346         alt_std_name: None,
2347         libs,
2348         debug_assertions,
2349         actually_rustdoc: false,
2350         trimmed_def_paths: TrimmedDefPaths::default(),
2351         cli_forced_codegen_units: codegen_units,
2352         cli_forced_thinlto_off: disable_thinlto,
2353         remap_path_prefix,
2354         real_rust_source_base_dir,
2355         edition,
2356         json_artifact_notifications,
2357         json_unused_externs,
2358         json_future_incompat,
2359         pretty,
2360         working_dir,
2361     }
2362 }
2363
2364 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2365     use PpMode::*;
2366
2367     let first = match debugging_opts.unpretty.as_deref()? {
2368         "normal" => Source(PpSourceMode::Normal),
2369         "identified" => Source(PpSourceMode::Identified),
2370         "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
2371         "expanded" => Source(PpSourceMode::Expanded),
2372         "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2373         "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2374         "ast-tree" => AstTree(PpAstTreeMode::Normal),
2375         "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2376         "hir" => Hir(PpHirMode::Normal),
2377         "hir,identified" => Hir(PpHirMode::Identified),
2378         "hir,typed" => Hir(PpHirMode::Typed),
2379         "hir-tree" => HirTree,
2380         "thir-tree" => ThirTree,
2381         "mir" => Mir,
2382         "mir-cfg" => MirCFG,
2383         name => early_error(
2384             efmt,
2385             &format!(
2386                 "argument to `unpretty` must be one of `normal`, \
2387                             `expanded`, `identified`, `expanded,identified`, \
2388                             `expanded,hygiene`, `everybody_loops`, \
2389                             `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2390                             `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2391                 name
2392             ),
2393         ),
2394     };
2395     tracing::debug!("got unpretty option: {:?}", first);
2396     Some(first)
2397 }
2398
2399 pub fn make_crate_type_option() -> RustcOptGroup {
2400     opt::multi_s(
2401         "",
2402         "crate-type",
2403         "Comma separated list of types of crates
2404                                 for the compiler to emit",
2405         "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2406     )
2407 }
2408
2409 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2410     let mut crate_types: Vec<CrateType> = Vec::new();
2411     for unparsed_crate_type in &list_list {
2412         for part in unparsed_crate_type.split(',') {
2413             let new_part = match part {
2414                 "lib" => default_lib_output(),
2415                 "rlib" => CrateType::Rlib,
2416                 "staticlib" => CrateType::Staticlib,
2417                 "dylib" => CrateType::Dylib,
2418                 "cdylib" => CrateType::Cdylib,
2419                 "bin" => CrateType::Executable,
2420                 "proc-macro" => CrateType::ProcMacro,
2421                 _ => return Err(format!("unknown crate type: `{}`", part)),
2422             };
2423             if !crate_types.contains(&new_part) {
2424                 crate_types.push(new_part)
2425             }
2426         }
2427     }
2428
2429     Ok(crate_types)
2430 }
2431
2432 pub mod nightly_options {
2433     use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2434     use crate::early_error;
2435     use rustc_feature::UnstableFeatures;
2436
2437     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2438         match_is_nightly_build(matches)
2439             && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2440     }
2441
2442     pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2443         is_nightly_build(matches.opt_str("crate-name").as_deref())
2444     }
2445
2446     pub fn is_nightly_build(krate: Option<&str>) -> bool {
2447         UnstableFeatures::from_environment(krate).is_nightly_build()
2448     }
2449
2450     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2451         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2452         let really_allows_unstable_options = match_is_nightly_build(matches);
2453
2454         for opt in flags.iter() {
2455             if opt.stability == OptionStability::Stable {
2456                 continue;
2457             }
2458             if !matches.opt_present(opt.name) {
2459                 continue;
2460             }
2461             if opt.name != "Z" && !has_z_unstable_option {
2462                 early_error(
2463                     ErrorOutputType::default(),
2464                     &format!(
2465                         "the `-Z unstable-options` flag must also be passed to enable \
2466                          the flag `{}`",
2467                         opt.name
2468                     ),
2469                 );
2470             }
2471             if really_allows_unstable_options {
2472                 continue;
2473             }
2474             match opt.stability {
2475                 OptionStability::Unstable => {
2476                     let msg = format!(
2477                         "the option `{}` is only accepted on the \
2478                          nightly compiler",
2479                         opt.name
2480                     );
2481                     early_error(ErrorOutputType::default(), &msg);
2482                 }
2483                 OptionStability::Stable => {}
2484             }
2485         }
2486     }
2487 }
2488
2489 impl fmt::Display for CrateType {
2490     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2491         match *self {
2492             CrateType::Executable => "bin".fmt(f),
2493             CrateType::Dylib => "dylib".fmt(f),
2494             CrateType::Rlib => "rlib".fmt(f),
2495             CrateType::Staticlib => "staticlib".fmt(f),
2496             CrateType::Cdylib => "cdylib".fmt(f),
2497             CrateType::ProcMacro => "proc-macro".fmt(f),
2498         }
2499     }
2500 }
2501
2502 #[derive(Copy, Clone, PartialEq, Debug)]
2503 pub enum PpSourceMode {
2504     /// `-Zunpretty=normal`
2505     Normal,
2506     /// `-Zunpretty=everybody_loops`
2507     EveryBodyLoops,
2508     /// `-Zunpretty=expanded`
2509     Expanded,
2510     /// `-Zunpretty=identified`
2511     Identified,
2512     /// `-Zunpretty=expanded,identified`
2513     ExpandedIdentified,
2514     /// `-Zunpretty=expanded,hygiene`
2515     ExpandedHygiene,
2516 }
2517
2518 #[derive(Copy, Clone, PartialEq, Debug)]
2519 pub enum PpAstTreeMode {
2520     /// `-Zunpretty=ast`
2521     Normal,
2522     /// `-Zunpretty=ast,expanded`
2523     Expanded,
2524 }
2525
2526 #[derive(Copy, Clone, PartialEq, Debug)]
2527 pub enum PpHirMode {
2528     /// `-Zunpretty=hir`
2529     Normal,
2530     /// `-Zunpretty=hir,identified`
2531     Identified,
2532     /// `-Zunpretty=hir,typed`
2533     Typed,
2534 }
2535
2536 #[derive(Copy, Clone, PartialEq, Debug)]
2537 pub enum PpMode {
2538     /// Options that print the source code, i.e.
2539     /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
2540     Source(PpSourceMode),
2541     AstTree(PpAstTreeMode),
2542     /// Options that print the HIR, i.e. `-Zunpretty=hir`
2543     Hir(PpHirMode),
2544     /// `-Zunpretty=hir-tree`
2545     HirTree,
2546     /// `-Zunpretty=thir-tree`
2547     ThirTree,
2548     /// `-Zunpretty=mir`
2549     Mir,
2550     /// `-Zunpretty=mir-cfg`
2551     MirCFG,
2552 }
2553
2554 impl PpMode {
2555     pub fn needs_ast_map(&self) -> bool {
2556         use PpMode::*;
2557         use PpSourceMode::*;
2558         match *self {
2559             Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2560
2561             Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2562             | AstTree(PpAstTreeMode::Expanded)
2563             | Hir(_)
2564             | HirTree
2565             | ThirTree
2566             | Mir
2567             | MirCFG => true,
2568         }
2569     }
2570
2571     pub fn needs_analysis(&self) -> bool {
2572         use PpMode::*;
2573         matches!(*self, Mir | MirCFG | ThirTree)
2574     }
2575 }
2576
2577 /// Command-line arguments passed to the compiler have to be incorporated with
2578 /// the dependency tracking system for incremental compilation. This module
2579 /// provides some utilities to make this more convenient.
2580 ///
2581 /// The values of all command-line arguments that are relevant for dependency
2582 /// tracking are hashed into a single value that determines whether the
2583 /// incremental compilation cache can be re-used or not. This hashing is done
2584 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2585 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2586 /// the hash of which is order dependent, but we might not want the order of
2587 /// arguments to make a difference for the hash).
2588 ///
2589 /// However, since the value provided by `Hash::hash` often *is* suitable,
2590 /// especially for primitive types, there is the
2591 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2592 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2593 /// we have an opt-in scheme here, so one is hopefully forced to think about
2594 /// how the hash should be calculated when adding a new command-line argument.
2595 crate mod dep_tracking {
2596     use super::LdImpl;
2597     use super::{
2598         BranchProtection, CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage,
2599         LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes,
2600         SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2601     };
2602     use crate::lint;
2603     use crate::options::WasiExecModel;
2604     use crate::utils::{NativeLib, NativeLibKind};
2605     use rustc_feature::UnstableFeatures;
2606     use rustc_span::edition::Edition;
2607     use rustc_span::RealFileName;
2608     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2609     use rustc_target::spec::{
2610         RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2611     };
2612     use std::collections::hash_map::DefaultHasher;
2613     use std::collections::BTreeMap;
2614     use std::hash::Hash;
2615     use std::num::NonZeroUsize;
2616     use std::path::PathBuf;
2617
2618     pub trait DepTrackingHash {
2619         fn hash(
2620             &self,
2621             hasher: &mut DefaultHasher,
2622             error_format: ErrorOutputType,
2623             for_crate_hash: bool,
2624         );
2625     }
2626
2627     macro_rules! impl_dep_tracking_hash_via_hash {
2628         ($($t:ty),+ $(,)?) => {$(
2629             impl DepTrackingHash for $t {
2630                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2631                     Hash::hash(self, hasher);
2632                 }
2633             }
2634         )+};
2635     }
2636
2637     impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2638         fn hash(
2639             &self,
2640             hasher: &mut DefaultHasher,
2641             error_format: ErrorOutputType,
2642             for_crate_hash: bool,
2643         ) {
2644             match self {
2645                 Some(x) => {
2646                     Hash::hash(&1, hasher);
2647                     DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2648                 }
2649                 None => Hash::hash(&0, hasher),
2650             }
2651         }
2652     }
2653
2654     impl_dep_tracking_hash_via_hash!(
2655         bool,
2656         usize,
2657         NonZeroUsize,
2658         u64,
2659         String,
2660         PathBuf,
2661         lint::Level,
2662         WasiExecModel,
2663         u32,
2664         RelocModel,
2665         CodeModel,
2666         TlsModel,
2667         InstrumentCoverage,
2668         CrateType,
2669         MergeFunctions,
2670         PanicStrategy,
2671         RelroLevel,
2672         Passes,
2673         OptLevel,
2674         LtoCli,
2675         DebugInfo,
2676         UnstableFeatures,
2677         NativeLib,
2678         NativeLibKind,
2679         SanitizerSet,
2680         CFGuard,
2681         TargetTriple,
2682         Edition,
2683         LinkerPluginLto,
2684         SplitDebuginfo,
2685         StackProtector,
2686         SwitchWithOptPath,
2687         SymbolManglingVersion,
2688         SourceFileHashAlgorithm,
2689         TrimmedDefPaths,
2690         Option<LdImpl>,
2691         OutputType,
2692         RealFileName,
2693         LocationDetail,
2694         BranchProtection,
2695     );
2696
2697     impl<T1, T2> DepTrackingHash for (T1, T2)
2698     where
2699         T1: DepTrackingHash,
2700         T2: DepTrackingHash,
2701     {
2702         fn hash(
2703             &self,
2704             hasher: &mut DefaultHasher,
2705             error_format: ErrorOutputType,
2706             for_crate_hash: bool,
2707         ) {
2708             Hash::hash(&0, hasher);
2709             DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2710             Hash::hash(&1, hasher);
2711             DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2712         }
2713     }
2714
2715     impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2716     where
2717         T1: DepTrackingHash,
2718         T2: DepTrackingHash,
2719         T3: DepTrackingHash,
2720     {
2721         fn hash(
2722             &self,
2723             hasher: &mut DefaultHasher,
2724             error_format: ErrorOutputType,
2725             for_crate_hash: bool,
2726         ) {
2727             Hash::hash(&0, hasher);
2728             DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2729             Hash::hash(&1, hasher);
2730             DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2731             Hash::hash(&2, hasher);
2732             DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2733         }
2734     }
2735
2736     impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2737         fn hash(
2738             &self,
2739             hasher: &mut DefaultHasher,
2740             error_format: ErrorOutputType,
2741             for_crate_hash: bool,
2742         ) {
2743             Hash::hash(&self.len(), hasher);
2744             for (index, elem) in self.iter().enumerate() {
2745                 Hash::hash(&index, hasher);
2746                 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2747             }
2748         }
2749     }
2750
2751     impl DepTrackingHash for OutputTypes {
2752         fn hash(
2753             &self,
2754             hasher: &mut DefaultHasher,
2755             error_format: ErrorOutputType,
2756             for_crate_hash: bool,
2757         ) {
2758             Hash::hash(&self.0.len(), hasher);
2759             for (key, val) in &self.0 {
2760                 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2761                 if !for_crate_hash {
2762                     DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2763                 }
2764             }
2765         }
2766     }
2767
2768     // This is a stable hash because BTreeMap is a sorted container
2769     crate fn stable_hash(
2770         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2771         hasher: &mut DefaultHasher,
2772         error_format: ErrorOutputType,
2773         for_crate_hash: bool,
2774     ) {
2775         for (key, sub_hash) in sub_hashes {
2776             // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2777             // the keys, as they are just plain strings
2778             Hash::hash(&key.len(), hasher);
2779             Hash::hash(key, hasher);
2780             sub_hash.hash(hasher, error_format, for_crate_hash);
2781         }
2782     }
2783 }