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