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 edition: DEFAULT_EDITION,
1368 json_artifact_notifications: false,
1369 json_unused_externs: JsonUnusedExterns::No,
1370 json_future_incompat: false,
1371 pretty: None,
1372 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
1373 color: ColorConfig::Auto,
1374 logical_env: FxIndexMap::default(),
1375 verbose: false,
1376 target_modifiers: BTreeMap::default(),
1377 }
1378 }
1379}
1380
1381impl Options {
1382 pub fn build_dep_graph(&self) -> bool {
1384 self.incremental.is_some()
1385 || self.unstable_opts.dump_dep_graph
1386 || self.unstable_opts.query_dep_graph
1387 }
1388
1389 pub fn file_path_mapping(&self) -> FilePathMapping {
1390 file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts)
1391 }
1392
1393 pub fn will_create_output_file(&self) -> bool {
1395 !self.unstable_opts.parse_crate_root_only && self.unstable_opts.ls.is_empty() }
1398
1399 #[inline]
1400 pub fn share_generics(&self) -> bool {
1401 match self.unstable_opts.share_generics {
1402 Some(setting) => setting,
1403 None => match self.optimize {
1404 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
1405 OptLevel::More | OptLevel::Aggressive => false,
1406 },
1407 }
1408 }
1409
1410 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
1411 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
1412 }
1413}
1414
1415impl UnstableOptions {
1416 pub fn dcx_flags(&self, can_emit_warnings: bool) -> DiagCtxtFlags {
1417 DiagCtxtFlags {
1418 can_emit_warnings,
1419 treat_err_as_bug: self.treat_err_as_bug,
1420 eagerly_emit_delayed_bugs: self.eagerly_emit_delayed_bugs,
1421 macro_backtrace: self.macro_backtrace,
1422 deduplicate_diagnostics: self.deduplicate_diagnostics,
1423 track_diagnostics: self.track_diagnostics,
1424 }
1425 }
1426
1427 pub fn src_hash_algorithm(&self, target: &Target) -> SourceFileHashAlgorithm {
1428 self.src_hash_algorithm.unwrap_or_else(|| {
1429 if target.is_like_msvc {
1430 SourceFileHashAlgorithm::Sha256
1431 } else {
1432 SourceFileHashAlgorithm::Md5
1433 }
1434 })
1435 }
1436
1437 pub fn checksum_hash_algorithm(&self) -> Option<SourceFileHashAlgorithm> {
1438 self.checksum_hash_algorithm
1439 }
1440}
1441
1442#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
1444pub enum EntryFnType {
1445 Main {
1446 sigpipe: u8,
1453 },
1454}
1455
1456#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
1457#[derive(HashStable_Generic)]
1458pub enum CrateType {
1459 Executable,
1460 Dylib,
1461 Rlib,
1462 Staticlib,
1463 Cdylib,
1464 ProcMacro,
1465 Sdylib,
1466}
1467
1468impl CrateType {
1469 pub fn has_metadata(self) -> bool {
1470 match self {
1471 CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
1472 CrateType::Executable
1473 | CrateType::Cdylib
1474 | CrateType::Staticlib
1475 | CrateType::Sdylib => false,
1476 }
1477 }
1478}
1479
1480#[derive(Clone, Hash, Debug, PartialEq, Eq)]
1481pub enum Passes {
1482 Some(Vec<String>),
1483 All,
1484}
1485
1486impl Passes {
1487 fn is_empty(&self) -> bool {
1488 match *self {
1489 Passes::Some(ref v) => v.is_empty(),
1490 Passes::All => false,
1491 }
1492 }
1493
1494 pub(crate) fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
1495 match *self {
1496 Passes::Some(ref mut v) => v.extend(passes),
1497 Passes::All => {}
1498 }
1499 }
1500}
1501
1502#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1503pub enum PAuthKey {
1504 A,
1505 B,
1506}
1507
1508#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1509pub struct PacRet {
1510 pub leaf: bool,
1511 pub pc: bool,
1512 pub key: PAuthKey,
1513}
1514
1515#[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
1516pub struct BranchProtection {
1517 pub bti: bool,
1518 pub pac_ret: Option<PacRet>,
1519}
1520
1521pub(crate) const fn default_lib_output() -> CrateType {
1522 CrateType::Rlib
1523}
1524
1525pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
1526 cfg::disallow_cfgs(sess, &user_cfg);
1528
1529 user_cfg.extend(cfg::default_configuration(sess));
1532 user_cfg
1533}
1534
1535pub fn build_target_config(
1536 early_dcx: &EarlyDiagCtxt,
1537 target: &TargetTuple,
1538 sysroot: &Path,
1539) -> Target {
1540 match Target::search(target, sysroot) {
1541 Ok((target, warnings)) => {
1542 for warning in warnings.warning_messages() {
1543 early_dcx.early_warn(warning)
1544 }
1545
1546 if !matches!(target.pointer_width, 16 | 32 | 64) {
1547 early_dcx.early_fatal(format!(
1548 "target specification was invalid: unrecognized target-pointer-width {}",
1549 target.pointer_width
1550 ))
1551 }
1552 target
1553 }
1554 Err(e) => {
1555 let mut err =
1556 early_dcx.early_struct_fatal(format!("error loading target specification: {e}"));
1557 err.help("run `rustc --print target-list` for a list of built-in targets");
1558 err.emit();
1559 }
1560 }
1561}
1562
1563#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1564pub enum OptionStability {
1565 Stable,
1566 Unstable,
1567}
1568
1569#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1570pub enum OptionKind {
1571 Opt,
1575
1576 Multi,
1580
1581 Flag,
1586
1587 FlagMulti,
1592}
1593
1594pub struct RustcOptGroup {
1595 pub name: &'static str,
1603 stability: OptionStability,
1604 kind: OptionKind,
1605
1606 short_name: &'static str,
1607 long_name: &'static str,
1608 desc: &'static str,
1609 value_hint: &'static str,
1610
1611 pub is_verbose_help_only: bool,
1614}
1615
1616impl RustcOptGroup {
1617 pub fn is_stable(&self) -> bool {
1618 self.stability == OptionStability::Stable
1619 }
1620
1621 pub fn apply(&self, options: &mut getopts::Options) {
1622 let &Self { short_name, long_name, desc, value_hint, .. } = self;
1623 match self.kind {
1624 OptionKind::Opt => options.optopt(short_name, long_name, desc, value_hint),
1625 OptionKind::Multi => options.optmulti(short_name, long_name, desc, value_hint),
1626 OptionKind::Flag => options.optflag(short_name, long_name, desc),
1627 OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
1628 };
1629 }
1630}
1631
1632pub fn make_opt(
1633 stability: OptionStability,
1634 kind: OptionKind,
1635 short_name: &'static str,
1636 long_name: &'static str,
1637 desc: &'static str,
1638 value_hint: &'static str,
1639) -> RustcOptGroup {
1640 match kind {
1642 OptionKind::Opt | OptionKind::Multi => {}
1643 OptionKind::Flag | OptionKind::FlagMulti => assert_eq!(value_hint, ""),
1644 }
1645 RustcOptGroup {
1646 name: cmp::max_by_key(short_name, long_name, |s| s.len()),
1647 stability,
1648 kind,
1649 short_name,
1650 long_name,
1651 desc,
1652 value_hint,
1653 is_verbose_help_only: false,
1654 }
1655}
1656
1657static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
1658 format!(
1659 "Specify which edition of the compiler to use when compiling code. \
1660The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
1661 )
1662});
1663
1664static PRINT_HELP: LazyLock<String> = LazyLock::new(|| {
1665 format!(
1666 "Compiler information to print on stdout (or to a file)\n\
1667 INFO may be one of <{}>.",
1668 PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::<Vec<_>>().join("|")
1669 )
1670});
1671
1672static EMIT_HELP: LazyLock<String> = LazyLock::new(|| {
1673 let mut result =
1674 String::from("Comma separated list of types of output for the compiler to emit.\n");
1675 result.push_str("Each TYPE has the default FILE name:\n");
1676
1677 for output in OutputType::iter_all() {
1678 result.push_str(&format!("* {} - {}\n", output.shorthand(), output.default_filename()));
1679 }
1680
1681 result
1682});
1683
1684pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1694 use OptionKind::{Flag, FlagMulti, Multi, Opt};
1695 use OptionStability::{Stable, Unstable};
1696
1697 use self::make_opt as opt;
1698
1699 let mut options = vec![
1700 opt(Stable, Flag, "h", "help", "Display this message", ""),
1701 opt(
1702 Stable,
1703 Multi,
1704 "",
1705 "cfg",
1706 "Configure the compilation environment.\n\
1707 SPEC supports the syntax `<NAME>[=\"<VALUE>\"]`.",
1708 "<SPEC>",
1709 ),
1710 opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "<SPEC>"),
1711 opt(
1712 Stable,
1713 Multi,
1714 "L",
1715 "",
1716 "Add a directory to the library search path. \
1717 The optional KIND can be one of <dependency|crate|native|framework|all> (default: all).",
1718 "[<KIND>=]<PATH>",
1719 ),
1720 opt(
1721 Stable,
1722 Multi,
1723 "l",
1724 "",
1725 "Link the generated crate(s) to the specified native\n\
1726 library NAME. The optional KIND can be one of\n\
1727 <static|framework|dylib> (default: dylib).\n\
1728 Optional comma separated MODIFIERS\n\
1729 <bundle|verbatim|whole-archive|as-needed>\n\
1730 may be specified each with a prefix of either '+' to\n\
1731 enable or '-' to disable.",
1732 "[<KIND>[:<MODIFIERS>]=]<NAME>[:<RENAME>]",
1733 ),
1734 make_crate_type_option(),
1735 opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "<NAME>"),
1736 opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST),
1737 opt(Stable, Multi, "", "emit", &EMIT_HELP, "<TYPE>[=<FILE>]"),
1738 opt(Stable, Multi, "", "print", &PRINT_HELP, "<INFO>[=<FILE>]"),
1739 opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""),
1740 opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""),
1741 opt(Stable, Opt, "o", "", "Write output to FILENAME", "<FILENAME>"),
1742 opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in DIR", "<DIR>"),
1743 opt(
1744 Stable,
1745 Opt,
1746 "",
1747 "explain",
1748 "Provide a detailed explanation of an error message",
1749 "<OPT>",
1750 ),
1751 opt(Stable, Flag, "", "test", "Build a test harness", ""),
1752 opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "<TARGET>"),
1753 opt(Stable, Multi, "A", "allow", "Set lint allowed", "<LINT>"),
1754 opt(Stable, Multi, "W", "warn", "Set lint warnings", "<LINT>"),
1755 opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "<LINT>"),
1756 opt(Stable, Multi, "D", "deny", "Set lint denied", "<LINT>"),
1757 opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "<LINT>"),
1758 opt(
1759 Stable,
1760 Multi,
1761 "",
1762 "cap-lints",
1763 "Set the most restrictive lint level. More restrictive lints are capped at this level",
1764 "<LEVEL>",
1765 ),
1766 opt(Stable, Multi, "C", "codegen", "Set a codegen option", "<OPT>[=<VALUE>]"),
1767 opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
1768 opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
1769 ];
1770
1771 let verbose_only = [
1774 opt(
1775 Stable,
1776 Multi,
1777 "",
1778 "extern",
1779 "Specify where an external rust library is located",
1780 "<NAME>[=<PATH>]",
1781 ),
1782 opt(Stable, Opt, "", "sysroot", "Override the system root", "<PATH>"),
1783 opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "<FLAG>"),
1784 opt(
1785 Stable,
1786 Opt,
1787 "",
1788 "error-format",
1789 "How errors and other messages are produced",
1790 "<human|json|short>",
1791 ),
1792 opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "<CONFIG>"),
1793 opt(
1794 Stable,
1795 Opt,
1796 "",
1797 "color",
1798 "Configure coloring of output:
1799 * auto = colorize, if output goes to a tty (default);
1800 * always = always colorize output;
1801 * never = never colorize output",
1802 "<auto|always|never>",
1803 ),
1804 opt(
1805 Stable,
1806 Opt,
1807 "",
1808 "diagnostic-width",
1809 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1810 "<WIDTH>",
1811 ),
1812 opt(
1813 Stable,
1814 Multi,
1815 "",
1816 "remap-path-prefix",
1817 "Remap source names in all output (compiler messages and output files)",
1818 "<FROM>=<TO>",
1819 ),
1820 opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "<VAR>=<VALUE>"),
1821 ];
1822 options.extend(verbose_only.into_iter().map(|mut opt| {
1823 opt.is_verbose_help_only = true;
1824 opt
1825 }));
1826
1827 options
1828}
1829
1830pub fn get_cmd_lint_options(
1831 early_dcx: &EarlyDiagCtxt,
1832 matches: &getopts::Matches,
1833) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1834 let mut lint_opts_with_position = vec![];
1835 let mut describe_lints = false;
1836
1837 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1838 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1839 if lint_name == "help" {
1840 describe_lints = true;
1841 } else {
1842 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1843 }
1844 }
1845 }
1846
1847 lint_opts_with_position.sort_by_key(|x| x.0);
1848 let lint_opts = lint_opts_with_position
1849 .iter()
1850 .cloned()
1851 .map(|(_, lint_name, level)| (lint_name, level))
1852 .collect();
1853
1854 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1855 lint::Level::from_str(&cap)
1856 .unwrap_or_else(|| early_dcx.early_fatal(format!("unknown lint level: `{cap}`")))
1857 });
1858
1859 (lint_opts, describe_lints, lint_cap)
1860}
1861
1862pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> ColorConfig {
1864 match matches.opt_str("color").as_deref() {
1865 Some("auto") => ColorConfig::Auto,
1866 Some("always") => ColorConfig::Always,
1867 Some("never") => ColorConfig::Never,
1868
1869 None => ColorConfig::Auto,
1870
1871 Some(arg) => early_dcx.early_fatal(format!(
1872 "argument for `--color` must be auto, \
1873 always or never (instead was `{arg}`)"
1874 )),
1875 }
1876}
1877
1878pub struct JsonConfig {
1880 pub json_rendered: HumanReadableErrorType,
1881 pub json_color: ColorConfig,
1882 json_artifact_notifications: bool,
1883 pub json_unused_externs: JsonUnusedExterns,
1884 json_future_incompat: bool,
1885}
1886
1887#[derive(Copy, Clone)]
1889pub enum JsonUnusedExterns {
1890 No,
1892 Silent,
1894 Loud,
1896}
1897
1898impl JsonUnusedExterns {
1899 pub fn is_enabled(&self) -> bool {
1900 match self {
1901 JsonUnusedExterns::No => false,
1902 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1903 }
1904 }
1905
1906 pub fn is_loud(&self) -> bool {
1907 match self {
1908 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1909 JsonUnusedExterns::Loud => true,
1910 }
1911 }
1912}
1913
1914pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
1919 let mut json_rendered = HumanReadableErrorType::Default;
1920 let mut json_color = ColorConfig::Never;
1921 let mut json_artifact_notifications = false;
1922 let mut json_unused_externs = JsonUnusedExterns::No;
1923 let mut json_future_incompat = false;
1924 for option in matches.opt_strs("json") {
1925 if matches.opt_str("color").is_some() {
1929 early_dcx.early_fatal("cannot specify the `--color` option with `--json`");
1930 }
1931
1932 for sub_option in option.split(',') {
1933 match sub_option {
1934 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1935 "diagnostic-unicode" => {
1936 json_rendered = HumanReadableErrorType::Unicode;
1937 }
1938 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1939 "artifacts" => json_artifact_notifications = true,
1940 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1941 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1942 "future-incompat" => json_future_incompat = true,
1943 s => early_dcx.early_fatal(format!("unknown `--json` option `{s}`")),
1944 }
1945 }
1946 }
1947
1948 JsonConfig {
1949 json_rendered,
1950 json_color,
1951 json_artifact_notifications,
1952 json_unused_externs,
1953 json_future_incompat,
1954 }
1955}
1956
1957pub fn parse_error_format(
1959 early_dcx: &mut EarlyDiagCtxt,
1960 matches: &getopts::Matches,
1961 color_config: ColorConfig,
1962 json_color: ColorConfig,
1963 json_rendered: HumanReadableErrorType,
1964) -> ErrorOutputType {
1965 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1970 match matches.opt_str("error-format").as_deref() {
1971 None | Some("human") => ErrorOutputType::HumanReadable { color_config, .. },
1972 Some("human-annotate-rs") => ErrorOutputType::HumanReadable {
1973 kind: HumanReadableErrorType::AnnotateSnippet,
1974 color_config,
1975 },
1976 Some("json") => {
1977 ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
1978 }
1979 Some("pretty-json") => {
1980 ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
1981 }
1982 Some("short") => {
1983 ErrorOutputType::HumanReadable { kind: HumanReadableErrorType::Short, color_config }
1984 }
1985 Some("human-unicode") => ErrorOutputType::HumanReadable {
1986 kind: HumanReadableErrorType::Unicode,
1987 color_config,
1988 },
1989 Some(arg) => {
1990 early_dcx.set_error_format(ErrorOutputType::HumanReadable { color_config, .. });
1991 early_dcx.early_fatal(format!(
1992 "argument for `--error-format` must be `human`, `human-annotate-rs`, \
1993 `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)"
1994 ))
1995 }
1996 }
1997 } else {
1998 ErrorOutputType::HumanReadable { color_config, .. }
1999 };
2000
2001 match error_format {
2002 ErrorOutputType::Json { .. } => {}
2003
2004 _ if !matches.opt_strs("json").is_empty() => {
2008 early_dcx.early_fatal("using `--json` requires also using `--error-format=json`");
2009 }
2010
2011 _ => {}
2012 }
2013
2014 error_format
2015}
2016
2017pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Edition {
2018 let edition = match matches.opt_str("edition") {
2019 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
2020 early_dcx.early_fatal(format!(
2021 "argument for `--edition` must be one of: \
2022 {EDITION_NAME_LIST}. (instead was `{arg}`)"
2023 ))
2024 }),
2025 None => DEFAULT_EDITION,
2026 };
2027
2028 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
2029 let is_nightly = nightly_options::match_is_nightly_build(matches);
2030 let msg = if !is_nightly {
2031 format!(
2032 "the crate requires edition {edition}, but the latest edition supported by this Rust version is {LATEST_STABLE_EDITION}"
2033 )
2034 } else {
2035 format!("edition {edition} is unstable and only available with -Z unstable-options")
2036 };
2037 early_dcx.early_fatal(msg)
2038 }
2039
2040 edition
2041}
2042
2043fn check_error_format_stability(
2044 early_dcx: &EarlyDiagCtxt,
2045 unstable_opts: &UnstableOptions,
2046 format: ErrorOutputType,
2047) {
2048 if unstable_opts.unstable_options {
2049 return;
2050 }
2051 let format = match format {
2052 ErrorOutputType::Json { pretty: true, .. } => "pretty-json",
2053 ErrorOutputType::HumanReadable { kind, .. } => match kind {
2054 HumanReadableErrorType::AnnotateSnippet => "human-annotate-rs",
2055 HumanReadableErrorType::Unicode => "human-unicode",
2056 _ => return,
2057 },
2058 _ => return,
2059 };
2060 early_dcx.early_fatal(format!("`--error-format={format}` is unstable"))
2061}
2062
2063fn parse_output_types(
2064 early_dcx: &EarlyDiagCtxt,
2065 unstable_opts: &UnstableOptions,
2066 matches: &getopts::Matches,
2067) -> OutputTypes {
2068 let mut output_types = BTreeMap::new();
2069 if !unstable_opts.parse_crate_root_only {
2070 for list in matches.opt_strs("emit") {
2071 for output_type in list.split(',') {
2072 let (shorthand, path) = split_out_file_name(output_type);
2073 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
2074 early_dcx.early_fatal(format!(
2075 "unknown emission type: `{shorthand}` - expected one of: {display}",
2076 display = OutputType::shorthands_display(),
2077 ))
2078 });
2079 if output_type == OutputType::ThinLinkBitcode && !unstable_opts.unstable_options {
2080 early_dcx.early_fatal(format!(
2081 "{} requested but -Zunstable-options not specified",
2082 OutputType::ThinLinkBitcode.shorthand()
2083 ));
2084 }
2085 output_types.insert(output_type, path);
2086 }
2087 }
2088 };
2089 if output_types.is_empty() {
2090 output_types.insert(OutputType::Exe, None);
2091 }
2092 OutputTypes(output_types)
2093}
2094
2095fn split_out_file_name(arg: &str) -> (&str, Option<OutFileName>) {
2096 match arg.split_once('=') {
2097 None => (arg, None),
2098 Some((kind, "-")) => (kind, Some(OutFileName::Stdout)),
2099 Some((kind, path)) => (kind, Some(OutFileName::Real(PathBuf::from(path)))),
2100 }
2101}
2102
2103fn should_override_cgus_and_disable_thinlto(
2104 early_dcx: &EarlyDiagCtxt,
2105 output_types: &OutputTypes,
2106 matches: &getopts::Matches,
2107 mut codegen_units: Option<usize>,
2108) -> (bool, Option<usize>) {
2109 let mut disable_local_thinlto = false;
2110 let incompatible: Vec<_> = output_types
2113 .0
2114 .iter()
2115 .map(|ot_path| ot_path.0)
2116 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2117 .map(|ot| ot.shorthand())
2118 .collect();
2119 if !incompatible.is_empty() {
2120 match codegen_units {
2121 Some(n) if n > 1 => {
2122 if matches.opt_present("o") {
2123 for ot in &incompatible {
2124 early_dcx.early_warn(format!(
2125 "`--emit={ot}` with `-o` incompatible with \
2126 `-C codegen-units=N` for N > 1",
2127 ));
2128 }
2129 early_dcx.early_warn("resetting to default -C codegen-units=1");
2130 codegen_units = Some(1);
2131 disable_local_thinlto = true;
2132 }
2133 }
2134 _ => {
2135 codegen_units = Some(1);
2136 disable_local_thinlto = true;
2137 }
2138 }
2139 }
2140
2141 if codegen_units == Some(0) {
2142 early_dcx.early_fatal("value for codegen units must be a positive non-zero integer");
2143 }
2144
2145 (disable_local_thinlto, codegen_units)
2146}
2147
2148fn collect_print_requests(
2149 early_dcx: &EarlyDiagCtxt,
2150 cg: &mut CodegenOptions,
2151 unstable_opts: &UnstableOptions,
2152 matches: &getopts::Matches,
2153) -> Vec<PrintRequest> {
2154 let mut prints = Vec::<PrintRequest>::new();
2155 if cg.target_cpu.as_deref() == Some("help") {
2156 prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout });
2157 cg.target_cpu = None;
2158 };
2159 if cg.target_feature == "help" {
2160 prints.push(PrintRequest { kind: PrintKind::TargetFeatures, out: OutFileName::Stdout });
2161 cg.target_feature = String::new();
2162 }
2163
2164 let mut printed_paths = FxHashSet::default();
2169
2170 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
2171 let (req, out) = split_out_file_name(&req);
2172
2173 let kind = if let Some((print_name, print_kind)) =
2174 PRINT_KINDS.iter().find(|&&(name, _)| name == req)
2175 {
2176 check_print_request_stability(early_dcx, unstable_opts, (print_name, *print_kind));
2177 *print_kind
2178 } else {
2179 let is_nightly = nightly_options::match_is_nightly_build(matches);
2180 emit_unknown_print_request_help(early_dcx, req, is_nightly)
2181 };
2182
2183 let out = out.unwrap_or(OutFileName::Stdout);
2184 if let OutFileName::Real(path) = &out {
2185 if !printed_paths.insert(path.clone()) {
2186 early_dcx.early_fatal(format!(
2187 "cannot print multiple outputs to the same path: {}",
2188 path.display(),
2189 ));
2190 }
2191 }
2192
2193 PrintRequest { kind, out }
2194 }));
2195
2196 prints
2197}
2198
2199fn check_print_request_stability(
2200 early_dcx: &EarlyDiagCtxt,
2201 unstable_opts: &UnstableOptions,
2202 (print_name, print_kind): (&str, PrintKind),
2203) {
2204 if !is_print_request_stable(print_kind) && !unstable_opts.unstable_options {
2205 early_dcx.early_fatal(format!(
2206 "the `-Z unstable-options` flag must also be passed to enable the `{print_name}` \
2207 print option"
2208 ));
2209 }
2210}
2211
2212fn is_print_request_stable(print_kind: PrintKind) -> bool {
2213 match print_kind {
2214 PrintKind::AllTargetSpecsJson
2215 | PrintKind::CheckCfg
2216 | PrintKind::CrateRootLintLevels
2217 | PrintKind::SupportedCrateTypes
2218 | PrintKind::TargetSpecJson => false,
2219 _ => true,
2220 }
2221}
2222
2223fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str, is_nightly: bool) -> ! {
2224 let prints = PRINT_KINDS
2225 .iter()
2226 .filter_map(|(name, kind)| {
2227 if !is_nightly && !is_print_request_stable(*kind) {
2229 None
2230 } else {
2231 Some(format!("`{name}`"))
2232 }
2233 })
2234 .collect::<Vec<_>>();
2235 let prints = prints.join(", ");
2236
2237 let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`"));
2238 #[allow(rustc::diagnostic_outside_of_impl)]
2239 diag.help(format!("valid print requests are: {prints}"));
2240
2241 if req == "lints" {
2242 diag.help(format!("use `-Whelp` to print a list of lints"));
2243 }
2244
2245 diag.help(format!("for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information"));
2246 diag.emit()
2247}
2248
2249pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTuple {
2250 match matches.opt_str("target") {
2251 Some(target) if target.ends_with(".json") => {
2252 let path = Path::new(&target);
2253 TargetTuple::from_path(path).unwrap_or_else(|_| {
2254 early_dcx.early_fatal(format!("target file {path:?} does not exist"))
2255 })
2256 }
2257 Some(target) => TargetTuple::TargetTuple(target),
2258 _ => TargetTuple::from_tuple(host_tuple()),
2259 }
2260}
2261
2262fn parse_opt_level(
2263 early_dcx: &EarlyDiagCtxt,
2264 matches: &getopts::Matches,
2265 cg: &CodegenOptions,
2266) -> OptLevel {
2267 let max_o = matches.opt_positions("O").into_iter().max();
2274 let max_c = matches
2275 .opt_strs_pos("C")
2276 .into_iter()
2277 .flat_map(|(i, s)| {
2278 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
2280 })
2281 .max();
2282 if max_o > max_c {
2283 OptLevel::Aggressive
2284 } else {
2285 match cg.opt_level.as_ref() {
2286 "0" => OptLevel::No,
2287 "1" => OptLevel::Less,
2288 "2" => OptLevel::More,
2289 "3" => OptLevel::Aggressive,
2290 "s" => OptLevel::Size,
2291 "z" => OptLevel::SizeMin,
2292 arg => {
2293 early_dcx.early_fatal(format!(
2294 "optimization level needs to be \
2295 between 0-3, s or z (instead was `{arg}`)"
2296 ));
2297 }
2298 }
2299 }
2300}
2301
2302fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInfo {
2303 let max_g = matches.opt_positions("g").into_iter().max();
2304 let max_c = matches
2305 .opt_strs_pos("C")
2306 .into_iter()
2307 .flat_map(|(i, s)| {
2308 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
2310 })
2311 .max();
2312 if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
2313}
2314
2315fn parse_assert_incr_state(
2316 early_dcx: &EarlyDiagCtxt,
2317 opt_assertion: &Option<String>,
2318) -> Option<IncrementalStateAssertion> {
2319 match opt_assertion {
2320 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
2321 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
2322 Some(s) => {
2323 early_dcx.early_fatal(format!("unexpected incremental state assertion value: {s}"))
2324 }
2325 None => None,
2326 }
2327}
2328
2329pub fn parse_externs(
2330 early_dcx: &EarlyDiagCtxt,
2331 matches: &getopts::Matches,
2332 unstable_opts: &UnstableOptions,
2333) -> Externs {
2334 let is_unstable_enabled = unstable_opts.unstable_options;
2335 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2336 for arg in matches.opt_strs("extern") {
2337 let ExternOpt { crate_name: name, path, options } =
2338 split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit());
2339
2340 let entry = externs.entry(name.to_owned());
2341
2342 use std::collections::btree_map::Entry;
2343
2344 let entry = if let Some(path) = path {
2345 let path = CanonicalizedPath::new(path);
2347 match entry {
2348 Entry::Vacant(vacant) => {
2349 let files = BTreeSet::from_iter(iter::once(path));
2350 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2351 }
2352 Entry::Occupied(occupied) => {
2353 let ext_ent = occupied.into_mut();
2354 match ext_ent {
2355 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2356 files.insert(path);
2357 }
2358 ExternEntry {
2359 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2360 ..
2361 } => {
2362 let files = BTreeSet::from_iter(iter::once(path));
2364 *location = ExternLocation::ExactPaths(files);
2365 }
2366 }
2367 ext_ent
2368 }
2369 }
2370 } else {
2371 match entry {
2373 Entry::Vacant(vacant) => {
2374 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2375 }
2376 Entry::Occupied(occupied) => {
2377 occupied.into_mut()
2379 }
2380 }
2381 };
2382
2383 let mut is_private_dep = false;
2384 let mut add_prelude = true;
2385 let mut nounused_dep = false;
2386 let mut force = false;
2387 if let Some(opts) = options {
2388 if !is_unstable_enabled {
2389 early_dcx.early_fatal(
2390 "the `-Z unstable-options` flag must also be passed to \
2391 enable `--extern` options",
2392 );
2393 }
2394 for opt in opts.split(',') {
2395 match opt {
2396 "priv" => is_private_dep = true,
2397 "noprelude" => {
2398 if let ExternLocation::ExactPaths(_) = &entry.location {
2399 add_prelude = false;
2400 } else {
2401 early_dcx.early_fatal(
2402 "the `noprelude` --extern option requires a file path",
2403 );
2404 }
2405 }
2406 "nounused" => nounused_dep = true,
2407 "force" => force = true,
2408 _ => early_dcx.early_fatal(format!("unknown --extern option `{opt}`")),
2409 }
2410 }
2411 }
2412
2413 entry.is_private_dep |= is_private_dep;
2416 entry.nounused_dep |= nounused_dep;
2418 entry.force |= force;
2420 entry.add_prelude |= add_prelude;
2422 }
2423 Externs(externs)
2424}
2425
2426fn parse_remap_path_prefix(
2427 early_dcx: &EarlyDiagCtxt,
2428 matches: &getopts::Matches,
2429 unstable_opts: &UnstableOptions,
2430) -> Vec<(PathBuf, PathBuf)> {
2431 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2432 .opt_strs("remap-path-prefix")
2433 .into_iter()
2434 .map(|remap| match remap.rsplit_once('=') {
2435 None => {
2436 early_dcx.early_fatal("--remap-path-prefix must contain '=' between FROM and TO")
2437 }
2438 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2439 })
2440 .collect();
2441 match &unstable_opts.remap_cwd_prefix {
2442 Some(to) => match std::env::current_dir() {
2443 Ok(cwd) => mapping.push((cwd, to.clone())),
2444 Err(_) => (),
2445 },
2446 None => (),
2447 };
2448 mapping
2449}
2450
2451fn parse_logical_env(
2452 early_dcx: &EarlyDiagCtxt,
2453 matches: &getopts::Matches,
2454) -> FxIndexMap<String, String> {
2455 let mut vars = FxIndexMap::default();
2456
2457 for arg in matches.opt_strs("env-set") {
2458 if let Some((name, val)) = arg.split_once('=') {
2459 vars.insert(name.to_string(), val.to_string());
2460 } else {
2461 early_dcx.early_fatal(format!("`--env-set`: specify value for variable `{arg}`"));
2462 }
2463 }
2464
2465 vars
2466}
2467
2468#[allow(rustc::bad_opt_access)]
2470pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches) -> Options {
2471 let color = parse_color(early_dcx, matches);
2472
2473 let edition = parse_crate_edition(early_dcx, matches);
2474
2475 let JsonConfig {
2476 json_rendered,
2477 json_color,
2478 json_artifact_notifications,
2479 json_unused_externs,
2480 json_future_incompat,
2481 } = parse_json(early_dcx, matches);
2482
2483 let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
2484
2485 early_dcx.set_error_format(error_format);
2486
2487 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2488 early_dcx.early_fatal("`--diagnostic-width` must be an positive integer");
2489 });
2490
2491 let unparsed_crate_types = matches.opt_strs("crate-type");
2492 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2493 .unwrap_or_else(|e| early_dcx.early_fatal(e));
2494
2495 let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
2496
2497 let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
2498 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
2499
2500 check_error_format_stability(early_dcx, &unstable_opts, error_format);
2501
2502 let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
2503
2504 let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
2505 let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2506 early_dcx,
2507 &output_types,
2508 matches,
2509 cg.codegen_units,
2510 );
2511
2512 if unstable_opts.threads == 0 {
2513 early_dcx.early_fatal("value for threads must be a positive non-zero integer");
2514 }
2515
2516 if unstable_opts.threads == parse::MAX_THREADS_CAP {
2517 early_dcx.early_warn(format!("number of threads was capped at {}", parse::MAX_THREADS_CAP));
2518 }
2519
2520 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2521
2522 let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state);
2523
2524 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2525 early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive");
2526 }
2527
2528 if unstable_opts.profile_sample_use.is_some()
2529 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2530 {
2531 early_dcx.early_fatal(
2532 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2533 );
2534 }
2535
2536 match cg.symbol_mangling_version {
2539 None | Some(SymbolManglingVersion::V0) => {}
2541
2542 Some(SymbolManglingVersion::Legacy) => {
2544 if !unstable_opts.unstable_options {
2545 early_dcx.early_fatal(
2546 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2547 );
2548 }
2549 }
2550 Some(SymbolManglingVersion::Hashed) => {
2551 if !unstable_opts.unstable_options {
2552 early_dcx.early_fatal(
2553 "`-C symbol-mangling-version=hashed` requires `-Z unstable-options`",
2554 );
2555 }
2556 }
2557 }
2558
2559 if cg.instrument_coverage != InstrumentCoverage::No {
2560 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2561 early_dcx.early_fatal(
2562 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2563 or `-C profile-generate`",
2564 );
2565 }
2566
2567 match cg.symbol_mangling_version {
2572 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2573 Some(SymbolManglingVersion::Legacy) => {
2574 early_dcx.early_warn(
2575 "-C instrument-coverage requires symbol mangling version `v0`, \
2576 but `-C symbol-mangling-version=legacy` was specified",
2577 );
2578 }
2579 Some(SymbolManglingVersion::V0) => {}
2580 Some(SymbolManglingVersion::Hashed) => {
2581 early_dcx.early_warn(
2582 "-C instrument-coverage requires symbol mangling version `v0`, \
2583 but `-C symbol-mangling-version=hashed` was specified",
2584 );
2585 }
2586 }
2587 }
2588
2589 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2590 unstable_opts.graphviz_font = graphviz_font;
2593 }
2594
2595 if !cg.embed_bitcode {
2596 match cg.lto {
2597 LtoCli::No | LtoCli::Unspecified => {}
2598 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
2599 early_dcx.early_fatal("options `-C embed-bitcode=no` and `-C lto` are incompatible")
2600 }
2601 }
2602 }
2603
2604 if !nightly_options::is_unstable_enabled(matches)
2605 && cg.force_frame_pointers == FramePointer::NonLeaf
2606 {
2607 early_dcx.early_fatal(
2608 "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
2609 and a nightly compiler",
2610 )
2611 }
2612
2613 if !nightly_options::is_unstable_enabled(matches) {
2617 let uses_unstable_self_contained_option =
2618 cg.link_self_contained.are_unstable_variants_set();
2619 if uses_unstable_self_contained_option {
2620 early_dcx.early_fatal(
2621 "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
2622 the `-Z unstable-options` flag must also be passed to use the unstable values",
2623 );
2624 }
2625
2626 if let Some(flavor) = cg.linker_flavor {
2627 if flavor.is_unstable() {
2628 early_dcx.early_fatal(format!(
2629 "the linker flavor `{}` is unstable, the `-Z unstable-options` \
2630 flag must also be passed to use the unstable values",
2631 flavor.desc()
2632 ));
2633 }
2634 }
2635 }
2636
2637 if let Some(erroneous_components) = cg.link_self_contained.check_consistency() {
2640 let names: String = erroneous_components
2641 .into_iter()
2642 .map(|c| c.as_str().unwrap())
2643 .intersperse(", ")
2644 .collect();
2645 early_dcx.early_fatal(format!(
2646 "some `-C link-self-contained` components were both enabled and disabled: {names}"
2647 ));
2648 }
2649
2650 let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches);
2651
2652 let cg = cg;
2653
2654 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2655 let target_triple = parse_target_triple(early_dcx, matches);
2656 let opt_level = parse_opt_level(early_dcx, matches, &cg);
2657 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2661 let debuginfo = select_debuginfo(matches, &cg);
2662 let debuginfo_compression = unstable_opts.debuginfo_compression;
2663
2664 let crate_name = matches.opt_str("crate-name");
2665 let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
2666 let libs = parse_native_libs(early_dcx, &unstable_opts, unstable_features, matches);
2668
2669 let test = matches.opt_present("test");
2670
2671 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2672 early_dcx.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
2673 }
2674
2675 if cg.remark.is_empty() && unstable_opts.remark_dir.is_some() {
2676 early_dcx
2677 .early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all");
2678 }
2679
2680 let externs = parse_externs(early_dcx, matches, &unstable_opts);
2681
2682 let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts);
2683
2684 let pretty = parse_pretty(early_dcx, &unstable_opts);
2685
2686 if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
2688 early_dcx.early_fatal("can't dump dependency graph without `-Z query-dep-graph`");
2689 }
2690
2691 let logical_env = parse_logical_env(early_dcx, matches);
2692
2693 let sysroot = filesearch::materialize_sysroot(sysroot_opt);
2694
2695 let real_rust_source_base_dir = {
2696 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2698 if let Ok(metadata) = candidate.symlink_metadata() {
2699 if metadata.file_type().is_symlink() {
2703 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2704 candidate = symlink_dest;
2705 }
2706 }
2707 }
2708
2709 candidate.join("library/std/src/lib.rs").is_file().then_some(candidate)
2711 };
2712
2713 let mut search_paths = vec![];
2714 for s in &matches.opt_strs("L") {
2715 search_paths.push(SearchPath::from_cli_opt(
2716 &sysroot,
2717 &target_triple,
2718 early_dcx,
2719 s,
2720 unstable_opts.unstable_options,
2721 ));
2722 }
2723
2724 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2725 early_dcx.early_fatal(format!("Current directory is invalid: {e}"));
2726 });
2727
2728 let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts);
2729 let working_dir = file_mapping.to_real_filename(&working_dir);
2730
2731 let verbose = matches.opt_present("verbose") || unstable_opts.verbose_internals;
2732
2733 Options {
2734 assert_incr_state,
2735 crate_types,
2736 optimize: opt_level,
2737 debuginfo,
2738 debuginfo_compression,
2739 lint_opts,
2740 lint_cap,
2741 describe_lints,
2742 output_types,
2743 search_paths,
2744 sysroot,
2745 target_triple,
2746 test,
2747 incremental,
2748 untracked_state_hash: Default::default(),
2749 unstable_opts,
2750 prints,
2751 cg,
2752 error_format,
2753 diagnostic_width,
2754 externs,
2755 unstable_features,
2756 crate_name,
2757 libs,
2758 debug_assertions,
2759 actually_rustdoc: false,
2760 resolve_doc_links: ResolveDocLinks::ExportedMetadata,
2761 trimmed_def_paths: false,
2762 cli_forced_codegen_units: codegen_units,
2763 cli_forced_local_thinlto_off: disable_local_thinlto,
2764 remap_path_prefix,
2765 real_rust_source_base_dir,
2766 edition,
2767 json_artifact_notifications,
2768 json_unused_externs,
2769 json_future_incompat,
2770 pretty,
2771 working_dir,
2772 color,
2773 logical_env,
2774 verbose,
2775 target_modifiers,
2776 }
2777}
2778
2779fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> Option<PpMode> {
2780 use PpMode::*;
2781
2782 let first = match unstable_opts.unpretty.as_deref()? {
2783 "normal" => Source(PpSourceMode::Normal),
2784 "identified" => Source(PpSourceMode::Identified),
2785 "expanded" => Source(PpSourceMode::Expanded),
2786 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2787 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2788 "ast-tree" => AstTree,
2789 "ast-tree,expanded" => AstTreeExpanded,
2790 "hir" => Hir(PpHirMode::Normal),
2791 "hir,identified" => Hir(PpHirMode::Identified),
2792 "hir,typed" => Hir(PpHirMode::Typed),
2793 "hir-tree" => HirTree,
2794 "thir-tree" => ThirTree,
2795 "thir-flat" => ThirFlat,
2796 "mir" => Mir,
2797 "stable-mir" => StableMir,
2798 "mir-cfg" => MirCFG,
2799 name => early_dcx.early_fatal(format!(
2800 "argument to `unpretty` must be one of `normal`, `identified`, \
2801 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2802 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2803 `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir`, `stable-mir`, or \
2804 `mir-cfg`; got {name}"
2805 )),
2806 };
2807 debug!("got unpretty option: {first:?}");
2808 Some(first)
2809}
2810
2811pub fn make_crate_type_option() -> RustcOptGroup {
2812 make_opt(
2813 OptionStability::Stable,
2814 OptionKind::Multi,
2815 "",
2816 "crate-type",
2817 "Comma separated list of types of crates
2818 for the compiler to emit",
2819 "<bin|lib|rlib|dylib|cdylib|staticlib|proc-macro>",
2820 )
2821}
2822
2823pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2824 let mut crate_types: Vec<CrateType> = Vec::new();
2825 for unparsed_crate_type in &list_list {
2826 for part in unparsed_crate_type.split(',') {
2827 let new_part = match part {
2828 "lib" => default_lib_output(),
2829 "rlib" => CrateType::Rlib,
2830 "staticlib" => CrateType::Staticlib,
2831 "dylib" => CrateType::Dylib,
2832 "cdylib" => CrateType::Cdylib,
2833 "bin" => CrateType::Executable,
2834 "proc-macro" => CrateType::ProcMacro,
2835 "sdylib" => CrateType::Sdylib,
2836 _ => {
2837 return Err(format!(
2838 "unknown crate type: `{part}`, expected one of: \
2839 `lib`, `rlib`, `staticlib`, `dylib`, `cdylib`, `bin`, `proc-macro`",
2840 ));
2841 }
2842 };
2843 if !crate_types.contains(&new_part) {
2844 crate_types.push(new_part)
2845 }
2846 }
2847 }
2848
2849 Ok(crate_types)
2850}
2851
2852pub mod nightly_options {
2853 use rustc_feature::UnstableFeatures;
2854
2855 use super::{OptionStability, RustcOptGroup};
2856 use crate::EarlyDiagCtxt;
2857
2858 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2859 match_is_nightly_build(matches)
2860 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2861 }
2862
2863 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2864 is_nightly_build(matches.opt_str("crate-name").as_deref())
2865 }
2866
2867 fn is_nightly_build(krate: Option<&str>) -> bool {
2868 UnstableFeatures::from_environment(krate).is_nightly_build()
2869 }
2870
2871 pub fn check_nightly_options(
2872 early_dcx: &EarlyDiagCtxt,
2873 matches: &getopts::Matches,
2874 flags: &[RustcOptGroup],
2875 ) {
2876 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2877 let really_allows_unstable_options = match_is_nightly_build(matches);
2878 let mut nightly_options_on_stable = 0;
2879
2880 for opt in flags.iter() {
2881 if opt.stability == OptionStability::Stable {
2882 continue;
2883 }
2884 if !matches.opt_present(opt.name) {
2885 continue;
2886 }
2887 if opt.name != "Z" && !has_z_unstable_option {
2888 early_dcx.early_fatal(format!(
2889 "the `-Z unstable-options` flag must also be passed to enable \
2890 the flag `{}`",
2891 opt.name
2892 ));
2893 }
2894 if really_allows_unstable_options {
2895 continue;
2896 }
2897 match opt.stability {
2898 OptionStability::Unstable => {
2899 nightly_options_on_stable += 1;
2900 let msg = format!(
2901 "the option `{}` is only accepted on the nightly compiler",
2902 opt.name
2903 );
2904 let _ = early_dcx.early_err(msg);
2906 }
2907 OptionStability::Stable => {}
2908 }
2909 }
2910 if nightly_options_on_stable > 0 {
2911 early_dcx
2912 .early_help("consider switching to a nightly toolchain: `rustup default nightly`");
2913 early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
2914 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>");
2915 early_dcx.early_fatal(format!(
2916 "{} nightly option{} were parsed",
2917 nightly_options_on_stable,
2918 if nightly_options_on_stable > 1 { "s" } else { "" }
2919 ));
2920 }
2921 }
2922}
2923
2924impl fmt::Display for CrateType {
2925 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2926 match *self {
2927 CrateType::Executable => "bin".fmt(f),
2928 CrateType::Dylib => "dylib".fmt(f),
2929 CrateType::Rlib => "rlib".fmt(f),
2930 CrateType::Staticlib => "staticlib".fmt(f),
2931 CrateType::Cdylib => "cdylib".fmt(f),
2932 CrateType::ProcMacro => "proc-macro".fmt(f),
2933 CrateType::Sdylib => "sdylib".fmt(f),
2934 }
2935 }
2936}
2937
2938impl IntoDiagArg for CrateType {
2939 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2940 self.to_string().into_diag_arg(&mut None)
2941 }
2942}
2943
2944#[derive(Copy, Clone, PartialEq, Debug)]
2945pub enum PpSourceMode {
2946 Normal,
2948 Expanded,
2950 Identified,
2952 ExpandedIdentified,
2954 ExpandedHygiene,
2956}
2957
2958#[derive(Copy, Clone, PartialEq, Debug)]
2959pub enum PpHirMode {
2960 Normal,
2962 Identified,
2964 Typed,
2966}
2967
2968#[derive(Copy, Clone, PartialEq, Debug)]
2969pub enum PpMode {
2971 Source(PpSourceMode),
2974 AstTree,
2976 AstTreeExpanded,
2978 Hir(PpHirMode),
2980 HirTree,
2982 ThirTree,
2984 ThirFlat,
2986 Mir,
2988 MirCFG,
2990 StableMir,
2992}
2993
2994impl PpMode {
2995 pub fn needs_ast_map(&self) -> bool {
2996 use PpMode::*;
2997 use PpSourceMode::*;
2998 match *self {
2999 Source(Normal | Identified) | AstTree => false,
3000
3001 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
3002 | AstTreeExpanded
3003 | Hir(_)
3004 | HirTree
3005 | ThirTree
3006 | ThirFlat
3007 | Mir
3008 | MirCFG
3009 | StableMir => true,
3010 }
3011 }
3012
3013 pub fn needs_analysis(&self) -> bool {
3014 use PpMode::*;
3015 matches!(*self, Hir(PpHirMode::Typed) | Mir | StableMir | MirCFG | ThirTree | ThirFlat)
3016 }
3017}
3018
3019#[derive(Clone, Hash, PartialEq, Eq, Debug)]
3020pub enum WasiExecModel {
3021 Command,
3022 Reactor,
3023}
3024
3025pub(crate) mod dep_tracking {
3044 use std::collections::BTreeMap;
3045 use std::hash::Hash;
3046 use std::num::NonZero;
3047 use std::path::PathBuf;
3048
3049 use rustc_abi::Align;
3050 use rustc_data_structures::fx::FxIndexMap;
3051 use rustc_data_structures::stable_hasher::StableHasher;
3052 use rustc_errors::LanguageIdentifier;
3053 use rustc_feature::UnstableFeatures;
3054 use rustc_hashes::Hash64;
3055 use rustc_span::RealFileName;
3056 use rustc_span::edition::Edition;
3057 use rustc_target::spec::{
3058 CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
3059 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple,
3060 TlsModel, WasmCAbi,
3061 };
3062
3063 use super::{
3064 AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
3065 CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
3066 InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
3067 LtoCli, MirStripDebugInfo, NextSolverConfig, OomStrategy, OptLevel, OutFileName,
3068 OutputType, OutputTypes, PatchableFunctionEntry, Polonius, RemapPathScopeComponents,
3069 ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
3070 SymbolManglingVersion, WasiExecModel,
3071 };
3072 use crate::lint;
3073 use crate::utils::NativeLib;
3074
3075 pub(crate) trait DepTrackingHash {
3076 fn hash(
3077 &self,
3078 hasher: &mut StableHasher,
3079 error_format: ErrorOutputType,
3080 for_crate_hash: bool,
3081 );
3082 }
3083
3084 macro_rules! impl_dep_tracking_hash_via_hash {
3085 ($($t:ty),+ $(,)?) => {$(
3086 impl DepTrackingHash for $t {
3087 fn hash(&self, hasher: &mut StableHasher, _: ErrorOutputType, _for_crate_hash: bool) {
3088 Hash::hash(self, hasher);
3089 }
3090 }
3091 )+};
3092 }
3093
3094 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
3095 fn hash(
3096 &self,
3097 hasher: &mut StableHasher,
3098 error_format: ErrorOutputType,
3099 for_crate_hash: bool,
3100 ) {
3101 match self {
3102 Some(x) => {
3103 Hash::hash(&1, hasher);
3104 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
3105 }
3106 None => Hash::hash(&0, hasher),
3107 }
3108 }
3109 }
3110
3111 impl_dep_tracking_hash_via_hash!(
3112 AutoDiff,
3113 bool,
3114 usize,
3115 NonZero<usize>,
3116 u64,
3117 Hash64,
3118 String,
3119 PathBuf,
3120 lint::Level,
3121 WasiExecModel,
3122 u32,
3123 FramePointer,
3124 RelocModel,
3125 CodeModel,
3126 TlsModel,
3127 InstrumentCoverage,
3128 CoverageOptions,
3129 InstrumentXRay,
3130 CrateType,
3131 MergeFunctions,
3132 OnBrokenPipe,
3133 PanicStrategy,
3134 RelroLevel,
3135 OptLevel,
3136 LtoCli,
3137 DebugInfo,
3138 DebugInfoCompression,
3139 MirStripDebugInfo,
3140 CollapseMacroDebuginfo,
3141 UnstableFeatures,
3142 NativeLib,
3143 SanitizerSet,
3144 CFGuard,
3145 CFProtection,
3146 TargetTuple,
3147 Edition,
3148 LinkerPluginLto,
3149 ResolveDocLinks,
3150 SplitDebuginfo,
3151 SplitDwarfKind,
3152 StackProtector,
3153 SwitchWithOptPath,
3154 SymbolManglingVersion,
3155 SymbolVisibility,
3156 RemapPathScopeComponents,
3157 SourceFileHashAlgorithm,
3158 OutFileName,
3159 OutputType,
3160 RealFileName,
3161 LocationDetail,
3162 FmtDebug,
3163 BranchProtection,
3164 OomStrategy,
3165 LanguageIdentifier,
3166 NextSolverConfig,
3167 PatchableFunctionEntry,
3168 Polonius,
3169 InliningThreshold,
3170 FunctionReturn,
3171 WasmCAbi,
3172 Align,
3173 );
3174
3175 impl<T1, T2> DepTrackingHash for (T1, T2)
3176 where
3177 T1: DepTrackingHash,
3178 T2: DepTrackingHash,
3179 {
3180 fn hash(
3181 &self,
3182 hasher: &mut StableHasher,
3183 error_format: ErrorOutputType,
3184 for_crate_hash: bool,
3185 ) {
3186 Hash::hash(&0, hasher);
3187 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3188 Hash::hash(&1, hasher);
3189 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3190 }
3191 }
3192
3193 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
3194 where
3195 T1: DepTrackingHash,
3196 T2: DepTrackingHash,
3197 T3: DepTrackingHash,
3198 {
3199 fn hash(
3200 &self,
3201 hasher: &mut StableHasher,
3202 error_format: ErrorOutputType,
3203 for_crate_hash: bool,
3204 ) {
3205 Hash::hash(&0, hasher);
3206 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3207 Hash::hash(&1, hasher);
3208 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3209 Hash::hash(&2, hasher);
3210 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
3211 }
3212 }
3213
3214 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
3215 fn hash(
3216 &self,
3217 hasher: &mut StableHasher,
3218 error_format: ErrorOutputType,
3219 for_crate_hash: bool,
3220 ) {
3221 Hash::hash(&self.len(), hasher);
3222 for (index, elem) in self.iter().enumerate() {
3223 Hash::hash(&index, hasher);
3224 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
3225 }
3226 }
3227 }
3228
3229 impl<T: DepTrackingHash, V: DepTrackingHash> DepTrackingHash for FxIndexMap<T, V> {
3230 fn hash(
3231 &self,
3232 hasher: &mut StableHasher,
3233 error_format: ErrorOutputType,
3234 for_crate_hash: bool,
3235 ) {
3236 Hash::hash(&self.len(), hasher);
3237 for (key, value) in self.iter() {
3238 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3239 DepTrackingHash::hash(value, hasher, error_format, for_crate_hash);
3240 }
3241 }
3242 }
3243
3244 impl DepTrackingHash for OutputTypes {
3245 fn hash(
3246 &self,
3247 hasher: &mut StableHasher,
3248 error_format: ErrorOutputType,
3249 for_crate_hash: bool,
3250 ) {
3251 Hash::hash(&self.0.len(), hasher);
3252 for (key, val) in &self.0 {
3253 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3254 if !for_crate_hash {
3255 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
3256 }
3257 }
3258 }
3259 }
3260
3261 pub(crate) fn stable_hash(
3263 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
3264 hasher: &mut StableHasher,
3265 error_format: ErrorOutputType,
3266 for_crate_hash: bool,
3267 ) {
3268 for (key, sub_hash) in sub_hashes {
3269 Hash::hash(&key.len(), hasher);
3272 Hash::hash(key, hasher);
3273 sub_hash.hash(hasher, error_format, for_crate_hash);
3274 }
3275 }
3276}
3277
3278#[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
3280pub enum OomStrategy {
3281 Panic,
3283
3284 Abort,
3286}
3287
3288impl OomStrategy {
3289 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
3290
3291 pub fn should_panic(self) -> u8 {
3292 match self {
3293 OomStrategy::Panic => 1,
3294 OomStrategy::Abort => 0,
3295 }
3296 }
3297}
3298
3299#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3301pub enum ProcMacroExecutionStrategy {
3302 SameThread,
3304
3305 CrossThread,
3307}
3308
3309#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3317pub enum CollapseMacroDebuginfo {
3318 No = 0,
3320 Unspecified = 1,
3322 External = 2,
3324 Yes = 3,
3326}
3327
3328#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3330pub enum DumpMonoStatsFormat {
3331 Markdown,
3333 Json,
3335}
3336
3337impl DumpMonoStatsFormat {
3338 pub fn extension(self) -> &'static str {
3339 match self {
3340 Self::Markdown => "md",
3341 Self::Json => "json",
3342 }
3343 }
3344}
3345
3346#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3349pub struct PatchableFunctionEntry {
3350 prefix: u8,
3352 entry: u8,
3354}
3355
3356impl PatchableFunctionEntry {
3357 pub fn from_total_and_prefix_nops(
3358 total_nops: u8,
3359 prefix_nops: u8,
3360 ) -> Option<PatchableFunctionEntry> {
3361 if total_nops < prefix_nops {
3362 None
3363 } else {
3364 Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops })
3365 }
3366 }
3367 pub fn prefix(&self) -> u8 {
3368 self.prefix
3369 }
3370 pub fn entry(&self) -> u8 {
3371 self.entry
3372 }
3373}
3374
3375#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3378pub enum Polonius {
3379 #[default]
3381 Off,
3382
3383 Legacy,
3385
3386 Next,
3388}
3389
3390impl Polonius {
3391 pub fn is_legacy_enabled(&self) -> bool {
3393 matches!(self, Polonius::Legacy)
3394 }
3395
3396 pub fn is_next_enabled(&self) -> bool {
3398 matches!(self, Polonius::Next)
3399 }
3400}
3401
3402#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3403pub enum InliningThreshold {
3404 Always,
3405 Sometimes(usize),
3406 Never,
3407}
3408
3409impl Default for InliningThreshold {
3410 fn default() -> Self {
3411 Self::Sometimes(100)
3412 }
3413}
3414
3415#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3417pub enum FunctionReturn {
3418 #[default]
3420 Keep,
3421
3422 ThunkExtern,
3424}
3425
3426#[derive(Clone, Copy, Default, PartialEq, Debug)]
3429pub enum MirIncludeSpans {
3430 Off,
3431 On,
3432 #[default]
3435 Nll,
3436}
3437
3438impl MirIncludeSpans {
3439 pub fn is_enabled(self) -> bool {
3444 self == MirIncludeSpans::On
3445 }
3446}