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