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