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