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