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