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