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