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