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