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