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