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