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