]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_session/src/config.rs
Rollup merge of #106412 - GuillaumeGomez:fix-links-to-primitive-rustdoc-json, r=aDotI...
[rust.git] / compiler / rustc_session / src / config.rs
1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
3
4 pub use crate::options::*;
5
6 use crate::search_paths::SearchPath;
7 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
8 use crate::{early_error, early_warn, Session};
9 use crate::{lint, HashStableContext};
10
11 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
12
13 use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
14 use rustc_target::abi::Align;
15 use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
16 use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
17
18 use crate::parse::{CrateCheckConfig, CrateConfig};
19 use rustc_feature::UnstableFeatures;
20 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
21 use rustc_span::source_map::{FileName, FilePathMapping};
22 use rustc_span::symbol::{sym, Symbol};
23 use rustc_span::RealFileName;
24 use rustc_span::SourceFileHashAlgorithm;
25
26 use rustc_errors::emitter::HumanReadableErrorType;
27 use rustc_errors::{ColorConfig, HandlerFlags};
28
29 use std::collections::btree_map::{
30     Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
31 };
32 use std::collections::{BTreeMap, BTreeSet};
33 use std::fmt;
34 use std::hash::Hash;
35 use std::iter;
36 use std::path::{Path, PathBuf};
37 use std::str::{self, FromStr};
38
39 pub mod sigpipe;
40
41 /// The different settings that the `-C strip` flag can have.
42 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
43 pub enum Strip {
44     /// Do not strip at all.
45     None,
46
47     /// Strip debuginfo.
48     Debuginfo,
49
50     /// Strip all symbols.
51     Symbols,
52 }
53
54 /// The different settings that the `-C control-flow-guard` flag can have.
55 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
56 pub enum CFGuard {
57     /// Do not emit Control Flow Guard metadata or checks.
58     Disabled,
59
60     /// Emit Control Flow Guard metadata but no checks.
61     NoChecks,
62
63     /// Emit Control Flow Guard metadata and checks.
64     Checks,
65 }
66
67 /// The different settings that the `-Z cf-protection` flag can have.
68 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
69 pub enum CFProtection {
70     /// Do not enable control-flow protection
71     None,
72
73     /// Emit control-flow protection for branches (enables indirect branch tracking).
74     Branch,
75
76     /// Emit control-flow protection for returns.
77     Return,
78
79     /// Emit control-flow protection for both branches and returns.
80     Full,
81 }
82
83 #[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
84 pub enum OptLevel {
85     No,         // -O0
86     Less,       // -O1
87     Default,    // -O2
88     Aggressive, // -O3
89     Size,       // -Os
90     SizeMin,    // -Oz
91 }
92
93 /// This is what the `LtoCli` values get mapped to after resolving defaults and
94 /// and taking other command line options into account.
95 ///
96 /// Note that linker plugin-based LTO is a different mechanism entirely.
97 #[derive(Clone, PartialEq)]
98 pub enum Lto {
99     /// Don't do any LTO whatsoever.
100     No,
101
102     /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
103     Thin,
104
105     /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
106     /// only relevant if multiple CGUs are used.
107     ThinLocal,
108
109     /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
110     Fat,
111 }
112
113 /// The different settings that the `-C lto` flag can have.
114 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
115 pub enum LtoCli {
116     /// `-C lto=no`
117     No,
118     /// `-C lto=yes`
119     Yes,
120     /// `-C lto`
121     NoParam,
122     /// `-C lto=thin`
123     Thin,
124     /// `-C lto=fat`
125     Fat,
126     /// No `-C lto` flag passed
127     Unspecified,
128 }
129
130 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
131 /// document highlighting each span of every statement (including terminators). `Terminator` and
132 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
133 /// computed span for the block, representing the entire range, covering the block's terminator and
134 /// all of its statements.
135 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
136 pub enum MirSpanview {
137     /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
138     Statement,
139     /// `-Z dump_mir_spanview=terminator`
140     Terminator,
141     /// `-Z dump_mir_spanview=block`
142     Block,
143 }
144
145 /// The different settings that the `-C instrument-coverage` flag can have.
146 ///
147 /// Coverage instrumentation now supports combining `-C instrument-coverage`
148 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
149 /// and higher). Nevertheless, there are many variables, depending on options
150 /// selected, code structure, and enabled attributes. If errors are encountered,
151 /// either while compiling or when generating `llvm-cov show` reports, consider
152 /// lowering the optimization level, including or excluding `-C link-dead-code`,
153 /// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
154 /// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
155 ///
156 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
157 /// coverage map, it will not attempt to generate synthetic functions for unused
158 /// (and not code-generated) functions (whether they are generic or not). As a
159 /// result, non-codegenned functions will not be included in the coverage map,
160 /// and will not appear, as covered or uncovered, in coverage reports.
161 ///
162 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
163 /// unless the function has type parameters.
164 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
165 pub enum InstrumentCoverage {
166     /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
167     All,
168     /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
169     ExceptUnusedGenerics,
170     /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
171     ExceptUnusedFunctions,
172     /// `-C instrument-coverage=off` (or `no`, etc.)
173     Off,
174 }
175
176 #[derive(Clone, PartialEq, Hash, Debug)]
177 pub enum LinkerPluginLto {
178     LinkerPlugin(PathBuf),
179     LinkerPluginAuto,
180     Disabled,
181 }
182
183 /// Used with `-Z assert-incr-state`.
184 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
185 pub enum IncrementalStateAssertion {
186     /// Found and loaded an existing session directory.
187     ///
188     /// Note that this says nothing about whether any particular query
189     /// will be found to be red or green.
190     Loaded,
191     /// Did not load an existing session directory.
192     NotLoaded,
193 }
194
195 impl LinkerPluginLto {
196     pub fn enabled(&self) -> bool {
197         match *self {
198             LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
199             LinkerPluginLto::Disabled => false,
200         }
201     }
202 }
203
204 /// The different settings that can be enabled via the `-Z location-detail` flag.
205 #[derive(Clone, PartialEq, Hash, Debug)]
206 pub struct LocationDetail {
207     pub file: bool,
208     pub line: bool,
209     pub column: bool,
210 }
211
212 impl LocationDetail {
213     pub fn all() -> Self {
214         Self { file: true, line: true, column: true }
215     }
216 }
217
218 #[derive(Clone, PartialEq, Hash, Debug)]
219 pub enum SwitchWithOptPath {
220     Enabled(Option<PathBuf>),
221     Disabled,
222 }
223
224 impl SwitchWithOptPath {
225     pub fn enabled(&self) -> bool {
226         match *self {
227             SwitchWithOptPath::Enabled(_) => true,
228             SwitchWithOptPath::Disabled => false,
229         }
230     }
231 }
232
233 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
234 #[derive(Encodable, Decodable)]
235 pub enum SymbolManglingVersion {
236     Legacy,
237     V0,
238 }
239
240 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
241 pub enum DebugInfo {
242     None,
243     Limited,
244     Full,
245 }
246
247 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
248 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
249 /// uses DWARF for debug-information.
250 ///
251 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
252 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
253 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
254 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
255 /// them in the object file in such a way that the linker will skip them.
256 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
257 pub enum SplitDwarfKind {
258     /// Sections which do not require relocation are written into object file but ignored by the
259     /// linker.
260     Single,
261     /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
262     /// which is ignored by the linker.
263     Split,
264 }
265
266 impl FromStr for SplitDwarfKind {
267     type Err = ();
268
269     fn from_str(s: &str) -> Result<Self, ()> {
270         Ok(match s {
271             "single" => SplitDwarfKind::Single,
272             "split" => SplitDwarfKind::Split,
273             _ => return Err(()),
274         })
275     }
276 }
277
278 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
279 #[derive(Encodable, Decodable)]
280 pub enum OutputType {
281     Bitcode,
282     Assembly,
283     LlvmAssembly,
284     Mir,
285     Metadata,
286     Object,
287     Exe,
288     DepInfo,
289 }
290
291 // Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
292 unsafe impl StableOrd for OutputType {}
293
294 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
295     type KeyType = Self;
296
297     fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
298         *self
299     }
300 }
301
302 impl OutputType {
303     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
304         match *self {
305             OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
306             OutputType::Bitcode
307             | OutputType::Assembly
308             | OutputType::LlvmAssembly
309             | OutputType::Mir
310             | OutputType::Object => false,
311         }
312     }
313
314     fn shorthand(&self) -> &'static str {
315         match *self {
316             OutputType::Bitcode => "llvm-bc",
317             OutputType::Assembly => "asm",
318             OutputType::LlvmAssembly => "llvm-ir",
319             OutputType::Mir => "mir",
320             OutputType::Object => "obj",
321             OutputType::Metadata => "metadata",
322             OutputType::Exe => "link",
323             OutputType::DepInfo => "dep-info",
324         }
325     }
326
327     fn from_shorthand(shorthand: &str) -> Option<Self> {
328         Some(match shorthand {
329             "asm" => OutputType::Assembly,
330             "llvm-ir" => OutputType::LlvmAssembly,
331             "mir" => OutputType::Mir,
332             "llvm-bc" => OutputType::Bitcode,
333             "obj" => OutputType::Object,
334             "metadata" => OutputType::Metadata,
335             "link" => OutputType::Exe,
336             "dep-info" => OutputType::DepInfo,
337             _ => return None,
338         })
339     }
340
341     fn shorthands_display() -> String {
342         format!(
343             "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
344             OutputType::Bitcode.shorthand(),
345             OutputType::Assembly.shorthand(),
346             OutputType::LlvmAssembly.shorthand(),
347             OutputType::Mir.shorthand(),
348             OutputType::Object.shorthand(),
349             OutputType::Metadata.shorthand(),
350             OutputType::Exe.shorthand(),
351             OutputType::DepInfo.shorthand(),
352         )
353     }
354
355     pub fn extension(&self) -> &'static str {
356         match *self {
357             OutputType::Bitcode => "bc",
358             OutputType::Assembly => "s",
359             OutputType::LlvmAssembly => "ll",
360             OutputType::Mir => "mir",
361             OutputType::Object => "o",
362             OutputType::Metadata => "rmeta",
363             OutputType::DepInfo => "d",
364             OutputType::Exe => "",
365         }
366     }
367 }
368
369 /// The type of diagnostics output to generate.
370 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
371 pub enum ErrorOutputType {
372     /// Output meant for the consumption of humans.
373     HumanReadable(HumanReadableErrorType),
374     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
375     Json {
376         /// Render the JSON in a human readable way (with indents and newlines).
377         pretty: bool,
378         /// The JSON output includes a `rendered` field that includes the rendered
379         /// human output.
380         json_rendered: HumanReadableErrorType,
381     },
382 }
383
384 impl Default for ErrorOutputType {
385     fn default() -> Self {
386         Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
387     }
388 }
389
390 /// Parameter to control path trimming.
391 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
392 pub enum TrimmedDefPaths {
393     /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
394     #[default]
395     Never,
396     /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
397     Always,
398     /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
399     GoodPath,
400 }
401
402 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
403 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
404 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
405 /// should only depend on the output types, not the paths they're written to.
406 #[derive(Clone, Debug, Hash, HashStable_Generic)]
407 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
408
409 impl OutputTypes {
410     pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
411         OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
412     }
413
414     pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
415         self.0.get(key)
416     }
417
418     pub fn contains_key(&self, key: &OutputType) -> bool {
419         self.0.contains_key(key)
420     }
421
422     pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
423         self.0.keys()
424     }
425
426     pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
427         self.0.values()
428     }
429
430     pub fn len(&self) -> usize {
431         self.0.len()
432     }
433
434     /// Returns `true` if any of the output types require codegen or linking.
435     pub fn should_codegen(&self) -> bool {
436         self.0.keys().any(|k| match *k {
437             OutputType::Bitcode
438             | OutputType::Assembly
439             | OutputType::LlvmAssembly
440             | OutputType::Mir
441             | OutputType::Object
442             | OutputType::Exe => true,
443             OutputType::Metadata | OutputType::DepInfo => false,
444         })
445     }
446
447     /// Returns `true` if any of the output types require linking.
448     pub fn should_link(&self) -> bool {
449         self.0.keys().any(|k| match *k {
450             OutputType::Bitcode
451             | OutputType::Assembly
452             | OutputType::LlvmAssembly
453             | OutputType::Mir
454             | OutputType::Metadata
455             | OutputType::Object
456             | OutputType::DepInfo => false,
457             OutputType::Exe => true,
458         })
459     }
460 }
461
462 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
463 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
464 /// would break dependency tracking for command-line arguments.
465 #[derive(Clone)]
466 pub struct Externs(BTreeMap<String, ExternEntry>);
467
468 #[derive(Clone, Debug)]
469 pub struct ExternEntry {
470     pub location: ExternLocation,
471     /// Indicates this is a "private" dependency for the
472     /// `exported_private_dependencies` lint.
473     ///
474     /// This can be set with the `priv` option like
475     /// `--extern priv:name=foo.rlib`.
476     pub is_private_dep: bool,
477     /// Add the extern entry to the extern prelude.
478     ///
479     /// This can be disabled with the `noprelude` option like
480     /// `--extern noprelude:name`.
481     pub add_prelude: bool,
482     /// The extern entry shouldn't be considered for unused dependency warnings.
483     ///
484     /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
485     /// suppress `unused-crate-dependencies` warnings.
486     pub nounused_dep: bool,
487 }
488
489 #[derive(Clone, Debug)]
490 pub enum ExternLocation {
491     /// Indicates to look for the library in the search paths.
492     ///
493     /// Added via `--extern name`.
494     FoundInLibrarySearchDirectories,
495     /// The locations where this extern entry must be found.
496     ///
497     /// The `CrateLoader` is responsible for loading these and figuring out
498     /// which one to use.
499     ///
500     /// Added via `--extern prelude_name=some_file.rlib`
501     ExactPaths(BTreeSet<CanonicalizedPath>),
502 }
503
504 impl Externs {
505     /// Used for testing.
506     pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
507         Externs(data)
508     }
509
510     pub fn get(&self, key: &str) -> Option<&ExternEntry> {
511         self.0.get(key)
512     }
513
514     pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
515         self.0.iter()
516     }
517
518     pub fn len(&self) -> usize {
519         self.0.len()
520     }
521 }
522
523 impl ExternEntry {
524     fn new(location: ExternLocation) -> ExternEntry {
525         ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
526     }
527
528     pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
529         match &self.location {
530             ExternLocation::ExactPaths(set) => Some(set.iter()),
531             _ => None,
532         }
533     }
534 }
535
536 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
537 pub enum PrintRequest {
538     FileNames,
539     Sysroot,
540     TargetLibdir,
541     CrateName,
542     Cfg,
543     CallingConventions,
544     TargetList,
545     TargetCPUs,
546     TargetFeatures,
547     RelocationModels,
548     CodeModels,
549     TlsModels,
550     TargetSpec,
551     NativeStaticLibs,
552     StackProtectorStrategies,
553     LinkArgs,
554     SplitDebuginfo,
555 }
556
557 pub enum Input {
558     /// Load source code from a file.
559     File(PathBuf),
560     /// Load source code from a string.
561     Str {
562         /// A string that is shown in place of a filename.
563         name: FileName,
564         /// An anonymous string containing the source code.
565         input: String,
566     },
567 }
568
569 impl Input {
570     pub fn filestem(&self) -> &str {
571         match *self {
572             Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
573             Input::Str { .. } => "rust_out",
574         }
575     }
576
577     pub fn source_name(&self) -> FileName {
578         match *self {
579             Input::File(ref ifile) => ifile.clone().into(),
580             Input::Str { ref name, .. } => name.clone(),
581         }
582     }
583 }
584
585 #[derive(Clone, Hash, Debug, HashStable_Generic)]
586 pub struct OutputFilenames {
587     pub out_directory: PathBuf,
588     filestem: String,
589     pub single_output_file: Option<PathBuf>,
590     pub temps_directory: Option<PathBuf>,
591     pub outputs: OutputTypes,
592 }
593
594 pub const RLINK_EXT: &str = "rlink";
595 pub const RUST_CGU_EXT: &str = "rcgu";
596 pub const DWARF_OBJECT_EXT: &str = "dwo";
597
598 impl OutputFilenames {
599     pub fn new(
600         out_directory: PathBuf,
601         out_filestem: String,
602         single_output_file: Option<PathBuf>,
603         temps_directory: Option<PathBuf>,
604         extra: String,
605         outputs: OutputTypes,
606     ) -> Self {
607         OutputFilenames {
608             out_directory,
609             single_output_file,
610             temps_directory,
611             outputs,
612             filestem: format!("{out_filestem}{extra}"),
613         }
614     }
615
616     pub fn path(&self, flavor: OutputType) -> PathBuf {
617         self.outputs
618             .get(&flavor)
619             .and_then(|p| p.to_owned())
620             .or_else(|| self.single_output_file.clone())
621             .unwrap_or_else(|| self.output_path(flavor))
622     }
623
624     /// Gets the output path where a compilation artifact of the given type
625     /// should be placed on disk.
626     pub fn output_path(&self, flavor: OutputType) -> PathBuf {
627         let extension = flavor.extension();
628         self.with_directory_and_extension(&self.out_directory, extension)
629     }
630
631     /// Gets the path where a compilation artifact of the given type for the
632     /// given codegen unit should be placed on disk. If codegen_unit_name is
633     /// None, a path distinct from those of any codegen unit will be generated.
634     pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
635         let extension = flavor.extension();
636         self.temp_path_ext(extension, codegen_unit_name)
637     }
638
639     /// Like `temp_path`, but specifically for dwarf objects.
640     pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
641         self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
642     }
643
644     /// Like `temp_path`, but also supports things where there is no corresponding
645     /// OutputType, like noopt-bitcode or lto-bitcode.
646     pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
647         let mut extension = String::new();
648
649         if let Some(codegen_unit_name) = codegen_unit_name {
650             extension.push_str(codegen_unit_name);
651         }
652
653         if !ext.is_empty() {
654             if !extension.is_empty() {
655                 extension.push('.');
656                 extension.push_str(RUST_CGU_EXT);
657                 extension.push('.');
658             }
659
660             extension.push_str(ext);
661         }
662
663         let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
664
665         self.with_directory_and_extension(temps_directory, &extension)
666     }
667
668     pub fn with_extension(&self, extension: &str) -> PathBuf {
669         self.with_directory_and_extension(&self.out_directory, extension)
670     }
671
672     fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
673         let mut path = directory.join(&self.filestem);
674         path.set_extension(extension);
675         path
676     }
677
678     /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
679     /// mode is being used, which is the logic that this function is intended to encapsulate.
680     pub fn split_dwarf_path(
681         &self,
682         split_debuginfo_kind: SplitDebuginfo,
683         split_dwarf_kind: SplitDwarfKind,
684         cgu_name: Option<&str>,
685     ) -> Option<PathBuf> {
686         let obj_out = self.temp_path(OutputType::Object, cgu_name);
687         let dwo_out = self.temp_path_dwo(cgu_name);
688         match (split_debuginfo_kind, split_dwarf_kind) {
689             (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
690             // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
691             // (pointing at the path which is being determined here). Use the path to the current
692             // object file.
693             (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
694                 Some(obj_out)
695             }
696             // Split mode emits the DWARF into a different file, use that path.
697             (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
698                 Some(dwo_out)
699             }
700         }
701     }
702 }
703
704 pub fn host_triple() -> &'static str {
705     // Get the host triple out of the build environment. This ensures that our
706     // idea of the host triple is the same as for the set of libraries we've
707     // actually built.  We can't just take LLVM's host triple because they
708     // normalize all ix86 architectures to i386.
709     //
710     // Instead of grabbing the host triple (for the current host), we grab (at
711     // compile time) the target triple that this rustc is built with and
712     // calling that (at runtime) the host triple.
713     (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
714 }
715
716 impl Default for Options {
717     fn default() -> Options {
718         Options {
719             assert_incr_state: None,
720             crate_types: Vec::new(),
721             optimize: OptLevel::No,
722             debuginfo: DebugInfo::None,
723             lint_opts: Vec::new(),
724             lint_cap: None,
725             describe_lints: false,
726             output_types: OutputTypes(BTreeMap::new()),
727             search_paths: vec![],
728             maybe_sysroot: None,
729             target_triple: TargetTriple::from_triple(host_triple()),
730             test: false,
731             incremental: None,
732             unstable_opts: Default::default(),
733             prints: Vec::new(),
734             cg: Default::default(),
735             error_format: ErrorOutputType::default(),
736             diagnostic_width: None,
737             externs: Externs(BTreeMap::new()),
738             crate_name: None,
739             libs: Vec::new(),
740             unstable_features: UnstableFeatures::Disallow,
741             debug_assertions: true,
742             actually_rustdoc: false,
743             trimmed_def_paths: TrimmedDefPaths::default(),
744             cli_forced_codegen_units: None,
745             cli_forced_local_thinlto_off: false,
746             remap_path_prefix: Vec::new(),
747             real_rust_source_base_dir: None,
748             edition: DEFAULT_EDITION,
749             json_artifact_notifications: false,
750             json_unused_externs: JsonUnusedExterns::No,
751             json_future_incompat: false,
752             pretty: None,
753             working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
754         }
755     }
756 }
757
758 impl Options {
759     /// Returns `true` if there is a reason to build the dep graph.
760     pub fn build_dep_graph(&self) -> bool {
761         self.incremental.is_some()
762             || self.unstable_opts.dump_dep_graph
763             || self.unstable_opts.query_dep_graph
764     }
765
766     pub fn file_path_mapping(&self) -> FilePathMapping {
767         FilePathMapping::new(self.remap_path_prefix.clone())
768     }
769
770     /// Returns `true` if there will be an output file generated.
771     pub fn will_create_output_file(&self) -> bool {
772         !self.unstable_opts.parse_only && // The file is just being parsed
773             !self.unstable_opts.ls // The file is just being queried
774     }
775
776     #[inline]
777     pub fn share_generics(&self) -> bool {
778         match self.unstable_opts.share_generics {
779             Some(setting) => setting,
780             None => match self.optimize {
781                 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
782                 OptLevel::Default | OptLevel::Aggressive => false,
783             },
784         }
785     }
786
787     pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
788         self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
789     }
790
791     #[allow(rustc::bad_opt_access)]
792     pub fn incremental_relative_spans(&self) -> bool {
793         self.unstable_opts.incremental_relative_spans
794             || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
795     }
796 }
797
798 impl UnstableOptions {
799     pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
800         HandlerFlags {
801             can_emit_warnings,
802             treat_err_as_bug: self.treat_err_as_bug,
803             dont_buffer_diagnostics: self.dont_buffer_diagnostics,
804             report_delayed_bugs: self.report_delayed_bugs,
805             macro_backtrace: self.macro_backtrace,
806             deduplicate_diagnostics: self.deduplicate_diagnostics,
807             track_diagnostics: self.track_diagnostics,
808         }
809     }
810 }
811
812 // The type of entry function, so users can have their own entry functions
813 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
814 pub enum EntryFnType {
815     Main {
816         /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
817         ///
818         /// What values that are valid and what they mean must be in sync
819         /// across rustc and libstd, but we don't want it public in libstd,
820         /// so we take a bit of an unusual approach with simple constants
821         /// and an `include!()`.
822         sigpipe: u8,
823     },
824     Start,
825 }
826
827 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
828 #[derive(HashStable_Generic)]
829 pub enum CrateType {
830     Executable,
831     Dylib,
832     Rlib,
833     Staticlib,
834     Cdylib,
835     ProcMacro,
836 }
837
838 impl CrateType {
839     /// When generated, is this crate type an archive?
840     pub fn is_archive(&self) -> bool {
841         match *self {
842             CrateType::Rlib | CrateType::Staticlib => true,
843             CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
844                 false
845             }
846         }
847     }
848 }
849
850 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
851 pub enum Passes {
852     Some(Vec<String>),
853     All,
854 }
855
856 impl Passes {
857     pub fn is_empty(&self) -> bool {
858         match *self {
859             Passes::Some(ref v) => v.is_empty(),
860             Passes::All => false,
861         }
862     }
863
864     pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
865         match *self {
866             Passes::Some(ref mut v) => v.extend(passes),
867             Passes::All => {}
868         }
869     }
870 }
871
872 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
873 pub enum PAuthKey {
874     A,
875     B,
876 }
877
878 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
879 pub struct PacRet {
880     pub leaf: bool,
881     pub key: PAuthKey,
882 }
883
884 #[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
885 pub struct BranchProtection {
886     pub bti: bool,
887     pub pac_ret: Option<PacRet>,
888 }
889
890 pub const fn default_lib_output() -> CrateType {
891     CrateType::Rlib
892 }
893
894 fn default_configuration(sess: &Session) -> CrateConfig {
895     // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
896     let end = &sess.target.endian;
897     let arch = &sess.target.arch;
898     let wordsz = sess.target.pointer_width.to_string();
899     let os = &sess.target.os;
900     let env = &sess.target.env;
901     let abi = &sess.target.abi;
902     let vendor = &sess.target.vendor;
903     let min_atomic_width = sess.target.min_atomic_width();
904     let max_atomic_width = sess.target.max_atomic_width();
905     let atomic_cas = sess.target.atomic_cas;
906     let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
907         sess.emit_fatal(err);
908     });
909
910     let mut ret = CrateConfig::default();
911     ret.reserve(7); // the minimum number of insertions
912     // Target bindings.
913     ret.insert((sym::target_os, Some(Symbol::intern(os))));
914     for fam in sess.target.families.as_ref() {
915         ret.insert((sym::target_family, Some(Symbol::intern(fam))));
916         if fam == "windows" {
917             ret.insert((sym::windows, None));
918         } else if fam == "unix" {
919             ret.insert((sym::unix, None));
920         }
921     }
922     ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
923     ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
924     ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
925     ret.insert((sym::target_env, Some(Symbol::intern(env))));
926     ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
927     ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
928     if sess.target.has_thread_local {
929         ret.insert((sym::target_thread_local, None));
930     }
931     for (i, align) in [
932         (8, layout.i8_align.abi),
933         (16, layout.i16_align.abi),
934         (32, layout.i32_align.abi),
935         (64, layout.i64_align.abi),
936         (128, layout.i128_align.abi),
937     ] {
938         if i >= min_atomic_width && i <= max_atomic_width {
939             let mut insert_atomic = |s, align: Align| {
940                 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
941                 if atomic_cas {
942                     ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
943                 }
944                 if align.bits() == i {
945                     ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
946                 }
947             };
948             let s = i.to_string();
949             insert_atomic(&s, align);
950             if s == wordsz {
951                 insert_atomic("ptr", layout.pointer_align.abi);
952             }
953         }
954     }
955
956     let panic_strategy = sess.panic_strategy();
957     ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
958
959     for s in sess.opts.unstable_opts.sanitizer {
960         let symbol = Symbol::intern(&s.to_string());
961         ret.insert((sym::sanitize, Some(symbol)));
962     }
963
964     if sess.opts.debug_assertions {
965         ret.insert((sym::debug_assertions, None));
966     }
967     // JUSTIFICATION: before wrapper fn is available
968     #[allow(rustc::bad_opt_access)]
969     if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
970         ret.insert((sym::proc_macro, None));
971     }
972     ret
973 }
974
975 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
976 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
977 /// but the symbol interner is not yet set up then, so we must convert it later.
978 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
979     cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
980 }
981
982 /// The parsed `--check-cfg` options
983 pub struct CheckCfg<T = String> {
984     /// The set of all `names()`, if None no name checking is performed
985     pub names_valid: Option<FxHashSet<T>>,
986     /// Is well known values activated
987     pub well_known_values: bool,
988     /// The set of all `values()`
989     pub values_valid: FxHashMap<T, FxHashSet<T>>,
990 }
991
992 impl<T> Default for CheckCfg<T> {
993     fn default() -> Self {
994         CheckCfg {
995             names_valid: Default::default(),
996             values_valid: Default::default(),
997             well_known_values: false,
998         }
999     }
1000 }
1001
1002 impl<T> CheckCfg<T> {
1003     fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1004         CheckCfg {
1005             names_valid: self
1006                 .names_valid
1007                 .as_ref()
1008                 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1009             values_valid: self
1010                 .values_valid
1011                 .iter()
1012                 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1013                 .collect(),
1014             well_known_values: self.well_known_values,
1015         }
1016     }
1017 }
1018
1019 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1020 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1021 /// but the symbol interner is not yet set up then, so we must convert it later.
1022 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1023     cfg.map_data(|s| Symbol::intern(s))
1024 }
1025
1026 impl CrateCheckConfig {
1027     /// Fills a `CrateCheckConfig` with well-known configuration names.
1028     fn fill_well_known_names(&mut self) {
1029         // NOTE: This should be kept in sync with `default_configuration` and
1030         // `fill_well_known_values`
1031         const WELL_KNOWN_NAMES: &[Symbol] = &[
1032             // rustc
1033             sym::unix,
1034             sym::windows,
1035             sym::target_os,
1036             sym::target_family,
1037             sym::target_arch,
1038             sym::target_endian,
1039             sym::target_pointer_width,
1040             sym::target_env,
1041             sym::target_abi,
1042             sym::target_vendor,
1043             sym::target_thread_local,
1044             sym::target_has_atomic_load_store,
1045             sym::target_has_atomic,
1046             sym::target_has_atomic_equal_alignment,
1047             sym::target_feature,
1048             sym::panic,
1049             sym::sanitize,
1050             sym::debug_assertions,
1051             sym::proc_macro,
1052             sym::test,
1053             sym::feature,
1054             // rustdoc
1055             sym::doc,
1056             sym::doctest,
1057             // miri
1058             sym::miri,
1059         ];
1060
1061         // We only insert well-known names if `names()` was activated
1062         if let Some(names_valid) = &mut self.names_valid {
1063             names_valid.extend(WELL_KNOWN_NAMES);
1064         }
1065     }
1066
1067     /// Fills a `CrateCheckConfig` with well-known configuration values.
1068     fn fill_well_known_values(&mut self) {
1069         if !self.well_known_values {
1070             return;
1071         }
1072
1073         // NOTE: This should be kept in sync with `default_configuration` and
1074         // `fill_well_known_names`
1075
1076         let panic_values = &PanicStrategy::all();
1077
1078         let atomic_values = &[
1079             sym::ptr,
1080             sym::integer(8usize),
1081             sym::integer(16usize),
1082             sym::integer(32usize),
1083             sym::integer(64usize),
1084             sym::integer(128usize),
1085         ];
1086
1087         let sanitize_values = SanitizerSet::all()
1088             .into_iter()
1089             .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1090
1091         // Unknown possible values:
1092         //  - `feature`
1093         //  - `target_feature`
1094
1095         // No-values
1096         for name in [
1097             sym::doc,
1098             sym::miri,
1099             sym::unix,
1100             sym::test,
1101             sym::doctest,
1102             sym::windows,
1103             sym::proc_macro,
1104             sym::debug_assertions,
1105             sym::target_thread_local,
1106         ] {
1107             self.values_valid.entry(name).or_default();
1108         }
1109
1110         // Pre-defined values
1111         self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1112         self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1113         self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1114         self.values_valid
1115             .entry(sym::target_has_atomic_load_store)
1116             .or_default()
1117             .extend(atomic_values);
1118         self.values_valid
1119             .entry(sym::target_has_atomic_equal_alignment)
1120             .or_default()
1121             .extend(atomic_values);
1122
1123         // Target specific values
1124         {
1125             const VALUES: [&Symbol; 8] = [
1126                 &sym::target_os,
1127                 &sym::target_family,
1128                 &sym::target_arch,
1129                 &sym::target_endian,
1130                 &sym::target_env,
1131                 &sym::target_abi,
1132                 &sym::target_vendor,
1133                 &sym::target_pointer_width,
1134             ];
1135
1136             // Initialize (if not already initialized)
1137             for &e in VALUES {
1138                 self.values_valid.entry(e).or_default();
1139             }
1140
1141             // Get all values map at once otherwise it would be costly.
1142             // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1143             let [
1144                 values_target_os,
1145                 values_target_family,
1146                 values_target_arch,
1147                 values_target_endian,
1148                 values_target_env,
1149                 values_target_abi,
1150                 values_target_vendor,
1151                 values_target_pointer_width,
1152             ] = self
1153                 .values_valid
1154                 .get_many_mut(VALUES)
1155                 .expect("unable to get all the check-cfg values buckets");
1156
1157             for target in TARGETS
1158                 .iter()
1159                 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1160             {
1161                 values_target_os.insert(Symbol::intern(&target.options.os));
1162                 values_target_family
1163                     .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1164                 values_target_arch.insert(Symbol::intern(&target.arch));
1165                 values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
1166                 values_target_env.insert(Symbol::intern(&target.options.env));
1167                 values_target_abi.insert(Symbol::intern(&target.options.abi));
1168                 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1169                 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1170             }
1171         }
1172     }
1173
1174     pub fn fill_well_known(&mut self) {
1175         self.fill_well_known_names();
1176         self.fill_well_known_values();
1177     }
1178 }
1179
1180 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1181     // Combine the configuration requested by the session (command line) with
1182     // some default and generated configuration items.
1183     let default_cfg = default_configuration(sess);
1184     // If the user wants a test runner, then add the test cfg.
1185     if sess.opts.test {
1186         user_cfg.insert((sym::test, None));
1187     }
1188     user_cfg.extend(default_cfg.iter().cloned());
1189     user_cfg
1190 }
1191
1192 pub(super) fn build_target_config(
1193     opts: &Options,
1194     target_override: Option<Target>,
1195     sysroot: &Path,
1196 ) -> Target {
1197     let target_result = target_override.map_or_else(
1198         || Target::search(&opts.target_triple, sysroot),
1199         |t| Ok((t, TargetWarnings::empty())),
1200     );
1201     let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1202         early_error(
1203             opts.error_format,
1204             &format!(
1205                 "Error loading target specification: {}. \
1206                  Run `rustc --print target-list` for a list of built-in targets",
1207                 e
1208             ),
1209         )
1210     });
1211     for warning in target_warnings.warning_messages() {
1212         early_warn(opts.error_format, &warning)
1213     }
1214
1215     if !matches!(target.pointer_width, 16 | 32 | 64) {
1216         early_error(
1217             opts.error_format,
1218             &format!(
1219                 "target specification was invalid: \
1220              unrecognized target-pointer-width {}",
1221                 target.pointer_width
1222             ),
1223         )
1224     }
1225
1226     target
1227 }
1228
1229 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1230 pub enum OptionStability {
1231     Stable,
1232     Unstable,
1233 }
1234
1235 pub struct RustcOptGroup {
1236     pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1237     pub name: &'static str,
1238     pub stability: OptionStability,
1239 }
1240
1241 impl RustcOptGroup {
1242     pub fn is_stable(&self) -> bool {
1243         self.stability == OptionStability::Stable
1244     }
1245
1246     pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1247     where
1248         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1249     {
1250         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1251     }
1252
1253     pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1254     where
1255         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1256     {
1257         RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1258     }
1259 }
1260
1261 // The `opt` local module holds wrappers around the `getopts` API that
1262 // adds extra rustc-specific metadata to each option; such metadata
1263 // is exposed by .  The public
1264 // functions below ending with `_u` are the functions that return
1265 // *unstable* options, i.e., options that are only enabled when the
1266 // user also passes the `-Z unstable-options` debugging flag.
1267 mod opt {
1268     // The `fn flag*` etc below are written so that we can use them
1269     // in the future; do not warn about them not being used right now.
1270     #![allow(dead_code)]
1271
1272     use super::RustcOptGroup;
1273
1274     pub type R = RustcOptGroup;
1275     pub type S = &'static str;
1276
1277     fn stable<F>(name: S, f: F) -> R
1278     where
1279         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1280     {
1281         RustcOptGroup::stable(name, f)
1282     }
1283
1284     fn unstable<F>(name: S, f: F) -> R
1285     where
1286         F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1287     {
1288         RustcOptGroup::unstable(name, f)
1289     }
1290
1291     fn longer(a: S, b: S) -> S {
1292         if a.len() > b.len() { a } else { b }
1293     }
1294
1295     pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1296         stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1297     }
1298     pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1299         stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1300     }
1301     pub fn flag_s(a: S, b: S, c: S) -> R {
1302         stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1303     }
1304     pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1305         stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1306     }
1307
1308     pub fn opt(a: S, b: S, c: S, d: S) -> R {
1309         unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1310     }
1311     pub fn multi(a: S, b: S, c: S, d: S) -> R {
1312         unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1313     }
1314 }
1315
1316 /// Returns the "short" subset of the rustc command line options,
1317 /// including metadata for each option, such as whether the option is
1318 /// part of the stable long-term interface for rustc.
1319 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1320     vec![
1321         opt::flag_s("h", "help", "Display this message"),
1322         opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1323         opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1324         opt::multi_s(
1325             "L",
1326             "",
1327             "Add a directory to the library search path. The
1328                              optional KIND can be one of dependency, crate, native,
1329                              framework, or all (the default).",
1330             "[KIND=]PATH",
1331         ),
1332         opt::multi_s(
1333             "l",
1334             "",
1335             "Link the generated crate(s) to the specified native
1336                              library NAME. The optional KIND can be one of
1337                              static, framework, or dylib (the default).
1338                              Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1339                              may be specified each with a prefix of either '+' to
1340                              enable or '-' to disable.",
1341             "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1342         ),
1343         make_crate_type_option(),
1344         opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1345         opt::opt_s(
1346             "",
1347             "edition",
1348             "Specify which edition of the compiler to use when compiling code.",
1349             EDITION_NAME_LIST,
1350         ),
1351         opt::multi_s(
1352             "",
1353             "emit",
1354             "Comma separated list of types of output for \
1355              the compiler to emit",
1356             "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1357         ),
1358         opt::multi_s(
1359             "",
1360             "print",
1361             "Compiler information to print on stdout",
1362             "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
1363              target-list|target-cpus|target-features|relocation-models|code-models|\
1364              tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1365              link-args]",
1366         ),
1367         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1368         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1369         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1370         opt::opt_s(
1371             "",
1372             "out-dir",
1373             "Write output to compiler-chosen filename \
1374              in <dir>",
1375             "DIR",
1376         ),
1377         opt::opt_s(
1378             "",
1379             "explain",
1380             "Provide a detailed explanation of an error \
1381              message",
1382             "OPT",
1383         ),
1384         opt::flag_s("", "test", "Build a test harness"),
1385         opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1386         opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1387         opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1388         opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1389         opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1390         opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1391         opt::multi_s(
1392             "",
1393             "cap-lints",
1394             "Set the most restrictive lint level. \
1395              More restrictive lints are capped at this \
1396              level",
1397             "LEVEL",
1398         ),
1399         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1400         opt::flag_s("V", "version", "Print version info and exit"),
1401         opt::flag_s("v", "verbose", "Use verbose output"),
1402     ]
1403 }
1404
1405 /// Returns all rustc command line options, including metadata for
1406 /// each option, such as whether the option is part of the stable
1407 /// long-term interface for rustc.
1408 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1409     let mut opts = rustc_short_optgroups();
1410     // FIXME: none of these descriptions are actually used
1411     opts.extend(vec![
1412         opt::multi_s(
1413             "",
1414             "extern",
1415             "Specify where an external rust library is located",
1416             "NAME[=PATH]",
1417         ),
1418         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1419         opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1420         opt::opt_s(
1421             "",
1422             "error-format",
1423             "How errors and other messages are produced",
1424             "human|json|short",
1425         ),
1426         opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1427         opt::opt_s(
1428             "",
1429             "color",
1430             "Configure coloring of output:
1431                                  auto   = colorize, if output goes to a tty (default);
1432                                  always = always colorize output;
1433                                  never  = never colorize output",
1434             "auto|always|never",
1435         ),
1436         opt::opt_s(
1437             "",
1438             "diagnostic-width",
1439             "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1440             "WIDTH",
1441         ),
1442         opt::multi_s(
1443             "",
1444             "remap-path-prefix",
1445             "Remap source names in all output (compiler messages and output files)",
1446             "FROM=TO",
1447         ),
1448     ]);
1449     opts
1450 }
1451
1452 pub fn get_cmd_lint_options(
1453     matches: &getopts::Matches,
1454     error_format: ErrorOutputType,
1455 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1456     let mut lint_opts_with_position = vec![];
1457     let mut describe_lints = false;
1458
1459     for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1460         for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1461             if lint_name == "help" {
1462                 describe_lints = true;
1463             } else {
1464                 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1465             }
1466         }
1467     }
1468
1469     lint_opts_with_position.sort_by_key(|x| x.0);
1470     let lint_opts = lint_opts_with_position
1471         .iter()
1472         .cloned()
1473         .map(|(_, lint_name, level)| (lint_name, level))
1474         .collect();
1475
1476     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1477         lint::Level::from_str(&cap)
1478             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1479     });
1480
1481     (lint_opts, describe_lints, lint_cap)
1482 }
1483
1484 /// Parses the `--color` flag.
1485 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1486     match matches.opt_str("color").as_deref() {
1487         Some("auto") => ColorConfig::Auto,
1488         Some("always") => ColorConfig::Always,
1489         Some("never") => ColorConfig::Never,
1490
1491         None => ColorConfig::Auto,
1492
1493         Some(arg) => early_error(
1494             ErrorOutputType::default(),
1495             &format!(
1496                 "argument for `--color` must be auto, \
1497                  always or never (instead was `{arg}`)"
1498             ),
1499         ),
1500     }
1501 }
1502
1503 /// Possible json config files
1504 pub struct JsonConfig {
1505     pub json_rendered: HumanReadableErrorType,
1506     pub json_artifact_notifications: bool,
1507     pub json_unused_externs: JsonUnusedExterns,
1508     pub json_future_incompat: bool,
1509 }
1510
1511 /// Report unused externs in event stream
1512 #[derive(Copy, Clone)]
1513 pub enum JsonUnusedExterns {
1514     /// Do not
1515     No,
1516     /// Report, but do not exit with failure status for deny/forbid
1517     Silent,
1518     /// Report, and also exit with failure status for deny/forbid
1519     Loud,
1520 }
1521
1522 impl JsonUnusedExterns {
1523     pub fn is_enabled(&self) -> bool {
1524         match self {
1525             JsonUnusedExterns::No => false,
1526             JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1527         }
1528     }
1529
1530     pub fn is_loud(&self) -> bool {
1531         match self {
1532             JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1533             JsonUnusedExterns::Loud => true,
1534         }
1535     }
1536 }
1537
1538 /// Parse the `--json` flag.
1539 ///
1540 /// The first value returned is how to render JSON diagnostics, and the second
1541 /// is whether or not artifact notifications are enabled.
1542 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1543     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1544         HumanReadableErrorType::Default;
1545     let mut json_color = ColorConfig::Never;
1546     let mut json_artifact_notifications = false;
1547     let mut json_unused_externs = JsonUnusedExterns::No;
1548     let mut json_future_incompat = false;
1549     for option in matches.opt_strs("json") {
1550         // For now conservatively forbid `--color` with `--json` since `--json`
1551         // won't actually be emitting any colors and anything colorized is
1552         // embedded in a diagnostic message anyway.
1553         if matches.opt_str("color").is_some() {
1554             early_error(
1555                 ErrorOutputType::default(),
1556                 "cannot specify the `--color` option with `--json`",
1557             );
1558         }
1559
1560         for sub_option in option.split(',') {
1561             match sub_option {
1562                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1563                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1564                 "artifacts" => json_artifact_notifications = true,
1565                 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1566                 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1567                 "future-incompat" => json_future_incompat = true,
1568                 s => early_error(
1569                     ErrorOutputType::default(),
1570                     &format!("unknown `--json` option `{s}`"),
1571                 ),
1572             }
1573         }
1574     }
1575
1576     JsonConfig {
1577         json_rendered: json_rendered(json_color),
1578         json_artifact_notifications,
1579         json_unused_externs,
1580         json_future_incompat,
1581     }
1582 }
1583
1584 /// Parses the `--error-format` flag.
1585 pub fn parse_error_format(
1586     matches: &getopts::Matches,
1587     color: ColorConfig,
1588     json_rendered: HumanReadableErrorType,
1589 ) -> ErrorOutputType {
1590     // We need the `opts_present` check because the driver will send us Matches
1591     // with only stable options if no unstable options are used. Since error-format
1592     // is unstable, it will not be present. We have to use `opts_present` not
1593     // `opt_present` because the latter will panic.
1594     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1595         match matches.opt_str("error-format").as_deref() {
1596             None | Some("human") => {
1597                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1598             }
1599             Some("human-annotate-rs") => {
1600                 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1601             }
1602             Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1603             Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1604             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1605
1606             Some(arg) => early_error(
1607                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1608                 &format!(
1609                     "argument for `--error-format` must be `human`, `json` or \
1610                      `short` (instead was `{arg}`)"
1611                 ),
1612             ),
1613         }
1614     } else {
1615         ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1616     };
1617
1618     match error_format {
1619         ErrorOutputType::Json { .. } => {}
1620
1621         // Conservatively require that the `--json` argument is coupled with
1622         // `--error-format=json`. This means that `--json` is specified we
1623         // should actually be emitting JSON blobs.
1624         _ if !matches.opt_strs("json").is_empty() => {
1625             early_error(
1626                 ErrorOutputType::default(),
1627                 "using `--json` requires also using `--error-format=json`",
1628             );
1629         }
1630
1631         _ => {}
1632     }
1633
1634     error_format
1635 }
1636
1637 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1638     let edition = match matches.opt_str("edition") {
1639         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1640             early_error(
1641                 ErrorOutputType::default(),
1642                 &format!(
1643                     "argument for `--edition` must be one of: \
1644                      {EDITION_NAME_LIST}. (instead was `{arg}`)"
1645                 ),
1646             )
1647         }),
1648         None => DEFAULT_EDITION,
1649     };
1650
1651     if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1652         let is_nightly = nightly_options::match_is_nightly_build(matches);
1653         let msg = if !is_nightly {
1654             format!(
1655                 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1656                 edition, LATEST_STABLE_EDITION
1657             )
1658         } else {
1659             format!("edition {edition} is unstable and only available with -Z unstable-options")
1660         };
1661         early_error(ErrorOutputType::default(), &msg)
1662     }
1663
1664     edition
1665 }
1666
1667 fn check_error_format_stability(
1668     unstable_opts: &UnstableOptions,
1669     error_format: ErrorOutputType,
1670     json_rendered: HumanReadableErrorType,
1671 ) {
1672     if !unstable_opts.unstable_options {
1673         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1674             early_error(
1675                 ErrorOutputType::Json { pretty: false, json_rendered },
1676                 "`--error-format=pretty-json` is unstable",
1677             );
1678         }
1679         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1680             error_format
1681         {
1682             early_error(
1683                 ErrorOutputType::Json { pretty: false, json_rendered },
1684                 "`--error-format=human-annotate-rs` is unstable",
1685             );
1686         }
1687     }
1688 }
1689
1690 fn parse_output_types(
1691     unstable_opts: &UnstableOptions,
1692     matches: &getopts::Matches,
1693     error_format: ErrorOutputType,
1694 ) -> OutputTypes {
1695     let mut output_types = BTreeMap::new();
1696     if !unstable_opts.parse_only {
1697         for list in matches.opt_strs("emit") {
1698             for output_type in list.split(',') {
1699                 let (shorthand, path) = match output_type.split_once('=') {
1700                     None => (output_type, None),
1701                     Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1702                 };
1703                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1704                     early_error(
1705                         error_format,
1706                         &format!(
1707                             "unknown emission type: `{shorthand}` - expected one of: {display}",
1708                             display = OutputType::shorthands_display(),
1709                         ),
1710                     )
1711                 });
1712                 output_types.insert(output_type, path);
1713             }
1714         }
1715     };
1716     if output_types.is_empty() {
1717         output_types.insert(OutputType::Exe, None);
1718     }
1719     OutputTypes(output_types)
1720 }
1721
1722 fn should_override_cgus_and_disable_thinlto(
1723     output_types: &OutputTypes,
1724     matches: &getopts::Matches,
1725     error_format: ErrorOutputType,
1726     mut codegen_units: Option<usize>,
1727 ) -> (bool, Option<usize>) {
1728     let mut disable_local_thinlto = false;
1729     // Issue #30063: if user requests LLVM-related output to one
1730     // particular path, disable codegen-units.
1731     let incompatible: Vec<_> = output_types
1732         .0
1733         .iter()
1734         .map(|ot_path| ot_path.0)
1735         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1736         .map(|ot| ot.shorthand())
1737         .collect();
1738     if !incompatible.is_empty() {
1739         match codegen_units {
1740             Some(n) if n > 1 => {
1741                 if matches.opt_present("o") {
1742                     for ot in &incompatible {
1743                         early_warn(
1744                             error_format,
1745                             &format!(
1746                                 "`--emit={ot}` with `-o` incompatible with \
1747                                  `-C codegen-units=N` for N > 1",
1748                             ),
1749                         );
1750                     }
1751                     early_warn(error_format, "resetting to default -C codegen-units=1");
1752                     codegen_units = Some(1);
1753                     disable_local_thinlto = true;
1754                 }
1755             }
1756             _ => {
1757                 codegen_units = Some(1);
1758                 disable_local_thinlto = true;
1759             }
1760         }
1761     }
1762
1763     if codegen_units == Some(0) {
1764         early_error(error_format, "value for codegen units must be a positive non-zero integer");
1765     }
1766
1767     (disable_local_thinlto, codegen_units)
1768 }
1769
1770 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1771     if unstable_opts.threads == 0 {
1772         early_error(error_format, "value for threads must be a positive non-zero integer");
1773     }
1774
1775     if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
1776         early_error(error_format, "optimization fuel is incompatible with multiple threads");
1777     }
1778 }
1779
1780 fn collect_print_requests(
1781     cg: &mut CodegenOptions,
1782     unstable_opts: &mut UnstableOptions,
1783     matches: &getopts::Matches,
1784     error_format: ErrorOutputType,
1785 ) -> Vec<PrintRequest> {
1786     let mut prints = Vec::<PrintRequest>::new();
1787     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1788         prints.push(PrintRequest::TargetCPUs);
1789         cg.target_cpu = None;
1790     };
1791     if cg.target_feature == "help" {
1792         prints.push(PrintRequest::TargetFeatures);
1793         cg.target_feature = String::new();
1794     }
1795
1796     const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
1797         ("crate-name", PrintRequest::CrateName),
1798         ("file-names", PrintRequest::FileNames),
1799         ("sysroot", PrintRequest::Sysroot),
1800         ("target-libdir", PrintRequest::TargetLibdir),
1801         ("cfg", PrintRequest::Cfg),
1802         ("calling-conventions", PrintRequest::CallingConventions),
1803         ("target-list", PrintRequest::TargetList),
1804         ("target-cpus", PrintRequest::TargetCPUs),
1805         ("target-features", PrintRequest::TargetFeatures),
1806         ("relocation-models", PrintRequest::RelocationModels),
1807         ("code-models", PrintRequest::CodeModels),
1808         ("tls-models", PrintRequest::TlsModels),
1809         ("native-static-libs", PrintRequest::NativeStaticLibs),
1810         ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
1811         ("target-spec-json", PrintRequest::TargetSpec),
1812         ("link-args", PrintRequest::LinkArgs),
1813         ("split-debuginfo", PrintRequest::SplitDebuginfo),
1814     ];
1815
1816     prints.extend(matches.opt_strs("print").into_iter().map(|req| {
1817         match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
1818             Some((_, PrintRequest::TargetSpec)) => {
1819                 if unstable_opts.unstable_options {
1820                     PrintRequest::TargetSpec
1821                 } else {
1822                     early_error(
1823                         error_format,
1824                         "the `-Z unstable-options` flag must also be passed to \
1825                      enable the target-spec-json print option",
1826                     );
1827                 }
1828             }
1829             Some(&(_, print_request)) => print_request,
1830             None => {
1831                 let prints =
1832                     PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
1833                 let prints = prints.join(", ");
1834                 early_error(
1835                     error_format,
1836                     &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
1837                 );
1838             }
1839         }
1840     }));
1841
1842     prints
1843 }
1844
1845 pub fn parse_target_triple(
1846     matches: &getopts::Matches,
1847     error_format: ErrorOutputType,
1848 ) -> TargetTriple {
1849     match matches.opt_str("target") {
1850         Some(target) if target.ends_with(".json") => {
1851             let path = Path::new(&target);
1852             TargetTriple::from_path(path).unwrap_or_else(|_| {
1853                 early_error(error_format, &format!("target file {path:?} does not exist"))
1854             })
1855         }
1856         Some(target) => TargetTriple::TargetTriple(target),
1857         _ => TargetTriple::from_triple(host_triple()),
1858     }
1859 }
1860
1861 fn parse_opt_level(
1862     matches: &getopts::Matches,
1863     cg: &CodegenOptions,
1864     error_format: ErrorOutputType,
1865 ) -> OptLevel {
1866     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1867     // to use them interchangeably. However, because they're technically different flags,
1868     // we need to work out manually which should take precedence if both are supplied (i.e.
1869     // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1870     // comparing them. Note that if a flag is not found, its position will be `None`, which
1871     // always compared less than `Some(_)`.
1872     let max_o = matches.opt_positions("O").into_iter().max();
1873     let max_c = matches
1874         .opt_strs_pos("C")
1875         .into_iter()
1876         .flat_map(|(i, s)| {
1877             // NB: This can match a string without `=`.
1878             if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
1879         })
1880         .max();
1881     if max_o > max_c {
1882         OptLevel::Default
1883     } else {
1884         match cg.opt_level.as_ref() {
1885             "0" => OptLevel::No,
1886             "1" => OptLevel::Less,
1887             "2" => OptLevel::Default,
1888             "3" => OptLevel::Aggressive,
1889             "s" => OptLevel::Size,
1890             "z" => OptLevel::SizeMin,
1891             arg => {
1892                 early_error(
1893                     error_format,
1894                     &format!(
1895                         "optimization level needs to be \
1896                             between 0-3, s or z (instead was `{arg}`)"
1897                     ),
1898                 );
1899             }
1900         }
1901     }
1902 }
1903
1904 fn select_debuginfo(
1905     matches: &getopts::Matches,
1906     cg: &CodegenOptions,
1907     error_format: ErrorOutputType,
1908 ) -> DebugInfo {
1909     let max_g = matches.opt_positions("g").into_iter().max();
1910     let max_c = matches
1911         .opt_strs_pos("C")
1912         .into_iter()
1913         .flat_map(|(i, s)| {
1914             // NB: This can match a string without `=`.
1915             if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
1916         })
1917         .max();
1918     if max_g > max_c {
1919         DebugInfo::Full
1920     } else {
1921         match cg.debuginfo {
1922             0 => DebugInfo::None,
1923             1 => DebugInfo::Limited,
1924             2 => DebugInfo::Full,
1925             arg => {
1926                 early_error(
1927                     error_format,
1928                     &format!(
1929                         "debug info level needs to be between \
1930                          0-2 (instead was `{arg}`)"
1931                     ),
1932                 );
1933             }
1934         }
1935     }
1936 }
1937
1938 pub(crate) fn parse_assert_incr_state(
1939     opt_assertion: &Option<String>,
1940     error_format: ErrorOutputType,
1941 ) -> Option<IncrementalStateAssertion> {
1942     match opt_assertion {
1943         Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1944         Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1945         Some(s) => {
1946             early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1947         }
1948         None => None,
1949     }
1950 }
1951
1952 fn parse_native_lib_kind(
1953     matches: &getopts::Matches,
1954     kind: &str,
1955     error_format: ErrorOutputType,
1956 ) -> (NativeLibKind, Option<bool>) {
1957     let (kind, modifiers) = match kind.split_once(':') {
1958         None => (kind, None),
1959         Some((kind, modifiers)) => (kind, Some(modifiers)),
1960     };
1961
1962     let kind = match kind {
1963         "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1964         "dylib" => NativeLibKind::Dylib { as_needed: None },
1965         "framework" => NativeLibKind::Framework { as_needed: None },
1966         "link-arg" => {
1967             if !nightly_options::is_unstable_enabled(matches) {
1968                 let why = if nightly_options::match_is_nightly_build(matches) {
1969                     " and only accepted on the nightly compiler"
1970                 } else {
1971                     ", the `-Z unstable-options` flag must also be passed to use it"
1972                 };
1973                 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
1974             }
1975             NativeLibKind::LinkArg
1976         }
1977         _ => early_error(
1978             error_format,
1979             &format!(
1980                 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
1981             ),
1982         ),
1983     };
1984     match modifiers {
1985         None => (kind, None),
1986         Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
1987     }
1988 }
1989
1990 fn parse_native_lib_modifiers(
1991     mut kind: NativeLibKind,
1992     modifiers: &str,
1993     error_format: ErrorOutputType,
1994     matches: &getopts::Matches,
1995 ) -> (NativeLibKind, Option<bool>) {
1996     let mut verbatim = None;
1997     for modifier in modifiers.split(',') {
1998         let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
1999             Some(m) => (m, modifier.starts_with('+')),
2000             None => early_error(
2001                 error_format,
2002                 "invalid linking modifier syntax, expected '+' or '-' prefix \
2003                  before one of: bundle, verbatim, whole-archive, as-needed",
2004             ),
2005         };
2006
2007         let report_unstable_modifier = || {
2008             if !nightly_options::is_unstable_enabled(matches) {
2009                 let why = if nightly_options::match_is_nightly_build(matches) {
2010                     " and only accepted on the nightly compiler"
2011                 } else {
2012                     ", the `-Z unstable-options` flag must also be passed to use it"
2013                 };
2014                 early_error(
2015                     error_format,
2016                     &format!("linking modifier `{modifier}` is unstable{why}"),
2017                 )
2018             }
2019         };
2020         let assign_modifier = |dst: &mut Option<bool>| {
2021             if dst.is_some() {
2022                 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2023                 early_error(error_format, &msg)
2024             } else {
2025                 *dst = Some(value);
2026             }
2027         };
2028         match (modifier, &mut kind) {
2029             ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2030             ("bundle", _) => early_error(
2031                 error_format,
2032                 "linking modifier `bundle` is only compatible with `static` linking kind",
2033             ),
2034
2035             ("verbatim", _) => assign_modifier(&mut verbatim),
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 }
2984
2985 /// Which format to use for `-Z dump-mono-stats`
2986 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
2987 pub enum DumpMonoStatsFormat {
2988     /// Pretty-print a markdown table
2989     Markdown,
2990     /// Emit structured JSON
2991     Json,
2992 }
2993
2994 impl DumpMonoStatsFormat {
2995     pub fn extension(self) -> &'static str {
2996         match self {
2997             Self::Markdown => "md",
2998             Self::Json => "json",
2999         }
3000     }
3001 }