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(),
596 #[derive(Clone, Hash, Debug, HashStable_Generic)]
597 pub struct OutputFilenames {
598 pub out_directory: PathBuf,
600 pub single_output_file: Option<PathBuf>,
601 pub temps_directory: Option<PathBuf>,
602 pub outputs: OutputTypes,
605 pub const RLINK_EXT: &str = "rlink";
606 pub const RUST_CGU_EXT: &str = "rcgu";
607 pub const DWARF_OBJECT_EXT: &str = "dwo";
609 impl OutputFilenames {
611 out_directory: PathBuf,
612 out_filestem: String,
613 single_output_file: Option<PathBuf>,
614 temps_directory: Option<PathBuf>,
616 outputs: OutputTypes,
623 filestem: format!("{out_filestem}{extra}"),
627 pub fn path(&self, flavor: OutputType) -> PathBuf {
630 .and_then(|p| p.to_owned())
631 .or_else(|| self.single_output_file.clone())
632 .unwrap_or_else(|| self.output_path(flavor))
635 /// Gets the output path where a compilation artifact of the given type
636 /// should be placed on disk.
637 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
638 let extension = flavor.extension();
639 self.with_directory_and_extension(&self.out_directory, extension)
642 /// Gets the path where a compilation artifact of the given type for the
643 /// given codegen unit should be placed on disk. If codegen_unit_name is
644 /// None, a path distinct from those of any codegen unit will be generated.
645 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
646 let extension = flavor.extension();
647 self.temp_path_ext(extension, codegen_unit_name)
650 /// Like `temp_path`, but specifically for dwarf objects.
651 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
652 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
655 /// Like `temp_path`, but also supports things where there is no corresponding
656 /// OutputType, like noopt-bitcode or lto-bitcode.
657 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
658 let mut extension = String::new();
660 if let Some(codegen_unit_name) = codegen_unit_name {
661 extension.push_str(codegen_unit_name);
665 if !extension.is_empty() {
667 extension.push_str(RUST_CGU_EXT);
671 extension.push_str(ext);
674 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
676 self.with_directory_and_extension(temps_directory, &extension)
679 pub fn with_extension(&self, extension: &str) -> PathBuf {
680 self.with_directory_and_extension(&self.out_directory, extension)
683 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
684 let mut path = directory.join(&self.filestem);
685 path.set_extension(extension);
689 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
690 /// mode is being used, which is the logic that this function is intended to encapsulate.
691 pub fn split_dwarf_path(
693 split_debuginfo_kind: SplitDebuginfo,
694 split_dwarf_kind: SplitDwarfKind,
695 cgu_name: Option<&str>,
696 ) -> Option<PathBuf> {
697 let obj_out = self.temp_path(OutputType::Object, cgu_name);
698 let dwo_out = self.temp_path_dwo(cgu_name);
699 match (split_debuginfo_kind, split_dwarf_kind) {
700 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
701 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
702 // (pointing at the path which is being determined here). Use the path to the current
704 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
707 // Split mode emits the DWARF into a different file, use that path.
708 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
715 pub fn host_triple() -> &'static str {
716 // Get the host triple out of the build environment. This ensures that our
717 // idea of the host triple is the same as for the set of libraries we've
718 // actually built. We can't just take LLVM's host triple because they
719 // normalize all ix86 architectures to i386.
721 // Instead of grabbing the host triple (for the current host), we grab (at
722 // compile time) the target triple that this rustc is built with and
723 // calling that (at runtime) the host triple.
724 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
727 impl Default for Options {
728 fn default() -> Options {
730 assert_incr_state: None,
731 crate_types: Vec::new(),
732 optimize: OptLevel::No,
733 debuginfo: DebugInfo::None,
734 lint_opts: Vec::new(),
736 describe_lints: false,
737 output_types: OutputTypes(BTreeMap::new()),
738 search_paths: vec![],
740 target_triple: TargetTriple::from_triple(host_triple()),
743 unstable_opts: Default::default(),
745 cg: Default::default(),
746 error_format: ErrorOutputType::default(),
747 diagnostic_width: None,
748 externs: Externs(BTreeMap::new()),
751 unstable_features: UnstableFeatures::Disallow,
752 debug_assertions: true,
753 actually_rustdoc: false,
754 trimmed_def_paths: TrimmedDefPaths::default(),
755 cli_forced_codegen_units: None,
756 cli_forced_local_thinlto_off: false,
757 remap_path_prefix: Vec::new(),
758 real_rust_source_base_dir: None,
759 edition: DEFAULT_EDITION,
760 json_artifact_notifications: false,
761 json_unused_externs: JsonUnusedExterns::No,
762 json_future_incompat: false,
764 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
770 /// Returns `true` if there is a reason to build the dep graph.
771 pub fn build_dep_graph(&self) -> bool {
772 self.incremental.is_some()
773 || self.unstable_opts.dump_dep_graph
774 || self.unstable_opts.query_dep_graph
777 pub fn file_path_mapping(&self) -> FilePathMapping {
778 FilePathMapping::new(self.remap_path_prefix.clone())
781 /// Returns `true` if there will be an output file generated.
782 pub fn will_create_output_file(&self) -> bool {
783 !self.unstable_opts.parse_only && // The file is just being parsed
784 !self.unstable_opts.ls // The file is just being queried
788 pub fn share_generics(&self) -> bool {
789 match self.unstable_opts.share_generics {
790 Some(setting) => setting,
791 None => match self.optimize {
792 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
793 OptLevel::Default | OptLevel::Aggressive => false,
798 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
799 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
802 #[allow(rustc::bad_opt_access)]
803 pub fn incremental_relative_spans(&self) -> bool {
804 self.unstable_opts.incremental_relative_spans
805 || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
809 impl UnstableOptions {
810 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
813 treat_err_as_bug: self.treat_err_as_bug,
814 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
815 report_delayed_bugs: self.report_delayed_bugs,
816 macro_backtrace: self.macro_backtrace,
817 deduplicate_diagnostics: self.deduplicate_diagnostics,
818 track_diagnostics: self.track_diagnostics,
823 // The type of entry function, so users can have their own entry functions
824 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
825 pub enum EntryFnType {
827 /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
829 /// What values that are valid and what they mean must be in sync
830 /// across rustc and libstd, but we don't want it public in libstd,
831 /// so we take a bit of an unusual approach with simple constants
832 /// and an `include!()`.
838 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
839 #[derive(HashStable_Generic)]
850 /// When generated, is this crate type an archive?
851 pub fn is_archive(&self) -> bool {
853 CrateType::Rlib | CrateType::Staticlib => true,
854 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
861 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
868 pub fn is_empty(&self) -> bool {
870 Passes::Some(ref v) => v.is_empty(),
871 Passes::All => false,
875 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
877 Passes::Some(ref mut v) => v.extend(passes),
883 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
889 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
895 #[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
896 pub struct BranchProtection {
898 pub pac_ret: Option<PacRet>,
901 pub const fn default_lib_output() -> CrateType {
905 fn default_configuration(sess: &Session) -> CrateConfig {
906 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
907 let end = &sess.target.endian;
908 let arch = &sess.target.arch;
909 let wordsz = sess.target.pointer_width.to_string();
910 let os = &sess.target.os;
911 let env = &sess.target.env;
912 let abi = &sess.target.abi;
913 let vendor = &sess.target.vendor;
914 let min_atomic_width = sess.target.min_atomic_width();
915 let max_atomic_width = sess.target.max_atomic_width();
916 let atomic_cas = sess.target.atomic_cas;
917 let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
918 sess.emit_fatal(err);
921 let mut ret = CrateConfig::default();
922 ret.reserve(7); // the minimum number of insertions
924 ret.insert((sym::target_os, Some(Symbol::intern(os))));
925 for fam in sess.target.families.as_ref() {
926 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
927 if fam == "windows" {
928 ret.insert((sym::windows, None));
929 } else if fam == "unix" {
930 ret.insert((sym::unix, None));
933 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
934 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
935 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
936 ret.insert((sym::target_env, Some(Symbol::intern(env))));
937 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
938 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
939 if sess.target.has_thread_local {
940 ret.insert((sym::target_thread_local, None));
943 (8, layout.i8_align.abi),
944 (16, layout.i16_align.abi),
945 (32, layout.i32_align.abi),
946 (64, layout.i64_align.abi),
947 (128, layout.i128_align.abi),
949 if i >= min_atomic_width && i <= max_atomic_width {
950 let mut insert_atomic = |s, align: Align| {
951 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
953 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
955 if align.bits() == i {
956 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
959 let s = i.to_string();
960 insert_atomic(&s, align);
962 insert_atomic("ptr", layout.pointer_align.abi);
967 let panic_strategy = sess.panic_strategy();
968 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
970 for s in sess.opts.unstable_opts.sanitizer {
971 let symbol = Symbol::intern(&s.to_string());
972 ret.insert((sym::sanitize, Some(symbol)));
975 if sess.opts.debug_assertions {
976 ret.insert((sym::debug_assertions, None));
978 // JUSTIFICATION: before wrapper fn is available
979 #[allow(rustc::bad_opt_access)]
980 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
981 ret.insert((sym::proc_macro, None));
986 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
987 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
988 /// but the symbol interner is not yet set up then, so we must convert it later.
989 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
990 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
993 /// The parsed `--check-cfg` options
994 pub struct CheckCfg<T = String> {
995 /// The set of all `names()`, if None no name checking is performed
996 pub names_valid: Option<FxHashSet<T>>,
997 /// Is well known values activated
998 pub well_known_values: bool,
999 /// The set of all `values()`
1000 pub values_valid: FxHashMap<T, FxHashSet<T>>,
1003 impl<T> Default for CheckCfg<T> {
1004 fn default() -> Self {
1006 names_valid: Default::default(),
1007 values_valid: Default::default(),
1008 well_known_values: false,
1013 impl<T> CheckCfg<T> {
1014 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1019 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1023 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1025 well_known_values: self.well_known_values,
1030 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1031 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1032 /// but the symbol interner is not yet set up then, so we must convert it later.
1033 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1034 cfg.map_data(|s| Symbol::intern(s))
1037 impl CrateCheckConfig {
1038 /// Fills a `CrateCheckConfig` with well-known configuration names.
1039 fn fill_well_known_names(&mut self) {
1040 // NOTE: This should be kept in sync with `default_configuration` and
1041 // `fill_well_known_values`
1042 const WELL_KNOWN_NAMES: &[Symbol] = &[
1050 sym::target_pointer_width,
1054 sym::target_thread_local,
1055 sym::target_has_atomic_load_store,
1056 sym::target_has_atomic,
1057 sym::target_has_atomic_equal_alignment,
1058 sym::target_feature,
1061 sym::debug_assertions,
1072 // We only insert well-known names if `names()` was activated
1073 if let Some(names_valid) = &mut self.names_valid {
1074 names_valid.extend(WELL_KNOWN_NAMES);
1078 /// Fills a `CrateCheckConfig` with well-known configuration values.
1079 fn fill_well_known_values(&mut self) {
1080 if !self.well_known_values {
1084 // NOTE: This should be kept in sync with `default_configuration` and
1085 // `fill_well_known_names`
1087 let panic_values = &PanicStrategy::all();
1089 let atomic_values = &[
1091 sym::integer(8usize),
1092 sym::integer(16usize),
1093 sym::integer(32usize),
1094 sym::integer(64usize),
1095 sym::integer(128usize),
1098 let sanitize_values = SanitizerSet::all()
1100 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1102 // Unknown possible values:
1104 // - `target_feature`
1115 sym::debug_assertions,
1116 sym::target_thread_local,
1118 self.values_valid.entry(name).or_default();
1121 // Pre-defined values
1122 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1123 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1124 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1126 .entry(sym::target_has_atomic_load_store)
1128 .extend(atomic_values);
1130 .entry(sym::target_has_atomic_equal_alignment)
1132 .extend(atomic_values);
1134 // Target specific values
1136 const VALUES: [&Symbol; 8] = [
1138 &sym::target_family,
1140 &sym::target_endian,
1143 &sym::target_vendor,
1144 &sym::target_pointer_width,
1147 // Initialize (if not already initialized)
1149 self.values_valid.entry(e).or_default();
1152 // Get all values map at once otherwise it would be costly.
1153 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1156 values_target_family,
1158 values_target_endian,
1161 values_target_vendor,
1162 values_target_pointer_width,
1165 .get_many_mut(VALUES)
1166 .expect("unable to get all the check-cfg values buckets");
1168 for target in TARGETS
1170 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1172 values_target_os.insert(Symbol::intern(&target.options.os));
1173 values_target_family
1174 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1175 values_target_arch.insert(Symbol::intern(&target.arch));
1176 values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
1177 values_target_env.insert(Symbol::intern(&target.options.env));
1178 values_target_abi.insert(Symbol::intern(&target.options.abi));
1179 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1180 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1185 pub fn fill_well_known(&mut self) {
1186 self.fill_well_known_names();
1187 self.fill_well_known_values();
1191 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1192 // Combine the configuration requested by the session (command line) with
1193 // some default and generated configuration items.
1194 let default_cfg = default_configuration(sess);
1195 // If the user wants a test runner, then add the test cfg.
1197 user_cfg.insert((sym::test, None));
1199 user_cfg.extend(default_cfg.iter().cloned());
1203 pub(super) fn build_target_config(
1205 target_override: Option<Target>,
1208 let target_result = target_override.map_or_else(
1209 || Target::search(&opts.target_triple, sysroot),
1210 |t| Ok((t, TargetWarnings::empty())),
1212 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1216 "Error loading target specification: {}. \
1217 Run `rustc --print target-list` for a list of built-in targets",
1222 for warning in target_warnings.warning_messages() {
1223 early_warn(opts.error_format, &warning)
1226 if !matches!(target.pointer_width, 16 | 32 | 64) {
1230 "target specification was invalid: \
1231 unrecognized target-pointer-width {}",
1232 target.pointer_width
1240 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1241 pub enum OptionStability {
1246 pub struct RustcOptGroup {
1247 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1248 pub name: &'static str,
1249 pub stability: OptionStability,
1252 impl RustcOptGroup {
1253 pub fn is_stable(&self) -> bool {
1254 self.stability == OptionStability::Stable
1257 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1259 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1261 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1264 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1266 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1268 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1272 // The `opt` local module holds wrappers around the `getopts` API that
1273 // adds extra rustc-specific metadata to each option; such metadata
1274 // is exposed by . The public
1275 // functions below ending with `_u` are the functions that return
1276 // *unstable* options, i.e., options that are only enabled when the
1277 // user also passes the `-Z unstable-options` debugging flag.
1279 // The `fn flag*` etc below are written so that we can use them
1280 // in the future; do not warn about them not being used right now.
1281 #![allow(dead_code)]
1283 use super::RustcOptGroup;
1285 pub type R = RustcOptGroup;
1286 pub type S = &'static str;
1288 fn stable<F>(name: S, f: F) -> R
1290 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1292 RustcOptGroup::stable(name, f)
1295 fn unstable<F>(name: S, f: F) -> R
1297 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1299 RustcOptGroup::unstable(name, f)
1302 fn longer(a: S, b: S) -> S {
1303 if a.len() > b.len() { a } else { b }
1306 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1307 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1309 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1310 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1312 pub fn flag_s(a: S, b: S, c: S) -> R {
1313 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1315 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1316 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1319 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1320 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1322 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1323 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1326 static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
1328 "Specify which edition of the compiler to use when compiling code. \
1329 The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
1332 /// Returns the "short" subset of the rustc command line options,
1333 /// including metadata for each option, such as whether the option is
1334 /// part of the stable long-term interface for rustc.
1335 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1337 opt::flag_s("h", "help", "Display this message"),
1338 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1339 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1343 "Add a directory to the library search path. The
1344 optional KIND can be one of dependency, crate, native,
1345 framework, or all (the default).",
1351 "Link the generated crate(s) to the specified native
1352 library NAME. The optional KIND can be one of
1353 static, framework, or dylib (the default).
1354 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1355 may be specified each with a prefix of either '+' to
1356 enable or '-' to disable.",
1357 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1359 make_crate_type_option(),
1360 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1370 "Comma separated list of types of output for \
1371 the compiler to emit",
1372 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1377 "Compiler information to print on stdout",
1378 "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
1379 target-list|target-cpus|target-features|relocation-models|code-models|\
1380 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1383 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1384 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1385 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1389 "Write output to compiler-chosen filename \
1396 "Provide a detailed explanation of an error \
1400 opt::flag_s("", "test", "Build a test harness"),
1401 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1402 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1403 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1404 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1405 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1406 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1410 "Set the most restrictive lint level. \
1411 More restrictive lints are capped at this \
1415 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1416 opt::flag_s("V", "version", "Print version info and exit"),
1417 opt::flag_s("v", "verbose", "Use verbose output"),
1421 /// Returns all rustc command line options, including metadata for
1422 /// each option, such as whether the option is part of the stable
1423 /// long-term interface for rustc.
1424 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1425 let mut opts = rustc_short_optgroups();
1426 // FIXME: none of these descriptions are actually used
1431 "Specify where an external rust library is located",
1434 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1435 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1439 "How errors and other messages are produced",
1442 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1446 "Configure coloring of output:
1447 auto = colorize, if output goes to a tty (default);
1448 always = always colorize output;
1449 never = never colorize output",
1450 "auto|always|never",
1455 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1460 "remap-path-prefix",
1461 "Remap source names in all output (compiler messages and output files)",
1468 pub fn get_cmd_lint_options(
1469 matches: &getopts::Matches,
1470 error_format: ErrorOutputType,
1471 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1472 let mut lint_opts_with_position = vec![];
1473 let mut describe_lints = false;
1475 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1476 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1477 if lint_name == "help" {
1478 describe_lints = true;
1480 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1485 lint_opts_with_position.sort_by_key(|x| x.0);
1486 let lint_opts = lint_opts_with_position
1489 .map(|(_, lint_name, level)| (lint_name, level))
1492 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1493 lint::Level::from_str(&cap)
1494 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1497 (lint_opts, describe_lints, lint_cap)
1500 /// Parses the `--color` flag.
1501 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1502 match matches.opt_str("color").as_deref() {
1503 Some("auto") => ColorConfig::Auto,
1504 Some("always") => ColorConfig::Always,
1505 Some("never") => ColorConfig::Never,
1507 None => ColorConfig::Auto,
1509 Some(arg) => early_error(
1510 ErrorOutputType::default(),
1512 "argument for `--color` must be auto, \
1513 always or never (instead was `{arg}`)"
1519 /// Possible json config files
1520 pub struct JsonConfig {
1521 pub json_rendered: HumanReadableErrorType,
1522 pub json_artifact_notifications: bool,
1523 pub json_unused_externs: JsonUnusedExterns,
1524 pub json_future_incompat: bool,
1527 /// Report unused externs in event stream
1528 #[derive(Copy, Clone)]
1529 pub enum JsonUnusedExterns {
1532 /// Report, but do not exit with failure status for deny/forbid
1534 /// Report, and also exit with failure status for deny/forbid
1538 impl JsonUnusedExterns {
1539 pub fn is_enabled(&self) -> bool {
1541 JsonUnusedExterns::No => false,
1542 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1546 pub fn is_loud(&self) -> bool {
1548 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1549 JsonUnusedExterns::Loud => true,
1554 /// Parse the `--json` flag.
1556 /// The first value returned is how to render JSON diagnostics, and the second
1557 /// is whether or not artifact notifications are enabled.
1558 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1559 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1560 HumanReadableErrorType::Default;
1561 let mut json_color = ColorConfig::Never;
1562 let mut json_artifact_notifications = false;
1563 let mut json_unused_externs = JsonUnusedExterns::No;
1564 let mut json_future_incompat = false;
1565 for option in matches.opt_strs("json") {
1566 // For now conservatively forbid `--color` with `--json` since `--json`
1567 // won't actually be emitting any colors and anything colorized is
1568 // embedded in a diagnostic message anyway.
1569 if matches.opt_str("color").is_some() {
1571 ErrorOutputType::default(),
1572 "cannot specify the `--color` option with `--json`",
1576 for sub_option in option.split(',') {
1578 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1579 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1580 "artifacts" => json_artifact_notifications = true,
1581 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1582 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1583 "future-incompat" => json_future_incompat = true,
1585 ErrorOutputType::default(),
1586 &format!("unknown `--json` option `{s}`"),
1593 json_rendered: json_rendered(json_color),
1594 json_artifact_notifications,
1595 json_unused_externs,
1596 json_future_incompat,
1600 /// Parses the `--error-format` flag.
1601 pub fn parse_error_format(
1602 matches: &getopts::Matches,
1604 json_rendered: HumanReadableErrorType,
1605 ) -> ErrorOutputType {
1606 // We need the `opts_present` check because the driver will send us Matches
1607 // with only stable options if no unstable options are used. Since error-format
1608 // is unstable, it will not be present. We have to use `opts_present` not
1609 // `opt_present` because the latter will panic.
1610 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1611 match matches.opt_str("error-format").as_deref() {
1612 None | Some("human") => {
1613 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1615 Some("human-annotate-rs") => {
1616 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1618 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1619 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1620 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1622 Some(arg) => early_error(
1623 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1625 "argument for `--error-format` must be `human`, `json` or \
1626 `short` (instead was `{arg}`)"
1631 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1634 match error_format {
1635 ErrorOutputType::Json { .. } => {}
1637 // Conservatively require that the `--json` argument is coupled with
1638 // `--error-format=json`. This means that `--json` is specified we
1639 // should actually be emitting JSON blobs.
1640 _ if !matches.opt_strs("json").is_empty() => {
1642 ErrorOutputType::default(),
1643 "using `--json` requires also using `--error-format=json`",
1653 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1654 let edition = match matches.opt_str("edition") {
1655 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1657 ErrorOutputType::default(),
1659 "argument for `--edition` must be one of: \
1660 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1664 None => DEFAULT_EDITION,
1667 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1668 let is_nightly = nightly_options::match_is_nightly_build(matches);
1669 let msg = if !is_nightly {
1671 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1672 edition, LATEST_STABLE_EDITION
1675 format!("edition {edition} is unstable and only available with -Z unstable-options")
1677 early_error(ErrorOutputType::default(), &msg)
1683 fn check_error_format_stability(
1684 unstable_opts: &UnstableOptions,
1685 error_format: ErrorOutputType,
1686 json_rendered: HumanReadableErrorType,
1688 if !unstable_opts.unstable_options {
1689 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1691 ErrorOutputType::Json { pretty: false, json_rendered },
1692 "`--error-format=pretty-json` is unstable",
1695 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1699 ErrorOutputType::Json { pretty: false, json_rendered },
1700 "`--error-format=human-annotate-rs` is unstable",
1706 fn parse_output_types(
1707 unstable_opts: &UnstableOptions,
1708 matches: &getopts::Matches,
1709 error_format: ErrorOutputType,
1711 let mut output_types = BTreeMap::new();
1712 if !unstable_opts.parse_only {
1713 for list in matches.opt_strs("emit") {
1714 for output_type in list.split(',') {
1715 let (shorthand, path) = match output_type.split_once('=') {
1716 None => (output_type, None),
1717 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1719 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1723 "unknown emission type: `{shorthand}` - expected one of: {display}",
1724 display = OutputType::shorthands_display(),
1728 output_types.insert(output_type, path);
1732 if output_types.is_empty() {
1733 output_types.insert(OutputType::Exe, None);
1735 OutputTypes(output_types)
1738 fn should_override_cgus_and_disable_thinlto(
1739 output_types: &OutputTypes,
1740 matches: &getopts::Matches,
1741 error_format: ErrorOutputType,
1742 mut codegen_units: Option<usize>,
1743 ) -> (bool, Option<usize>) {
1744 let mut disable_local_thinlto = false;
1745 // Issue #30063: if user requests LLVM-related output to one
1746 // particular path, disable codegen-units.
1747 let incompatible: Vec<_> = output_types
1750 .map(|ot_path| ot_path.0)
1751 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1752 .map(|ot| ot.shorthand())
1754 if !incompatible.is_empty() {
1755 match codegen_units {
1756 Some(n) if n > 1 => {
1757 if matches.opt_present("o") {
1758 for ot in &incompatible {
1762 "`--emit={ot}` with `-o` incompatible with \
1763 `-C codegen-units=N` for N > 1",
1767 early_warn(error_format, "resetting to default -C codegen-units=1");
1768 codegen_units = Some(1);
1769 disable_local_thinlto = true;
1773 codegen_units = Some(1);
1774 disable_local_thinlto = true;
1779 if codegen_units == Some(0) {
1780 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1783 (disable_local_thinlto, codegen_units)
1786 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1787 if unstable_opts.threads == 0 {
1788 early_error(error_format, "value for threads must be a positive non-zero integer");
1791 if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
1792 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1796 fn collect_print_requests(
1797 cg: &mut CodegenOptions,
1798 unstable_opts: &mut UnstableOptions,
1799 matches: &getopts::Matches,
1800 error_format: ErrorOutputType,
1801 ) -> Vec<PrintRequest> {
1802 let mut prints = Vec::<PrintRequest>::new();
1803 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1804 prints.push(PrintRequest::TargetCPUs);
1805 cg.target_cpu = None;
1807 if cg.target_feature == "help" {
1808 prints.push(PrintRequest::TargetFeatures);
1809 cg.target_feature = String::new();
1812 const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
1813 ("crate-name", PrintRequest::CrateName),
1814 ("file-names", PrintRequest::FileNames),
1815 ("sysroot", PrintRequest::Sysroot),
1816 ("target-libdir", PrintRequest::TargetLibdir),
1817 ("cfg", PrintRequest::Cfg),
1818 ("calling-conventions", PrintRequest::CallingConventions),
1819 ("target-list", PrintRequest::TargetList),
1820 ("target-cpus", PrintRequest::TargetCPUs),
1821 ("target-features", PrintRequest::TargetFeatures),
1822 ("relocation-models", PrintRequest::RelocationModels),
1823 ("code-models", PrintRequest::CodeModels),
1824 ("tls-models", PrintRequest::TlsModels),
1825 ("native-static-libs", PrintRequest::NativeStaticLibs),
1826 ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
1827 ("target-spec-json", PrintRequest::TargetSpec),
1828 ("link-args", PrintRequest::LinkArgs),
1829 ("split-debuginfo", PrintRequest::SplitDebuginfo),
1832 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
1833 match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
1834 Some((_, PrintRequest::TargetSpec)) => {
1835 if unstable_opts.unstable_options {
1836 PrintRequest::TargetSpec
1840 "the `-Z unstable-options` flag must also be passed to \
1841 enable the target-spec-json print option",
1845 Some(&(_, print_request)) => print_request,
1848 PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
1849 let prints = prints.join(", ");
1852 &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
1861 pub fn parse_target_triple(
1862 matches: &getopts::Matches,
1863 error_format: ErrorOutputType,
1865 match matches.opt_str("target") {
1866 Some(target) if target.ends_with(".json") => {
1867 let path = Path::new(&target);
1868 TargetTriple::from_path(path).unwrap_or_else(|_| {
1869 early_error(error_format, &format!("target file {path:?} does not exist"))
1872 Some(target) => TargetTriple::TargetTriple(target),
1873 _ => TargetTriple::from_triple(host_triple()),
1878 matches: &getopts::Matches,
1879 cg: &CodegenOptions,
1880 error_format: ErrorOutputType,
1882 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1883 // to use them interchangeably. However, because they're technically different flags,
1884 // we need to work out manually which should take precedence if both are supplied (i.e.
1885 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1886 // comparing them. Note that if a flag is not found, its position will be `None`, which
1887 // always compared less than `Some(_)`.
1888 let max_o = matches.opt_positions("O").into_iter().max();
1892 .flat_map(|(i, s)| {
1893 // NB: This can match a string without `=`.
1894 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
1900 match cg.opt_level.as_ref() {
1901 "0" => OptLevel::No,
1902 "1" => OptLevel::Less,
1903 "2" => OptLevel::Default,
1904 "3" => OptLevel::Aggressive,
1905 "s" => OptLevel::Size,
1906 "z" => OptLevel::SizeMin,
1911 "optimization level needs to be \
1912 between 0-3, s or z (instead was `{arg}`)"
1920 fn select_debuginfo(
1921 matches: &getopts::Matches,
1922 cg: &CodegenOptions,
1923 error_format: ErrorOutputType,
1925 let max_g = matches.opt_positions("g").into_iter().max();
1929 .flat_map(|(i, s)| {
1930 // NB: This can match a string without `=`.
1931 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
1937 match cg.debuginfo {
1938 0 => DebugInfo::None,
1939 1 => DebugInfo::Limited,
1940 2 => DebugInfo::Full,
1945 "debug info level needs to be between \
1946 0-2 (instead was `{arg}`)"
1954 pub(crate) fn parse_assert_incr_state(
1955 opt_assertion: &Option<String>,
1956 error_format: ErrorOutputType,
1957 ) -> Option<IncrementalStateAssertion> {
1958 match opt_assertion {
1959 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1960 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1962 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1968 fn parse_native_lib_kind(
1969 matches: &getopts::Matches,
1971 error_format: ErrorOutputType,
1972 ) -> (NativeLibKind, Option<bool>) {
1973 let (kind, modifiers) = match kind.split_once(':') {
1974 None => (kind, None),
1975 Some((kind, modifiers)) => (kind, Some(modifiers)),
1978 let kind = match kind {
1979 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1980 "dylib" => NativeLibKind::Dylib { as_needed: None },
1981 "framework" => NativeLibKind::Framework { as_needed: None },
1983 if !nightly_options::is_unstable_enabled(matches) {
1984 let why = if nightly_options::match_is_nightly_build(matches) {
1985 " and only accepted on the nightly compiler"
1987 ", the `-Z unstable-options` flag must also be passed to use it"
1989 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
1991 NativeLibKind::LinkArg
1996 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
2001 None => (kind, None),
2002 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
2006 fn parse_native_lib_modifiers(
2007 mut kind: NativeLibKind,
2009 error_format: ErrorOutputType,
2010 matches: &getopts::Matches,
2011 ) -> (NativeLibKind, Option<bool>) {
2012 let mut verbatim = None;
2013 for modifier in modifiers.split(',') {
2014 let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
2015 Some(m) => (m, modifier.starts_with('+')),
2016 None => early_error(
2018 "invalid linking modifier syntax, expected '+' or '-' prefix \
2019 before one of: bundle, verbatim, whole-archive, as-needed",
2023 let report_unstable_modifier = || {
2024 if !nightly_options::is_unstable_enabled(matches) {
2025 let why = if nightly_options::match_is_nightly_build(matches) {
2026 " and only accepted on the nightly compiler"
2028 ", the `-Z unstable-options` flag must also be passed to use it"
2032 &format!("linking modifier `{modifier}` is unstable{why}"),
2036 let assign_modifier = |dst: &mut Option<bool>| {
2038 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2039 early_error(error_format, &msg)
2044 match (modifier, &mut kind) {
2045 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2046 ("bundle", _) => early_error(
2048 "linking modifier `bundle` is only compatible with `static` linking kind",
2051 ("verbatim", _) => assign_modifier(&mut verbatim),
2053 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2054 assign_modifier(whole_archive)
2056 ("whole-archive", _) => early_error(
2058 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2061 ("as-needed", NativeLibKind::Dylib { as_needed })
2062 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2063 report_unstable_modifier();
2064 assign_modifier(as_needed)
2066 ("as-needed", _) => early_error(
2068 "linking modifier `as-needed` is only compatible with \
2069 `dylib` and `framework` linking kinds",
2072 // Note: this error also excludes the case with empty modifier
2073 // string, like `modifiers = ""`.
2077 "unknown linking modifier `{modifier}`, expected one \
2078 of: bundle, verbatim, whole-archive, as-needed"
2087 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2092 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2093 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2094 // where MODIFIERS are a comma separated list of supported modifiers
2095 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2096 // with either + or - to indicate whether it is enabled or disabled.
2097 // The last value specified for a given modifier wins.
2098 let (name, kind, verbatim) = match s.split_once('=') {
2099 None => (s, NativeLibKind::Unspecified, None),
2100 Some((kind, name)) => {
2101 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2102 (name.to_string(), kind, verbatim)
2106 let (name, new_name) = match name.split_once(':') {
2107 None => (name, None),
2108 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2110 if name.is_empty() {
2111 early_error(error_format, "library name must not be empty");
2113 NativeLib { name, new_name, kind, verbatim }
2118 pub fn parse_externs(
2119 matches: &getopts::Matches,
2120 unstable_opts: &UnstableOptions,
2121 error_format: ErrorOutputType,
2123 let is_unstable_enabled = unstable_opts.unstable_options;
2124 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2125 for arg in matches.opt_strs("extern") {
2126 let (name, path) = match arg.split_once('=') {
2127 None => (arg, None),
2128 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2130 let (options, name) = match name.split_once(':') {
2131 None => (None, name),
2132 Some((opts, name)) => (Some(opts), name.to_string()),
2135 let path = path.map(|p| CanonicalizedPath::new(p));
2137 let entry = externs.entry(name.to_owned());
2139 use std::collections::btree_map::Entry;
2141 let entry = if let Some(path) = path {
2142 // --extern prelude_name=some_file.rlib
2144 Entry::Vacant(vacant) => {
2145 let files = BTreeSet::from_iter(iter::once(path));
2146 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2148 Entry::Occupied(occupied) => {
2149 let ext_ent = occupied.into_mut();
2151 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2155 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2158 // Exact paths take precedence over search directories.
2159 let files = BTreeSet::from_iter(iter::once(path));
2160 *location = ExternLocation::ExactPaths(files);
2167 // --extern prelude_name
2169 Entry::Vacant(vacant) => {
2170 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2172 Entry::Occupied(occupied) => {
2173 // Ignore if already specified.
2179 let mut is_private_dep = false;
2180 let mut add_prelude = true;
2181 let mut nounused_dep = false;
2182 if let Some(opts) = options {
2183 if !is_unstable_enabled {
2186 "the `-Z unstable-options` flag must also be passed to \
2187 enable `--extern options",
2190 for opt in opts.split(',') {
2192 "priv" => is_private_dep = true,
2194 if let ExternLocation::ExactPaths(_) = &entry.location {
2195 add_prelude = false;
2199 "the `noprelude` --extern option requires a file path",
2203 "nounused" => nounused_dep = true,
2204 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2209 // Crates start out being not private, and go to being private `priv`
2211 entry.is_private_dep |= is_private_dep;
2212 // likewise `nounused`
2213 entry.nounused_dep |= nounused_dep;
2214 // If any flag is missing `noprelude`, then add to the prelude.
2215 entry.add_prelude |= add_prelude;
2220 fn parse_remap_path_prefix(
2221 matches: &getopts::Matches,
2222 unstable_opts: &UnstableOptions,
2223 error_format: ErrorOutputType,
2224 ) -> Vec<(PathBuf, PathBuf)> {
2225 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2226 .opt_strs("remap-path-prefix")
2228 .map(|remap| match remap.rsplit_once('=') {
2229 None => early_error(
2231 "--remap-path-prefix must contain '=' between FROM and TO",
2233 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2236 match &unstable_opts.remap_cwd_prefix {
2237 Some(to) => match std::env::current_dir() {
2238 Ok(cwd) => mapping.push((cwd, to.clone())),
2246 // JUSTIFICATION: before wrapper fn is available
2247 #[allow(rustc::bad_opt_access)]
2248 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2249 let color = parse_color(matches);
2251 let edition = parse_crate_edition(matches);
2255 json_artifact_notifications,
2256 json_unused_externs,
2257 json_future_incompat,
2258 } = parse_json(matches);
2260 let error_format = parse_error_format(matches, color, json_rendered);
2262 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2263 early_error(error_format, "`--diagnostic-width` must be an positive integer");
2266 let unparsed_crate_types = matches.opt_strs("crate-type");
2267 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2268 .unwrap_or_else(|e| early_error(error_format, &e));
2270 let mut unstable_opts = UnstableOptions::build(matches, error_format);
2271 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2273 check_error_format_stability(&unstable_opts, error_format, json_rendered);
2275 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2278 "the `-Z unstable-options` flag must also be passed to enable \
2279 the flag `--json=unused-externs`",
2283 let output_types = parse_output_types(&unstable_opts, matches, error_format);
2285 let mut cg = CodegenOptions::build(matches, error_format);
2286 let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2293 check_thread_count(&unstable_opts, error_format);
2295 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2297 let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
2299 if unstable_opts.profile && incremental.is_some() {
2302 "can't instrument with gcov profiling when compiling incrementally",
2305 if unstable_opts.profile {
2306 match codegen_units {
2308 None => codegen_units = Some(1),
2309 Some(_) => early_error(
2311 "can't instrument with gcov profiling with multiple codegen units",
2316 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2319 "options `-C profile-generate` and `-C profile-use` are exclusive",
2323 if unstable_opts.profile_sample_use.is_some()
2324 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2328 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2332 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2334 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2335 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2338 "incompatible values passed for `-C symbol-mangling-version` \
2339 and `-Z symbol-mangling-version`",
2342 (Some(SymbolManglingVersion::V0), _) => {}
2343 (Some(_), _) if !unstable_opts.unstable_options => {
2346 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2353 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2355 cg.symbol_mangling_version = smv;
2360 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2362 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2363 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2366 "incompatible values passed for `-C instrument-coverage` \
2367 and `-Z instrument-coverage`",
2370 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2371 (Some(_), _) if !unstable_opts.unstable_options => {
2374 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2381 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2383 cg.instrument_coverage = ic;
2388 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2389 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2392 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2393 or `-C profile-generate`",
2397 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2398 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2399 // multiple runs, including some changes to source code; so mangled names must be consistent
2400 // across compilations.
2401 match cg.symbol_mangling_version {
2402 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2403 Some(SymbolManglingVersion::Legacy) => {
2406 "-C instrument-coverage requires symbol mangling version `v0`, \
2407 but `-C symbol-mangling-version=legacy` was specified",
2410 Some(SymbolManglingVersion::V0) => {}
2414 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2415 unstable_opts.graphviz_font = graphviz_font;
2418 if !cg.embed_bitcode {
2420 LtoCli::No | LtoCli::Unspecified => {}
2421 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2423 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2428 let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
2432 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2433 let target_triple = parse_target_triple(matches, error_format);
2434 let opt_level = parse_opt_level(matches, &cg, error_format);
2435 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2436 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2437 // for more details.
2438 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2439 let debuginfo = select_debuginfo(matches, &cg, error_format);
2441 let mut search_paths = vec![];
2442 for s in &matches.opt_strs("L") {
2443 search_paths.push(SearchPath::from_cli_opt(s, error_format));
2446 let libs = parse_libs(matches, error_format);
2448 let test = matches.opt_present("test");
2450 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2451 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2454 let externs = parse_externs(matches, &unstable_opts, error_format);
2456 let crate_name = matches.opt_str("crate-name");
2458 let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
2460 let pretty = parse_pretty(&unstable_opts, error_format);
2462 // Try to find a directory containing the Rust `src`, for more details see
2463 // the doc comment on the `real_rust_source_base_dir` field.
2465 let sysroot = match &sysroot_opt {
2468 tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
2472 let real_rust_source_base_dir = {
2473 // This is the location used by the `rust-src` `rustup` component.
2474 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2475 if let Ok(metadata) = candidate.symlink_metadata() {
2476 // Replace the symlink rustbuild creates, with its destination.
2477 // We could try to use `fs::canonicalize` instead, but that might
2478 // produce unnecessarily verbose path.
2479 if metadata.file_type().is_symlink() {
2480 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2481 candidate = symlink_dest;
2486 // Only use this directory if it has a file we can expect to always find.
2487 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2490 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2491 early_error(error_format, &format!("Current directory is invalid: {e}"));
2494 let (path, remapped) =
2495 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2496 let working_dir = if remapped {
2497 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2499 RealFileName::LocalPath(path)
2505 optimize: opt_level,
2512 maybe_sysroot: sysroot_opt,
2522 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2526 actually_rustdoc: false,
2527 trimmed_def_paths: TrimmedDefPaths::default(),
2528 cli_forced_codegen_units: codegen_units,
2529 cli_forced_local_thinlto_off: disable_local_thinlto,
2531 real_rust_source_base_dir,
2533 json_artifact_notifications,
2534 json_unused_externs,
2535 json_future_incompat,
2541 fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2544 let first = match unstable_opts.unpretty.as_deref()? {
2545 "normal" => Source(PpSourceMode::Normal),
2546 "identified" => Source(PpSourceMode::Identified),
2547 "expanded" => Source(PpSourceMode::Expanded),
2548 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2549 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2550 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2551 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2552 "hir" => Hir(PpHirMode::Normal),
2553 "hir,identified" => Hir(PpHirMode::Identified),
2554 "hir,typed" => Hir(PpHirMode::Typed),
2555 "hir-tree" => HirTree,
2556 "thir-tree" => ThirTree,
2558 "mir-cfg" => MirCFG,
2559 name => early_error(
2562 "argument to `unpretty` must be one of `normal`, `identified`, \
2563 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2564 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2565 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2569 debug!("got unpretty option: {first:?}");
2573 pub fn make_crate_type_option() -> RustcOptGroup {
2577 "Comma separated list of types of crates
2578 for the compiler to emit",
2579 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2583 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2584 let mut crate_types: Vec<CrateType> = Vec::new();
2585 for unparsed_crate_type in &list_list {
2586 for part in unparsed_crate_type.split(',') {
2587 let new_part = match part {
2588 "lib" => default_lib_output(),
2589 "rlib" => CrateType::Rlib,
2590 "staticlib" => CrateType::Staticlib,
2591 "dylib" => CrateType::Dylib,
2592 "cdylib" => CrateType::Cdylib,
2593 "bin" => CrateType::Executable,
2594 "proc-macro" => CrateType::ProcMacro,
2595 _ => return Err(format!("unknown crate type: `{part}`")),
2597 if !crate_types.contains(&new_part) {
2598 crate_types.push(new_part)
2606 pub mod nightly_options {
2607 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2608 use crate::early_error;
2609 use rustc_feature::UnstableFeatures;
2611 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2612 match_is_nightly_build(matches)
2613 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2616 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2617 is_nightly_build(matches.opt_str("crate-name").as_deref())
2620 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2621 UnstableFeatures::from_environment(krate).is_nightly_build()
2624 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2625 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2626 let really_allows_unstable_options = match_is_nightly_build(matches);
2628 for opt in flags.iter() {
2629 if opt.stability == OptionStability::Stable {
2632 if !matches.opt_present(opt.name) {
2635 if opt.name != "Z" && !has_z_unstable_option {
2637 ErrorOutputType::default(),
2639 "the `-Z unstable-options` flag must also be passed to enable \
2645 if really_allows_unstable_options {
2648 match opt.stability {
2649 OptionStability::Unstable => {
2651 "the option `{}` is only accepted on the \
2655 early_error(ErrorOutputType::default(), &msg);
2657 OptionStability::Stable => {}
2663 impl fmt::Display for CrateType {
2664 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2666 CrateType::Executable => "bin".fmt(f),
2667 CrateType::Dylib => "dylib".fmt(f),
2668 CrateType::Rlib => "rlib".fmt(f),
2669 CrateType::Staticlib => "staticlib".fmt(f),
2670 CrateType::Cdylib => "cdylib".fmt(f),
2671 CrateType::ProcMacro => "proc-macro".fmt(f),
2676 #[derive(Copy, Clone, PartialEq, Debug)]
2677 pub enum PpSourceMode {
2678 /// `-Zunpretty=normal`
2680 /// `-Zunpretty=expanded`
2682 /// `-Zunpretty=identified`
2684 /// `-Zunpretty=expanded,identified`
2686 /// `-Zunpretty=expanded,hygiene`
2690 #[derive(Copy, Clone, PartialEq, Debug)]
2691 pub enum PpAstTreeMode {
2692 /// `-Zunpretty=ast`
2694 /// `-Zunpretty=ast,expanded`
2698 #[derive(Copy, Clone, PartialEq, Debug)]
2699 pub enum PpHirMode {
2700 /// `-Zunpretty=hir`
2702 /// `-Zunpretty=hir,identified`
2704 /// `-Zunpretty=hir,typed`
2708 #[derive(Copy, Clone, PartialEq, Debug)]
2710 /// Options that print the source code, i.e.
2711 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2712 Source(PpSourceMode),
2713 AstTree(PpAstTreeMode),
2714 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2716 /// `-Zunpretty=hir-tree`
2718 /// `-Zunpretty=thir-tree`
2720 /// `-Zunpretty=mir`
2722 /// `-Zunpretty=mir-cfg`
2727 pub fn needs_ast_map(&self) -> bool {
2729 use PpSourceMode::*;
2731 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2733 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2734 | AstTree(PpAstTreeMode::Expanded)
2742 pub fn needs_hir(&self) -> bool {
2745 Source(_) | AstTree(_) => false,
2747 Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
2751 pub fn needs_analysis(&self) -> bool {
2753 matches!(*self, Mir | MirCFG | ThirTree)
2757 /// Command-line arguments passed to the compiler have to be incorporated with
2758 /// the dependency tracking system for incremental compilation. This module
2759 /// provides some utilities to make this more convenient.
2761 /// The values of all command-line arguments that are relevant for dependency
2762 /// tracking are hashed into a single value that determines whether the
2763 /// incremental compilation cache can be re-used or not. This hashing is done
2764 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2765 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2766 /// the hash of which is order dependent, but we might not want the order of
2767 /// arguments to make a difference for the hash).
2769 /// However, since the value provided by `Hash::hash` often *is* suitable,
2770 /// especially for primitive types, there is the
2771 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2772 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2773 /// we have an opt-in scheme here, so one is hopefully forced to think about
2774 /// how the hash should be calculated when adding a new command-line argument.
2775 pub(crate) mod dep_tracking {
2777 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2778 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2779 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
2780 SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
2783 use crate::options::WasiExecModel;
2784 use crate::utils::{NativeLib, NativeLibKind};
2785 use rustc_errors::LanguageIdentifier;
2786 use rustc_feature::UnstableFeatures;
2787 use rustc_span::edition::Edition;
2788 use rustc_span::RealFileName;
2789 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2790 use rustc_target::spec::{
2791 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2793 use std::collections::hash_map::DefaultHasher;
2794 use std::collections::BTreeMap;
2795 use std::hash::Hash;
2796 use std::num::NonZeroUsize;
2797 use std::path::PathBuf;
2799 pub trait DepTrackingHash {
2802 hasher: &mut DefaultHasher,
2803 error_format: ErrorOutputType,
2804 for_crate_hash: bool,
2808 macro_rules! impl_dep_tracking_hash_via_hash {
2809 ($($t:ty),+ $(,)?) => {$(
2810 impl DepTrackingHash for $t {
2811 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2812 Hash::hash(self, hasher);
2818 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2821 hasher: &mut DefaultHasher,
2822 error_format: ErrorOutputType,
2823 for_crate_hash: bool,
2827 Hash::hash(&1, hasher);
2828 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2830 None => Hash::hash(&0, hasher),
2835 impl_dep_tracking_hash_via_hash!(
2870 SymbolManglingVersion,
2871 SourceFileHashAlgorithm,
2883 impl<T1, T2> DepTrackingHash for (T1, T2)
2885 T1: DepTrackingHash,
2886 T2: DepTrackingHash,
2890 hasher: &mut DefaultHasher,
2891 error_format: ErrorOutputType,
2892 for_crate_hash: bool,
2894 Hash::hash(&0, hasher);
2895 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2896 Hash::hash(&1, hasher);
2897 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2901 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2903 T1: DepTrackingHash,
2904 T2: DepTrackingHash,
2905 T3: DepTrackingHash,
2909 hasher: &mut DefaultHasher,
2910 error_format: ErrorOutputType,
2911 for_crate_hash: bool,
2913 Hash::hash(&0, hasher);
2914 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2915 Hash::hash(&1, hasher);
2916 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2917 Hash::hash(&2, hasher);
2918 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2922 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2925 hasher: &mut DefaultHasher,
2926 error_format: ErrorOutputType,
2927 for_crate_hash: bool,
2929 Hash::hash(&self.len(), hasher);
2930 for (index, elem) in self.iter().enumerate() {
2931 Hash::hash(&index, hasher);
2932 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2937 impl DepTrackingHash for OutputTypes {
2940 hasher: &mut DefaultHasher,
2941 error_format: ErrorOutputType,
2942 for_crate_hash: bool,
2944 Hash::hash(&self.0.len(), hasher);
2945 for (key, val) in &self.0 {
2946 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2947 if !for_crate_hash {
2948 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2954 // This is a stable hash because BTreeMap is a sorted container
2955 pub(crate) fn stable_hash(
2956 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2957 hasher: &mut DefaultHasher,
2958 error_format: ErrorOutputType,
2959 for_crate_hash: bool,
2961 for (key, sub_hash) in sub_hashes {
2962 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2963 // the keys, as they are just plain strings
2964 Hash::hash(&key.len(), hasher);
2965 Hash::hash(key, hasher);
2966 sub_hash.hash(hasher, error_format, for_crate_hash);
2971 /// Default behavior to use in out-of-memory situations.
2972 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2973 pub enum OomStrategy {
2974 /// Generate a panic that can be caught by `catch_unwind`.
2977 /// Abort the process immediately.
2982 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2984 pub fn should_panic(self) -> u8 {
2986 OomStrategy::Panic => 1,
2987 OomStrategy::Abort => 0,
2992 /// How to run proc-macro code when building this crate
2993 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
2994 pub enum ProcMacroExecutionStrategy {
2995 /// Run the proc-macro code on the same thread as the server.
2998 /// Run the proc-macro code on a different thread.
3002 /// Which format to use for `-Z dump-mono-stats`
3003 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
3004 pub enum DumpMonoStatsFormat {
3005 /// Pretty-print a markdown table
3007 /// Emit structured JSON
3011 impl DumpMonoStatsFormat {
3012 pub fn extension(self) -> &'static str {
3014 Self::Markdown => "md",
3015 Self::Json => "json",