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