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)]
868 /// When generated, is this crate type an archive?
869 pub fn is_archive(&self) -> bool {
871 CrateType::Rlib | CrateType::Staticlib => true,
872 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
879 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
886 pub fn is_empty(&self) -> bool {
888 Passes::Some(ref v) => v.is_empty(),
889 Passes::All => false,
893 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
895 Passes::Some(ref mut v) => v.extend(passes),
901 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
907 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
913 #[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
914 pub struct BranchProtection {
916 pub pac_ret: Option<PacRet>,
919 pub const fn default_lib_output() -> CrateType {
923 fn default_configuration(sess: &Session) -> CrateConfig {
924 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
925 let end = &sess.target.endian;
926 let arch = &sess.target.arch;
927 let wordsz = sess.target.pointer_width.to_string();
928 let os = &sess.target.os;
929 let env = &sess.target.env;
930 let abi = &sess.target.abi;
931 let vendor = &sess.target.vendor;
932 let min_atomic_width = sess.target.min_atomic_width();
933 let max_atomic_width = sess.target.max_atomic_width();
934 let atomic_cas = sess.target.atomic_cas;
935 let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
936 sess.emit_fatal(err);
939 let mut ret = CrateConfig::default();
940 ret.reserve(7); // the minimum number of insertions
942 ret.insert((sym::target_os, Some(Symbol::intern(os))));
943 for fam in sess.target.families.as_ref() {
944 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
945 if fam == "windows" {
946 ret.insert((sym::windows, None));
947 } else if fam == "unix" {
948 ret.insert((sym::unix, None));
951 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
952 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
953 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
954 ret.insert((sym::target_env, Some(Symbol::intern(env))));
955 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
956 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
957 if sess.target.has_thread_local {
958 ret.insert((sym::target_thread_local, None));
961 (8, layout.i8_align.abi),
962 (16, layout.i16_align.abi),
963 (32, layout.i32_align.abi),
964 (64, layout.i64_align.abi),
965 (128, layout.i128_align.abi),
967 if i >= min_atomic_width && i <= max_atomic_width {
968 let mut insert_atomic = |s, align: Align| {
969 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
971 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
973 if align.bits() == i {
974 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
977 let s = i.to_string();
978 insert_atomic(&s, align);
980 insert_atomic("ptr", layout.pointer_align.abi);
985 let panic_strategy = sess.panic_strategy();
986 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
988 for s in sess.opts.unstable_opts.sanitizer {
989 let symbol = Symbol::intern(&s.to_string());
990 ret.insert((sym::sanitize, Some(symbol)));
993 if sess.opts.debug_assertions {
994 ret.insert((sym::debug_assertions, None));
996 // JUSTIFICATION: before wrapper fn is available
997 #[allow(rustc::bad_opt_access)]
998 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
999 ret.insert((sym::proc_macro, None));
1004 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1005 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1006 /// but the symbol interner is not yet set up then, so we must convert it later.
1007 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
1008 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
1011 /// The parsed `--check-cfg` options
1012 pub struct CheckCfg<T = String> {
1013 /// The set of all `names()`, if None no name checking is performed
1014 pub names_valid: Option<FxHashSet<T>>,
1015 /// Is well known values activated
1016 pub well_known_values: bool,
1017 /// The set of all `values()`
1018 pub values_valid: FxHashMap<T, FxHashSet<T>>,
1021 impl<T> Default for CheckCfg<T> {
1022 fn default() -> Self {
1024 names_valid: Default::default(),
1025 values_valid: Default::default(),
1026 well_known_values: false,
1031 impl<T> CheckCfg<T> {
1032 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1037 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1041 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1043 well_known_values: self.well_known_values,
1048 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1049 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1050 /// but the symbol interner is not yet set up then, so we must convert it later.
1051 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1052 cfg.map_data(|s| Symbol::intern(s))
1055 impl CrateCheckConfig {
1056 /// Fills a `CrateCheckConfig` with well-known configuration names.
1057 fn fill_well_known_names(&mut self) {
1058 // NOTE: This should be kept in sync with `default_configuration` and
1059 // `fill_well_known_values`
1060 const WELL_KNOWN_NAMES: &[Symbol] = &[
1068 sym::target_pointer_width,
1072 sym::target_thread_local,
1073 sym::target_has_atomic_load_store,
1074 sym::target_has_atomic,
1075 sym::target_has_atomic_equal_alignment,
1076 sym::target_feature,
1079 sym::debug_assertions,
1090 // We only insert well-known names if `names()` was activated
1091 if let Some(names_valid) = &mut self.names_valid {
1092 names_valid.extend(WELL_KNOWN_NAMES);
1096 /// Fills a `CrateCheckConfig` with well-known configuration values.
1097 fn fill_well_known_values(&mut self) {
1098 if !self.well_known_values {
1102 // NOTE: This should be kept in sync with `default_configuration` and
1103 // `fill_well_known_names`
1105 let panic_values = &PanicStrategy::all();
1107 let atomic_values = &[
1109 sym::integer(8usize),
1110 sym::integer(16usize),
1111 sym::integer(32usize),
1112 sym::integer(64usize),
1113 sym::integer(128usize),
1116 let sanitize_values = SanitizerSet::all()
1118 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1120 // Unknown possible values:
1122 // - `target_feature`
1133 sym::debug_assertions,
1134 sym::target_thread_local,
1136 self.values_valid.entry(name).or_default();
1139 // Pre-defined values
1140 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1141 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1142 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1144 .entry(sym::target_has_atomic_load_store)
1146 .extend(atomic_values);
1148 .entry(sym::target_has_atomic_equal_alignment)
1150 .extend(atomic_values);
1152 // Target specific values
1154 const VALUES: [&Symbol; 8] = [
1156 &sym::target_family,
1158 &sym::target_endian,
1161 &sym::target_vendor,
1162 &sym::target_pointer_width,
1165 // Initialize (if not already initialized)
1167 self.values_valid.entry(e).or_default();
1170 // Get all values map at once otherwise it would be costly.
1171 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1174 values_target_family,
1176 values_target_endian,
1179 values_target_vendor,
1180 values_target_pointer_width,
1183 .get_many_mut(VALUES)
1184 .expect("unable to get all the check-cfg values buckets");
1186 for target in TARGETS
1188 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1190 values_target_os.insert(Symbol::intern(&target.options.os));
1191 values_target_family
1192 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1193 values_target_arch.insert(Symbol::intern(&target.arch));
1194 values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
1195 values_target_env.insert(Symbol::intern(&target.options.env));
1196 values_target_abi.insert(Symbol::intern(&target.options.abi));
1197 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1198 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1203 pub fn fill_well_known(&mut self) {
1204 self.fill_well_known_names();
1205 self.fill_well_known_values();
1209 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1210 // Combine the configuration requested by the session (command line) with
1211 // some default and generated configuration items.
1212 let default_cfg = default_configuration(sess);
1213 // If the user wants a test runner, then add the test cfg.
1215 user_cfg.insert((sym::test, None));
1217 user_cfg.extend(default_cfg.iter().cloned());
1221 pub(super) fn build_target_config(
1223 target_override: Option<Target>,
1226 let target_result = target_override.map_or_else(
1227 || Target::search(&opts.target_triple, sysroot),
1228 |t| Ok((t, TargetWarnings::empty())),
1230 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1234 "Error loading target specification: {}. \
1235 Run `rustc --print target-list` for a list of built-in targets",
1240 for warning in target_warnings.warning_messages() {
1241 early_warn(opts.error_format, &warning)
1244 if !matches!(target.pointer_width, 16 | 32 | 64) {
1248 "target specification was invalid: \
1249 unrecognized target-pointer-width {}",
1250 target.pointer_width
1258 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1259 pub enum OptionStability {
1264 pub struct RustcOptGroup {
1265 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1266 pub name: &'static str,
1267 pub stability: OptionStability,
1270 impl RustcOptGroup {
1271 pub fn is_stable(&self) -> bool {
1272 self.stability == OptionStability::Stable
1275 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1277 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1279 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1282 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1284 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1286 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1290 // The `opt` local module holds wrappers around the `getopts` API that
1291 // adds extra rustc-specific metadata to each option; such metadata
1292 // is exposed by . The public
1293 // functions below ending with `_u` are the functions that return
1294 // *unstable* options, i.e., options that are only enabled when the
1295 // user also passes the `-Z unstable-options` debugging flag.
1297 // The `fn flag*` etc below are written so that we can use them
1298 // in the future; do not warn about them not being used right now.
1299 #![allow(dead_code)]
1301 use super::RustcOptGroup;
1303 pub type R = RustcOptGroup;
1304 pub type S = &'static str;
1306 fn stable<F>(name: S, f: F) -> R
1308 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1310 RustcOptGroup::stable(name, f)
1313 fn unstable<F>(name: S, f: F) -> R
1315 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1317 RustcOptGroup::unstable(name, f)
1320 fn longer(a: S, b: S) -> S {
1321 if a.len() > b.len() { a } else { b }
1324 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1325 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1327 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1328 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1330 pub fn flag_s(a: S, b: S, c: S) -> R {
1331 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1333 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1334 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1337 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1338 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1340 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1341 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1344 static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
1346 "Specify which edition of the compiler to use when compiling code. \
1347 The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
1350 /// Returns the "short" subset of the rustc command line options,
1351 /// including metadata for each option, such as whether the option is
1352 /// part of the stable long-term interface for rustc.
1353 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1355 opt::flag_s("h", "help", "Display this message"),
1356 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1357 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1361 "Add a directory to the library search path. The
1362 optional KIND can be one of dependency, crate, native,
1363 framework, or all (the default).",
1369 "Link the generated crate(s) to the specified native
1370 library NAME. The optional KIND can be one of
1371 static, framework, or dylib (the default).
1372 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1373 may be specified each with a prefix of either '+' to
1374 enable or '-' to disable.",
1375 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1377 make_crate_type_option(),
1378 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1388 "Comma separated list of types of output for \
1389 the compiler to emit",
1390 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1395 "Compiler information to print on stdout",
1396 "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
1397 target-list|target-cpus|target-features|relocation-models|code-models|\
1398 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1401 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1402 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1403 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1407 "Write output to compiler-chosen filename \
1414 "Provide a detailed explanation of an error \
1418 opt::flag_s("", "test", "Build a test harness"),
1419 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1420 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1421 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1422 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1423 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1424 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1428 "Set the most restrictive lint level. \
1429 More restrictive lints are capped at this \
1433 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1434 opt::flag_s("V", "version", "Print version info and exit"),
1435 opt::flag_s("v", "verbose", "Use verbose output"),
1439 /// Returns all rustc command line options, including metadata for
1440 /// each option, such as whether the option is part of the stable
1441 /// long-term interface for rustc.
1442 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1443 let mut opts = rustc_short_optgroups();
1444 // FIXME: none of these descriptions are actually used
1449 "Specify where an external rust library is located",
1452 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1453 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1457 "How errors and other messages are produced",
1460 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1464 "Configure coloring of output:
1465 auto = colorize, if output goes to a tty (default);
1466 always = always colorize output;
1467 never = never colorize output",
1468 "auto|always|never",
1473 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1478 "remap-path-prefix",
1479 "Remap source names in all output (compiler messages and output files)",
1486 pub fn get_cmd_lint_options(
1487 matches: &getopts::Matches,
1488 error_format: ErrorOutputType,
1489 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1490 let mut lint_opts_with_position = vec![];
1491 let mut describe_lints = false;
1493 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1494 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1495 if lint_name == "help" {
1496 describe_lints = true;
1498 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1503 lint_opts_with_position.sort_by_key(|x| x.0);
1504 let lint_opts = lint_opts_with_position
1507 .map(|(_, lint_name, level)| (lint_name, level))
1510 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1511 lint::Level::from_str(&cap)
1512 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1515 (lint_opts, describe_lints, lint_cap)
1518 /// Parses the `--color` flag.
1519 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1520 match matches.opt_str("color").as_deref() {
1521 Some("auto") => ColorConfig::Auto,
1522 Some("always") => ColorConfig::Always,
1523 Some("never") => ColorConfig::Never,
1525 None => ColorConfig::Auto,
1527 Some(arg) => early_error(
1528 ErrorOutputType::default(),
1530 "argument for `--color` must be auto, \
1531 always or never (instead was `{arg}`)"
1537 /// Possible json config files
1538 pub struct JsonConfig {
1539 pub json_rendered: HumanReadableErrorType,
1540 pub json_artifact_notifications: bool,
1541 pub json_unused_externs: JsonUnusedExterns,
1542 pub json_future_incompat: bool,
1545 /// Report unused externs in event stream
1546 #[derive(Copy, Clone)]
1547 pub enum JsonUnusedExterns {
1550 /// Report, but do not exit with failure status for deny/forbid
1552 /// Report, and also exit with failure status for deny/forbid
1556 impl JsonUnusedExterns {
1557 pub fn is_enabled(&self) -> bool {
1559 JsonUnusedExterns::No => false,
1560 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1564 pub fn is_loud(&self) -> bool {
1566 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1567 JsonUnusedExterns::Loud => true,
1572 /// Parse the `--json` flag.
1574 /// The first value returned is how to render JSON diagnostics, and the second
1575 /// is whether or not artifact notifications are enabled.
1576 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1577 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1578 HumanReadableErrorType::Default;
1579 let mut json_color = ColorConfig::Never;
1580 let mut json_artifact_notifications = false;
1581 let mut json_unused_externs = JsonUnusedExterns::No;
1582 let mut json_future_incompat = false;
1583 for option in matches.opt_strs("json") {
1584 // For now conservatively forbid `--color` with `--json` since `--json`
1585 // won't actually be emitting any colors and anything colorized is
1586 // embedded in a diagnostic message anyway.
1587 if matches.opt_str("color").is_some() {
1589 ErrorOutputType::default(),
1590 "cannot specify the `--color` option with `--json`",
1594 for sub_option in option.split(',') {
1596 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1597 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1598 "artifacts" => json_artifact_notifications = true,
1599 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1600 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1601 "future-incompat" => json_future_incompat = true,
1603 ErrorOutputType::default(),
1604 &format!("unknown `--json` option `{s}`"),
1611 json_rendered: json_rendered(json_color),
1612 json_artifact_notifications,
1613 json_unused_externs,
1614 json_future_incompat,
1618 /// Parses the `--error-format` flag.
1619 pub fn parse_error_format(
1620 matches: &getopts::Matches,
1622 json_rendered: HumanReadableErrorType,
1623 ) -> ErrorOutputType {
1624 // We need the `opts_present` check because the driver will send us Matches
1625 // with only stable options if no unstable options are used. Since error-format
1626 // is unstable, it will not be present. We have to use `opts_present` not
1627 // `opt_present` because the latter will panic.
1628 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1629 match matches.opt_str("error-format").as_deref() {
1630 None | Some("human") => {
1631 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1633 Some("human-annotate-rs") => {
1634 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1636 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1637 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1638 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1640 Some(arg) => early_error(
1641 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1643 "argument for `--error-format` must be `human`, `json` or \
1644 `short` (instead was `{arg}`)"
1649 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1652 match error_format {
1653 ErrorOutputType::Json { .. } => {}
1655 // Conservatively require that the `--json` argument is coupled with
1656 // `--error-format=json`. This means that `--json` is specified we
1657 // should actually be emitting JSON blobs.
1658 _ if !matches.opt_strs("json").is_empty() => {
1660 ErrorOutputType::default(),
1661 "using `--json` requires also using `--error-format=json`",
1671 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1672 let edition = match matches.opt_str("edition") {
1673 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1675 ErrorOutputType::default(),
1677 "argument for `--edition` must be one of: \
1678 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1682 None => DEFAULT_EDITION,
1685 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1686 let is_nightly = nightly_options::match_is_nightly_build(matches);
1687 let msg = if !is_nightly {
1689 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1690 edition, LATEST_STABLE_EDITION
1693 format!("edition {edition} is unstable and only available with -Z unstable-options")
1695 early_error(ErrorOutputType::default(), &msg)
1701 fn check_error_format_stability(
1702 unstable_opts: &UnstableOptions,
1703 error_format: ErrorOutputType,
1704 json_rendered: HumanReadableErrorType,
1706 if !unstable_opts.unstable_options {
1707 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1709 ErrorOutputType::Json { pretty: false, json_rendered },
1710 "`--error-format=pretty-json` is unstable",
1713 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1717 ErrorOutputType::Json { pretty: false, json_rendered },
1718 "`--error-format=human-annotate-rs` is unstable",
1724 fn parse_output_types(
1725 unstable_opts: &UnstableOptions,
1726 matches: &getopts::Matches,
1727 error_format: ErrorOutputType,
1729 let mut output_types = BTreeMap::new();
1730 if !unstable_opts.parse_only {
1731 for list in matches.opt_strs("emit") {
1732 for output_type in list.split(',') {
1733 let (shorthand, path) = match output_type.split_once('=') {
1734 None => (output_type, None),
1735 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1737 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1741 "unknown emission type: `{shorthand}` - expected one of: {display}",
1742 display = OutputType::shorthands_display(),
1746 output_types.insert(output_type, path);
1750 if output_types.is_empty() {
1751 output_types.insert(OutputType::Exe, None);
1753 OutputTypes(output_types)
1756 fn should_override_cgus_and_disable_thinlto(
1757 output_types: &OutputTypes,
1758 matches: &getopts::Matches,
1759 error_format: ErrorOutputType,
1760 mut codegen_units: Option<usize>,
1761 ) -> (bool, Option<usize>) {
1762 let mut disable_local_thinlto = false;
1763 // Issue #30063: if user requests LLVM-related output to one
1764 // particular path, disable codegen-units.
1765 let incompatible: Vec<_> = output_types
1768 .map(|ot_path| ot_path.0)
1769 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1770 .map(|ot| ot.shorthand())
1772 if !incompatible.is_empty() {
1773 match codegen_units {
1774 Some(n) if n > 1 => {
1775 if matches.opt_present("o") {
1776 for ot in &incompatible {
1780 "`--emit={ot}` with `-o` incompatible with \
1781 `-C codegen-units=N` for N > 1",
1785 early_warn(error_format, "resetting to default -C codegen-units=1");
1786 codegen_units = Some(1);
1787 disable_local_thinlto = true;
1791 codegen_units = Some(1);
1792 disable_local_thinlto = true;
1797 if codegen_units == Some(0) {
1798 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1801 (disable_local_thinlto, codegen_units)
1804 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1805 if unstable_opts.threads == 0 {
1806 early_error(error_format, "value for threads must be a positive non-zero integer");
1809 if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
1810 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1814 fn collect_print_requests(
1815 cg: &mut CodegenOptions,
1816 unstable_opts: &mut UnstableOptions,
1817 matches: &getopts::Matches,
1818 error_format: ErrorOutputType,
1819 ) -> Vec<PrintRequest> {
1820 let mut prints = Vec::<PrintRequest>::new();
1821 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1822 prints.push(PrintRequest::TargetCPUs);
1823 cg.target_cpu = None;
1825 if cg.target_feature == "help" {
1826 prints.push(PrintRequest::TargetFeatures);
1827 cg.target_feature = String::new();
1830 const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
1831 ("crate-name", PrintRequest::CrateName),
1832 ("file-names", PrintRequest::FileNames),
1833 ("sysroot", PrintRequest::Sysroot),
1834 ("target-libdir", PrintRequest::TargetLibdir),
1835 ("cfg", PrintRequest::Cfg),
1836 ("calling-conventions", PrintRequest::CallingConventions),
1837 ("target-list", PrintRequest::TargetList),
1838 ("target-cpus", PrintRequest::TargetCPUs),
1839 ("target-features", PrintRequest::TargetFeatures),
1840 ("relocation-models", PrintRequest::RelocationModels),
1841 ("code-models", PrintRequest::CodeModels),
1842 ("tls-models", PrintRequest::TlsModels),
1843 ("native-static-libs", PrintRequest::NativeStaticLibs),
1844 ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
1845 ("target-spec-json", PrintRequest::TargetSpec),
1846 ("link-args", PrintRequest::LinkArgs),
1847 ("split-debuginfo", PrintRequest::SplitDebuginfo),
1850 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
1851 match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
1852 Some((_, PrintRequest::TargetSpec)) => {
1853 if unstable_opts.unstable_options {
1854 PrintRequest::TargetSpec
1858 "the `-Z unstable-options` flag must also be passed to \
1859 enable the target-spec-json print option",
1863 Some(&(_, print_request)) => print_request,
1866 PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
1867 let prints = prints.join(", ");
1870 &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
1879 pub fn parse_target_triple(
1880 matches: &getopts::Matches,
1881 error_format: ErrorOutputType,
1883 match matches.opt_str("target") {
1884 Some(target) if target.ends_with(".json") => {
1885 let path = Path::new(&target);
1886 TargetTriple::from_path(path).unwrap_or_else(|_| {
1887 early_error(error_format, &format!("target file {path:?} does not exist"))
1890 Some(target) => TargetTriple::TargetTriple(target),
1891 _ => TargetTriple::from_triple(host_triple()),
1896 matches: &getopts::Matches,
1897 cg: &CodegenOptions,
1898 error_format: ErrorOutputType,
1900 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1901 // to use them interchangeably. However, because they're technically different flags,
1902 // we need to work out manually which should take precedence if both are supplied (i.e.
1903 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1904 // comparing them. Note that if a flag is not found, its position will be `None`, which
1905 // always compared less than `Some(_)`.
1906 let max_o = matches.opt_positions("O").into_iter().max();
1910 .flat_map(|(i, s)| {
1911 // NB: This can match a string without `=`.
1912 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
1918 match cg.opt_level.as_ref() {
1919 "0" => OptLevel::No,
1920 "1" => OptLevel::Less,
1921 "2" => OptLevel::Default,
1922 "3" => OptLevel::Aggressive,
1923 "s" => OptLevel::Size,
1924 "z" => OptLevel::SizeMin,
1929 "optimization level needs to be \
1930 between 0-3, s or z (instead was `{arg}`)"
1938 fn select_debuginfo(
1939 matches: &getopts::Matches,
1940 cg: &CodegenOptions,
1941 error_format: ErrorOutputType,
1943 let max_g = matches.opt_positions("g").into_iter().max();
1947 .flat_map(|(i, s)| {
1948 // NB: This can match a string without `=`.
1949 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
1955 match cg.debuginfo {
1956 0 => DebugInfo::None,
1957 1 => DebugInfo::Limited,
1958 2 => DebugInfo::Full,
1963 "debug info level needs to be between \
1964 0-2 (instead was `{arg}`)"
1972 pub(crate) fn parse_assert_incr_state(
1973 opt_assertion: &Option<String>,
1974 error_format: ErrorOutputType,
1975 ) -> Option<IncrementalStateAssertion> {
1976 match opt_assertion {
1977 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1978 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1980 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1986 fn parse_native_lib_kind(
1987 matches: &getopts::Matches,
1989 error_format: ErrorOutputType,
1990 ) -> (NativeLibKind, Option<bool>) {
1991 let (kind, modifiers) = match kind.split_once(':') {
1992 None => (kind, None),
1993 Some((kind, modifiers)) => (kind, Some(modifiers)),
1996 let kind = match kind {
1997 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1998 "dylib" => NativeLibKind::Dylib { as_needed: None },
1999 "framework" => NativeLibKind::Framework { as_needed: None },
2001 if !nightly_options::is_unstable_enabled(matches) {
2002 let why = if nightly_options::match_is_nightly_build(matches) {
2003 " and only accepted on the nightly compiler"
2005 ", the `-Z unstable-options` flag must also be passed to use it"
2007 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
2009 NativeLibKind::LinkArg
2014 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
2019 None => (kind, None),
2020 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
2024 fn parse_native_lib_modifiers(
2025 mut kind: NativeLibKind,
2027 error_format: ErrorOutputType,
2028 matches: &getopts::Matches,
2029 ) -> (NativeLibKind, Option<bool>) {
2030 let mut verbatim = None;
2031 for modifier in modifiers.split(',') {
2032 let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
2033 Some(m) => (m, modifier.starts_with('+')),
2034 None => early_error(
2036 "invalid linking modifier syntax, expected '+' or '-' prefix \
2037 before one of: bundle, verbatim, whole-archive, as-needed",
2041 let report_unstable_modifier = || {
2042 if !nightly_options::is_unstable_enabled(matches) {
2043 let why = if nightly_options::match_is_nightly_build(matches) {
2044 " and only accepted on the nightly compiler"
2046 ", the `-Z unstable-options` flag must also be passed to use it"
2050 &format!("linking modifier `{modifier}` is unstable{why}"),
2054 let assign_modifier = |dst: &mut Option<bool>| {
2056 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2057 early_error(error_format, &msg)
2062 match (modifier, &mut kind) {
2063 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2064 ("bundle", _) => early_error(
2066 "linking modifier `bundle` is only compatible with `static` linking kind",
2069 ("verbatim", _) => assign_modifier(&mut verbatim),
2071 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2072 assign_modifier(whole_archive)
2074 ("whole-archive", _) => early_error(
2076 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2079 ("as-needed", NativeLibKind::Dylib { as_needed })
2080 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2081 report_unstable_modifier();
2082 assign_modifier(as_needed)
2084 ("as-needed", _) => early_error(
2086 "linking modifier `as-needed` is only compatible with \
2087 `dylib` and `framework` linking kinds",
2090 // Note: this error also excludes the case with empty modifier
2091 // string, like `modifiers = ""`.
2095 "unknown linking modifier `{modifier}`, expected one \
2096 of: bundle, verbatim, whole-archive, as-needed"
2105 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2110 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2111 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2112 // where MODIFIERS are a comma separated list of supported modifiers
2113 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2114 // with either + or - to indicate whether it is enabled or disabled.
2115 // The last value specified for a given modifier wins.
2116 let (name, kind, verbatim) = match s.split_once('=') {
2117 None => (s, NativeLibKind::Unspecified, None),
2118 Some((kind, name)) => {
2119 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2120 (name.to_string(), kind, verbatim)
2124 let (name, new_name) = match name.split_once(':') {
2125 None => (name, None),
2126 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2128 if name.is_empty() {
2129 early_error(error_format, "library name must not be empty");
2131 NativeLib { name, new_name, kind, verbatim }
2136 pub fn parse_externs(
2137 matches: &getopts::Matches,
2138 unstable_opts: &UnstableOptions,
2139 error_format: ErrorOutputType,
2141 let is_unstable_enabled = unstable_opts.unstable_options;
2142 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2143 for arg in matches.opt_strs("extern") {
2144 let (name, path) = match arg.split_once('=') {
2145 None => (arg, None),
2146 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2148 let (options, name) = match name.split_once(':') {
2149 None => (None, name),
2150 Some((opts, name)) => (Some(opts), name.to_string()),
2153 let path = path.map(|p| CanonicalizedPath::new(p));
2155 let entry = externs.entry(name.to_owned());
2157 use std::collections::btree_map::Entry;
2159 let entry = if let Some(path) = path {
2160 // --extern prelude_name=some_file.rlib
2162 Entry::Vacant(vacant) => {
2163 let files = BTreeSet::from_iter(iter::once(path));
2164 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2166 Entry::Occupied(occupied) => {
2167 let ext_ent = occupied.into_mut();
2169 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2173 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2176 // Exact paths take precedence over search directories.
2177 let files = BTreeSet::from_iter(iter::once(path));
2178 *location = ExternLocation::ExactPaths(files);
2185 // --extern prelude_name
2187 Entry::Vacant(vacant) => {
2188 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2190 Entry::Occupied(occupied) => {
2191 // Ignore if already specified.
2197 let mut is_private_dep = false;
2198 let mut add_prelude = true;
2199 let mut nounused_dep = false;
2200 if let Some(opts) = options {
2201 if !is_unstable_enabled {
2204 "the `-Z unstable-options` flag must also be passed to \
2205 enable `--extern options",
2208 for opt in opts.split(',') {
2210 "priv" => is_private_dep = true,
2212 if let ExternLocation::ExactPaths(_) = &entry.location {
2213 add_prelude = false;
2217 "the `noprelude` --extern option requires a file path",
2221 "nounused" => nounused_dep = true,
2222 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2227 // Crates start out being not private, and go to being private `priv`
2229 entry.is_private_dep |= is_private_dep;
2230 // likewise `nounused`
2231 entry.nounused_dep |= nounused_dep;
2232 // If any flag is missing `noprelude`, then add to the prelude.
2233 entry.add_prelude |= add_prelude;
2238 fn parse_remap_path_prefix(
2239 matches: &getopts::Matches,
2240 unstable_opts: &UnstableOptions,
2241 error_format: ErrorOutputType,
2242 ) -> Vec<(PathBuf, PathBuf)> {
2243 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2244 .opt_strs("remap-path-prefix")
2246 .map(|remap| match remap.rsplit_once('=') {
2247 None => early_error(
2249 "--remap-path-prefix must contain '=' between FROM and TO",
2251 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2254 match &unstable_opts.remap_cwd_prefix {
2255 Some(to) => match std::env::current_dir() {
2256 Ok(cwd) => mapping.push((cwd, to.clone())),
2264 // JUSTIFICATION: before wrapper fn is available
2265 #[allow(rustc::bad_opt_access)]
2266 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2267 let color = parse_color(matches);
2269 let edition = parse_crate_edition(matches);
2273 json_artifact_notifications,
2274 json_unused_externs,
2275 json_future_incompat,
2276 } = parse_json(matches);
2278 let error_format = parse_error_format(matches, color, json_rendered);
2280 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2281 early_error(error_format, "`--diagnostic-width` must be an positive integer");
2284 let unparsed_crate_types = matches.opt_strs("crate-type");
2285 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2286 .unwrap_or_else(|e| early_error(error_format, &e));
2288 let mut unstable_opts = UnstableOptions::build(matches, error_format);
2289 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2291 check_error_format_stability(&unstable_opts, error_format, json_rendered);
2293 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2296 "the `-Z unstable-options` flag must also be passed to enable \
2297 the flag `--json=unused-externs`",
2301 let output_types = parse_output_types(&unstable_opts, matches, error_format);
2303 let mut cg = CodegenOptions::build(matches, error_format);
2304 let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2311 check_thread_count(&unstable_opts, error_format);
2313 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2315 let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
2317 if unstable_opts.profile && incremental.is_some() {
2320 "can't instrument with gcov profiling when compiling incrementally",
2323 if unstable_opts.profile {
2324 match codegen_units {
2326 None => codegen_units = Some(1),
2327 Some(_) => early_error(
2329 "can't instrument with gcov profiling with multiple codegen units",
2334 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2337 "options `-C profile-generate` and `-C profile-use` are exclusive",
2341 if unstable_opts.profile_sample_use.is_some()
2342 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2346 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2350 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2352 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2353 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2356 "incompatible values passed for `-C symbol-mangling-version` \
2357 and `-Z symbol-mangling-version`",
2360 (Some(SymbolManglingVersion::V0), _) => {}
2361 (Some(_), _) if !unstable_opts.unstable_options => {
2364 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2371 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2373 cg.symbol_mangling_version = smv;
2378 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2380 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2381 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2384 "incompatible values passed for `-C instrument-coverage` \
2385 and `-Z instrument-coverage`",
2388 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2389 (Some(_), _) if !unstable_opts.unstable_options => {
2392 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2399 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2401 cg.instrument_coverage = ic;
2406 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2407 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2410 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2411 or `-C profile-generate`",
2415 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2416 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2417 // multiple runs, including some changes to source code; so mangled names must be consistent
2418 // across compilations.
2419 match cg.symbol_mangling_version {
2420 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2421 Some(SymbolManglingVersion::Legacy) => {
2424 "-C instrument-coverage requires symbol mangling version `v0`, \
2425 but `-C symbol-mangling-version=legacy` was specified",
2428 Some(SymbolManglingVersion::V0) => {}
2432 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2433 unstable_opts.graphviz_font = graphviz_font;
2436 if !cg.embed_bitcode {
2438 LtoCli::No | LtoCli::Unspecified => {}
2439 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2441 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2446 let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
2450 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2451 let target_triple = parse_target_triple(matches, error_format);
2452 let opt_level = parse_opt_level(matches, &cg, error_format);
2453 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2454 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2455 // for more details.
2456 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2457 let debuginfo = select_debuginfo(matches, &cg, error_format);
2459 let mut search_paths = vec![];
2460 for s in &matches.opt_strs("L") {
2461 search_paths.push(SearchPath::from_cli_opt(s, error_format));
2464 let libs = parse_libs(matches, error_format);
2466 let test = matches.opt_present("test");
2468 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2469 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2472 let externs = parse_externs(matches, &unstable_opts, error_format);
2474 let crate_name = matches.opt_str("crate-name");
2476 let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
2478 let pretty = parse_pretty(&unstable_opts, error_format);
2480 // query-dep-graph is required if dump-dep-graph is given #106736
2481 if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
2482 early_error(error_format, "can't dump dependency graph without `-Z query-dep-graph`");
2485 // Try to find a directory containing the Rust `src`, for more details see
2486 // the doc comment on the `real_rust_source_base_dir` field.
2488 let sysroot = match &sysroot_opt {
2491 tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
2495 let real_rust_source_base_dir = {
2496 // This is the location used by the `rust-src` `rustup` component.
2497 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2498 if let Ok(metadata) = candidate.symlink_metadata() {
2499 // Replace the symlink rustbuild creates, with its destination.
2500 // We could try to use `fs::canonicalize` instead, but that might
2501 // produce unnecessarily verbose path.
2502 if metadata.file_type().is_symlink() {
2503 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2504 candidate = symlink_dest;
2509 // Only use this directory if it has a file we can expect to always find.
2510 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2513 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2514 early_error(error_format, &format!("Current directory is invalid: {e}"));
2517 let remap = FilePathMapping::new(remap_path_prefix.clone());
2518 let (path, remapped) = remap.map_prefix(&working_dir);
2519 let working_dir = if remapped {
2520 RealFileName::Remapped { virtual_name: path.into_owned(), local_path: Some(working_dir) }
2522 RealFileName::LocalPath(path.into_owned())
2528 optimize: opt_level,
2535 maybe_sysroot: sysroot_opt,
2545 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2549 actually_rustdoc: false,
2550 trimmed_def_paths: TrimmedDefPaths::default(),
2551 cli_forced_codegen_units: codegen_units,
2552 cli_forced_local_thinlto_off: disable_local_thinlto,
2554 real_rust_source_base_dir,
2556 json_artifact_notifications,
2557 json_unused_externs,
2558 json_future_incompat,
2564 fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2567 let first = match unstable_opts.unpretty.as_deref()? {
2568 "normal" => Source(PpSourceMode::Normal),
2569 "identified" => Source(PpSourceMode::Identified),
2570 "expanded" => Source(PpSourceMode::Expanded),
2571 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2572 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2573 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2574 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2575 "hir" => Hir(PpHirMode::Normal),
2576 "hir,identified" => Hir(PpHirMode::Identified),
2577 "hir,typed" => Hir(PpHirMode::Typed),
2578 "hir-tree" => HirTree,
2579 "thir-tree" => ThirTree,
2581 "mir-cfg" => MirCFG,
2582 name => early_error(
2585 "argument to `unpretty` must be one of `normal`, `identified`, \
2586 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2587 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2588 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2592 debug!("got unpretty option: {first:?}");
2596 pub fn make_crate_type_option() -> RustcOptGroup {
2600 "Comma separated list of types of crates
2601 for the compiler to emit",
2602 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2606 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2607 let mut crate_types: Vec<CrateType> = Vec::new();
2608 for unparsed_crate_type in &list_list {
2609 for part in unparsed_crate_type.split(',') {
2610 let new_part = match part {
2611 "lib" => default_lib_output(),
2612 "rlib" => CrateType::Rlib,
2613 "staticlib" => CrateType::Staticlib,
2614 "dylib" => CrateType::Dylib,
2615 "cdylib" => CrateType::Cdylib,
2616 "bin" => CrateType::Executable,
2617 "proc-macro" => CrateType::ProcMacro,
2618 _ => return Err(format!("unknown crate type: `{part}`")),
2620 if !crate_types.contains(&new_part) {
2621 crate_types.push(new_part)
2629 pub mod nightly_options {
2630 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2631 use crate::early_error;
2632 use rustc_feature::UnstableFeatures;
2634 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2635 match_is_nightly_build(matches)
2636 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2639 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2640 is_nightly_build(matches.opt_str("crate-name").as_deref())
2643 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2644 UnstableFeatures::from_environment(krate).is_nightly_build()
2647 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2648 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2649 let really_allows_unstable_options = match_is_nightly_build(matches);
2651 for opt in flags.iter() {
2652 if opt.stability == OptionStability::Stable {
2655 if !matches.opt_present(opt.name) {
2658 if opt.name != "Z" && !has_z_unstable_option {
2660 ErrorOutputType::default(),
2662 "the `-Z unstable-options` flag must also be passed to enable \
2668 if really_allows_unstable_options {
2671 match opt.stability {
2672 OptionStability::Unstable => {
2674 "the option `{}` is only accepted on the \
2678 early_error(ErrorOutputType::default(), &msg);
2680 OptionStability::Stable => {}
2686 impl fmt::Display for CrateType {
2687 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2689 CrateType::Executable => "bin".fmt(f),
2690 CrateType::Dylib => "dylib".fmt(f),
2691 CrateType::Rlib => "rlib".fmt(f),
2692 CrateType::Staticlib => "staticlib".fmt(f),
2693 CrateType::Cdylib => "cdylib".fmt(f),
2694 CrateType::ProcMacro => "proc-macro".fmt(f),
2699 #[derive(Copy, Clone, PartialEq, Debug)]
2700 pub enum PpSourceMode {
2701 /// `-Zunpretty=normal`
2703 /// `-Zunpretty=expanded`
2705 /// `-Zunpretty=identified`
2707 /// `-Zunpretty=expanded,identified`
2709 /// `-Zunpretty=expanded,hygiene`
2713 #[derive(Copy, Clone, PartialEq, Debug)]
2714 pub enum PpAstTreeMode {
2715 /// `-Zunpretty=ast`
2717 /// `-Zunpretty=ast,expanded`
2721 #[derive(Copy, Clone, PartialEq, Debug)]
2722 pub enum PpHirMode {
2723 /// `-Zunpretty=hir`
2725 /// `-Zunpretty=hir,identified`
2727 /// `-Zunpretty=hir,typed`
2731 #[derive(Copy, Clone, PartialEq, Debug)]
2733 /// Options that print the source code, i.e.
2734 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2735 Source(PpSourceMode),
2736 AstTree(PpAstTreeMode),
2737 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2739 /// `-Zunpretty=hir-tree`
2741 /// `-Zunpretty=thir-tree`
2743 /// `-Zunpretty=mir`
2745 /// `-Zunpretty=mir-cfg`
2750 pub fn needs_ast_map(&self) -> bool {
2752 use PpSourceMode::*;
2754 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2756 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2757 | AstTree(PpAstTreeMode::Expanded)
2765 pub fn needs_hir(&self) -> bool {
2768 Source(_) | AstTree(_) => false,
2770 Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
2774 pub fn needs_analysis(&self) -> bool {
2776 matches!(*self, Mir | MirCFG | ThirTree)
2780 /// Command-line arguments passed to the compiler have to be incorporated with
2781 /// the dependency tracking system for incremental compilation. This module
2782 /// provides some utilities to make this more convenient.
2784 /// The values of all command-line arguments that are relevant for dependency
2785 /// tracking are hashed into a single value that determines whether the
2786 /// incremental compilation cache can be re-used or not. This hashing is done
2787 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2788 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2789 /// the hash of which is order dependent, but we might not want the order of
2790 /// arguments to make a difference for the hash).
2792 /// However, since the value provided by `Hash::hash` often *is* suitable,
2793 /// especially for primitive types, there is the
2794 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2795 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2796 /// we have an opt-in scheme here, so one is hopefully forced to think about
2797 /// how the hash should be calculated when adding a new command-line argument.
2798 pub(crate) mod dep_tracking {
2800 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2801 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2802 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
2803 SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
2806 use crate::options::WasiExecModel;
2807 use crate::utils::{NativeLib, NativeLibKind};
2808 use rustc_errors::LanguageIdentifier;
2809 use rustc_feature::UnstableFeatures;
2810 use rustc_span::edition::Edition;
2811 use rustc_span::RealFileName;
2812 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2813 use rustc_target::spec::{
2814 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2816 use std::collections::hash_map::DefaultHasher;
2817 use std::collections::BTreeMap;
2818 use std::hash::Hash;
2819 use std::num::NonZeroUsize;
2820 use std::path::PathBuf;
2822 pub trait DepTrackingHash {
2825 hasher: &mut DefaultHasher,
2826 error_format: ErrorOutputType,
2827 for_crate_hash: bool,
2831 macro_rules! impl_dep_tracking_hash_via_hash {
2832 ($($t:ty),+ $(,)?) => {$(
2833 impl DepTrackingHash for $t {
2834 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2835 Hash::hash(self, hasher);
2841 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2844 hasher: &mut DefaultHasher,
2845 error_format: ErrorOutputType,
2846 for_crate_hash: bool,
2850 Hash::hash(&1, hasher);
2851 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2853 None => Hash::hash(&0, hasher),
2858 impl_dep_tracking_hash_via_hash!(
2893 SymbolManglingVersion,
2894 SourceFileHashAlgorithm,
2906 impl<T1, T2> DepTrackingHash for (T1, T2)
2908 T1: DepTrackingHash,
2909 T2: DepTrackingHash,
2913 hasher: &mut DefaultHasher,
2914 error_format: ErrorOutputType,
2915 for_crate_hash: bool,
2917 Hash::hash(&0, hasher);
2918 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2919 Hash::hash(&1, hasher);
2920 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2924 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2926 T1: DepTrackingHash,
2927 T2: DepTrackingHash,
2928 T3: DepTrackingHash,
2932 hasher: &mut DefaultHasher,
2933 error_format: ErrorOutputType,
2934 for_crate_hash: bool,
2936 Hash::hash(&0, hasher);
2937 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2938 Hash::hash(&1, hasher);
2939 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2940 Hash::hash(&2, hasher);
2941 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2945 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2948 hasher: &mut DefaultHasher,
2949 error_format: ErrorOutputType,
2950 for_crate_hash: bool,
2952 Hash::hash(&self.len(), hasher);
2953 for (index, elem) in self.iter().enumerate() {
2954 Hash::hash(&index, hasher);
2955 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2960 impl DepTrackingHash for OutputTypes {
2963 hasher: &mut DefaultHasher,
2964 error_format: ErrorOutputType,
2965 for_crate_hash: bool,
2967 Hash::hash(&self.0.len(), hasher);
2968 for (key, val) in &self.0 {
2969 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2970 if !for_crate_hash {
2971 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2977 // This is a stable hash because BTreeMap is a sorted container
2978 pub(crate) fn stable_hash(
2979 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2980 hasher: &mut DefaultHasher,
2981 error_format: ErrorOutputType,
2982 for_crate_hash: bool,
2984 for (key, sub_hash) in sub_hashes {
2985 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2986 // the keys, as they are just plain strings
2987 Hash::hash(&key.len(), hasher);
2988 Hash::hash(key, hasher);
2989 sub_hash.hash(hasher, error_format, for_crate_hash);
2994 /// Default behavior to use in out-of-memory situations.
2995 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2996 pub enum OomStrategy {
2997 /// Generate a panic that can be caught by `catch_unwind`.
3000 /// Abort the process immediately.
3005 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
3007 pub fn should_panic(self) -> u8 {
3009 OomStrategy::Panic => 1,
3010 OomStrategy::Abort => 0,
3015 /// How to run proc-macro code when building this crate
3016 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
3017 pub enum ProcMacroExecutionStrategy {
3018 /// Run the proc-macro code on the same thread as the server.
3021 /// Run the proc-macro code on a different thread.
3025 /// Which format to use for `-Z dump-mono-stats`
3026 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
3027 pub enum DumpMonoStatsFormat {
3028 /// Pretty-print a markdown table
3030 /// Emit structured JSON
3034 impl DumpMonoStatsFormat {
3035 pub fn extension(self) -> &'static str {
3037 Self::Markdown => "md",
3038 Self::Json => "json",