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