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