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