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