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