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