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