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