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