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