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