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