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