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 { short: false, unicode: 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(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
1969 let mut json_rendered = HumanReadableErrorType { short: false, unicode: false };
1970 let mut json_color = ColorConfig::Never;
1971 let mut json_artifact_notifications = false;
1972 let mut json_unused_externs = JsonUnusedExterns::No;
1973 let mut json_future_incompat = false;
1974 let mut json_timings = false;
1975 for option in matches.opt_strs("json") {
1976 if matches.opt_str("color").is_some() {
1980 early_dcx.early_fatal("cannot specify the `--color` option with `--json`");
1981 }
1982
1983 for sub_option in option.split(',') {
1984 match sub_option {
1985 "diagnostic-short" => {
1986 json_rendered = HumanReadableErrorType { short: true, unicode: false };
1987 }
1988 "diagnostic-unicode" => {
1989 json_rendered = HumanReadableErrorType { short: false, unicode: true };
1990 }
1991 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1992 "artifacts" => json_artifact_notifications = true,
1993 "timings" => json_timings = true,
1994 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1995 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1996 "future-incompat" => json_future_incompat = true,
1997 s => early_dcx.early_fatal(format!("unknown `--json` option `{s}`")),
1998 }
1999 }
2000 }
2001
2002 JsonConfig {
2003 json_rendered,
2004 json_color,
2005 json_artifact_notifications,
2006 json_timings,
2007 json_unused_externs,
2008 json_future_incompat,
2009 }
2010}
2011
2012pub fn parse_error_format(
2014 early_dcx: &mut EarlyDiagCtxt,
2015 matches: &getopts::Matches,
2016 color_config: ColorConfig,
2017 json_color: ColorConfig,
2018 json_rendered: HumanReadableErrorType,
2019) -> ErrorOutputType {
2020 let default_kind = HumanReadableErrorType { short: false, unicode: false };
2021 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
2026 match matches.opt_str("error-format").as_deref() {
2027 None | Some("human") => {
2028 ErrorOutputType::HumanReadable { color_config, kind: default_kind }
2029 }
2030 Some("json") => {
2031 ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
2032 }
2033 Some("pretty-json") => {
2034 ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
2035 }
2036 Some("short") => ErrorOutputType::HumanReadable {
2037 kind: HumanReadableErrorType { short: true, unicode: false },
2038 color_config,
2039 },
2040 Some("human-unicode") => ErrorOutputType::HumanReadable {
2041 kind: HumanReadableErrorType { short: false, unicode: true },
2042 color_config,
2043 },
2044 Some(arg) => {
2045 early_dcx.set_error_format(ErrorOutputType::HumanReadable {
2046 color_config,
2047 kind: default_kind,
2048 });
2049 early_dcx.early_fatal(format!(
2050 "argument for `--error-format` must be `human`, `human-unicode`, \
2051 `json`, `pretty-json` or `short` (instead was `{arg}`)"
2052 ))
2053 }
2054 }
2055 } else {
2056 ErrorOutputType::HumanReadable { color_config, kind: default_kind }
2057 };
2058
2059 match error_format {
2060 ErrorOutputType::Json { .. } => {}
2061
2062 _ if !matches.opt_strs("json").is_empty() => {
2066 early_dcx.early_fatal("using `--json` requires also using `--error-format=json`");
2067 }
2068
2069 _ => {}
2070 }
2071
2072 error_format
2073}
2074
2075pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Edition {
2076 let edition = match matches.opt_str("edition") {
2077 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
2078 early_dcx.early_fatal(format!(
2079 "argument for `--edition` must be one of: \
2080 {EDITION_NAME_LIST}. (instead was `{arg}`)"
2081 ))
2082 }),
2083 None => DEFAULT_EDITION,
2084 };
2085
2086 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
2087 let is_nightly = nightly_options::match_is_nightly_build(matches);
2088 let msg = if !is_nightly {
2089 format!(
2090 "the crate requires edition {edition}, but the latest edition supported by this Rust version is {LATEST_STABLE_EDITION}"
2091 )
2092 } else {
2093 format!("edition {edition} is unstable and only available with -Z unstable-options")
2094 };
2095 early_dcx.early_fatal(msg)
2096 }
2097
2098 edition
2099}
2100
2101fn check_error_format_stability(
2102 early_dcx: &EarlyDiagCtxt,
2103 unstable_opts: &UnstableOptions,
2104 is_nightly_build: bool,
2105 format: ErrorOutputType,
2106) {
2107 if unstable_opts.unstable_options || is_nightly_build {
2108 return;
2109 }
2110 let format = match format {
2111 ErrorOutputType::Json { pretty: true, .. } => "pretty-json",
2112 ErrorOutputType::HumanReadable { kind, .. } => match kind {
2113 HumanReadableErrorType { unicode: true, .. } => "human-unicode",
2114 _ => return,
2115 },
2116 _ => return,
2117 };
2118 early_dcx.early_fatal(format!("`--error-format={format}` is unstable"))
2119}
2120
2121fn parse_output_types(
2122 early_dcx: &EarlyDiagCtxt,
2123 unstable_opts: &UnstableOptions,
2124 matches: &getopts::Matches,
2125) -> OutputTypes {
2126 let mut output_types = BTreeMap::new();
2127 if !unstable_opts.parse_crate_root_only {
2128 for list in matches.opt_strs("emit") {
2129 for output_type in list.split(',') {
2130 let (shorthand, path) = split_out_file_name(output_type);
2131 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
2132 early_dcx.early_fatal(format!(
2133 "unknown emission type: `{shorthand}` - expected one of: {display}",
2134 display = OutputType::shorthands_display(),
2135 ))
2136 });
2137 if output_type == OutputType::ThinLinkBitcode && !unstable_opts.unstable_options {
2138 early_dcx.early_fatal(format!(
2139 "{} requested but -Zunstable-options not specified",
2140 OutputType::ThinLinkBitcode.shorthand()
2141 ));
2142 }
2143 output_types.insert(output_type, path);
2144 }
2145 }
2146 };
2147 if output_types.is_empty() {
2148 output_types.insert(OutputType::Exe, None);
2149 }
2150 OutputTypes(output_types)
2151}
2152
2153fn split_out_file_name(arg: &str) -> (&str, Option<OutFileName>) {
2154 match arg.split_once('=') {
2155 None => (arg, None),
2156 Some((kind, "-")) => (kind, Some(OutFileName::Stdout)),
2157 Some((kind, path)) => (kind, Some(OutFileName::Real(PathBuf::from(path)))),
2158 }
2159}
2160
2161fn should_override_cgus_and_disable_thinlto(
2162 early_dcx: &EarlyDiagCtxt,
2163 output_types: &OutputTypes,
2164 matches: &getopts::Matches,
2165 mut codegen_units: Option<usize>,
2166) -> (bool, Option<usize>) {
2167 let mut disable_local_thinlto = false;
2168 let incompatible: Vec<_> = output_types
2171 .0
2172 .iter()
2173 .map(|ot_path| ot_path.0)
2174 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2175 .map(|ot| ot.shorthand())
2176 .collect();
2177 if !incompatible.is_empty() {
2178 match codegen_units {
2179 Some(n) if n > 1 => {
2180 if matches.opt_present("o") {
2181 for ot in &incompatible {
2182 early_dcx.early_warn(format!(
2183 "`--emit={ot}` with `-o` incompatible with \
2184 `-C codegen-units=N` for N > 1",
2185 ));
2186 }
2187 early_dcx.early_warn("resetting to default -C codegen-units=1");
2188 codegen_units = Some(1);
2189 disable_local_thinlto = true;
2190 }
2191 }
2192 _ => {
2193 codegen_units = Some(1);
2194 disable_local_thinlto = true;
2195 }
2196 }
2197 }
2198
2199 if codegen_units == Some(0) {
2200 early_dcx.early_fatal("value for codegen units must be a positive non-zero integer");
2201 }
2202
2203 (disable_local_thinlto, codegen_units)
2204}
2205
2206pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTuple {
2207 match matches.opt_str("target") {
2208 Some(target) if target.ends_with(".json") => {
2209 let path = Path::new(&target);
2210 TargetTuple::from_path(path).unwrap_or_else(|_| {
2211 early_dcx.early_fatal(format!("target file {path:?} does not exist"))
2212 })
2213 }
2214 Some(target) => TargetTuple::TargetTuple(target),
2215 _ => TargetTuple::from_tuple(host_tuple()),
2216 }
2217}
2218
2219fn parse_opt_level(
2220 early_dcx: &EarlyDiagCtxt,
2221 matches: &getopts::Matches,
2222 cg: &CodegenOptions,
2223) -> OptLevel {
2224 let max_o = matches.opt_positions("O").into_iter().max();
2231 let max_c = matches
2232 .opt_strs_pos("C")
2233 .into_iter()
2234 .flat_map(|(i, s)| {
2235 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
2237 })
2238 .max();
2239 if max_o > max_c {
2240 OptLevel::Aggressive
2241 } else {
2242 match cg.opt_level.as_ref() {
2243 "0" => OptLevel::No,
2244 "1" => OptLevel::Less,
2245 "2" => OptLevel::More,
2246 "3" => OptLevel::Aggressive,
2247 "s" => OptLevel::Size,
2248 "z" => OptLevel::SizeMin,
2249 arg => {
2250 early_dcx.early_fatal(format!(
2251 "optimization level needs to be \
2252 between 0-3, s or z (instead was `{arg}`)"
2253 ));
2254 }
2255 }
2256 }
2257}
2258
2259fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInfo {
2260 let max_g = matches.opt_positions("g").into_iter().max();
2261 let max_c = matches
2262 .opt_strs_pos("C")
2263 .into_iter()
2264 .flat_map(|(i, s)| {
2265 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
2267 })
2268 .max();
2269 if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
2270}
2271
2272fn parse_assert_incr_state(
2273 early_dcx: &EarlyDiagCtxt,
2274 opt_assertion: &Option<String>,
2275) -> Option<IncrementalStateAssertion> {
2276 match opt_assertion {
2277 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
2278 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
2279 Some(s) => {
2280 early_dcx.early_fatal(format!("unexpected incremental state assertion value: {s}"))
2281 }
2282 None => None,
2283 }
2284}
2285
2286pub fn parse_externs(
2287 early_dcx: &EarlyDiagCtxt,
2288 matches: &getopts::Matches,
2289 unstable_opts: &UnstableOptions,
2290) -> Externs {
2291 let is_unstable_enabled = unstable_opts.unstable_options;
2292 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2293 for arg in matches.opt_strs("extern") {
2294 let ExternOpt { crate_name: name, path, options } =
2295 split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit());
2296
2297 let entry = externs.entry(name.to_owned());
2298
2299 use std::collections::btree_map::Entry;
2300
2301 let entry = if let Some(path) = path {
2302 let path = CanonicalizedPath::new(path);
2304 match entry {
2305 Entry::Vacant(vacant) => {
2306 let files = BTreeSet::from_iter(iter::once(path));
2307 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2308 }
2309 Entry::Occupied(occupied) => {
2310 let ext_ent = occupied.into_mut();
2311 match ext_ent {
2312 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2313 files.insert(path);
2314 }
2315 ExternEntry {
2316 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2317 ..
2318 } => {
2319 let files = BTreeSet::from_iter(iter::once(path));
2321 *location = ExternLocation::ExactPaths(files);
2322 }
2323 }
2324 ext_ent
2325 }
2326 }
2327 } else {
2328 match entry {
2330 Entry::Vacant(vacant) => {
2331 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2332 }
2333 Entry::Occupied(occupied) => {
2334 occupied.into_mut()
2336 }
2337 }
2338 };
2339
2340 let mut is_private_dep = false;
2341 let mut add_prelude = true;
2342 let mut nounused_dep = false;
2343 let mut force = false;
2344 if let Some(opts) = options {
2345 if !is_unstable_enabled {
2346 early_dcx.early_fatal(
2347 "the `-Z unstable-options` flag must also be passed to \
2348 enable `--extern` options",
2349 );
2350 }
2351 for opt in opts.split(',') {
2352 match opt {
2353 "priv" => is_private_dep = true,
2354 "noprelude" => {
2355 if let ExternLocation::ExactPaths(_) = &entry.location {
2356 add_prelude = false;
2357 } else {
2358 early_dcx.early_fatal(
2359 "the `noprelude` --extern option requires a file path",
2360 );
2361 }
2362 }
2363 "nounused" => nounused_dep = true,
2364 "force" => force = true,
2365 _ => early_dcx.early_fatal(format!("unknown --extern option `{opt}`")),
2366 }
2367 }
2368 }
2369
2370 entry.is_private_dep |= is_private_dep;
2373 entry.nounused_dep |= nounused_dep;
2375 entry.force |= force;
2377 entry.add_prelude |= add_prelude;
2379 }
2380 Externs(externs)
2381}
2382
2383fn parse_remap_path_prefix(
2384 early_dcx: &EarlyDiagCtxt,
2385 matches: &getopts::Matches,
2386 unstable_opts: &UnstableOptions,
2387) -> Vec<(PathBuf, PathBuf)> {
2388 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2389 .opt_strs("remap-path-prefix")
2390 .into_iter()
2391 .map(|remap| match remap.rsplit_once('=') {
2392 None => {
2393 early_dcx.early_fatal("--remap-path-prefix must contain '=' between FROM and TO")
2394 }
2395 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2396 })
2397 .collect();
2398 match &unstable_opts.remap_cwd_prefix {
2399 Some(to) => match std::env::current_dir() {
2400 Ok(cwd) => mapping.push((cwd, to.clone())),
2401 Err(_) => (),
2402 },
2403 None => (),
2404 };
2405 mapping
2406}
2407
2408fn parse_logical_env(
2409 early_dcx: &EarlyDiagCtxt,
2410 matches: &getopts::Matches,
2411) -> FxIndexMap<String, String> {
2412 let mut vars = FxIndexMap::default();
2413
2414 for arg in matches.opt_strs("env-set") {
2415 if let Some((name, val)) = arg.split_once('=') {
2416 vars.insert(name.to_string(), val.to_string());
2417 } else {
2418 early_dcx.early_fatal(format!("`--env-set`: specify value for variable `{arg}`"));
2419 }
2420 }
2421
2422 vars
2423}
2424
2425#[allow(rustc::bad_opt_access)]
2427pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches) -> Options {
2428 let color = parse_color(early_dcx, matches);
2429
2430 let edition = parse_crate_edition(early_dcx, matches);
2431
2432 let crate_name = matches.opt_str("crate-name");
2433 let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
2434 let JsonConfig {
2435 json_rendered,
2436 json_color,
2437 json_artifact_notifications,
2438 json_timings,
2439 json_unused_externs,
2440 json_future_incompat,
2441 } = parse_json(early_dcx, matches);
2442
2443 let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
2444
2445 early_dcx.set_error_format(error_format);
2446
2447 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2448 early_dcx.early_fatal("`--diagnostic-width` must be an positive integer");
2449 });
2450
2451 let unparsed_crate_types = matches.opt_strs("crate-type");
2452 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2453 .unwrap_or_else(|e| early_dcx.early_fatal(e));
2454
2455 let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
2456
2457 let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
2458 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
2459
2460 if !unstable_opts.unstable_options && json_timings {
2461 early_dcx.early_fatal("--json=timings is unstable and requires using `-Zunstable-options`");
2462 }
2463
2464 check_error_format_stability(
2465 early_dcx,
2466 &unstable_opts,
2467 unstable_features.is_nightly_build(),
2468 error_format,
2469 );
2470
2471 let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
2472
2473 let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
2474 let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2475 early_dcx,
2476 &output_types,
2477 matches,
2478 cg.codegen_units,
2479 );
2480
2481 if unstable_opts.threads == 0 {
2482 early_dcx.early_fatal("value for threads must be a positive non-zero integer");
2483 }
2484
2485 if unstable_opts.threads == parse::MAX_THREADS_CAP {
2486 early_dcx.early_warn(format!("number of threads was capped at {}", parse::MAX_THREADS_CAP));
2487 }
2488
2489 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2490
2491 let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state);
2492
2493 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2494 early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive");
2495 }
2496
2497 if unstable_opts.profile_sample_use.is_some()
2498 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2499 {
2500 early_dcx.early_fatal(
2501 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2502 );
2503 }
2504
2505 match cg.symbol_mangling_version {
2508 None | Some(SymbolManglingVersion::V0) => {}
2510
2511 Some(SymbolManglingVersion::Legacy) => {
2513 if !unstable_opts.unstable_options {
2514 early_dcx.early_fatal(
2515 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2516 );
2517 }
2518 }
2519 Some(SymbolManglingVersion::Hashed) => {
2520 if !unstable_opts.unstable_options {
2521 early_dcx.early_fatal(
2522 "`-C symbol-mangling-version=hashed` requires `-Z unstable-options`",
2523 );
2524 }
2525 }
2526 }
2527
2528 if cg.instrument_coverage != InstrumentCoverage::No {
2529 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2530 early_dcx.early_fatal(
2531 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2532 or `-C profile-generate`",
2533 );
2534 }
2535
2536 match cg.symbol_mangling_version {
2541 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2542 Some(SymbolManglingVersion::Legacy) => {
2543 early_dcx.early_warn(
2544 "-C instrument-coverage requires symbol mangling version `v0`, \
2545 but `-C symbol-mangling-version=legacy` was specified",
2546 );
2547 }
2548 Some(SymbolManglingVersion::V0) => {}
2549 Some(SymbolManglingVersion::Hashed) => {
2550 early_dcx.early_warn(
2551 "-C instrument-coverage requires symbol mangling version `v0`, \
2552 but `-C symbol-mangling-version=hashed` was specified",
2553 );
2554 }
2555 }
2556 }
2557
2558 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2559 unstable_opts.graphviz_font = graphviz_font;
2562 }
2563
2564 if !cg.embed_bitcode {
2565 match cg.lto {
2566 LtoCli::No | LtoCli::Unspecified => {}
2567 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
2568 early_dcx.early_fatal("options `-C embed-bitcode=no` and `-C lto` are incompatible")
2569 }
2570 }
2571 }
2572
2573 let unstable_options_enabled = nightly_options::is_unstable_enabled(matches);
2574 if !unstable_options_enabled && cg.force_frame_pointers == FramePointer::NonLeaf {
2575 early_dcx.early_fatal(
2576 "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
2577 and a nightly compiler",
2578 )
2579 }
2580
2581 if !nightly_options::is_unstable_enabled(matches)
2582 && unstable_opts.offload.contains(&Offload::Enable)
2583 {
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}