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