rustc_session/
config.rs

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