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