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