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