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