1#![allow(rustc::untranslatable_diagnostic)] use std::collections::btree_map::{
7 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
8};
9use std::collections::{BTreeMap, BTreeSet};
10use std::ffi::OsStr;
11use std::hash::Hash;
12use std::path::{Path, PathBuf};
13use std::str::{self, FromStr};
14use std::sync::LazyLock;
15use std::{cmp, fmt, fs, iter};
16
17use externs::{ExternOpt, split_extern_opt};
18use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
19use rustc_data_structures::stable_hasher::{StableHasher, StableOrd, ToStableHashKey};
20use rustc_errors::emitter::HumanReadableErrorType;
21use rustc_errors::{ColorConfig, DiagArgValue, DiagCtxtFlags, IntoDiagArg};
22use rustc_feature::UnstableFeatures;
23use rustc_hashes::Hash64;
24use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic};
25use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION};
26use rustc_span::source_map::FilePathMapping;
27use rustc_span::{FileName, RealFileName, SourceFileHashAlgorithm, Symbol, sym};
28use rustc_target::spec::{
29 FramePointer, LinkSelfContainedComponents, LinkerFeatures, PanicStrategy, SplitDebuginfo,
30 Target, TargetTuple,
31};
32use tracing::debug;
33
34pub use crate::config::cfg::{Cfg, CheckCfg, ExpectedValues};
35use crate::config::native_libs::parse_native_libs;
36pub use crate::config::print_request::{PrintKind, PrintRequest};
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;
46mod print_request;
47pub mod sigpipe;
48
49#[derive(Clone, Copy, PartialEq, Hash, Debug)]
51pub enum Strip {
52 None,
54
55 Debuginfo,
57
58 Symbols,
60}
61
62#[derive(Clone, Copy, PartialEq, Hash, Debug)]
64pub enum CFGuard {
65 Disabled,
67
68 NoChecks,
70
71 Checks,
73}
74
75#[derive(Clone, Copy, PartialEq, Hash, Debug)]
77pub enum CFProtection {
78 None,
80
81 Branch,
83
84 Return,
86
87 Full,
89}
90
91#[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
92pub enum OptLevel {
93 No,
95 Less,
97 More,
99 Aggressive,
101 Size,
103 SizeMin,
105}
106
107#[derive(Clone, PartialEq)]
112pub enum Lto {
113 No,
115
116 Thin,
118
119 ThinLocal,
122
123 Fat,
125}
126
127#[derive(Clone, Copy, PartialEq, Hash, Debug)]
129pub enum LtoCli {
130 No,
132 Yes,
134 NoParam,
136 Thin,
138 Fat,
140 Unspecified,
142}
143
144#[derive(Clone, Copy, PartialEq, Hash, Debug)]
146pub enum InstrumentCoverage {
147 No,
149 Yes,
151}
152
153#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
155pub struct CoverageOptions {
156 pub level: CoverageLevel,
157
158 pub discard_all_spans_in_codegen: bool,
164}
165
166#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
168pub enum CoverageLevel {
169 #[default]
171 Block,
172 Branch,
174 Condition,
190}
191
192#[derive(Clone, PartialEq, Hash, Debug)]
194pub enum Offload {
195 Device,
197 Host(String),
199 Test,
201}
202
203#[derive(Clone, PartialEq, Hash, Debug)]
205pub enum AutoDiff {
206 Enable,
208
209 PrintTA,
211 PrintTAFn(String),
213 PrintAA,
215 PrintPerf,
217 PrintSteps,
219 PrintModBefore,
221 PrintModAfter,
223 PrintModFinal,
225
226 PrintPasses,
228 NoPostopt,
230 LooseTypes,
233 Inline,
235 NoTT,
237}
238
239#[derive(Clone, Copy, PartialEq, Hash, Debug)]
241pub enum AnnotateMoves {
242 Disabled,
244 Enabled(Option<u64>),
247}
248
249#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
251pub struct InstrumentXRay {
252 pub always: bool,
254 pub never: bool,
256 pub ignore_loops: bool,
259 pub instruction_threshold: Option<usize>,
262 pub skip_entry: bool,
264 pub skip_exit: bool,
266}
267
268#[derive(Clone, PartialEq, Hash, Debug)]
269pub enum LinkerPluginLto {
270 LinkerPlugin(PathBuf),
271 LinkerPluginAuto,
272 Disabled,
273}
274
275impl LinkerPluginLto {
276 pub fn enabled(&self) -> bool {
277 match *self {
278 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
279 LinkerPluginLto::Disabled => false,
280 }
281 }
282}
283
284#[derive(Default, Clone, PartialEq, Debug)]
300pub struct LinkSelfContained {
301 pub explicitly_set: Option<bool>,
304
305 enabled_components: LinkSelfContainedComponents,
308
309 disabled_components: LinkSelfContainedComponents,
312}
313
314impl LinkSelfContained {
315 pub(crate) fn handle_cli_component(&mut self, component: &str) -> Option<()> {
318 if let Some(component_to_enable) = component.strip_prefix('+') {
323 self.explicitly_set = None;
324 self.enabled_components
325 .insert(LinkSelfContainedComponents::from_str(component_to_enable).ok()?);
326 Some(())
327 } else if let Some(component_to_disable) = component.strip_prefix('-') {
328 self.explicitly_set = None;
329 self.disabled_components
330 .insert(LinkSelfContainedComponents::from_str(component_to_disable).ok()?);
331 Some(())
332 } else {
333 None
334 }
335 }
336
337 pub(crate) fn set_all_explicitly(&mut self, enabled: bool) {
340 self.explicitly_set = Some(enabled);
341
342 if enabled {
343 self.enabled_components = LinkSelfContainedComponents::all();
344 self.disabled_components = LinkSelfContainedComponents::empty();
345 } else {
346 self.enabled_components = LinkSelfContainedComponents::empty();
347 self.disabled_components = LinkSelfContainedComponents::all();
348 }
349 }
350
351 pub fn on() -> Self {
353 let mut on = LinkSelfContained::default();
354 on.set_all_explicitly(true);
355 on
356 }
357
358 fn check_unstable_variants(&self, target_tuple: &TargetTuple) -> Result<(), String> {
362 if self.explicitly_set.is_some() {
363 return Ok(());
364 }
365
366 let has_minus_linker = self.disabled_components.is_linker_enabled();
368 if has_minus_linker && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
369 return Err(format!(
370 "`-C link-self-contained=-linker` is unstable on the `{target_tuple}` \
371 target. The `-Z unstable-options` flag must also be passed to use it on this target",
372 ));
373 }
374
375 let unstable_enabled = self.enabled_components;
377 let unstable_disabled = self.disabled_components - LinkSelfContainedComponents::LINKER;
378 if !unstable_enabled.union(unstable_disabled).is_empty() {
379 return Err(String::from(
380 "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` \
381 are stable, the `-Z unstable-options` flag must also be passed to use \
382 the unstable values",
383 ));
384 }
385
386 Ok(())
387 }
388
389 pub fn is_linker_enabled(&self) -> bool {
392 self.enabled_components.contains(LinkSelfContainedComponents::LINKER)
393 }
394
395 pub fn is_linker_disabled(&self) -> bool {
398 self.disabled_components.contains(LinkSelfContainedComponents::LINKER)
399 }
400
401 fn check_consistency(&self) -> Option<LinkSelfContainedComponents> {
404 if self.explicitly_set.is_some() {
405 None
406 } else {
407 let common = self.enabled_components.intersection(self.disabled_components);
408 if common.is_empty() { None } else { Some(common) }
409 }
410 }
411}
412
413#[derive(Default, Copy, Clone, PartialEq, Debug)]
422pub struct LinkerFeaturesCli {
423 pub enabled: LinkerFeatures,
425
426 pub disabled: LinkerFeatures,
428}
429
430impl LinkerFeaturesCli {
431 pub(crate) fn handle_cli_feature(&mut self, feature: &str) -> Option<()> {
434 match feature {
440 "+lld" => {
441 self.enabled.insert(LinkerFeatures::LLD);
442 self.disabled.remove(LinkerFeatures::LLD);
443 Some(())
444 }
445 "-lld" => {
446 self.disabled.insert(LinkerFeatures::LLD);
447 self.enabled.remove(LinkerFeatures::LLD);
448 Some(())
449 }
450 _ => None,
451 }
452 }
453
454 pub(crate) fn check_unstable_variants(&self, target_tuple: &TargetTuple) -> Result<(), String> {
459 let has_minus_lld = self.disabled.is_lld_enabled();
461 if has_minus_lld && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
462 return Err(format!(
463 "`-C linker-features=-lld` is unstable on the `{target_tuple}` \
464 target. The `-Z unstable-options` flag must also be passed to use it on this target",
465 ));
466 }
467
468 let unstable_enabled = self.enabled;
470 let unstable_disabled = self.disabled - LinkerFeatures::LLD;
471 if !unstable_enabled.union(unstable_disabled).is_empty() {
472 let unstable_features: Vec<_> = unstable_enabled
473 .iter()
474 .map(|f| format!("+{}", f.as_str().unwrap()))
475 .chain(unstable_disabled.iter().map(|f| format!("-{}", f.as_str().unwrap())))
476 .collect();
477 return Err(format!(
478 "`-C linker-features={}` is unstable, and also requires the \
479 `-Z unstable-options` flag to be used",
480 unstable_features.join(","),
481 ));
482 }
483
484 Ok(())
485 }
486}
487
488#[derive(Clone, Copy, PartialEq, Hash, Debug)]
490pub enum IncrementalStateAssertion {
491 Loaded,
496 NotLoaded,
498}
499
500#[derive(Copy, Clone, PartialEq, Hash, Debug)]
502pub struct LocationDetail {
503 pub file: bool,
504 pub line: bool,
505 pub column: bool,
506}
507
508impl LocationDetail {
509 pub(crate) fn all() -> Self {
510 Self { file: true, line: true, column: true }
511 }
512}
513
514#[derive(Copy, Clone, PartialEq, Hash, Debug)]
516pub enum FmtDebug {
517 Full,
519 Shallow,
521 None,
523}
524
525impl FmtDebug {
526 pub(crate) fn all() -> [Symbol; 3] {
527 [sym::full, sym::none, sym::shallow]
528 }
529}
530
531#[derive(Clone, PartialEq, Hash, Debug)]
532pub enum SwitchWithOptPath {
533 Enabled(Option<PathBuf>),
534 Disabled,
535}
536
537impl SwitchWithOptPath {
538 pub fn enabled(&self) -> bool {
539 match *self {
540 SwitchWithOptPath::Enabled(_) => true,
541 SwitchWithOptPath::Disabled => false,
542 }
543 }
544}
545
546#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
547#[derive(Encodable, BlobDecodable)]
548pub enum SymbolManglingVersion {
549 Legacy,
550 V0,
551 Hashed,
552}
553
554#[derive(Clone, Copy, Debug, PartialEq, Hash)]
555pub enum DebugInfo {
556 None,
557 LineDirectivesOnly,
558 LineTablesOnly,
559 Limited,
560 Full,
561}
562
563#[derive(Clone, Copy, Debug, PartialEq, Hash)]
564pub enum DebugInfoCompression {
565 None,
566 Zlib,
567 Zstd,
568}
569
570#[derive(Clone, Copy, Debug, PartialEq, Hash)]
571pub enum MirStripDebugInfo {
572 None,
573 LocalsInTinyFunctions,
574 AllLocals,
575}
576
577#[derive(Clone, Copy, Debug, PartialEq, Hash)]
587pub enum SplitDwarfKind {
588 Single,
591 Split,
594}
595
596impl FromStr for SplitDwarfKind {
597 type Err = ();
598
599 fn from_str(s: &str) -> Result<Self, ()> {
600 Ok(match s {
601 "single" => SplitDwarfKind::Single,
602 "split" => SplitDwarfKind::Split,
603 _ => return Err(()),
604 })
605 }
606}
607
608macro_rules! define_output_types {
609 (
610 $(
611 $(#[doc = $doc:expr])*
612 $Variant:ident => {
613 shorthand: $shorthand:expr,
614 extension: $extension:expr,
615 description: $description:expr,
616 default_filename: $default_filename:expr,
617 is_text: $is_text:expr,
618 compatible_with_cgus_and_single_output: $compatible:expr
619 }
620 ),* $(,)?
621 ) => {
622 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
623 #[derive(Encodable, Decodable)]
624 pub enum OutputType {
625 $(
626 $(#[doc = $doc])*
627 $Variant,
628 )*
629 }
630
631
632 impl StableOrd for OutputType {
633 const CAN_USE_UNSTABLE_SORT: bool = true;
634
635 const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
637 }
638
639 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
640 type KeyType = Self;
641
642 fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
643 *self
644 }
645 }
646
647
648 impl OutputType {
649 pub fn iter_all() -> impl Iterator<Item = OutputType> {
650 static ALL_VARIANTS: &[OutputType] = &[
651 $(
652 OutputType::$Variant,
653 )*
654 ];
655 ALL_VARIANTS.iter().copied()
656 }
657
658 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
659 match *self {
660 $(
661 OutputType::$Variant => $compatible,
662 )*
663 }
664 }
665
666 pub fn shorthand(&self) -> &'static str {
667 match *self {
668 $(
669 OutputType::$Variant => $shorthand,
670 )*
671 }
672 }
673
674 fn from_shorthand(shorthand: &str) -> Option<Self> {
675 match shorthand {
676 $(
677 s if s == $shorthand => Some(OutputType::$Variant),
678 )*
679 _ => None,
680 }
681 }
682
683 fn shorthands_display() -> String {
684 let shorthands = vec![
685 $(
686 format!("`{}`", $shorthand),
687 )*
688 ];
689 shorthands.join(", ")
690 }
691
692 pub fn extension(&self) -> &'static str {
693 match *self {
694 $(
695 OutputType::$Variant => $extension,
696 )*
697 }
698 }
699
700 pub fn is_text_output(&self) -> bool {
701 match *self {
702 $(
703 OutputType::$Variant => $is_text,
704 )*
705 }
706 }
707
708 pub fn description(&self) -> &'static str {
709 match *self {
710 $(
711 OutputType::$Variant => $description,
712 )*
713 }
714 }
715
716 pub fn default_filename(&self) -> &'static str {
717 match *self {
718 $(
719 OutputType::$Variant => $default_filename,
720 )*
721 }
722 }
723
724
725 }
726 }
727}
728
729define_output_types! {
730 Assembly => {
731 shorthand: "asm",
732 extension: "s",
733 description: "Generates a file with the crate's assembly code",
734 default_filename: "CRATE_NAME.s",
735 is_text: true,
736 compatible_with_cgus_and_single_output: false
737 },
738 #[doc = "This is the optimized bitcode, which could be either pre-LTO or non-LTO bitcode,"]
739 #[doc = "depending on the specific request type."]
740 Bitcode => {
741 shorthand: "llvm-bc",
742 extension: "bc",
743 description: "Generates a binary file containing the LLVM bitcode",
744 default_filename: "CRATE_NAME.bc",
745 is_text: false,
746 compatible_with_cgus_and_single_output: false
747 },
748 DepInfo => {
749 shorthand: "dep-info",
750 extension: "d",
751 description: "Generates a file with Makefile syntax that indicates all the source files that were loaded to generate the crate",
752 default_filename: "CRATE_NAME.d",
753 is_text: true,
754 compatible_with_cgus_and_single_output: true
755 },
756 Exe => {
757 shorthand: "link",
758 extension: "",
759 description: "Generates the crates specified by --crate-type. This is the default if --emit is not specified",
760 default_filename: "(platform and crate-type dependent)",
761 is_text: false,
762 compatible_with_cgus_and_single_output: true
763 },
764 LlvmAssembly => {
765 shorthand: "llvm-ir",
766 extension: "ll",
767 description: "Generates a file containing LLVM IR",
768 default_filename: "CRATE_NAME.ll",
769 is_text: true,
770 compatible_with_cgus_and_single_output: false
771 },
772 Metadata => {
773 shorthand: "metadata",
774 extension: "rmeta",
775 description: "Generates a file containing metadata about the crate",
776 default_filename: "libCRATE_NAME.rmeta",
777 is_text: false,
778 compatible_with_cgus_and_single_output: true
779 },
780 Mir => {
781 shorthand: "mir",
782 extension: "mir",
783 description: "Generates a file containing rustc's mid-level intermediate representation",
784 default_filename: "CRATE_NAME.mir",
785 is_text: true,
786 compatible_with_cgus_and_single_output: false
787 },
788 Object => {
789 shorthand: "obj",
790 extension: "o",
791 description: "Generates a native object file",
792 default_filename: "CRATE_NAME.o",
793 is_text: false,
794 compatible_with_cgus_and_single_output: false
795 },
796 #[doc = "This is the summary or index data part of the ThinLTO bitcode."]
797 ThinLinkBitcode => {
798 shorthand: "thin-link-bitcode",
799 extension: "indexing.o",
800 description: "Generates the ThinLTO summary as bitcode",
801 default_filename: "CRATE_NAME.indexing.o",
802 is_text: false,
803 compatible_with_cgus_and_single_output: false
804 },
805}
806
807#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
809pub enum ErrorOutputType {
810 #[default]
812 HumanReadable {
813 kind: HumanReadableErrorType = HumanReadableErrorType { short: false, unicode: false },
814 color_config: ColorConfig = ColorConfig::Auto,
815 },
816 Json {
818 pretty: bool,
820 json_rendered: HumanReadableErrorType,
823 color_config: ColorConfig,
824 },
825}
826
827#[derive(Clone, Hash, Debug)]
828pub enum ResolveDocLinks {
829 None,
831 ExportedMetadata,
833 Exported,
835 All,
837}
838
839#[derive(Clone, Debug, Hash, HashStable_Generic, Encodable, Decodable)]
844pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>);
845
846impl OutputTypes {
847 pub fn new(entries: &[(OutputType, Option<OutFileName>)]) -> OutputTypes {
848 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
849 }
850
851 pub(crate) fn get(&self, key: &OutputType) -> Option<&Option<OutFileName>> {
852 self.0.get(key)
853 }
854
855 pub fn contains_key(&self, key: &OutputType) -> bool {
856 self.0.contains_key(key)
857 }
858
859 pub fn contains_explicit_name(&self, key: &OutputType) -> bool {
861 matches!(self.0.get(key), Some(Some(..)))
862 }
863
864 pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> {
865 self.0.iter()
866 }
867
868 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<OutFileName>> {
869 self.0.keys()
870 }
871
872 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<OutFileName>> {
873 self.0.values()
874 }
875
876 pub fn len(&self) -> usize {
877 self.0.len()
878 }
879
880 pub fn should_codegen(&self) -> bool {
882 self.0.keys().any(|k| match *k {
883 OutputType::Bitcode
884 | OutputType::ThinLinkBitcode
885 | OutputType::Assembly
886 | OutputType::LlvmAssembly
887 | OutputType::Mir
888 | OutputType::Object
889 | OutputType::Exe => true,
890 OutputType::Metadata | OutputType::DepInfo => false,
891 })
892 }
893
894 pub fn should_link(&self) -> bool {
896 self.0.keys().any(|k| match *k {
897 OutputType::Bitcode
898 | OutputType::ThinLinkBitcode
899 | OutputType::Assembly
900 | OutputType::LlvmAssembly
901 | OutputType::Mir
902 | OutputType::Metadata
903 | OutputType::Object
904 | OutputType::DepInfo => false,
905 OutputType::Exe => true,
906 })
907 }
908}
909
910#[derive(Clone)]
914pub struct Externs(BTreeMap<String, ExternEntry>);
915
916#[derive(Clone, Debug)]
917pub struct ExternEntry {
918 pub location: ExternLocation,
919 pub is_private_dep: bool,
925 pub add_prelude: bool,
930 pub nounused_dep: bool,
935 pub force: bool,
941}
942
943#[derive(Clone, Debug)]
944pub enum ExternLocation {
945 FoundInLibrarySearchDirectories,
949 ExactPaths(BTreeSet<CanonicalizedPath>),
956}
957
958impl Externs {
959 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
961 Externs(data)
962 }
963
964 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
965 self.0.get(key)
966 }
967
968 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
969 self.0.iter()
970 }
971}
972
973impl ExternEntry {
974 fn new(location: ExternLocation) -> ExternEntry {
975 ExternEntry {
976 location,
977 is_private_dep: false,
978 add_prelude: false,
979 nounused_dep: false,
980 force: false,
981 }
982 }
983
984 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
985 match &self.location {
986 ExternLocation::ExactPaths(set) => Some(set.iter()),
987 _ => None,
988 }
989 }
990}
991
992#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]
993pub struct NextSolverConfig {
994 pub coherence: bool = true,
996 pub globally: bool = false,
999}
1000
1001#[derive(Clone)]
1002pub enum Input {
1003 File(PathBuf),
1005 Str {
1007 name: FileName,
1009 input: String,
1011 },
1012}
1013
1014impl Input {
1015 pub fn filestem(&self) -> &str {
1016 if let Input::File(ifile) = self {
1017 if let Some(name) = ifile.file_stem().and_then(OsStr::to_str) {
1020 return name;
1021 }
1022 }
1023 "rust_out"
1024 }
1025
1026 pub fn file_name(&self, session: &Session) -> FileName {
1027 match *self {
1028 Input::File(ref ifile) => FileName::Real(
1029 session
1030 .psess
1031 .source_map()
1032 .path_mapping()
1033 .to_real_filename(session.psess.source_map().working_dir(), ifile.as_path()),
1034 ),
1035 Input::Str { ref name, .. } => name.clone(),
1036 }
1037 }
1038
1039 pub fn opt_path(&self) -> Option<&Path> {
1040 match self {
1041 Input::File(file) => Some(file),
1042 Input::Str { name, .. } => match name {
1043 FileName::Real(real) => real.local_path(),
1044 FileName::CfgSpec(_) => None,
1045 FileName::Anon(_) => None,
1046 FileName::MacroExpansion(_) => None,
1047 FileName::ProcMacroSourceCode(_) => None,
1048 FileName::CliCrateAttr(_) => None,
1049 FileName::Custom(_) => None,
1050 FileName::DocTest(path, _) => Some(path),
1051 FileName::InlineAsm(_) => None,
1052 },
1053 }
1054 }
1055}
1056
1057#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq, Eq, Encodable, Decodable)]
1058pub enum OutFileName {
1059 Real(PathBuf),
1060 Stdout,
1061}
1062
1063impl OutFileName {
1064 pub fn parent(&self) -> Option<&Path> {
1065 match *self {
1066 OutFileName::Real(ref path) => path.parent(),
1067 OutFileName::Stdout => None,
1068 }
1069 }
1070
1071 pub fn filestem(&self) -> Option<&OsStr> {
1072 match *self {
1073 OutFileName::Real(ref path) => path.file_stem(),
1074 OutFileName::Stdout => Some(OsStr::new("stdout")),
1075 }
1076 }
1077
1078 pub fn is_stdout(&self) -> bool {
1079 match *self {
1080 OutFileName::Real(_) => false,
1081 OutFileName::Stdout => true,
1082 }
1083 }
1084
1085 pub fn is_tty(&self) -> bool {
1086 use std::io::IsTerminal;
1087 match *self {
1088 OutFileName::Real(_) => false,
1089 OutFileName::Stdout => std::io::stdout().is_terminal(),
1090 }
1091 }
1092
1093 pub fn as_path(&self) -> &Path {
1094 match *self {
1095 OutFileName::Real(ref path) => path.as_ref(),
1096 OutFileName::Stdout => Path::new("stdout"),
1097 }
1098 }
1099
1100 pub fn file_for_writing(
1106 &self,
1107 outputs: &OutputFilenames,
1108 flavor: OutputType,
1109 codegen_unit_name: &str,
1110 invocation_temp: Option<&str>,
1111 ) -> PathBuf {
1112 match *self {
1113 OutFileName::Real(ref path) => path.clone(),
1114 OutFileName::Stdout => {
1115 outputs.temp_path_for_cgu(flavor, codegen_unit_name, invocation_temp)
1116 }
1117 }
1118 }
1119
1120 pub fn overwrite(&self, content: &str, sess: &Session) {
1121 match self {
1122 OutFileName::Stdout => print!("{content}"),
1123 OutFileName::Real(path) => {
1124 if let Err(e) = fs::write(path, content) {
1125 sess.dcx().emit_fatal(FileWriteFail { path, err: e.to_string() });
1126 }
1127 }
1128 }
1129 }
1130}
1131
1132#[derive(Clone, Hash, Debug, HashStable_Generic, Encodable, Decodable)]
1133pub struct OutputFilenames {
1134 pub(crate) out_directory: PathBuf,
1135 crate_stem: String,
1137 filestem: String,
1139 pub single_output_file: Option<OutFileName>,
1140 temps_directory: Option<PathBuf>,
1141 explicit_dwo_out_directory: Option<PathBuf>,
1142 pub outputs: OutputTypes,
1143}
1144
1145pub const RLINK_EXT: &str = "rlink";
1146pub const RUST_CGU_EXT: &str = "rcgu";
1147pub const DWARF_OBJECT_EXT: &str = "dwo";
1148pub const MAX_FILENAME_LENGTH: usize = 143; fn maybe_strip_file_name(mut path: PathBuf) -> PathBuf {
1154 if path.file_name().map_or(0, |name| name.len()) > MAX_FILENAME_LENGTH {
1155 let filename = path.file_name().unwrap().to_string_lossy();
1156 let hash_len = 64 / 4; let hyphen_len = 1; let allowed_suffix = MAX_FILENAME_LENGTH.saturating_sub(hash_len + hyphen_len);
1161
1162 let stripped_bytes = filename.len().saturating_sub(allowed_suffix);
1164
1165 let split_at = filename.ceil_char_boundary(stripped_bytes);
1167
1168 let mut hasher = StableHasher::new();
1169 filename[..split_at].hash(&mut hasher);
1170 let hash = hasher.finish::<Hash64>();
1171
1172 path.set_file_name(format!("{:x}-{}", hash, &filename[split_at..]));
1173 }
1174 path
1175}
1176impl OutputFilenames {
1177 pub fn new(
1178 out_directory: PathBuf,
1179 out_crate_name: String,
1180 out_filestem: String,
1181 single_output_file: Option<OutFileName>,
1182 temps_directory: Option<PathBuf>,
1183 explicit_dwo_out_directory: Option<PathBuf>,
1184 extra: String,
1185 outputs: OutputTypes,
1186 ) -> Self {
1187 OutputFilenames {
1188 out_directory,
1189 single_output_file,
1190 temps_directory,
1191 explicit_dwo_out_directory,
1192 outputs,
1193 crate_stem: format!("{out_crate_name}{extra}"),
1194 filestem: format!("{out_filestem}{extra}"),
1195 }
1196 }
1197
1198 pub fn path(&self, flavor: OutputType) -> OutFileName {
1199 self.outputs
1200 .get(&flavor)
1201 .and_then(|p| p.to_owned())
1202 .or_else(|| self.single_output_file.clone())
1203 .unwrap_or_else(|| OutFileName::Real(self.output_path(flavor)))
1204 }
1205
1206 pub fn interface_path(&self) -> PathBuf {
1207 self.out_directory.join(format!("lib{}.rs", self.crate_stem))
1208 }
1209
1210 fn output_path(&self, flavor: OutputType) -> PathBuf {
1213 let extension = flavor.extension();
1214 match flavor {
1215 OutputType::Metadata => {
1216 self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension))
1217 }
1218 _ => self.with_directory_and_extension(&self.out_directory, extension),
1219 }
1220 }
1221
1222 pub fn temp_path_for_cgu(
1226 &self,
1227 flavor: OutputType,
1228 codegen_unit_name: &str,
1229 invocation_temp: Option<&str>,
1230 ) -> PathBuf {
1231 let extension = flavor.extension();
1232 self.temp_path_ext_for_cgu(extension, codegen_unit_name, invocation_temp)
1233 }
1234
1235 pub fn temp_path_dwo_for_cgu(
1237 &self,
1238 codegen_unit_name: &str,
1239 invocation_temp: Option<&str>,
1240 ) -> PathBuf {
1241 let p = self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp);
1242 if let Some(dwo_out) = &self.explicit_dwo_out_directory {
1243 let mut o = dwo_out.clone();
1244 o.push(p.file_name().unwrap());
1245 o
1246 } else {
1247 p
1248 }
1249 }
1250
1251 pub fn temp_path_ext_for_cgu(
1254 &self,
1255 ext: &str,
1256 codegen_unit_name: &str,
1257 invocation_temp: Option<&str>,
1258 ) -> PathBuf {
1259 let mut extension = codegen_unit_name.to_string();
1260
1261 if let Some(rng) = invocation_temp {
1263 extension.push('.');
1264 extension.push_str(rng);
1265 }
1266
1267 if !ext.is_empty() {
1270 extension.push('.');
1271 extension.push_str(RUST_CGU_EXT);
1272 extension.push('.');
1273 extension.push_str(ext);
1274 }
1275
1276 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
1277 maybe_strip_file_name(self.with_directory_and_extension(temps_directory, &extension))
1278 }
1279
1280 pub fn temp_path_for_diagnostic(&self, ext: &str) -> PathBuf {
1281 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
1282 self.with_directory_and_extension(temps_directory, &ext)
1283 }
1284
1285 pub fn with_extension(&self, extension: &str) -> PathBuf {
1286 self.with_directory_and_extension(&self.out_directory, extension)
1287 }
1288
1289 pub fn with_directory_and_extension(&self, directory: &Path, extension: &str) -> PathBuf {
1290 let mut path = directory.join(&self.filestem);
1291 path.set_extension(extension);
1292 path
1293 }
1294
1295 pub fn split_dwarf_path(
1298 &self,
1299 split_debuginfo_kind: SplitDebuginfo,
1300 split_dwarf_kind: SplitDwarfKind,
1301 cgu_name: &str,
1302 invocation_temp: Option<&str>,
1303 ) -> Option<PathBuf> {
1304 let obj_out = self.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp);
1305 let dwo_out = self.temp_path_dwo_for_cgu(cgu_name, invocation_temp);
1306 match (split_debuginfo_kind, split_dwarf_kind) {
1307 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
1308 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
1312 Some(obj_out)
1313 }
1314 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
1316 Some(dwo_out)
1317 }
1318 }
1319 }
1320}
1321
1322#[derive(Clone, Debug)]
1323pub struct Sysroot {
1324 pub explicit: Option<PathBuf>,
1325 pub default: PathBuf,
1326}
1327
1328impl Sysroot {
1329 pub fn new(explicit: Option<PathBuf>) -> Sysroot {
1330 Sysroot { explicit, default: filesearch::default_sysroot() }
1331 }
1332
1333 pub fn path(&self) -> &Path {
1335 self.explicit.as_deref().unwrap_or(&self.default)
1336 }
1337
1338 pub fn all_paths(&self) -> impl Iterator<Item = &Path> {
1340 self.explicit.as_deref().into_iter().chain(iter::once(&*self.default))
1341 }
1342}
1343
1344pub fn host_tuple() -> &'static str {
1345 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
1354}
1355
1356fn file_path_mapping(
1357 remap_path_prefix: Vec<(PathBuf, PathBuf)>,
1358 unstable_opts: &UnstableOptions,
1359) -> FilePathMapping {
1360 FilePathMapping::new(remap_path_prefix.clone(), unstable_opts.remap_path_scope)
1361}
1362
1363impl Default for Options {
1364 fn default() -> Options {
1365 let unstable_opts = UnstableOptions::default();
1366
1367 let working_dir = {
1371 let working_dir = std::env::current_dir().unwrap();
1372 let file_mapping = file_path_mapping(Vec::new(), &unstable_opts);
1373 file_mapping.to_real_filename(&RealFileName::empty(), &working_dir)
1374 };
1375
1376 Options {
1377 assert_incr_state: None,
1378 crate_types: Vec::new(),
1379 optimize: OptLevel::No,
1380 debuginfo: DebugInfo::None,
1381 lint_opts: Vec::new(),
1382 lint_cap: None,
1383 describe_lints: false,
1384 output_types: OutputTypes(BTreeMap::new()),
1385 search_paths: vec![],
1386 sysroot: Sysroot::new(None),
1387 target_triple: TargetTuple::from_tuple(host_tuple()),
1388 test: false,
1389 incremental: None,
1390 untracked_state_hash: Default::default(),
1391 unstable_opts,
1392 prints: Vec::new(),
1393 cg: Default::default(),
1394 error_format: ErrorOutputType::default(),
1395 diagnostic_width: None,
1396 externs: Externs(BTreeMap::new()),
1397 crate_name: None,
1398 libs: Vec::new(),
1399 unstable_features: UnstableFeatures::Disallow,
1400 debug_assertions: true,
1401 actually_rustdoc: false,
1402 resolve_doc_links: ResolveDocLinks::None,
1403 trimmed_def_paths: false,
1404 cli_forced_codegen_units: None,
1405 cli_forced_local_thinlto_off: false,
1406 remap_path_prefix: Vec::new(),
1407 real_rust_source_base_dir: None,
1408 real_rustc_dev_source_base_dir: None,
1409 edition: DEFAULT_EDITION,
1410 json_artifact_notifications: false,
1411 json_timings: false,
1412 json_unused_externs: JsonUnusedExterns::No,
1413 json_future_incompat: false,
1414 pretty: None,
1415 working_dir,
1416 color: ColorConfig::Auto,
1417 logical_env: FxIndexMap::default(),
1418 verbose: false,
1419 target_modifiers: BTreeMap::default(),
1420 }
1421 }
1422}
1423
1424impl Options {
1425 pub fn build_dep_graph(&self) -> bool {
1427 self.incremental.is_some()
1428 || self.unstable_opts.dump_dep_graph
1429 || self.unstable_opts.query_dep_graph
1430 }
1431
1432 pub fn file_path_mapping(&self) -> FilePathMapping {
1433 file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts)
1434 }
1435
1436 pub fn will_create_output_file(&self) -> bool {
1438 !self.unstable_opts.parse_crate_root_only && self.unstable_opts.ls.is_empty() }
1441
1442 #[inline]
1443 pub fn share_generics(&self) -> bool {
1444 match self.unstable_opts.share_generics {
1445 Some(setting) => setting,
1446 None => match self.optimize {
1447 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
1448 OptLevel::More | OptLevel::Aggressive => false,
1449 },
1450 }
1451 }
1452
1453 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
1454 self.cg.symbol_mangling_version.unwrap_or(if self.unstable_features.is_nightly_build() {
1455 SymbolManglingVersion::V0
1456 } else {
1457 SymbolManglingVersion::Legacy
1458 })
1459 }
1460
1461 #[inline]
1462 pub fn autodiff_enabled(&self) -> bool {
1463 self.unstable_opts.autodiff.contains(&AutoDiff::Enable)
1464 }
1465}
1466
1467impl UnstableOptions {
1468 pub fn dcx_flags(&self, can_emit_warnings: bool) -> DiagCtxtFlags {
1469 DiagCtxtFlags {
1470 can_emit_warnings,
1471 treat_err_as_bug: self.treat_err_as_bug,
1472 eagerly_emit_delayed_bugs: self.eagerly_emit_delayed_bugs,
1473 macro_backtrace: self.macro_backtrace,
1474 deduplicate_diagnostics: self.deduplicate_diagnostics,
1475 track_diagnostics: self.track_diagnostics,
1476 }
1477 }
1478
1479 pub fn src_hash_algorithm(&self, target: &Target) -> SourceFileHashAlgorithm {
1480 self.src_hash_algorithm.unwrap_or_else(|| {
1481 if target.is_like_msvc {
1482 SourceFileHashAlgorithm::Sha256
1483 } else {
1484 SourceFileHashAlgorithm::Md5
1485 }
1486 })
1487 }
1488
1489 pub fn checksum_hash_algorithm(&self) -> Option<SourceFileHashAlgorithm> {
1490 self.checksum_hash_algorithm
1491 }
1492}
1493
1494#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
1496pub enum EntryFnType {
1497 Main {
1498 sigpipe: u8,
1505 },
1506}
1507
1508#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, BlobDecodable)]
1509#[derive(HashStable_Generic)]
1510pub enum CrateType {
1511 Executable,
1512 Dylib,
1513 Rlib,
1514 Staticlib,
1515 Cdylib,
1516 ProcMacro,
1517 Sdylib,
1518}
1519
1520impl CrateType {
1521 pub fn has_metadata(self) -> bool {
1522 match self {
1523 CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
1524 CrateType::Executable
1525 | CrateType::Cdylib
1526 | CrateType::Staticlib
1527 | CrateType::Sdylib => false,
1528 }
1529 }
1530}
1531
1532#[derive(Clone, Hash, Debug, PartialEq, Eq)]
1533pub enum Passes {
1534 Some(Vec<String>),
1535 All,
1536}
1537
1538impl Passes {
1539 fn is_empty(&self) -> bool {
1540 match *self {
1541 Passes::Some(ref v) => v.is_empty(),
1542 Passes::All => false,
1543 }
1544 }
1545
1546 pub(crate) fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
1547 match *self {
1548 Passes::Some(ref mut v) => v.extend(passes),
1549 Passes::All => {}
1550 }
1551 }
1552}
1553
1554#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1555pub enum PAuthKey {
1556 A,
1557 B,
1558}
1559
1560#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1561pub struct PacRet {
1562 pub leaf: bool,
1563 pub pc: bool,
1564 pub key: PAuthKey,
1565}
1566
1567#[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
1568pub struct BranchProtection {
1569 pub bti: bool,
1570 pub pac_ret: Option<PacRet>,
1571 pub gcs: bool,
1572}
1573
1574pub(crate) const fn default_lib_output() -> CrateType {
1575 CrateType::Rlib
1576}
1577
1578pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
1579 cfg::disallow_cfgs(sess, &user_cfg);
1581
1582 user_cfg.extend(cfg::default_configuration(sess));
1585 user_cfg
1586}
1587
1588pub fn build_target_config(
1589 early_dcx: &EarlyDiagCtxt,
1590 target: &TargetTuple,
1591 sysroot: &Path,
1592) -> Target {
1593 match Target::search(target, sysroot) {
1594 Ok((target, warnings)) => {
1595 for warning in warnings.warning_messages() {
1596 early_dcx.early_warn(warning)
1597 }
1598
1599 if !matches!(target.pointer_width, 16 | 32 | 64) {
1600 early_dcx.early_fatal(format!(
1601 "target specification was invalid: unrecognized target-pointer-width {}",
1602 target.pointer_width
1603 ))
1604 }
1605 target
1606 }
1607 Err(e) => {
1608 let mut err =
1609 early_dcx.early_struct_fatal(format!("error loading target specification: {e}"));
1610 err.help("run `rustc --print target-list` for a list of built-in targets");
1611 err.emit();
1612 }
1613 }
1614}
1615
1616#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1617pub enum OptionStability {
1618 Stable,
1619 Unstable,
1620}
1621
1622#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1623pub enum OptionKind {
1624 Opt,
1628
1629 Multi,
1633
1634 Flag,
1639
1640 FlagMulti,
1645}
1646
1647pub struct RustcOptGroup {
1648 pub name: &'static str,
1656 stability: OptionStability,
1657 kind: OptionKind,
1658
1659 short_name: &'static str,
1660 long_name: &'static str,
1661 desc: &'static str,
1662 value_hint: &'static str,
1663
1664 pub is_verbose_help_only: bool,
1667}
1668
1669impl RustcOptGroup {
1670 pub fn is_stable(&self) -> bool {
1671 self.stability == OptionStability::Stable
1672 }
1673
1674 pub fn apply(&self, options: &mut getopts::Options) {
1675 let &Self { short_name, long_name, desc, value_hint, .. } = self;
1676 match self.kind {
1677 OptionKind::Opt => options.optopt(short_name, long_name, desc, value_hint),
1678 OptionKind::Multi => options.optmulti(short_name, long_name, desc, value_hint),
1679 OptionKind::Flag => options.optflag(short_name, long_name, desc),
1680 OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
1681 };
1682 }
1683
1684 pub fn long_name(&self) -> &str {
1686 self.long_name
1687 }
1688}
1689
1690pub fn make_opt(
1691 stability: OptionStability,
1692 kind: OptionKind,
1693 short_name: &'static str,
1694 long_name: &'static str,
1695 desc: &'static str,
1696 value_hint: &'static str,
1697) -> RustcOptGroup {
1698 match kind {
1700 OptionKind::Opt | OptionKind::Multi => {}
1701 OptionKind::Flag | OptionKind::FlagMulti => assert_eq!(value_hint, ""),
1702 }
1703 RustcOptGroup {
1704 name: cmp::max_by_key(short_name, long_name, |s| s.len()),
1705 stability,
1706 kind,
1707 short_name,
1708 long_name,
1709 desc,
1710 value_hint,
1711 is_verbose_help_only: false,
1712 }
1713}
1714
1715static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
1716 format!(
1717 "Specify which edition of the compiler to use when compiling code. \
1718The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
1719 )
1720});
1721
1722static EMIT_HELP: LazyLock<String> = LazyLock::new(|| {
1723 let mut result =
1724 String::from("Comma separated list of types of output for the compiler to emit.\n");
1725 result.push_str("Each TYPE has the default FILE name:\n");
1726
1727 for output in OutputType::iter_all() {
1728 result.push_str(&format!("* {} - {}\n", output.shorthand(), output.default_filename()));
1729 }
1730
1731 result
1732});
1733
1734pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1744 use OptionKind::{Flag, FlagMulti, Multi, Opt};
1745 use OptionStability::{Stable, Unstable};
1746
1747 use self::make_opt as opt;
1748
1749 let mut options = vec![
1750 opt(Stable, Flag, "h", "help", "Display this message", ""),
1751 opt(
1752 Stable,
1753 Multi,
1754 "",
1755 "cfg",
1756 "Configure the compilation environment.\n\
1757 SPEC supports the syntax `<NAME>[=\"<VALUE>\"]`.",
1758 "<SPEC>",
1759 ),
1760 opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "<SPEC>"),
1761 opt(
1762 Stable,
1763 Multi,
1764 "L",
1765 "",
1766 "Add a directory to the library search path. \
1767 The optional KIND can be one of <dependency|crate|native|framework|all> (default: all).",
1768 "[<KIND>=]<PATH>",
1769 ),
1770 opt(
1771 Stable,
1772 Multi,
1773 "l",
1774 "",
1775 "Link the generated crate(s) to the specified native\n\
1776 library NAME. The optional KIND can be one of\n\
1777 <static|framework|dylib> (default: dylib).\n\
1778 Optional comma separated MODIFIERS\n\
1779 <bundle|verbatim|whole-archive|as-needed>\n\
1780 may be specified each with a prefix of either '+' to\n\
1781 enable or '-' to disable.",
1782 "[<KIND>[:<MODIFIERS>]=]<NAME>[:<RENAME>]",
1783 ),
1784 make_crate_type_option(),
1785 opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "<NAME>"),
1786 opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST),
1787 opt(Stable, Multi, "", "emit", &EMIT_HELP, "<TYPE>[=<FILE>]"),
1788 opt(Stable, Multi, "", "print", &print_request::PRINT_HELP, "<INFO>[=<FILE>]"),
1789 opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""),
1790 opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""),
1791 opt(Stable, Opt, "o", "", "Write output to FILENAME", "<FILENAME>"),
1792 opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in DIR", "<DIR>"),
1793 opt(
1794 Stable,
1795 Opt,
1796 "",
1797 "explain",
1798 "Provide a detailed explanation of an error message",
1799 "<OPT>",
1800 ),
1801 opt(Stable, Flag, "", "test", "Build a test harness", ""),
1802 opt(Stable, Opt, "", "target", "Target tuple for which the code is compiled", "<TARGET>"),
1803 opt(Stable, Multi, "A", "allow", "Set lint allowed", "<LINT>"),
1804 opt(Stable, Multi, "W", "warn", "Set lint warnings", "<LINT>"),
1805 opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "<LINT>"),
1806 opt(Stable, Multi, "D", "deny", "Set lint denied", "<LINT>"),
1807 opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "<LINT>"),
1808 opt(
1809 Stable,
1810 Multi,
1811 "",
1812 "cap-lints",
1813 "Set the most restrictive lint level. More restrictive lints are capped at this level",
1814 "<LEVEL>",
1815 ),
1816 opt(Stable, Multi, "C", "codegen", "Set a codegen option", "<OPT>[=<VALUE>]"),
1817 opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
1818 opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
1819 ];
1820
1821 let verbose_only = [
1824 opt(
1825 Stable,
1826 Multi,
1827 "",
1828 "extern",
1829 "Specify where an external rust library is located",
1830 "<NAME>[=<PATH>]",
1831 ),
1832 opt(Stable, Opt, "", "sysroot", "Override the system root", "<PATH>"),
1833 opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "<FLAG>"),
1834 opt(
1835 Stable,
1836 Opt,
1837 "",
1838 "error-format",
1839 "How errors and other messages are produced",
1840 "<human|json|short>",
1841 ),
1842 opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "<CONFIG>"),
1843 opt(
1844 Stable,
1845 Opt,
1846 "",
1847 "color",
1848 "Configure coloring of output:
1849 * auto = colorize, if output goes to a tty (default);
1850 * always = always colorize output;
1851 * never = never colorize output",
1852 "<auto|always|never>",
1853 ),
1854 opt(
1855 Stable,
1856 Opt,
1857 "",
1858 "diagnostic-width",
1859 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1860 "<WIDTH>",
1861 ),
1862 opt(
1863 Stable,
1864 Multi,
1865 "",
1866 "remap-path-prefix",
1867 "Remap source names in all output (compiler messages and output files)",
1868 "<FROM>=<TO>",
1869 ),
1870 opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "<VAR>=<VALUE>"),
1871 ];
1872 options.extend(verbose_only.into_iter().map(|mut opt| {
1873 opt.is_verbose_help_only = true;
1874 opt
1875 }));
1876
1877 options
1878}
1879
1880pub fn get_cmd_lint_options(
1881 early_dcx: &EarlyDiagCtxt,
1882 matches: &getopts::Matches,
1883) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1884 let mut lint_opts_with_position = vec![];
1885 let mut describe_lints = false;
1886
1887 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1888 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1889 if lint_name == "help" {
1890 describe_lints = true;
1891 } else {
1892 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1893 }
1894 }
1895 }
1896
1897 lint_opts_with_position.sort_by_key(|x| x.0);
1898 let lint_opts = lint_opts_with_position
1899 .iter()
1900 .cloned()
1901 .map(|(_, lint_name, level)| (lint_name, level))
1902 .collect();
1903
1904 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1905 lint::Level::from_str(&cap)
1906 .unwrap_or_else(|| early_dcx.early_fatal(format!("unknown lint level: `{cap}`")))
1907 });
1908
1909 (lint_opts, describe_lints, lint_cap)
1910}
1911
1912pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> ColorConfig {
1914 match matches.opt_str("color").as_deref() {
1915 Some("auto") => ColorConfig::Auto,
1916 Some("always") => ColorConfig::Always,
1917 Some("never") => ColorConfig::Never,
1918
1919 None => ColorConfig::Auto,
1920
1921 Some(arg) => early_dcx.early_fatal(format!(
1922 "argument for `--color` must be auto, \
1923 always or never (instead was `{arg}`)"
1924 )),
1925 }
1926}
1927
1928pub struct JsonConfig {
1930 pub json_rendered: HumanReadableErrorType,
1931 pub json_color: ColorConfig,
1932 json_artifact_notifications: bool,
1933 json_timings: bool,
1936 pub json_unused_externs: JsonUnusedExterns,
1937 json_future_incompat: bool,
1938}
1939
1940#[derive(Copy, Clone)]
1942pub enum JsonUnusedExterns {
1943 No,
1945 Silent,
1947 Loud,
1949}
1950
1951impl JsonUnusedExterns {
1952 pub fn is_enabled(&self) -> bool {
1953 match self {
1954 JsonUnusedExterns::No => false,
1955 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1956 }
1957 }
1958
1959 pub fn is_loud(&self) -> bool {
1960 match self {
1961 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1962 JsonUnusedExterns::Loud => true,
1963 }
1964 }
1965}
1966
1967pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
1972 let mut json_rendered = HumanReadableErrorType { short: false, unicode: false };
1973 let mut json_color = ColorConfig::Never;
1974 let mut json_artifact_notifications = false;
1975 let mut json_unused_externs = JsonUnusedExterns::No;
1976 let mut json_future_incompat = false;
1977 let mut json_timings = false;
1978 for option in matches.opt_strs("json") {
1979 if matches.opt_str("color").is_some() {
1983 early_dcx.early_fatal("cannot specify the `--color` option with `--json`");
1984 }
1985
1986 for sub_option in option.split(',') {
1987 match sub_option {
1988 "diagnostic-short" => {
1989 json_rendered = HumanReadableErrorType { short: true, unicode: false };
1990 }
1991 "diagnostic-unicode" => {
1992 json_rendered = HumanReadableErrorType { short: false, unicode: true };
1993 }
1994 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1995 "artifacts" => json_artifact_notifications = true,
1996 "timings" => json_timings = true,
1997 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1998 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1999 "future-incompat" => json_future_incompat = true,
2000 s => early_dcx.early_fatal(format!("unknown `--json` option `{s}`")),
2001 }
2002 }
2003 }
2004
2005 JsonConfig {
2006 json_rendered,
2007 json_color,
2008 json_artifact_notifications,
2009 json_timings,
2010 json_unused_externs,
2011 json_future_incompat,
2012 }
2013}
2014
2015pub fn parse_error_format(
2017 early_dcx: &mut EarlyDiagCtxt,
2018 matches: &getopts::Matches,
2019 color_config: ColorConfig,
2020 json_color: ColorConfig,
2021 json_rendered: HumanReadableErrorType,
2022) -> ErrorOutputType {
2023 let default_kind = HumanReadableErrorType { short: false, unicode: false };
2024 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
2029 match matches.opt_str("error-format").as_deref() {
2030 None | Some("human") => {
2031 ErrorOutputType::HumanReadable { color_config, kind: default_kind }
2032 }
2033 Some("json") => {
2034 ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
2035 }
2036 Some("pretty-json") => {
2037 ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
2038 }
2039 Some("short") => ErrorOutputType::HumanReadable {
2040 kind: HumanReadableErrorType { short: true, unicode: false },
2041 color_config,
2042 },
2043 Some("human-unicode") => ErrorOutputType::HumanReadable {
2044 kind: HumanReadableErrorType { short: false, unicode: true },
2045 color_config,
2046 },
2047 Some(arg) => {
2048 early_dcx.set_error_format(ErrorOutputType::HumanReadable {
2049 color_config,
2050 kind: default_kind,
2051 });
2052 early_dcx.early_fatal(format!(
2053 "argument for `--error-format` must be `human`, `human-unicode`, \
2054 `json`, `pretty-json` or `short` (instead was `{arg}`)"
2055 ))
2056 }
2057 }
2058 } else {
2059 ErrorOutputType::HumanReadable { color_config, kind: default_kind }
2060 };
2061
2062 match error_format {
2063 ErrorOutputType::Json { .. } => {}
2064
2065 _ if !matches.opt_strs("json").is_empty() => {
2069 early_dcx.early_fatal("using `--json` requires also using `--error-format=json`");
2070 }
2071
2072 _ => {}
2073 }
2074
2075 error_format
2076}
2077
2078pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Edition {
2079 let edition = match matches.opt_str("edition") {
2080 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
2081 early_dcx.early_fatal(format!(
2082 "argument for `--edition` must be one of: \
2083 {EDITION_NAME_LIST}. (instead was `{arg}`)"
2084 ))
2085 }),
2086 None => DEFAULT_EDITION,
2087 };
2088
2089 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
2090 let is_nightly = nightly_options::match_is_nightly_build(matches);
2091 let msg = if !is_nightly {
2092 format!(
2093 "the crate requires edition {edition}, but the latest edition supported by this Rust version is {LATEST_STABLE_EDITION}"
2094 )
2095 } else {
2096 format!("edition {edition} is unstable and only available with -Z unstable-options")
2097 };
2098 early_dcx.early_fatal(msg)
2099 }
2100
2101 edition
2102}
2103
2104fn check_error_format_stability(
2105 early_dcx: &EarlyDiagCtxt,
2106 unstable_opts: &UnstableOptions,
2107 is_nightly_build: bool,
2108 format: ErrorOutputType,
2109) {
2110 if unstable_opts.unstable_options || is_nightly_build {
2111 return;
2112 }
2113 let format = match format {
2114 ErrorOutputType::Json { pretty: true, .. } => "pretty-json",
2115 ErrorOutputType::HumanReadable { kind, .. } => match kind {
2116 HumanReadableErrorType { unicode: true, .. } => "human-unicode",
2117 _ => return,
2118 },
2119 _ => return,
2120 };
2121 early_dcx.early_fatal(format!("`--error-format={format}` is unstable"))
2122}
2123
2124fn parse_output_types(
2125 early_dcx: &EarlyDiagCtxt,
2126 unstable_opts: &UnstableOptions,
2127 matches: &getopts::Matches,
2128) -> OutputTypes {
2129 let mut output_types = BTreeMap::new();
2130 if !unstable_opts.parse_crate_root_only {
2131 for list in matches.opt_strs("emit") {
2132 for output_type in list.split(',') {
2133 let (shorthand, path) = split_out_file_name(output_type);
2134 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
2135 early_dcx.early_fatal(format!(
2136 "unknown emission type: `{shorthand}` - expected one of: {display}",
2137 display = OutputType::shorthands_display(),
2138 ))
2139 });
2140 if output_type == OutputType::ThinLinkBitcode && !unstable_opts.unstable_options {
2141 early_dcx.early_fatal(format!(
2142 "{} requested but -Zunstable-options not specified",
2143 OutputType::ThinLinkBitcode.shorthand()
2144 ));
2145 }
2146 output_types.insert(output_type, path);
2147 }
2148 }
2149 };
2150 if output_types.is_empty() {
2151 output_types.insert(OutputType::Exe, None);
2152 }
2153 OutputTypes(output_types)
2154}
2155
2156fn split_out_file_name(arg: &str) -> (&str, Option<OutFileName>) {
2157 match arg.split_once('=') {
2158 None => (arg, None),
2159 Some((kind, "-")) => (kind, Some(OutFileName::Stdout)),
2160 Some((kind, path)) => (kind, Some(OutFileName::Real(PathBuf::from(path)))),
2161 }
2162}
2163
2164fn should_override_cgus_and_disable_thinlto(
2165 early_dcx: &EarlyDiagCtxt,
2166 output_types: &OutputTypes,
2167 matches: &getopts::Matches,
2168 mut codegen_units: Option<usize>,
2169) -> (bool, Option<usize>) {
2170 let mut disable_local_thinlto = false;
2171 let incompatible: Vec<_> = output_types
2174 .0
2175 .iter()
2176 .map(|ot_path| ot_path.0)
2177 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2178 .map(|ot| ot.shorthand())
2179 .collect();
2180 if !incompatible.is_empty() {
2181 match codegen_units {
2182 Some(n) if n > 1 => {
2183 if matches.opt_present("o") {
2184 for ot in &incompatible {
2185 early_dcx.early_warn(format!(
2186 "`--emit={ot}` with `-o` incompatible with \
2187 `-C codegen-units=N` for N > 1",
2188 ));
2189 }
2190 early_dcx.early_warn("resetting to default -C codegen-units=1");
2191 codegen_units = Some(1);
2192 disable_local_thinlto = true;
2193 }
2194 }
2195 _ => {
2196 codegen_units = Some(1);
2197 disable_local_thinlto = true;
2198 }
2199 }
2200 }
2201
2202 if codegen_units == Some(0) {
2203 early_dcx.early_fatal("value for codegen units must be a positive non-zero integer");
2204 }
2205
2206 (disable_local_thinlto, codegen_units)
2207}
2208
2209pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTuple {
2210 match matches.opt_str("target") {
2211 Some(target) if target.ends_with(".json") => {
2212 let path = Path::new(&target);
2213 TargetTuple::from_path(path).unwrap_or_else(|_| {
2214 early_dcx.early_fatal(format!("target file {path:?} does not exist"))
2215 })
2216 }
2217 Some(target) => TargetTuple::TargetTuple(target),
2218 _ => TargetTuple::from_tuple(host_tuple()),
2219 }
2220}
2221
2222fn parse_opt_level(
2223 early_dcx: &EarlyDiagCtxt,
2224 matches: &getopts::Matches,
2225 cg: &CodegenOptions,
2226) -> OptLevel {
2227 let max_o = matches.opt_positions("O").into_iter().max();
2234 let max_c = matches
2235 .opt_strs_pos("C")
2236 .into_iter()
2237 .flat_map(|(i, s)| {
2238 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
2240 })
2241 .max();
2242 if max_o > max_c {
2243 OptLevel::Aggressive
2244 } else {
2245 match cg.opt_level.as_ref() {
2246 "0" => OptLevel::No,
2247 "1" => OptLevel::Less,
2248 "2" => OptLevel::More,
2249 "3" => OptLevel::Aggressive,
2250 "s" => OptLevel::Size,
2251 "z" => OptLevel::SizeMin,
2252 arg => {
2253 early_dcx.early_fatal(format!(
2254 "optimization level needs to be \
2255 between 0-3, s or z (instead was `{arg}`)"
2256 ));
2257 }
2258 }
2259 }
2260}
2261
2262fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInfo {
2263 let max_g = matches.opt_positions("g").into_iter().max();
2264 let max_c = matches
2265 .opt_strs_pos("C")
2266 .into_iter()
2267 .flat_map(|(i, s)| {
2268 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
2270 })
2271 .max();
2272 if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
2273}
2274
2275fn parse_assert_incr_state(
2276 early_dcx: &EarlyDiagCtxt,
2277 opt_assertion: &Option<String>,
2278) -> Option<IncrementalStateAssertion> {
2279 match opt_assertion {
2280 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
2281 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
2282 Some(s) => {
2283 early_dcx.early_fatal(format!("unexpected incremental state assertion value: {s}"))
2284 }
2285 None => None,
2286 }
2287}
2288
2289pub fn parse_externs(
2290 early_dcx: &EarlyDiagCtxt,
2291 matches: &getopts::Matches,
2292 unstable_opts: &UnstableOptions,
2293) -> Externs {
2294 let is_unstable_enabled = unstable_opts.unstable_options;
2295 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2296 for arg in matches.opt_strs("extern") {
2297 let ExternOpt { crate_name: name, path, options } =
2298 split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit());
2299
2300 let entry = externs.entry(name.to_owned());
2301
2302 use std::collections::btree_map::Entry;
2303
2304 let entry = if let Some(path) = path {
2305 let path = CanonicalizedPath::new(path);
2307 match entry {
2308 Entry::Vacant(vacant) => {
2309 let files = BTreeSet::from_iter(iter::once(path));
2310 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2311 }
2312 Entry::Occupied(occupied) => {
2313 let ext_ent = occupied.into_mut();
2314 match ext_ent {
2315 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2316 files.insert(path);
2317 }
2318 ExternEntry {
2319 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2320 ..
2321 } => {
2322 let files = BTreeSet::from_iter(iter::once(path));
2324 *location = ExternLocation::ExactPaths(files);
2325 }
2326 }
2327 ext_ent
2328 }
2329 }
2330 } else {
2331 match entry {
2333 Entry::Vacant(vacant) => {
2334 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2335 }
2336 Entry::Occupied(occupied) => {
2337 occupied.into_mut()
2339 }
2340 }
2341 };
2342
2343 let mut is_private_dep = false;
2344 let mut add_prelude = true;
2345 let mut nounused_dep = false;
2346 let mut force = false;
2347 if let Some(opts) = options {
2348 if !is_unstable_enabled {
2349 early_dcx.early_fatal(
2350 "the `-Z unstable-options` flag must also be passed to \
2351 enable `--extern` options",
2352 );
2353 }
2354 for opt in opts.split(',') {
2355 match opt {
2356 "priv" => is_private_dep = true,
2357 "noprelude" => {
2358 if let ExternLocation::ExactPaths(_) = &entry.location {
2359 add_prelude = false;
2360 } else {
2361 early_dcx.early_fatal(
2362 "the `noprelude` --extern option requires a file path",
2363 );
2364 }
2365 }
2366 "nounused" => nounused_dep = true,
2367 "force" => force = true,
2368 _ => early_dcx.early_fatal(format!("unknown --extern option `{opt}`")),
2369 }
2370 }
2371 }
2372
2373 entry.is_private_dep |= is_private_dep;
2376 entry.nounused_dep |= nounused_dep;
2378 entry.force |= force;
2380 entry.add_prelude |= add_prelude;
2382 }
2383 Externs(externs)
2384}
2385
2386fn parse_remap_path_prefix(
2387 early_dcx: &EarlyDiagCtxt,
2388 matches: &getopts::Matches,
2389 unstable_opts: &UnstableOptions,
2390) -> Vec<(PathBuf, PathBuf)> {
2391 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2392 .opt_strs("remap-path-prefix")
2393 .into_iter()
2394 .map(|remap| match remap.rsplit_once('=') {
2395 None => {
2396 early_dcx.early_fatal("--remap-path-prefix must contain '=' between FROM and TO")
2397 }
2398 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2399 })
2400 .collect();
2401 match &unstable_opts.remap_cwd_prefix {
2402 Some(to) => match std::env::current_dir() {
2403 Ok(cwd) => mapping.push((cwd, to.clone())),
2404 Err(_) => (),
2405 },
2406 None => (),
2407 };
2408 mapping
2409}
2410
2411fn parse_logical_env(
2412 early_dcx: &EarlyDiagCtxt,
2413 matches: &getopts::Matches,
2414) -> FxIndexMap<String, String> {
2415 let mut vars = FxIndexMap::default();
2416
2417 for arg in matches.opt_strs("env-set") {
2418 if let Some((name, val)) = arg.split_once('=') {
2419 vars.insert(name.to_string(), val.to_string());
2420 } else {
2421 early_dcx.early_fatal(format!("`--env-set`: specify value for variable `{arg}`"));
2422 }
2423 }
2424
2425 vars
2426}
2427
2428#[allow(rustc::bad_opt_access)]
2430pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches) -> Options {
2431 let color = parse_color(early_dcx, matches);
2432
2433 let edition = parse_crate_edition(early_dcx, matches);
2434
2435 let crate_name = matches.opt_str("crate-name");
2436 let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
2437 let JsonConfig {
2438 json_rendered,
2439 json_color,
2440 json_artifact_notifications,
2441 json_timings,
2442 json_unused_externs,
2443 json_future_incompat,
2444 } = parse_json(early_dcx, matches);
2445
2446 let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
2447
2448 early_dcx.set_error_format(error_format);
2449
2450 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2451 early_dcx.early_fatal("`--diagnostic-width` must be an positive integer");
2452 });
2453
2454 let unparsed_crate_types = matches.opt_strs("crate-type");
2455 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2456 .unwrap_or_else(|e| early_dcx.early_fatal(e));
2457
2458 let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
2459
2460 let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
2461 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
2462
2463 if !unstable_opts.unstable_options && json_timings {
2464 early_dcx.early_fatal("--json=timings is unstable and requires using `-Zunstable-options`");
2465 }
2466
2467 check_error_format_stability(
2468 early_dcx,
2469 &unstable_opts,
2470 unstable_features.is_nightly_build(),
2471 error_format,
2472 );
2473
2474 let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
2475
2476 let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
2477 let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2478 early_dcx,
2479 &output_types,
2480 matches,
2481 cg.codegen_units,
2482 );
2483
2484 if unstable_opts.threads == 0 {
2485 early_dcx.early_fatal("value for threads must be a positive non-zero integer");
2486 }
2487
2488 if unstable_opts.threads == parse::MAX_THREADS_CAP {
2489 early_dcx.early_warn(format!("number of threads was capped at {}", parse::MAX_THREADS_CAP));
2490 }
2491
2492 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2493
2494 let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state);
2495
2496 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2497 early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive");
2498 }
2499
2500 if unstable_opts.profile_sample_use.is_some()
2501 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2502 {
2503 early_dcx.early_fatal(
2504 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2505 );
2506 }
2507
2508 match cg.symbol_mangling_version {
2511 None | Some(SymbolManglingVersion::V0) => {}
2513
2514 Some(SymbolManglingVersion::Legacy) => {
2516 if !unstable_opts.unstable_options {
2517 early_dcx.early_fatal(
2518 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2519 );
2520 }
2521 }
2522 Some(SymbolManglingVersion::Hashed) => {
2523 if !unstable_opts.unstable_options {
2524 early_dcx.early_fatal(
2525 "`-C symbol-mangling-version=hashed` requires `-Z unstable-options`",
2526 );
2527 }
2528 }
2529 }
2530
2531 if cg.instrument_coverage != InstrumentCoverage::No {
2532 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2533 early_dcx.early_fatal(
2534 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2535 or `-C profile-generate`",
2536 );
2537 }
2538
2539 match cg.symbol_mangling_version {
2544 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2545 Some(SymbolManglingVersion::Legacy) => {
2546 early_dcx.early_warn(
2547 "-C instrument-coverage requires symbol mangling version `v0`, \
2548 but `-C symbol-mangling-version=legacy` was specified",
2549 );
2550 }
2551 Some(SymbolManglingVersion::V0) => {}
2552 Some(SymbolManglingVersion::Hashed) => {
2553 early_dcx.early_warn(
2554 "-C instrument-coverage requires symbol mangling version `v0`, \
2555 but `-C symbol-mangling-version=hashed` was specified",
2556 );
2557 }
2558 }
2559 }
2560
2561 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2562 unstable_opts.graphviz_font = graphviz_font;
2565 }
2566
2567 if !cg.embed_bitcode {
2568 match cg.lto {
2569 LtoCli::No | LtoCli::Unspecified => {}
2570 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
2571 early_dcx.early_fatal("options `-C embed-bitcode=no` and `-C lto` are incompatible")
2572 }
2573 }
2574 }
2575
2576 let unstable_options_enabled = nightly_options::is_unstable_enabled(matches);
2577 if !unstable_options_enabled && cg.force_frame_pointers == FramePointer::NonLeaf {
2578 early_dcx.early_fatal(
2579 "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
2580 and a nightly compiler",
2581 )
2582 }
2583
2584 if !nightly_options::is_unstable_enabled(matches) && !unstable_opts.offload.is_empty() {
2585 early_dcx.early_fatal(
2586 "`-Zoffload=Enable` also requires `-Zunstable-options` \
2587 and a nightly compiler",
2588 )
2589 }
2590
2591 let target_triple = parse_target_triple(early_dcx, matches);
2592
2593 if !unstable_options_enabled {
2596 if let Err(error) = cg.link_self_contained.check_unstable_variants(&target_triple) {
2597 early_dcx.early_fatal(error);
2598 }
2599
2600 if let Some(flavor) = cg.linker_flavor {
2601 if flavor.is_unstable() {
2602 early_dcx.early_fatal(format!(
2603 "the linker flavor `{}` is unstable, the `-Z unstable-options` \
2604 flag must also be passed to use the unstable values",
2605 flavor.desc()
2606 ));
2607 }
2608 }
2609 }
2610
2611 if let Some(erroneous_components) = cg.link_self_contained.check_consistency() {
2614 let names: String = erroneous_components
2615 .into_iter()
2616 .map(|c| c.as_str().unwrap())
2617 .intersperse(", ")
2618 .collect();
2619 early_dcx.early_fatal(format!(
2620 "some `-C link-self-contained` components were both enabled and disabled: {names}"
2621 ));
2622 }
2623
2624 let prints = print_request::collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches);
2625
2626 if unstable_opts.retpoline_external_thunk {
2628 unstable_opts.retpoline = true;
2629 target_modifiers.insert(
2630 OptionsTargetModifiers::UnstableOptions(UnstableOptionsTargetModifiers::retpoline),
2631 "true".to_string(),
2632 );
2633 }
2634
2635 let cg = cg;
2636
2637 let opt_level = parse_opt_level(early_dcx, matches, &cg);
2638 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2642 let debuginfo = select_debuginfo(matches, &cg);
2643
2644 if !unstable_options_enabled {
2645 if let Err(error) = cg.linker_features.check_unstable_variants(&target_triple) {
2646 early_dcx.early_fatal(error);
2647 }
2648 }
2649
2650 if !unstable_options_enabled && cg.panic == Some(PanicStrategy::ImmediateAbort) {
2651 early_dcx.early_fatal(
2652 "`-Cpanic=immediate-abort` requires `-Zunstable-options` and a nightly compiler",
2653 )
2654 }
2655
2656 let libs = parse_native_libs(early_dcx, &unstable_opts, unstable_features, matches);
2658
2659 let test = matches.opt_present("test");
2660
2661 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2662 early_dcx.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
2663 }
2664
2665 if cg.remark.is_empty() && unstable_opts.remark_dir.is_some() {
2666 early_dcx
2667 .early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all");
2668 }
2669
2670 let externs = parse_externs(early_dcx, matches, &unstable_opts);
2671
2672 let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts);
2673
2674 let pretty = parse_pretty(early_dcx, &unstable_opts);
2675
2676 if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
2678 early_dcx.early_fatal("can't dump dependency graph without `-Z query-dep-graph`");
2679 }
2680
2681 let logical_env = parse_logical_env(early_dcx, matches);
2682
2683 let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from));
2684
2685 let real_source_base_dir = |suffix: &str, confirm: &str| {
2686 let mut candidate = sysroot.path().join(suffix);
2687 if let Ok(metadata) = candidate.symlink_metadata() {
2688 if metadata.file_type().is_symlink() {
2692 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2693 candidate = symlink_dest;
2694 }
2695 }
2696 }
2697
2698 candidate.join(confirm).is_file().then_some(candidate)
2700 };
2701
2702 let real_rust_source_base_dir =
2703 real_source_base_dir("lib/rustlib/src/rust", "library/std/src/lib.rs");
2705
2706 let real_rustc_dev_source_base_dir =
2707 real_source_base_dir("lib/rustlib/rustc-src/rust", "compiler/rustc/src/main.rs");
2709
2710 let search_paths: Vec<SearchPath> = {
2715 let mut seen_search_paths = FxHashSet::default();
2716 let search_path_matches: Vec<String> = matches.opt_strs("L");
2717 search_path_matches
2718 .iter()
2719 .filter(|p| seen_search_paths.insert(*p))
2720 .map(|path| {
2721 SearchPath::from_cli_opt(
2722 sysroot.path(),
2723 &target_triple,
2724 early_dcx,
2725 &path,
2726 unstable_opts.unstable_options,
2727 )
2728 })
2729 .collect()
2730 };
2731
2732 let working_dir = {
2735 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2736 early_dcx.early_fatal(format!("Current directory is invalid: {e}"));
2737 });
2738
2739 let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts);
2740 file_mapping.to_real_filename(&RealFileName::empty(), &working_dir)
2741 };
2742
2743 let verbose = matches.opt_present("verbose") || unstable_opts.verbose_internals;
2744
2745 Options {
2746 assert_incr_state,
2747 crate_types,
2748 optimize: opt_level,
2749 debuginfo,
2750 lint_opts,
2751 lint_cap,
2752 describe_lints,
2753 output_types,
2754 search_paths,
2755 sysroot,
2756 target_triple,
2757 test,
2758 incremental,
2759 untracked_state_hash: Default::default(),
2760 unstable_opts,
2761 prints,
2762 cg,
2763 error_format,
2764 diagnostic_width,
2765 externs,
2766 unstable_features,
2767 crate_name,
2768 libs,
2769 debug_assertions,
2770 actually_rustdoc: false,
2771 resolve_doc_links: ResolveDocLinks::ExportedMetadata,
2772 trimmed_def_paths: false,
2773 cli_forced_codegen_units: codegen_units,
2774 cli_forced_local_thinlto_off: disable_local_thinlto,
2775 remap_path_prefix,
2776 real_rust_source_base_dir,
2777 real_rustc_dev_source_base_dir,
2778 edition,
2779 json_artifact_notifications,
2780 json_timings,
2781 json_unused_externs,
2782 json_future_incompat,
2783 pretty,
2784 working_dir,
2785 color,
2786 logical_env,
2787 verbose,
2788 target_modifiers,
2789 }
2790}
2791
2792fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> Option<PpMode> {
2793 use PpMode::*;
2794
2795 let first = match unstable_opts.unpretty.as_deref()? {
2796 "normal" => Source(PpSourceMode::Normal),
2797 "identified" => Source(PpSourceMode::Identified),
2798 "expanded" => Source(PpSourceMode::Expanded),
2799 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2800 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2801 "ast-tree" => AstTree,
2802 "ast-tree,expanded" => AstTreeExpanded,
2803 "hir" => Hir(PpHirMode::Normal),
2804 "hir,identified" => Hir(PpHirMode::Identified),
2805 "hir,typed" => Hir(PpHirMode::Typed),
2806 "hir-tree" => HirTree,
2807 "thir-tree" => ThirTree,
2808 "thir-flat" => ThirFlat,
2809 "mir" => Mir,
2810 "stable-mir" => StableMir,
2811 "mir-cfg" => MirCFG,
2812 name => early_dcx.early_fatal(format!(
2813 "argument to `unpretty` must be one of `normal`, `identified`, \
2814 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2815 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2816 `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir`, `stable-mir`, or \
2817 `mir-cfg`; got {name}"
2818 )),
2819 };
2820 debug!("got unpretty option: {first:?}");
2821 Some(first)
2822}
2823
2824pub fn make_crate_type_option() -> RustcOptGroup {
2825 make_opt(
2826 OptionStability::Stable,
2827 OptionKind::Multi,
2828 "",
2829 "crate-type",
2830 "Comma separated list of types of crates
2831 for the compiler to emit",
2832 "<bin|lib|rlib|dylib|cdylib|staticlib|proc-macro>",
2833 )
2834}
2835
2836pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2837 let mut crate_types: Vec<CrateType> = Vec::new();
2838 for unparsed_crate_type in &list_list {
2839 for part in unparsed_crate_type.split(',') {
2840 let new_part = match part {
2841 "lib" => default_lib_output(),
2842 "rlib" => CrateType::Rlib,
2843 "staticlib" => CrateType::Staticlib,
2844 "dylib" => CrateType::Dylib,
2845 "cdylib" => CrateType::Cdylib,
2846 "bin" => CrateType::Executable,
2847 "proc-macro" => CrateType::ProcMacro,
2848 "sdylib" => CrateType::Sdylib,
2849 _ => {
2850 return Err(format!(
2851 "unknown crate type: `{part}`, expected one of: \
2852 `lib`, `rlib`, `staticlib`, `dylib`, `cdylib`, `bin`, `proc-macro`",
2853 ));
2854 }
2855 };
2856 if !crate_types.contains(&new_part) {
2857 crate_types.push(new_part)
2858 }
2859 }
2860 }
2861
2862 Ok(crate_types)
2863}
2864
2865pub mod nightly_options {
2866 use rustc_feature::UnstableFeatures;
2867
2868 use super::{OptionStability, RustcOptGroup};
2869 use crate::EarlyDiagCtxt;
2870
2871 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2872 match_is_nightly_build(matches)
2873 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2874 }
2875
2876 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2877 is_nightly_build(matches.opt_str("crate-name").as_deref())
2878 }
2879
2880 fn is_nightly_build(krate: Option<&str>) -> bool {
2881 UnstableFeatures::from_environment(krate).is_nightly_build()
2882 }
2883
2884 pub fn check_nightly_options(
2885 early_dcx: &EarlyDiagCtxt,
2886 matches: &getopts::Matches,
2887 flags: &[RustcOptGroup],
2888 ) {
2889 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2890 let really_allows_unstable_options = match_is_nightly_build(matches);
2891 let mut nightly_options_on_stable = 0;
2892
2893 for opt in flags.iter() {
2894 if opt.stability == OptionStability::Stable {
2895 continue;
2896 }
2897 if !matches.opt_present(opt.name) {
2898 continue;
2899 }
2900 if opt.name != "Z" && !has_z_unstable_option {
2901 early_dcx.early_fatal(format!(
2902 "the `-Z unstable-options` flag must also be passed to enable \
2903 the flag `{}`",
2904 opt.name
2905 ));
2906 }
2907 if really_allows_unstable_options {
2908 continue;
2909 }
2910 match opt.stability {
2911 OptionStability::Unstable => {
2912 nightly_options_on_stable += 1;
2913 let msg = format!(
2914 "the option `{}` is only accepted on the nightly compiler",
2915 opt.name
2916 );
2917 let _ = early_dcx.early_err(msg);
2919 }
2920 OptionStability::Stable => {}
2921 }
2922 }
2923 if nightly_options_on_stable > 0 {
2924 early_dcx
2925 .early_help("consider switching to a nightly toolchain: `rustup default nightly`");
2926 early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
2927 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>");
2928 early_dcx.early_fatal(format!(
2929 "{} nightly option{} were parsed",
2930 nightly_options_on_stable,
2931 if nightly_options_on_stable > 1 { "s" } else { "" }
2932 ));
2933 }
2934 }
2935}
2936
2937impl fmt::Display for CrateType {
2938 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2939 match *self {
2940 CrateType::Executable => "bin".fmt(f),
2941 CrateType::Dylib => "dylib".fmt(f),
2942 CrateType::Rlib => "rlib".fmt(f),
2943 CrateType::Staticlib => "staticlib".fmt(f),
2944 CrateType::Cdylib => "cdylib".fmt(f),
2945 CrateType::ProcMacro => "proc-macro".fmt(f),
2946 CrateType::Sdylib => "sdylib".fmt(f),
2947 }
2948 }
2949}
2950
2951impl IntoDiagArg for CrateType {
2952 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2953 self.to_string().into_diag_arg(&mut None)
2954 }
2955}
2956
2957#[derive(Copy, Clone, PartialEq, Debug)]
2958pub enum PpSourceMode {
2959 Normal,
2961 Expanded,
2963 Identified,
2965 ExpandedIdentified,
2967 ExpandedHygiene,
2969}
2970
2971#[derive(Copy, Clone, PartialEq, Debug)]
2972pub enum PpHirMode {
2973 Normal,
2975 Identified,
2977 Typed,
2979}
2980
2981#[derive(Copy, Clone, PartialEq, Debug)]
2982pub enum PpMode {
2984 Source(PpSourceMode),
2987 AstTree,
2989 AstTreeExpanded,
2991 Hir(PpHirMode),
2993 HirTree,
2995 ThirTree,
2997 ThirFlat,
2999 Mir,
3001 MirCFG,
3003 StableMir,
3005}
3006
3007impl PpMode {
3008 pub fn needs_ast_map(&self) -> bool {
3009 use PpMode::*;
3010 use PpSourceMode::*;
3011 match *self {
3012 Source(Normal | Identified) | AstTree => false,
3013
3014 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
3015 | AstTreeExpanded
3016 | Hir(_)
3017 | HirTree
3018 | ThirTree
3019 | ThirFlat
3020 | Mir
3021 | MirCFG
3022 | StableMir => true,
3023 }
3024 }
3025
3026 pub fn needs_analysis(&self) -> bool {
3027 use PpMode::*;
3028 matches!(*self, Hir(PpHirMode::Typed) | Mir | StableMir | MirCFG | ThirTree | ThirFlat)
3029 }
3030}
3031
3032#[derive(Clone, Hash, PartialEq, Eq, Debug)]
3033pub enum WasiExecModel {
3034 Command,
3035 Reactor,
3036}
3037
3038pub(crate) mod dep_tracking {
3057 use std::collections::BTreeMap;
3058 use std::hash::Hash;
3059 use std::num::NonZero;
3060 use std::path::PathBuf;
3061
3062 use rustc_abi::Align;
3063 use rustc_data_structures::fx::FxIndexMap;
3064 use rustc_data_structures::stable_hasher::StableHasher;
3065 use rustc_errors::LanguageIdentifier;
3066 use rustc_feature::UnstableFeatures;
3067 use rustc_hashes::Hash64;
3068 use rustc_hir::attrs::CollapseMacroDebuginfo;
3069 use rustc_span::edition::Edition;
3070 use rustc_span::{RealFileName, RemapPathScopeComponents};
3071 use rustc_target::spec::{
3072 CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
3073 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple,
3074 TlsModel,
3075 };
3076
3077 use super::{
3078 AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CFProtection, CoverageOptions,
3079 CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
3080 InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
3081 LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OptLevel, OutFileName, OutputType,
3082 OutputTypes, PatchableFunctionEntry, Polonius, ResolveDocLinks, SourceFileHashAlgorithm,
3083 SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
3084 };
3085 use crate::lint;
3086 use crate::utils::NativeLib;
3087
3088 pub(crate) trait DepTrackingHash {
3089 fn hash(
3090 &self,
3091 hasher: &mut StableHasher,
3092 error_format: ErrorOutputType,
3093 for_crate_hash: bool,
3094 );
3095 }
3096
3097 macro_rules! impl_dep_tracking_hash_via_hash {
3098 ($($t:ty),+ $(,)?) => {$(
3099 impl DepTrackingHash for $t {
3100 fn hash(&self, hasher: &mut StableHasher, _: ErrorOutputType, _for_crate_hash: bool) {
3101 Hash::hash(self, hasher);
3102 }
3103 }
3104 )+};
3105 }
3106
3107 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
3108 fn hash(
3109 &self,
3110 hasher: &mut StableHasher,
3111 error_format: ErrorOutputType,
3112 for_crate_hash: bool,
3113 ) {
3114 match self {
3115 Some(x) => {
3116 Hash::hash(&1, hasher);
3117 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
3118 }
3119 None => Hash::hash(&0, hasher),
3120 }
3121 }
3122 }
3123
3124 impl_dep_tracking_hash_via_hash!(
3125 (),
3126 AnnotateMoves,
3127 AutoDiff,
3128 Offload,
3129 bool,
3130 usize,
3131 NonZero<usize>,
3132 u64,
3133 Hash64,
3134 String,
3135 PathBuf,
3136 lint::Level,
3137 WasiExecModel,
3138 u32,
3139 FramePointer,
3140 RelocModel,
3141 CodeModel,
3142 TlsModel,
3143 InstrumentCoverage,
3144 CoverageOptions,
3145 InstrumentXRay,
3146 CrateType,
3147 MergeFunctions,
3148 OnBrokenPipe,
3149 PanicStrategy,
3150 RelroLevel,
3151 OptLevel,
3152 LtoCli,
3153 DebugInfo,
3154 DebugInfoCompression,
3155 MirStripDebugInfo,
3156 CollapseMacroDebuginfo,
3157 UnstableFeatures,
3158 NativeLib,
3159 SanitizerSet,
3160 CFGuard,
3161 CFProtection,
3162 TargetTuple,
3163 Edition,
3164 LinkerPluginLto,
3165 ResolveDocLinks,
3166 SplitDebuginfo,
3167 SplitDwarfKind,
3168 StackProtector,
3169 SwitchWithOptPath,
3170 SymbolManglingVersion,
3171 SymbolVisibility,
3172 RemapPathScopeComponents,
3173 SourceFileHashAlgorithm,
3174 OutFileName,
3175 OutputType,
3176 RealFileName,
3177 LocationDetail,
3178 FmtDebug,
3179 BranchProtection,
3180 LanguageIdentifier,
3181 NextSolverConfig,
3182 PatchableFunctionEntry,
3183 Polonius,
3184 InliningThreshold,
3185 FunctionReturn,
3186 Align,
3187 );
3188
3189 impl<T1, T2> DepTrackingHash for (T1, T2)
3190 where
3191 T1: DepTrackingHash,
3192 T2: DepTrackingHash,
3193 {
3194 fn hash(
3195 &self,
3196 hasher: &mut StableHasher,
3197 error_format: ErrorOutputType,
3198 for_crate_hash: bool,
3199 ) {
3200 Hash::hash(&0, hasher);
3201 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3202 Hash::hash(&1, hasher);
3203 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3204 }
3205 }
3206
3207 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
3208 where
3209 T1: DepTrackingHash,
3210 T2: DepTrackingHash,
3211 T3: DepTrackingHash,
3212 {
3213 fn hash(
3214 &self,
3215 hasher: &mut StableHasher,
3216 error_format: ErrorOutputType,
3217 for_crate_hash: bool,
3218 ) {
3219 Hash::hash(&0, hasher);
3220 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3221 Hash::hash(&1, hasher);
3222 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3223 Hash::hash(&2, hasher);
3224 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
3225 }
3226 }
3227
3228 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
3229 fn hash(
3230 &self,
3231 hasher: &mut StableHasher,
3232 error_format: ErrorOutputType,
3233 for_crate_hash: bool,
3234 ) {
3235 Hash::hash(&self.len(), hasher);
3236 for (index, elem) in self.iter().enumerate() {
3237 Hash::hash(&index, hasher);
3238 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
3239 }
3240 }
3241 }
3242
3243 impl<T: DepTrackingHash, V: DepTrackingHash> DepTrackingHash for FxIndexMap<T, V> {
3244 fn hash(
3245 &self,
3246 hasher: &mut StableHasher,
3247 error_format: ErrorOutputType,
3248 for_crate_hash: bool,
3249 ) {
3250 Hash::hash(&self.len(), hasher);
3251 for (key, value) in self.iter() {
3252 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3253 DepTrackingHash::hash(value, hasher, error_format, for_crate_hash);
3254 }
3255 }
3256 }
3257
3258 impl DepTrackingHash for OutputTypes {
3259 fn hash(
3260 &self,
3261 hasher: &mut StableHasher,
3262 error_format: ErrorOutputType,
3263 for_crate_hash: bool,
3264 ) {
3265 Hash::hash(&self.0.len(), hasher);
3266 for (key, val) in &self.0 {
3267 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3268 if !for_crate_hash {
3269 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
3270 }
3271 }
3272 }
3273 }
3274
3275 pub(crate) fn stable_hash(
3277 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
3278 hasher: &mut StableHasher,
3279 error_format: ErrorOutputType,
3280 for_crate_hash: bool,
3281 ) {
3282 for (key, sub_hash) in sub_hashes {
3283 Hash::hash(&key.len(), hasher);
3286 Hash::hash(key, hasher);
3287 sub_hash.hash(hasher, error_format, for_crate_hash);
3288 }
3289 }
3290}
3291
3292#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3294pub enum ProcMacroExecutionStrategy {
3295 SameThread,
3297
3298 CrossThread,
3300}
3301
3302#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3304pub enum DumpMonoStatsFormat {
3305 Markdown,
3307 Json,
3309}
3310
3311impl DumpMonoStatsFormat {
3312 pub fn extension(self) -> &'static str {
3313 match self {
3314 Self::Markdown => "md",
3315 Self::Json => "json",
3316 }
3317 }
3318}
3319
3320#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3323pub struct PatchableFunctionEntry {
3324 prefix: u8,
3326 entry: u8,
3328}
3329
3330impl PatchableFunctionEntry {
3331 pub fn from_total_and_prefix_nops(
3332 total_nops: u8,
3333 prefix_nops: u8,
3334 ) -> Option<PatchableFunctionEntry> {
3335 if total_nops < prefix_nops {
3336 None
3337 } else {
3338 Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops })
3339 }
3340 }
3341 pub fn prefix(&self) -> u8 {
3342 self.prefix
3343 }
3344 pub fn entry(&self) -> u8 {
3345 self.entry
3346 }
3347}
3348
3349#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3352pub enum Polonius {
3353 #[default]
3355 Off,
3356
3357 Legacy,
3359
3360 Next,
3362}
3363
3364impl Polonius {
3365 pub fn is_legacy_enabled(&self) -> bool {
3367 matches!(self, Polonius::Legacy)
3368 }
3369
3370 pub fn is_next_enabled(&self) -> bool {
3372 matches!(self, Polonius::Next)
3373 }
3374}
3375
3376#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3377pub enum InliningThreshold {
3378 Always,
3379 Sometimes(usize),
3380 Never,
3381}
3382
3383impl Default for InliningThreshold {
3384 fn default() -> Self {
3385 Self::Sometimes(100)
3386 }
3387}
3388
3389#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3391pub enum FunctionReturn {
3392 #[default]
3394 Keep,
3395
3396 ThunkExtern,
3398}
3399
3400#[derive(Clone, Copy, Default, PartialEq, Debug)]
3403pub enum MirIncludeSpans {
3404 Off,
3405 On,
3406 #[default]
3409 Nll,
3410}
3411
3412impl MirIncludeSpans {
3413 pub fn is_enabled(self) -> bool {
3418 self == MirIncludeSpans::On
3419 }
3420}