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, Eq, 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 hyphen_len = 1; let allowed_suffix = MAX_FILENAME_LENGTH.saturating_sub(hash_len + hyphen_len);
1218
1219 let stripped_bytes = filename.len().saturating_sub(allowed_suffix);
1221
1222 let split_at = filename.ceil_char_boundary(stripped_bytes);
1224
1225 let mut hasher = StableHasher::new();
1226 filename[..split_at].hash(&mut hasher);
1227 let hash = hasher.finish::<Hash64>();
1228
1229 path.set_file_name(format!("{:x}-{}", hash, &filename[split_at..]));
1230 }
1231 path
1232}
1233impl OutputFilenames {
1234 pub fn new(
1235 out_directory: PathBuf,
1236 out_crate_name: String,
1237 out_filestem: String,
1238 single_output_file: Option<OutFileName>,
1239 temps_directory: Option<PathBuf>,
1240 explicit_dwo_out_directory: Option<PathBuf>,
1241 extra: String,
1242 outputs: OutputTypes,
1243 ) -> Self {
1244 OutputFilenames {
1245 out_directory,
1246 single_output_file,
1247 temps_directory,
1248 explicit_dwo_out_directory,
1249 outputs,
1250 crate_stem: format!("{out_crate_name}{extra}"),
1251 filestem: format!("{out_filestem}{extra}"),
1252 }
1253 }
1254
1255 pub fn path(&self, flavor: OutputType) -> OutFileName {
1256 self.outputs
1257 .get(&flavor)
1258 .and_then(|p| p.to_owned())
1259 .or_else(|| self.single_output_file.clone())
1260 .unwrap_or_else(|| OutFileName::Real(self.output_path(flavor)))
1261 }
1262
1263 pub fn interface_path(&self) -> PathBuf {
1264 self.out_directory.join(format!("lib{}.rs", self.crate_stem))
1265 }
1266
1267 fn output_path(&self, flavor: OutputType) -> PathBuf {
1270 let extension = flavor.extension();
1271 match flavor {
1272 OutputType::Metadata => {
1273 self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension))
1274 }
1275 _ => self.with_directory_and_extension(&self.out_directory, extension),
1276 }
1277 }
1278
1279 pub fn temp_path_for_cgu(
1283 &self,
1284 flavor: OutputType,
1285 codegen_unit_name: &str,
1286 invocation_temp: Option<&str>,
1287 ) -> PathBuf {
1288 let extension = flavor.extension();
1289 self.temp_path_ext_for_cgu(extension, codegen_unit_name, invocation_temp)
1290 }
1291
1292 pub fn temp_path_dwo_for_cgu(
1294 &self,
1295 codegen_unit_name: &str,
1296 invocation_temp: Option<&str>,
1297 ) -> PathBuf {
1298 let p = self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp);
1299 if let Some(dwo_out) = &self.explicit_dwo_out_directory {
1300 let mut o = dwo_out.clone();
1301 o.push(p.file_name().unwrap());
1302 o
1303 } else {
1304 p
1305 }
1306 }
1307
1308 pub fn temp_path_ext_for_cgu(
1311 &self,
1312 ext: &str,
1313 codegen_unit_name: &str,
1314 invocation_temp: Option<&str>,
1315 ) -> PathBuf {
1316 let mut extension = codegen_unit_name.to_string();
1317
1318 if let Some(rng) = invocation_temp {
1320 extension.push('.');
1321 extension.push_str(rng);
1322 }
1323
1324 if !ext.is_empty() {
1327 extension.push('.');
1328 extension.push_str(RUST_CGU_EXT);
1329 extension.push('.');
1330 extension.push_str(ext);
1331 }
1332
1333 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
1334 maybe_strip_file_name(self.with_directory_and_extension(temps_directory, &extension))
1335 }
1336
1337 pub fn temp_path_for_diagnostic(&self, ext: &str) -> PathBuf {
1338 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
1339 self.with_directory_and_extension(temps_directory, &ext)
1340 }
1341
1342 pub fn with_extension(&self, extension: &str) -> PathBuf {
1343 self.with_directory_and_extension(&self.out_directory, extension)
1344 }
1345
1346 pub fn with_directory_and_extension(&self, directory: &Path, extension: &str) -> PathBuf {
1347 let mut path = directory.join(&self.filestem);
1348 path.set_extension(extension);
1349 path
1350 }
1351
1352 pub fn split_dwarf_path(
1355 &self,
1356 split_debuginfo_kind: SplitDebuginfo,
1357 split_dwarf_kind: SplitDwarfKind,
1358 cgu_name: &str,
1359 invocation_temp: Option<&str>,
1360 ) -> Option<PathBuf> {
1361 let obj_out = self.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp);
1362 let dwo_out = self.temp_path_dwo_for_cgu(cgu_name, invocation_temp);
1363 match (split_debuginfo_kind, split_dwarf_kind) {
1364 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
1365 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
1369 Some(obj_out)
1370 }
1371 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
1373 Some(dwo_out)
1374 }
1375 }
1376 }
1377}
1378
1379bitflags::bitflags! {
1380 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1382 pub struct RemapPathScopeComponents: u8 {
1383 const MACRO = 1 << 0;
1385 const DIAGNOSTICS = 1 << 1;
1387 const DEBUGINFO = 1 << 3;
1389 const COVERAGE = 1 << 4;
1391
1392 const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits() | Self::COVERAGE.bits();
1395 }
1396}
1397
1398#[derive(Clone, Debug)]
1399pub struct Sysroot {
1400 pub explicit: Option<PathBuf>,
1401 pub default: PathBuf,
1402}
1403
1404impl Sysroot {
1405 pub fn new(explicit: Option<PathBuf>) -> Sysroot {
1406 Sysroot { explicit, default: filesearch::default_sysroot() }
1407 }
1408
1409 pub fn path(&self) -> &Path {
1411 self.explicit.as_deref().unwrap_or(&self.default)
1412 }
1413
1414 pub fn all_paths(&self) -> impl Iterator<Item = &Path> {
1416 self.explicit.as_deref().into_iter().chain(iter::once(&*self.default))
1417 }
1418}
1419
1420pub fn host_tuple() -> &'static str {
1421 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
1430}
1431
1432fn file_path_mapping(
1433 remap_path_prefix: Vec<(PathBuf, PathBuf)>,
1434 unstable_opts: &UnstableOptions,
1435) -> FilePathMapping {
1436 FilePathMapping::new(
1437 remap_path_prefix.clone(),
1438 if unstable_opts.remap_path_scope.contains(RemapPathScopeComponents::DIAGNOSTICS)
1439 && !remap_path_prefix.is_empty()
1440 {
1441 FileNameDisplayPreference::Remapped
1442 } else {
1443 FileNameDisplayPreference::Local
1444 },
1445 if unstable_opts.remap_path_scope.is_all() {
1446 FileNameEmbeddablePreference::RemappedOnly
1447 } else {
1448 FileNameEmbeddablePreference::LocalAndRemapped
1449 },
1450 )
1451}
1452
1453impl Default for Options {
1454 fn default() -> Options {
1455 Options {
1456 assert_incr_state: None,
1457 crate_types: Vec::new(),
1458 optimize: OptLevel::No,
1459 debuginfo: DebugInfo::None,
1460 debuginfo_compression: DebugInfoCompression::None,
1461 lint_opts: Vec::new(),
1462 lint_cap: None,
1463 describe_lints: false,
1464 output_types: OutputTypes(BTreeMap::new()),
1465 search_paths: vec![],
1466 sysroot: Sysroot::new(None),
1467 target_triple: TargetTuple::from_tuple(host_tuple()),
1468 test: false,
1469 incremental: None,
1470 untracked_state_hash: Default::default(),
1471 unstable_opts: Default::default(),
1472 prints: Vec::new(),
1473 cg: Default::default(),
1474 error_format: ErrorOutputType::default(),
1475 diagnostic_width: None,
1476 externs: Externs(BTreeMap::new()),
1477 crate_name: None,
1478 libs: Vec::new(),
1479 unstable_features: UnstableFeatures::Disallow,
1480 debug_assertions: true,
1481 actually_rustdoc: false,
1482 resolve_doc_links: ResolveDocLinks::None,
1483 trimmed_def_paths: false,
1484 cli_forced_codegen_units: None,
1485 cli_forced_local_thinlto_off: false,
1486 remap_path_prefix: Vec::new(),
1487 real_rust_source_base_dir: None,
1488 real_rustc_dev_source_base_dir: None,
1489 edition: DEFAULT_EDITION,
1490 json_artifact_notifications: false,
1491 json_timings: false,
1492 json_unused_externs: JsonUnusedExterns::No,
1493 json_future_incompat: false,
1494 pretty: None,
1495 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
1496 color: ColorConfig::Auto,
1497 logical_env: FxIndexMap::default(),
1498 verbose: false,
1499 target_modifiers: BTreeMap::default(),
1500 }
1501 }
1502}
1503
1504impl Options {
1505 pub fn build_dep_graph(&self) -> bool {
1507 self.incremental.is_some()
1508 || self.unstable_opts.dump_dep_graph
1509 || self.unstable_opts.query_dep_graph
1510 }
1511
1512 pub fn file_path_mapping(&self) -> FilePathMapping {
1513 file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts)
1514 }
1515
1516 pub fn will_create_output_file(&self) -> bool {
1518 !self.unstable_opts.parse_crate_root_only && self.unstable_opts.ls.is_empty() }
1521
1522 #[inline]
1523 pub fn share_generics(&self) -> bool {
1524 match self.unstable_opts.share_generics {
1525 Some(setting) => setting,
1526 None => match self.optimize {
1527 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
1528 OptLevel::More | OptLevel::Aggressive => false,
1529 },
1530 }
1531 }
1532
1533 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
1534 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
1535 }
1536
1537 #[inline]
1538 pub fn autodiff_enabled(&self) -> bool {
1539 self.unstable_opts.autodiff.contains(&AutoDiff::Enable)
1540 }
1541}
1542
1543impl UnstableOptions {
1544 pub fn dcx_flags(&self, can_emit_warnings: bool) -> DiagCtxtFlags {
1545 DiagCtxtFlags {
1546 can_emit_warnings,
1547 treat_err_as_bug: self.treat_err_as_bug,
1548 eagerly_emit_delayed_bugs: self.eagerly_emit_delayed_bugs,
1549 macro_backtrace: self.macro_backtrace,
1550 deduplicate_diagnostics: self.deduplicate_diagnostics,
1551 track_diagnostics: self.track_diagnostics,
1552 }
1553 }
1554
1555 pub fn src_hash_algorithm(&self, target: &Target) -> SourceFileHashAlgorithm {
1556 self.src_hash_algorithm.unwrap_or_else(|| {
1557 if target.is_like_msvc {
1558 SourceFileHashAlgorithm::Sha256
1559 } else {
1560 SourceFileHashAlgorithm::Md5
1561 }
1562 })
1563 }
1564
1565 pub fn checksum_hash_algorithm(&self) -> Option<SourceFileHashAlgorithm> {
1566 self.checksum_hash_algorithm
1567 }
1568}
1569
1570#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
1572pub enum EntryFnType {
1573 Main {
1574 sigpipe: u8,
1581 },
1582}
1583
1584#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
1585#[derive(HashStable_Generic)]
1586pub enum CrateType {
1587 Executable,
1588 Dylib,
1589 Rlib,
1590 Staticlib,
1591 Cdylib,
1592 ProcMacro,
1593 Sdylib,
1594}
1595
1596impl CrateType {
1597 pub fn has_metadata(self) -> bool {
1598 match self {
1599 CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
1600 CrateType::Executable
1601 | CrateType::Cdylib
1602 | CrateType::Staticlib
1603 | CrateType::Sdylib => false,
1604 }
1605 }
1606}
1607
1608#[derive(Clone, Hash, Debug, PartialEq, Eq)]
1609pub enum Passes {
1610 Some(Vec<String>),
1611 All,
1612}
1613
1614impl Passes {
1615 fn is_empty(&self) -> bool {
1616 match *self {
1617 Passes::Some(ref v) => v.is_empty(),
1618 Passes::All => false,
1619 }
1620 }
1621
1622 pub(crate) fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
1623 match *self {
1624 Passes::Some(ref mut v) => v.extend(passes),
1625 Passes::All => {}
1626 }
1627 }
1628}
1629
1630#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1631pub enum PAuthKey {
1632 A,
1633 B,
1634}
1635
1636#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1637pub struct PacRet {
1638 pub leaf: bool,
1639 pub pc: bool,
1640 pub key: PAuthKey,
1641}
1642
1643#[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
1644pub struct BranchProtection {
1645 pub bti: bool,
1646 pub pac_ret: Option<PacRet>,
1647 pub gcs: bool,
1648}
1649
1650pub(crate) const fn default_lib_output() -> CrateType {
1651 CrateType::Rlib
1652}
1653
1654pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
1655 cfg::disallow_cfgs(sess, &user_cfg);
1657
1658 user_cfg.extend(cfg::default_configuration(sess));
1661 user_cfg
1662}
1663
1664pub fn build_target_config(
1665 early_dcx: &EarlyDiagCtxt,
1666 target: &TargetTuple,
1667 sysroot: &Path,
1668) -> Target {
1669 match Target::search(target, sysroot) {
1670 Ok((target, warnings)) => {
1671 for warning in warnings.warning_messages() {
1672 early_dcx.early_warn(warning)
1673 }
1674
1675 if !matches!(target.pointer_width, 16 | 32 | 64) {
1676 early_dcx.early_fatal(format!(
1677 "target specification was invalid: unrecognized target-pointer-width {}",
1678 target.pointer_width
1679 ))
1680 }
1681 target
1682 }
1683 Err(e) => {
1684 let mut err =
1685 early_dcx.early_struct_fatal(format!("error loading target specification: {e}"));
1686 err.help("run `rustc --print target-list` for a list of built-in targets");
1687 err.emit();
1688 }
1689 }
1690}
1691
1692#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1693pub enum OptionStability {
1694 Stable,
1695 Unstable,
1696}
1697
1698#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1699pub enum OptionKind {
1700 Opt,
1704
1705 Multi,
1709
1710 Flag,
1715
1716 FlagMulti,
1721}
1722
1723pub struct RustcOptGroup {
1724 pub name: &'static str,
1732 stability: OptionStability,
1733 kind: OptionKind,
1734
1735 short_name: &'static str,
1736 long_name: &'static str,
1737 desc: &'static str,
1738 value_hint: &'static str,
1739
1740 pub is_verbose_help_only: bool,
1743}
1744
1745impl RustcOptGroup {
1746 pub fn is_stable(&self) -> bool {
1747 self.stability == OptionStability::Stable
1748 }
1749
1750 pub fn apply(&self, options: &mut getopts::Options) {
1751 let &Self { short_name, long_name, desc, value_hint, .. } = self;
1752 match self.kind {
1753 OptionKind::Opt => options.optopt(short_name, long_name, desc, value_hint),
1754 OptionKind::Multi => options.optmulti(short_name, long_name, desc, value_hint),
1755 OptionKind::Flag => options.optflag(short_name, long_name, desc),
1756 OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
1757 };
1758 }
1759
1760 pub fn long_name(&self) -> &str {
1762 self.long_name
1763 }
1764}
1765
1766pub fn make_opt(
1767 stability: OptionStability,
1768 kind: OptionKind,
1769 short_name: &'static str,
1770 long_name: &'static str,
1771 desc: &'static str,
1772 value_hint: &'static str,
1773) -> RustcOptGroup {
1774 match kind {
1776 OptionKind::Opt | OptionKind::Multi => {}
1777 OptionKind::Flag | OptionKind::FlagMulti => assert_eq!(value_hint, ""),
1778 }
1779 RustcOptGroup {
1780 name: cmp::max_by_key(short_name, long_name, |s| s.len()),
1781 stability,
1782 kind,
1783 short_name,
1784 long_name,
1785 desc,
1786 value_hint,
1787 is_verbose_help_only: false,
1788 }
1789}
1790
1791static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
1792 format!(
1793 "Specify which edition of the compiler to use when compiling code. \
1794The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
1795 )
1796});
1797
1798static PRINT_HELP: LazyLock<String> = LazyLock::new(|| {
1799 format!(
1800 "Compiler information to print on stdout (or to a file)\n\
1801 INFO may be one of <{}>.",
1802 PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::<Vec<_>>().join("|")
1803 )
1804});
1805
1806static EMIT_HELP: LazyLock<String> = LazyLock::new(|| {
1807 let mut result =
1808 String::from("Comma separated list of types of output for the compiler to emit.\n");
1809 result.push_str("Each TYPE has the default FILE name:\n");
1810
1811 for output in OutputType::iter_all() {
1812 result.push_str(&format!("* {} - {}\n", output.shorthand(), output.default_filename()));
1813 }
1814
1815 result
1816});
1817
1818pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1828 use OptionKind::{Flag, FlagMulti, Multi, Opt};
1829 use OptionStability::{Stable, Unstable};
1830
1831 use self::make_opt as opt;
1832
1833 let mut options = vec![
1834 opt(Stable, Flag, "h", "help", "Display this message", ""),
1835 opt(
1836 Stable,
1837 Multi,
1838 "",
1839 "cfg",
1840 "Configure the compilation environment.\n\
1841 SPEC supports the syntax `<NAME>[=\"<VALUE>\"]`.",
1842 "<SPEC>",
1843 ),
1844 opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "<SPEC>"),
1845 opt(
1846 Stable,
1847 Multi,
1848 "L",
1849 "",
1850 "Add a directory to the library search path. \
1851 The optional KIND can be one of <dependency|crate|native|framework|all> (default: all).",
1852 "[<KIND>=]<PATH>",
1853 ),
1854 opt(
1855 Stable,
1856 Multi,
1857 "l",
1858 "",
1859 "Link the generated crate(s) to the specified native\n\
1860 library NAME. The optional KIND can be one of\n\
1861 <static|framework|dylib> (default: dylib).\n\
1862 Optional comma separated MODIFIERS\n\
1863 <bundle|verbatim|whole-archive|as-needed>\n\
1864 may be specified each with a prefix of either '+' to\n\
1865 enable or '-' to disable.",
1866 "[<KIND>[:<MODIFIERS>]=]<NAME>[:<RENAME>]",
1867 ),
1868 make_crate_type_option(),
1869 opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "<NAME>"),
1870 opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST),
1871 opt(Stable, Multi, "", "emit", &EMIT_HELP, "<TYPE>[=<FILE>]"),
1872 opt(Stable, Multi, "", "print", &PRINT_HELP, "<INFO>[=<FILE>]"),
1873 opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""),
1874 opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""),
1875 opt(Stable, Opt, "o", "", "Write output to FILENAME", "<FILENAME>"),
1876 opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in DIR", "<DIR>"),
1877 opt(
1878 Stable,
1879 Opt,
1880 "",
1881 "explain",
1882 "Provide a detailed explanation of an error message",
1883 "<OPT>",
1884 ),
1885 opt(Stable, Flag, "", "test", "Build a test harness", ""),
1886 opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "<TARGET>"),
1887 opt(Stable, Multi, "A", "allow", "Set lint allowed", "<LINT>"),
1888 opt(Stable, Multi, "W", "warn", "Set lint warnings", "<LINT>"),
1889 opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "<LINT>"),
1890 opt(Stable, Multi, "D", "deny", "Set lint denied", "<LINT>"),
1891 opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "<LINT>"),
1892 opt(
1893 Stable,
1894 Multi,
1895 "",
1896 "cap-lints",
1897 "Set the most restrictive lint level. More restrictive lints are capped at this level",
1898 "<LEVEL>",
1899 ),
1900 opt(Stable, Multi, "C", "codegen", "Set a codegen option", "<OPT>[=<VALUE>]"),
1901 opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
1902 opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
1903 ];
1904
1905 let verbose_only = [
1908 opt(
1909 Stable,
1910 Multi,
1911 "",
1912 "extern",
1913 "Specify where an external rust library is located",
1914 "<NAME>[=<PATH>]",
1915 ),
1916 opt(Stable, Opt, "", "sysroot", "Override the system root", "<PATH>"),
1917 opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "<FLAG>"),
1918 opt(
1919 Stable,
1920 Opt,
1921 "",
1922 "error-format",
1923 "How errors and other messages are produced",
1924 "<human|json|short>",
1925 ),
1926 opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "<CONFIG>"),
1927 opt(
1928 Stable,
1929 Opt,
1930 "",
1931 "color",
1932 "Configure coloring of output:
1933 * auto = colorize, if output goes to a tty (default);
1934 * always = always colorize output;
1935 * never = never colorize output",
1936 "<auto|always|never>",
1937 ),
1938 opt(
1939 Stable,
1940 Opt,
1941 "",
1942 "diagnostic-width",
1943 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1944 "<WIDTH>",
1945 ),
1946 opt(
1947 Stable,
1948 Multi,
1949 "",
1950 "remap-path-prefix",
1951 "Remap source names in all output (compiler messages and output files)",
1952 "<FROM>=<TO>",
1953 ),
1954 opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "<VAR>=<VALUE>"),
1955 ];
1956 options.extend(verbose_only.into_iter().map(|mut opt| {
1957 opt.is_verbose_help_only = true;
1958 opt
1959 }));
1960
1961 options
1962}
1963
1964pub fn get_cmd_lint_options(
1965 early_dcx: &EarlyDiagCtxt,
1966 matches: &getopts::Matches,
1967) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1968 let mut lint_opts_with_position = vec![];
1969 let mut describe_lints = false;
1970
1971 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1972 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1973 if lint_name == "help" {
1974 describe_lints = true;
1975 } else {
1976 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1977 }
1978 }
1979 }
1980
1981 lint_opts_with_position.sort_by_key(|x| x.0);
1982 let lint_opts = lint_opts_with_position
1983 .iter()
1984 .cloned()
1985 .map(|(_, lint_name, level)| (lint_name, level))
1986 .collect();
1987
1988 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1989 lint::Level::from_str(&cap)
1990 .unwrap_or_else(|| early_dcx.early_fatal(format!("unknown lint level: `{cap}`")))
1991 });
1992
1993 (lint_opts, describe_lints, lint_cap)
1994}
1995
1996pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> ColorConfig {
1998 match matches.opt_str("color").as_deref() {
1999 Some("auto") => ColorConfig::Auto,
2000 Some("always") => ColorConfig::Always,
2001 Some("never") => ColorConfig::Never,
2002
2003 None => ColorConfig::Auto,
2004
2005 Some(arg) => early_dcx.early_fatal(format!(
2006 "argument for `--color` must be auto, \
2007 always or never (instead was `{arg}`)"
2008 )),
2009 }
2010}
2011
2012pub struct JsonConfig {
2014 pub json_rendered: HumanReadableErrorType,
2015 pub json_color: ColorConfig,
2016 json_artifact_notifications: bool,
2017 json_timings: bool,
2020 pub json_unused_externs: JsonUnusedExterns,
2021 json_future_incompat: bool,
2022}
2023
2024#[derive(Copy, Clone)]
2026pub enum JsonUnusedExterns {
2027 No,
2029 Silent,
2031 Loud,
2033}
2034
2035impl JsonUnusedExterns {
2036 pub fn is_enabled(&self) -> bool {
2037 match self {
2038 JsonUnusedExterns::No => false,
2039 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
2040 }
2041 }
2042
2043 pub fn is_loud(&self) -> bool {
2044 match self {
2045 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
2046 JsonUnusedExterns::Loud => true,
2047 }
2048 }
2049}
2050
2051pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
2056 let mut json_rendered = HumanReadableErrorType::Default;
2057 let mut json_color = ColorConfig::Never;
2058 let mut json_artifact_notifications = false;
2059 let mut json_unused_externs = JsonUnusedExterns::No;
2060 let mut json_future_incompat = false;
2061 let mut json_timings = false;
2062 for option in matches.opt_strs("json") {
2063 if matches.opt_str("color").is_some() {
2067 early_dcx.early_fatal("cannot specify the `--color` option with `--json`");
2068 }
2069
2070 for sub_option in option.split(',') {
2071 match sub_option {
2072 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
2073 "diagnostic-unicode" => {
2074 json_rendered = HumanReadableErrorType::Unicode;
2075 }
2076 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
2077 "artifacts" => json_artifact_notifications = true,
2078 "timings" => json_timings = true,
2079 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
2080 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
2081 "future-incompat" => json_future_incompat = true,
2082 s => early_dcx.early_fatal(format!("unknown `--json` option `{s}`")),
2083 }
2084 }
2085 }
2086
2087 JsonConfig {
2088 json_rendered,
2089 json_color,
2090 json_artifact_notifications,
2091 json_timings,
2092 json_unused_externs,
2093 json_future_incompat,
2094 }
2095}
2096
2097pub fn parse_error_format(
2099 early_dcx: &mut EarlyDiagCtxt,
2100 matches: &getopts::Matches,
2101 color_config: ColorConfig,
2102 json_color: ColorConfig,
2103 json_rendered: HumanReadableErrorType,
2104) -> ErrorOutputType {
2105 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
2110 match matches.opt_str("error-format").as_deref() {
2111 None | Some("human") => ErrorOutputType::HumanReadable { color_config, .. },
2112 Some("human-annotate-rs") => ErrorOutputType::HumanReadable {
2113 kind: HumanReadableErrorType::AnnotateSnippet,
2114 color_config,
2115 },
2116 Some("json") => {
2117 ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
2118 }
2119 Some("pretty-json") => {
2120 ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
2121 }
2122 Some("short") => {
2123 ErrorOutputType::HumanReadable { kind: HumanReadableErrorType::Short, color_config }
2124 }
2125 Some("human-unicode") => ErrorOutputType::HumanReadable {
2126 kind: HumanReadableErrorType::Unicode,
2127 color_config,
2128 },
2129 Some(arg) => {
2130 early_dcx.set_error_format(ErrorOutputType::HumanReadable { color_config, .. });
2131 early_dcx.early_fatal(format!(
2132 "argument for `--error-format` must be `human`, `human-annotate-rs`, \
2133 `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)"
2134 ))
2135 }
2136 }
2137 } else {
2138 ErrorOutputType::HumanReadable { color_config, .. }
2139 };
2140
2141 match error_format {
2142 ErrorOutputType::Json { .. } => {}
2143
2144 _ if !matches.opt_strs("json").is_empty() => {
2148 early_dcx.early_fatal("using `--json` requires also using `--error-format=json`");
2149 }
2150
2151 _ => {}
2152 }
2153
2154 error_format
2155}
2156
2157pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Edition {
2158 let edition = match matches.opt_str("edition") {
2159 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
2160 early_dcx.early_fatal(format!(
2161 "argument for `--edition` must be one of: \
2162 {EDITION_NAME_LIST}. (instead was `{arg}`)"
2163 ))
2164 }),
2165 None => DEFAULT_EDITION,
2166 };
2167
2168 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
2169 let is_nightly = nightly_options::match_is_nightly_build(matches);
2170 let msg = if !is_nightly {
2171 format!(
2172 "the crate requires edition {edition}, but the latest edition supported by this Rust version is {LATEST_STABLE_EDITION}"
2173 )
2174 } else {
2175 format!("edition {edition} is unstable and only available with -Z unstable-options")
2176 };
2177 early_dcx.early_fatal(msg)
2178 }
2179
2180 edition
2181}
2182
2183fn check_error_format_stability(
2184 early_dcx: &EarlyDiagCtxt,
2185 unstable_opts: &UnstableOptions,
2186 format: ErrorOutputType,
2187) {
2188 if unstable_opts.unstable_options {
2189 return;
2190 }
2191 let format = match format {
2192 ErrorOutputType::Json { pretty: true, .. } => "pretty-json",
2193 ErrorOutputType::HumanReadable { kind, .. } => match kind {
2194 HumanReadableErrorType::AnnotateSnippet => "human-annotate-rs",
2195 HumanReadableErrorType::Unicode => "human-unicode",
2196 _ => return,
2197 },
2198 _ => return,
2199 };
2200 early_dcx.early_fatal(format!("`--error-format={format}` is unstable"))
2201}
2202
2203fn parse_output_types(
2204 early_dcx: &EarlyDiagCtxt,
2205 unstable_opts: &UnstableOptions,
2206 matches: &getopts::Matches,
2207) -> OutputTypes {
2208 let mut output_types = BTreeMap::new();
2209 if !unstable_opts.parse_crate_root_only {
2210 for list in matches.opt_strs("emit") {
2211 for output_type in list.split(',') {
2212 let (shorthand, path) = split_out_file_name(output_type);
2213 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
2214 early_dcx.early_fatal(format!(
2215 "unknown emission type: `{shorthand}` - expected one of: {display}",
2216 display = OutputType::shorthands_display(),
2217 ))
2218 });
2219 if output_type == OutputType::ThinLinkBitcode && !unstable_opts.unstable_options {
2220 early_dcx.early_fatal(format!(
2221 "{} requested but -Zunstable-options not specified",
2222 OutputType::ThinLinkBitcode.shorthand()
2223 ));
2224 }
2225 output_types.insert(output_type, path);
2226 }
2227 }
2228 };
2229 if output_types.is_empty() {
2230 output_types.insert(OutputType::Exe, None);
2231 }
2232 OutputTypes(output_types)
2233}
2234
2235fn split_out_file_name(arg: &str) -> (&str, Option<OutFileName>) {
2236 match arg.split_once('=') {
2237 None => (arg, None),
2238 Some((kind, "-")) => (kind, Some(OutFileName::Stdout)),
2239 Some((kind, path)) => (kind, Some(OutFileName::Real(PathBuf::from(path)))),
2240 }
2241}
2242
2243fn should_override_cgus_and_disable_thinlto(
2244 early_dcx: &EarlyDiagCtxt,
2245 output_types: &OutputTypes,
2246 matches: &getopts::Matches,
2247 mut codegen_units: Option<usize>,
2248) -> (bool, Option<usize>) {
2249 let mut disable_local_thinlto = false;
2250 let incompatible: Vec<_> = output_types
2253 .0
2254 .iter()
2255 .map(|ot_path| ot_path.0)
2256 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2257 .map(|ot| ot.shorthand())
2258 .collect();
2259 if !incompatible.is_empty() {
2260 match codegen_units {
2261 Some(n) if n > 1 => {
2262 if matches.opt_present("o") {
2263 for ot in &incompatible {
2264 early_dcx.early_warn(format!(
2265 "`--emit={ot}` with `-o` incompatible with \
2266 `-C codegen-units=N` for N > 1",
2267 ));
2268 }
2269 early_dcx.early_warn("resetting to default -C codegen-units=1");
2270 codegen_units = Some(1);
2271 disable_local_thinlto = true;
2272 }
2273 }
2274 _ => {
2275 codegen_units = Some(1);
2276 disable_local_thinlto = true;
2277 }
2278 }
2279 }
2280
2281 if codegen_units == Some(0) {
2282 early_dcx.early_fatal("value for codegen units must be a positive non-zero integer");
2283 }
2284
2285 (disable_local_thinlto, codegen_units)
2286}
2287
2288fn collect_print_requests(
2289 early_dcx: &EarlyDiagCtxt,
2290 cg: &mut CodegenOptions,
2291 unstable_opts: &UnstableOptions,
2292 matches: &getopts::Matches,
2293) -> Vec<PrintRequest> {
2294 let mut prints = Vec::<PrintRequest>::new();
2295 if cg.target_cpu.as_deref() == Some("help") {
2296 prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout });
2297 cg.target_cpu = None;
2298 };
2299 if cg.target_feature == "help" {
2300 prints.push(PrintRequest { kind: PrintKind::TargetFeatures, out: OutFileName::Stdout });
2301 cg.target_feature = String::new();
2302 }
2303
2304 let mut printed_paths = FxHashSet::default();
2309
2310 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
2311 let (req, out) = split_out_file_name(&req);
2312
2313 let kind = if let Some((print_name, print_kind)) =
2314 PRINT_KINDS.iter().find(|&&(name, _)| name == req)
2315 {
2316 check_print_request_stability(early_dcx, unstable_opts, (print_name, *print_kind));
2317 *print_kind
2318 } else {
2319 let is_nightly = nightly_options::match_is_nightly_build(matches);
2320 emit_unknown_print_request_help(early_dcx, req, is_nightly)
2321 };
2322
2323 let out = out.unwrap_or(OutFileName::Stdout);
2324 if let OutFileName::Real(path) = &out {
2325 if !printed_paths.insert(path.clone()) {
2326 early_dcx.early_fatal(format!(
2327 "cannot print multiple outputs to the same path: {}",
2328 path.display(),
2329 ));
2330 }
2331 }
2332
2333 PrintRequest { kind, out }
2334 }));
2335
2336 prints
2337}
2338
2339fn check_print_request_stability(
2340 early_dcx: &EarlyDiagCtxt,
2341 unstable_opts: &UnstableOptions,
2342 (print_name, print_kind): (&str, PrintKind),
2343) {
2344 if !is_print_request_stable(print_kind) && !unstable_opts.unstable_options {
2345 early_dcx.early_fatal(format!(
2346 "the `-Z unstable-options` flag must also be passed to enable the `{print_name}` \
2347 print option"
2348 ));
2349 }
2350}
2351
2352fn is_print_request_stable(print_kind: PrintKind) -> bool {
2353 match print_kind {
2354 PrintKind::AllTargetSpecsJson
2355 | PrintKind::CheckCfg
2356 | PrintKind::CrateRootLintLevels
2357 | PrintKind::SupportedCrateTypes
2358 | PrintKind::TargetSpecJson
2359 | PrintKind::TargetSpecJsonSchema => false,
2360 _ => true,
2361 }
2362}
2363
2364fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str, is_nightly: bool) -> ! {
2365 let prints = PRINT_KINDS
2366 .iter()
2367 .filter_map(|(name, kind)| {
2368 if !is_nightly && !is_print_request_stable(*kind) {
2370 None
2371 } else {
2372 Some(format!("`{name}`"))
2373 }
2374 })
2375 .collect::<Vec<_>>();
2376 let prints = prints.join(", ");
2377
2378 let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`"));
2379 #[allow(rustc::diagnostic_outside_of_impl)]
2380 diag.help(format!("valid print requests are: {prints}"));
2381
2382 if req == "lints" {
2383 diag.help(format!("use `-Whelp` to print a list of lints"));
2384 }
2385
2386 diag.help(format!("for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information"));
2387 diag.emit()
2388}
2389
2390pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTuple {
2391 match matches.opt_str("target") {
2392 Some(target) if target.ends_with(".json") => {
2393 let path = Path::new(&target);
2394 TargetTuple::from_path(path).unwrap_or_else(|_| {
2395 early_dcx.early_fatal(format!("target file {path:?} does not exist"))
2396 })
2397 }
2398 Some(target) => TargetTuple::TargetTuple(target),
2399 _ => TargetTuple::from_tuple(host_tuple()),
2400 }
2401}
2402
2403fn parse_opt_level(
2404 early_dcx: &EarlyDiagCtxt,
2405 matches: &getopts::Matches,
2406 cg: &CodegenOptions,
2407) -> OptLevel {
2408 let max_o = matches.opt_positions("O").into_iter().max();
2415 let max_c = matches
2416 .opt_strs_pos("C")
2417 .into_iter()
2418 .flat_map(|(i, s)| {
2419 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
2421 })
2422 .max();
2423 if max_o > max_c {
2424 OptLevel::Aggressive
2425 } else {
2426 match cg.opt_level.as_ref() {
2427 "0" => OptLevel::No,
2428 "1" => OptLevel::Less,
2429 "2" => OptLevel::More,
2430 "3" => OptLevel::Aggressive,
2431 "s" => OptLevel::Size,
2432 "z" => OptLevel::SizeMin,
2433 arg => {
2434 early_dcx.early_fatal(format!(
2435 "optimization level needs to be \
2436 between 0-3, s or z (instead was `{arg}`)"
2437 ));
2438 }
2439 }
2440 }
2441}
2442
2443fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInfo {
2444 let max_g = matches.opt_positions("g").into_iter().max();
2445 let max_c = matches
2446 .opt_strs_pos("C")
2447 .into_iter()
2448 .flat_map(|(i, s)| {
2449 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
2451 })
2452 .max();
2453 if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
2454}
2455
2456fn parse_assert_incr_state(
2457 early_dcx: &EarlyDiagCtxt,
2458 opt_assertion: &Option<String>,
2459) -> Option<IncrementalStateAssertion> {
2460 match opt_assertion {
2461 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
2462 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
2463 Some(s) => {
2464 early_dcx.early_fatal(format!("unexpected incremental state assertion value: {s}"))
2465 }
2466 None => None,
2467 }
2468}
2469
2470pub fn parse_externs(
2471 early_dcx: &EarlyDiagCtxt,
2472 matches: &getopts::Matches,
2473 unstable_opts: &UnstableOptions,
2474) -> Externs {
2475 let is_unstable_enabled = unstable_opts.unstable_options;
2476 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2477 for arg in matches.opt_strs("extern") {
2478 let ExternOpt { crate_name: name, path, options } =
2479 split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit());
2480
2481 let entry = externs.entry(name.to_owned());
2482
2483 use std::collections::btree_map::Entry;
2484
2485 let entry = if let Some(path) = path {
2486 let path = CanonicalizedPath::new(path);
2488 match entry {
2489 Entry::Vacant(vacant) => {
2490 let files = BTreeSet::from_iter(iter::once(path));
2491 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2492 }
2493 Entry::Occupied(occupied) => {
2494 let ext_ent = occupied.into_mut();
2495 match ext_ent {
2496 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2497 files.insert(path);
2498 }
2499 ExternEntry {
2500 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2501 ..
2502 } => {
2503 let files = BTreeSet::from_iter(iter::once(path));
2505 *location = ExternLocation::ExactPaths(files);
2506 }
2507 }
2508 ext_ent
2509 }
2510 }
2511 } else {
2512 match entry {
2514 Entry::Vacant(vacant) => {
2515 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2516 }
2517 Entry::Occupied(occupied) => {
2518 occupied.into_mut()
2520 }
2521 }
2522 };
2523
2524 let mut is_private_dep = false;
2525 let mut add_prelude = true;
2526 let mut nounused_dep = false;
2527 let mut force = false;
2528 if let Some(opts) = options {
2529 if !is_unstable_enabled {
2530 early_dcx.early_fatal(
2531 "the `-Z unstable-options` flag must also be passed to \
2532 enable `--extern` options",
2533 );
2534 }
2535 for opt in opts.split(',') {
2536 match opt {
2537 "priv" => is_private_dep = true,
2538 "noprelude" => {
2539 if let ExternLocation::ExactPaths(_) = &entry.location {
2540 add_prelude = false;
2541 } else {
2542 early_dcx.early_fatal(
2543 "the `noprelude` --extern option requires a file path",
2544 );
2545 }
2546 }
2547 "nounused" => nounused_dep = true,
2548 "force" => force = true,
2549 _ => early_dcx.early_fatal(format!("unknown --extern option `{opt}`")),
2550 }
2551 }
2552 }
2553
2554 entry.is_private_dep |= is_private_dep;
2557 entry.nounused_dep |= nounused_dep;
2559 entry.force |= force;
2561 entry.add_prelude |= add_prelude;
2563 }
2564 Externs(externs)
2565}
2566
2567fn parse_remap_path_prefix(
2568 early_dcx: &EarlyDiagCtxt,
2569 matches: &getopts::Matches,
2570 unstable_opts: &UnstableOptions,
2571) -> Vec<(PathBuf, PathBuf)> {
2572 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2573 .opt_strs("remap-path-prefix")
2574 .into_iter()
2575 .map(|remap| match remap.rsplit_once('=') {
2576 None => {
2577 early_dcx.early_fatal("--remap-path-prefix must contain '=' between FROM and TO")
2578 }
2579 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2580 })
2581 .collect();
2582 match &unstable_opts.remap_cwd_prefix {
2583 Some(to) => match std::env::current_dir() {
2584 Ok(cwd) => mapping.push((cwd, to.clone())),
2585 Err(_) => (),
2586 },
2587 None => (),
2588 };
2589 mapping
2590}
2591
2592fn parse_logical_env(
2593 early_dcx: &EarlyDiagCtxt,
2594 matches: &getopts::Matches,
2595) -> FxIndexMap<String, String> {
2596 let mut vars = FxIndexMap::default();
2597
2598 for arg in matches.opt_strs("env-set") {
2599 if let Some((name, val)) = arg.split_once('=') {
2600 vars.insert(name.to_string(), val.to_string());
2601 } else {
2602 early_dcx.early_fatal(format!("`--env-set`: specify value for variable `{arg}`"));
2603 }
2604 }
2605
2606 vars
2607}
2608
2609#[allow(rustc::bad_opt_access)]
2611pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches) -> Options {
2612 let color = parse_color(early_dcx, matches);
2613
2614 let edition = parse_crate_edition(early_dcx, matches);
2615
2616 let JsonConfig {
2617 json_rendered,
2618 json_color,
2619 json_artifact_notifications,
2620 json_timings,
2621 json_unused_externs,
2622 json_future_incompat,
2623 } = parse_json(early_dcx, matches);
2624
2625 let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
2626
2627 early_dcx.set_error_format(error_format);
2628
2629 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2630 early_dcx.early_fatal("`--diagnostic-width` must be an positive integer");
2631 });
2632
2633 let unparsed_crate_types = matches.opt_strs("crate-type");
2634 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2635 .unwrap_or_else(|e| early_dcx.early_fatal(e));
2636
2637 let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
2638
2639 let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
2640 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
2641
2642 if !unstable_opts.unstable_options && json_timings {
2643 early_dcx.early_fatal("--json=timings is unstable and requires using `-Zunstable-options`");
2644 }
2645
2646 check_error_format_stability(early_dcx, &unstable_opts, error_format);
2647
2648 let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
2649
2650 let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
2651 let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2652 early_dcx,
2653 &output_types,
2654 matches,
2655 cg.codegen_units,
2656 );
2657
2658 if unstable_opts.threads == 0 {
2659 early_dcx.early_fatal("value for threads must be a positive non-zero integer");
2660 }
2661
2662 if unstable_opts.threads == parse::MAX_THREADS_CAP {
2663 early_dcx.early_warn(format!("number of threads was capped at {}", parse::MAX_THREADS_CAP));
2664 }
2665
2666 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2667
2668 let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state);
2669
2670 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2671 early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive");
2672 }
2673
2674 if unstable_opts.profile_sample_use.is_some()
2675 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2676 {
2677 early_dcx.early_fatal(
2678 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2679 );
2680 }
2681
2682 match cg.symbol_mangling_version {
2685 None | Some(SymbolManglingVersion::V0) => {}
2687
2688 Some(SymbolManglingVersion::Legacy) => {
2690 if !unstable_opts.unstable_options {
2691 early_dcx.early_fatal(
2692 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2693 );
2694 }
2695 }
2696 Some(SymbolManglingVersion::Hashed) => {
2697 if !unstable_opts.unstable_options {
2698 early_dcx.early_fatal(
2699 "`-C symbol-mangling-version=hashed` requires `-Z unstable-options`",
2700 );
2701 }
2702 }
2703 }
2704
2705 if cg.instrument_coverage != InstrumentCoverage::No {
2706 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2707 early_dcx.early_fatal(
2708 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2709 or `-C profile-generate`",
2710 );
2711 }
2712
2713 match cg.symbol_mangling_version {
2718 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2719 Some(SymbolManglingVersion::Legacy) => {
2720 early_dcx.early_warn(
2721 "-C instrument-coverage requires symbol mangling version `v0`, \
2722 but `-C symbol-mangling-version=legacy` was specified",
2723 );
2724 }
2725 Some(SymbolManglingVersion::V0) => {}
2726 Some(SymbolManglingVersion::Hashed) => {
2727 early_dcx.early_warn(
2728 "-C instrument-coverage requires symbol mangling version `v0`, \
2729 but `-C symbol-mangling-version=hashed` was specified",
2730 );
2731 }
2732 }
2733 }
2734
2735 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2736 unstable_opts.graphviz_font = graphviz_font;
2739 }
2740
2741 if !cg.embed_bitcode {
2742 match cg.lto {
2743 LtoCli::No | LtoCli::Unspecified => {}
2744 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
2745 early_dcx.early_fatal("options `-C embed-bitcode=no` and `-C lto` are incompatible")
2746 }
2747 }
2748 }
2749
2750 let unstable_options_enabled = nightly_options::is_unstable_enabled(matches);
2751 if !unstable_options_enabled && cg.force_frame_pointers == FramePointer::NonLeaf {
2752 early_dcx.early_fatal(
2753 "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
2754 and a nightly compiler",
2755 )
2756 }
2757
2758 if !nightly_options::is_unstable_enabled(matches)
2759 && unstable_opts.offload.contains(&Offload::Enable)
2760 {
2761 early_dcx.early_fatal(
2762 "`-Zoffload=Enable` also requires `-Zunstable-options` \
2763 and a nightly compiler",
2764 )
2765 }
2766
2767 let target_triple = parse_target_triple(early_dcx, matches);
2768
2769 if !unstable_options_enabled {
2772 if let Err(error) = cg.link_self_contained.check_unstable_variants(&target_triple) {
2773 early_dcx.early_fatal(error);
2774 }
2775
2776 if let Some(flavor) = cg.linker_flavor {
2777 if flavor.is_unstable() {
2778 early_dcx.early_fatal(format!(
2779 "the linker flavor `{}` is unstable, the `-Z unstable-options` \
2780 flag must also be passed to use the unstable values",
2781 flavor.desc()
2782 ));
2783 }
2784 }
2785 }
2786
2787 if let Some(erroneous_components) = cg.link_self_contained.check_consistency() {
2790 let names: String = erroneous_components
2791 .into_iter()
2792 .map(|c| c.as_str().unwrap())
2793 .intersperse(", ")
2794 .collect();
2795 early_dcx.early_fatal(format!(
2796 "some `-C link-self-contained` components were both enabled and disabled: {names}"
2797 ));
2798 }
2799
2800 let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches);
2801
2802 if unstable_opts.retpoline_external_thunk {
2804 unstable_opts.retpoline = true;
2805 target_modifiers.insert(
2806 OptionsTargetModifiers::UnstableOptions(UnstableOptionsTargetModifiers::retpoline),
2807 "true".to_string(),
2808 );
2809 }
2810
2811 let cg = cg;
2812
2813 let opt_level = parse_opt_level(early_dcx, matches, &cg);
2814 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2818 let debuginfo = select_debuginfo(matches, &cg);
2819 let debuginfo_compression = unstable_opts.debuginfo_compression;
2820
2821 if !unstable_options_enabled {
2822 if let Err(error) = cg.linker_features.check_unstable_variants(&target_triple) {
2823 early_dcx.early_fatal(error);
2824 }
2825 }
2826
2827 if !unstable_options_enabled && cg.panic == Some(PanicStrategy::ImmediateAbort) {
2828 early_dcx.early_fatal(
2829 "`-Cpanic=immediate-abort` requires `-Zunstable-options` and a nightly compiler",
2830 )
2831 }
2832
2833 let crate_name = matches.opt_str("crate-name");
2834 let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
2835 let libs = parse_native_libs(early_dcx, &unstable_opts, unstable_features, matches);
2837
2838 let test = matches.opt_present("test");
2839
2840 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2841 early_dcx.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
2842 }
2843
2844 if cg.remark.is_empty() && unstable_opts.remark_dir.is_some() {
2845 early_dcx
2846 .early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all");
2847 }
2848
2849 let externs = parse_externs(early_dcx, matches, &unstable_opts);
2850
2851 let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts);
2852
2853 let pretty = parse_pretty(early_dcx, &unstable_opts);
2854
2855 if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
2857 early_dcx.early_fatal("can't dump dependency graph without `-Z query-dep-graph`");
2858 }
2859
2860 let logical_env = parse_logical_env(early_dcx, matches);
2861
2862 let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from));
2863
2864 let real_source_base_dir = |suffix: &str, confirm: &str| {
2865 let mut candidate = sysroot.path().join(suffix);
2866 if let Ok(metadata) = candidate.symlink_metadata() {
2867 if metadata.file_type().is_symlink() {
2871 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2872 candidate = symlink_dest;
2873 }
2874 }
2875 }
2876
2877 candidate.join(confirm).is_file().then_some(candidate)
2879 };
2880
2881 let real_rust_source_base_dir =
2882 real_source_base_dir("lib/rustlib/src/rust", "library/std/src/lib.rs");
2884
2885 let real_rustc_dev_source_base_dir =
2886 real_source_base_dir("lib/rustlib/rustc-src/rust", "compiler/rustc/src/main.rs");
2888
2889 let search_paths: Vec<SearchPath> = {
2894 let mut seen_search_paths = FxHashSet::default();
2895 let search_path_matches: Vec<String> = matches.opt_strs("L");
2896 search_path_matches
2897 .iter()
2898 .filter(|p| seen_search_paths.insert(*p))
2899 .map(|path| {
2900 SearchPath::from_cli_opt(
2901 sysroot.path(),
2902 &target_triple,
2903 early_dcx,
2904 &path,
2905 unstable_opts.unstable_options,
2906 )
2907 })
2908 .collect()
2909 };
2910
2911 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2912 early_dcx.early_fatal(format!("Current directory is invalid: {e}"));
2913 });
2914
2915 let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts);
2916 let working_dir = file_mapping.to_real_filename(&working_dir);
2917
2918 let verbose = matches.opt_present("verbose") || unstable_opts.verbose_internals;
2919
2920 Options {
2921 assert_incr_state,
2922 crate_types,
2923 optimize: opt_level,
2924 debuginfo,
2925 debuginfo_compression,
2926 lint_opts,
2927 lint_cap,
2928 describe_lints,
2929 output_types,
2930 search_paths,
2931 sysroot,
2932 target_triple,
2933 test,
2934 incremental,
2935 untracked_state_hash: Default::default(),
2936 unstable_opts,
2937 prints,
2938 cg,
2939 error_format,
2940 diagnostic_width,
2941 externs,
2942 unstable_features,
2943 crate_name,
2944 libs,
2945 debug_assertions,
2946 actually_rustdoc: false,
2947 resolve_doc_links: ResolveDocLinks::ExportedMetadata,
2948 trimmed_def_paths: false,
2949 cli_forced_codegen_units: codegen_units,
2950 cli_forced_local_thinlto_off: disable_local_thinlto,
2951 remap_path_prefix,
2952 real_rust_source_base_dir,
2953 real_rustc_dev_source_base_dir,
2954 edition,
2955 json_artifact_notifications,
2956 json_timings,
2957 json_unused_externs,
2958 json_future_incompat,
2959 pretty,
2960 working_dir,
2961 color,
2962 logical_env,
2963 verbose,
2964 target_modifiers,
2965 }
2966}
2967
2968fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> Option<PpMode> {
2969 use PpMode::*;
2970
2971 let first = match unstable_opts.unpretty.as_deref()? {
2972 "normal" => Source(PpSourceMode::Normal),
2973 "identified" => Source(PpSourceMode::Identified),
2974 "expanded" => Source(PpSourceMode::Expanded),
2975 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2976 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2977 "ast-tree" => AstTree,
2978 "ast-tree,expanded" => AstTreeExpanded,
2979 "hir" => Hir(PpHirMode::Normal),
2980 "hir,identified" => Hir(PpHirMode::Identified),
2981 "hir,typed" => Hir(PpHirMode::Typed),
2982 "hir-tree" => HirTree,
2983 "thir-tree" => ThirTree,
2984 "thir-flat" => ThirFlat,
2985 "mir" => Mir,
2986 "stable-mir" => StableMir,
2987 "mir-cfg" => MirCFG,
2988 name => early_dcx.early_fatal(format!(
2989 "argument to `unpretty` must be one of `normal`, `identified`, \
2990 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2991 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2992 `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir`, `stable-mir`, or \
2993 `mir-cfg`; got {name}"
2994 )),
2995 };
2996 debug!("got unpretty option: {first:?}");
2997 Some(first)
2998}
2999
3000pub fn make_crate_type_option() -> RustcOptGroup {
3001 make_opt(
3002 OptionStability::Stable,
3003 OptionKind::Multi,
3004 "",
3005 "crate-type",
3006 "Comma separated list of types of crates
3007 for the compiler to emit",
3008 "<bin|lib|rlib|dylib|cdylib|staticlib|proc-macro>",
3009 )
3010}
3011
3012pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
3013 let mut crate_types: Vec<CrateType> = Vec::new();
3014 for unparsed_crate_type in &list_list {
3015 for part in unparsed_crate_type.split(',') {
3016 let new_part = match part {
3017 "lib" => default_lib_output(),
3018 "rlib" => CrateType::Rlib,
3019 "staticlib" => CrateType::Staticlib,
3020 "dylib" => CrateType::Dylib,
3021 "cdylib" => CrateType::Cdylib,
3022 "bin" => CrateType::Executable,
3023 "proc-macro" => CrateType::ProcMacro,
3024 "sdylib" => CrateType::Sdylib,
3025 _ => {
3026 return Err(format!(
3027 "unknown crate type: `{part}`, expected one of: \
3028 `lib`, `rlib`, `staticlib`, `dylib`, `cdylib`, `bin`, `proc-macro`",
3029 ));
3030 }
3031 };
3032 if !crate_types.contains(&new_part) {
3033 crate_types.push(new_part)
3034 }
3035 }
3036 }
3037
3038 Ok(crate_types)
3039}
3040
3041pub mod nightly_options {
3042 use rustc_feature::UnstableFeatures;
3043
3044 use super::{OptionStability, RustcOptGroup};
3045 use crate::EarlyDiagCtxt;
3046
3047 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
3048 match_is_nightly_build(matches)
3049 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
3050 }
3051
3052 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
3053 is_nightly_build(matches.opt_str("crate-name").as_deref())
3054 }
3055
3056 fn is_nightly_build(krate: Option<&str>) -> bool {
3057 UnstableFeatures::from_environment(krate).is_nightly_build()
3058 }
3059
3060 pub fn check_nightly_options(
3061 early_dcx: &EarlyDiagCtxt,
3062 matches: &getopts::Matches,
3063 flags: &[RustcOptGroup],
3064 ) {
3065 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
3066 let really_allows_unstable_options = match_is_nightly_build(matches);
3067 let mut nightly_options_on_stable = 0;
3068
3069 for opt in flags.iter() {
3070 if opt.stability == OptionStability::Stable {
3071 continue;
3072 }
3073 if !matches.opt_present(opt.name) {
3074 continue;
3075 }
3076 if opt.name != "Z" && !has_z_unstable_option {
3077 early_dcx.early_fatal(format!(
3078 "the `-Z unstable-options` flag must also be passed to enable \
3079 the flag `{}`",
3080 opt.name
3081 ));
3082 }
3083 if really_allows_unstable_options {
3084 continue;
3085 }
3086 match opt.stability {
3087 OptionStability::Unstable => {
3088 nightly_options_on_stable += 1;
3089 let msg = format!(
3090 "the option `{}` is only accepted on the nightly compiler",
3091 opt.name
3092 );
3093 let _ = early_dcx.early_err(msg);
3095 }
3096 OptionStability::Stable => {}
3097 }
3098 }
3099 if nightly_options_on_stable > 0 {
3100 early_dcx
3101 .early_help("consider switching to a nightly toolchain: `rustup default nightly`");
3102 early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
3103 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>");
3104 early_dcx.early_fatal(format!(
3105 "{} nightly option{} were parsed",
3106 nightly_options_on_stable,
3107 if nightly_options_on_stable > 1 { "s" } else { "" }
3108 ));
3109 }
3110 }
3111}
3112
3113impl fmt::Display for CrateType {
3114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3115 match *self {
3116 CrateType::Executable => "bin".fmt(f),
3117 CrateType::Dylib => "dylib".fmt(f),
3118 CrateType::Rlib => "rlib".fmt(f),
3119 CrateType::Staticlib => "staticlib".fmt(f),
3120 CrateType::Cdylib => "cdylib".fmt(f),
3121 CrateType::ProcMacro => "proc-macro".fmt(f),
3122 CrateType::Sdylib => "sdylib".fmt(f),
3123 }
3124 }
3125}
3126
3127impl IntoDiagArg for CrateType {
3128 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
3129 self.to_string().into_diag_arg(&mut None)
3130 }
3131}
3132
3133#[derive(Copy, Clone, PartialEq, Debug)]
3134pub enum PpSourceMode {
3135 Normal,
3137 Expanded,
3139 Identified,
3141 ExpandedIdentified,
3143 ExpandedHygiene,
3145}
3146
3147#[derive(Copy, Clone, PartialEq, Debug)]
3148pub enum PpHirMode {
3149 Normal,
3151 Identified,
3153 Typed,
3155}
3156
3157#[derive(Copy, Clone, PartialEq, Debug)]
3158pub enum PpMode {
3160 Source(PpSourceMode),
3163 AstTree,
3165 AstTreeExpanded,
3167 Hir(PpHirMode),
3169 HirTree,
3171 ThirTree,
3173 ThirFlat,
3175 Mir,
3177 MirCFG,
3179 StableMir,
3181}
3182
3183impl PpMode {
3184 pub fn needs_ast_map(&self) -> bool {
3185 use PpMode::*;
3186 use PpSourceMode::*;
3187 match *self {
3188 Source(Normal | Identified) | AstTree => false,
3189
3190 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
3191 | AstTreeExpanded
3192 | Hir(_)
3193 | HirTree
3194 | ThirTree
3195 | ThirFlat
3196 | Mir
3197 | MirCFG
3198 | StableMir => true,
3199 }
3200 }
3201
3202 pub fn needs_analysis(&self) -> bool {
3203 use PpMode::*;
3204 matches!(*self, Hir(PpHirMode::Typed) | Mir | StableMir | MirCFG | ThirTree | ThirFlat)
3205 }
3206}
3207
3208#[derive(Clone, Hash, PartialEq, Eq, Debug)]
3209pub enum WasiExecModel {
3210 Command,
3211 Reactor,
3212}
3213
3214pub(crate) mod dep_tracking {
3233 use std::collections::BTreeMap;
3234 use std::hash::Hash;
3235 use std::num::NonZero;
3236 use std::path::PathBuf;
3237
3238 use rustc_abi::Align;
3239 use rustc_data_structures::fx::FxIndexMap;
3240 use rustc_data_structures::stable_hasher::StableHasher;
3241 use rustc_errors::LanguageIdentifier;
3242 use rustc_feature::UnstableFeatures;
3243 use rustc_hashes::Hash64;
3244 use rustc_span::RealFileName;
3245 use rustc_span::edition::Edition;
3246 use rustc_target::spec::{
3247 CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
3248 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple,
3249 TlsModel,
3250 };
3251
3252 use super::{
3253 AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
3254 CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
3255 InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
3256 LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OomStrategy, OptLevel, OutFileName,
3257 OutputType, OutputTypes, PatchableFunctionEntry, Polonius, RemapPathScopeComponents,
3258 ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
3259 SymbolManglingVersion, WasiExecModel,
3260 };
3261 use crate::lint;
3262 use crate::utils::NativeLib;
3263
3264 pub(crate) trait DepTrackingHash {
3265 fn hash(
3266 &self,
3267 hasher: &mut StableHasher,
3268 error_format: ErrorOutputType,
3269 for_crate_hash: bool,
3270 );
3271 }
3272
3273 macro_rules! impl_dep_tracking_hash_via_hash {
3274 ($($t:ty),+ $(,)?) => {$(
3275 impl DepTrackingHash for $t {
3276 fn hash(&self, hasher: &mut StableHasher, _: ErrorOutputType, _for_crate_hash: bool) {
3277 Hash::hash(self, hasher);
3278 }
3279 }
3280 )+};
3281 }
3282
3283 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
3284 fn hash(
3285 &self,
3286 hasher: &mut StableHasher,
3287 error_format: ErrorOutputType,
3288 for_crate_hash: bool,
3289 ) {
3290 match self {
3291 Some(x) => {
3292 Hash::hash(&1, hasher);
3293 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
3294 }
3295 None => Hash::hash(&0, hasher),
3296 }
3297 }
3298 }
3299
3300 impl_dep_tracking_hash_via_hash!(
3301 (),
3302 AutoDiff,
3303 Offload,
3304 bool,
3305 usize,
3306 NonZero<usize>,
3307 u64,
3308 Hash64,
3309 String,
3310 PathBuf,
3311 lint::Level,
3312 WasiExecModel,
3313 u32,
3314 FramePointer,
3315 RelocModel,
3316 CodeModel,
3317 TlsModel,
3318 InstrumentCoverage,
3319 CoverageOptions,
3320 InstrumentXRay,
3321 CrateType,
3322 MergeFunctions,
3323 OnBrokenPipe,
3324 PanicStrategy,
3325 RelroLevel,
3326 OptLevel,
3327 LtoCli,
3328 DebugInfo,
3329 DebugInfoCompression,
3330 MirStripDebugInfo,
3331 CollapseMacroDebuginfo,
3332 UnstableFeatures,
3333 NativeLib,
3334 SanitizerSet,
3335 CFGuard,
3336 CFProtection,
3337 TargetTuple,
3338 Edition,
3339 LinkerPluginLto,
3340 ResolveDocLinks,
3341 SplitDebuginfo,
3342 SplitDwarfKind,
3343 StackProtector,
3344 SwitchWithOptPath,
3345 SymbolManglingVersion,
3346 SymbolVisibility,
3347 RemapPathScopeComponents,
3348 SourceFileHashAlgorithm,
3349 OutFileName,
3350 OutputType,
3351 RealFileName,
3352 LocationDetail,
3353 FmtDebug,
3354 BranchProtection,
3355 OomStrategy,
3356 LanguageIdentifier,
3357 NextSolverConfig,
3358 PatchableFunctionEntry,
3359 Polonius,
3360 InliningThreshold,
3361 FunctionReturn,
3362 Align,
3363 );
3364
3365 impl<T1, T2> DepTrackingHash for (T1, T2)
3366 where
3367 T1: DepTrackingHash,
3368 T2: DepTrackingHash,
3369 {
3370 fn hash(
3371 &self,
3372 hasher: &mut StableHasher,
3373 error_format: ErrorOutputType,
3374 for_crate_hash: bool,
3375 ) {
3376 Hash::hash(&0, hasher);
3377 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3378 Hash::hash(&1, hasher);
3379 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3380 }
3381 }
3382
3383 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
3384 where
3385 T1: DepTrackingHash,
3386 T2: DepTrackingHash,
3387 T3: DepTrackingHash,
3388 {
3389 fn hash(
3390 &self,
3391 hasher: &mut StableHasher,
3392 error_format: ErrorOutputType,
3393 for_crate_hash: bool,
3394 ) {
3395 Hash::hash(&0, hasher);
3396 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3397 Hash::hash(&1, hasher);
3398 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3399 Hash::hash(&2, hasher);
3400 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
3401 }
3402 }
3403
3404 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
3405 fn hash(
3406 &self,
3407 hasher: &mut StableHasher,
3408 error_format: ErrorOutputType,
3409 for_crate_hash: bool,
3410 ) {
3411 Hash::hash(&self.len(), hasher);
3412 for (index, elem) in self.iter().enumerate() {
3413 Hash::hash(&index, hasher);
3414 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
3415 }
3416 }
3417 }
3418
3419 impl<T: DepTrackingHash, V: DepTrackingHash> DepTrackingHash for FxIndexMap<T, V> {
3420 fn hash(
3421 &self,
3422 hasher: &mut StableHasher,
3423 error_format: ErrorOutputType,
3424 for_crate_hash: bool,
3425 ) {
3426 Hash::hash(&self.len(), hasher);
3427 for (key, value) in self.iter() {
3428 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3429 DepTrackingHash::hash(value, hasher, error_format, for_crate_hash);
3430 }
3431 }
3432 }
3433
3434 impl DepTrackingHash for OutputTypes {
3435 fn hash(
3436 &self,
3437 hasher: &mut StableHasher,
3438 error_format: ErrorOutputType,
3439 for_crate_hash: bool,
3440 ) {
3441 Hash::hash(&self.0.len(), hasher);
3442 for (key, val) in &self.0 {
3443 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3444 if !for_crate_hash {
3445 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
3446 }
3447 }
3448 }
3449 }
3450
3451 pub(crate) fn stable_hash(
3453 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
3454 hasher: &mut StableHasher,
3455 error_format: ErrorOutputType,
3456 for_crate_hash: bool,
3457 ) {
3458 for (key, sub_hash) in sub_hashes {
3459 Hash::hash(&key.len(), hasher);
3462 Hash::hash(key, hasher);
3463 sub_hash.hash(hasher, error_format, for_crate_hash);
3464 }
3465 }
3466}
3467
3468#[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
3470pub enum OomStrategy {
3471 Panic,
3473
3474 Abort,
3476}
3477
3478impl OomStrategy {
3479 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic_v2";
3480
3481 pub fn should_panic(self) -> u8 {
3482 match self {
3483 OomStrategy::Panic => 1,
3484 OomStrategy::Abort => 0,
3485 }
3486 }
3487}
3488
3489#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3491pub enum ProcMacroExecutionStrategy {
3492 SameThread,
3494
3495 CrossThread,
3497}
3498
3499#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3507pub enum CollapseMacroDebuginfo {
3508 No = 0,
3510 Unspecified = 1,
3512 External = 2,
3514 Yes = 3,
3516}
3517
3518#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3520pub enum DumpMonoStatsFormat {
3521 Markdown,
3523 Json,
3525}
3526
3527impl DumpMonoStatsFormat {
3528 pub fn extension(self) -> &'static str {
3529 match self {
3530 Self::Markdown => "md",
3531 Self::Json => "json",
3532 }
3533 }
3534}
3535
3536#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3539pub struct PatchableFunctionEntry {
3540 prefix: u8,
3542 entry: u8,
3544}
3545
3546impl PatchableFunctionEntry {
3547 pub fn from_total_and_prefix_nops(
3548 total_nops: u8,
3549 prefix_nops: u8,
3550 ) -> Option<PatchableFunctionEntry> {
3551 if total_nops < prefix_nops {
3552 None
3553 } else {
3554 Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops })
3555 }
3556 }
3557 pub fn prefix(&self) -> u8 {
3558 self.prefix
3559 }
3560 pub fn entry(&self) -> u8 {
3561 self.entry
3562 }
3563}
3564
3565#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3568pub enum Polonius {
3569 #[default]
3571 Off,
3572
3573 Legacy,
3575
3576 Next,
3578}
3579
3580impl Polonius {
3581 pub fn is_legacy_enabled(&self) -> bool {
3583 matches!(self, Polonius::Legacy)
3584 }
3585
3586 pub fn is_next_enabled(&self) -> bool {
3588 matches!(self, Polonius::Next)
3589 }
3590}
3591
3592#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3593pub enum InliningThreshold {
3594 Always,
3595 Sometimes(usize),
3596 Never,
3597}
3598
3599impl Default for InliningThreshold {
3600 fn default() -> Self {
3601 Self::Sometimes(100)
3602 }
3603}
3604
3605#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3607pub enum FunctionReturn {
3608 #[default]
3610 Keep,
3611
3612 ThunkExtern,
3614}
3615
3616#[derive(Clone, Copy, Default, PartialEq, Debug)]
3619pub enum MirIncludeSpans {
3620 Off,
3621 On,
3622 #[default]
3625 Nll,
3626}
3627
3628impl MirIncludeSpans {
3629 pub fn is_enabled(self) -> bool {
3634 self == MirIncludeSpans::On
3635 }
3636}