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