1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
6 use crate::search_paths::SearchPath;
7 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
8 use crate::{early_error, early_warn, Session};
9 use crate::{lint, HashStableContext};
11 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
13 use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
14 use rustc_target::abi::Align;
15 use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
16 use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
18 use crate::parse::{CrateCheckConfig, CrateConfig};
19 use rustc_feature::UnstableFeatures;
20 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
21 use rustc_span::source_map::{FileName, FilePathMapping};
22 use rustc_span::symbol::{sym, Symbol};
23 use rustc_span::RealFileName;
24 use rustc_span::SourceFileHashAlgorithm;
26 use rustc_errors::emitter::HumanReadableErrorType;
27 use rustc_errors::{ColorConfig, HandlerFlags};
29 use std::collections::btree_map::{
30 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
32 use std::collections::{BTreeMap, BTreeSet};
36 use std::path::{Path, PathBuf};
37 use std::str::{self, FromStr};
38 use std::sync::LazyLock;
42 /// The different settings that the `-C strip` flag can have.
43 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
45 /// Do not strip at all.
51 /// Strip all symbols.
55 /// The different settings that the `-C control-flow-guard` flag can have.
56 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
58 /// Do not emit Control Flow Guard metadata or checks.
61 /// Emit Control Flow Guard metadata but no checks.
64 /// Emit Control Flow Guard metadata and checks.
68 /// The different settings that the `-Z cf-protection` flag can have.
69 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
70 pub enum CFProtection {
71 /// Do not enable control-flow protection
74 /// Emit control-flow protection for branches (enables indirect branch tracking).
77 /// Emit control-flow protection for returns.
80 /// Emit control-flow protection for both branches and returns.
84 #[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
94 /// This is what the `LtoCli` values get mapped to after resolving defaults and
95 /// and taking other command line options into account.
97 /// Note that linker plugin-based LTO is a different mechanism entirely.
98 #[derive(Clone, PartialEq)]
100 /// Don't do any LTO whatsoever.
103 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
106 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
107 /// only relevant if multiple CGUs are used.
110 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
114 /// The different settings that the `-C lto` flag can have.
115 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
127 /// No `-C lto` flag passed
131 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
132 /// document highlighting each span of every statement (including terminators). `Terminator` and
133 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
134 /// computed span for the block, representing the entire range, covering the block's terminator and
135 /// all of its statements.
136 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
137 pub enum MirSpanview {
138 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
140 /// `-Z dump_mir_spanview=terminator`
142 /// `-Z dump_mir_spanview=block`
146 /// The different settings that the `-C instrument-coverage` flag can have.
148 /// Coverage instrumentation now supports combining `-C instrument-coverage`
149 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
150 /// and higher). Nevertheless, there are many variables, depending on options
151 /// selected, code structure, and enabled attributes. If errors are encountered,
152 /// either while compiling or when generating `llvm-cov show` reports, consider
153 /// lowering the optimization level, including or excluding `-C link-dead-code`,
154 /// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
155 /// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
157 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
158 /// coverage map, it will not attempt to generate synthetic functions for unused
159 /// (and not code-generated) functions (whether they are generic or not). As a
160 /// result, non-codegenned functions will not be included in the coverage map,
161 /// and will not appear, as covered or uncovered, in coverage reports.
163 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
164 /// unless the function has type parameters.
165 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
166 pub enum InstrumentCoverage {
167 /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
169 /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
170 ExceptUnusedGenerics,
171 /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
172 ExceptUnusedFunctions,
173 /// `-C instrument-coverage=off` (or `no`, etc.)
177 #[derive(Clone, PartialEq, Hash, Debug)]
178 pub enum LinkerPluginLto {
179 LinkerPlugin(PathBuf),
184 /// Used with `-Z assert-incr-state`.
185 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
186 pub enum IncrementalStateAssertion {
187 /// Found and loaded an existing session directory.
189 /// Note that this says nothing about whether any particular query
190 /// will be found to be red or green.
192 /// Did not load an existing session directory.
196 impl LinkerPluginLto {
197 pub fn enabled(&self) -> bool {
199 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
200 LinkerPluginLto::Disabled => false,
205 /// The different settings that can be enabled via the `-Z location-detail` flag.
206 #[derive(Clone, PartialEq, Hash, Debug)]
207 pub struct LocationDetail {
213 impl LocationDetail {
214 pub fn all() -> Self {
215 Self { file: true, line: true, column: true }
219 #[derive(Clone, PartialEq, Hash, Debug)]
220 pub enum SwitchWithOptPath {
221 Enabled(Option<PathBuf>),
225 impl SwitchWithOptPath {
226 pub fn enabled(&self) -> bool {
228 SwitchWithOptPath::Enabled(_) => true,
229 SwitchWithOptPath::Disabled => false,
234 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
235 #[derive(Encodable, Decodable)]
236 pub enum SymbolManglingVersion {
241 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
248 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
249 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
250 /// uses DWARF for debug-information.
252 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
253 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
254 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
255 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
256 /// them in the object file in such a way that the linker will skip them.
257 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
258 pub enum SplitDwarfKind {
259 /// Sections which do not require relocation are written into object file but ignored by the
262 /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
263 /// which is ignored by the linker.
267 impl FromStr for SplitDwarfKind {
270 fn from_str(s: &str) -> Result<Self, ()> {
272 "single" => SplitDwarfKind::Single,
273 "split" => SplitDwarfKind::Split,
279 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
280 #[derive(Encodable, Decodable)]
281 pub enum OutputType {
292 // Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
293 unsafe impl StableOrd for OutputType {}
295 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
298 fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
304 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
306 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
308 | OutputType::Assembly
309 | OutputType::LlvmAssembly
311 | OutputType::Object => false,
315 fn shorthand(&self) -> &'static str {
317 OutputType::Bitcode => "llvm-bc",
318 OutputType::Assembly => "asm",
319 OutputType::LlvmAssembly => "llvm-ir",
320 OutputType::Mir => "mir",
321 OutputType::Object => "obj",
322 OutputType::Metadata => "metadata",
323 OutputType::Exe => "link",
324 OutputType::DepInfo => "dep-info",
328 fn from_shorthand(shorthand: &str) -> Option<Self> {
329 Some(match shorthand {
330 "asm" => OutputType::Assembly,
331 "llvm-ir" => OutputType::LlvmAssembly,
332 "mir" => OutputType::Mir,
333 "llvm-bc" => OutputType::Bitcode,
334 "obj" => OutputType::Object,
335 "metadata" => OutputType::Metadata,
336 "link" => OutputType::Exe,
337 "dep-info" => OutputType::DepInfo,
342 fn shorthands_display() -> String {
344 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
345 OutputType::Bitcode.shorthand(),
346 OutputType::Assembly.shorthand(),
347 OutputType::LlvmAssembly.shorthand(),
348 OutputType::Mir.shorthand(),
349 OutputType::Object.shorthand(),
350 OutputType::Metadata.shorthand(),
351 OutputType::Exe.shorthand(),
352 OutputType::DepInfo.shorthand(),
356 pub fn extension(&self) -> &'static str {
358 OutputType::Bitcode => "bc",
359 OutputType::Assembly => "s",
360 OutputType::LlvmAssembly => "ll",
361 OutputType::Mir => "mir",
362 OutputType::Object => "o",
363 OutputType::Metadata => "rmeta",
364 OutputType::DepInfo => "d",
365 OutputType::Exe => "",
370 /// The type of diagnostics output to generate.
371 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
372 pub enum ErrorOutputType {
373 /// Output meant for the consumption of humans.
374 HumanReadable(HumanReadableErrorType),
375 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
377 /// Render the JSON in a human readable way (with indents and newlines).
379 /// The JSON output includes a `rendered` field that includes the rendered
381 json_rendered: HumanReadableErrorType,
385 impl Default for ErrorOutputType {
386 fn default() -> Self {
387 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
391 /// Parameter to control path trimming.
392 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
393 pub enum TrimmedDefPaths {
394 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
397 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
399 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
403 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
404 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
405 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
406 /// should only depend on the output types, not the paths they're written to.
407 #[derive(Clone, Debug, Hash, HashStable_Generic)]
408 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
411 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
412 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
415 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
419 pub fn contains_key(&self, key: &OutputType) -> bool {
420 self.0.contains_key(key)
423 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
427 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
431 pub fn len(&self) -> usize {
435 /// Returns `true` if any of the output types require codegen or linking.
436 pub fn should_codegen(&self) -> bool {
437 self.0.keys().any(|k| match *k {
439 | OutputType::Assembly
440 | OutputType::LlvmAssembly
443 | OutputType::Exe => true,
444 OutputType::Metadata | OutputType::DepInfo => false,
448 /// Returns `true` if any of the output types require linking.
449 pub fn should_link(&self) -> bool {
450 self.0.keys().any(|k| match *k {
452 | OutputType::Assembly
453 | OutputType::LlvmAssembly
455 | OutputType::Metadata
457 | OutputType::DepInfo => false,
458 OutputType::Exe => true,
463 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
464 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
465 /// would break dependency tracking for command-line arguments.
467 pub struct Externs(BTreeMap<String, ExternEntry>);
469 #[derive(Clone, Debug)]
470 pub struct ExternEntry {
471 pub location: ExternLocation,
472 /// Indicates this is a "private" dependency for the
473 /// `exported_private_dependencies` lint.
475 /// This can be set with the `priv` option like
476 /// `--extern priv:name=foo.rlib`.
477 pub is_private_dep: bool,
478 /// Add the extern entry to the extern prelude.
480 /// This can be disabled with the `noprelude` option like
481 /// `--extern noprelude:name`.
482 pub add_prelude: bool,
483 /// The extern entry shouldn't be considered for unused dependency warnings.
485 /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
486 /// suppress `unused-crate-dependencies` warnings.
487 pub nounused_dep: bool,
490 #[derive(Clone, Debug)]
491 pub enum ExternLocation {
492 /// Indicates to look for the library in the search paths.
494 /// Added via `--extern name`.
495 FoundInLibrarySearchDirectories,
496 /// The locations where this extern entry must be found.
498 /// The `CrateLoader` is responsible for loading these and figuring out
499 /// which one to use.
501 /// Added via `--extern prelude_name=some_file.rlib`
502 ExactPaths(BTreeSet<CanonicalizedPath>),
506 /// Used for testing.
507 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
511 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
515 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
519 pub fn len(&self) -> usize {
525 fn new(location: ExternLocation) -> ExternEntry {
526 ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
529 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
530 match &self.location {
531 ExternLocation::ExactPaths(set) => Some(set.iter()),
537 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
538 pub enum PrintRequest {
553 StackProtectorStrategies,
558 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
559 pub enum TraitSolver {
560 /// Classic trait solver in `rustc_trait_selection::traits::select`
562 /// Chalk trait solver
564 /// Experimental trait solver in `rustc_trait_selection::solve`
569 /// Load source code from a file.
571 /// Load source code from a string.
573 /// A string that is shown in place of a filename.
575 /// An anonymous string containing the source code.
581 pub fn filestem(&self) -> &str {
583 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
584 Input::Str { .. } => "rust_out",
588 pub fn source_name(&self) -> FileName {
590 Input::File(ref ifile) => ifile.clone().into(),
591 Input::Str { ref name, .. } => name.clone(),
595 pub fn opt_path(&self) -> Option<&Path> {
597 Input::File(file) => Some(file),
598 Input::Str { name, .. } => match name {
599 FileName::Real(real) => real.local_path(),
600 FileName::QuoteExpansion(_) => None,
601 FileName::Anon(_) => None,
602 FileName::MacroExpansion(_) => None,
603 FileName::ProcMacroSourceCode(_) => None,
604 FileName::CfgSpec(_) => None,
605 FileName::CliCrateAttr(_) => None,
606 FileName::Custom(_) => None,
607 FileName::DocTest(path, _) => Some(path),
608 FileName::InlineAsm(_) => None,
614 #[derive(Clone, Hash, Debug, HashStable_Generic)]
615 pub struct OutputFilenames {
616 pub out_directory: PathBuf,
618 pub single_output_file: Option<PathBuf>,
619 pub temps_directory: Option<PathBuf>,
620 pub outputs: OutputTypes,
623 pub const RLINK_EXT: &str = "rlink";
624 pub const RUST_CGU_EXT: &str = "rcgu";
625 pub const DWARF_OBJECT_EXT: &str = "dwo";
627 impl OutputFilenames {
629 out_directory: PathBuf,
630 out_filestem: String,
631 single_output_file: Option<PathBuf>,
632 temps_directory: Option<PathBuf>,
634 outputs: OutputTypes,
641 filestem: format!("{out_filestem}{extra}"),
645 pub fn path(&self, flavor: OutputType) -> PathBuf {
648 .and_then(|p| p.to_owned())
649 .or_else(|| self.single_output_file.clone())
650 .unwrap_or_else(|| self.output_path(flavor))
653 /// Gets the output path where a compilation artifact of the given type
654 /// should be placed on disk.
655 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
656 let extension = flavor.extension();
657 self.with_directory_and_extension(&self.out_directory, extension)
660 /// Gets the path where a compilation artifact of the given type for the
661 /// given codegen unit should be placed on disk. If codegen_unit_name is
662 /// None, a path distinct from those of any codegen unit will be generated.
663 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
664 let extension = flavor.extension();
665 self.temp_path_ext(extension, codegen_unit_name)
668 /// Like `temp_path`, but specifically for dwarf objects.
669 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
670 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
673 /// Like `temp_path`, but also supports things where there is no corresponding
674 /// OutputType, like noopt-bitcode or lto-bitcode.
675 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
676 let mut extension = String::new();
678 if let Some(codegen_unit_name) = codegen_unit_name {
679 extension.push_str(codegen_unit_name);
683 if !extension.is_empty() {
685 extension.push_str(RUST_CGU_EXT);
689 extension.push_str(ext);
692 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
694 self.with_directory_and_extension(temps_directory, &extension)
697 pub fn with_extension(&self, extension: &str) -> PathBuf {
698 self.with_directory_and_extension(&self.out_directory, extension)
701 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
702 let mut path = directory.join(&self.filestem);
703 path.set_extension(extension);
707 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
708 /// mode is being used, which is the logic that this function is intended to encapsulate.
709 pub fn split_dwarf_path(
711 split_debuginfo_kind: SplitDebuginfo,
712 split_dwarf_kind: SplitDwarfKind,
713 cgu_name: Option<&str>,
714 ) -> Option<PathBuf> {
715 let obj_out = self.temp_path(OutputType::Object, cgu_name);
716 let dwo_out = self.temp_path_dwo(cgu_name);
717 match (split_debuginfo_kind, split_dwarf_kind) {
718 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
719 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
720 // (pointing at the path which is being determined here). Use the path to the current
722 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
725 // Split mode emits the DWARF into a different file, use that path.
726 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
733 pub fn host_triple() -> &'static str {
734 // Get the host triple out of the build environment. This ensures that our
735 // idea of the host triple is the same as for the set of libraries we've
736 // actually built. We can't just take LLVM's host triple because they
737 // normalize all ix86 architectures to i386.
739 // Instead of grabbing the host triple (for the current host), we grab (at
740 // compile time) the target triple that this rustc is built with and
741 // calling that (at runtime) the host triple.
742 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
745 impl Default for Options {
746 fn default() -> Options {
748 assert_incr_state: None,
749 crate_types: Vec::new(),
750 optimize: OptLevel::No,
751 debuginfo: DebugInfo::None,
752 lint_opts: Vec::new(),
754 describe_lints: false,
755 output_types: OutputTypes(BTreeMap::new()),
756 search_paths: vec![],
758 target_triple: TargetTriple::from_triple(host_triple()),
761 unstable_opts: Default::default(),
763 cg: Default::default(),
764 error_format: ErrorOutputType::default(),
765 diagnostic_width: None,
766 externs: Externs(BTreeMap::new()),
769 unstable_features: UnstableFeatures::Disallow,
770 debug_assertions: true,
771 actually_rustdoc: false,
772 trimmed_def_paths: TrimmedDefPaths::default(),
773 cli_forced_codegen_units: None,
774 cli_forced_local_thinlto_off: false,
775 remap_path_prefix: Vec::new(),
776 real_rust_source_base_dir: None,
777 edition: DEFAULT_EDITION,
778 json_artifact_notifications: false,
779 json_unused_externs: JsonUnusedExterns::No,
780 json_future_incompat: false,
782 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
788 /// Returns `true` if there is a reason to build the dep graph.
789 pub fn build_dep_graph(&self) -> bool {
790 self.incremental.is_some()
791 || self.unstable_opts.dump_dep_graph
792 || self.unstable_opts.query_dep_graph
795 pub fn file_path_mapping(&self) -> FilePathMapping {
796 FilePathMapping::new(self.remap_path_prefix.clone())
799 /// Returns `true` if there will be an output file generated.
800 pub fn will_create_output_file(&self) -> bool {
801 !self.unstable_opts.parse_only && // The file is just being parsed
802 !self.unstable_opts.ls // The file is just being queried
806 pub fn share_generics(&self) -> bool {
807 match self.unstable_opts.share_generics {
808 Some(setting) => setting,
809 None => match self.optimize {
810 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
811 OptLevel::Default | OptLevel::Aggressive => false,
816 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
817 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
820 #[allow(rustc::bad_opt_access)]
821 pub fn incremental_relative_spans(&self) -> bool {
822 self.unstable_opts.incremental_relative_spans
823 || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
827 impl UnstableOptions {
828 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
831 treat_err_as_bug: self.treat_err_as_bug,
832 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
833 report_delayed_bugs: self.report_delayed_bugs,
834 macro_backtrace: self.macro_backtrace,
835 deduplicate_diagnostics: self.deduplicate_diagnostics,
836 track_diagnostics: self.track_diagnostics,
841 // The type of entry function, so users can have their own entry functions
842 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
843 pub enum EntryFnType {
845 /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
847 /// What values that are valid and what they mean must be in sync
848 /// across rustc and libstd, but we don't want it public in libstd,
849 /// so we take a bit of an unusual approach with simple constants
850 /// and an `include!()`.
856 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
857 #[derive(HashStable_Generic)]
867 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
874 pub fn is_empty(&self) -> bool {
876 Passes::Some(ref v) => v.is_empty(),
877 Passes::All => false,
881 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
883 Passes::Some(ref mut v) => v.extend(passes),
889 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
895 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
901 #[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
902 pub struct BranchProtection {
904 pub pac_ret: Option<PacRet>,
907 pub const fn default_lib_output() -> CrateType {
911 fn default_configuration(sess: &Session) -> CrateConfig {
912 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
913 let end = &sess.target.endian;
914 let arch = &sess.target.arch;
915 let wordsz = sess.target.pointer_width.to_string();
916 let os = &sess.target.os;
917 let env = &sess.target.env;
918 let abi = &sess.target.abi;
919 let vendor = &sess.target.vendor;
920 let min_atomic_width = sess.target.min_atomic_width();
921 let max_atomic_width = sess.target.max_atomic_width();
922 let atomic_cas = sess.target.atomic_cas;
923 let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
924 sess.emit_fatal(err);
927 let mut ret = CrateConfig::default();
928 ret.reserve(7); // the minimum number of insertions
930 ret.insert((sym::target_os, Some(Symbol::intern(os))));
931 for fam in sess.target.families.as_ref() {
932 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
933 if fam == "windows" {
934 ret.insert((sym::windows, None));
935 } else if fam == "unix" {
936 ret.insert((sym::unix, None));
939 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
940 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
941 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
942 ret.insert((sym::target_env, Some(Symbol::intern(env))));
943 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
944 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
945 if sess.target.has_thread_local {
946 ret.insert((sym::target_thread_local, None));
949 (8, layout.i8_align.abi),
950 (16, layout.i16_align.abi),
951 (32, layout.i32_align.abi),
952 (64, layout.i64_align.abi),
953 (128, layout.i128_align.abi),
955 if i >= min_atomic_width && i <= max_atomic_width {
956 let mut insert_atomic = |s, align: Align| {
957 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
959 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
961 if align.bits() == i {
962 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
965 let s = i.to_string();
966 insert_atomic(&s, align);
968 insert_atomic("ptr", layout.pointer_align.abi);
973 let panic_strategy = sess.panic_strategy();
974 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
976 for s in sess.opts.unstable_opts.sanitizer {
977 let symbol = Symbol::intern(&s.to_string());
978 ret.insert((sym::sanitize, Some(symbol)));
981 if sess.opts.debug_assertions {
982 ret.insert((sym::debug_assertions, None));
984 // JUSTIFICATION: before wrapper fn is available
985 #[allow(rustc::bad_opt_access)]
986 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
987 ret.insert((sym::proc_macro, None));
992 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
993 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
994 /// but the symbol interner is not yet set up then, so we must convert it later.
995 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
996 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
999 /// The parsed `--check-cfg` options
1000 pub struct CheckCfg<T = String> {
1001 /// The set of all `names()`, if None no name checking is performed
1002 pub names_valid: Option<FxHashSet<T>>,
1003 /// Is well known values activated
1004 pub well_known_values: bool,
1005 /// The set of all `values()`
1006 pub values_valid: FxHashMap<T, FxHashSet<T>>,
1009 impl<T> Default for CheckCfg<T> {
1010 fn default() -> Self {
1012 names_valid: Default::default(),
1013 values_valid: Default::default(),
1014 well_known_values: false,
1019 impl<T> CheckCfg<T> {
1020 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1025 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1029 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1031 well_known_values: self.well_known_values,
1036 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1037 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1038 /// but the symbol interner is not yet set up then, so we must convert it later.
1039 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1040 cfg.map_data(|s| Symbol::intern(s))
1043 impl CrateCheckConfig {
1044 /// Fills a `CrateCheckConfig` with well-known configuration names.
1045 fn fill_well_known_names(&mut self) {
1046 // NOTE: This should be kept in sync with `default_configuration` and
1047 // `fill_well_known_values`
1048 const WELL_KNOWN_NAMES: &[Symbol] = &[
1056 sym::target_pointer_width,
1060 sym::target_thread_local,
1061 sym::target_has_atomic_load_store,
1062 sym::target_has_atomic,
1063 sym::target_has_atomic_equal_alignment,
1064 sym::target_feature,
1067 sym::debug_assertions,
1078 // We only insert well-known names if `names()` was activated
1079 if let Some(names_valid) = &mut self.names_valid {
1080 names_valid.extend(WELL_KNOWN_NAMES);
1084 /// Fills a `CrateCheckConfig` with well-known configuration values.
1085 fn fill_well_known_values(&mut self) {
1086 if !self.well_known_values {
1090 // NOTE: This should be kept in sync with `default_configuration` and
1091 // `fill_well_known_names`
1093 let panic_values = &PanicStrategy::all();
1095 let atomic_values = &[
1097 sym::integer(8usize),
1098 sym::integer(16usize),
1099 sym::integer(32usize),
1100 sym::integer(64usize),
1101 sym::integer(128usize),
1104 let sanitize_values = SanitizerSet::all()
1106 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1108 // Unknown possible values:
1110 // - `target_feature`
1121 sym::debug_assertions,
1122 sym::target_thread_local,
1124 self.values_valid.entry(name).or_default();
1127 // Pre-defined values
1128 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1129 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1130 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1132 .entry(sym::target_has_atomic_load_store)
1134 .extend(atomic_values);
1136 .entry(sym::target_has_atomic_equal_alignment)
1138 .extend(atomic_values);
1140 // Target specific values
1142 const VALUES: [&Symbol; 8] = [
1144 &sym::target_family,
1146 &sym::target_endian,
1149 &sym::target_vendor,
1150 &sym::target_pointer_width,
1153 // Initialize (if not already initialized)
1155 self.values_valid.entry(e).or_default();
1158 // Get all values map at once otherwise it would be costly.
1159 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1162 values_target_family,
1164 values_target_endian,
1167 values_target_vendor,
1168 values_target_pointer_width,
1171 .get_many_mut(VALUES)
1172 .expect("unable to get all the check-cfg values buckets");
1174 for target in TARGETS
1176 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1178 values_target_os.insert(Symbol::intern(&target.options.os));
1179 values_target_family
1180 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1181 values_target_arch.insert(Symbol::intern(&target.arch));
1182 values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
1183 values_target_env.insert(Symbol::intern(&target.options.env));
1184 values_target_abi.insert(Symbol::intern(&target.options.abi));
1185 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1186 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1191 pub fn fill_well_known(&mut self) {
1192 self.fill_well_known_names();
1193 self.fill_well_known_values();
1197 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1198 // Combine the configuration requested by the session (command line) with
1199 // some default and generated configuration items.
1200 let default_cfg = default_configuration(sess);
1201 // If the user wants a test runner, then add the test cfg.
1203 user_cfg.insert((sym::test, None));
1205 user_cfg.extend(default_cfg.iter().cloned());
1209 pub(super) fn build_target_config(
1211 target_override: Option<Target>,
1214 let target_result = target_override.map_or_else(
1215 || Target::search(&opts.target_triple, sysroot),
1216 |t| Ok((t, TargetWarnings::empty())),
1218 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1222 "Error loading target specification: {}. \
1223 Run `rustc --print target-list` for a list of built-in targets",
1228 for warning in target_warnings.warning_messages() {
1229 early_warn(opts.error_format, &warning)
1232 if !matches!(target.pointer_width, 16 | 32 | 64) {
1236 "target specification was invalid: \
1237 unrecognized target-pointer-width {}",
1238 target.pointer_width
1246 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1247 pub enum OptionStability {
1252 pub struct RustcOptGroup {
1253 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1254 pub name: &'static str,
1255 pub stability: OptionStability,
1258 impl RustcOptGroup {
1259 pub fn is_stable(&self) -> bool {
1260 self.stability == OptionStability::Stable
1263 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1265 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1267 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1270 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1272 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1274 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1278 // The `opt` local module holds wrappers around the `getopts` API that
1279 // adds extra rustc-specific metadata to each option; such metadata
1280 // is exposed by . The public
1281 // functions below ending with `_u` are the functions that return
1282 // *unstable* options, i.e., options that are only enabled when the
1283 // user also passes the `-Z unstable-options` debugging flag.
1285 // The `fn flag*` etc below are written so that we can use them
1286 // in the future; do not warn about them not being used right now.
1287 #![allow(dead_code)]
1289 use super::RustcOptGroup;
1291 pub type R = RustcOptGroup;
1292 pub type S = &'static str;
1294 fn stable<F>(name: S, f: F) -> R
1296 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1298 RustcOptGroup::stable(name, f)
1301 fn unstable<F>(name: S, f: F) -> R
1303 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1305 RustcOptGroup::unstable(name, f)
1308 fn longer(a: S, b: S) -> S {
1309 if a.len() > b.len() { a } else { b }
1312 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1313 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1315 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1316 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1318 pub fn flag_s(a: S, b: S, c: S) -> R {
1319 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1321 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1322 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1325 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1326 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1328 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1329 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1332 static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
1334 "Specify which edition of the compiler to use when compiling code. \
1335 The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
1338 /// Returns the "short" subset of the rustc command line options,
1339 /// including metadata for each option, such as whether the option is
1340 /// part of the stable long-term interface for rustc.
1341 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1343 opt::flag_s("h", "help", "Display this message"),
1344 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1345 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1349 "Add a directory to the library search path. The
1350 optional KIND can be one of dependency, crate, native,
1351 framework, or all (the default).",
1357 "Link the generated crate(s) to the specified native
1358 library NAME. The optional KIND can be one of
1359 static, framework, or dylib (the default).
1360 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1361 may be specified each with a prefix of either '+' to
1362 enable or '-' to disable.",
1363 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1365 make_crate_type_option(),
1366 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1376 "Comma separated list of types of output for \
1377 the compiler to emit",
1378 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1383 "Compiler information to print on stdout",
1384 "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
1385 target-list|target-cpus|target-features|relocation-models|code-models|\
1386 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1389 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1390 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1391 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1395 "Write output to compiler-chosen filename \
1402 "Provide a detailed explanation of an error \
1406 opt::flag_s("", "test", "Build a test harness"),
1407 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1408 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1409 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1410 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1411 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1412 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1416 "Set the most restrictive lint level. \
1417 More restrictive lints are capped at this \
1421 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1422 opt::flag_s("V", "version", "Print version info and exit"),
1423 opt::flag_s("v", "verbose", "Use verbose output"),
1427 /// Returns all rustc command line options, including metadata for
1428 /// each option, such as whether the option is part of the stable
1429 /// long-term interface for rustc.
1430 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1431 let mut opts = rustc_short_optgroups();
1432 // FIXME: none of these descriptions are actually used
1437 "Specify where an external rust library is located",
1440 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1441 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1445 "How errors and other messages are produced",
1448 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1452 "Configure coloring of output:
1453 auto = colorize, if output goes to a tty (default);
1454 always = always colorize output;
1455 never = never colorize output",
1456 "auto|always|never",
1461 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1466 "remap-path-prefix",
1467 "Remap source names in all output (compiler messages and output files)",
1474 pub fn get_cmd_lint_options(
1475 matches: &getopts::Matches,
1476 error_format: ErrorOutputType,
1477 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1478 let mut lint_opts_with_position = vec![];
1479 let mut describe_lints = false;
1481 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1482 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1483 if lint_name == "help" {
1484 describe_lints = true;
1486 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1491 lint_opts_with_position.sort_by_key(|x| x.0);
1492 let lint_opts = lint_opts_with_position
1495 .map(|(_, lint_name, level)| (lint_name, level))
1498 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1499 lint::Level::from_str(&cap)
1500 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1503 (lint_opts, describe_lints, lint_cap)
1506 /// Parses the `--color` flag.
1507 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1508 match matches.opt_str("color").as_deref() {
1509 Some("auto") => ColorConfig::Auto,
1510 Some("always") => ColorConfig::Always,
1511 Some("never") => ColorConfig::Never,
1513 None => ColorConfig::Auto,
1515 Some(arg) => early_error(
1516 ErrorOutputType::default(),
1518 "argument for `--color` must be auto, \
1519 always or never (instead was `{arg}`)"
1525 /// Possible json config files
1526 pub struct JsonConfig {
1527 pub json_rendered: HumanReadableErrorType,
1528 pub json_artifact_notifications: bool,
1529 pub json_unused_externs: JsonUnusedExterns,
1530 pub json_future_incompat: bool,
1533 /// Report unused externs in event stream
1534 #[derive(Copy, Clone)]
1535 pub enum JsonUnusedExterns {
1538 /// Report, but do not exit with failure status for deny/forbid
1540 /// Report, and also exit with failure status for deny/forbid
1544 impl JsonUnusedExterns {
1545 pub fn is_enabled(&self) -> bool {
1547 JsonUnusedExterns::No => false,
1548 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1552 pub fn is_loud(&self) -> bool {
1554 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1555 JsonUnusedExterns::Loud => true,
1560 /// Parse the `--json` flag.
1562 /// The first value returned is how to render JSON diagnostics, and the second
1563 /// is whether or not artifact notifications are enabled.
1564 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1565 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1566 HumanReadableErrorType::Default;
1567 let mut json_color = ColorConfig::Never;
1568 let mut json_artifact_notifications = false;
1569 let mut json_unused_externs = JsonUnusedExterns::No;
1570 let mut json_future_incompat = false;
1571 for option in matches.opt_strs("json") {
1572 // For now conservatively forbid `--color` with `--json` since `--json`
1573 // won't actually be emitting any colors and anything colorized is
1574 // embedded in a diagnostic message anyway.
1575 if matches.opt_str("color").is_some() {
1577 ErrorOutputType::default(),
1578 "cannot specify the `--color` option with `--json`",
1582 for sub_option in option.split(',') {
1584 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1585 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1586 "artifacts" => json_artifact_notifications = true,
1587 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1588 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1589 "future-incompat" => json_future_incompat = true,
1591 ErrorOutputType::default(),
1592 &format!("unknown `--json` option `{s}`"),
1599 json_rendered: json_rendered(json_color),
1600 json_artifact_notifications,
1601 json_unused_externs,
1602 json_future_incompat,
1606 /// Parses the `--error-format` flag.
1607 pub fn parse_error_format(
1608 matches: &getopts::Matches,
1610 json_rendered: HumanReadableErrorType,
1611 ) -> ErrorOutputType {
1612 // We need the `opts_present` check because the driver will send us Matches
1613 // with only stable options if no unstable options are used. Since error-format
1614 // is unstable, it will not be present. We have to use `opts_present` not
1615 // `opt_present` because the latter will panic.
1616 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1617 match matches.opt_str("error-format").as_deref() {
1618 None | Some("human") => {
1619 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1621 Some("human-annotate-rs") => {
1622 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1624 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1625 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1626 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1628 Some(arg) => early_error(
1629 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1631 "argument for `--error-format` must be `human`, `json` or \
1632 `short` (instead was `{arg}`)"
1637 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1640 match error_format {
1641 ErrorOutputType::Json { .. } => {}
1643 // Conservatively require that the `--json` argument is coupled with
1644 // `--error-format=json`. This means that `--json` is specified we
1645 // should actually be emitting JSON blobs.
1646 _ if !matches.opt_strs("json").is_empty() => {
1648 ErrorOutputType::default(),
1649 "using `--json` requires also using `--error-format=json`",
1659 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1660 let edition = match matches.opt_str("edition") {
1661 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1663 ErrorOutputType::default(),
1665 "argument for `--edition` must be one of: \
1666 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1670 None => DEFAULT_EDITION,
1673 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1674 let is_nightly = nightly_options::match_is_nightly_build(matches);
1675 let msg = if !is_nightly {
1677 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1678 edition, LATEST_STABLE_EDITION
1681 format!("edition {edition} is unstable and only available with -Z unstable-options")
1683 early_error(ErrorOutputType::default(), &msg)
1689 fn check_error_format_stability(
1690 unstable_opts: &UnstableOptions,
1691 error_format: ErrorOutputType,
1692 json_rendered: HumanReadableErrorType,
1694 if !unstable_opts.unstable_options {
1695 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1697 ErrorOutputType::Json { pretty: false, json_rendered },
1698 "`--error-format=pretty-json` is unstable",
1701 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1705 ErrorOutputType::Json { pretty: false, json_rendered },
1706 "`--error-format=human-annotate-rs` is unstable",
1712 fn parse_output_types(
1713 unstable_opts: &UnstableOptions,
1714 matches: &getopts::Matches,
1715 error_format: ErrorOutputType,
1717 let mut output_types = BTreeMap::new();
1718 if !unstable_opts.parse_only {
1719 for list in matches.opt_strs("emit") {
1720 for output_type in list.split(',') {
1721 let (shorthand, path) = match output_type.split_once('=') {
1722 None => (output_type, None),
1723 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1725 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1729 "unknown emission type: `{shorthand}` - expected one of: {display}",
1730 display = OutputType::shorthands_display(),
1734 output_types.insert(output_type, path);
1738 if output_types.is_empty() {
1739 output_types.insert(OutputType::Exe, None);
1741 OutputTypes(output_types)
1744 fn should_override_cgus_and_disable_thinlto(
1745 output_types: &OutputTypes,
1746 matches: &getopts::Matches,
1747 error_format: ErrorOutputType,
1748 mut codegen_units: Option<usize>,
1749 ) -> (bool, Option<usize>) {
1750 let mut disable_local_thinlto = false;
1751 // Issue #30063: if user requests LLVM-related output to one
1752 // particular path, disable codegen-units.
1753 let incompatible: Vec<_> = output_types
1756 .map(|ot_path| ot_path.0)
1757 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1758 .map(|ot| ot.shorthand())
1760 if !incompatible.is_empty() {
1761 match codegen_units {
1762 Some(n) if n > 1 => {
1763 if matches.opt_present("o") {
1764 for ot in &incompatible {
1768 "`--emit={ot}` with `-o` incompatible with \
1769 `-C codegen-units=N` for N > 1",
1773 early_warn(error_format, "resetting to default -C codegen-units=1");
1774 codegen_units = Some(1);
1775 disable_local_thinlto = true;
1779 codegen_units = Some(1);
1780 disable_local_thinlto = true;
1785 if codegen_units == Some(0) {
1786 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1789 (disable_local_thinlto, codegen_units)
1792 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1793 if unstable_opts.threads == 0 {
1794 early_error(error_format, "value for threads must be a positive non-zero integer");
1797 if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
1798 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1802 fn collect_print_requests(
1803 cg: &mut CodegenOptions,
1804 unstable_opts: &mut UnstableOptions,
1805 matches: &getopts::Matches,
1806 error_format: ErrorOutputType,
1807 ) -> Vec<PrintRequest> {
1808 let mut prints = Vec::<PrintRequest>::new();
1809 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1810 prints.push(PrintRequest::TargetCPUs);
1811 cg.target_cpu = None;
1813 if cg.target_feature == "help" {
1814 prints.push(PrintRequest::TargetFeatures);
1815 cg.target_feature = String::new();
1818 const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
1819 ("crate-name", PrintRequest::CrateName),
1820 ("file-names", PrintRequest::FileNames),
1821 ("sysroot", PrintRequest::Sysroot),
1822 ("target-libdir", PrintRequest::TargetLibdir),
1823 ("cfg", PrintRequest::Cfg),
1824 ("calling-conventions", PrintRequest::CallingConventions),
1825 ("target-list", PrintRequest::TargetList),
1826 ("target-cpus", PrintRequest::TargetCPUs),
1827 ("target-features", PrintRequest::TargetFeatures),
1828 ("relocation-models", PrintRequest::RelocationModels),
1829 ("code-models", PrintRequest::CodeModels),
1830 ("tls-models", PrintRequest::TlsModels),
1831 ("native-static-libs", PrintRequest::NativeStaticLibs),
1832 ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
1833 ("target-spec-json", PrintRequest::TargetSpec),
1834 ("link-args", PrintRequest::LinkArgs),
1835 ("split-debuginfo", PrintRequest::SplitDebuginfo),
1838 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
1839 match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
1840 Some((_, PrintRequest::TargetSpec)) => {
1841 if unstable_opts.unstable_options {
1842 PrintRequest::TargetSpec
1846 "the `-Z unstable-options` flag must also be passed to \
1847 enable the target-spec-json print option",
1851 Some(&(_, print_request)) => print_request,
1854 PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
1855 let prints = prints.join(", ");
1858 &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
1867 pub fn parse_target_triple(
1868 matches: &getopts::Matches,
1869 error_format: ErrorOutputType,
1871 match matches.opt_str("target") {
1872 Some(target) if target.ends_with(".json") => {
1873 let path = Path::new(&target);
1874 TargetTriple::from_path(path).unwrap_or_else(|_| {
1875 early_error(error_format, &format!("target file {path:?} does not exist"))
1878 Some(target) => TargetTriple::TargetTriple(target),
1879 _ => TargetTriple::from_triple(host_triple()),
1884 matches: &getopts::Matches,
1885 cg: &CodegenOptions,
1886 error_format: ErrorOutputType,
1888 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1889 // to use them interchangeably. However, because they're technically different flags,
1890 // we need to work out manually which should take precedence if both are supplied (i.e.
1891 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1892 // comparing them. Note that if a flag is not found, its position will be `None`, which
1893 // always compared less than `Some(_)`.
1894 let max_o = matches.opt_positions("O").into_iter().max();
1898 .flat_map(|(i, s)| {
1899 // NB: This can match a string without `=`.
1900 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
1906 match cg.opt_level.as_ref() {
1907 "0" => OptLevel::No,
1908 "1" => OptLevel::Less,
1909 "2" => OptLevel::Default,
1910 "3" => OptLevel::Aggressive,
1911 "s" => OptLevel::Size,
1912 "z" => OptLevel::SizeMin,
1917 "optimization level needs to be \
1918 between 0-3, s or z (instead was `{arg}`)"
1926 fn select_debuginfo(
1927 matches: &getopts::Matches,
1928 cg: &CodegenOptions,
1929 error_format: ErrorOutputType,
1931 let max_g = matches.opt_positions("g").into_iter().max();
1935 .flat_map(|(i, s)| {
1936 // NB: This can match a string without `=`.
1937 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
1943 match cg.debuginfo {
1944 0 => DebugInfo::None,
1945 1 => DebugInfo::Limited,
1946 2 => DebugInfo::Full,
1951 "debug info level needs to be between \
1952 0-2 (instead was `{arg}`)"
1960 pub(crate) fn parse_assert_incr_state(
1961 opt_assertion: &Option<String>,
1962 error_format: ErrorOutputType,
1963 ) -> Option<IncrementalStateAssertion> {
1964 match opt_assertion {
1965 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1966 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1968 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1974 fn parse_native_lib_kind(
1975 matches: &getopts::Matches,
1977 error_format: ErrorOutputType,
1978 ) -> (NativeLibKind, Option<bool>) {
1979 let (kind, modifiers) = match kind.split_once(':') {
1980 None => (kind, None),
1981 Some((kind, modifiers)) => (kind, Some(modifiers)),
1984 let kind = match kind {
1985 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1986 "dylib" => NativeLibKind::Dylib { as_needed: None },
1987 "framework" => NativeLibKind::Framework { as_needed: None },
1989 if !nightly_options::is_unstable_enabled(matches) {
1990 let why = if nightly_options::match_is_nightly_build(matches) {
1991 " and only accepted on the nightly compiler"
1993 ", the `-Z unstable-options` flag must also be passed to use it"
1995 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
1997 NativeLibKind::LinkArg
2002 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
2007 None => (kind, None),
2008 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
2012 fn parse_native_lib_modifiers(
2013 mut kind: NativeLibKind,
2015 error_format: ErrorOutputType,
2016 matches: &getopts::Matches,
2017 ) -> (NativeLibKind, Option<bool>) {
2018 let mut verbatim = None;
2019 for modifier in modifiers.split(',') {
2020 let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
2021 Some(m) => (m, modifier.starts_with('+')),
2022 None => early_error(
2024 "invalid linking modifier syntax, expected '+' or '-' prefix \
2025 before one of: bundle, verbatim, whole-archive, as-needed",
2029 let report_unstable_modifier = || {
2030 if !nightly_options::is_unstable_enabled(matches) {
2031 let why = if nightly_options::match_is_nightly_build(matches) {
2032 " and only accepted on the nightly compiler"
2034 ", the `-Z unstable-options` flag must also be passed to use it"
2038 &format!("linking modifier `{modifier}` is unstable{why}"),
2042 let assign_modifier = |dst: &mut Option<bool>| {
2044 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2045 early_error(error_format, &msg)
2050 match (modifier, &mut kind) {
2051 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2052 ("bundle", _) => early_error(
2054 "linking modifier `bundle` is only compatible with `static` linking kind",
2057 ("verbatim", _) => assign_modifier(&mut verbatim),
2059 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2060 assign_modifier(whole_archive)
2062 ("whole-archive", _) => early_error(
2064 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2067 ("as-needed", NativeLibKind::Dylib { as_needed })
2068 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2069 report_unstable_modifier();
2070 assign_modifier(as_needed)
2072 ("as-needed", _) => early_error(
2074 "linking modifier `as-needed` is only compatible with \
2075 `dylib` and `framework` linking kinds",
2078 // Note: this error also excludes the case with empty modifier
2079 // string, like `modifiers = ""`.
2083 "unknown linking modifier `{modifier}`, expected one \
2084 of: bundle, verbatim, whole-archive, as-needed"
2093 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2098 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2099 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2100 // where MODIFIERS are a comma separated list of supported modifiers
2101 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2102 // with either + or - to indicate whether it is enabled or disabled.
2103 // The last value specified for a given modifier wins.
2104 let (name, kind, verbatim) = match s.split_once('=') {
2105 None => (s, NativeLibKind::Unspecified, None),
2106 Some((kind, name)) => {
2107 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2108 (name.to_string(), kind, verbatim)
2112 let (name, new_name) = match name.split_once(':') {
2113 None => (name, None),
2114 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2116 if name.is_empty() {
2117 early_error(error_format, "library name must not be empty");
2119 NativeLib { name, new_name, kind, verbatim }
2124 pub fn parse_externs(
2125 matches: &getopts::Matches,
2126 unstable_opts: &UnstableOptions,
2127 error_format: ErrorOutputType,
2129 let is_unstable_enabled = unstable_opts.unstable_options;
2130 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2131 for arg in matches.opt_strs("extern") {
2132 let (name, path) = match arg.split_once('=') {
2133 None => (arg, None),
2134 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2136 let (options, name) = match name.split_once(':') {
2137 None => (None, name),
2138 Some((opts, name)) => (Some(opts), name.to_string()),
2141 let path = path.map(|p| CanonicalizedPath::new(p));
2143 let entry = externs.entry(name.to_owned());
2145 use std::collections::btree_map::Entry;
2147 let entry = if let Some(path) = path {
2148 // --extern prelude_name=some_file.rlib
2150 Entry::Vacant(vacant) => {
2151 let files = BTreeSet::from_iter(iter::once(path));
2152 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2154 Entry::Occupied(occupied) => {
2155 let ext_ent = occupied.into_mut();
2157 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2161 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2164 // Exact paths take precedence over search directories.
2165 let files = BTreeSet::from_iter(iter::once(path));
2166 *location = ExternLocation::ExactPaths(files);
2173 // --extern prelude_name
2175 Entry::Vacant(vacant) => {
2176 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2178 Entry::Occupied(occupied) => {
2179 // Ignore if already specified.
2185 let mut is_private_dep = false;
2186 let mut add_prelude = true;
2187 let mut nounused_dep = false;
2188 if let Some(opts) = options {
2189 if !is_unstable_enabled {
2192 "the `-Z unstable-options` flag must also be passed to \
2193 enable `--extern options",
2196 for opt in opts.split(',') {
2198 "priv" => is_private_dep = true,
2200 if let ExternLocation::ExactPaths(_) = &entry.location {
2201 add_prelude = false;
2205 "the `noprelude` --extern option requires a file path",
2209 "nounused" => nounused_dep = true,
2210 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2215 // Crates start out being not private, and go to being private `priv`
2217 entry.is_private_dep |= is_private_dep;
2218 // likewise `nounused`
2219 entry.nounused_dep |= nounused_dep;
2220 // If any flag is missing `noprelude`, then add to the prelude.
2221 entry.add_prelude |= add_prelude;
2226 fn parse_remap_path_prefix(
2227 matches: &getopts::Matches,
2228 unstable_opts: &UnstableOptions,
2229 error_format: ErrorOutputType,
2230 ) -> Vec<(PathBuf, PathBuf)> {
2231 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2232 .opt_strs("remap-path-prefix")
2234 .map(|remap| match remap.rsplit_once('=') {
2235 None => early_error(
2237 "--remap-path-prefix must contain '=' between FROM and TO",
2239 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2242 match &unstable_opts.remap_cwd_prefix {
2243 Some(to) => match std::env::current_dir() {
2244 Ok(cwd) => mapping.push((cwd, to.clone())),
2252 // JUSTIFICATION: before wrapper fn is available
2253 #[allow(rustc::bad_opt_access)]
2254 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2255 let color = parse_color(matches);
2257 let edition = parse_crate_edition(matches);
2261 json_artifact_notifications,
2262 json_unused_externs,
2263 json_future_incompat,
2264 } = parse_json(matches);
2266 let error_format = parse_error_format(matches, color, json_rendered);
2268 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2269 early_error(error_format, "`--diagnostic-width` must be an positive integer");
2272 let unparsed_crate_types = matches.opt_strs("crate-type");
2273 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2274 .unwrap_or_else(|e| early_error(error_format, &e));
2276 let mut unstable_opts = UnstableOptions::build(matches, error_format);
2277 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2279 check_error_format_stability(&unstable_opts, error_format, json_rendered);
2281 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2284 "the `-Z unstable-options` flag must also be passed to enable \
2285 the flag `--json=unused-externs`",
2289 let output_types = parse_output_types(&unstable_opts, matches, error_format);
2291 let mut cg = CodegenOptions::build(matches, error_format);
2292 let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2299 check_thread_count(&unstable_opts, error_format);
2301 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2303 let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
2305 if unstable_opts.profile && incremental.is_some() {
2308 "can't instrument with gcov profiling when compiling incrementally",
2311 if unstable_opts.profile {
2312 match codegen_units {
2314 None => codegen_units = Some(1),
2315 Some(_) => early_error(
2317 "can't instrument with gcov profiling with multiple codegen units",
2322 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2325 "options `-C profile-generate` and `-C profile-use` are exclusive",
2329 if unstable_opts.profile_sample_use.is_some()
2330 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2334 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2338 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2340 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2341 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2344 "incompatible values passed for `-C symbol-mangling-version` \
2345 and `-Z symbol-mangling-version`",
2348 (Some(SymbolManglingVersion::V0), _) => {}
2349 (Some(_), _) if !unstable_opts.unstable_options => {
2352 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2359 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2361 cg.symbol_mangling_version = smv;
2366 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2368 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2369 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2372 "incompatible values passed for `-C instrument-coverage` \
2373 and `-Z instrument-coverage`",
2376 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2377 (Some(_), _) if !unstable_opts.unstable_options => {
2380 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2387 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2389 cg.instrument_coverage = ic;
2394 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2395 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2398 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2399 or `-C profile-generate`",
2403 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2404 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2405 // multiple runs, including some changes to source code; so mangled names must be consistent
2406 // across compilations.
2407 match cg.symbol_mangling_version {
2408 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2409 Some(SymbolManglingVersion::Legacy) => {
2412 "-C instrument-coverage requires symbol mangling version `v0`, \
2413 but `-C symbol-mangling-version=legacy` was specified",
2416 Some(SymbolManglingVersion::V0) => {}
2420 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2421 unstable_opts.graphviz_font = graphviz_font;
2424 if !cg.embed_bitcode {
2426 LtoCli::No | LtoCli::Unspecified => {}
2427 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2429 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2434 let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
2438 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2439 let target_triple = parse_target_triple(matches, error_format);
2440 let opt_level = parse_opt_level(matches, &cg, error_format);
2441 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2442 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2443 // for more details.
2444 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2445 let debuginfo = select_debuginfo(matches, &cg, error_format);
2447 let mut search_paths = vec![];
2448 for s in &matches.opt_strs("L") {
2449 search_paths.push(SearchPath::from_cli_opt(s, error_format));
2452 let libs = parse_libs(matches, error_format);
2454 let test = matches.opt_present("test");
2456 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2457 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2460 let externs = parse_externs(matches, &unstable_opts, error_format);
2462 let crate_name = matches.opt_str("crate-name");
2464 let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
2466 let pretty = parse_pretty(&unstable_opts, error_format);
2468 // query-dep-graph is required if dump-dep-graph is given #106736
2469 if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
2470 early_error(error_format, "can't dump dependency graph without `-Z query-dep-graph`");
2473 // Try to find a directory containing the Rust `src`, for more details see
2474 // the doc comment on the `real_rust_source_base_dir` field.
2476 let sysroot = match &sysroot_opt {
2479 tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
2483 let real_rust_source_base_dir = {
2484 // This is the location used by the `rust-src` `rustup` component.
2485 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2486 if let Ok(metadata) = candidate.symlink_metadata() {
2487 // Replace the symlink rustbuild creates, with its destination.
2488 // We could try to use `fs::canonicalize` instead, but that might
2489 // produce unnecessarily verbose path.
2490 if metadata.file_type().is_symlink() {
2491 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2492 candidate = symlink_dest;
2497 // Only use this directory if it has a file we can expect to always find.
2498 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2501 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2502 early_error(error_format, &format!("Current directory is invalid: {e}"));
2505 let remap = FilePathMapping::new(remap_path_prefix.clone());
2506 let (path, remapped) = remap.map_prefix(&working_dir);
2507 let working_dir = if remapped {
2508 RealFileName::Remapped { virtual_name: path.into_owned(), local_path: Some(working_dir) }
2510 RealFileName::LocalPath(path.into_owned())
2516 optimize: opt_level,
2523 maybe_sysroot: sysroot_opt,
2533 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2537 actually_rustdoc: false,
2538 trimmed_def_paths: TrimmedDefPaths::default(),
2539 cli_forced_codegen_units: codegen_units,
2540 cli_forced_local_thinlto_off: disable_local_thinlto,
2542 real_rust_source_base_dir,
2544 json_artifact_notifications,
2545 json_unused_externs,
2546 json_future_incompat,
2552 fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2555 let first = match unstable_opts.unpretty.as_deref()? {
2556 "normal" => Source(PpSourceMode::Normal),
2557 "identified" => Source(PpSourceMode::Identified),
2558 "expanded" => Source(PpSourceMode::Expanded),
2559 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2560 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2561 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2562 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2563 "hir" => Hir(PpHirMode::Normal),
2564 "hir,identified" => Hir(PpHirMode::Identified),
2565 "hir,typed" => Hir(PpHirMode::Typed),
2566 "hir-tree" => HirTree,
2567 "thir-tree" => ThirTree,
2569 "mir-cfg" => MirCFG,
2570 name => early_error(
2573 "argument to `unpretty` must be one of `normal`, `identified`, \
2574 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2575 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2576 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2580 debug!("got unpretty option: {first:?}");
2584 pub fn make_crate_type_option() -> RustcOptGroup {
2588 "Comma separated list of types of crates
2589 for the compiler to emit",
2590 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2594 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2595 let mut crate_types: Vec<CrateType> = Vec::new();
2596 for unparsed_crate_type in &list_list {
2597 for part in unparsed_crate_type.split(',') {
2598 let new_part = match part {
2599 "lib" => default_lib_output(),
2600 "rlib" => CrateType::Rlib,
2601 "staticlib" => CrateType::Staticlib,
2602 "dylib" => CrateType::Dylib,
2603 "cdylib" => CrateType::Cdylib,
2604 "bin" => CrateType::Executable,
2605 "proc-macro" => CrateType::ProcMacro,
2606 _ => return Err(format!("unknown crate type: `{part}`")),
2608 if !crate_types.contains(&new_part) {
2609 crate_types.push(new_part)
2617 pub mod nightly_options {
2618 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2619 use crate::early_error;
2620 use rustc_feature::UnstableFeatures;
2622 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2623 match_is_nightly_build(matches)
2624 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2627 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2628 is_nightly_build(matches.opt_str("crate-name").as_deref())
2631 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2632 UnstableFeatures::from_environment(krate).is_nightly_build()
2635 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2636 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2637 let really_allows_unstable_options = match_is_nightly_build(matches);
2639 for opt in flags.iter() {
2640 if opt.stability == OptionStability::Stable {
2643 if !matches.opt_present(opt.name) {
2646 if opt.name != "Z" && !has_z_unstable_option {
2648 ErrorOutputType::default(),
2650 "the `-Z unstable-options` flag must also be passed to enable \
2656 if really_allows_unstable_options {
2659 match opt.stability {
2660 OptionStability::Unstable => {
2662 "the option `{}` is only accepted on the \
2666 early_error(ErrorOutputType::default(), &msg);
2668 OptionStability::Stable => {}
2674 impl fmt::Display for CrateType {
2675 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2677 CrateType::Executable => "bin".fmt(f),
2678 CrateType::Dylib => "dylib".fmt(f),
2679 CrateType::Rlib => "rlib".fmt(f),
2680 CrateType::Staticlib => "staticlib".fmt(f),
2681 CrateType::Cdylib => "cdylib".fmt(f),
2682 CrateType::ProcMacro => "proc-macro".fmt(f),
2687 #[derive(Copy, Clone, PartialEq, Debug)]
2688 pub enum PpSourceMode {
2689 /// `-Zunpretty=normal`
2691 /// `-Zunpretty=expanded`
2693 /// `-Zunpretty=identified`
2695 /// `-Zunpretty=expanded,identified`
2697 /// `-Zunpretty=expanded,hygiene`
2701 #[derive(Copy, Clone, PartialEq, Debug)]
2702 pub enum PpAstTreeMode {
2703 /// `-Zunpretty=ast`
2705 /// `-Zunpretty=ast,expanded`
2709 #[derive(Copy, Clone, PartialEq, Debug)]
2710 pub enum PpHirMode {
2711 /// `-Zunpretty=hir`
2713 /// `-Zunpretty=hir,identified`
2715 /// `-Zunpretty=hir,typed`
2719 #[derive(Copy, Clone, PartialEq, Debug)]
2721 /// Options that print the source code, i.e.
2722 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2723 Source(PpSourceMode),
2724 AstTree(PpAstTreeMode),
2725 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2727 /// `-Zunpretty=hir-tree`
2729 /// `-Zunpretty=thir-tree`
2731 /// `-Zunpretty=mir`
2733 /// `-Zunpretty=mir-cfg`
2738 pub fn needs_ast_map(&self) -> bool {
2740 use PpSourceMode::*;
2742 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2744 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2745 | AstTree(PpAstTreeMode::Expanded)
2753 pub fn needs_hir(&self) -> bool {
2756 Source(_) | AstTree(_) => false,
2758 Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
2762 pub fn needs_analysis(&self) -> bool {
2764 matches!(*self, Mir | MirCFG | ThirTree)
2768 /// Command-line arguments passed to the compiler have to be incorporated with
2769 /// the dependency tracking system for incremental compilation. This module
2770 /// provides some utilities to make this more convenient.
2772 /// The values of all command-line arguments that are relevant for dependency
2773 /// tracking are hashed into a single value that determines whether the
2774 /// incremental compilation cache can be re-used or not. This hashing is done
2775 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2776 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2777 /// the hash of which is order dependent, but we might not want the order of
2778 /// arguments to make a difference for the hash).
2780 /// However, since the value provided by `Hash::hash` often *is* suitable,
2781 /// especially for primitive types, there is the
2782 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2783 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2784 /// we have an opt-in scheme here, so one is hopefully forced to think about
2785 /// how the hash should be calculated when adding a new command-line argument.
2786 pub(crate) mod dep_tracking {
2788 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2789 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2790 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
2791 SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
2794 use crate::options::WasiExecModel;
2795 use crate::utils::{NativeLib, NativeLibKind};
2796 use rustc_errors::LanguageIdentifier;
2797 use rustc_feature::UnstableFeatures;
2798 use rustc_span::edition::Edition;
2799 use rustc_span::RealFileName;
2800 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2801 use rustc_target::spec::{
2802 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2804 use std::collections::hash_map::DefaultHasher;
2805 use std::collections::BTreeMap;
2806 use std::hash::Hash;
2807 use std::num::NonZeroUsize;
2808 use std::path::PathBuf;
2810 pub trait DepTrackingHash {
2813 hasher: &mut DefaultHasher,
2814 error_format: ErrorOutputType,
2815 for_crate_hash: bool,
2819 macro_rules! impl_dep_tracking_hash_via_hash {
2820 ($($t:ty),+ $(,)?) => {$(
2821 impl DepTrackingHash for $t {
2822 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2823 Hash::hash(self, hasher);
2829 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2832 hasher: &mut DefaultHasher,
2833 error_format: ErrorOutputType,
2834 for_crate_hash: bool,
2838 Hash::hash(&1, hasher);
2839 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2841 None => Hash::hash(&0, hasher),
2846 impl_dep_tracking_hash_via_hash!(
2881 SymbolManglingVersion,
2882 SourceFileHashAlgorithm,
2894 impl<T1, T2> DepTrackingHash for (T1, T2)
2896 T1: DepTrackingHash,
2897 T2: DepTrackingHash,
2901 hasher: &mut DefaultHasher,
2902 error_format: ErrorOutputType,
2903 for_crate_hash: bool,
2905 Hash::hash(&0, hasher);
2906 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2907 Hash::hash(&1, hasher);
2908 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2912 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2914 T1: DepTrackingHash,
2915 T2: DepTrackingHash,
2916 T3: DepTrackingHash,
2920 hasher: &mut DefaultHasher,
2921 error_format: ErrorOutputType,
2922 for_crate_hash: bool,
2924 Hash::hash(&0, hasher);
2925 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2926 Hash::hash(&1, hasher);
2927 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2928 Hash::hash(&2, hasher);
2929 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2933 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2936 hasher: &mut DefaultHasher,
2937 error_format: ErrorOutputType,
2938 for_crate_hash: bool,
2940 Hash::hash(&self.len(), hasher);
2941 for (index, elem) in self.iter().enumerate() {
2942 Hash::hash(&index, hasher);
2943 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2948 impl DepTrackingHash for OutputTypes {
2951 hasher: &mut DefaultHasher,
2952 error_format: ErrorOutputType,
2953 for_crate_hash: bool,
2955 Hash::hash(&self.0.len(), hasher);
2956 for (key, val) in &self.0 {
2957 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2958 if !for_crate_hash {
2959 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2965 // This is a stable hash because BTreeMap is a sorted container
2966 pub(crate) fn stable_hash(
2967 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2968 hasher: &mut DefaultHasher,
2969 error_format: ErrorOutputType,
2970 for_crate_hash: bool,
2972 for (key, sub_hash) in sub_hashes {
2973 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2974 // the keys, as they are just plain strings
2975 Hash::hash(&key.len(), hasher);
2976 Hash::hash(key, hasher);
2977 sub_hash.hash(hasher, error_format, for_crate_hash);
2982 /// Default behavior to use in out-of-memory situations.
2983 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2984 pub enum OomStrategy {
2985 /// Generate a panic that can be caught by `catch_unwind`.
2988 /// Abort the process immediately.
2993 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2995 pub fn should_panic(self) -> u8 {
2997 OomStrategy::Panic => 1,
2998 OomStrategy::Abort => 0,
3003 /// How to run proc-macro code when building this crate
3004 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
3005 pub enum ProcMacroExecutionStrategy {
3006 /// Run the proc-macro code on the same thread as the server.
3009 /// Run the proc-macro code on a different thread.
3013 /// Which format to use for `-Z dump-mono-stats`
3014 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
3015 pub enum DumpMonoStatsFormat {
3016 /// Pretty-print a markdown table
3018 /// Emit structured JSON
3022 impl DumpMonoStatsFormat {
3023 pub fn extension(self) -> &'static str {
3025 Self::Markdown => "md",
3026 Self::Json => "json",