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