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