1#![allow(rustc::untranslatable_diagnostic)] use 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, SplitDebuginfo, Target, TargetTuple,
33};
34use tracing::debug;
35
36pub use crate::config::cfg::{Cfg, CheckCfg, ExpectedValues};
37use crate::config::native_libs::parse_native_libs;
38use crate::errors::FileWriteFail;
39pub use crate::options::*;
40use crate::search_paths::SearchPath;
41use crate::utils::CanonicalizedPath;
42use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint};
43
44mod cfg;
45mod externs;
46mod native_libs;
47pub mod sigpipe;
48
49pub const PRINT_KINDS: &[(&str, PrintKind)] = &[
50    ("all-target-specs-json", PrintKind::AllTargetSpecsJson),
52    ("calling-conventions", PrintKind::CallingConventions),
53    ("cfg", PrintKind::Cfg),
54    ("check-cfg", PrintKind::CheckCfg),
55    ("code-models", PrintKind::CodeModels),
56    ("crate-name", PrintKind::CrateName),
57    ("crate-root-lint-levels", PrintKind::CrateRootLintLevels),
58    ("deployment-target", PrintKind::DeploymentTarget),
59    ("file-names", PrintKind::FileNames),
60    ("host-tuple", PrintKind::HostTuple),
61    ("link-args", PrintKind::LinkArgs),
62    ("native-static-libs", PrintKind::NativeStaticLibs),
63    ("relocation-models", PrintKind::RelocationModels),
64    ("split-debuginfo", PrintKind::SplitDebuginfo),
65    ("stack-protector-strategies", PrintKind::StackProtectorStrategies),
66    ("supported-crate-types", PrintKind::SupportedCrateTypes),
67    ("sysroot", PrintKind::Sysroot),
68    ("target-cpus", PrintKind::TargetCPUs),
69    ("target-features", PrintKind::TargetFeatures),
70    ("target-libdir", PrintKind::TargetLibdir),
71    ("target-list", PrintKind::TargetList),
72    ("target-spec-json", PrintKind::TargetSpecJson),
73    ("target-spec-json-schema", PrintKind::TargetSpecJsonSchema),
74    ("tls-models", PrintKind::TlsModels),
75    ];
77
78#[derive(Clone, Copy, PartialEq, Hash, Debug)]
80pub enum Strip {
81    None,
83
84    Debuginfo,
86
87    Symbols,
89}
90
91#[derive(Clone, Copy, PartialEq, Hash, Debug)]
93pub enum CFGuard {
94    Disabled,
96
97    NoChecks,
99
100    Checks,
102}
103
104#[derive(Clone, Copy, PartialEq, Hash, Debug)]
106pub enum CFProtection {
107    None,
109
110    Branch,
112
113    Return,
115
116    Full,
118}
119
120#[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
121pub enum OptLevel {
122    No,
124    Less,
126    More,
128    Aggressive,
130    Size,
132    SizeMin,
134}
135
136#[derive(Clone, PartialEq)]
141pub enum Lto {
142    No,
144
145    Thin,
147
148    ThinLocal,
151
152    Fat,
154}
155
156#[derive(Clone, Copy, PartialEq, Hash, Debug)]
158pub enum LtoCli {
159    No,
161    Yes,
163    NoParam,
165    Thin,
167    Fat,
169    Unspecified,
171}
172
173#[derive(Clone, Copy, PartialEq, Hash, Debug)]
175pub enum InstrumentCoverage {
176    No,
178    Yes,
180}
181
182#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
184pub struct CoverageOptions {
185    pub level: CoverageLevel,
186
187    pub discard_all_spans_in_codegen: bool,
193}
194
195#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
197pub enum CoverageLevel {
198    #[default]
200    Block,
201    Branch,
203    Condition,
219}
220
221#[derive(Clone, Copy, PartialEq, Hash, Debug)]
223pub enum Offload {
224    Enable,
226}
227
228#[derive(Clone, PartialEq, Hash, Debug)]
230pub enum AutoDiff {
231    Enable,
233
234    PrintTA,
236    PrintTAFn(String),
238    PrintAA,
240    PrintPerf,
242    PrintSteps,
244    PrintModBefore,
246    PrintModAfter,
248    PrintModFinal,
250
251    PrintPasses,
253    NoPostopt,
255    LooseTypes,
258    Inline,
260}
261
262#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
264pub struct InstrumentXRay {
265    pub always: bool,
267    pub never: bool,
269    pub ignore_loops: bool,
272    pub instruction_threshold: Option<usize>,
275    pub skip_entry: bool,
277    pub skip_exit: bool,
279}
280
281#[derive(Clone, PartialEq, Hash, Debug)]
282pub enum LinkerPluginLto {
283    LinkerPlugin(PathBuf),
284    LinkerPluginAuto,
285    Disabled,
286}
287
288impl LinkerPluginLto {
289    pub fn enabled(&self) -> bool {
290        match *self {
291            LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
292            LinkerPluginLto::Disabled => false,
293        }
294    }
295}
296
297#[derive(Default, Clone, PartialEq, Debug)]
313pub struct LinkSelfContained {
314    pub explicitly_set: Option<bool>,
317
318    enabled_components: LinkSelfContainedComponents,
321
322    disabled_components: LinkSelfContainedComponents,
325}
326
327impl LinkSelfContained {
328    pub(crate) fn handle_cli_component(&mut self, component: &str) -> Option<()> {
331        if let Some(component_to_enable) = component.strip_prefix('+') {
336            self.explicitly_set = None;
337            self.enabled_components
338                .insert(LinkSelfContainedComponents::from_str(component_to_enable).ok()?);
339            Some(())
340        } else if let Some(component_to_disable) = component.strip_prefix('-') {
341            self.explicitly_set = None;
342            self.disabled_components
343                .insert(LinkSelfContainedComponents::from_str(component_to_disable).ok()?);
344            Some(())
345        } else {
346            None
347        }
348    }
349
350    pub(crate) fn set_all_explicitly(&mut self, enabled: bool) {
353        self.explicitly_set = Some(enabled);
354
355        if enabled {
356            self.enabled_components = LinkSelfContainedComponents::all();
357            self.disabled_components = LinkSelfContainedComponents::empty();
358        } else {
359            self.enabled_components = LinkSelfContainedComponents::empty();
360            self.disabled_components = LinkSelfContainedComponents::all();
361        }
362    }
363
364    pub fn on() -> Self {
366        let mut on = LinkSelfContained::default();
367        on.set_all_explicitly(true);
368        on
369    }
370
371    fn check_unstable_variants(&self, target_tuple: &TargetTuple) -> Result<(), String> {
375        if self.explicitly_set.is_some() {
376            return Ok(());
377        }
378
379        let has_minus_linker = self.disabled_components.is_linker_enabled();
381        if has_minus_linker && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
382            return Err(format!(
383                "`-C link-self-contained=-linker` is unstable on the `{target_tuple}` \
384                    target. The `-Z unstable-options` flag must also be passed to use it on this target",
385            ));
386        }
387
388        let unstable_enabled = self.enabled_components;
390        let unstable_disabled = self.disabled_components - LinkSelfContainedComponents::LINKER;
391        if !unstable_enabled.union(unstable_disabled).is_empty() {
392            return Err(String::from(
393                "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` \
394                are stable, the `-Z unstable-options` flag must also be passed to use \
395                the unstable values",
396            ));
397        }
398
399        Ok(())
400    }
401
402    pub fn is_linker_enabled(&self) -> bool {
405        self.enabled_components.contains(LinkSelfContainedComponents::LINKER)
406    }
407
408    pub fn is_linker_disabled(&self) -> bool {
411        self.disabled_components.contains(LinkSelfContainedComponents::LINKER)
412    }
413
414    fn check_consistency(&self) -> Option<LinkSelfContainedComponents> {
417        if self.explicitly_set.is_some() {
418            None
419        } else {
420            let common = self.enabled_components.intersection(self.disabled_components);
421            if common.is_empty() { None } else { Some(common) }
422        }
423    }
424}
425
426#[derive(Default, Copy, Clone, PartialEq, Debug)]
435pub struct LinkerFeaturesCli {
436    pub enabled: LinkerFeatures,
438
439    pub disabled: LinkerFeatures,
441}
442
443impl LinkerFeaturesCli {
444    pub(crate) fn handle_cli_feature(&mut self, feature: &str) -> Option<()> {
447        match feature {
453            "+lld" => {
454                self.enabled.insert(LinkerFeatures::LLD);
455                self.disabled.remove(LinkerFeatures::LLD);
456                Some(())
457            }
458            "-lld" => {
459                self.disabled.insert(LinkerFeatures::LLD);
460                self.enabled.remove(LinkerFeatures::LLD);
461                Some(())
462            }
463            _ => None,
464        }
465    }
466
467    pub(crate) fn check_unstable_variants(&self, target_tuple: &TargetTuple) -> Result<(), String> {
472        let has_minus_lld = self.disabled.is_lld_enabled();
474        if has_minus_lld && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
475            return Err(format!(
476                "`-C linker-features=-lld` is unstable on the `{target_tuple}` \
477                    target. The `-Z unstable-options` flag must also be passed to use it on this target",
478            ));
479        }
480
481        let unstable_enabled = self.enabled;
483        let unstable_disabled = self.disabled - LinkerFeatures::LLD;
484        if !unstable_enabled.union(unstable_disabled).is_empty() {
485            let unstable_features: Vec<_> = unstable_enabled
486                .iter()
487                .map(|f| format!("+{}", f.as_str().unwrap()))
488                .chain(unstable_disabled.iter().map(|f| format!("-{}", f.as_str().unwrap())))
489                .collect();
490            return Err(format!(
491                "`-C linker-features={}` is unstable, and also requires the \
492                `-Z unstable-options` flag to be used",
493                unstable_features.join(","),
494            ));
495        }
496
497        Ok(())
498    }
499}
500
501#[derive(Clone, Copy, PartialEq, Hash, Debug)]
503pub enum IncrementalStateAssertion {
504    Loaded,
509    NotLoaded,
511}
512
513#[derive(Copy, Clone, PartialEq, Hash, Debug)]
515pub struct LocationDetail {
516    pub file: bool,
517    pub line: bool,
518    pub column: bool,
519}
520
521impl LocationDetail {
522    pub(crate) fn all() -> Self {
523        Self { file: true, line: true, column: true }
524    }
525}
526
527#[derive(Copy, Clone, PartialEq, Hash, Debug)]
529pub enum FmtDebug {
530    Full,
532    Shallow,
534    None,
536}
537
538impl FmtDebug {
539    pub(crate) fn all() -> [Symbol; 3] {
540        [sym::full, sym::none, sym::shallow]
541    }
542}
543
544#[derive(Clone, PartialEq, Hash, Debug)]
545pub enum SwitchWithOptPath {
546    Enabled(Option<PathBuf>),
547    Disabled,
548}
549
550impl SwitchWithOptPath {
551    pub fn enabled(&self) -> bool {
552        match *self {
553            SwitchWithOptPath::Enabled(_) => true,
554            SwitchWithOptPath::Disabled => false,
555        }
556    }
557}
558
559#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
560#[derive(Encodable, Decodable)]
561pub enum SymbolManglingVersion {
562    Legacy,
563    V0,
564    Hashed,
565}
566
567#[derive(Clone, Copy, Debug, PartialEq, Hash)]
568pub enum DebugInfo {
569    None,
570    LineDirectivesOnly,
571    LineTablesOnly,
572    Limited,
573    Full,
574}
575
576#[derive(Clone, Copy, Debug, PartialEq, Hash)]
577pub enum DebugInfoCompression {
578    None,
579    Zlib,
580    Zstd,
581}
582
583impl ToString for DebugInfoCompression {
584    fn to_string(&self) -> String {
585        match self {
586            DebugInfoCompression::None => "none",
587            DebugInfoCompression::Zlib => "zlib",
588            DebugInfoCompression::Zstd => "zstd",
589        }
590        .to_owned()
591    }
592}
593
594#[derive(Clone, Copy, Debug, PartialEq, Hash)]
595pub enum MirStripDebugInfo {
596    None,
597    LocalsInTinyFunctions,
598    AllLocals,
599}
600
601#[derive(Clone, Copy, Debug, PartialEq, Hash)]
611pub enum SplitDwarfKind {
612    Single,
615    Split,
618}
619
620impl FromStr for SplitDwarfKind {
621    type Err = ();
622
623    fn from_str(s: &str) -> Result<Self, ()> {
624        Ok(match s {
625            "single" => SplitDwarfKind::Single,
626            "split" => SplitDwarfKind::Split,
627            _ => return Err(()),
628        })
629    }
630}
631
632macro_rules! define_output_types {
633    (
634        $(
635            $(#[doc = $doc:expr])*
636            $Variant:ident => {
637                shorthand: $shorthand:expr,
638                extension: $extension:expr,
639                description: $description:expr,
640                default_filename: $default_filename:expr,
641                is_text: $is_text:expr,
642                compatible_with_cgus_and_single_output: $compatible:expr
643            }
644        ),* $(,)?
645    ) => {
646        #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
647        #[derive(Encodable, Decodable)]
648        pub enum OutputType {
649            $(
650                $(#[doc = $doc])*
651                $Variant,
652            )*
653        }
654
655
656        impl StableOrd for OutputType {
657            const CAN_USE_UNSTABLE_SORT: bool = true;
658
659            const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
661        }
662
663        impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
664            type KeyType = Self;
665
666            fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
667                *self
668            }
669        }
670
671
672        impl OutputType {
673            pub fn iter_all() -> impl Iterator<Item = OutputType> {
674                static ALL_VARIANTS: &[OutputType] = &[
675                    $(
676                        OutputType::$Variant,
677                    )*
678                ];
679                ALL_VARIANTS.iter().copied()
680            }
681
682            fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
683                match *self {
684                    $(
685                        OutputType::$Variant => $compatible,
686                    )*
687                }
688            }
689
690            pub fn shorthand(&self) -> &'static str {
691                match *self {
692                    $(
693                        OutputType::$Variant => $shorthand,
694                    )*
695                }
696            }
697
698            fn from_shorthand(shorthand: &str) -> Option<Self> {
699                match shorthand {
700                    $(
701                        s if s == $shorthand => Some(OutputType::$Variant),
702                    )*
703                    _ => None,
704                }
705            }
706
707            fn shorthands_display() -> String {
708                let shorthands = vec![
709                    $(
710                        format!("`{}`", $shorthand),
711                    )*
712                ];
713                shorthands.join(", ")
714            }
715
716            pub fn extension(&self) -> &'static str {
717                match *self {
718                    $(
719                        OutputType::$Variant => $extension,
720                    )*
721                }
722            }
723
724            pub fn is_text_output(&self) -> bool {
725                match *self {
726                    $(
727                        OutputType::$Variant => $is_text,
728                    )*
729                }
730            }
731
732            pub fn description(&self) -> &'static str {
733                match *self {
734                    $(
735                        OutputType::$Variant => $description,
736                    )*
737                }
738            }
739
740            pub fn default_filename(&self) -> &'static str {
741                match *self {
742                    $(
743                        OutputType::$Variant => $default_filename,
744                    )*
745                }
746            }
747
748
749        }
750    }
751}
752
753define_output_types! {
754    Assembly => {
755        shorthand: "asm",
756        extension: "s",
757        description: "Generates a file with the crate's assembly code",
758        default_filename: "CRATE_NAME.s",
759        is_text: true,
760        compatible_with_cgus_and_single_output: false
761    },
762    #[doc = "This is the optimized bitcode, which could be either pre-LTO or non-LTO bitcode,"]
763    #[doc = "depending on the specific request type."]
764    Bitcode => {
765        shorthand: "llvm-bc",
766        extension: "bc",
767        description: "Generates a binary file containing the LLVM bitcode",
768        default_filename: "CRATE_NAME.bc",
769        is_text: false,
770        compatible_with_cgus_and_single_output: false
771    },
772    DepInfo => {
773        shorthand: "dep-info",
774        extension: "d",
775        description: "Generates a file with Makefile syntax that indicates all the source files that were loaded to generate the crate",
776        default_filename: "CRATE_NAME.d",
777        is_text: true,
778        compatible_with_cgus_and_single_output: true
779    },
780    Exe => {
781        shorthand: "link",
782        extension: "",
783        description: "Generates the crates specified by --crate-type. This is the default if --emit is not specified",
784        default_filename: "(platform and crate-type dependent)",
785        is_text: false,
786        compatible_with_cgus_and_single_output: true
787    },
788    LlvmAssembly => {
789        shorthand: "llvm-ir",
790        extension: "ll",
791        description: "Generates a file containing LLVM IR",
792        default_filename: "CRATE_NAME.ll",
793        is_text: true,
794        compatible_with_cgus_and_single_output: false
795    },
796    Metadata => {
797        shorthand: "metadata",
798        extension: "rmeta",
799        description: "Generates a file containing metadata about the crate",
800        default_filename: "libCRATE_NAME.rmeta",
801        is_text: false,
802        compatible_with_cgus_and_single_output: true
803    },
804    Mir => {
805        shorthand: "mir",
806        extension: "mir",
807        description: "Generates a file containing rustc's mid-level intermediate representation",
808        default_filename: "CRATE_NAME.mir",
809        is_text: true,
810        compatible_with_cgus_and_single_output: false
811    },
812    Object => {
813        shorthand: "obj",
814        extension: "o",
815        description: "Generates a native object file",
816        default_filename: "CRATE_NAME.o",
817        is_text: false,
818        compatible_with_cgus_and_single_output: false
819    },
820    #[doc = "This is the summary or index data part of the ThinLTO bitcode."]
821    ThinLinkBitcode => {
822        shorthand: "thin-link-bitcode",
823        extension: "indexing.o",
824        description: "Generates the ThinLTO summary as bitcode",
825        default_filename: "CRATE_NAME.indexing.o",
826        is_text: false,
827        compatible_with_cgus_and_single_output: false
828    },
829}
830
831#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
833pub enum ErrorOutputType {
834    #[default]
836    HumanReadable {
837        kind: HumanReadableErrorType = HumanReadableErrorType::Default,
838        color_config: ColorConfig = ColorConfig::Auto,
839    },
840    Json {
842        pretty: bool,
844        json_rendered: HumanReadableErrorType,
847        color_config: ColorConfig,
848    },
849}
850
851#[derive(Clone, Hash, Debug)]
852pub enum ResolveDocLinks {
853    None,
855    ExportedMetadata,
857    Exported,
859    All,
861}
862
863#[derive(Clone, Debug, Hash, HashStable_Generic, Encodable, Decodable)]
868pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>);
869
870impl OutputTypes {
871    pub fn new(entries: &[(OutputType, Option<OutFileName>)]) -> OutputTypes {
872        OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
873    }
874
875    pub(crate) fn get(&self, key: &OutputType) -> Option<&Option<OutFileName>> {
876        self.0.get(key)
877    }
878
879    pub fn contains_key(&self, key: &OutputType) -> bool {
880        self.0.contains_key(key)
881    }
882
883    pub fn contains_explicit_name(&self, key: &OutputType) -> bool {
885        matches!(self.0.get(key), Some(Some(..)))
886    }
887
888    pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> {
889        self.0.iter()
890    }
891
892    pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<OutFileName>> {
893        self.0.keys()
894    }
895
896    pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<OutFileName>> {
897        self.0.values()
898    }
899
900    pub fn len(&self) -> usize {
901        self.0.len()
902    }
903
904    pub fn should_codegen(&self) -> bool {
906        self.0.keys().any(|k| match *k {
907            OutputType::Bitcode
908            | OutputType::ThinLinkBitcode
909            | OutputType::Assembly
910            | OutputType::LlvmAssembly
911            | OutputType::Mir
912            | OutputType::Object
913            | OutputType::Exe => true,
914            OutputType::Metadata | OutputType::DepInfo => false,
915        })
916    }
917
918    pub fn should_link(&self) -> bool {
920        self.0.keys().any(|k| match *k {
921            OutputType::Bitcode
922            | OutputType::ThinLinkBitcode
923            | OutputType::Assembly
924            | OutputType::LlvmAssembly
925            | OutputType::Mir
926            | OutputType::Metadata
927            | OutputType::Object
928            | OutputType::DepInfo => false,
929            OutputType::Exe => true,
930        })
931    }
932}
933
934#[derive(Clone)]
938pub struct Externs(BTreeMap<String, ExternEntry>);
939
940#[derive(Clone, Debug)]
941pub struct ExternEntry {
942    pub location: ExternLocation,
943    pub is_private_dep: bool,
949    pub add_prelude: bool,
954    pub nounused_dep: bool,
959    pub force: bool,
965}
966
967#[derive(Clone, Debug)]
968pub enum ExternLocation {
969    FoundInLibrarySearchDirectories,
973    ExactPaths(BTreeSet<CanonicalizedPath>),
980}
981
982impl Externs {
983    pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
985        Externs(data)
986    }
987
988    pub fn get(&self, key: &str) -> Option<&ExternEntry> {
989        self.0.get(key)
990    }
991
992    pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
993        self.0.iter()
994    }
995}
996
997impl ExternEntry {
998    fn new(location: ExternLocation) -> ExternEntry {
999        ExternEntry {
1000            location,
1001            is_private_dep: false,
1002            add_prelude: false,
1003            nounused_dep: false,
1004            force: false,
1005        }
1006    }
1007
1008    pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
1009        match &self.location {
1010            ExternLocation::ExactPaths(set) => Some(set.iter()),
1011            _ => None,
1012        }
1013    }
1014}
1015
1016#[derive(Clone, PartialEq, Debug)]
1017pub struct PrintRequest {
1018    pub kind: PrintKind,
1019    pub out: OutFileName,
1020}
1021
1022#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1023pub enum PrintKind {
1024    AllTargetSpecsJson,
1026    CallingConventions,
1027    Cfg,
1028    CheckCfg,
1029    CodeModels,
1030    CrateName,
1031    CrateRootLintLevels,
1032    DeploymentTarget,
1033    FileNames,
1034    HostTuple,
1035    LinkArgs,
1036    NativeStaticLibs,
1037    RelocationModels,
1038    SplitDebuginfo,
1039    StackProtectorStrategies,
1040    SupportedCrateTypes,
1041    Sysroot,
1042    TargetCPUs,
1043    TargetFeatures,
1044    TargetLibdir,
1045    TargetList,
1046    TargetSpecJson,
1047    TargetSpecJsonSchema,
1048    TlsModels,
1049    }
1051
1052#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]
1053pub struct NextSolverConfig {
1054    pub coherence: bool = true,
1056    pub globally: bool = false,
1059}
1060
1061#[derive(Clone)]
1062pub enum Input {
1063    File(PathBuf),
1065    Str {
1067        name: FileName,
1069        input: String,
1071    },
1072}
1073
1074impl Input {
1075    pub fn filestem(&self) -> &str {
1076        if let Input::File(ifile) = self {
1077            if let Some(name) = ifile.file_stem().and_then(OsStr::to_str) {
1080                return name;
1081            }
1082        }
1083        "rust_out"
1084    }
1085
1086    pub fn source_name(&self) -> FileName {
1087        match *self {
1088            Input::File(ref ifile) => ifile.clone().into(),
1089            Input::Str { ref name, .. } => name.clone(),
1090        }
1091    }
1092
1093    pub fn opt_path(&self) -> Option<&Path> {
1094        match self {
1095            Input::File(file) => Some(file),
1096            Input::Str { name, .. } => match name {
1097                FileName::Real(real) => real.local_path(),
1098                FileName::CfgSpec(_) => None,
1099                FileName::Anon(_) => None,
1100                FileName::MacroExpansion(_) => None,
1101                FileName::ProcMacroSourceCode(_) => None,
1102                FileName::CliCrateAttr(_) => None,
1103                FileName::Custom(_) => None,
1104                FileName::DocTest(path, _) => Some(path),
1105                FileName::InlineAsm(_) => None,
1106            },
1107        }
1108    }
1109}
1110
1111#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq, Encodable, Decodable)]
1112pub enum OutFileName {
1113    Real(PathBuf),
1114    Stdout,
1115}
1116
1117impl OutFileName {
1118    pub fn parent(&self) -> Option<&Path> {
1119        match *self {
1120            OutFileName::Real(ref path) => path.parent(),
1121            OutFileName::Stdout => None,
1122        }
1123    }
1124
1125    pub fn filestem(&self) -> Option<&OsStr> {
1126        match *self {
1127            OutFileName::Real(ref path) => path.file_stem(),
1128            OutFileName::Stdout => Some(OsStr::new("stdout")),
1129        }
1130    }
1131
1132    pub fn is_stdout(&self) -> bool {
1133        match *self {
1134            OutFileName::Real(_) => false,
1135            OutFileName::Stdout => true,
1136        }
1137    }
1138
1139    pub fn is_tty(&self) -> bool {
1140        use std::io::IsTerminal;
1141        match *self {
1142            OutFileName::Real(_) => false,
1143            OutFileName::Stdout => std::io::stdout().is_terminal(),
1144        }
1145    }
1146
1147    pub fn as_path(&self) -> &Path {
1148        match *self {
1149            OutFileName::Real(ref path) => path.as_ref(),
1150            OutFileName::Stdout => Path::new("stdout"),
1151        }
1152    }
1153
1154    pub fn file_for_writing(
1160        &self,
1161        outputs: &OutputFilenames,
1162        flavor: OutputType,
1163        codegen_unit_name: &str,
1164        invocation_temp: Option<&str>,
1165    ) -> PathBuf {
1166        match *self {
1167            OutFileName::Real(ref path) => path.clone(),
1168            OutFileName::Stdout => {
1169                outputs.temp_path_for_cgu(flavor, codegen_unit_name, invocation_temp)
1170            }
1171        }
1172    }
1173
1174    pub fn overwrite(&self, content: &str, sess: &Session) {
1175        match self {
1176            OutFileName::Stdout => print!("{content}"),
1177            OutFileName::Real(path) => {
1178                if let Err(e) = fs::write(path, content) {
1179                    sess.dcx().emit_fatal(FileWriteFail { path, err: e.to_string() });
1180                }
1181            }
1182        }
1183    }
1184}
1185
1186#[derive(Clone, Hash, Debug, HashStable_Generic, Encodable, Decodable)]
1187pub struct OutputFilenames {
1188    pub(crate) out_directory: PathBuf,
1189    crate_stem: String,
1191    filestem: String,
1193    pub single_output_file: Option<OutFileName>,
1194    temps_directory: Option<PathBuf>,
1195    pub outputs: OutputTypes,
1196}
1197
1198pub const RLINK_EXT: &str = "rlink";
1199pub const RUST_CGU_EXT: &str = "rcgu";
1200pub const DWARF_OBJECT_EXT: &str = "dwo";
1201pub const MAX_FILENAME_LENGTH: usize = 143; fn maybe_strip_file_name(mut path: PathBuf) -> PathBuf {
1207    if path.file_name().map_or(0, |name| name.len()) > MAX_FILENAME_LENGTH {
1208        let filename = path.file_name().unwrap().to_string_lossy();
1209        let hash_len = 64 / 4; let hyphen_len = 1; let allowed_suffix = MAX_FILENAME_LENGTH.saturating_sub(hash_len + hyphen_len);
1214
1215        let stripped_bytes = filename.len().saturating_sub(allowed_suffix);
1217
1218        let split_at = filename.ceil_char_boundary(stripped_bytes);
1220
1221        let mut hasher = StableHasher::new();
1222        filename[..split_at].hash(&mut hasher);
1223        let hash = hasher.finish::<Hash64>();
1224
1225        path.set_file_name(format!("{:x}-{}", hash, &filename[split_at..]));
1226    }
1227    path
1228}
1229impl OutputFilenames {
1230    pub fn new(
1231        out_directory: PathBuf,
1232        out_crate_name: String,
1233        out_filestem: String,
1234        single_output_file: Option<OutFileName>,
1235        temps_directory: Option<PathBuf>,
1236        extra: String,
1237        outputs: OutputTypes,
1238    ) -> Self {
1239        OutputFilenames {
1240            out_directory,
1241            single_output_file,
1242            temps_directory,
1243            outputs,
1244            crate_stem: format!("{out_crate_name}{extra}"),
1245            filestem: format!("{out_filestem}{extra}"),
1246        }
1247    }
1248
1249    pub fn path(&self, flavor: OutputType) -> OutFileName {
1250        self.outputs
1251            .get(&flavor)
1252            .and_then(|p| p.to_owned())
1253            .or_else(|| self.single_output_file.clone())
1254            .unwrap_or_else(|| OutFileName::Real(self.output_path(flavor)))
1255    }
1256
1257    pub fn interface_path(&self) -> PathBuf {
1258        self.out_directory.join(format!("lib{}.rs", self.crate_stem))
1259    }
1260
1261    fn output_path(&self, flavor: OutputType) -> PathBuf {
1264        let extension = flavor.extension();
1265        match flavor {
1266            OutputType::Metadata => {
1267                self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension))
1268            }
1269            _ => self.with_directory_and_extension(&self.out_directory, extension),
1270        }
1271    }
1272
1273    pub fn temp_path_for_cgu(
1277        &self,
1278        flavor: OutputType,
1279        codegen_unit_name: &str,
1280        invocation_temp: Option<&str>,
1281    ) -> PathBuf {
1282        let extension = flavor.extension();
1283        self.temp_path_ext_for_cgu(extension, codegen_unit_name, invocation_temp)
1284    }
1285
1286    pub fn temp_path_dwo_for_cgu(
1288        &self,
1289        codegen_unit_name: &str,
1290        invocation_temp: Option<&str>,
1291    ) -> PathBuf {
1292        self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp)
1293    }
1294
1295    pub fn temp_path_ext_for_cgu(
1298        &self,
1299        ext: &str,
1300        codegen_unit_name: &str,
1301        invocation_temp: Option<&str>,
1302    ) -> PathBuf {
1303        let mut extension = codegen_unit_name.to_string();
1304
1305        if let Some(rng) = invocation_temp {
1307            extension.push('.');
1308            extension.push_str(rng);
1309        }
1310
1311        if !ext.is_empty() {
1314            extension.push('.');
1315            extension.push_str(RUST_CGU_EXT);
1316            extension.push('.');
1317            extension.push_str(ext);
1318        }
1319
1320        let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
1321        maybe_strip_file_name(self.with_directory_and_extension(temps_directory, &extension))
1322    }
1323
1324    pub fn temp_path_for_diagnostic(&self, ext: &str) -> PathBuf {
1325        let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
1326        self.with_directory_and_extension(temps_directory, &ext)
1327    }
1328
1329    pub fn with_extension(&self, extension: &str) -> PathBuf {
1330        self.with_directory_and_extension(&self.out_directory, extension)
1331    }
1332
1333    pub fn with_directory_and_extension(&self, directory: &Path, extension: &str) -> PathBuf {
1334        let mut path = directory.join(&self.filestem);
1335        path.set_extension(extension);
1336        path
1337    }
1338
1339    pub fn split_dwarf_path(
1342        &self,
1343        split_debuginfo_kind: SplitDebuginfo,
1344        split_dwarf_kind: SplitDwarfKind,
1345        cgu_name: &str,
1346        invocation_temp: Option<&str>,
1347    ) -> Option<PathBuf> {
1348        let obj_out = self.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp);
1349        let dwo_out = self.temp_path_dwo_for_cgu(cgu_name, invocation_temp);
1350        match (split_debuginfo_kind, split_dwarf_kind) {
1351            (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
1352            (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
1356                Some(obj_out)
1357            }
1358            (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
1360                Some(dwo_out)
1361            }
1362        }
1363    }
1364}
1365
1366bitflags::bitflags! {
1367    #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1369    pub struct RemapPathScopeComponents: u8 {
1370        const MACRO = 1 << 0;
1372        const DIAGNOSTICS = 1 << 1;
1374        const DEBUGINFO = 1 << 3;
1376
1377        const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits();
1380    }
1381}
1382
1383#[derive(Clone, Debug)]
1384pub struct Sysroot {
1385    pub explicit: Option<PathBuf>,
1386    pub default: PathBuf,
1387}
1388
1389impl Sysroot {
1390    pub fn new(explicit: Option<PathBuf>) -> Sysroot {
1391        Sysroot { explicit, default: filesearch::default_sysroot() }
1392    }
1393
1394    pub fn path(&self) -> &Path {
1396        self.explicit.as_deref().unwrap_or(&self.default)
1397    }
1398
1399    pub fn all_paths(&self) -> impl Iterator<Item = &Path> {
1401        self.explicit.as_deref().into_iter().chain(iter::once(&*self.default))
1402    }
1403}
1404
1405pub fn host_tuple() -> &'static str {
1406    (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
1415}
1416
1417fn file_path_mapping(
1418    remap_path_prefix: Vec<(PathBuf, PathBuf)>,
1419    unstable_opts: &UnstableOptions,
1420) -> FilePathMapping {
1421    FilePathMapping::new(
1422        remap_path_prefix.clone(),
1423        if unstable_opts.remap_path_scope.contains(RemapPathScopeComponents::DIAGNOSTICS)
1424            && !remap_path_prefix.is_empty()
1425        {
1426            FileNameDisplayPreference::Remapped
1427        } else {
1428            FileNameDisplayPreference::Local
1429        },
1430        if unstable_opts.remap_path_scope.is_all() {
1431            FileNameEmbeddablePreference::RemappedOnly
1432        } else {
1433            FileNameEmbeddablePreference::LocalAndRemapped
1434        },
1435    )
1436}
1437
1438impl Default for Options {
1439    fn default() -> Options {
1440        Options {
1441            assert_incr_state: None,
1442            crate_types: Vec::new(),
1443            optimize: OptLevel::No,
1444            debuginfo: DebugInfo::None,
1445            debuginfo_compression: DebugInfoCompression::None,
1446            lint_opts: Vec::new(),
1447            lint_cap: None,
1448            describe_lints: false,
1449            output_types: OutputTypes(BTreeMap::new()),
1450            search_paths: vec![],
1451            sysroot: Sysroot::new(None),
1452            target_triple: TargetTuple::from_tuple(host_tuple()),
1453            test: false,
1454            incremental: None,
1455            untracked_state_hash: Default::default(),
1456            unstable_opts: Default::default(),
1457            prints: Vec::new(),
1458            cg: Default::default(),
1459            error_format: ErrorOutputType::default(),
1460            diagnostic_width: None,
1461            externs: Externs(BTreeMap::new()),
1462            crate_name: None,
1463            libs: Vec::new(),
1464            unstable_features: UnstableFeatures::Disallow,
1465            debug_assertions: true,
1466            actually_rustdoc: false,
1467            resolve_doc_links: ResolveDocLinks::None,
1468            trimmed_def_paths: false,
1469            cli_forced_codegen_units: None,
1470            cli_forced_local_thinlto_off: false,
1471            remap_path_prefix: Vec::new(),
1472            real_rust_source_base_dir: None,
1473            real_rustc_dev_source_base_dir: None,
1474            edition: DEFAULT_EDITION,
1475            json_artifact_notifications: false,
1476            json_timings: false,
1477            json_unused_externs: JsonUnusedExterns::No,
1478            json_future_incompat: false,
1479            pretty: None,
1480            working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
1481            color: ColorConfig::Auto,
1482            logical_env: FxIndexMap::default(),
1483            verbose: false,
1484            target_modifiers: BTreeMap::default(),
1485        }
1486    }
1487}
1488
1489impl Options {
1490    pub fn build_dep_graph(&self) -> bool {
1492        self.incremental.is_some()
1493            || self.unstable_opts.dump_dep_graph
1494            || self.unstable_opts.query_dep_graph
1495    }
1496
1497    pub fn file_path_mapping(&self) -> FilePathMapping {
1498        file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts)
1499    }
1500
1501    pub fn will_create_output_file(&self) -> bool {
1503        !self.unstable_opts.parse_crate_root_only && self.unstable_opts.ls.is_empty() }
1506
1507    #[inline]
1508    pub fn share_generics(&self) -> bool {
1509        match self.unstable_opts.share_generics {
1510            Some(setting) => setting,
1511            None => match self.optimize {
1512                OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
1513                OptLevel::More | OptLevel::Aggressive => false,
1514            },
1515        }
1516    }
1517
1518    pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
1519        self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
1520    }
1521}
1522
1523impl UnstableOptions {
1524    pub fn dcx_flags(&self, can_emit_warnings: bool) -> DiagCtxtFlags {
1525        DiagCtxtFlags {
1526            can_emit_warnings,
1527            treat_err_as_bug: self.treat_err_as_bug,
1528            eagerly_emit_delayed_bugs: self.eagerly_emit_delayed_bugs,
1529            macro_backtrace: self.macro_backtrace,
1530            deduplicate_diagnostics: self.deduplicate_diagnostics,
1531            track_diagnostics: self.track_diagnostics,
1532        }
1533    }
1534
1535    pub fn src_hash_algorithm(&self, target: &Target) -> SourceFileHashAlgorithm {
1536        self.src_hash_algorithm.unwrap_or_else(|| {
1537            if target.is_like_msvc {
1538                SourceFileHashAlgorithm::Sha256
1539            } else {
1540                SourceFileHashAlgorithm::Md5
1541            }
1542        })
1543    }
1544
1545    pub fn checksum_hash_algorithm(&self) -> Option<SourceFileHashAlgorithm> {
1546        self.checksum_hash_algorithm
1547    }
1548}
1549
1550#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
1552pub enum EntryFnType {
1553    Main {
1554        sigpipe: u8,
1561    },
1562}
1563
1564#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
1565#[derive(HashStable_Generic)]
1566pub enum CrateType {
1567    Executable,
1568    Dylib,
1569    Rlib,
1570    Staticlib,
1571    Cdylib,
1572    ProcMacro,
1573    Sdylib,
1574}
1575
1576impl CrateType {
1577    pub fn has_metadata(self) -> bool {
1578        match self {
1579            CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
1580            CrateType::Executable
1581            | CrateType::Cdylib
1582            | CrateType::Staticlib
1583            | CrateType::Sdylib => false,
1584        }
1585    }
1586}
1587
1588#[derive(Clone, Hash, Debug, PartialEq, Eq)]
1589pub enum Passes {
1590    Some(Vec<String>),
1591    All,
1592}
1593
1594impl Passes {
1595    fn is_empty(&self) -> bool {
1596        match *self {
1597            Passes::Some(ref v) => v.is_empty(),
1598            Passes::All => false,
1599        }
1600    }
1601
1602    pub(crate) fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
1603        match *self {
1604            Passes::Some(ref mut v) => v.extend(passes),
1605            Passes::All => {}
1606        }
1607    }
1608}
1609
1610#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1611pub enum PAuthKey {
1612    A,
1613    B,
1614}
1615
1616#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1617pub struct PacRet {
1618    pub leaf: bool,
1619    pub pc: bool,
1620    pub key: PAuthKey,
1621}
1622
1623#[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
1624pub struct BranchProtection {
1625    pub bti: bool,
1626    pub pac_ret: Option<PacRet>,
1627}
1628
1629pub(crate) const fn default_lib_output() -> CrateType {
1630    CrateType::Rlib
1631}
1632
1633pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
1634    cfg::disallow_cfgs(sess, &user_cfg);
1636
1637    user_cfg.extend(cfg::default_configuration(sess));
1640    user_cfg
1641}
1642
1643pub fn build_target_config(
1644    early_dcx: &EarlyDiagCtxt,
1645    target: &TargetTuple,
1646    sysroot: &Path,
1647) -> Target {
1648    match Target::search(target, sysroot) {
1649        Ok((target, warnings)) => {
1650            for warning in warnings.warning_messages() {
1651                early_dcx.early_warn(warning)
1652            }
1653
1654            if !matches!(target.pointer_width, 16 | 32 | 64) {
1655                early_dcx.early_fatal(format!(
1656                    "target specification was invalid: unrecognized target-pointer-width {}",
1657                    target.pointer_width
1658                ))
1659            }
1660            target
1661        }
1662        Err(e) => {
1663            let mut err =
1664                early_dcx.early_struct_fatal(format!("error loading target specification: {e}"));
1665            err.help("run `rustc --print target-list` for a list of built-in targets");
1666            err.emit();
1667        }
1668    }
1669}
1670
1671#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1672pub enum OptionStability {
1673    Stable,
1674    Unstable,
1675}
1676
1677#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1678pub enum OptionKind {
1679    Opt,
1683
1684    Multi,
1688
1689    Flag,
1694
1695    FlagMulti,
1700}
1701
1702pub struct RustcOptGroup {
1703    pub name: &'static str,
1711    stability: OptionStability,
1712    kind: OptionKind,
1713
1714    short_name: &'static str,
1715    long_name: &'static str,
1716    desc: &'static str,
1717    value_hint: &'static str,
1718
1719    pub is_verbose_help_only: bool,
1722}
1723
1724impl RustcOptGroup {
1725    pub fn is_stable(&self) -> bool {
1726        self.stability == OptionStability::Stable
1727    }
1728
1729    pub fn apply(&self, options: &mut getopts::Options) {
1730        let &Self { short_name, long_name, desc, value_hint, .. } = self;
1731        match self.kind {
1732            OptionKind::Opt => options.optopt(short_name, long_name, desc, value_hint),
1733            OptionKind::Multi => options.optmulti(short_name, long_name, desc, value_hint),
1734            OptionKind::Flag => options.optflag(short_name, long_name, desc),
1735            OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
1736        };
1737    }
1738
1739    pub fn long_name(&self) -> &str {
1741        self.long_name
1742    }
1743}
1744
1745pub fn make_opt(
1746    stability: OptionStability,
1747    kind: OptionKind,
1748    short_name: &'static str,
1749    long_name: &'static str,
1750    desc: &'static str,
1751    value_hint: &'static str,
1752) -> RustcOptGroup {
1753    match kind {
1755        OptionKind::Opt | OptionKind::Multi => {}
1756        OptionKind::Flag | OptionKind::FlagMulti => assert_eq!(value_hint, ""),
1757    }
1758    RustcOptGroup {
1759        name: cmp::max_by_key(short_name, long_name, |s| s.len()),
1760        stability,
1761        kind,
1762        short_name,
1763        long_name,
1764        desc,
1765        value_hint,
1766        is_verbose_help_only: false,
1767    }
1768}
1769
1770static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
1771    format!(
1772        "Specify which edition of the compiler to use when compiling code. \
1773The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
1774    )
1775});
1776
1777static PRINT_HELP: LazyLock<String> = LazyLock::new(|| {
1778    format!(
1779        "Compiler information to print on stdout (or to a file)\n\
1780        INFO may be one of <{}>.",
1781        PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::<Vec<_>>().join("|")
1782    )
1783});
1784
1785static EMIT_HELP: LazyLock<String> = LazyLock::new(|| {
1786    let mut result =
1787        String::from("Comma separated list of types of output for the compiler to emit.\n");
1788    result.push_str("Each TYPE has the default FILE name:\n");
1789
1790    for output in OutputType::iter_all() {
1791        result.push_str(&format!("*  {} - {}\n", output.shorthand(), output.default_filename()));
1792    }
1793
1794    result
1795});
1796
1797pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1807    use OptionKind::{Flag, FlagMulti, Multi, Opt};
1808    use OptionStability::{Stable, Unstable};
1809
1810    use self::make_opt as opt;
1811
1812    let mut options = vec![
1813        opt(Stable, Flag, "h", "help", "Display this message", ""),
1814        opt(
1815            Stable,
1816            Multi,
1817            "",
1818            "cfg",
1819            "Configure the compilation environment.\n\
1820                SPEC supports the syntax `<NAME>[=\"<VALUE>\"]`.",
1821            "<SPEC>",
1822        ),
1823        opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "<SPEC>"),
1824        opt(
1825            Stable,
1826            Multi,
1827            "L",
1828            "",
1829            "Add a directory to the library search path. \
1830                The optional KIND can be one of <dependency|crate|native|framework|all> (default: all).",
1831            "[<KIND>=]<PATH>",
1832        ),
1833        opt(
1834            Stable,
1835            Multi,
1836            "l",
1837            "",
1838            "Link the generated crate(s) to the specified native\n\
1839                library NAME. The optional KIND can be one of\n\
1840                <static|framework|dylib> (default: dylib).\n\
1841                Optional comma separated MODIFIERS\n\
1842                <bundle|verbatim|whole-archive|as-needed>\n\
1843                may be specified each with a prefix of either '+' to\n\
1844                enable or '-' to disable.",
1845            "[<KIND>[:<MODIFIERS>]=]<NAME>[:<RENAME>]",
1846        ),
1847        make_crate_type_option(),
1848        opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "<NAME>"),
1849        opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST),
1850        opt(Stable, Multi, "", "emit", &EMIT_HELP, "<TYPE>[=<FILE>]"),
1851        opt(Stable, Multi, "", "print", &PRINT_HELP, "<INFO>[=<FILE>]"),
1852        opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""),
1853        opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""),
1854        opt(Stable, Opt, "o", "", "Write output to FILENAME", "<FILENAME>"),
1855        opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in DIR", "<DIR>"),
1856        opt(
1857            Stable,
1858            Opt,
1859            "",
1860            "explain",
1861            "Provide a detailed explanation of an error message",
1862            "<OPT>",
1863        ),
1864        opt(Stable, Flag, "", "test", "Build a test harness", ""),
1865        opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "<TARGET>"),
1866        opt(Stable, Multi, "A", "allow", "Set lint allowed", "<LINT>"),
1867        opt(Stable, Multi, "W", "warn", "Set lint warnings", "<LINT>"),
1868        opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "<LINT>"),
1869        opt(Stable, Multi, "D", "deny", "Set lint denied", "<LINT>"),
1870        opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "<LINT>"),
1871        opt(
1872            Stable,
1873            Multi,
1874            "",
1875            "cap-lints",
1876            "Set the most restrictive lint level. More restrictive lints are capped at this level",
1877            "<LEVEL>",
1878        ),
1879        opt(Stable, Multi, "C", "codegen", "Set a codegen option", "<OPT>[=<VALUE>]"),
1880        opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
1881        opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
1882    ];
1883
1884    let verbose_only = [
1887        opt(
1888            Stable,
1889            Multi,
1890            "",
1891            "extern",
1892            "Specify where an external rust library is located",
1893            "<NAME>[=<PATH>]",
1894        ),
1895        opt(Stable, Opt, "", "sysroot", "Override the system root", "<PATH>"),
1896        opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "<FLAG>"),
1897        opt(
1898            Stable,
1899            Opt,
1900            "",
1901            "error-format",
1902            "How errors and other messages are produced",
1903            "<human|json|short>",
1904        ),
1905        opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "<CONFIG>"),
1906        opt(
1907            Stable,
1908            Opt,
1909            "",
1910            "color",
1911            "Configure coloring of output:
1912                * auto   = colorize, if output goes to a tty (default);
1913                * always = always colorize output;
1914                * never  = never colorize output",
1915            "<auto|always|never>",
1916        ),
1917        opt(
1918            Stable,
1919            Opt,
1920            "",
1921            "diagnostic-width",
1922            "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1923            "<WIDTH>",
1924        ),
1925        opt(
1926            Stable,
1927            Multi,
1928            "",
1929            "remap-path-prefix",
1930            "Remap source names in all output (compiler messages and output files)",
1931            "<FROM>=<TO>",
1932        ),
1933        opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "<VAR>=<VALUE>"),
1934    ];
1935    options.extend(verbose_only.into_iter().map(|mut opt| {
1936        opt.is_verbose_help_only = true;
1937        opt
1938    }));
1939
1940    options
1941}
1942
1943pub fn get_cmd_lint_options(
1944    early_dcx: &EarlyDiagCtxt,
1945    matches: &getopts::Matches,
1946) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1947    let mut lint_opts_with_position = vec![];
1948    let mut describe_lints = false;
1949
1950    for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1951        for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1952            if lint_name == "help" {
1953                describe_lints = true;
1954            } else {
1955                lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1956            }
1957        }
1958    }
1959
1960    lint_opts_with_position.sort_by_key(|x| x.0);
1961    let lint_opts = lint_opts_with_position
1962        .iter()
1963        .cloned()
1964        .map(|(_, lint_name, level)| (lint_name, level))
1965        .collect();
1966
1967    let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1968        lint::Level::from_str(&cap)
1969            .unwrap_or_else(|| early_dcx.early_fatal(format!("unknown lint level: `{cap}`")))
1970    });
1971
1972    (lint_opts, describe_lints, lint_cap)
1973}
1974
1975pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> ColorConfig {
1977    match matches.opt_str("color").as_deref() {
1978        Some("auto") => ColorConfig::Auto,
1979        Some("always") => ColorConfig::Always,
1980        Some("never") => ColorConfig::Never,
1981
1982        None => ColorConfig::Auto,
1983
1984        Some(arg) => early_dcx.early_fatal(format!(
1985            "argument for `--color` must be auto, \
1986                 always or never (instead was `{arg}`)"
1987        )),
1988    }
1989}
1990
1991pub struct JsonConfig {
1993    pub json_rendered: HumanReadableErrorType,
1994    pub json_color: ColorConfig,
1995    json_artifact_notifications: bool,
1996    json_timings: bool,
1999    pub json_unused_externs: JsonUnusedExterns,
2000    json_future_incompat: bool,
2001}
2002
2003#[derive(Copy, Clone)]
2005pub enum JsonUnusedExterns {
2006    No,
2008    Silent,
2010    Loud,
2012}
2013
2014impl JsonUnusedExterns {
2015    pub fn is_enabled(&self) -> bool {
2016        match self {
2017            JsonUnusedExterns::No => false,
2018            JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
2019        }
2020    }
2021
2022    pub fn is_loud(&self) -> bool {
2023        match self {
2024            JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
2025            JsonUnusedExterns::Loud => true,
2026        }
2027    }
2028}
2029
2030pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
2035    let mut json_rendered = HumanReadableErrorType::Default;
2036    let mut json_color = ColorConfig::Never;
2037    let mut json_artifact_notifications = false;
2038    let mut json_unused_externs = JsonUnusedExterns::No;
2039    let mut json_future_incompat = false;
2040    let mut json_timings = false;
2041    for option in matches.opt_strs("json") {
2042        if matches.opt_str("color").is_some() {
2046            early_dcx.early_fatal("cannot specify the `--color` option with `--json`");
2047        }
2048
2049        for sub_option in option.split(',') {
2050            match sub_option {
2051                "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
2052                "diagnostic-unicode" => {
2053                    json_rendered = HumanReadableErrorType::Unicode;
2054                }
2055                "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
2056                "artifacts" => json_artifact_notifications = true,
2057                "timings" => json_timings = true,
2058                "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
2059                "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
2060                "future-incompat" => json_future_incompat = true,
2061                s => early_dcx.early_fatal(format!("unknown `--json` option `{s}`")),
2062            }
2063        }
2064    }
2065
2066    JsonConfig {
2067        json_rendered,
2068        json_color,
2069        json_artifact_notifications,
2070        json_timings,
2071        json_unused_externs,
2072        json_future_incompat,
2073    }
2074}
2075
2076pub fn parse_error_format(
2078    early_dcx: &mut EarlyDiagCtxt,
2079    matches: &getopts::Matches,
2080    color_config: ColorConfig,
2081    json_color: ColorConfig,
2082    json_rendered: HumanReadableErrorType,
2083) -> ErrorOutputType {
2084    let error_format = if matches.opts_present(&["error-format".to_owned()]) {
2089        match matches.opt_str("error-format").as_deref() {
2090            None | Some("human") => ErrorOutputType::HumanReadable { color_config, .. },
2091            Some("human-annotate-rs") => ErrorOutputType::HumanReadable {
2092                kind: HumanReadableErrorType::AnnotateSnippet,
2093                color_config,
2094            },
2095            Some("json") => {
2096                ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
2097            }
2098            Some("pretty-json") => {
2099                ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
2100            }
2101            Some("short") => {
2102                ErrorOutputType::HumanReadable { kind: HumanReadableErrorType::Short, color_config }
2103            }
2104            Some("human-unicode") => ErrorOutputType::HumanReadable {
2105                kind: HumanReadableErrorType::Unicode,
2106                color_config,
2107            },
2108            Some(arg) => {
2109                early_dcx.set_error_format(ErrorOutputType::HumanReadable { color_config, .. });
2110                early_dcx.early_fatal(format!(
2111                    "argument for `--error-format` must be `human`, `human-annotate-rs`, \
2112                    `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)"
2113                ))
2114            }
2115        }
2116    } else {
2117        ErrorOutputType::HumanReadable { color_config, .. }
2118    };
2119
2120    match error_format {
2121        ErrorOutputType::Json { .. } => {}
2122
2123        _ if !matches.opt_strs("json").is_empty() => {
2127            early_dcx.early_fatal("using `--json` requires also using `--error-format=json`");
2128        }
2129
2130        _ => {}
2131    }
2132
2133    error_format
2134}
2135
2136pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Edition {
2137    let edition = match matches.opt_str("edition") {
2138        Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
2139            early_dcx.early_fatal(format!(
2140                "argument for `--edition` must be one of: \
2141                     {EDITION_NAME_LIST}. (instead was `{arg}`)"
2142            ))
2143        }),
2144        None => DEFAULT_EDITION,
2145    };
2146
2147    if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
2148        let is_nightly = nightly_options::match_is_nightly_build(matches);
2149        let msg = if !is_nightly {
2150            format!(
2151                "the crate requires edition {edition}, but the latest edition supported by this Rust version is {LATEST_STABLE_EDITION}"
2152            )
2153        } else {
2154            format!("edition {edition} is unstable and only available with -Z unstable-options")
2155        };
2156        early_dcx.early_fatal(msg)
2157    }
2158
2159    edition
2160}
2161
2162fn check_error_format_stability(
2163    early_dcx: &EarlyDiagCtxt,
2164    unstable_opts: &UnstableOptions,
2165    format: ErrorOutputType,
2166) {
2167    if unstable_opts.unstable_options {
2168        return;
2169    }
2170    let format = match format {
2171        ErrorOutputType::Json { pretty: true, .. } => "pretty-json",
2172        ErrorOutputType::HumanReadable { kind, .. } => match kind {
2173            HumanReadableErrorType::AnnotateSnippet => "human-annotate-rs",
2174            HumanReadableErrorType::Unicode => "human-unicode",
2175            _ => return,
2176        },
2177        _ => return,
2178    };
2179    early_dcx.early_fatal(format!("`--error-format={format}` is unstable"))
2180}
2181
2182fn parse_output_types(
2183    early_dcx: &EarlyDiagCtxt,
2184    unstable_opts: &UnstableOptions,
2185    matches: &getopts::Matches,
2186) -> OutputTypes {
2187    let mut output_types = BTreeMap::new();
2188    if !unstable_opts.parse_crate_root_only {
2189        for list in matches.opt_strs("emit") {
2190            for output_type in list.split(',') {
2191                let (shorthand, path) = split_out_file_name(output_type);
2192                let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
2193                    early_dcx.early_fatal(format!(
2194                        "unknown emission type: `{shorthand}` - expected one of: {display}",
2195                        display = OutputType::shorthands_display(),
2196                    ))
2197                });
2198                if output_type == OutputType::ThinLinkBitcode && !unstable_opts.unstable_options {
2199                    early_dcx.early_fatal(format!(
2200                        "{} requested but -Zunstable-options not specified",
2201                        OutputType::ThinLinkBitcode.shorthand()
2202                    ));
2203                }
2204                output_types.insert(output_type, path);
2205            }
2206        }
2207    };
2208    if output_types.is_empty() {
2209        output_types.insert(OutputType::Exe, None);
2210    }
2211    OutputTypes(output_types)
2212}
2213
2214fn split_out_file_name(arg: &str) -> (&str, Option<OutFileName>) {
2215    match arg.split_once('=') {
2216        None => (arg, None),
2217        Some((kind, "-")) => (kind, Some(OutFileName::Stdout)),
2218        Some((kind, path)) => (kind, Some(OutFileName::Real(PathBuf::from(path)))),
2219    }
2220}
2221
2222fn should_override_cgus_and_disable_thinlto(
2223    early_dcx: &EarlyDiagCtxt,
2224    output_types: &OutputTypes,
2225    matches: &getopts::Matches,
2226    mut codegen_units: Option<usize>,
2227) -> (bool, Option<usize>) {
2228    let mut disable_local_thinlto = false;
2229    let incompatible: Vec<_> = output_types
2232        .0
2233        .iter()
2234        .map(|ot_path| ot_path.0)
2235        .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2236        .map(|ot| ot.shorthand())
2237        .collect();
2238    if !incompatible.is_empty() {
2239        match codegen_units {
2240            Some(n) if n > 1 => {
2241                if matches.opt_present("o") {
2242                    for ot in &incompatible {
2243                        early_dcx.early_warn(format!(
2244                            "`--emit={ot}` with `-o` incompatible with \
2245                                 `-C codegen-units=N` for N > 1",
2246                        ));
2247                    }
2248                    early_dcx.early_warn("resetting to default -C codegen-units=1");
2249                    codegen_units = Some(1);
2250                    disable_local_thinlto = true;
2251                }
2252            }
2253            _ => {
2254                codegen_units = Some(1);
2255                disable_local_thinlto = true;
2256            }
2257        }
2258    }
2259
2260    if codegen_units == Some(0) {
2261        early_dcx.early_fatal("value for codegen units must be a positive non-zero integer");
2262    }
2263
2264    (disable_local_thinlto, codegen_units)
2265}
2266
2267fn collect_print_requests(
2268    early_dcx: &EarlyDiagCtxt,
2269    cg: &mut CodegenOptions,
2270    unstable_opts: &UnstableOptions,
2271    matches: &getopts::Matches,
2272) -> Vec<PrintRequest> {
2273    let mut prints = Vec::<PrintRequest>::new();
2274    if cg.target_cpu.as_deref() == Some("help") {
2275        prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout });
2276        cg.target_cpu = None;
2277    };
2278    if cg.target_feature == "help" {
2279        prints.push(PrintRequest { kind: PrintKind::TargetFeatures, out: OutFileName::Stdout });
2280        cg.target_feature = String::new();
2281    }
2282
2283    let mut printed_paths = FxHashSet::default();
2288
2289    prints.extend(matches.opt_strs("print").into_iter().map(|req| {
2290        let (req, out) = split_out_file_name(&req);
2291
2292        let kind = if let Some((print_name, print_kind)) =
2293            PRINT_KINDS.iter().find(|&&(name, _)| name == req)
2294        {
2295            check_print_request_stability(early_dcx, unstable_opts, (print_name, *print_kind));
2296            *print_kind
2297        } else {
2298            let is_nightly = nightly_options::match_is_nightly_build(matches);
2299            emit_unknown_print_request_help(early_dcx, req, is_nightly)
2300        };
2301
2302        let out = out.unwrap_or(OutFileName::Stdout);
2303        if let OutFileName::Real(path) = &out {
2304            if !printed_paths.insert(path.clone()) {
2305                early_dcx.early_fatal(format!(
2306                    "cannot print multiple outputs to the same path: {}",
2307                    path.display(),
2308                ));
2309            }
2310        }
2311
2312        PrintRequest { kind, out }
2313    }));
2314
2315    prints
2316}
2317
2318fn check_print_request_stability(
2319    early_dcx: &EarlyDiagCtxt,
2320    unstable_opts: &UnstableOptions,
2321    (print_name, print_kind): (&str, PrintKind),
2322) {
2323    if !is_print_request_stable(print_kind) && !unstable_opts.unstable_options {
2324        early_dcx.early_fatal(format!(
2325            "the `-Z unstable-options` flag must also be passed to enable the `{print_name}` \
2326                print option"
2327        ));
2328    }
2329}
2330
2331fn is_print_request_stable(print_kind: PrintKind) -> bool {
2332    match print_kind {
2333        PrintKind::AllTargetSpecsJson
2334        | PrintKind::CheckCfg
2335        | PrintKind::CrateRootLintLevels
2336        | PrintKind::SupportedCrateTypes
2337        | PrintKind::TargetSpecJson
2338        | PrintKind::TargetSpecJsonSchema => false,
2339        _ => true,
2340    }
2341}
2342
2343fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str, is_nightly: bool) -> ! {
2344    let prints = PRINT_KINDS
2345        .iter()
2346        .filter_map(|(name, kind)| {
2347            if !is_nightly && !is_print_request_stable(*kind) {
2349                None
2350            } else {
2351                Some(format!("`{name}`"))
2352            }
2353        })
2354        .collect::<Vec<_>>();
2355    let prints = prints.join(", ");
2356
2357    let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`"));
2358    #[allow(rustc::diagnostic_outside_of_impl)]
2359    diag.help(format!("valid print requests are: {prints}"));
2360
2361    if req == "lints" {
2362        diag.help(format!("use `-Whelp` to print a list of lints"));
2363    }
2364
2365    diag.help(format!("for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information"));
2366    diag.emit()
2367}
2368
2369pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTuple {
2370    match matches.opt_str("target") {
2371        Some(target) if target.ends_with(".json") => {
2372            let path = Path::new(&target);
2373            TargetTuple::from_path(path).unwrap_or_else(|_| {
2374                early_dcx.early_fatal(format!("target file {path:?} does not exist"))
2375            })
2376        }
2377        Some(target) => TargetTuple::TargetTuple(target),
2378        _ => TargetTuple::from_tuple(host_tuple()),
2379    }
2380}
2381
2382fn parse_opt_level(
2383    early_dcx: &EarlyDiagCtxt,
2384    matches: &getopts::Matches,
2385    cg: &CodegenOptions,
2386) -> OptLevel {
2387    let max_o = matches.opt_positions("O").into_iter().max();
2394    let max_c = matches
2395        .opt_strs_pos("C")
2396        .into_iter()
2397        .flat_map(|(i, s)| {
2398            if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
2400        })
2401        .max();
2402    if max_o > max_c {
2403        OptLevel::Aggressive
2404    } else {
2405        match cg.opt_level.as_ref() {
2406            "0" => OptLevel::No,
2407            "1" => OptLevel::Less,
2408            "2" => OptLevel::More,
2409            "3" => OptLevel::Aggressive,
2410            "s" => OptLevel::Size,
2411            "z" => OptLevel::SizeMin,
2412            arg => {
2413                early_dcx.early_fatal(format!(
2414                    "optimization level needs to be \
2415                            between 0-3, s or z (instead was `{arg}`)"
2416                ));
2417            }
2418        }
2419    }
2420}
2421
2422fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInfo {
2423    let max_g = matches.opt_positions("g").into_iter().max();
2424    let max_c = matches
2425        .opt_strs_pos("C")
2426        .into_iter()
2427        .flat_map(|(i, s)| {
2428            if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
2430        })
2431        .max();
2432    if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
2433}
2434
2435fn parse_assert_incr_state(
2436    early_dcx: &EarlyDiagCtxt,
2437    opt_assertion: &Option<String>,
2438) -> Option<IncrementalStateAssertion> {
2439    match opt_assertion {
2440        Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
2441        Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
2442        Some(s) => {
2443            early_dcx.early_fatal(format!("unexpected incremental state assertion value: {s}"))
2444        }
2445        None => None,
2446    }
2447}
2448
2449pub fn parse_externs(
2450    early_dcx: &EarlyDiagCtxt,
2451    matches: &getopts::Matches,
2452    unstable_opts: &UnstableOptions,
2453) -> Externs {
2454    let is_unstable_enabled = unstable_opts.unstable_options;
2455    let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2456    for arg in matches.opt_strs("extern") {
2457        let ExternOpt { crate_name: name, path, options } =
2458            split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit());
2459
2460        let entry = externs.entry(name.to_owned());
2461
2462        use std::collections::btree_map::Entry;
2463
2464        let entry = if let Some(path) = path {
2465            let path = CanonicalizedPath::new(path);
2467            match entry {
2468                Entry::Vacant(vacant) => {
2469                    let files = BTreeSet::from_iter(iter::once(path));
2470                    vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2471                }
2472                Entry::Occupied(occupied) => {
2473                    let ext_ent = occupied.into_mut();
2474                    match ext_ent {
2475                        ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2476                            files.insert(path);
2477                        }
2478                        ExternEntry {
2479                            location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2480                            ..
2481                        } => {
2482                            let files = BTreeSet::from_iter(iter::once(path));
2484                            *location = ExternLocation::ExactPaths(files);
2485                        }
2486                    }
2487                    ext_ent
2488                }
2489            }
2490        } else {
2491            match entry {
2493                Entry::Vacant(vacant) => {
2494                    vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2495                }
2496                Entry::Occupied(occupied) => {
2497                    occupied.into_mut()
2499                }
2500            }
2501        };
2502
2503        let mut is_private_dep = false;
2504        let mut add_prelude = true;
2505        let mut nounused_dep = false;
2506        let mut force = false;
2507        if let Some(opts) = options {
2508            if !is_unstable_enabled {
2509                early_dcx.early_fatal(
2510                    "the `-Z unstable-options` flag must also be passed to \
2511                     enable `--extern` options",
2512                );
2513            }
2514            for opt in opts.split(',') {
2515                match opt {
2516                    "priv" => is_private_dep = true,
2517                    "noprelude" => {
2518                        if let ExternLocation::ExactPaths(_) = &entry.location {
2519                            add_prelude = false;
2520                        } else {
2521                            early_dcx.early_fatal(
2522                                "the `noprelude` --extern option requires a file path",
2523                            );
2524                        }
2525                    }
2526                    "nounused" => nounused_dep = true,
2527                    "force" => force = true,
2528                    _ => early_dcx.early_fatal(format!("unknown --extern option `{opt}`")),
2529                }
2530            }
2531        }
2532
2533        entry.is_private_dep |= is_private_dep;
2536        entry.nounused_dep |= nounused_dep;
2538        entry.force |= force;
2540        entry.add_prelude |= add_prelude;
2542    }
2543    Externs(externs)
2544}
2545
2546fn parse_remap_path_prefix(
2547    early_dcx: &EarlyDiagCtxt,
2548    matches: &getopts::Matches,
2549    unstable_opts: &UnstableOptions,
2550) -> Vec<(PathBuf, PathBuf)> {
2551    let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2552        .opt_strs("remap-path-prefix")
2553        .into_iter()
2554        .map(|remap| match remap.rsplit_once('=') {
2555            None => {
2556                early_dcx.early_fatal("--remap-path-prefix must contain '=' between FROM and TO")
2557            }
2558            Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2559        })
2560        .collect();
2561    match &unstable_opts.remap_cwd_prefix {
2562        Some(to) => match std::env::current_dir() {
2563            Ok(cwd) => mapping.push((cwd, to.clone())),
2564            Err(_) => (),
2565        },
2566        None => (),
2567    };
2568    mapping
2569}
2570
2571fn parse_logical_env(
2572    early_dcx: &EarlyDiagCtxt,
2573    matches: &getopts::Matches,
2574) -> FxIndexMap<String, String> {
2575    let mut vars = FxIndexMap::default();
2576
2577    for arg in matches.opt_strs("env-set") {
2578        if let Some((name, val)) = arg.split_once('=') {
2579            vars.insert(name.to_string(), val.to_string());
2580        } else {
2581            early_dcx.early_fatal(format!("`--env-set`: specify value for variable `{arg}`"));
2582        }
2583    }
2584
2585    vars
2586}
2587
2588#[allow(rustc::bad_opt_access)]
2590pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches) -> Options {
2591    let color = parse_color(early_dcx, matches);
2592
2593    let edition = parse_crate_edition(early_dcx, matches);
2594
2595    let JsonConfig {
2596        json_rendered,
2597        json_color,
2598        json_artifact_notifications,
2599        json_timings,
2600        json_unused_externs,
2601        json_future_incompat,
2602    } = parse_json(early_dcx, matches);
2603
2604    let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
2605
2606    early_dcx.set_error_format(error_format);
2607
2608    let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2609        early_dcx.early_fatal("`--diagnostic-width` must be an positive integer");
2610    });
2611
2612    let unparsed_crate_types = matches.opt_strs("crate-type");
2613    let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2614        .unwrap_or_else(|e| early_dcx.early_fatal(e));
2615
2616    let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
2617
2618    let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
2619    let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
2620
2621    if !unstable_opts.unstable_options && json_timings {
2622        early_dcx.early_fatal("--json=timings is unstable and requires using `-Zunstable-options`");
2623    }
2624
2625    check_error_format_stability(early_dcx, &unstable_opts, error_format);
2626
2627    let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
2628
2629    let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
2630    let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2631        early_dcx,
2632        &output_types,
2633        matches,
2634        cg.codegen_units,
2635    );
2636
2637    if unstable_opts.threads == 0 {
2638        early_dcx.early_fatal("value for threads must be a positive non-zero integer");
2639    }
2640
2641    if unstable_opts.threads == parse::MAX_THREADS_CAP {
2642        early_dcx.early_warn(format!("number of threads was capped at {}", parse::MAX_THREADS_CAP));
2643    }
2644
2645    let incremental = cg.incremental.as_ref().map(PathBuf::from);
2646
2647    let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state);
2648
2649    if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2650        early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive");
2651    }
2652
2653    if unstable_opts.profile_sample_use.is_some()
2654        && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2655    {
2656        early_dcx.early_fatal(
2657            "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2658        );
2659    }
2660
2661    match cg.symbol_mangling_version {
2664        None | Some(SymbolManglingVersion::V0) => {}
2666
2667        Some(SymbolManglingVersion::Legacy) => {
2669            if !unstable_opts.unstable_options {
2670                early_dcx.early_fatal(
2671                    "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2672                );
2673            }
2674        }
2675        Some(SymbolManglingVersion::Hashed) => {
2676            if !unstable_opts.unstable_options {
2677                early_dcx.early_fatal(
2678                    "`-C symbol-mangling-version=hashed` requires `-Z unstable-options`",
2679                );
2680            }
2681        }
2682    }
2683
2684    if cg.instrument_coverage != InstrumentCoverage::No {
2685        if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2686            early_dcx.early_fatal(
2687                "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2688                or `-C profile-generate`",
2689            );
2690        }
2691
2692        match cg.symbol_mangling_version {
2697            None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2698            Some(SymbolManglingVersion::Legacy) => {
2699                early_dcx.early_warn(
2700                    "-C instrument-coverage requires symbol mangling version `v0`, \
2701                    but `-C symbol-mangling-version=legacy` was specified",
2702                );
2703            }
2704            Some(SymbolManglingVersion::V0) => {}
2705            Some(SymbolManglingVersion::Hashed) => {
2706                early_dcx.early_warn(
2707                    "-C instrument-coverage requires symbol mangling version `v0`, \
2708                    but `-C symbol-mangling-version=hashed` was specified",
2709                );
2710            }
2711        }
2712    }
2713
2714    if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2715        unstable_opts.graphviz_font = graphviz_font;
2718    }
2719
2720    if !cg.embed_bitcode {
2721        match cg.lto {
2722            LtoCli::No | LtoCli::Unspecified => {}
2723            LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
2724                early_dcx.early_fatal("options `-C embed-bitcode=no` and `-C lto` are incompatible")
2725            }
2726        }
2727    }
2728
2729    let unstable_options_enabled = nightly_options::is_unstable_enabled(matches);
2730    if !unstable_options_enabled && cg.force_frame_pointers == FramePointer::NonLeaf {
2731        early_dcx.early_fatal(
2732            "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
2733                and a nightly compiler",
2734        )
2735    }
2736
2737    if !nightly_options::is_unstable_enabled(matches)
2738        && unstable_opts.offload.contains(&Offload::Enable)
2739    {
2740        early_dcx.early_fatal(
2741            "`-Zoffload=Enable` also requires `-Zunstable-options` \
2742                and a nightly compiler",
2743        )
2744    }
2745
2746    let target_triple = parse_target_triple(early_dcx, matches);
2747
2748    if !unstable_options_enabled {
2751        if let Err(error) = cg.link_self_contained.check_unstable_variants(&target_triple) {
2752            early_dcx.early_fatal(error);
2753        }
2754
2755        if let Some(flavor) = cg.linker_flavor {
2756            if flavor.is_unstable() {
2757                early_dcx.early_fatal(format!(
2758                    "the linker flavor `{}` is unstable, the `-Z unstable-options` \
2759                        flag must also be passed to use the unstable values",
2760                    flavor.desc()
2761                ));
2762            }
2763        }
2764    }
2765
2766    if let Some(erroneous_components) = cg.link_self_contained.check_consistency() {
2769        let names: String = erroneous_components
2770            .into_iter()
2771            .map(|c| c.as_str().unwrap())
2772            .intersperse(", ")
2773            .collect();
2774        early_dcx.early_fatal(format!(
2775            "some `-C link-self-contained` components were both enabled and disabled: {names}"
2776        ));
2777    }
2778
2779    let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches);
2780
2781    if unstable_opts.retpoline_external_thunk {
2783        unstable_opts.retpoline = true;
2784        target_modifiers.insert(
2785            OptionsTargetModifiers::UnstableOptions(UnstableOptionsTargetModifiers::retpoline),
2786            "true".to_string(),
2787        );
2788    }
2789
2790    let cg = cg;
2791
2792    let opt_level = parse_opt_level(early_dcx, matches, &cg);
2793    let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2797    let debuginfo = select_debuginfo(matches, &cg);
2798    let debuginfo_compression = unstable_opts.debuginfo_compression;
2799
2800    if !unstable_options_enabled {
2801        if let Err(error) = cg.linker_features.check_unstable_variants(&target_triple) {
2802            early_dcx.early_fatal(error);
2803        }
2804    }
2805
2806    let crate_name = matches.opt_str("crate-name");
2807    let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
2808    let libs = parse_native_libs(early_dcx, &unstable_opts, unstable_features, matches);
2810
2811    let test = matches.opt_present("test");
2812
2813    if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2814        early_dcx.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
2815    }
2816
2817    if cg.remark.is_empty() && unstable_opts.remark_dir.is_some() {
2818        early_dcx
2819            .early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all");
2820    }
2821
2822    let externs = parse_externs(early_dcx, matches, &unstable_opts);
2823
2824    let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts);
2825
2826    let pretty = parse_pretty(early_dcx, &unstable_opts);
2827
2828    if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
2830        early_dcx.early_fatal("can't dump dependency graph without `-Z query-dep-graph`");
2831    }
2832
2833    let logical_env = parse_logical_env(early_dcx, matches);
2834
2835    let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from));
2836
2837    let real_source_base_dir = |suffix: &str, confirm: &str| {
2838        let mut candidate = sysroot.path().join(suffix);
2839        if let Ok(metadata) = candidate.symlink_metadata() {
2840            if metadata.file_type().is_symlink() {
2844                if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2845                    candidate = symlink_dest;
2846                }
2847            }
2848        }
2849
2850        candidate.join(confirm).is_file().then_some(candidate)
2852    };
2853
2854    let real_rust_source_base_dir =
2855        real_source_base_dir("lib/rustlib/src/rust", "library/std/src/lib.rs");
2857
2858    let real_rustc_dev_source_base_dir =
2859        real_source_base_dir("lib/rustlib/rustc-src/rust", "compiler/rustc/src/main.rs");
2861
2862    let search_paths: Vec<SearchPath> = {
2867        let mut seen_search_paths = FxHashSet::default();
2868        let search_path_matches: Vec<String> = matches.opt_strs("L");
2869        search_path_matches
2870            .iter()
2871            .filter(|p| seen_search_paths.insert(*p))
2872            .map(|path| {
2873                SearchPath::from_cli_opt(
2874                    sysroot.path(),
2875                    &target_triple,
2876                    early_dcx,
2877                    &path,
2878                    unstable_opts.unstable_options,
2879                )
2880            })
2881            .collect()
2882    };
2883
2884    let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2885        early_dcx.early_fatal(format!("Current directory is invalid: {e}"));
2886    });
2887
2888    let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts);
2889    let working_dir = file_mapping.to_real_filename(&working_dir);
2890
2891    let verbose = matches.opt_present("verbose") || unstable_opts.verbose_internals;
2892
2893    Options {
2894        assert_incr_state,
2895        crate_types,
2896        optimize: opt_level,
2897        debuginfo,
2898        debuginfo_compression,
2899        lint_opts,
2900        lint_cap,
2901        describe_lints,
2902        output_types,
2903        search_paths,
2904        sysroot,
2905        target_triple,
2906        test,
2907        incremental,
2908        untracked_state_hash: Default::default(),
2909        unstable_opts,
2910        prints,
2911        cg,
2912        error_format,
2913        diagnostic_width,
2914        externs,
2915        unstable_features,
2916        crate_name,
2917        libs,
2918        debug_assertions,
2919        actually_rustdoc: false,
2920        resolve_doc_links: ResolveDocLinks::ExportedMetadata,
2921        trimmed_def_paths: false,
2922        cli_forced_codegen_units: codegen_units,
2923        cli_forced_local_thinlto_off: disable_local_thinlto,
2924        remap_path_prefix,
2925        real_rust_source_base_dir,
2926        real_rustc_dev_source_base_dir,
2927        edition,
2928        json_artifact_notifications,
2929        json_timings,
2930        json_unused_externs,
2931        json_future_incompat,
2932        pretty,
2933        working_dir,
2934        color,
2935        logical_env,
2936        verbose,
2937        target_modifiers,
2938    }
2939}
2940
2941fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> Option<PpMode> {
2942    use PpMode::*;
2943
2944    let first = match unstable_opts.unpretty.as_deref()? {
2945        "normal" => Source(PpSourceMode::Normal),
2946        "identified" => Source(PpSourceMode::Identified),
2947        "expanded" => Source(PpSourceMode::Expanded),
2948        "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2949        "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2950        "ast-tree" => AstTree,
2951        "ast-tree,expanded" => AstTreeExpanded,
2952        "hir" => Hir(PpHirMode::Normal),
2953        "hir,identified" => Hir(PpHirMode::Identified),
2954        "hir,typed" => Hir(PpHirMode::Typed),
2955        "hir-tree" => HirTree,
2956        "thir-tree" => ThirTree,
2957        "thir-flat" => ThirFlat,
2958        "mir" => Mir,
2959        "stable-mir" => StableMir,
2960        "mir-cfg" => MirCFG,
2961        name => early_dcx.early_fatal(format!(
2962            "argument to `unpretty` must be one of `normal`, `identified`, \
2963                            `expanded`, `expanded,identified`, `expanded,hygiene`, \
2964                            `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2965                            `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir`, `stable-mir`, or \
2966                            `mir-cfg`; got {name}"
2967        )),
2968    };
2969    debug!("got unpretty option: {first:?}");
2970    Some(first)
2971}
2972
2973pub fn make_crate_type_option() -> RustcOptGroup {
2974    make_opt(
2975        OptionStability::Stable,
2976        OptionKind::Multi,
2977        "",
2978        "crate-type",
2979        "Comma separated list of types of crates
2980                                for the compiler to emit",
2981        "<bin|lib|rlib|dylib|cdylib|staticlib|proc-macro>",
2982    )
2983}
2984
2985pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2986    let mut crate_types: Vec<CrateType> = Vec::new();
2987    for unparsed_crate_type in &list_list {
2988        for part in unparsed_crate_type.split(',') {
2989            let new_part = match part {
2990                "lib" => default_lib_output(),
2991                "rlib" => CrateType::Rlib,
2992                "staticlib" => CrateType::Staticlib,
2993                "dylib" => CrateType::Dylib,
2994                "cdylib" => CrateType::Cdylib,
2995                "bin" => CrateType::Executable,
2996                "proc-macro" => CrateType::ProcMacro,
2997                "sdylib" => CrateType::Sdylib,
2998                _ => {
2999                    return Err(format!(
3000                        "unknown crate type: `{part}`, expected one of: \
3001                        `lib`, `rlib`, `staticlib`, `dylib`, `cdylib`, `bin`, `proc-macro`",
3002                    ));
3003                }
3004            };
3005            if !crate_types.contains(&new_part) {
3006                crate_types.push(new_part)
3007            }
3008        }
3009    }
3010
3011    Ok(crate_types)
3012}
3013
3014pub mod nightly_options {
3015    use rustc_feature::UnstableFeatures;
3016
3017    use super::{OptionStability, RustcOptGroup};
3018    use crate::EarlyDiagCtxt;
3019
3020    pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
3021        match_is_nightly_build(matches)
3022            && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
3023    }
3024
3025    pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
3026        is_nightly_build(matches.opt_str("crate-name").as_deref())
3027    }
3028
3029    fn is_nightly_build(krate: Option<&str>) -> bool {
3030        UnstableFeatures::from_environment(krate).is_nightly_build()
3031    }
3032
3033    pub fn check_nightly_options(
3034        early_dcx: &EarlyDiagCtxt,
3035        matches: &getopts::Matches,
3036        flags: &[RustcOptGroup],
3037    ) {
3038        let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
3039        let really_allows_unstable_options = match_is_nightly_build(matches);
3040        let mut nightly_options_on_stable = 0;
3041
3042        for opt in flags.iter() {
3043            if opt.stability == OptionStability::Stable {
3044                continue;
3045            }
3046            if !matches.opt_present(opt.name) {
3047                continue;
3048            }
3049            if opt.name != "Z" && !has_z_unstable_option {
3050                early_dcx.early_fatal(format!(
3051                    "the `-Z unstable-options` flag must also be passed to enable \
3052                         the flag `{}`",
3053                    opt.name
3054                ));
3055            }
3056            if really_allows_unstable_options {
3057                continue;
3058            }
3059            match opt.stability {
3060                OptionStability::Unstable => {
3061                    nightly_options_on_stable += 1;
3062                    let msg = format!(
3063                        "the option `{}` is only accepted on the nightly compiler",
3064                        opt.name
3065                    );
3066                    let _ = early_dcx.early_err(msg);
3068                }
3069                OptionStability::Stable => {}
3070            }
3071        }
3072        if nightly_options_on_stable > 0 {
3073            early_dcx
3074                .early_help("consider switching to a nightly toolchain: `rustup default nightly`");
3075            early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
3076            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>");
3077            early_dcx.early_fatal(format!(
3078                "{} nightly option{} were parsed",
3079                nightly_options_on_stable,
3080                if nightly_options_on_stable > 1 { "s" } else { "" }
3081            ));
3082        }
3083    }
3084}
3085
3086impl fmt::Display for CrateType {
3087    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3088        match *self {
3089            CrateType::Executable => "bin".fmt(f),
3090            CrateType::Dylib => "dylib".fmt(f),
3091            CrateType::Rlib => "rlib".fmt(f),
3092            CrateType::Staticlib => "staticlib".fmt(f),
3093            CrateType::Cdylib => "cdylib".fmt(f),
3094            CrateType::ProcMacro => "proc-macro".fmt(f),
3095            CrateType::Sdylib => "sdylib".fmt(f),
3096        }
3097    }
3098}
3099
3100impl IntoDiagArg for CrateType {
3101    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
3102        self.to_string().into_diag_arg(&mut None)
3103    }
3104}
3105
3106#[derive(Copy, Clone, PartialEq, Debug)]
3107pub enum PpSourceMode {
3108    Normal,
3110    Expanded,
3112    Identified,
3114    ExpandedIdentified,
3116    ExpandedHygiene,
3118}
3119
3120#[derive(Copy, Clone, PartialEq, Debug)]
3121pub enum PpHirMode {
3122    Normal,
3124    Identified,
3126    Typed,
3128}
3129
3130#[derive(Copy, Clone, PartialEq, Debug)]
3131pub enum PpMode {
3133    Source(PpSourceMode),
3136    AstTree,
3138    AstTreeExpanded,
3140    Hir(PpHirMode),
3142    HirTree,
3144    ThirTree,
3146    ThirFlat,
3148    Mir,
3150    MirCFG,
3152    StableMir,
3154}
3155
3156impl PpMode {
3157    pub fn needs_ast_map(&self) -> bool {
3158        use PpMode::*;
3159        use PpSourceMode::*;
3160        match *self {
3161            Source(Normal | Identified) | AstTree => false,
3162
3163            Source(Expanded | ExpandedIdentified | ExpandedHygiene)
3164            | AstTreeExpanded
3165            | Hir(_)
3166            | HirTree
3167            | ThirTree
3168            | ThirFlat
3169            | Mir
3170            | MirCFG
3171            | StableMir => true,
3172        }
3173    }
3174
3175    pub fn needs_analysis(&self) -> bool {
3176        use PpMode::*;
3177        matches!(*self, Hir(PpHirMode::Typed) | Mir | StableMir | MirCFG | ThirTree | ThirFlat)
3178    }
3179}
3180
3181#[derive(Clone, Hash, PartialEq, Eq, Debug)]
3182pub enum WasiExecModel {
3183    Command,
3184    Reactor,
3185}
3186
3187pub(crate) mod dep_tracking {
3206    use std::collections::BTreeMap;
3207    use std::hash::Hash;
3208    use std::num::NonZero;
3209    use std::path::PathBuf;
3210
3211    use rustc_abi::Align;
3212    use rustc_data_structures::fx::FxIndexMap;
3213    use rustc_data_structures::stable_hasher::StableHasher;
3214    use rustc_errors::LanguageIdentifier;
3215    use rustc_feature::UnstableFeatures;
3216    use rustc_hashes::Hash64;
3217    use rustc_span::RealFileName;
3218    use rustc_span::edition::Edition;
3219    use rustc_target::spec::{
3220        CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
3221        RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple,
3222        TlsModel,
3223    };
3224
3225    use super::{
3226        AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
3227        CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
3228        InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
3229        LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OomStrategy, OptLevel, OutFileName,
3230        OutputType, OutputTypes, PatchableFunctionEntry, Polonius, RemapPathScopeComponents,
3231        ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
3232        SymbolManglingVersion, WasiExecModel,
3233    };
3234    use crate::lint;
3235    use crate::utils::NativeLib;
3236
3237    pub(crate) trait DepTrackingHash {
3238        fn hash(
3239            &self,
3240            hasher: &mut StableHasher,
3241            error_format: ErrorOutputType,
3242            for_crate_hash: bool,
3243        );
3244    }
3245
3246    macro_rules! impl_dep_tracking_hash_via_hash {
3247        ($($t:ty),+ $(,)?) => {$(
3248            impl DepTrackingHash for $t {
3249                fn hash(&self, hasher: &mut StableHasher, _: ErrorOutputType, _for_crate_hash: bool) {
3250                    Hash::hash(self, hasher);
3251                }
3252            }
3253        )+};
3254    }
3255
3256    impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
3257        fn hash(
3258            &self,
3259            hasher: &mut StableHasher,
3260            error_format: ErrorOutputType,
3261            for_crate_hash: bool,
3262        ) {
3263            match self {
3264                Some(x) => {
3265                    Hash::hash(&1, hasher);
3266                    DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
3267                }
3268                None => Hash::hash(&0, hasher),
3269            }
3270        }
3271    }
3272
3273    impl_dep_tracking_hash_via_hash!(
3274        (),
3275        AutoDiff,
3276        Offload,
3277        bool,
3278        usize,
3279        NonZero<usize>,
3280        u64,
3281        Hash64,
3282        String,
3283        PathBuf,
3284        lint::Level,
3285        WasiExecModel,
3286        u32,
3287        FramePointer,
3288        RelocModel,
3289        CodeModel,
3290        TlsModel,
3291        InstrumentCoverage,
3292        CoverageOptions,
3293        InstrumentXRay,
3294        CrateType,
3295        MergeFunctions,
3296        OnBrokenPipe,
3297        PanicStrategy,
3298        RelroLevel,
3299        OptLevel,
3300        LtoCli,
3301        DebugInfo,
3302        DebugInfoCompression,
3303        MirStripDebugInfo,
3304        CollapseMacroDebuginfo,
3305        UnstableFeatures,
3306        NativeLib,
3307        SanitizerSet,
3308        CFGuard,
3309        CFProtection,
3310        TargetTuple,
3311        Edition,
3312        LinkerPluginLto,
3313        ResolveDocLinks,
3314        SplitDebuginfo,
3315        SplitDwarfKind,
3316        StackProtector,
3317        SwitchWithOptPath,
3318        SymbolManglingVersion,
3319        SymbolVisibility,
3320        RemapPathScopeComponents,
3321        SourceFileHashAlgorithm,
3322        OutFileName,
3323        OutputType,
3324        RealFileName,
3325        LocationDetail,
3326        FmtDebug,
3327        BranchProtection,
3328        OomStrategy,
3329        LanguageIdentifier,
3330        NextSolverConfig,
3331        PatchableFunctionEntry,
3332        Polonius,
3333        InliningThreshold,
3334        FunctionReturn,
3335        Align,
3336    );
3337
3338    impl<T1, T2> DepTrackingHash for (T1, T2)
3339    where
3340        T1: DepTrackingHash,
3341        T2: DepTrackingHash,
3342    {
3343        fn hash(
3344            &self,
3345            hasher: &mut StableHasher,
3346            error_format: ErrorOutputType,
3347            for_crate_hash: bool,
3348        ) {
3349            Hash::hash(&0, hasher);
3350            DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3351            Hash::hash(&1, hasher);
3352            DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3353        }
3354    }
3355
3356    impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
3357    where
3358        T1: DepTrackingHash,
3359        T2: DepTrackingHash,
3360        T3: DepTrackingHash,
3361    {
3362        fn hash(
3363            &self,
3364            hasher: &mut StableHasher,
3365            error_format: ErrorOutputType,
3366            for_crate_hash: bool,
3367        ) {
3368            Hash::hash(&0, hasher);
3369            DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3370            Hash::hash(&1, hasher);
3371            DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3372            Hash::hash(&2, hasher);
3373            DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
3374        }
3375    }
3376
3377    impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
3378        fn hash(
3379            &self,
3380            hasher: &mut StableHasher,
3381            error_format: ErrorOutputType,
3382            for_crate_hash: bool,
3383        ) {
3384            Hash::hash(&self.len(), hasher);
3385            for (index, elem) in self.iter().enumerate() {
3386                Hash::hash(&index, hasher);
3387                DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
3388            }
3389        }
3390    }
3391
3392    impl<T: DepTrackingHash, V: DepTrackingHash> DepTrackingHash for FxIndexMap<T, V> {
3393        fn hash(
3394            &self,
3395            hasher: &mut StableHasher,
3396            error_format: ErrorOutputType,
3397            for_crate_hash: bool,
3398        ) {
3399            Hash::hash(&self.len(), hasher);
3400            for (key, value) in self.iter() {
3401                DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3402                DepTrackingHash::hash(value, hasher, error_format, for_crate_hash);
3403            }
3404        }
3405    }
3406
3407    impl DepTrackingHash for OutputTypes {
3408        fn hash(
3409            &self,
3410            hasher: &mut StableHasher,
3411            error_format: ErrorOutputType,
3412            for_crate_hash: bool,
3413        ) {
3414            Hash::hash(&self.0.len(), hasher);
3415            for (key, val) in &self.0 {
3416                DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3417                if !for_crate_hash {
3418                    DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
3419                }
3420            }
3421        }
3422    }
3423
3424    pub(crate) fn stable_hash(
3426        sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
3427        hasher: &mut StableHasher,
3428        error_format: ErrorOutputType,
3429        for_crate_hash: bool,
3430    ) {
3431        for (key, sub_hash) in sub_hashes {
3432            Hash::hash(&key.len(), hasher);
3435            Hash::hash(key, hasher);
3436            sub_hash.hash(hasher, error_format, for_crate_hash);
3437        }
3438    }
3439}
3440
3441#[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
3443pub enum OomStrategy {
3444    Panic,
3446
3447    Abort,
3449}
3450
3451impl OomStrategy {
3452    pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic_v2";
3453
3454    pub fn should_panic(self) -> u8 {
3455        match self {
3456            OomStrategy::Panic => 1,
3457            OomStrategy::Abort => 0,
3458        }
3459    }
3460}
3461
3462#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3464pub enum ProcMacroExecutionStrategy {
3465    SameThread,
3467
3468    CrossThread,
3470}
3471
3472#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3480pub enum CollapseMacroDebuginfo {
3481    No = 0,
3483    Unspecified = 1,
3485    External = 2,
3487    Yes = 3,
3489}
3490
3491#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3493pub enum DumpMonoStatsFormat {
3494    Markdown,
3496    Json,
3498}
3499
3500impl DumpMonoStatsFormat {
3501    pub fn extension(self) -> &'static str {
3502        match self {
3503            Self::Markdown => "md",
3504            Self::Json => "json",
3505        }
3506    }
3507}
3508
3509#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3512pub struct PatchableFunctionEntry {
3513    prefix: u8,
3515    entry: u8,
3517}
3518
3519impl PatchableFunctionEntry {
3520    pub fn from_total_and_prefix_nops(
3521        total_nops: u8,
3522        prefix_nops: u8,
3523    ) -> Option<PatchableFunctionEntry> {
3524        if total_nops < prefix_nops {
3525            None
3526        } else {
3527            Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops })
3528        }
3529    }
3530    pub fn prefix(&self) -> u8 {
3531        self.prefix
3532    }
3533    pub fn entry(&self) -> u8 {
3534        self.entry
3535    }
3536}
3537
3538#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3541pub enum Polonius {
3542    #[default]
3544    Off,
3545
3546    Legacy,
3548
3549    Next,
3551}
3552
3553impl Polonius {
3554    pub fn is_legacy_enabled(&self) -> bool {
3556        matches!(self, Polonius::Legacy)
3557    }
3558
3559    pub fn is_next_enabled(&self) -> bool {
3561        matches!(self, Polonius::Next)
3562    }
3563}
3564
3565#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3566pub enum InliningThreshold {
3567    Always,
3568    Sometimes(usize),
3569    Never,
3570}
3571
3572impl Default for InliningThreshold {
3573    fn default() -> Self {
3574        Self::Sometimes(100)
3575    }
3576}
3577
3578#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3580pub enum FunctionReturn {
3581    #[default]
3583    Keep,
3584
3585    ThunkExtern,
3587}
3588
3589#[derive(Clone, Copy, Default, PartialEq, Debug)]
3592pub enum MirIncludeSpans {
3593    Off,
3594    On,
3595    #[default]
3598    Nll,
3599}
3600
3601impl MirIncludeSpans {
3602    pub fn is_enabled(self) -> bool {
3607        self == MirIncludeSpans::On
3608    }
3609}