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