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