1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
7 use crate::search_paths::SearchPath;
8 use crate::utils::{CanonicalizedPath, NativeLibKind};
9 use crate::{early_error, early_warn, Session};
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
13 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
15 use rustc_target::abi::{Align, TargetDataLayout};
16 use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
18 use rustc_serialize::json;
20 use crate::parse::CrateConfig;
21 use rustc_feature::UnstableFeatures;
22 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
23 use rustc_span::source_map::{FileName, FilePathMapping};
24 use rustc_span::symbol::{sym, Symbol};
25 use rustc_span::SourceFileHashAlgorithm;
27 use rustc_errors::emitter::HumanReadableErrorType;
28 use rustc_errors::{ColorConfig, HandlerFlags};
30 use std::collections::btree_map::{
31 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
33 use std::collections::{BTreeMap, BTreeSet};
35 use std::iter::{self, FromIterator};
36 use std::path::{Path, PathBuf};
37 use std::str::{self, FromStr};
40 #[derive(Default, Encodable, Decodable)]
41 pub struct SanitizerSet: u8 {
42 const ADDRESS = 1 << 0;
44 const MEMORY = 1 << 2;
45 const THREAD = 1 << 3;
46 const HWADDRESS = 1 << 4;
50 /// Formats a sanitizer set as a comma separated list of sanitizers' names.
51 impl fmt::Display for SanitizerSet {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 SanitizerSet::ADDRESS => "address",
57 SanitizerSet::LEAK => "leak",
58 SanitizerSet::MEMORY => "memory",
59 SanitizerSet::THREAD => "thread",
60 SanitizerSet::HWADDRESS => "hwaddress",
61 _ => panic!("unrecognized sanitizer {:?}", s),
73 impl IntoIterator for SanitizerSet {
74 type Item = SanitizerSet;
75 type IntoIter = std::vec::IntoIter<SanitizerSet>;
77 fn into_iter(self) -> Self::IntoIter {
79 SanitizerSet::ADDRESS,
83 SanitizerSet::HWADDRESS,
87 .filter(|&s| self.contains(s))
93 impl<CTX> HashStable<CTX> for SanitizerSet {
94 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
95 self.bits().hash_stable(ctx, hasher);
99 /// The different settings that the `-Z strip` flag can have.
100 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
102 /// Do not strip at all.
108 /// Strip all symbols.
112 /// The different settings that the `-C control-flow-guard` flag can have.
113 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
115 /// Do not emit Control Flow Guard metadata or checks.
118 /// Emit Control Flow Guard metadata but no checks.
121 /// Emit Control Flow Guard metadata and checks.
125 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
135 impl_stable_hash_via_hash!(OptLevel);
137 /// This is what the `LtoCli` values get mapped to after resolving defaults and
138 /// and taking other command line options into account.
139 #[derive(Clone, PartialEq)]
141 /// Don't do any LTO whatsoever
144 /// Do a full crate graph LTO with ThinLTO
147 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
151 /// Do a full crate graph LTO with "fat" LTO
155 /// The different settings that the `-C lto` flag can have.
156 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
168 /// No `-C lto` flag passed
172 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
173 /// document highlighting each span of every statement (including terminators). `Terminator` and
174 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
175 /// computed span for the block, representing the entire range, covering the block's terminator and
176 /// all of its statements.
177 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
178 pub enum MirSpanview {
179 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
181 /// `-Z dump_mir_spanview=terminator`
183 /// `-Z dump_mir_spanview=block`
187 /// The different settings that the `-Z instrument-coverage` flag can have.
189 /// Coverage instrumentation now supports combining `-Z instrument-coverage`
190 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
191 /// and higher). Nevertheless, there are many variables, depending on options
192 /// selected, code structure, and enabled attributes. If errors are encountered,
193 /// either while compiling or when generating `llvm-cov show` reports, consider
194 /// lowering the optimization level, including or excluding `-C link-dead-code`,
195 /// or using `-Z instrument-coverage=except-unused-functions` or `-Z
196 /// instrument-coverage=except-unused-generics`.
198 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
199 /// coverage map, it will not attempt to generate synthetic functions for unused
200 /// (and not code-generated) functions (whether they are generic or not). As a
201 /// result, non-codegenned functions will not be included in the coverage map,
202 /// and will not appear, as covered or uncovered, in coverage reports.
204 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
205 /// unless the function has type parameters.
206 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
207 pub enum InstrumentCoverage {
208 /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
210 /// `-Z instrument-coverage=except-unused-generics`
211 ExceptUnusedGenerics,
212 /// `-Z instrument-coverage=except-unused-functions`
213 ExceptUnusedFunctions,
214 /// `-Z instrument-coverage=off` (or `no`, etc.)
218 #[derive(Clone, PartialEq, Hash)]
219 pub enum LinkerPluginLto {
220 LinkerPlugin(PathBuf),
225 impl LinkerPluginLto {
226 pub fn enabled(&self) -> bool {
228 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
229 LinkerPluginLto::Disabled => false,
234 #[derive(Clone, PartialEq, Hash)]
235 pub enum SwitchWithOptPath {
236 Enabled(Option<PathBuf>),
240 impl SwitchWithOptPath {
241 pub fn enabled(&self) -> bool {
243 SwitchWithOptPath::Enabled(_) => true,
244 SwitchWithOptPath::Disabled => false,
249 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
250 #[derive(Encodable, Decodable)]
251 pub enum SymbolManglingVersion {
256 impl_stable_hash_via_hash!(SymbolManglingVersion);
258 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
265 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
266 #[derive(Encodable, Decodable)]
267 pub enum OutputType {
278 impl_stable_hash_via_hash!(OutputType);
281 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
283 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
285 | OutputType::Assembly
286 | OutputType::LlvmAssembly
288 | OutputType::Object => false,
292 fn shorthand(&self) -> &'static str {
294 OutputType::Bitcode => "llvm-bc",
295 OutputType::Assembly => "asm",
296 OutputType::LlvmAssembly => "llvm-ir",
297 OutputType::Mir => "mir",
298 OutputType::Object => "obj",
299 OutputType::Metadata => "metadata",
300 OutputType::Exe => "link",
301 OutputType::DepInfo => "dep-info",
305 fn from_shorthand(shorthand: &str) -> Option<Self> {
306 Some(match shorthand {
307 "asm" => OutputType::Assembly,
308 "llvm-ir" => OutputType::LlvmAssembly,
309 "mir" => OutputType::Mir,
310 "llvm-bc" => OutputType::Bitcode,
311 "obj" => OutputType::Object,
312 "metadata" => OutputType::Metadata,
313 "link" => OutputType::Exe,
314 "dep-info" => OutputType::DepInfo,
319 fn shorthands_display() -> String {
321 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
322 OutputType::Bitcode.shorthand(),
323 OutputType::Assembly.shorthand(),
324 OutputType::LlvmAssembly.shorthand(),
325 OutputType::Mir.shorthand(),
326 OutputType::Object.shorthand(),
327 OutputType::Metadata.shorthand(),
328 OutputType::Exe.shorthand(),
329 OutputType::DepInfo.shorthand(),
333 pub fn extension(&self) -> &'static str {
335 OutputType::Bitcode => "bc",
336 OutputType::Assembly => "s",
337 OutputType::LlvmAssembly => "ll",
338 OutputType::Mir => "mir",
339 OutputType::Object => "o",
340 OutputType::Metadata => "rmeta",
341 OutputType::DepInfo => "d",
342 OutputType::Exe => "",
347 /// The type of diagnostics output to generate.
348 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
349 pub enum ErrorOutputType {
350 /// Output meant for the consumption of humans.
351 HumanReadable(HumanReadableErrorType),
352 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
354 /// Render the JSON in a human readable way (with indents and newlines).
356 /// The JSON output includes a `rendered` field that includes the rendered
358 json_rendered: HumanReadableErrorType,
362 impl Default for ErrorOutputType {
363 fn default() -> Self {
364 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
368 /// Parameter to control path trimming.
369 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
370 pub enum TrimmedDefPaths {
371 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
373 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
375 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
379 impl Default for TrimmedDefPaths {
380 fn default() -> Self {
385 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
386 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
387 /// dependency tracking for command-line arguments.
388 #[derive(Clone, Hash, Debug)]
389 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
391 impl_stable_hash_via_hash!(OutputTypes);
394 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
395 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
398 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
402 pub fn contains_key(&self, key: &OutputType) -> bool {
403 self.0.contains_key(key)
406 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
410 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
414 pub fn len(&self) -> usize {
418 // Returns `true` if any of the output types require codegen or linking.
419 pub fn should_codegen(&self) -> bool {
420 self.0.keys().any(|k| match *k {
422 | OutputType::Assembly
423 | OutputType::LlvmAssembly
426 | OutputType::Exe => true,
427 OutputType::Metadata | OutputType::DepInfo => false,
431 // Returns `true` if any of the output types require linking.
432 pub fn should_link(&self) -> bool {
433 self.0.keys().any(|k| match *k {
435 | OutputType::Assembly
436 | OutputType::LlvmAssembly
438 | OutputType::Metadata
440 | OutputType::DepInfo => false,
441 OutputType::Exe => true,
446 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
447 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
448 /// would break dependency tracking for command-line arguments.
450 pub struct Externs(BTreeMap<String, ExternEntry>);
453 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
455 #[derive(Clone, Debug)]
456 pub struct ExternEntry {
457 pub location: ExternLocation,
458 /// Indicates this is a "private" dependency for the
459 /// `exported_private_dependencies` lint.
461 /// This can be set with the `priv` option like
462 /// `--extern priv:name=foo.rlib`.
463 pub is_private_dep: bool,
464 /// Add the extern entry to the extern prelude.
466 /// This can be disabled with the `noprelude` option like
467 /// `--extern noprelude:name`.
468 pub add_prelude: bool,
471 #[derive(Clone, Debug)]
472 pub enum ExternLocation {
473 /// Indicates to look for the library in the search paths.
475 /// Added via `--extern name`.
476 FoundInLibrarySearchDirectories,
477 /// The locations where this extern entry must be found.
479 /// The `CrateLoader` is responsible for loading these and figuring out
480 /// which one to use.
482 /// Added via `--extern prelude_name=some_file.rlib`
483 ExactPaths(BTreeSet<CanonicalizedPath>),
486 /// Supplied source location of a dependency - for example in a build specification
487 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
488 /// a file and line, then the build system can specify that. On the other hand, it may
489 /// make more sense to have an arbitrary raw string.
490 #[derive(Clone, PartialEq)]
491 pub enum ExternDepSpec {
494 /// Raw data in json format
498 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
499 fn from(from: &'a ExternDepSpec) -> Self {
501 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
502 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
508 /// Used for testing.
509 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
513 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
517 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
523 fn new(location: ExternLocation) -> ExternEntry {
524 ExternEntry { location, is_private_dep: false, add_prelude: false }
527 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
528 match &self.location {
529 ExternLocation::ExactPaths(set) => Some(set.iter()),
535 impl ExternDepSpecs {
536 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
540 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
545 impl fmt::Display for ExternDepSpec {
546 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
548 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
549 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
554 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
555 pub enum PrintRequest {
571 #[derive(Copy, Clone)]
572 pub enum BorrowckMode {
578 /// Returns whether we should run the MIR-based borrow check, but also fall back
579 /// on the AST borrow check if the MIR-based one errors.
580 pub fn migrate(self) -> bool {
582 BorrowckMode::Mir => false,
583 BorrowckMode::Migrate => true,
589 /// Load source code from a file.
591 /// Load source code from a string.
593 /// A string that is shown in place of a filename.
595 /// An anonymous string containing the source code.
601 pub fn filestem(&self) -> &str {
603 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
604 Input::Str { .. } => "rust_out",
608 pub fn source_name(&self) -> FileName {
610 Input::File(ref ifile) => ifile.clone().into(),
611 Input::Str { ref name, .. } => name.clone(),
616 #[derive(Clone, Hash, Debug)]
617 pub struct OutputFilenames {
618 pub out_directory: PathBuf,
620 pub single_output_file: Option<PathBuf>,
621 pub outputs: OutputTypes,
624 impl_stable_hash_via_hash!(OutputFilenames);
626 pub const RLINK_EXT: &str = "rlink";
627 pub const RUST_CGU_EXT: &str = "rcgu";
628 pub const DWARF_OBJECT_EXT: &str = "dwo";
630 impl OutputFilenames {
632 out_directory: PathBuf,
633 out_filestem: String,
634 single_output_file: Option<PathBuf>,
636 outputs: OutputTypes,
642 filestem: format!("{}{}", out_filestem, extra),
646 pub fn path(&self, flavor: OutputType) -> PathBuf {
649 .and_then(|p| p.to_owned())
650 .or_else(|| self.single_output_file.clone())
651 .unwrap_or_else(|| self.temp_path(flavor, None))
654 /// Gets the path where a compilation artifact of the given type for the
655 /// given codegen unit should be placed on disk. If codegen_unit_name is
656 /// None, a path distinct from those of any codegen unit will be generated.
657 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
658 let extension = flavor.extension();
659 self.temp_path_ext(extension, codegen_unit_name)
662 /// Like `temp_path`, but specifically for dwarf objects.
663 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
664 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
667 /// Like `temp_path`, but also supports things where there is no corresponding
668 /// OutputType, like noopt-bitcode or lto-bitcode.
669 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
670 let mut extension = String::new();
672 if let Some(codegen_unit_name) = codegen_unit_name {
673 extension.push_str(codegen_unit_name);
677 if !extension.is_empty() {
679 extension.push_str(RUST_CGU_EXT);
683 extension.push_str(ext);
686 self.with_extension(&extension)
689 pub fn with_extension(&self, extension: &str) -> PathBuf {
690 let mut path = self.out_directory.join(&self.filestem);
691 path.set_extension(extension);
695 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
696 /// mode is being used, which is the logic that this function is intended to encapsulate.
697 pub fn split_dwarf_path(
699 split_debuginfo_kind: SplitDebuginfo,
700 cgu_name: Option<&str>,
701 ) -> Option<PathBuf> {
702 let obj_out = self.temp_path(OutputType::Object, cgu_name);
703 let dwo_out = self.temp_path_dwo(cgu_name);
704 match split_debuginfo_kind {
705 SplitDebuginfo::Off => None,
706 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
707 // (pointing at the path which is being determined here). Use the path to the current
709 SplitDebuginfo::Packed => Some(obj_out),
710 // Split mode emits the DWARF into a different file, use that path.
711 SplitDebuginfo::Unpacked => Some(dwo_out),
716 pub fn host_triple() -> &'static str {
717 // Get the host triple out of the build environment. This ensures that our
718 // idea of the host triple is the same as for the set of libraries we've
719 // actually built. We can't just take LLVM's host triple because they
720 // normalize all ix86 architectures to i386.
722 // Instead of grabbing the host triple (for the current host), we grab (at
723 // compile time) the target triple that this rustc is built with and
724 // calling that (at runtime) the host triple.
725 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
728 impl Default for Options {
729 fn default() -> Options {
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 debugging_opts: basic_debugging_options(),
745 borrowck_mode: BorrowckMode::Migrate,
746 cg: basic_codegen_options(),
747 error_format: ErrorOutputType::default(),
748 externs: Externs(BTreeMap::new()),
749 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
753 unstable_features: UnstableFeatures::Disallow,
754 debug_assertions: true,
755 actually_rustdoc: false,
756 trimmed_def_paths: TrimmedDefPaths::default(),
757 cli_forced_codegen_units: None,
758 cli_forced_thinlto_off: false,
759 remap_path_prefix: Vec::new(),
760 edition: DEFAULT_EDITION,
761 json_artifact_notifications: false,
768 /// Returns `true` if there is a reason to build the dep graph.
769 pub fn build_dep_graph(&self) -> bool {
770 self.incremental.is_some()
771 || self.debugging_opts.dump_dep_graph
772 || self.debugging_opts.query_dep_graph
775 pub fn file_path_mapping(&self) -> FilePathMapping {
776 FilePathMapping::new(self.remap_path_prefix.clone())
779 /// Returns `true` if there will be an output file generated.
780 pub fn will_create_output_file(&self) -> bool {
781 !self.debugging_opts.parse_only && // The file is just being parsed
782 !self.debugging_opts.ls // The file is just being queried
786 pub fn share_generics(&self) -> bool {
787 match self.debugging_opts.share_generics {
788 Some(setting) => setting,
789 None => match self.optimize {
790 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
791 OptLevel::Default | OptLevel::Aggressive => false,
797 impl DebuggingOptions {
798 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
801 treat_err_as_bug: self.treat_err_as_bug,
802 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
803 report_delayed_bugs: self.report_delayed_bugs,
804 macro_backtrace: self.macro_backtrace,
805 deduplicate_diagnostics: self.deduplicate_diagnostics,
809 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
810 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
814 // The type of entry function, so users can have their own entry functions
815 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
816 pub enum EntryFnType {
821 impl_stable_hash_via_hash!(EntryFnType);
823 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
833 impl_stable_hash_via_hash!(CrateType);
835 #[derive(Clone, Hash)]
842 pub fn is_empty(&self) -> bool {
844 Passes::Some(ref v) => v.is_empty(),
845 Passes::All => false,
850 pub const fn default_lib_output() -> CrateType {
854 pub fn default_configuration(sess: &Session) -> CrateConfig {
855 let end = &sess.target.endian;
856 let arch = &sess.target.arch;
857 let wordsz = sess.target.pointer_width.to_string();
858 let os = &sess.target.os;
859 let env = &sess.target.env;
860 let vendor = &sess.target.vendor;
861 let min_atomic_width = sess.target.min_atomic_width();
862 let max_atomic_width = sess.target.max_atomic_width();
863 let atomic_cas = sess.target.atomic_cas;
864 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
868 let mut ret = FxHashSet::default();
869 ret.reserve(6); // the minimum number of insertions
871 ret.insert((sym::target_os, Some(Symbol::intern(os))));
872 if let Some(ref fam) = sess.target.os_family {
873 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
874 if fam == "windows" {
875 ret.insert((sym::windows, None));
876 } else if fam == "unix" {
877 ret.insert((sym::unix, None));
880 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
881 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
882 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
883 ret.insert((sym::target_env, Some(Symbol::intern(env))));
884 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
885 if sess.target.has_elf_tls {
886 ret.insert((sym::target_thread_local, None));
888 for &(i, align) in &[
889 (8, layout.i8_align.abi),
890 (16, layout.i16_align.abi),
891 (32, layout.i32_align.abi),
892 (64, layout.i64_align.abi),
893 (128, layout.i128_align.abi),
895 if i >= min_atomic_width && i <= max_atomic_width {
896 let mut insert_atomic = |s, align: Align| {
897 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
899 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
901 if align.bits() == i {
902 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
905 let s = i.to_string();
906 insert_atomic(&s, align);
908 insert_atomic("ptr", layout.pointer_align.abi);
913 let panic_strategy = sess.panic_strategy();
914 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
916 for s in sess.opts.debugging_opts.sanitizer {
917 let symbol = Symbol::intern(&s.to_string());
918 ret.insert((sym::sanitize, Some(symbol)));
921 if sess.opts.debug_assertions {
922 ret.insert((sym::debug_assertions, None));
924 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
925 ret.insert((sym::proc_macro, None));
930 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
931 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
932 /// but the symbol interner is not yet set up then, so we must convert it later.
933 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
934 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
937 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
938 // Combine the configuration requested by the session (command line) with
939 // some default and generated configuration items.
940 let default_cfg = default_configuration(sess);
941 // If the user wants a test runner, then add the test cfg.
943 user_cfg.insert((sym::test, None));
945 user_cfg.extend(default_cfg.iter().cloned());
949 pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
950 let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
951 let target = target_result.unwrap_or_else(|e| {
955 "Error loading target specification: {}. \
956 Use `--print target-list` for a list of built-in targets",
962 if !matches!(target.pointer_width, 16 | 32 | 64) {
966 "target specification was invalid: \
967 unrecognized target-pointer-width {}",
976 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
977 pub enum OptionStability {
982 pub struct RustcOptGroup {
983 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
984 pub name: &'static str,
985 pub stability: OptionStability,
989 pub fn is_stable(&self) -> bool {
990 self.stability == OptionStability::Stable
993 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
995 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
997 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1000 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1002 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1004 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1008 // The `opt` local module holds wrappers around the `getopts` API that
1009 // adds extra rustc-specific metadata to each option; such metadata
1010 // is exposed by . The public
1011 // functions below ending with `_u` are the functions that return
1012 // *unstable* options, i.e., options that are only enabled when the
1013 // user also passes the `-Z unstable-options` debugging flag.
1015 // The `fn flag*` etc below are written so that we can use them
1016 // in the future; do not warn about them not being used right now.
1017 #![allow(dead_code)]
1019 use super::RustcOptGroup;
1021 pub type R = RustcOptGroup;
1022 pub type S = &'static str;
1024 fn stable<F>(name: S, f: F) -> R
1026 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1028 RustcOptGroup::stable(name, f)
1031 fn unstable<F>(name: S, f: F) -> R
1033 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1035 RustcOptGroup::unstable(name, f)
1038 fn longer(a: S, b: S) -> S {
1039 if a.len() > b.len() { a } else { b }
1042 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1043 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1045 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1046 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1048 pub fn flag_s(a: S, b: S, c: S) -> R {
1049 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1051 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1052 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1055 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1056 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1058 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1059 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1063 /// Returns the "short" subset of the rustc command line options,
1064 /// including metadata for each option, such as whether the option is
1065 /// part of the stable long-term interface for rustc.
1066 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1068 opt::flag_s("h", "help", "Display this message"),
1069 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1073 "Add a directory to the library search path. The
1074 optional KIND can be one of dependency, crate, native,
1075 framework, or all (the default).",
1081 "Link the generated crate(s) to the specified native
1082 library NAME. The optional KIND can be one of
1083 static, framework, or dylib (the default).",
1086 make_crate_type_option(),
1087 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1091 "Specify which edition of the compiler to use when compiling code.",
1097 "Comma separated list of types of output for \
1098 the compiler to emit",
1099 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1104 "Compiler information to print on stdout",
1105 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1106 target-cpus|target-features|relocation-models|\
1107 code-models|tls-models|target-spec-json|native-static-libs]",
1109 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1110 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1111 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1115 "Write output to compiler-chosen filename \
1122 "Provide a detailed explanation of an error \
1126 opt::flag_s("", "test", "Build a test harness"),
1127 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1128 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1129 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1130 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1131 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1135 "Set the most restrictive lint level. \
1136 More restrictive lints are capped at this \
1140 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1141 opt::flag_s("V", "version", "Print version info and exit"),
1142 opt::flag_s("v", "verbose", "Use verbose output"),
1146 /// Returns all rustc command line options, including metadata for
1147 /// each option, such as whether the option is part of the stable
1148 /// long-term interface for rustc.
1149 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1150 let mut opts = rustc_short_optgroups();
1155 "Specify where an external rust library is located",
1161 "Location where an external crate dependency is specified",
1164 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1165 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1169 "How errors and other messages are produced",
1172 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1176 "Configure coloring of output:
1177 auto = colorize, if output goes to a tty (default);
1178 always = always colorize output;
1179 never = never colorize output",
1180 "auto|always|never",
1185 "Pretty-print the input instead of compiling;
1186 valid types are: `normal` (un-annotated source),
1187 `expanded` (crates expanded), or
1188 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1193 "remap-path-prefix",
1194 "Remap source names in all output (compiler messages and output files)",
1201 pub fn get_cmd_lint_options(
1202 matches: &getopts::Matches,
1203 error_format: ErrorOutputType,
1204 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1205 let mut lint_opts_with_position = vec![];
1206 let mut describe_lints = false;
1208 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1209 for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1210 let arg_pos = if let lint::Forbid = level {
1211 // HACK: forbid is always specified last, so it can't be overridden.
1212 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1213 // fixed and `forbid` works as expected.
1218 if lint_name == "help" {
1219 describe_lints = true;
1221 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1226 lint_opts_with_position.sort_by_key(|x| x.0);
1227 let lint_opts = lint_opts_with_position
1230 .map(|(_, lint_name, level)| (lint_name, level))
1233 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1234 lint::Level::from_str(&cap)
1235 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1237 (lint_opts, describe_lints, lint_cap)
1240 /// Parses the `--color` flag.
1241 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1242 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1243 Some("auto") => ColorConfig::Auto,
1244 Some("always") => ColorConfig::Always,
1245 Some("never") => ColorConfig::Never,
1247 None => ColorConfig::Auto,
1249 Some(arg) => early_error(
1250 ErrorOutputType::default(),
1252 "argument for `--color` must be auto, \
1253 always or never (instead was `{}`)",
1260 /// Parse the `--json` flag.
1262 /// The first value returned is how to render JSON diagnostics, and the second
1263 /// is whether or not artifact notifications are enabled.
1264 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1265 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1266 HumanReadableErrorType::Default;
1267 let mut json_color = ColorConfig::Never;
1268 let mut json_artifact_notifications = false;
1269 for option in matches.opt_strs("json") {
1270 // For now conservatively forbid `--color` with `--json` since `--json`
1271 // won't actually be emitting any colors and anything colorized is
1272 // embedded in a diagnostic message anyway.
1273 if matches.opt_str("color").is_some() {
1275 ErrorOutputType::default(),
1276 "cannot specify the `--color` option with `--json`",
1280 for sub_option in option.split(',') {
1282 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1283 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1284 "artifacts" => json_artifact_notifications = true,
1286 ErrorOutputType::default(),
1287 &format!("unknown `--json` option `{}`", s),
1292 (json_rendered(json_color), json_artifact_notifications)
1295 /// Parses the `--error-format` flag.
1296 pub fn parse_error_format(
1297 matches: &getopts::Matches,
1299 json_rendered: HumanReadableErrorType,
1300 ) -> ErrorOutputType {
1301 // We need the `opts_present` check because the driver will send us Matches
1302 // with only stable options if no unstable options are used. Since error-format
1303 // is unstable, it will not be present. We have to use `opts_present` not
1304 // `opt_present` because the latter will panic.
1305 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1306 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1307 None | Some("human") => {
1308 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1310 Some("human-annotate-rs") => {
1311 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1313 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1314 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1315 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1317 Some(arg) => early_error(
1318 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1320 "argument for `--error-format` must be `human`, `json` or \
1321 `short` (instead was `{}`)",
1327 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1330 match error_format {
1331 ErrorOutputType::Json { .. } => {}
1333 // Conservatively require that the `--json` argument is coupled with
1334 // `--error-format=json`. This means that `--json` is specified we
1335 // should actually be emitting JSON blobs.
1336 _ if !matches.opt_strs("json").is_empty() => {
1338 ErrorOutputType::default(),
1339 "using `--json` requires also using `--error-format=json`",
1349 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1350 let edition = match matches.opt_str("edition") {
1351 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1353 ErrorOutputType::default(),
1355 "argument for `--edition` must be one of: \
1356 {}. (instead was `{}`)",
1357 EDITION_NAME_LIST, arg
1361 None => DEFAULT_EDITION,
1364 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1366 ErrorOutputType::default(),
1368 "edition {} is unstable and only available with -Z unstable-options.",
1377 fn check_debug_option_stability(
1378 debugging_opts: &DebuggingOptions,
1379 error_format: ErrorOutputType,
1380 json_rendered: HumanReadableErrorType,
1382 if !debugging_opts.unstable_options {
1383 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1385 ErrorOutputType::Json { pretty: false, json_rendered },
1386 "`--error-format=pretty-json` is unstable",
1389 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1393 ErrorOutputType::Json { pretty: false, json_rendered },
1394 "`--error-format=human-annotate-rs` is unstable",
1400 fn parse_output_types(
1401 debugging_opts: &DebuggingOptions,
1402 matches: &getopts::Matches,
1403 error_format: ErrorOutputType,
1405 let mut output_types = BTreeMap::new();
1406 if !debugging_opts.parse_only {
1407 for list in matches.opt_strs("emit") {
1408 for output_type in list.split(',') {
1409 let (shorthand, path) = match output_type.split_once('=') {
1410 None => (output_type, None),
1411 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1413 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1417 "unknown emission type: `{}` - expected one of: {}",
1419 OutputType::shorthands_display(),
1423 output_types.insert(output_type, path);
1427 if output_types.is_empty() {
1428 output_types.insert(OutputType::Exe, None);
1430 OutputTypes(output_types)
1433 fn should_override_cgus_and_disable_thinlto(
1434 output_types: &OutputTypes,
1435 matches: &getopts::Matches,
1436 error_format: ErrorOutputType,
1437 mut codegen_units: Option<usize>,
1438 ) -> (bool, Option<usize>) {
1439 let mut disable_thinlto = false;
1440 // Issue #30063: if user requests LLVM-related output to one
1441 // particular path, disable codegen-units.
1442 let incompatible: Vec<_> = output_types
1445 .map(|ot_path| ot_path.0)
1446 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1447 .map(|ot| ot.shorthand())
1449 if !incompatible.is_empty() {
1450 match codegen_units {
1451 Some(n) if n > 1 => {
1452 if matches.opt_present("o") {
1453 for ot in &incompatible {
1457 "`--emit={}` with `-o` incompatible with \
1458 `-C codegen-units=N` for N > 1",
1463 early_warn(error_format, "resetting to default -C codegen-units=1");
1464 codegen_units = Some(1);
1465 disable_thinlto = true;
1469 codegen_units = Some(1);
1470 disable_thinlto = true;
1475 if codegen_units == Some(0) {
1476 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1479 (disable_thinlto, codegen_units)
1482 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1483 if debugging_opts.threads == 0 {
1484 early_error(error_format, "value for threads must be a positive non-zero integer");
1487 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1488 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1492 fn collect_print_requests(
1493 cg: &mut CodegenOptions,
1494 dopts: &mut DebuggingOptions,
1495 matches: &getopts::Matches,
1496 error_format: ErrorOutputType,
1497 ) -> Vec<PrintRequest> {
1498 let mut prints = Vec::<PrintRequest>::new();
1499 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1500 prints.push(PrintRequest::TargetCPUs);
1501 cg.target_cpu = None;
1503 if cg.target_feature == "help" {
1504 prints.push(PrintRequest::TargetFeatures);
1505 cg.target_feature = String::new();
1508 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1509 "crate-name" => PrintRequest::CrateName,
1510 "file-names" => PrintRequest::FileNames,
1511 "sysroot" => PrintRequest::Sysroot,
1512 "target-libdir" => PrintRequest::TargetLibdir,
1513 "cfg" => PrintRequest::Cfg,
1514 "target-list" => PrintRequest::TargetList,
1515 "target-cpus" => PrintRequest::TargetCPUs,
1516 "target-features" => PrintRequest::TargetFeatures,
1517 "relocation-models" => PrintRequest::RelocationModels,
1518 "code-models" => PrintRequest::CodeModels,
1519 "tls-models" => PrintRequest::TlsModels,
1520 "native-static-libs" => PrintRequest::NativeStaticLibs,
1521 "target-spec-json" => {
1522 if dopts.unstable_options {
1523 PrintRequest::TargetSpec
1527 "the `-Z unstable-options` flag must also be passed to \
1528 enable the target-spec-json print option",
1532 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1538 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1539 match matches.opt_str("target") {
1540 Some(target) if target.ends_with(".json") => {
1541 let path = Path::new(&target);
1542 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1543 early_error(error_format, &format!("target file {:?} does not exist", path))
1546 Some(target) => TargetTriple::TargetTriple(target),
1547 _ => TargetTriple::from_triple(host_triple()),
1552 matches: &getopts::Matches,
1553 cg: &CodegenOptions,
1554 error_format: ErrorOutputType,
1556 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1557 // to use them interchangeably. However, because they're technically different flags,
1558 // we need to work out manually which should take precedence if both are supplied (i.e.
1559 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1560 // comparing them. Note that if a flag is not found, its position will be `None`, which
1561 // always compared less than `Some(_)`.
1562 let max_o = matches.opt_positions("O").into_iter().max();
1566 .flat_map(|(i, s)| {
1567 // NB: This can match a string without `=`.
1568 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1574 match cg.opt_level.as_ref() {
1575 "0" => OptLevel::No,
1576 "1" => OptLevel::Less,
1577 "2" => OptLevel::Default,
1578 "3" => OptLevel::Aggressive,
1579 "s" => OptLevel::Size,
1580 "z" => OptLevel::SizeMin,
1585 "optimization level needs to be \
1586 between 0-3, s or z (instead was `{}`)",
1595 fn select_debuginfo(
1596 matches: &getopts::Matches,
1597 cg: &CodegenOptions,
1598 error_format: ErrorOutputType,
1600 let max_g = matches.opt_positions("g").into_iter().max();
1604 .flat_map(|(i, s)| {
1605 // NB: This can match a string without `=`.
1606 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1612 match cg.debuginfo {
1613 0 => DebugInfo::None,
1614 1 => DebugInfo::Limited,
1615 2 => DebugInfo::Full,
1620 "debug info level needs to be between \
1621 0-2 (instead was `{}`)",
1631 matches: &getopts::Matches,
1632 error_format: ErrorOutputType,
1633 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1638 // Parse string of the form "[KIND=]lib[:new_name]",
1639 // where KIND is one of "dylib", "framework", "static".
1640 let (name, kind) = match s.split_once('=') {
1641 None => (s, NativeLibKind::Unspecified),
1642 Some((kind, name)) => {
1643 let kind = match kind {
1644 "dylib" => NativeLibKind::Dylib,
1645 "framework" => NativeLibKind::Framework,
1646 "static" => NativeLibKind::StaticBundle,
1647 "static-nobundle" => NativeLibKind::StaticNoBundle,
1652 "unknown library kind `{}`, expected \
1653 one of dylib, framework, or static",
1659 (name.to_string(), kind)
1662 if kind == NativeLibKind::StaticNoBundle
1663 && !nightly_options::match_is_nightly_build(matches)
1667 "the library kind 'static-nobundle' is only \
1668 accepted on the nightly compiler",
1671 let (name, new_name) = match name.split_once(':') {
1672 None => (name, None),
1673 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1675 (name, new_name, kind)
1680 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1681 match dopts.borrowck.as_ref() {
1682 "migrate" => BorrowckMode::Migrate,
1683 "mir" => BorrowckMode::Mir,
1684 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1688 pub fn parse_externs(
1689 matches: &getopts::Matches,
1690 debugging_opts: &DebuggingOptions,
1691 error_format: ErrorOutputType,
1693 let is_unstable_enabled = debugging_opts.unstable_options;
1694 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1695 for arg in matches.opt_strs("extern") {
1696 let (name, path) = match arg.split_once('=') {
1697 None => (arg, None),
1698 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1700 let (options, name) = match name.split_once(':') {
1701 None => (None, name),
1702 Some((opts, name)) => (Some(opts), name.to_string()),
1705 let path = path.map(|p| CanonicalizedPath::new(p));
1707 let entry = externs.entry(name.to_owned());
1709 use std::collections::btree_map::Entry;
1711 let entry = if let Some(path) = path {
1712 // --extern prelude_name=some_file.rlib
1714 Entry::Vacant(vacant) => {
1715 let files = BTreeSet::from_iter(iter::once(path));
1716 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1718 Entry::Occupied(occupied) => {
1719 let ext_ent = occupied.into_mut();
1721 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1725 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1728 // Exact paths take precedence over search directories.
1729 let files = BTreeSet::from_iter(iter::once(path));
1730 *location = ExternLocation::ExactPaths(files);
1737 // --extern prelude_name
1739 Entry::Vacant(vacant) => {
1740 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1742 Entry::Occupied(occupied) => {
1743 // Ignore if already specified.
1749 let mut is_private_dep = false;
1750 let mut add_prelude = true;
1751 if let Some(opts) = options {
1752 if !is_unstable_enabled {
1755 "the `-Z unstable-options` flag must also be passed to \
1756 enable `--extern options",
1759 for opt in opts.split(',') {
1761 "priv" => is_private_dep = true,
1763 if let ExternLocation::ExactPaths(_) = &entry.location {
1764 add_prelude = false;
1768 "the `noprelude` --extern option requires a file path",
1772 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1777 // Crates start out being not private, and go to being private `priv`
1779 entry.is_private_dep |= is_private_dep;
1780 // If any flag is missing `noprelude`, then add to the prelude.
1781 entry.add_prelude |= add_prelude;
1786 fn parse_extern_dep_specs(
1787 matches: &getopts::Matches,
1788 debugging_opts: &DebuggingOptions,
1789 error_format: ErrorOutputType,
1790 ) -> ExternDepSpecs {
1791 let is_unstable_enabled = debugging_opts.unstable_options;
1792 let mut map = BTreeMap::new();
1794 for arg in matches.opt_strs("extern-location") {
1795 if !is_unstable_enabled {
1798 "`--extern-location` option is unstable: set `-Z unstable-options`",
1802 let mut parts = arg.splitn(2, '=');
1803 let name = parts.next().unwrap_or_else(|| {
1804 early_error(error_format, "`--extern-location` value must not be empty")
1806 let loc = parts.next().unwrap_or_else(|| {
1809 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1813 let locparts: Vec<_> = loc.split(":").collect();
1814 let spec = match &locparts[..] {
1816 // Don't want `:` split string
1817 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1818 early_error(error_format, "`--extern-location`: missing `raw` location")
1820 ExternDepSpec::Raw(raw.to_string())
1823 // Don't want `:` split string
1824 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1825 early_error(error_format, "`--extern-location`: missing `json` location")
1827 let json = json::from_str(raw).unwrap_or_else(|_| {
1830 &format!("`--extern-location`: malformed json location `{}`", raw),
1833 ExternDepSpec::Json(json)
1835 [bad, ..] => early_error(
1837 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1839 [] => early_error(error_format, "missing location specification"),
1842 map.insert(name.to_string(), spec);
1845 ExternDepSpecs::new(map)
1848 fn parse_remap_path_prefix(
1849 matches: &getopts::Matches,
1850 error_format: ErrorOutputType,
1851 ) -> Vec<(PathBuf, PathBuf)> {
1853 .opt_strs("remap-path-prefix")
1855 .map(|remap| match remap.rsplit_once('=') {
1856 None => early_error(
1858 "--remap-path-prefix must contain '=' between FROM and TO",
1860 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1865 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1866 let color = parse_color(matches);
1868 let edition = parse_crate_edition(matches);
1870 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1872 let error_format = parse_error_format(matches, color, json_rendered);
1874 let unparsed_crate_types = matches.opt_strs("crate-type");
1875 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1876 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1878 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1880 let mut debugging_opts = build_debugging_options(matches, error_format);
1881 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1883 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1885 let mut cg = build_codegen_options(matches, error_format);
1886 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1893 check_thread_count(&debugging_opts, error_format);
1895 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1897 if debugging_opts.profile && incremental.is_some() {
1900 "can't instrument with gcov profiling when compiling incrementally",
1903 if debugging_opts.profile {
1904 match codegen_units {
1906 None => codegen_units = Some(1),
1907 Some(_) => early_error(
1909 "can't instrument with gcov profiling with multiple codegen units",
1914 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1917 "options `-C profile-generate` and `-C profile-use` are exclusive",
1921 if debugging_opts.instrument_coverage.is_some()
1922 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
1924 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1927 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1928 or `-C profile-generate`",
1932 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
1933 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
1934 // multiple runs, including some changes to source code; so mangled names must be consistent
1935 // across compilations.
1936 match debugging_opts.symbol_mangling_version {
1938 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
1940 Some(SymbolManglingVersion::Legacy) => {
1943 "-Z instrument-coverage requires symbol mangling version `v0`, \
1944 but `-Z symbol-mangling-version=legacy` was specified",
1947 Some(SymbolManglingVersion::V0) => {}
1951 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
1952 debugging_opts.graphviz_font = graphviz_font;
1955 if !cg.embed_bitcode {
1957 LtoCli::No | LtoCli::Unspecified => {}
1958 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1960 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1965 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1969 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1970 let target_triple = parse_target_triple(matches, error_format);
1971 let opt_level = parse_opt_level(matches, &cg, error_format);
1972 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1973 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1974 // for more details.
1975 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1976 let debuginfo = select_debuginfo(matches, &cg, error_format);
1978 let mut search_paths = vec![];
1979 for s in &matches.opt_strs("L") {
1980 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1983 let libs = parse_libs(matches, error_format);
1985 let test = matches.opt_present("test");
1987 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1989 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1990 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1993 let externs = parse_externs(matches, &debugging_opts, error_format);
1994 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
1996 let crate_name = matches.opt_str("crate-name");
1998 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2000 let pretty = parse_pretty(matches, &debugging_opts, error_format);
2002 if !debugging_opts.unstable_options
2003 && !target_triple.triple().contains("apple")
2004 && cg.split_debuginfo.is_some()
2007 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2013 optimize: opt_level,
2020 maybe_sysroot: sysroot_opt,
2030 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2036 actually_rustdoc: false,
2037 trimmed_def_paths: TrimmedDefPaths::default(),
2038 cli_forced_codegen_units: codegen_units,
2039 cli_forced_thinlto_off: disable_thinlto,
2042 json_artifact_notifications,
2048 matches: &getopts::Matches,
2049 debugging_opts: &DebuggingOptions,
2050 efmt: ErrorOutputType,
2051 ) -> Option<PpMode> {
2052 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
2054 let first = match (name, extended) {
2055 ("normal", _) => Source(PpSourceMode::Normal),
2056 ("identified", _) => Source(PpSourceMode::Identified),
2057 ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
2058 ("expanded", _) => Source(PpSourceMode::Expanded),
2059 ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
2060 ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
2061 ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
2062 ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
2063 ("hir", true) => Hir(PpHirMode::Normal),
2064 ("hir,identified", true) => Hir(PpHirMode::Identified),
2065 ("hir,typed", true) => Hir(PpHirMode::Typed),
2066 ("hir-tree", true) => HirTree,
2067 ("thir-tree", true) => ThirTree,
2068 ("mir", true) => Mir,
2069 ("mir-cfg", true) => MirCFG,
2075 "argument to `unpretty` must be one of `normal`, \
2076 `expanded`, `identified`, `expanded,identified`, \
2077 `expanded,hygiene`, `everybody_loops`, \
2078 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2079 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2087 "argument to `pretty` must be one of `normal`, \
2088 `expanded`, `identified`, or `expanded,identified`; got {}",
2095 tracing::debug!("got unpretty option: {:?}", first);
2099 if debugging_opts.unstable_options {
2100 if let Some(a) = matches.opt_default("pretty", "normal") {
2101 // stable pretty-print variants only
2102 return Some(parse_pretty_inner(efmt, &a, false));
2106 debugging_opts.unpretty.as_ref().map(|a| {
2107 // extended with unstable pretty-print variants
2108 parse_pretty_inner(efmt, &a, true)
2112 pub fn make_crate_type_option() -> RustcOptGroup {
2116 "Comma separated list of types of crates
2117 for the compiler to emit",
2118 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2122 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2123 let mut crate_types: Vec<CrateType> = Vec::new();
2124 for unparsed_crate_type in &list_list {
2125 for part in unparsed_crate_type.split(',') {
2126 let new_part = match part {
2127 "lib" => default_lib_output(),
2128 "rlib" => CrateType::Rlib,
2129 "staticlib" => CrateType::Staticlib,
2130 "dylib" => CrateType::Dylib,
2131 "cdylib" => CrateType::Cdylib,
2132 "bin" => CrateType::Executable,
2133 "proc-macro" => CrateType::ProcMacro,
2134 _ => return Err(format!("unknown crate type: `{}`", part)),
2136 if !crate_types.contains(&new_part) {
2137 crate_types.push(new_part)
2145 pub mod nightly_options {
2146 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2147 use crate::early_error;
2148 use rustc_feature::UnstableFeatures;
2150 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2151 match_is_nightly_build(matches)
2152 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2155 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2156 is_nightly_build(matches.opt_str("crate-name").as_deref())
2159 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2160 UnstableFeatures::from_environment(krate).is_nightly_build()
2163 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2164 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2165 let really_allows_unstable_options = match_is_nightly_build(matches);
2167 for opt in flags.iter() {
2168 if opt.stability == OptionStability::Stable {
2171 if !matches.opt_present(opt.name) {
2174 if opt.name != "Z" && !has_z_unstable_option {
2176 ErrorOutputType::default(),
2178 "the `-Z unstable-options` flag must also be passed to enable \
2184 if really_allows_unstable_options {
2187 match opt.stability {
2188 OptionStability::Unstable => {
2190 "the option `{}` is only accepted on the \
2194 early_error(ErrorOutputType::default(), &msg);
2196 OptionStability::Stable => {}
2202 impl fmt::Display for CrateType {
2203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2205 CrateType::Executable => "bin".fmt(f),
2206 CrateType::Dylib => "dylib".fmt(f),
2207 CrateType::Rlib => "rlib".fmt(f),
2208 CrateType::Staticlib => "staticlib".fmt(f),
2209 CrateType::Cdylib => "cdylib".fmt(f),
2210 CrateType::ProcMacro => "proc-macro".fmt(f),
2215 #[derive(Copy, Clone, PartialEq, Debug)]
2216 pub enum PpSourceMode {
2217 /// `--pretty=normal`
2219 /// `-Zunpretty=everybody_loops`
2221 /// `--pretty=expanded`
2223 /// `--pretty=identified`
2225 /// `--pretty=expanded,identified`
2227 /// `--pretty=expanded,hygiene`
2231 #[derive(Copy, Clone, PartialEq, Debug)]
2232 pub enum PpAstTreeMode {
2233 /// `-Zunpretty=ast`
2235 /// `-Zunpretty=ast,expanded`
2239 #[derive(Copy, Clone, PartialEq, Debug)]
2240 pub enum PpHirMode {
2241 /// `-Zunpretty=hir`
2243 /// `-Zunpretty=hir,identified`
2245 /// `-Zunpretty=hir,typed`
2249 #[derive(Copy, Clone, PartialEq, Debug)]
2251 /// Options that print the source code, i.e.
2252 /// `--pretty` and `-Zunpretty=everybody_loops`
2253 Source(PpSourceMode),
2254 AstTree(PpAstTreeMode),
2255 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2257 /// `-Zunpretty=hir-tree`
2259 /// `-Zunpretty=thir-tree`
2261 /// `-Zunpretty=mir`
2263 /// `-Zunpretty=mir-cfg`
2268 pub fn needs_ast_map(&self) -> bool {
2270 use PpSourceMode::*;
2272 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2274 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2275 | AstTree(PpAstTreeMode::Expanded)
2284 pub fn needs_analysis(&self) -> bool {
2286 matches!(*self, Mir | MirCFG | ThirTree)
2290 /// Command-line arguments passed to the compiler have to be incorporated with
2291 /// the dependency tracking system for incremental compilation. This module
2292 /// provides some utilities to make this more convenient.
2294 /// The values of all command-line arguments that are relevant for dependency
2295 /// tracking are hashed into a single value that determines whether the
2296 /// incremental compilation cache can be re-used or not. This hashing is done
2297 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2298 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2299 /// the hash of which is order dependent, but we might not want the order of
2300 /// arguments to make a difference for the hash).
2302 /// However, since the value provided by `Hash::hash` often *is* suitable,
2303 /// especially for primitive types, there is the
2304 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2305 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2306 /// we have an opt-in scheme here, so one is hopefully forced to think about
2307 /// how the hash should be calculated when adding a new command-line argument.
2308 crate mod dep_tracking {
2310 CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2311 LtoCli, OptLevel, OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm,
2312 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2315 use crate::options::WasiExecModel;
2316 use crate::utils::NativeLibKind;
2317 use rustc_feature::UnstableFeatures;
2318 use rustc_span::edition::Edition;
2319 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2320 use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
2321 use std::collections::hash_map::DefaultHasher;
2322 use std::collections::BTreeMap;
2323 use std::hash::Hash;
2324 use std::num::NonZeroUsize;
2325 use std::path::PathBuf;
2327 pub trait DepTrackingHash {
2328 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2331 macro_rules! impl_dep_tracking_hash_via_hash {
2333 impl DepTrackingHash for $t {
2334 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2335 Hash::hash(self, hasher);
2341 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2343 impl DepTrackingHash for Vec<$t> {
2344 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2345 let mut elems: Vec<&$t> = self.iter().collect();
2347 Hash::hash(&elems.len(), hasher);
2348 for (index, elem) in elems.iter().enumerate() {
2349 Hash::hash(&index, hasher);
2350 DepTrackingHash::hash(*elem, hasher, error_format);
2357 impl_dep_tracking_hash_via_hash!(bool);
2358 impl_dep_tracking_hash_via_hash!(usize);
2359 impl_dep_tracking_hash_via_hash!(u64);
2360 impl_dep_tracking_hash_via_hash!(String);
2361 impl_dep_tracking_hash_via_hash!(PathBuf);
2362 impl_dep_tracking_hash_via_hash!(lint::Level);
2363 impl_dep_tracking_hash_via_hash!(Option<bool>);
2364 impl_dep_tracking_hash_via_hash!(Option<usize>);
2365 impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
2366 impl_dep_tracking_hash_via_hash!(Option<String>);
2367 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2368 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2369 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2370 impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2371 impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
2372 impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2373 impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>);
2374 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2375 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2376 impl_dep_tracking_hash_via_hash!(Option<InstrumentCoverage>);
2377 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2378 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2379 impl_dep_tracking_hash_via_hash!(CrateType);
2380 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2381 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2382 impl_dep_tracking_hash_via_hash!(RelroLevel);
2383 impl_dep_tracking_hash_via_hash!(Passes);
2384 impl_dep_tracking_hash_via_hash!(OptLevel);
2385 impl_dep_tracking_hash_via_hash!(LtoCli);
2386 impl_dep_tracking_hash_via_hash!(DebugInfo);
2387 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2388 impl_dep_tracking_hash_via_hash!(OutputTypes);
2389 impl_dep_tracking_hash_via_hash!(NativeLibKind);
2390 impl_dep_tracking_hash_via_hash!(SanitizerSet);
2391 impl_dep_tracking_hash_via_hash!(CFGuard);
2392 impl_dep_tracking_hash_via_hash!(TargetTriple);
2393 impl_dep_tracking_hash_via_hash!(Edition);
2394 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2395 impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
2396 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2397 impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
2398 impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2399 impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
2401 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2402 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2403 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2404 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2405 impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
2406 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2408 impl<T1, T2> DepTrackingHash for (T1, T2)
2410 T1: DepTrackingHash,
2411 T2: DepTrackingHash,
2413 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2414 Hash::hash(&0, hasher);
2415 DepTrackingHash::hash(&self.0, hasher, error_format);
2416 Hash::hash(&1, hasher);
2417 DepTrackingHash::hash(&self.1, hasher, error_format);
2421 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2423 T1: DepTrackingHash,
2424 T2: DepTrackingHash,
2425 T3: DepTrackingHash,
2427 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2428 Hash::hash(&0, hasher);
2429 DepTrackingHash::hash(&self.0, hasher, error_format);
2430 Hash::hash(&1, hasher);
2431 DepTrackingHash::hash(&self.1, hasher, error_format);
2432 Hash::hash(&2, hasher);
2433 DepTrackingHash::hash(&self.2, hasher, error_format);
2437 // This is a stable hash because BTreeMap is a sorted container
2438 crate fn stable_hash(
2439 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2440 hasher: &mut DefaultHasher,
2441 error_format: ErrorOutputType,
2443 for (key, sub_hash) in sub_hashes {
2444 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2445 // the keys, as they are just plain strings
2446 Hash::hash(&key.len(), hasher);
2447 Hash::hash(key, hasher);
2448 sub_hash.hash(hasher, error_format);