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