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 rustc_data_structures::fx::{FxHashSet, FxIndexMap};
18use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
19use rustc_errors::emitter::HumanReadableErrorType;
20use rustc_errors::{ColorConfig, DiagArgValue, DiagCtxtFlags, IntoDiagArg};
21use rustc_feature::UnstableFeatures;
22use rustc_macros::{Decodable, Encodable, HashStable_Generic};
23use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION};
24use rustc_span::source_map::FilePathMapping;
25use rustc_span::{
26 FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm, Symbol, sym,
27};
28use rustc_target::spec::{
29 FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple,
30};
31use tracing::debug;
32
33pub use crate::config::cfg::{Cfg, CheckCfg, ExpectedValues};
34use crate::config::native_libs::parse_native_libs;
35use crate::errors::FileWriteFail;
36pub use crate::options::*;
37use crate::search_paths::SearchPath;
38use crate::utils::CanonicalizedPath;
39use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint};
40
41mod cfg;
42mod native_libs;
43pub mod sigpipe;
44
45pub const PRINT_KINDS: &[(&str, PrintKind)] = &[
46 ("all-target-specs-json", PrintKind::AllTargetSpecsJson),
48 ("calling-conventions", PrintKind::CallingConventions),
49 ("cfg", PrintKind::Cfg),
50 ("check-cfg", PrintKind::CheckCfg),
51 ("code-models", PrintKind::CodeModels),
52 ("crate-name", PrintKind::CrateName),
53 ("deployment-target", PrintKind::DeploymentTarget),
54 ("file-names", PrintKind::FileNames),
55 ("host-tuple", PrintKind::HostTuple),
56 ("link-args", PrintKind::LinkArgs),
57 ("native-static-libs", PrintKind::NativeStaticLibs),
58 ("relocation-models", PrintKind::RelocationModels),
59 ("split-debuginfo", PrintKind::SplitDebuginfo),
60 ("stack-protector-strategies", PrintKind::StackProtectorStrategies),
61 ("supported-crate-types", PrintKind::SupportedCrateTypes),
62 ("sysroot", PrintKind::Sysroot),
63 ("target-cpus", PrintKind::TargetCPUs),
64 ("target-features", PrintKind::TargetFeatures),
65 ("target-libdir", PrintKind::TargetLibdir),
66 ("target-list", PrintKind::TargetList),
67 ("target-spec-json", PrintKind::TargetSpecJson),
68 ("tls-models", PrintKind::TlsModels),
69 ];
71
72#[derive(Clone, Copy, PartialEq, Hash, Debug)]
74pub enum Strip {
75 None,
77
78 Debuginfo,
80
81 Symbols,
83}
84
85#[derive(Clone, Copy, PartialEq, Hash, Debug)]
87pub enum CFGuard {
88 Disabled,
90
91 NoChecks,
93
94 Checks,
96}
97
98#[derive(Clone, Copy, PartialEq, Hash, Debug)]
100pub enum CFProtection {
101 None,
103
104 Branch,
106
107 Return,
109
110 Full,
112}
113
114#[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
115pub enum OptLevel {
116 No,
118 Less,
120 More,
122 Aggressive,
124 Size,
126 SizeMin,
128}
129
130#[derive(Clone, PartialEq)]
135pub enum Lto {
136 No,
138
139 Thin,
141
142 ThinLocal,
145
146 Fat,
148}
149
150#[derive(Clone, Copy, PartialEq, Hash, Debug)]
152pub enum LtoCli {
153 No,
155 Yes,
157 NoParam,
159 Thin,
161 Fat,
163 Unspecified,
165}
166
167#[derive(Clone, Copy, PartialEq, Hash, Debug)]
169pub enum InstrumentCoverage {
170 No,
172 Yes,
174}
175
176#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
178pub struct CoverageOptions {
179 pub level: CoverageLevel,
180
181 pub no_mir_spans: bool,
188
189 pub discard_all_spans_in_codegen: bool,
194}
195
196#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
198pub enum CoverageLevel {
199 #[default]
201 Block,
202 Branch,
204 Condition,
220 Mcdc,
223}
224
225#[derive(Clone, Copy, PartialEq, Hash, Debug)]
227pub enum AutoDiff {
228 Enable,
230
231 PrintTA,
233 PrintAA,
235 PrintPerf,
237 PrintSteps,
239 PrintModBefore,
241 PrintModAfter,
243
244 LooseTypes,
247 Inline,
249}
250
251#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
253pub struct InstrumentXRay {
254 pub always: bool,
256 pub never: bool,
258 pub ignore_loops: bool,
261 pub instruction_threshold: Option<usize>,
264 pub skip_entry: bool,
266 pub skip_exit: bool,
268}
269
270#[derive(Clone, PartialEq, Hash, Debug)]
271pub enum LinkerPluginLto {
272 LinkerPlugin(PathBuf),
273 LinkerPluginAuto,
274 Disabled,
275}
276
277impl LinkerPluginLto {
278 pub fn enabled(&self) -> bool {
279 match *self {
280 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
281 LinkerPluginLto::Disabled => false,
282 }
283 }
284}
285
286#[derive(Default, Clone, PartialEq, Debug)]
302pub struct LinkSelfContained {
303 pub explicitly_set: Option<bool>,
306
307 enabled_components: LinkSelfContainedComponents,
310
311 disabled_components: LinkSelfContainedComponents,
314}
315
316impl LinkSelfContained {
317 pub(crate) fn handle_cli_component(&mut self, component: &str) -> Option<()> {
320 if let Some(component_to_enable) = component.strip_prefix('+') {
325 self.explicitly_set = None;
326 self.enabled_components
327 .insert(LinkSelfContainedComponents::from_str(component_to_enable)?);
328 Some(())
329 } else if let Some(component_to_disable) = component.strip_prefix('-') {
330 self.explicitly_set = None;
331 self.disabled_components
332 .insert(LinkSelfContainedComponents::from_str(component_to_disable)?);
333 Some(())
334 } else {
335 None
336 }
337 }
338
339 pub(crate) fn set_all_explicitly(&mut self, enabled: bool) {
342 self.explicitly_set = Some(enabled);
343
344 if enabled {
345 self.enabled_components = LinkSelfContainedComponents::all();
346 self.disabled_components = LinkSelfContainedComponents::empty();
347 } else {
348 self.enabled_components = LinkSelfContainedComponents::empty();
349 self.disabled_components = LinkSelfContainedComponents::all();
350 }
351 }
352
353 pub fn on() -> Self {
355 let mut on = LinkSelfContained::default();
356 on.set_all_explicitly(true);
357 on
358 }
359
360 fn are_unstable_variants_set(&self) -> bool {
364 let any_component_set =
365 !self.enabled_components.is_empty() || !self.disabled_components.is_empty();
366 self.explicitly_set.is_none() && any_component_set
367 }
368
369 pub fn is_linker_enabled(&self) -> bool {
372 self.enabled_components.contains(LinkSelfContainedComponents::LINKER)
373 }
374
375 pub fn is_linker_disabled(&self) -> bool {
378 self.disabled_components.contains(LinkSelfContainedComponents::LINKER)
379 }
380
381 fn check_consistency(&self) -> Option<LinkSelfContainedComponents> {
384 if self.explicitly_set.is_some() {
385 None
386 } else {
387 let common = self.enabled_components.intersection(self.disabled_components);
388 if common.is_empty() { None } else { Some(common) }
389 }
390 }
391}
392
393#[derive(Default, Copy, Clone, PartialEq, Debug)]
402pub struct LinkerFeaturesCli {
403 pub enabled: LinkerFeatures,
405
406 pub disabled: LinkerFeatures,
408}
409
410impl LinkerFeaturesCli {
411 pub(crate) fn handle_cli_feature(&mut self, feature: &str) -> Option<()> {
414 match feature {
420 "+lld" => {
421 self.enabled.insert(LinkerFeatures::LLD);
422 self.disabled.remove(LinkerFeatures::LLD);
423 Some(())
424 }
425 "-lld" => {
426 self.disabled.insert(LinkerFeatures::LLD);
427 self.enabled.remove(LinkerFeatures::LLD);
428 Some(())
429 }
430 _ => None,
431 }
432 }
433}
434
435#[derive(Clone, Copy, PartialEq, Hash, Debug)]
437pub enum IncrementalStateAssertion {
438 Loaded,
443 NotLoaded,
445}
446
447#[derive(Copy, Clone, PartialEq, Hash, Debug)]
449pub struct LocationDetail {
450 pub file: bool,
451 pub line: bool,
452 pub column: bool,
453}
454
455impl LocationDetail {
456 pub(crate) fn all() -> Self {
457 Self { file: true, line: true, column: true }
458 }
459}
460
461#[derive(Copy, Clone, PartialEq, Hash, Debug)]
463pub enum FmtDebug {
464 Full,
466 Shallow,
468 None,
470}
471
472impl FmtDebug {
473 pub(crate) fn all() -> [Symbol; 3] {
474 [sym::full, sym::none, sym::shallow]
475 }
476}
477
478#[derive(Clone, PartialEq, Hash, Debug)]
479pub enum SwitchWithOptPath {
480 Enabled(Option<PathBuf>),
481 Disabled,
482}
483
484impl SwitchWithOptPath {
485 pub fn enabled(&self) -> bool {
486 match *self {
487 SwitchWithOptPath::Enabled(_) => true,
488 SwitchWithOptPath::Disabled => false,
489 }
490 }
491}
492
493#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
494#[derive(Encodable, Decodable)]
495pub enum SymbolManglingVersion {
496 Legacy,
497 V0,
498 Hashed,
499}
500
501#[derive(Clone, Copy, Debug, PartialEq, Hash)]
502pub enum DebugInfo {
503 None,
504 LineDirectivesOnly,
505 LineTablesOnly,
506 Limited,
507 Full,
508}
509
510#[derive(Clone, Copy, Debug, PartialEq, Hash)]
511pub enum DebugInfoCompression {
512 None,
513 Zlib,
514 Zstd,
515}
516
517impl ToString for DebugInfoCompression {
518 fn to_string(&self) -> String {
519 match self {
520 DebugInfoCompression::None => "none",
521 DebugInfoCompression::Zlib => "zlib",
522 DebugInfoCompression::Zstd => "zstd",
523 }
524 .to_owned()
525 }
526}
527
528#[derive(Clone, Copy, Debug, PartialEq, Hash)]
529pub enum MirStripDebugInfo {
530 None,
531 LocalsInTinyFunctions,
532 AllLocals,
533}
534
535#[derive(Clone, Copy, Debug, PartialEq, Hash)]
545pub enum SplitDwarfKind {
546 Single,
549 Split,
552}
553
554impl FromStr for SplitDwarfKind {
555 type Err = ();
556
557 fn from_str(s: &str) -> Result<Self, ()> {
558 Ok(match s {
559 "single" => SplitDwarfKind::Single,
560 "split" => SplitDwarfKind::Split,
561 _ => return Err(()),
562 })
563 }
564}
565
566#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
567#[derive(Encodable, Decodable)]
568pub enum OutputType {
569 Bitcode,
572 ThinLinkBitcode,
574 Assembly,
575 LlvmAssembly,
576 Mir,
577 Metadata,
578 Object,
579 Exe,
580 DepInfo,
581}
582
583impl StableOrd for OutputType {
584 const CAN_USE_UNSTABLE_SORT: bool = true;
585
586 const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
588}
589
590impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
591 type KeyType = Self;
592
593 fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
594 *self
595 }
596}
597
598impl OutputType {
599 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
600 match *self {
601 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
602 OutputType::Bitcode
603 | OutputType::ThinLinkBitcode
604 | OutputType::Assembly
605 | OutputType::LlvmAssembly
606 | OutputType::Mir
607 | OutputType::Object => false,
608 }
609 }
610
611 pub fn shorthand(&self) -> &'static str {
612 match *self {
613 OutputType::Bitcode => "llvm-bc",
614 OutputType::ThinLinkBitcode => "thin-link-bitcode",
615 OutputType::Assembly => "asm",
616 OutputType::LlvmAssembly => "llvm-ir",
617 OutputType::Mir => "mir",
618 OutputType::Object => "obj",
619 OutputType::Metadata => "metadata",
620 OutputType::Exe => "link",
621 OutputType::DepInfo => "dep-info",
622 }
623 }
624
625 fn from_shorthand(shorthand: &str) -> Option<Self> {
626 Some(match shorthand {
627 "asm" => OutputType::Assembly,
628 "llvm-ir" => OutputType::LlvmAssembly,
629 "mir" => OutputType::Mir,
630 "llvm-bc" => OutputType::Bitcode,
631 "thin-link-bitcode" => OutputType::ThinLinkBitcode,
632 "obj" => OutputType::Object,
633 "metadata" => OutputType::Metadata,
634 "link" => OutputType::Exe,
635 "dep-info" => OutputType::DepInfo,
636 _ => return None,
637 })
638 }
639
640 fn shorthands_display() -> String {
641 format!(
642 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
643 OutputType::Bitcode.shorthand(),
644 OutputType::ThinLinkBitcode.shorthand(),
645 OutputType::Assembly.shorthand(),
646 OutputType::LlvmAssembly.shorthand(),
647 OutputType::Mir.shorthand(),
648 OutputType::Object.shorthand(),
649 OutputType::Metadata.shorthand(),
650 OutputType::Exe.shorthand(),
651 OutputType::DepInfo.shorthand(),
652 )
653 }
654
655 pub fn extension(&self) -> &'static str {
656 match *self {
657 OutputType::Bitcode => "bc",
658 OutputType::ThinLinkBitcode => "indexing.o",
659 OutputType::Assembly => "s",
660 OutputType::LlvmAssembly => "ll",
661 OutputType::Mir => "mir",
662 OutputType::Object => "o",
663 OutputType::Metadata => "rmeta",
664 OutputType::DepInfo => "d",
665 OutputType::Exe => "",
666 }
667 }
668
669 pub fn is_text_output(&self) -> bool {
670 match *self {
671 OutputType::Assembly
672 | OutputType::LlvmAssembly
673 | OutputType::Mir
674 | OutputType::DepInfo => true,
675 OutputType::Bitcode
676 | OutputType::ThinLinkBitcode
677 | OutputType::Object
678 | OutputType::Metadata
679 | OutputType::Exe => false,
680 }
681 }
682}
683
684#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
686pub enum ErrorOutputType {
687 #[default]
689 HumanReadable {
690 kind: HumanReadableErrorType = HumanReadableErrorType::Default,
691 color_config: ColorConfig = ColorConfig::Auto,
692 },
693 Json {
695 pretty: bool,
697 json_rendered: HumanReadableErrorType,
700 color_config: ColorConfig,
701 },
702}
703
704#[derive(Clone, Hash, Debug)]
705pub enum ResolveDocLinks {
706 None,
708 ExportedMetadata,
710 Exported,
712 All,
714}
715
716#[derive(Clone, Debug, Hash, HashStable_Generic, Encodable, Decodable)]
721pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>);
722
723impl OutputTypes {
724 pub fn new(entries: &[(OutputType, Option<OutFileName>)]) -> OutputTypes {
725 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
726 }
727
728 pub(crate) fn get(&self, key: &OutputType) -> Option<&Option<OutFileName>> {
729 self.0.get(key)
730 }
731
732 pub fn contains_key(&self, key: &OutputType) -> bool {
733 self.0.contains_key(key)
734 }
735
736 pub fn contains_explicit_name(&self, key: &OutputType) -> bool {
738 matches!(self.0.get(key), Some(Some(..)))
739 }
740
741 pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> {
742 self.0.iter()
743 }
744
745 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<OutFileName>> {
746 self.0.keys()
747 }
748
749 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<OutFileName>> {
750 self.0.values()
751 }
752
753 pub fn len(&self) -> usize {
754 self.0.len()
755 }
756
757 pub fn should_codegen(&self) -> bool {
759 self.0.keys().any(|k| match *k {
760 OutputType::Bitcode
761 | OutputType::ThinLinkBitcode
762 | OutputType::Assembly
763 | OutputType::LlvmAssembly
764 | OutputType::Mir
765 | OutputType::Object
766 | OutputType::Exe => true,
767 OutputType::Metadata | OutputType::DepInfo => false,
768 })
769 }
770
771 pub fn should_link(&self) -> bool {
773 self.0.keys().any(|k| match *k {
774 OutputType::Bitcode
775 | OutputType::ThinLinkBitcode
776 | OutputType::Assembly
777 | OutputType::LlvmAssembly
778 | OutputType::Mir
779 | OutputType::Metadata
780 | OutputType::Object
781 | OutputType::DepInfo => false,
782 OutputType::Exe => true,
783 })
784 }
785}
786
787#[derive(Clone)]
791pub struct Externs(BTreeMap<String, ExternEntry>);
792
793#[derive(Clone, Debug)]
794pub struct ExternEntry {
795 pub location: ExternLocation,
796 pub is_private_dep: bool,
802 pub add_prelude: bool,
807 pub nounused_dep: bool,
812 pub force: bool,
818}
819
820#[derive(Clone, Debug)]
821pub enum ExternLocation {
822 FoundInLibrarySearchDirectories,
826 ExactPaths(BTreeSet<CanonicalizedPath>),
833}
834
835impl Externs {
836 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
838 Externs(data)
839 }
840
841 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
842 self.0.get(key)
843 }
844
845 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
846 self.0.iter()
847 }
848}
849
850impl ExternEntry {
851 fn new(location: ExternLocation) -> ExternEntry {
852 ExternEntry {
853 location,
854 is_private_dep: false,
855 add_prelude: false,
856 nounused_dep: false,
857 force: false,
858 }
859 }
860
861 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
862 match &self.location {
863 ExternLocation::ExactPaths(set) => Some(set.iter()),
864 _ => None,
865 }
866 }
867}
868
869#[derive(Clone, PartialEq, Debug)]
870pub struct PrintRequest {
871 pub kind: PrintKind,
872 pub out: OutFileName,
873}
874
875#[derive(Copy, Clone, PartialEq, Eq, Debug)]
876pub enum PrintKind {
877 AllTargetSpecsJson,
879 CallingConventions,
880 Cfg,
881 CheckCfg,
882 CodeModels,
883 CrateName,
884 DeploymentTarget,
885 FileNames,
886 HostTuple,
887 LinkArgs,
888 NativeStaticLibs,
889 RelocationModels,
890 SplitDebuginfo,
891 StackProtectorStrategies,
892 SupportedCrateTypes,
893 Sysroot,
894 TargetCPUs,
895 TargetFeatures,
896 TargetLibdir,
897 TargetList,
898 TargetSpecJson,
899 TlsModels,
900 }
902
903#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]
904pub struct NextSolverConfig {
905 pub coherence: bool = true,
907 pub globally: bool = false,
910}
911
912#[derive(Clone)]
913pub enum Input {
914 File(PathBuf),
916 Str {
918 name: FileName,
920 input: String,
922 },
923}
924
925impl Input {
926 pub fn filestem(&self) -> &str {
927 if let Input::File(ifile) = self {
928 if let Some(name) = ifile.file_stem().and_then(OsStr::to_str) {
931 return name;
932 }
933 }
934 "rust_out"
935 }
936
937 pub fn source_name(&self) -> FileName {
938 match *self {
939 Input::File(ref ifile) => ifile.clone().into(),
940 Input::Str { ref name, .. } => name.clone(),
941 }
942 }
943
944 pub fn opt_path(&self) -> Option<&Path> {
945 match self {
946 Input::File(file) => Some(file),
947 Input::Str { name, .. } => match name {
948 FileName::Real(real) => real.local_path(),
949 FileName::CfgSpec(_) => None,
950 FileName::Anon(_) => None,
951 FileName::MacroExpansion(_) => None,
952 FileName::ProcMacroSourceCode(_) => None,
953 FileName::CliCrateAttr(_) => None,
954 FileName::Custom(_) => None,
955 FileName::DocTest(path, _) => Some(path),
956 FileName::InlineAsm(_) => None,
957 },
958 }
959 }
960}
961
962#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq, Encodable, Decodable)]
963pub enum OutFileName {
964 Real(PathBuf),
965 Stdout,
966}
967
968impl OutFileName {
969 pub fn parent(&self) -> Option<&Path> {
970 match *self {
971 OutFileName::Real(ref path) => path.parent(),
972 OutFileName::Stdout => None,
973 }
974 }
975
976 pub fn filestem(&self) -> Option<&OsStr> {
977 match *self {
978 OutFileName::Real(ref path) => path.file_stem(),
979 OutFileName::Stdout => Some(OsStr::new("stdout")),
980 }
981 }
982
983 pub fn is_stdout(&self) -> bool {
984 match *self {
985 OutFileName::Real(_) => false,
986 OutFileName::Stdout => true,
987 }
988 }
989
990 pub fn is_tty(&self) -> bool {
991 use std::io::IsTerminal;
992 match *self {
993 OutFileName::Real(_) => false,
994 OutFileName::Stdout => std::io::stdout().is_terminal(),
995 }
996 }
997
998 pub fn as_path(&self) -> &Path {
999 match *self {
1000 OutFileName::Real(ref path) => path.as_ref(),
1001 OutFileName::Stdout => Path::new("stdout"),
1002 }
1003 }
1004
1005 pub fn file_for_writing(
1011 &self,
1012 outputs: &OutputFilenames,
1013 flavor: OutputType,
1014 codegen_unit_name: Option<&str>,
1015 ) -> PathBuf {
1016 match *self {
1017 OutFileName::Real(ref path) => path.clone(),
1018 OutFileName::Stdout => outputs.temp_path(flavor, codegen_unit_name),
1019 }
1020 }
1021
1022 pub fn overwrite(&self, content: &str, sess: &Session) {
1023 match self {
1024 OutFileName::Stdout => print!("{content}"),
1025 OutFileName::Real(path) => {
1026 if let Err(e) = fs::write(path, content) {
1027 sess.dcx().emit_fatal(FileWriteFail { path, err: e.to_string() });
1028 }
1029 }
1030 }
1031 }
1032}
1033
1034#[derive(Clone, Hash, Debug, HashStable_Generic, Encodable, Decodable)]
1035pub struct OutputFilenames {
1036 pub(crate) out_directory: PathBuf,
1037 crate_stem: String,
1039 filestem: String,
1041 pub single_output_file: Option<OutFileName>,
1042 temps_directory: Option<PathBuf>,
1043 pub outputs: OutputTypes,
1044}
1045
1046pub const RLINK_EXT: &str = "rlink";
1047pub const RUST_CGU_EXT: &str = "rcgu";
1048pub const DWARF_OBJECT_EXT: &str = "dwo";
1049
1050impl OutputFilenames {
1051 pub fn new(
1052 out_directory: PathBuf,
1053 out_crate_name: String,
1054 out_filestem: String,
1055 single_output_file: Option<OutFileName>,
1056 temps_directory: Option<PathBuf>,
1057 extra: String,
1058 outputs: OutputTypes,
1059 ) -> Self {
1060 OutputFilenames {
1061 out_directory,
1062 single_output_file,
1063 temps_directory,
1064 outputs,
1065 crate_stem: format!("{out_crate_name}{extra}"),
1066 filestem: format!("{out_filestem}{extra}"),
1067 }
1068 }
1069
1070 pub fn path(&self, flavor: OutputType) -> OutFileName {
1071 self.outputs
1072 .get(&flavor)
1073 .and_then(|p| p.to_owned())
1074 .or_else(|| self.single_output_file.clone())
1075 .unwrap_or_else(|| OutFileName::Real(self.output_path(flavor)))
1076 }
1077
1078 fn output_path(&self, flavor: OutputType) -> PathBuf {
1081 let extension = flavor.extension();
1082 match flavor {
1083 OutputType::Metadata => {
1084 self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension))
1085 }
1086 _ => self.with_directory_and_extension(&self.out_directory, extension),
1087 }
1088 }
1089
1090 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
1094 let extension = flavor.extension();
1095 self.temp_path_ext(extension, codegen_unit_name)
1096 }
1097
1098 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
1100 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
1101 }
1102
1103 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
1106 let mut extension = String::new();
1107
1108 if let Some(codegen_unit_name) = codegen_unit_name {
1109 extension.push_str(codegen_unit_name);
1110 }
1111
1112 if !ext.is_empty() {
1113 if !extension.is_empty() {
1114 extension.push('.');
1115 extension.push_str(RUST_CGU_EXT);
1116 extension.push('.');
1117 }
1118
1119 extension.push_str(ext);
1120 }
1121
1122 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
1123
1124 self.with_directory_and_extension(temps_directory, &extension)
1125 }
1126
1127 pub fn with_extension(&self, extension: &str) -> PathBuf {
1128 self.with_directory_and_extension(&self.out_directory, extension)
1129 }
1130
1131 pub fn with_directory_and_extension(&self, directory: &Path, extension: &str) -> PathBuf {
1132 let mut path = directory.join(&self.filestem);
1133 path.set_extension(extension);
1134 path
1135 }
1136
1137 pub fn split_dwarf_path(
1140 &self,
1141 split_debuginfo_kind: SplitDebuginfo,
1142 split_dwarf_kind: SplitDwarfKind,
1143 cgu_name: Option<&str>,
1144 ) -> Option<PathBuf> {
1145 let obj_out = self.temp_path(OutputType::Object, cgu_name);
1146 let dwo_out = self.temp_path_dwo(cgu_name);
1147 match (split_debuginfo_kind, split_dwarf_kind) {
1148 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
1149 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
1153 Some(obj_out)
1154 }
1155 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
1157 Some(dwo_out)
1158 }
1159 }
1160 }
1161}
1162
1163bitflags::bitflags! {
1164 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1166 pub struct RemapPathScopeComponents: u8 {
1167 const MACRO = 1 << 0;
1169 const DIAGNOSTICS = 1 << 1;
1171 const DEBUGINFO = 1 << 3;
1173
1174 const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits();
1177 }
1178}
1179
1180pub fn host_tuple() -> &'static str {
1181 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
1190}
1191
1192fn file_path_mapping(
1193 remap_path_prefix: Vec<(PathBuf, PathBuf)>,
1194 unstable_opts: &UnstableOptions,
1195) -> FilePathMapping {
1196 FilePathMapping::new(
1197 remap_path_prefix.clone(),
1198 if unstable_opts.remap_path_scope.contains(RemapPathScopeComponents::DIAGNOSTICS)
1199 && !remap_path_prefix.is_empty()
1200 {
1201 FileNameDisplayPreference::Remapped
1202 } else {
1203 FileNameDisplayPreference::Local
1204 },
1205 )
1206}
1207
1208impl Default for Options {
1209 fn default() -> Options {
1210 Options {
1211 assert_incr_state: None,
1212 crate_types: Vec::new(),
1213 optimize: OptLevel::No,
1214 debuginfo: DebugInfo::None,
1215 debuginfo_compression: DebugInfoCompression::None,
1216 lint_opts: Vec::new(),
1217 lint_cap: None,
1218 describe_lints: false,
1219 output_types: OutputTypes(BTreeMap::new()),
1220 search_paths: vec![],
1221 sysroot: filesearch::materialize_sysroot(None),
1222 target_triple: TargetTuple::from_tuple(host_tuple()),
1223 test: false,
1224 incremental: None,
1225 untracked_state_hash: Default::default(),
1226 unstable_opts: Default::default(),
1227 prints: Vec::new(),
1228 cg: Default::default(),
1229 error_format: ErrorOutputType::default(),
1230 diagnostic_width: None,
1231 externs: Externs(BTreeMap::new()),
1232 crate_name: None,
1233 libs: Vec::new(),
1234 unstable_features: UnstableFeatures::Disallow,
1235 debug_assertions: true,
1236 actually_rustdoc: false,
1237 resolve_doc_links: ResolveDocLinks::None,
1238 trimmed_def_paths: false,
1239 cli_forced_codegen_units: None,
1240 cli_forced_local_thinlto_off: false,
1241 remap_path_prefix: Vec::new(),
1242 real_rust_source_base_dir: None,
1243 edition: DEFAULT_EDITION,
1244 json_artifact_notifications: false,
1245 json_unused_externs: JsonUnusedExterns::No,
1246 json_future_incompat: false,
1247 pretty: None,
1248 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
1249 color: ColorConfig::Auto,
1250 logical_env: FxIndexMap::default(),
1251 verbose: false,
1252 target_modifiers: BTreeMap::default(),
1253 }
1254 }
1255}
1256
1257impl Options {
1258 pub fn build_dep_graph(&self) -> bool {
1260 self.incremental.is_some()
1261 || self.unstable_opts.dump_dep_graph
1262 || self.unstable_opts.query_dep_graph
1263 }
1264
1265 pub fn file_path_mapping(&self) -> FilePathMapping {
1266 file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts)
1267 }
1268
1269 pub fn will_create_output_file(&self) -> bool {
1271 !self.unstable_opts.parse_crate_root_only && self.unstable_opts.ls.is_empty() }
1274
1275 #[inline]
1276 pub fn share_generics(&self) -> bool {
1277 match self.unstable_opts.share_generics {
1278 Some(setting) => setting,
1279 None => match self.optimize {
1280 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
1281 OptLevel::More | OptLevel::Aggressive => false,
1282 },
1283 }
1284 }
1285
1286 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
1287 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
1288 }
1289}
1290
1291impl UnstableOptions {
1292 pub fn dcx_flags(&self, can_emit_warnings: bool) -> DiagCtxtFlags {
1293 DiagCtxtFlags {
1294 can_emit_warnings,
1295 treat_err_as_bug: self.treat_err_as_bug,
1296 eagerly_emit_delayed_bugs: self.eagerly_emit_delayed_bugs,
1297 macro_backtrace: self.macro_backtrace,
1298 deduplicate_diagnostics: self.deduplicate_diagnostics,
1299 track_diagnostics: self.track_diagnostics,
1300 }
1301 }
1302
1303 pub fn src_hash_algorithm(&self, target: &Target) -> SourceFileHashAlgorithm {
1304 self.src_hash_algorithm.unwrap_or_else(|| {
1305 if target.is_like_msvc {
1306 SourceFileHashAlgorithm::Sha256
1307 } else {
1308 SourceFileHashAlgorithm::Md5
1309 }
1310 })
1311 }
1312
1313 pub fn checksum_hash_algorithm(&self) -> Option<SourceFileHashAlgorithm> {
1314 self.checksum_hash_algorithm
1315 }
1316}
1317
1318#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
1320pub enum EntryFnType {
1321 Main {
1322 sigpipe: u8,
1329 },
1330}
1331
1332#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
1333#[derive(HashStable_Generic)]
1334pub enum CrateType {
1335 Executable,
1336 Dylib,
1337 Rlib,
1338 Staticlib,
1339 Cdylib,
1340 ProcMacro,
1341}
1342
1343impl CrateType {
1344 pub fn has_metadata(self) -> bool {
1345 match self {
1346 CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
1347 CrateType::Executable | CrateType::Cdylib | CrateType::Staticlib => false,
1348 }
1349 }
1350}
1351
1352#[derive(Clone, Hash, Debug, PartialEq, Eq)]
1353pub enum Passes {
1354 Some(Vec<String>),
1355 All,
1356}
1357
1358impl Passes {
1359 fn is_empty(&self) -> bool {
1360 match *self {
1361 Passes::Some(ref v) => v.is_empty(),
1362 Passes::All => false,
1363 }
1364 }
1365
1366 pub(crate) fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
1367 match *self {
1368 Passes::Some(ref mut v) => v.extend(passes),
1369 Passes::All => {}
1370 }
1371 }
1372}
1373
1374#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1375pub enum PAuthKey {
1376 A,
1377 B,
1378}
1379
1380#[derive(Clone, Copy, Hash, Debug, PartialEq)]
1381pub struct PacRet {
1382 pub leaf: bool,
1383 pub pc: bool,
1384 pub key: PAuthKey,
1385}
1386
1387#[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
1388pub struct BranchProtection {
1389 pub bti: bool,
1390 pub pac_ret: Option<PacRet>,
1391}
1392
1393pub(crate) const fn default_lib_output() -> CrateType {
1394 CrateType::Rlib
1395}
1396
1397pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
1398 cfg::disallow_cfgs(sess, &user_cfg);
1400
1401 user_cfg.extend(cfg::default_configuration(sess));
1404 user_cfg
1405}
1406
1407pub fn build_target_config(
1408 early_dcx: &EarlyDiagCtxt,
1409 target: &TargetTuple,
1410 sysroot: &Path,
1411) -> Target {
1412 match Target::search(target, sysroot) {
1413 Ok((target, warnings)) => {
1414 for warning in warnings.warning_messages() {
1415 early_dcx.early_warn(warning)
1416 }
1417
1418 if !matches!(target.pointer_width, 16 | 32 | 64) {
1419 early_dcx.early_fatal(format!(
1420 "target specification was invalid: unrecognized target-pointer-width {}",
1421 target.pointer_width
1422 ))
1423 }
1424 target
1425 }
1426 Err(e) => early_dcx.early_fatal(format!(
1427 "Error loading target specification: {e}. \
1428 Run `rustc --print target-list` for a list of built-in targets"
1429 )),
1430 }
1431}
1432
1433#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1434pub enum OptionStability {
1435 Stable,
1436 Unstable,
1437}
1438
1439#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1440pub enum OptionKind {
1441 Opt,
1445
1446 Multi,
1450
1451 Flag,
1456
1457 FlagMulti,
1462}
1463
1464pub struct RustcOptGroup {
1465 pub name: &'static str,
1473 stability: OptionStability,
1474 kind: OptionKind,
1475
1476 short_name: &'static str,
1477 long_name: &'static str,
1478 desc: &'static str,
1479 value_hint: &'static str,
1480
1481 pub is_verbose_help_only: bool,
1484}
1485
1486impl RustcOptGroup {
1487 pub fn is_stable(&self) -> bool {
1488 self.stability == OptionStability::Stable
1489 }
1490
1491 pub fn apply(&self, options: &mut getopts::Options) {
1492 let &Self { short_name, long_name, desc, value_hint, .. } = self;
1493 match self.kind {
1494 OptionKind::Opt => options.optopt(short_name, long_name, desc, value_hint),
1495 OptionKind::Multi => options.optmulti(short_name, long_name, desc, value_hint),
1496 OptionKind::Flag => options.optflag(short_name, long_name, desc),
1497 OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
1498 };
1499 }
1500}
1501
1502pub fn make_opt(
1503 stability: OptionStability,
1504 kind: OptionKind,
1505 short_name: &'static str,
1506 long_name: &'static str,
1507 desc: &'static str,
1508 value_hint: &'static str,
1509) -> RustcOptGroup {
1510 match kind {
1512 OptionKind::Opt | OptionKind::Multi => {}
1513 OptionKind::Flag | OptionKind::FlagMulti => assert_eq!(value_hint, ""),
1514 }
1515 RustcOptGroup {
1516 name: cmp::max_by_key(short_name, long_name, |s| s.len()),
1517 stability,
1518 kind,
1519 short_name,
1520 long_name,
1521 desc,
1522 value_hint,
1523 is_verbose_help_only: false,
1524 }
1525}
1526
1527static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
1528 format!(
1529 "Specify which edition of the compiler to use when compiling code. \
1530The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
1531 )
1532});
1533
1534static PRINT_KINDS_STRING: LazyLock<String> = LazyLock::new(|| {
1535 format!(
1536 "[{}]",
1537 PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::<Vec<_>>().join("|")
1538 )
1539});
1540
1541pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1544 use OptionKind::{Flag, FlagMulti, Multi, Opt};
1545 use OptionStability::{Stable, Unstable};
1546
1547 use self::make_opt as opt;
1548
1549 let mut options = vec![
1550 opt(Stable, Flag, "h", "help", "Display this message", ""),
1551 opt(
1552 Stable,
1553 Multi,
1554 "",
1555 "cfg",
1556 "Configure the compilation environment.\n\
1557 SPEC supports the syntax `NAME[=\"VALUE\"]`.",
1558 "SPEC",
1559 ),
1560 opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "SPEC"),
1561 opt(
1562 Stable,
1563 Multi,
1564 "L",
1565 "",
1566 "Add a directory to the library search path. \
1567 The optional KIND can be one of dependency, crate, native, framework, or all (the default).",
1568 "[KIND=]PATH",
1569 ),
1570 opt(
1571 Stable,
1572 Multi,
1573 "l",
1574 "",
1575 "Link the generated crate(s) to the specified native\n\
1576 library NAME. The optional KIND can be one of\n\
1577 static, framework, or dylib (the default).\n\
1578 Optional comma separated MODIFIERS\n\
1579 (bundle|verbatim|whole-archive|as-needed)\n\
1580 may be specified each with a prefix of either '+' to\n\
1581 enable or '-' to disable.",
1582 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1583 ),
1584 make_crate_type_option(),
1585 opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "NAME"),
1586 opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST),
1587 opt(
1588 Stable,
1589 Multi,
1590 "",
1591 "emit",
1592 "Comma separated list of types of output for the compiler to emit",
1593 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1594 ),
1595 opt(
1596 Stable,
1597 Multi,
1598 "",
1599 "print",
1600 "Compiler information to print on stdout",
1601 &PRINT_KINDS_STRING,
1602 ),
1603 opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""),
1604 opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""),
1605 opt(Stable, Opt, "o", "", "Write output to <filename>", "FILENAME"),
1606 opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
1607 opt(
1608 Stable,
1609 Opt,
1610 "",
1611 "explain",
1612 "Provide a detailed explanation of an error message",
1613 "OPT",
1614 ),
1615 opt(Stable, Flag, "", "test", "Build a test harness", ""),
1616 opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "TARGET"),
1617 opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
1618 opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
1619 opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
1620 opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
1621 opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
1622 opt(
1623 Stable,
1624 Multi,
1625 "",
1626 "cap-lints",
1627 "Set the most restrictive lint level. More restrictive lints are capped at this level",
1628 "LEVEL",
1629 ),
1630 opt(Stable, Multi, "C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1631 opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
1632 opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
1633 ];
1634
1635 let verbose_only = [
1638 opt(
1639 Stable,
1640 Multi,
1641 "",
1642 "extern",
1643 "Specify where an external rust library is located",
1644 "NAME[=PATH]",
1645 ),
1646 opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"),
1647 opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "FLAG"),
1648 opt(
1649 Stable,
1650 Opt,
1651 "",
1652 "error-format",
1653 "How errors and other messages are produced",
1654 "human|json|short",
1655 ),
1656 opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "CONFIG"),
1657 opt(
1658 Stable,
1659 Opt,
1660 "",
1661 "color",
1662 "Configure coloring of output:
1663 auto = colorize, if output goes to a tty (default);
1664 always = always colorize output;
1665 never = never colorize output",
1666 "auto|always|never",
1667 ),
1668 opt(
1669 Stable,
1670 Opt,
1671 "",
1672 "diagnostic-width",
1673 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1674 "WIDTH",
1675 ),
1676 opt(
1677 Stable,
1678 Multi,
1679 "",
1680 "remap-path-prefix",
1681 "Remap source names in all output (compiler messages and output files)",
1682 "FROM=TO",
1683 ),
1684 opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "VAR=VALUE"),
1685 ];
1686 options.extend(verbose_only.into_iter().map(|mut opt| {
1687 opt.is_verbose_help_only = true;
1688 opt
1689 }));
1690
1691 options
1692}
1693
1694pub fn get_cmd_lint_options(
1695 early_dcx: &EarlyDiagCtxt,
1696 matches: &getopts::Matches,
1697) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1698 let mut lint_opts_with_position = vec![];
1699 let mut describe_lints = false;
1700
1701 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1702 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1703 if lint_name == "help" {
1704 describe_lints = true;
1705 } else {
1706 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1707 }
1708 }
1709 }
1710
1711 lint_opts_with_position.sort_by_key(|x| x.0);
1712 let lint_opts = lint_opts_with_position
1713 .iter()
1714 .cloned()
1715 .map(|(_, lint_name, level)| (lint_name, level))
1716 .collect();
1717
1718 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1719 lint::Level::from_str(&cap)
1720 .unwrap_or_else(|| early_dcx.early_fatal(format!("unknown lint level: `{cap}`")))
1721 });
1722
1723 (lint_opts, describe_lints, lint_cap)
1724}
1725
1726pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> ColorConfig {
1728 match matches.opt_str("color").as_deref() {
1729 Some("auto") => ColorConfig::Auto,
1730 Some("always") => ColorConfig::Always,
1731 Some("never") => ColorConfig::Never,
1732
1733 None => ColorConfig::Auto,
1734
1735 Some(arg) => early_dcx.early_fatal(format!(
1736 "argument for `--color` must be auto, \
1737 always or never (instead was `{arg}`)"
1738 )),
1739 }
1740}
1741
1742pub struct JsonConfig {
1744 pub json_rendered: HumanReadableErrorType,
1745 pub json_color: ColorConfig,
1746 json_artifact_notifications: bool,
1747 pub json_unused_externs: JsonUnusedExterns,
1748 json_future_incompat: bool,
1749}
1750
1751#[derive(Copy, Clone)]
1753pub enum JsonUnusedExterns {
1754 No,
1756 Silent,
1758 Loud,
1760}
1761
1762impl JsonUnusedExterns {
1763 pub fn is_enabled(&self) -> bool {
1764 match self {
1765 JsonUnusedExterns::No => false,
1766 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1767 }
1768 }
1769
1770 pub fn is_loud(&self) -> bool {
1771 match self {
1772 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1773 JsonUnusedExterns::Loud => true,
1774 }
1775 }
1776}
1777
1778pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
1783 let mut json_rendered = HumanReadableErrorType::Default;
1784 let mut json_color = ColorConfig::Never;
1785 let mut json_artifact_notifications = false;
1786 let mut json_unused_externs = JsonUnusedExterns::No;
1787 let mut json_future_incompat = false;
1788 for option in matches.opt_strs("json") {
1789 if matches.opt_str("color").is_some() {
1793 early_dcx.early_fatal("cannot specify the `--color` option with `--json`");
1794 }
1795
1796 for sub_option in option.split(',') {
1797 match sub_option {
1798 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1799 "diagnostic-unicode" => {
1800 json_rendered = HumanReadableErrorType::Unicode;
1801 }
1802 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1803 "artifacts" => json_artifact_notifications = true,
1804 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1805 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1806 "future-incompat" => json_future_incompat = true,
1807 s => early_dcx.early_fatal(format!("unknown `--json` option `{s}`")),
1808 }
1809 }
1810 }
1811
1812 JsonConfig {
1813 json_rendered,
1814 json_color,
1815 json_artifact_notifications,
1816 json_unused_externs,
1817 json_future_incompat,
1818 }
1819}
1820
1821pub fn parse_error_format(
1823 early_dcx: &mut EarlyDiagCtxt,
1824 matches: &getopts::Matches,
1825 color_config: ColorConfig,
1826 json_color: ColorConfig,
1827 json_rendered: HumanReadableErrorType,
1828) -> ErrorOutputType {
1829 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1834 match matches.opt_str("error-format").as_deref() {
1835 None | Some("human") => ErrorOutputType::HumanReadable { color_config, .. },
1836 Some("human-annotate-rs") => ErrorOutputType::HumanReadable {
1837 kind: HumanReadableErrorType::AnnotateSnippet,
1838 color_config,
1839 },
1840 Some("json") => {
1841 ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
1842 }
1843 Some("pretty-json") => {
1844 ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
1845 }
1846 Some("short") => {
1847 ErrorOutputType::HumanReadable { kind: HumanReadableErrorType::Short, color_config }
1848 }
1849 Some("human-unicode") => ErrorOutputType::HumanReadable {
1850 kind: HumanReadableErrorType::Unicode,
1851 color_config,
1852 },
1853 Some(arg) => {
1854 early_dcx.set_error_format(ErrorOutputType::HumanReadable { color_config, .. });
1855 early_dcx.early_fatal(format!(
1856 "argument for `--error-format` must be `human`, `human-annotate-rs`, \
1857 `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)"
1858 ))
1859 }
1860 }
1861 } else {
1862 ErrorOutputType::HumanReadable { color_config, .. }
1863 };
1864
1865 match error_format {
1866 ErrorOutputType::Json { .. } => {}
1867
1868 _ if !matches.opt_strs("json").is_empty() => {
1872 early_dcx.early_fatal("using `--json` requires also using `--error-format=json`");
1873 }
1874
1875 _ => {}
1876 }
1877
1878 error_format
1879}
1880
1881pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Edition {
1882 let edition = match matches.opt_str("edition") {
1883 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1884 early_dcx.early_fatal(format!(
1885 "argument for `--edition` must be one of: \
1886 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1887 ))
1888 }),
1889 None => DEFAULT_EDITION,
1890 };
1891
1892 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1893 let is_nightly = nightly_options::match_is_nightly_build(matches);
1894 let msg = if !is_nightly {
1895 format!(
1896 "the crate requires edition {edition}, but the latest edition supported by this Rust version is {LATEST_STABLE_EDITION}"
1897 )
1898 } else {
1899 format!("edition {edition} is unstable and only available with -Z unstable-options")
1900 };
1901 early_dcx.early_fatal(msg)
1902 }
1903
1904 edition
1905}
1906
1907fn check_error_format_stability(
1908 early_dcx: &EarlyDiagCtxt,
1909 unstable_opts: &UnstableOptions,
1910 format: ErrorOutputType,
1911) {
1912 if unstable_opts.unstable_options {
1913 return;
1914 }
1915 let format = match format {
1916 ErrorOutputType::Json { pretty: true, .. } => "pretty-json",
1917 ErrorOutputType::HumanReadable { kind, .. } => match kind {
1918 HumanReadableErrorType::AnnotateSnippet => "human-annotate-rs",
1919 HumanReadableErrorType::Unicode => "human-unicode",
1920 _ => return,
1921 },
1922 _ => return,
1923 };
1924 early_dcx.early_fatal(format!("`--error-format={format}` is unstable"))
1925}
1926
1927fn parse_output_types(
1928 early_dcx: &EarlyDiagCtxt,
1929 unstable_opts: &UnstableOptions,
1930 matches: &getopts::Matches,
1931) -> OutputTypes {
1932 let mut output_types = BTreeMap::new();
1933 if !unstable_opts.parse_crate_root_only {
1934 for list in matches.opt_strs("emit") {
1935 for output_type in list.split(',') {
1936 let (shorthand, path) = split_out_file_name(output_type);
1937 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1938 early_dcx.early_fatal(format!(
1939 "unknown emission type: `{shorthand}` - expected one of: {display}",
1940 display = OutputType::shorthands_display(),
1941 ))
1942 });
1943 if output_type == OutputType::ThinLinkBitcode && !unstable_opts.unstable_options {
1944 early_dcx.early_fatal(format!(
1945 "{} requested but -Zunstable-options not specified",
1946 OutputType::ThinLinkBitcode.shorthand()
1947 ));
1948 }
1949 output_types.insert(output_type, path);
1950 }
1951 }
1952 };
1953 if output_types.is_empty() {
1954 output_types.insert(OutputType::Exe, None);
1955 }
1956 OutputTypes(output_types)
1957}
1958
1959fn split_out_file_name(arg: &str) -> (&str, Option<OutFileName>) {
1960 match arg.split_once('=') {
1961 None => (arg, None),
1962 Some((kind, "-")) => (kind, Some(OutFileName::Stdout)),
1963 Some((kind, path)) => (kind, Some(OutFileName::Real(PathBuf::from(path)))),
1964 }
1965}
1966
1967fn should_override_cgus_and_disable_thinlto(
1968 early_dcx: &EarlyDiagCtxt,
1969 output_types: &OutputTypes,
1970 matches: &getopts::Matches,
1971 mut codegen_units: Option<usize>,
1972) -> (bool, Option<usize>) {
1973 let mut disable_local_thinlto = false;
1974 let incompatible: Vec<_> = output_types
1977 .0
1978 .iter()
1979 .map(|ot_path| ot_path.0)
1980 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1981 .map(|ot| ot.shorthand())
1982 .collect();
1983 if !incompatible.is_empty() {
1984 match codegen_units {
1985 Some(n) if n > 1 => {
1986 if matches.opt_present("o") {
1987 for ot in &incompatible {
1988 early_dcx.early_warn(format!(
1989 "`--emit={ot}` with `-o` incompatible with \
1990 `-C codegen-units=N` for N > 1",
1991 ));
1992 }
1993 early_dcx.early_warn("resetting to default -C codegen-units=1");
1994 codegen_units = Some(1);
1995 disable_local_thinlto = true;
1996 }
1997 }
1998 _ => {
1999 codegen_units = Some(1);
2000 disable_local_thinlto = true;
2001 }
2002 }
2003 }
2004
2005 if codegen_units == Some(0) {
2006 early_dcx.early_fatal("value for codegen units must be a positive non-zero integer");
2007 }
2008
2009 (disable_local_thinlto, codegen_units)
2010}
2011
2012fn collect_print_requests(
2013 early_dcx: &EarlyDiagCtxt,
2014 cg: &mut CodegenOptions,
2015 unstable_opts: &UnstableOptions,
2016 matches: &getopts::Matches,
2017) -> Vec<PrintRequest> {
2018 let mut prints = Vec::<PrintRequest>::new();
2019 if cg.target_cpu.as_deref() == Some("help") {
2020 prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout });
2021 cg.target_cpu = None;
2022 };
2023 if cg.target_feature == "help" {
2024 prints.push(PrintRequest { kind: PrintKind::TargetFeatures, out: OutFileName::Stdout });
2025 cg.target_feature = String::new();
2026 }
2027
2028 let mut printed_paths = FxHashSet::default();
2033
2034 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
2035 let (req, out) = split_out_file_name(&req);
2036
2037 let kind = if let Some((print_name, print_kind)) =
2038 PRINT_KINDS.iter().find(|&&(name, _)| name == req)
2039 {
2040 check_print_request_stability(early_dcx, unstable_opts, (print_name, *print_kind));
2041 *print_kind
2042 } else {
2043 emit_unknown_print_request_help(early_dcx, req)
2044 };
2045
2046 let out = out.unwrap_or(OutFileName::Stdout);
2047 if let OutFileName::Real(path) = &out {
2048 if !printed_paths.insert(path.clone()) {
2049 early_dcx.early_fatal(format!(
2050 "cannot print multiple outputs to the same path: {}",
2051 path.display(),
2052 ));
2053 }
2054 }
2055
2056 PrintRequest { kind, out }
2057 }));
2058
2059 prints
2060}
2061
2062fn check_print_request_stability(
2063 early_dcx: &EarlyDiagCtxt,
2064 unstable_opts: &UnstableOptions,
2065 (print_name, print_kind): (&str, PrintKind),
2066) {
2067 match print_kind {
2068 PrintKind::AllTargetSpecsJson
2069 | PrintKind::CheckCfg
2070 | PrintKind::SupportedCrateTypes
2071 | PrintKind::TargetSpecJson
2072 if !unstable_opts.unstable_options =>
2073 {
2074 early_dcx.early_fatal(format!(
2075 "the `-Z unstable-options` flag must also be passed to enable the `{print_name}` \
2076 print option"
2077 ));
2078 }
2079 _ => {}
2080 }
2081}
2082
2083fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str) -> ! {
2084 let prints = PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
2085 let prints = prints.join(", ");
2086
2087 let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`"));
2088 #[allow(rustc::diagnostic_outside_of_impl)]
2089 diag.help(format!("valid print requests are: {prints}"));
2090
2091 if req == "lints" {
2092 diag.help(format!("use `-Whelp` to print a list of lints"));
2093 }
2094
2095 diag.help(format!("for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information"));
2096 diag.emit()
2097}
2098
2099pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTuple {
2100 match matches.opt_str("target") {
2101 Some(target) if target.ends_with(".json") => {
2102 let path = Path::new(&target);
2103 TargetTuple::from_path(path).unwrap_or_else(|_| {
2104 early_dcx.early_fatal(format!("target file {path:?} does not exist"))
2105 })
2106 }
2107 Some(target) => TargetTuple::TargetTuple(target),
2108 _ => TargetTuple::from_tuple(host_tuple()),
2109 }
2110}
2111
2112fn parse_opt_level(
2113 early_dcx: &EarlyDiagCtxt,
2114 matches: &getopts::Matches,
2115 cg: &CodegenOptions,
2116) -> OptLevel {
2117 let max_o = matches.opt_positions("O").into_iter().max();
2124 let max_c = matches
2125 .opt_strs_pos("C")
2126 .into_iter()
2127 .flat_map(|(i, s)| {
2128 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
2130 })
2131 .max();
2132 if max_o > max_c {
2133 OptLevel::Aggressive
2134 } else {
2135 match cg.opt_level.as_ref() {
2136 "0" => OptLevel::No,
2137 "1" => OptLevel::Less,
2138 "2" => OptLevel::More,
2139 "3" => OptLevel::Aggressive,
2140 "s" => OptLevel::Size,
2141 "z" => OptLevel::SizeMin,
2142 arg => {
2143 early_dcx.early_fatal(format!(
2144 "optimization level needs to be \
2145 between 0-3, s or z (instead was `{arg}`)"
2146 ));
2147 }
2148 }
2149 }
2150}
2151
2152fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInfo {
2153 let max_g = matches.opt_positions("g").into_iter().max();
2154 let max_c = matches
2155 .opt_strs_pos("C")
2156 .into_iter()
2157 .flat_map(|(i, s)| {
2158 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
2160 })
2161 .max();
2162 if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
2163}
2164
2165fn parse_assert_incr_state(
2166 early_dcx: &EarlyDiagCtxt,
2167 opt_assertion: &Option<String>,
2168) -> Option<IncrementalStateAssertion> {
2169 match opt_assertion {
2170 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
2171 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
2172 Some(s) => {
2173 early_dcx.early_fatal(format!("unexpected incremental state assertion value: {s}"))
2174 }
2175 None => None,
2176 }
2177}
2178
2179pub fn parse_externs(
2180 early_dcx: &EarlyDiagCtxt,
2181 matches: &getopts::Matches,
2182 unstable_opts: &UnstableOptions,
2183) -> Externs {
2184 fn is_ascii_ident(string: &str) -> bool {
2185 let mut chars = string.chars();
2186 if let Some(start) = chars.next()
2187 && (start.is_ascii_alphabetic() || start == '_')
2188 {
2189 chars.all(|char| char.is_ascii_alphanumeric() || char == '_')
2190 } else {
2191 false
2192 }
2193 }
2194
2195 let is_unstable_enabled = unstable_opts.unstable_options;
2196 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2197 for arg in matches.opt_strs("extern") {
2198 let (name, path) = match arg.split_once('=') {
2199 None => (arg, None),
2200 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2201 };
2202 let (options, name) = match name.split_once(':') {
2203 None => (None, name),
2204 Some((opts, name)) => (Some(opts), name.to_string()),
2205 };
2206
2207 if !is_ascii_ident(&name) {
2208 let mut error = early_dcx.early_struct_fatal(format!(
2209 "crate name `{name}` passed to `--extern` is not a valid ASCII identifier"
2210 ));
2211 let adjusted_name = name.replace('-', "_");
2212 if is_ascii_ident(&adjusted_name) {
2213 #[allow(rustc::diagnostic_outside_of_impl)] error.help(format!(
2215 "consider replacing the dashes with underscores: `{adjusted_name}`"
2216 ));
2217 }
2218 error.emit();
2219 }
2220
2221 let path = path.map(|p| CanonicalizedPath::new(p));
2222
2223 let entry = externs.entry(name.to_owned());
2224
2225 use std::collections::btree_map::Entry;
2226
2227 let entry = if let Some(path) = path {
2228 match entry {
2230 Entry::Vacant(vacant) => {
2231 let files = BTreeSet::from_iter(iter::once(path));
2232 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2233 }
2234 Entry::Occupied(occupied) => {
2235 let ext_ent = occupied.into_mut();
2236 match ext_ent {
2237 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2238 files.insert(path);
2239 }
2240 ExternEntry {
2241 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2242 ..
2243 } => {
2244 let files = BTreeSet::from_iter(iter::once(path));
2246 *location = ExternLocation::ExactPaths(files);
2247 }
2248 }
2249 ext_ent
2250 }
2251 }
2252 } else {
2253 match entry {
2255 Entry::Vacant(vacant) => {
2256 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2257 }
2258 Entry::Occupied(occupied) => {
2259 occupied.into_mut()
2261 }
2262 }
2263 };
2264
2265 let mut is_private_dep = false;
2266 let mut add_prelude = true;
2267 let mut nounused_dep = false;
2268 let mut force = false;
2269 if let Some(opts) = options {
2270 if !is_unstable_enabled {
2271 early_dcx.early_fatal(
2272 "the `-Z unstable-options` flag must also be passed to \
2273 enable `--extern` options",
2274 );
2275 }
2276 for opt in opts.split(',') {
2277 match opt {
2278 "priv" => is_private_dep = true,
2279 "noprelude" => {
2280 if let ExternLocation::ExactPaths(_) = &entry.location {
2281 add_prelude = false;
2282 } else {
2283 early_dcx.early_fatal(
2284 "the `noprelude` --extern option requires a file path",
2285 );
2286 }
2287 }
2288 "nounused" => nounused_dep = true,
2289 "force" => force = true,
2290 _ => early_dcx.early_fatal(format!("unknown --extern option `{opt}`")),
2291 }
2292 }
2293 }
2294
2295 entry.is_private_dep |= is_private_dep;
2298 entry.nounused_dep |= nounused_dep;
2300 entry.force |= force;
2302 entry.add_prelude |= add_prelude;
2304 }
2305 Externs(externs)
2306}
2307
2308fn parse_remap_path_prefix(
2309 early_dcx: &EarlyDiagCtxt,
2310 matches: &getopts::Matches,
2311 unstable_opts: &UnstableOptions,
2312) -> Vec<(PathBuf, PathBuf)> {
2313 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2314 .opt_strs("remap-path-prefix")
2315 .into_iter()
2316 .map(|remap| match remap.rsplit_once('=') {
2317 None => {
2318 early_dcx.early_fatal("--remap-path-prefix must contain '=' between FROM and TO")
2319 }
2320 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2321 })
2322 .collect();
2323 match &unstable_opts.remap_cwd_prefix {
2324 Some(to) => match std::env::current_dir() {
2325 Ok(cwd) => mapping.push((cwd, to.clone())),
2326 Err(_) => (),
2327 },
2328 None => (),
2329 };
2330 mapping
2331}
2332
2333fn parse_logical_env(
2334 early_dcx: &EarlyDiagCtxt,
2335 matches: &getopts::Matches,
2336) -> FxIndexMap<String, String> {
2337 let mut vars = FxIndexMap::default();
2338
2339 for arg in matches.opt_strs("env-set") {
2340 if let Some((name, val)) = arg.split_once('=') {
2341 vars.insert(name.to_string(), val.to_string());
2342 } else {
2343 early_dcx.early_fatal(format!("`--env-set`: specify value for variable `{arg}`"));
2344 }
2345 }
2346
2347 vars
2348}
2349
2350#[allow(rustc::bad_opt_access)]
2352pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches) -> Options {
2353 let color = parse_color(early_dcx, matches);
2354
2355 let edition = parse_crate_edition(early_dcx, matches);
2356
2357 let JsonConfig {
2358 json_rendered,
2359 json_color,
2360 json_artifact_notifications,
2361 json_unused_externs,
2362 json_future_incompat,
2363 } = parse_json(early_dcx, matches);
2364
2365 let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
2366
2367 early_dcx.set_error_format(error_format);
2368
2369 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2370 early_dcx.early_fatal("`--diagnostic-width` must be an positive integer");
2371 });
2372
2373 let unparsed_crate_types = matches.opt_strs("crate-type");
2374 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2375 .unwrap_or_else(|e| early_dcx.early_fatal(e));
2376
2377 let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
2378
2379 let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
2380 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
2381
2382 check_error_format_stability(early_dcx, &unstable_opts, error_format);
2383
2384 let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
2385
2386 let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
2387 let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2388 early_dcx,
2389 &output_types,
2390 matches,
2391 cg.codegen_units,
2392 );
2393
2394 if unstable_opts.threads == 0 {
2395 early_dcx.early_fatal("value for threads must be a positive non-zero integer");
2396 }
2397
2398 if unstable_opts.threads == parse::MAX_THREADS_CAP {
2399 early_dcx.early_warn(format!("number of threads was capped at {}", parse::MAX_THREADS_CAP));
2400 }
2401
2402 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2403
2404 let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state);
2405
2406 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2407 early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive");
2408 }
2409
2410 if unstable_opts.profile_sample_use.is_some()
2411 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2412 {
2413 early_dcx.early_fatal(
2414 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2415 );
2416 }
2417
2418 match cg.symbol_mangling_version {
2421 None | Some(SymbolManglingVersion::V0) => {}
2423
2424 Some(SymbolManglingVersion::Legacy) => {
2426 if !unstable_opts.unstable_options {
2427 early_dcx.early_fatal(
2428 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2429 );
2430 }
2431 }
2432 Some(SymbolManglingVersion::Hashed) => {
2433 if !unstable_opts.unstable_options {
2434 early_dcx.early_fatal(
2435 "`-C symbol-mangling-version=hashed` requires `-Z unstable-options`",
2436 );
2437 }
2438 }
2439 }
2440
2441 if cg.instrument_coverage != InstrumentCoverage::No {
2442 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2443 early_dcx.early_fatal(
2444 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2445 or `-C profile-generate`",
2446 );
2447 }
2448
2449 match cg.symbol_mangling_version {
2454 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2455 Some(SymbolManglingVersion::Legacy) => {
2456 early_dcx.early_warn(
2457 "-C instrument-coverage requires symbol mangling version `v0`, \
2458 but `-C symbol-mangling-version=legacy` was specified",
2459 );
2460 }
2461 Some(SymbolManglingVersion::V0) => {}
2462 Some(SymbolManglingVersion::Hashed) => {
2463 early_dcx.early_warn(
2464 "-C instrument-coverage requires symbol mangling version `v0`, \
2465 but `-C symbol-mangling-version=hashed` was specified",
2466 );
2467 }
2468 }
2469 }
2470
2471 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2472 unstable_opts.graphviz_font = graphviz_font;
2475 }
2476
2477 if !cg.embed_bitcode {
2478 match cg.lto {
2479 LtoCli::No | LtoCli::Unspecified => {}
2480 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
2481 early_dcx.early_fatal("options `-C embed-bitcode=no` and `-C lto` are incompatible")
2482 }
2483 }
2484 }
2485
2486 if !nightly_options::is_unstable_enabled(matches)
2487 && cg.force_frame_pointers == FramePointer::NonLeaf
2488 {
2489 early_dcx.early_fatal(
2490 "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
2491 and a nightly compiler",
2492 )
2493 }
2494
2495 if !nightly_options::is_unstable_enabled(matches) {
2499 let uses_unstable_self_contained_option =
2500 cg.link_self_contained.are_unstable_variants_set();
2501 if uses_unstable_self_contained_option {
2502 early_dcx.early_fatal(
2503 "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
2504 the `-Z unstable-options` flag must also be passed to use the unstable values",
2505 );
2506 }
2507
2508 if let Some(flavor) = cg.linker_flavor {
2509 if flavor.is_unstable() {
2510 early_dcx.early_fatal(format!(
2511 "the linker flavor `{}` is unstable, the `-Z unstable-options` \
2512 flag must also be passed to use the unstable values",
2513 flavor.desc()
2514 ));
2515 }
2516 }
2517 }
2518
2519 if let Some(erroneous_components) = cg.link_self_contained.check_consistency() {
2522 let names: String = erroneous_components
2523 .into_iter()
2524 .map(|c| c.as_str().unwrap())
2525 .intersperse(", ")
2526 .collect();
2527 early_dcx.early_fatal(format!(
2528 "some `-C link-self-contained` components were both enabled and disabled: {names}"
2529 ));
2530 }
2531
2532 let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches);
2533
2534 let cg = cg;
2535
2536 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2537 let target_triple = parse_target_triple(early_dcx, matches);
2538 let opt_level = parse_opt_level(early_dcx, matches, &cg);
2539 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2543 let debuginfo = select_debuginfo(matches, &cg);
2544 let debuginfo_compression = unstable_opts.debuginfo_compression;
2545
2546 let crate_name = matches.opt_str("crate-name");
2547 let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
2548 let libs = parse_native_libs(early_dcx, &unstable_opts, unstable_features, matches);
2550
2551 let test = matches.opt_present("test");
2552
2553 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2554 early_dcx.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
2555 }
2556
2557 if cg.remark.is_empty() && unstable_opts.remark_dir.is_some() {
2558 early_dcx
2559 .early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all");
2560 }
2561
2562 let externs = parse_externs(early_dcx, matches, &unstable_opts);
2563
2564 let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts);
2565
2566 let pretty = parse_pretty(early_dcx, &unstable_opts);
2567
2568 if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
2570 early_dcx.early_fatal("can't dump dependency graph without `-Z query-dep-graph`");
2571 }
2572
2573 let logical_env = parse_logical_env(early_dcx, matches);
2574
2575 let sysroot = filesearch::materialize_sysroot(sysroot_opt);
2576
2577 let real_rust_source_base_dir = {
2578 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2580 if let Ok(metadata) = candidate.symlink_metadata() {
2581 if metadata.file_type().is_symlink() {
2585 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2586 candidate = symlink_dest;
2587 }
2588 }
2589 }
2590
2591 candidate.join("library/std/src/lib.rs").is_file().then_some(candidate)
2593 };
2594
2595 let mut search_paths = vec![];
2596 for s in &matches.opt_strs("L") {
2597 search_paths.push(SearchPath::from_cli_opt(
2598 &sysroot,
2599 &target_triple,
2600 early_dcx,
2601 s,
2602 unstable_opts.unstable_options,
2603 ));
2604 }
2605
2606 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2607 early_dcx.early_fatal(format!("Current directory is invalid: {e}"));
2608 });
2609
2610 let file_mapping = file_path_mapping(remap_path_prefix.clone(), &unstable_opts);
2611 let working_dir = file_mapping.to_real_filename(&working_dir);
2612
2613 let verbose = matches.opt_present("verbose") || unstable_opts.verbose_internals;
2614
2615 Options {
2616 assert_incr_state,
2617 crate_types,
2618 optimize: opt_level,
2619 debuginfo,
2620 debuginfo_compression,
2621 lint_opts,
2622 lint_cap,
2623 describe_lints,
2624 output_types,
2625 search_paths,
2626 sysroot,
2627 target_triple,
2628 test,
2629 incremental,
2630 untracked_state_hash: Default::default(),
2631 unstable_opts,
2632 prints,
2633 cg,
2634 error_format,
2635 diagnostic_width,
2636 externs,
2637 unstable_features,
2638 crate_name,
2639 libs,
2640 debug_assertions,
2641 actually_rustdoc: false,
2642 resolve_doc_links: ResolveDocLinks::ExportedMetadata,
2643 trimmed_def_paths: false,
2644 cli_forced_codegen_units: codegen_units,
2645 cli_forced_local_thinlto_off: disable_local_thinlto,
2646 remap_path_prefix,
2647 real_rust_source_base_dir,
2648 edition,
2649 json_artifact_notifications,
2650 json_unused_externs,
2651 json_future_incompat,
2652 pretty,
2653 working_dir,
2654 color,
2655 logical_env,
2656 verbose,
2657 target_modifiers,
2658 }
2659}
2660
2661fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> Option<PpMode> {
2662 use PpMode::*;
2663
2664 let first = match unstable_opts.unpretty.as_deref()? {
2665 "normal" => Source(PpSourceMode::Normal),
2666 "identified" => Source(PpSourceMode::Identified),
2667 "expanded" => Source(PpSourceMode::Expanded),
2668 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2669 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2670 "ast-tree" => AstTree,
2671 "ast-tree,expanded" => AstTreeExpanded,
2672 "hir" => Hir(PpHirMode::Normal),
2673 "hir,identified" => Hir(PpHirMode::Identified),
2674 "hir,typed" => Hir(PpHirMode::Typed),
2675 "hir-tree" => HirTree,
2676 "thir-tree" => ThirTree,
2677 "thir-flat" => ThirFlat,
2678 "mir" => Mir,
2679 "stable-mir" => StableMir,
2680 "mir-cfg" => MirCFG,
2681 name => early_dcx.early_fatal(format!(
2682 "argument to `unpretty` must be one of `normal`, `identified`, \
2683 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2684 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2685 `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir`, `stable-mir`, or \
2686 `mir-cfg`; got {name}"
2687 )),
2688 };
2689 debug!("got unpretty option: {first:?}");
2690 Some(first)
2691}
2692
2693pub fn make_crate_type_option() -> RustcOptGroup {
2694 make_opt(
2695 OptionStability::Stable,
2696 OptionKind::Multi,
2697 "",
2698 "crate-type",
2699 "Comma separated list of types of crates
2700 for the compiler to emit",
2701 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2702 )
2703}
2704
2705pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2706 let mut crate_types: Vec<CrateType> = Vec::new();
2707 for unparsed_crate_type in &list_list {
2708 for part in unparsed_crate_type.split(',') {
2709 let new_part = match part {
2710 "lib" => default_lib_output(),
2711 "rlib" => CrateType::Rlib,
2712 "staticlib" => CrateType::Staticlib,
2713 "dylib" => CrateType::Dylib,
2714 "cdylib" => CrateType::Cdylib,
2715 "bin" => CrateType::Executable,
2716 "proc-macro" => CrateType::ProcMacro,
2717 _ => {
2718 return Err(format!(
2719 "unknown crate type: `{part}`, expected one of: \
2720 `lib`, `rlib`, `staticlib`, `dylib`, `cdylib`, `bin`, `proc-macro`",
2721 ));
2722 }
2723 };
2724 if !crate_types.contains(&new_part) {
2725 crate_types.push(new_part)
2726 }
2727 }
2728 }
2729
2730 Ok(crate_types)
2731}
2732
2733pub mod nightly_options {
2734 use rustc_feature::UnstableFeatures;
2735
2736 use super::{OptionStability, RustcOptGroup};
2737 use crate::EarlyDiagCtxt;
2738
2739 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2740 match_is_nightly_build(matches)
2741 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2742 }
2743
2744 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2745 is_nightly_build(matches.opt_str("crate-name").as_deref())
2746 }
2747
2748 fn is_nightly_build(krate: Option<&str>) -> bool {
2749 UnstableFeatures::from_environment(krate).is_nightly_build()
2750 }
2751
2752 pub fn check_nightly_options(
2753 early_dcx: &EarlyDiagCtxt,
2754 matches: &getopts::Matches,
2755 flags: &[RustcOptGroup],
2756 ) {
2757 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2758 let really_allows_unstable_options = match_is_nightly_build(matches);
2759 let mut nightly_options_on_stable = 0;
2760
2761 for opt in flags.iter() {
2762 if opt.stability == OptionStability::Stable {
2763 continue;
2764 }
2765 if !matches.opt_present(opt.name) {
2766 continue;
2767 }
2768 if opt.name != "Z" && !has_z_unstable_option {
2769 early_dcx.early_fatal(format!(
2770 "the `-Z unstable-options` flag must also be passed to enable \
2771 the flag `{}`",
2772 opt.name
2773 ));
2774 }
2775 if really_allows_unstable_options {
2776 continue;
2777 }
2778 match opt.stability {
2779 OptionStability::Unstable => {
2780 nightly_options_on_stable += 1;
2781 let msg = format!(
2782 "the option `{}` is only accepted on the nightly compiler",
2783 opt.name
2784 );
2785 let _ = early_dcx.early_err(msg);
2787 }
2788 OptionStability::Stable => {}
2789 }
2790 }
2791 if nightly_options_on_stable > 0 {
2792 early_dcx
2793 .early_help("consider switching to a nightly toolchain: `rustup default nightly`");
2794 early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
2795 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>");
2796 early_dcx.early_fatal(format!(
2797 "{} nightly option{} were parsed",
2798 nightly_options_on_stable,
2799 if nightly_options_on_stable > 1 { "s" } else { "" }
2800 ));
2801 }
2802 }
2803}
2804
2805impl fmt::Display for CrateType {
2806 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2807 match *self {
2808 CrateType::Executable => "bin".fmt(f),
2809 CrateType::Dylib => "dylib".fmt(f),
2810 CrateType::Rlib => "rlib".fmt(f),
2811 CrateType::Staticlib => "staticlib".fmt(f),
2812 CrateType::Cdylib => "cdylib".fmt(f),
2813 CrateType::ProcMacro => "proc-macro".fmt(f),
2814 }
2815 }
2816}
2817
2818impl IntoDiagArg for CrateType {
2819 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2820 self.to_string().into_diag_arg(&mut None)
2821 }
2822}
2823
2824#[derive(Copy, Clone, PartialEq, Debug)]
2825pub enum PpSourceMode {
2826 Normal,
2828 Expanded,
2830 Identified,
2832 ExpandedIdentified,
2834 ExpandedHygiene,
2836}
2837
2838#[derive(Copy, Clone, PartialEq, Debug)]
2839pub enum PpHirMode {
2840 Normal,
2842 Identified,
2844 Typed,
2846}
2847
2848#[derive(Copy, Clone, PartialEq, Debug)]
2849pub enum PpMode {
2851 Source(PpSourceMode),
2854 AstTree,
2856 AstTreeExpanded,
2858 Hir(PpHirMode),
2860 HirTree,
2862 ThirTree,
2864 ThirFlat,
2866 Mir,
2868 MirCFG,
2870 StableMir,
2872}
2873
2874impl PpMode {
2875 pub fn needs_ast_map(&self) -> bool {
2876 use PpMode::*;
2877 use PpSourceMode::*;
2878 match *self {
2879 Source(Normal | Identified) | AstTree => false,
2880
2881 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2882 | AstTreeExpanded
2883 | Hir(_)
2884 | HirTree
2885 | ThirTree
2886 | ThirFlat
2887 | Mir
2888 | MirCFG
2889 | StableMir => true,
2890 }
2891 }
2892
2893 pub fn needs_analysis(&self) -> bool {
2894 use PpMode::*;
2895 matches!(*self, Hir(PpHirMode::Typed) | Mir | StableMir | MirCFG | ThirTree | ThirFlat)
2896 }
2897}
2898
2899#[derive(Clone, Hash, PartialEq, Eq, Debug)]
2900pub enum WasiExecModel {
2901 Command,
2902 Reactor,
2903}
2904
2905pub(crate) mod dep_tracking {
2924 use std::collections::BTreeMap;
2925 use std::hash::Hash;
2926 use std::num::NonZero;
2927 use std::path::PathBuf;
2928
2929 use rustc_abi::Align;
2930 use rustc_data_structures::fx::FxIndexMap;
2931 use rustc_data_structures::stable_hasher::StableHasher;
2932 use rustc_errors::LanguageIdentifier;
2933 use rustc_feature::UnstableFeatures;
2934 use rustc_hashes::Hash64;
2935 use rustc_span::RealFileName;
2936 use rustc_span::edition::Edition;
2937 use rustc_target::spec::{
2938 CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
2939 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple,
2940 TlsModel, WasmCAbi,
2941 };
2942
2943 use super::{
2944 AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
2945 CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
2946 InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
2947 LtoCli, MirStripDebugInfo, NextSolverConfig, OomStrategy, OptLevel, OutFileName,
2948 OutputType, OutputTypes, PatchableFunctionEntry, Polonius, RemapPathScopeComponents,
2949 ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
2950 SymbolManglingVersion, WasiExecModel,
2951 };
2952 use crate::lint;
2953 use crate::utils::NativeLib;
2954
2955 pub(crate) trait DepTrackingHash {
2956 fn hash(
2957 &self,
2958 hasher: &mut StableHasher,
2959 error_format: ErrorOutputType,
2960 for_crate_hash: bool,
2961 );
2962 }
2963
2964 macro_rules! impl_dep_tracking_hash_via_hash {
2965 ($($t:ty),+ $(,)?) => {$(
2966 impl DepTrackingHash for $t {
2967 fn hash(&self, hasher: &mut StableHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2968 Hash::hash(self, hasher);
2969 }
2970 }
2971 )+};
2972 }
2973
2974 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2975 fn hash(
2976 &self,
2977 hasher: &mut StableHasher,
2978 error_format: ErrorOutputType,
2979 for_crate_hash: bool,
2980 ) {
2981 match self {
2982 Some(x) => {
2983 Hash::hash(&1, hasher);
2984 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2985 }
2986 None => Hash::hash(&0, hasher),
2987 }
2988 }
2989 }
2990
2991 impl_dep_tracking_hash_via_hash!(
2992 AutoDiff,
2993 bool,
2994 usize,
2995 NonZero<usize>,
2996 u64,
2997 Hash64,
2998 String,
2999 PathBuf,
3000 lint::Level,
3001 WasiExecModel,
3002 u32,
3003 FramePointer,
3004 RelocModel,
3005 CodeModel,
3006 TlsModel,
3007 InstrumentCoverage,
3008 CoverageOptions,
3009 InstrumentXRay,
3010 CrateType,
3011 MergeFunctions,
3012 OnBrokenPipe,
3013 PanicStrategy,
3014 RelroLevel,
3015 OptLevel,
3016 LtoCli,
3017 DebugInfo,
3018 DebugInfoCompression,
3019 MirStripDebugInfo,
3020 CollapseMacroDebuginfo,
3021 UnstableFeatures,
3022 NativeLib,
3023 SanitizerSet,
3024 CFGuard,
3025 CFProtection,
3026 TargetTuple,
3027 Edition,
3028 LinkerPluginLto,
3029 ResolveDocLinks,
3030 SplitDebuginfo,
3031 SplitDwarfKind,
3032 StackProtector,
3033 SwitchWithOptPath,
3034 SymbolManglingVersion,
3035 SymbolVisibility,
3036 RemapPathScopeComponents,
3037 SourceFileHashAlgorithm,
3038 OutFileName,
3039 OutputType,
3040 RealFileName,
3041 LocationDetail,
3042 FmtDebug,
3043 BranchProtection,
3044 OomStrategy,
3045 LanguageIdentifier,
3046 NextSolverConfig,
3047 PatchableFunctionEntry,
3048 Polonius,
3049 InliningThreshold,
3050 FunctionReturn,
3051 WasmCAbi,
3052 Align,
3053 );
3054
3055 impl<T1, T2> DepTrackingHash for (T1, T2)
3056 where
3057 T1: DepTrackingHash,
3058 T2: DepTrackingHash,
3059 {
3060 fn hash(
3061 &self,
3062 hasher: &mut StableHasher,
3063 error_format: ErrorOutputType,
3064 for_crate_hash: bool,
3065 ) {
3066 Hash::hash(&0, hasher);
3067 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3068 Hash::hash(&1, hasher);
3069 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3070 }
3071 }
3072
3073 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
3074 where
3075 T1: DepTrackingHash,
3076 T2: DepTrackingHash,
3077 T3: DepTrackingHash,
3078 {
3079 fn hash(
3080 &self,
3081 hasher: &mut StableHasher,
3082 error_format: ErrorOutputType,
3083 for_crate_hash: bool,
3084 ) {
3085 Hash::hash(&0, hasher);
3086 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3087 Hash::hash(&1, hasher);
3088 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3089 Hash::hash(&2, hasher);
3090 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
3091 }
3092 }
3093
3094 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
3095 fn hash(
3096 &self,
3097 hasher: &mut StableHasher,
3098 error_format: ErrorOutputType,
3099 for_crate_hash: bool,
3100 ) {
3101 Hash::hash(&self.len(), hasher);
3102 for (index, elem) in self.iter().enumerate() {
3103 Hash::hash(&index, hasher);
3104 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
3105 }
3106 }
3107 }
3108
3109 impl<T: DepTrackingHash, V: DepTrackingHash> DepTrackingHash for FxIndexMap<T, V> {
3110 fn hash(
3111 &self,
3112 hasher: &mut StableHasher,
3113 error_format: ErrorOutputType,
3114 for_crate_hash: bool,
3115 ) {
3116 Hash::hash(&self.len(), hasher);
3117 for (key, value) in self.iter() {
3118 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3119 DepTrackingHash::hash(value, hasher, error_format, for_crate_hash);
3120 }
3121 }
3122 }
3123
3124 impl DepTrackingHash for OutputTypes {
3125 fn hash(
3126 &self,
3127 hasher: &mut StableHasher,
3128 error_format: ErrorOutputType,
3129 for_crate_hash: bool,
3130 ) {
3131 Hash::hash(&self.0.len(), hasher);
3132 for (key, val) in &self.0 {
3133 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3134 if !for_crate_hash {
3135 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
3136 }
3137 }
3138 }
3139 }
3140
3141 pub(crate) fn stable_hash(
3143 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
3144 hasher: &mut StableHasher,
3145 error_format: ErrorOutputType,
3146 for_crate_hash: bool,
3147 ) {
3148 for (key, sub_hash) in sub_hashes {
3149 Hash::hash(&key.len(), hasher);
3152 Hash::hash(key, hasher);
3153 sub_hash.hash(hasher, error_format, for_crate_hash);
3154 }
3155 }
3156}
3157
3158#[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
3160pub enum OomStrategy {
3161 Panic,
3163
3164 Abort,
3166}
3167
3168impl OomStrategy {
3169 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
3170
3171 pub fn should_panic(self) -> u8 {
3172 match self {
3173 OomStrategy::Panic => 1,
3174 OomStrategy::Abort => 0,
3175 }
3176 }
3177}
3178
3179#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3181pub enum ProcMacroExecutionStrategy {
3182 SameThread,
3184
3185 CrossThread,
3187}
3188
3189#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3197pub enum CollapseMacroDebuginfo {
3198 No = 0,
3200 Unspecified = 1,
3202 External = 2,
3204 Yes = 3,
3206}
3207
3208#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3210pub enum DumpMonoStatsFormat {
3211 Markdown,
3213 Json,
3215}
3216
3217impl DumpMonoStatsFormat {
3218 pub fn extension(self) -> &'static str {
3219 match self {
3220 Self::Markdown => "md",
3221 Self::Json => "json",
3222 }
3223 }
3224}
3225
3226#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3229pub struct PatchableFunctionEntry {
3230 prefix: u8,
3232 entry: u8,
3234}
3235
3236impl PatchableFunctionEntry {
3237 pub fn from_total_and_prefix_nops(
3238 total_nops: u8,
3239 prefix_nops: u8,
3240 ) -> Option<PatchableFunctionEntry> {
3241 if total_nops < prefix_nops {
3242 None
3243 } else {
3244 Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops })
3245 }
3246 }
3247 pub fn prefix(&self) -> u8 {
3248 self.prefix
3249 }
3250 pub fn entry(&self) -> u8 {
3251 self.entry
3252 }
3253}
3254
3255#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3258pub enum Polonius {
3259 #[default]
3261 Off,
3262
3263 Legacy,
3265
3266 Next,
3268}
3269
3270impl Polonius {
3271 pub fn is_legacy_enabled(&self) -> bool {
3273 matches!(self, Polonius::Legacy)
3274 }
3275
3276 pub fn is_next_enabled(&self) -> bool {
3278 matches!(self, Polonius::Next)
3279 }
3280}
3281
3282#[derive(Clone, Copy, PartialEq, Hash, Debug)]
3283pub enum InliningThreshold {
3284 Always,
3285 Sometimes(usize),
3286 Never,
3287}
3288
3289impl Default for InliningThreshold {
3290 fn default() -> Self {
3291 Self::Sometimes(100)
3292 }
3293}
3294
3295#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
3297pub enum FunctionReturn {
3298 #[default]
3300 Keep,
3301
3302 ThunkExtern,
3304}
3305
3306#[derive(Clone, Copy, Default, PartialEq, Debug)]
3309pub enum MirIncludeSpans {
3310 Off,
3311 On,
3312 #[default]
3315 Nll,
3316}
3317
3318impl MirIncludeSpans {
3319 pub fn is_enabled(self) -> bool {
3324 self == MirIncludeSpans::On
3325 }
3326}