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