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