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