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