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;
14 use rustc_target::abi::{Align, TargetDataLayout};
15 use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
17 use rustc_serialize::json;
19 use crate::parse::CrateConfig;
20 use rustc_feature::UnstableFeatures;
21 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
22 use rustc_span::source_map::{FileName, FilePathMapping};
23 use rustc_span::symbol::{sym, Symbol};
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};
34 use std::iter::{self, FromIterator};
35 use std::path::{Path, PathBuf};
36 use std::str::{self, FromStr};
38 /// The different settings that the `-Z strip` flag can have.
39 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
41 /// Do not strip at all.
47 /// Strip all symbols.
51 /// The different settings that the `-C control-flow-guard` flag can have.
52 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
54 /// Do not emit Control Flow Guard metadata or checks.
57 /// Emit Control Flow Guard metadata but no checks.
60 /// Emit Control Flow Guard metadata and checks.
64 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
74 impl_stable_hash_via_hash!(OptLevel);
76 /// This is what the `LtoCli` values get mapped to after resolving defaults and
77 /// and taking other command line options into account.
79 /// Note that linker plugin-based LTO is a different mechanism entirely.
80 #[derive(Clone, PartialEq)]
82 /// Don't do any LTO whatsoever.
85 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
88 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
89 /// only relevant if multiple CGUs are used.
92 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
96 /// The different settings that the `-C lto` flag can have.
97 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
109 /// No `-C lto` flag passed
113 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
114 /// document highlighting each span of every statement (including terminators). `Terminator` and
115 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
116 /// computed span for the block, representing the entire range, covering the block's terminator and
117 /// all of its statements.
118 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
119 pub enum MirSpanview {
120 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
122 /// `-Z dump_mir_spanview=terminator`
124 /// `-Z dump_mir_spanview=block`
128 /// The different settings that the `-Z instrument-coverage` flag can have.
130 /// Coverage instrumentation now supports combining `-Z instrument-coverage`
131 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
132 /// and higher). Nevertheless, there are many variables, depending on options
133 /// selected, code structure, and enabled attributes. If errors are encountered,
134 /// either while compiling or when generating `llvm-cov show` reports, consider
135 /// lowering the optimization level, including or excluding `-C link-dead-code`,
136 /// or using `-Z instrument-coverage=except-unused-functions` or `-Z
137 /// instrument-coverage=except-unused-generics`.
139 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
140 /// coverage map, it will not attempt to generate synthetic functions for unused
141 /// (and not code-generated) functions (whether they are generic or not). As a
142 /// result, non-codegenned functions will not be included in the coverage map,
143 /// and will not appear, as covered or uncovered, in coverage reports.
145 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
146 /// unless the function has type parameters.
147 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
148 pub enum InstrumentCoverage {
149 /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
151 /// `-Z instrument-coverage=except-unused-generics`
152 ExceptUnusedGenerics,
153 /// `-Z instrument-coverage=except-unused-functions`
154 ExceptUnusedFunctions,
155 /// `-Z instrument-coverage=off` (or `no`, etc.)
159 #[derive(Clone, PartialEq, Hash)]
160 pub enum LinkerPluginLto {
161 LinkerPlugin(PathBuf),
166 impl LinkerPluginLto {
167 pub fn enabled(&self) -> bool {
169 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
170 LinkerPluginLto::Disabled => false,
175 #[derive(Clone, PartialEq, Hash)]
176 pub enum SwitchWithOptPath {
177 Enabled(Option<PathBuf>),
181 impl SwitchWithOptPath {
182 pub fn enabled(&self) -> bool {
184 SwitchWithOptPath::Enabled(_) => true,
185 SwitchWithOptPath::Disabled => false,
190 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
191 #[derive(Encodable, Decodable)]
192 pub enum SymbolManglingVersion {
197 impl_stable_hash_via_hash!(SymbolManglingVersion);
199 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
206 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
207 #[derive(Encodable, Decodable)]
208 pub enum OutputType {
219 impl_stable_hash_via_hash!(OutputType);
222 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
224 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
226 | OutputType::Assembly
227 | OutputType::LlvmAssembly
229 | OutputType::Object => false,
233 fn shorthand(&self) -> &'static str {
235 OutputType::Bitcode => "llvm-bc",
236 OutputType::Assembly => "asm",
237 OutputType::LlvmAssembly => "llvm-ir",
238 OutputType::Mir => "mir",
239 OutputType::Object => "obj",
240 OutputType::Metadata => "metadata",
241 OutputType::Exe => "link",
242 OutputType::DepInfo => "dep-info",
246 fn from_shorthand(shorthand: &str) -> Option<Self> {
247 Some(match shorthand {
248 "asm" => OutputType::Assembly,
249 "llvm-ir" => OutputType::LlvmAssembly,
250 "mir" => OutputType::Mir,
251 "llvm-bc" => OutputType::Bitcode,
252 "obj" => OutputType::Object,
253 "metadata" => OutputType::Metadata,
254 "link" => OutputType::Exe,
255 "dep-info" => OutputType::DepInfo,
260 fn shorthands_display() -> String {
262 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
263 OutputType::Bitcode.shorthand(),
264 OutputType::Assembly.shorthand(),
265 OutputType::LlvmAssembly.shorthand(),
266 OutputType::Mir.shorthand(),
267 OutputType::Object.shorthand(),
268 OutputType::Metadata.shorthand(),
269 OutputType::Exe.shorthand(),
270 OutputType::DepInfo.shorthand(),
274 pub fn extension(&self) -> &'static str {
276 OutputType::Bitcode => "bc",
277 OutputType::Assembly => "s",
278 OutputType::LlvmAssembly => "ll",
279 OutputType::Mir => "mir",
280 OutputType::Object => "o",
281 OutputType::Metadata => "rmeta",
282 OutputType::DepInfo => "d",
283 OutputType::Exe => "",
288 /// The type of diagnostics output to generate.
289 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
290 pub enum ErrorOutputType {
291 /// Output meant for the consumption of humans.
292 HumanReadable(HumanReadableErrorType),
293 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
295 /// Render the JSON in a human readable way (with indents and newlines).
297 /// The JSON output includes a `rendered` field that includes the rendered
299 json_rendered: HumanReadableErrorType,
303 impl Default for ErrorOutputType {
304 fn default() -> Self {
305 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
309 /// Parameter to control path trimming.
310 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
311 pub enum TrimmedDefPaths {
312 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
314 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
316 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
320 impl Default for TrimmedDefPaths {
321 fn default() -> Self {
326 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
327 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
328 /// dependency tracking for command-line arguments.
329 #[derive(Clone, Hash, Debug)]
330 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
332 impl_stable_hash_via_hash!(OutputTypes);
335 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
336 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
339 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
343 pub fn contains_key(&self, key: &OutputType) -> bool {
344 self.0.contains_key(key)
347 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
351 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
355 pub fn len(&self) -> usize {
359 // Returns `true` if any of the output types require codegen or linking.
360 pub fn should_codegen(&self) -> bool {
361 self.0.keys().any(|k| match *k {
363 | OutputType::Assembly
364 | OutputType::LlvmAssembly
367 | OutputType::Exe => true,
368 OutputType::Metadata | OutputType::DepInfo => false,
372 // Returns `true` if any of the output types require linking.
373 pub fn should_link(&self) -> bool {
374 self.0.keys().any(|k| match *k {
376 | OutputType::Assembly
377 | OutputType::LlvmAssembly
379 | OutputType::Metadata
381 | OutputType::DepInfo => false,
382 OutputType::Exe => true,
387 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
388 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
389 /// would break dependency tracking for command-line arguments.
391 pub struct Externs(BTreeMap<String, ExternEntry>);
394 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
396 #[derive(Clone, Debug)]
397 pub struct ExternEntry {
398 pub location: ExternLocation,
399 /// Indicates this is a "private" dependency for the
400 /// `exported_private_dependencies` lint.
402 /// This can be set with the `priv` option like
403 /// `--extern priv:name=foo.rlib`.
404 pub is_private_dep: bool,
405 /// Add the extern entry to the extern prelude.
407 /// This can be disabled with the `noprelude` option like
408 /// `--extern noprelude:name`.
409 pub add_prelude: bool,
412 #[derive(Clone, Debug)]
413 pub enum ExternLocation {
414 /// Indicates to look for the library in the search paths.
416 /// Added via `--extern name`.
417 FoundInLibrarySearchDirectories,
418 /// The locations where this extern entry must be found.
420 /// The `CrateLoader` is responsible for loading these and figuring out
421 /// which one to use.
423 /// Added via `--extern prelude_name=some_file.rlib`
424 ExactPaths(BTreeSet<CanonicalizedPath>),
427 /// Supplied source location of a dependency - for example in a build specification
428 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
429 /// a file and line, then the build system can specify that. On the other hand, it may
430 /// make more sense to have an arbitrary raw string.
431 #[derive(Clone, PartialEq)]
432 pub enum ExternDepSpec {
435 /// Raw data in json format
439 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
440 fn from(from: &'a ExternDepSpec) -> Self {
442 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
443 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
449 /// Used for testing.
450 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
454 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
458 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
462 pub fn len(&self) -> usize {
468 fn new(location: ExternLocation) -> ExternEntry {
469 ExternEntry { location, is_private_dep: false, add_prelude: false }
472 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
473 match &self.location {
474 ExternLocation::ExactPaths(set) => Some(set.iter()),
480 impl ExternDepSpecs {
481 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
485 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
490 impl fmt::Display for ExternDepSpec {
491 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
493 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
494 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
499 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
500 pub enum PrintRequest {
516 #[derive(Copy, Clone)]
517 pub enum BorrowckMode {
523 /// Returns whether we should run the MIR-based borrow check, but also fall back
524 /// on the AST borrow check if the MIR-based one errors.
525 pub fn migrate(self) -> bool {
527 BorrowckMode::Mir => false,
528 BorrowckMode::Migrate => true,
534 /// Load source code from a file.
536 /// Load source code from a string.
538 /// A string that is shown in place of a filename.
540 /// An anonymous string containing the source code.
546 pub fn filestem(&self) -> &str {
548 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
549 Input::Str { .. } => "rust_out",
553 pub fn source_name(&self) -> FileName {
555 Input::File(ref ifile) => ifile.clone().into(),
556 Input::Str { ref name, .. } => name.clone(),
561 #[derive(Clone, Hash, Debug)]
562 pub struct OutputFilenames {
563 pub out_directory: PathBuf,
565 pub single_output_file: Option<PathBuf>,
566 pub outputs: OutputTypes,
569 impl_stable_hash_via_hash!(OutputFilenames);
571 pub const RLINK_EXT: &str = "rlink";
572 pub const RUST_CGU_EXT: &str = "rcgu";
573 pub const DWARF_OBJECT_EXT: &str = "dwo";
575 impl OutputFilenames {
577 out_directory: PathBuf,
578 out_filestem: String,
579 single_output_file: Option<PathBuf>,
581 outputs: OutputTypes,
587 filestem: format!("{}{}", out_filestem, extra),
591 pub fn path(&self, flavor: OutputType) -> PathBuf {
594 .and_then(|p| p.to_owned())
595 .or_else(|| self.single_output_file.clone())
596 .unwrap_or_else(|| self.temp_path(flavor, None))
599 /// Gets the path where a compilation artifact of the given type for the
600 /// given codegen unit should be placed on disk. If codegen_unit_name is
601 /// None, a path distinct from those of any codegen unit will be generated.
602 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
603 let extension = flavor.extension();
604 self.temp_path_ext(extension, codegen_unit_name)
607 /// Like `temp_path`, but specifically for dwarf objects.
608 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
609 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
612 /// Like `temp_path`, but also supports things where there is no corresponding
613 /// OutputType, like noopt-bitcode or lto-bitcode.
614 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
615 let mut extension = String::new();
617 if let Some(codegen_unit_name) = codegen_unit_name {
618 extension.push_str(codegen_unit_name);
622 if !extension.is_empty() {
624 extension.push_str(RUST_CGU_EXT);
628 extension.push_str(ext);
631 self.with_extension(&extension)
634 pub fn with_extension(&self, extension: &str) -> PathBuf {
635 let mut path = self.out_directory.join(&self.filestem);
636 path.set_extension(extension);
640 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
641 /// mode is being used, which is the logic that this function is intended to encapsulate.
642 pub fn split_dwarf_path(
644 split_debuginfo_kind: SplitDebuginfo,
645 cgu_name: Option<&str>,
646 ) -> Option<PathBuf> {
647 let obj_out = self.temp_path(OutputType::Object, cgu_name);
648 let dwo_out = self.temp_path_dwo(cgu_name);
649 match split_debuginfo_kind {
650 SplitDebuginfo::Off => None,
651 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
652 // (pointing at the path which is being determined here). Use the path to the current
654 SplitDebuginfo::Packed => Some(obj_out),
655 // Split mode emits the DWARF into a different file, use that path.
656 SplitDebuginfo::Unpacked => Some(dwo_out),
661 pub fn host_triple() -> &'static str {
662 // Get the host triple out of the build environment. This ensures that our
663 // idea of the host triple is the same as for the set of libraries we've
664 // actually built. We can't just take LLVM's host triple because they
665 // normalize all ix86 architectures to i386.
667 // Instead of grabbing the host triple (for the current host), we grab (at
668 // compile time) the target triple that this rustc is built with and
669 // calling that (at runtime) the host triple.
670 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
673 impl Default for Options {
674 fn default() -> Options {
676 crate_types: Vec::new(),
677 optimize: OptLevel::No,
678 debuginfo: DebugInfo::None,
679 lint_opts: Vec::new(),
681 describe_lints: false,
682 output_types: OutputTypes(BTreeMap::new()),
683 search_paths: vec![],
685 target_triple: TargetTriple::from_triple(host_triple()),
688 debugging_opts: basic_debugging_options(),
690 borrowck_mode: BorrowckMode::Migrate,
691 cg: basic_codegen_options(),
692 error_format: ErrorOutputType::default(),
693 externs: Externs(BTreeMap::new()),
694 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
698 unstable_features: UnstableFeatures::Disallow,
699 debug_assertions: true,
700 actually_rustdoc: false,
701 trimmed_def_paths: TrimmedDefPaths::default(),
702 cli_forced_codegen_units: None,
703 cli_forced_thinlto_off: false,
704 remap_path_prefix: Vec::new(),
705 edition: DEFAULT_EDITION,
706 json_artifact_notifications: false,
707 json_unused_externs: false,
714 /// Returns `true` if there is a reason to build the dep graph.
715 pub fn build_dep_graph(&self) -> bool {
716 self.incremental.is_some()
717 || self.debugging_opts.dump_dep_graph
718 || self.debugging_opts.query_dep_graph
721 pub fn file_path_mapping(&self) -> FilePathMapping {
722 FilePathMapping::new(self.remap_path_prefix.clone())
725 /// Returns `true` if there will be an output file generated.
726 pub fn will_create_output_file(&self) -> bool {
727 !self.debugging_opts.parse_only && // The file is just being parsed
728 !self.debugging_opts.ls // The file is just being queried
732 pub fn share_generics(&self) -> bool {
733 match self.debugging_opts.share_generics {
734 Some(setting) => setting,
735 None => match self.optimize {
736 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
737 OptLevel::Default | OptLevel::Aggressive => false,
743 impl DebuggingOptions {
744 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
747 treat_err_as_bug: self.treat_err_as_bug,
748 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
749 report_delayed_bugs: self.report_delayed_bugs,
750 macro_backtrace: self.macro_backtrace,
751 deduplicate_diagnostics: self.deduplicate_diagnostics,
755 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
756 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
760 // The type of entry function, so users can have their own entry functions
761 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
762 pub enum EntryFnType {
767 impl_stable_hash_via_hash!(EntryFnType);
769 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
779 impl_stable_hash_via_hash!(CrateType);
781 #[derive(Clone, Hash)]
788 pub fn is_empty(&self) -> bool {
790 Passes::Some(ref v) => v.is_empty(),
791 Passes::All => false,
796 pub const fn default_lib_output() -> CrateType {
800 pub fn default_configuration(sess: &Session) -> CrateConfig {
801 let end = &sess.target.endian;
802 let arch = &sess.target.arch;
803 let wordsz = sess.target.pointer_width.to_string();
804 let os = &sess.target.os;
805 let env = &sess.target.env;
806 let vendor = &sess.target.vendor;
807 let min_atomic_width = sess.target.min_atomic_width();
808 let max_atomic_width = sess.target.max_atomic_width();
809 let atomic_cas = sess.target.atomic_cas;
810 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
814 let mut ret = FxHashSet::default();
815 ret.reserve(6); // the minimum number of insertions
817 ret.insert((sym::target_os, Some(Symbol::intern(os))));
818 if let Some(ref fam) = sess.target.os_family {
819 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
820 if fam == "windows" {
821 ret.insert((sym::windows, None));
822 } else if fam == "unix" {
823 ret.insert((sym::unix, None));
826 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
827 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
828 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
829 ret.insert((sym::target_env, Some(Symbol::intern(env))));
830 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
831 if sess.target.has_elf_tls {
832 ret.insert((sym::target_thread_local, None));
834 for &(i, align) in &[
835 (8, layout.i8_align.abi),
836 (16, layout.i16_align.abi),
837 (32, layout.i32_align.abi),
838 (64, layout.i64_align.abi),
839 (128, layout.i128_align.abi),
841 if i >= min_atomic_width && i <= max_atomic_width {
842 let mut insert_atomic = |s, align: Align| {
843 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
845 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
847 if align.bits() == i {
848 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
851 let s = i.to_string();
852 insert_atomic(&s, align);
854 insert_atomic("ptr", layout.pointer_align.abi);
859 let panic_strategy = sess.panic_strategy();
860 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
862 for s in sess.opts.debugging_opts.sanitizer {
863 let symbol = Symbol::intern(&s.to_string());
864 ret.insert((sym::sanitize, Some(symbol)));
867 if sess.opts.debug_assertions {
868 ret.insert((sym::debug_assertions, None));
870 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
871 ret.insert((sym::proc_macro, None));
876 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
877 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
878 /// but the symbol interner is not yet set up then, so we must convert it later.
879 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
880 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
883 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
884 // Combine the configuration requested by the session (command line) with
885 // some default and generated configuration items.
886 let default_cfg = default_configuration(sess);
887 // If the user wants a test runner, then add the test cfg.
889 user_cfg.insert((sym::test, None));
891 user_cfg.extend(default_cfg.iter().cloned());
895 pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
896 let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
897 let target = target_result.unwrap_or_else(|e| {
901 "Error loading target specification: {}. \
902 Run `rustc --print target-list` for a list of built-in targets",
908 if !matches!(target.pointer_width, 16 | 32 | 64) {
912 "target specification was invalid: \
913 unrecognized target-pointer-width {}",
922 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
923 pub enum OptionStability {
928 pub struct RustcOptGroup {
929 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
930 pub name: &'static str,
931 pub stability: OptionStability,
935 pub fn is_stable(&self) -> bool {
936 self.stability == OptionStability::Stable
939 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
941 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
943 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
946 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
948 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
950 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
954 // The `opt` local module holds wrappers around the `getopts` API that
955 // adds extra rustc-specific metadata to each option; such metadata
956 // is exposed by . The public
957 // functions below ending with `_u` are the functions that return
958 // *unstable* options, i.e., options that are only enabled when the
959 // user also passes the `-Z unstable-options` debugging flag.
961 // The `fn flag*` etc below are written so that we can use them
962 // in the future; do not warn about them not being used right now.
965 use super::RustcOptGroup;
967 pub type R = RustcOptGroup;
968 pub type S = &'static str;
970 fn stable<F>(name: S, f: F) -> R
972 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
974 RustcOptGroup::stable(name, f)
977 fn unstable<F>(name: S, f: F) -> R
979 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
981 RustcOptGroup::unstable(name, f)
984 fn longer(a: S, b: S) -> S {
985 if a.len() > b.len() { a } else { b }
988 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
989 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
991 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
992 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
994 pub fn flag_s(a: S, b: S, c: S) -> R {
995 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
997 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
998 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1001 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1002 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1004 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1005 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1009 /// Returns the "short" subset of the rustc command line options,
1010 /// including metadata for each option, such as whether the option is
1011 /// part of the stable long-term interface for rustc.
1012 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1014 opt::flag_s("h", "help", "Display this message"),
1015 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1019 "Add a directory to the library search path. The
1020 optional KIND can be one of dependency, crate, native,
1021 framework, or all (the default).",
1027 "Link the generated crate(s) to the specified native
1028 library NAME. The optional KIND can be one of
1029 static, framework, or dylib (the default).",
1032 make_crate_type_option(),
1033 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1037 "Specify which edition of the compiler to use when compiling code.",
1043 "Comma separated list of types of output for \
1044 the compiler to emit",
1045 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1050 "Compiler information to print on stdout",
1051 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1052 target-cpus|target-features|relocation-models|\
1053 code-models|tls-models|target-spec-json|native-static-libs]",
1055 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1056 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1057 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1061 "Write output to compiler-chosen filename \
1068 "Provide a detailed explanation of an error \
1072 opt::flag_s("", "test", "Build a test harness"),
1073 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1074 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1075 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1076 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1077 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1081 "Set the most restrictive lint level. \
1082 More restrictive lints are capped at this \
1086 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1087 opt::flag_s("V", "version", "Print version info and exit"),
1088 opt::flag_s("v", "verbose", "Use verbose output"),
1092 /// Returns all rustc command line options, including metadata for
1093 /// each option, such as whether the option is part of the stable
1094 /// long-term interface for rustc.
1095 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1096 let mut opts = rustc_short_optgroups();
1101 "Specify where an external rust library is located",
1107 "Location where an external crate dependency is specified",
1110 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1111 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1115 "How errors and other messages are produced",
1118 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1122 "Configure coloring of output:
1123 auto = colorize, if output goes to a tty (default);
1124 always = always colorize output;
1125 never = never colorize output",
1126 "auto|always|never",
1131 "Pretty-print the input instead of compiling;
1132 valid types are: `normal` (un-annotated source),
1133 `expanded` (crates expanded), or
1134 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1139 "remap-path-prefix",
1140 "Remap source names in all output (compiler messages and output files)",
1147 pub fn get_cmd_lint_options(
1148 matches: &getopts::Matches,
1149 error_format: ErrorOutputType,
1150 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1151 let mut lint_opts_with_position = vec![];
1152 let mut describe_lints = false;
1154 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1155 for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1156 let arg_pos = if let lint::Forbid = level {
1157 // HACK: forbid is always specified last, so it can't be overridden.
1158 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1159 // fixed and `forbid` works as expected.
1164 if lint_name == "help" {
1165 describe_lints = true;
1167 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1172 lint_opts_with_position.sort_by_key(|x| x.0);
1173 let lint_opts = lint_opts_with_position
1176 .map(|(_, lint_name, level)| (lint_name, level))
1179 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1180 lint::Level::from_str(&cap)
1181 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1183 (lint_opts, describe_lints, lint_cap)
1186 /// Parses the `--color` flag.
1187 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1188 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1189 Some("auto") => ColorConfig::Auto,
1190 Some("always") => ColorConfig::Always,
1191 Some("never") => ColorConfig::Never,
1193 None => ColorConfig::Auto,
1195 Some(arg) => early_error(
1196 ErrorOutputType::default(),
1198 "argument for `--color` must be auto, \
1199 always or never (instead was `{}`)",
1206 /// Possible json config files
1207 pub struct JsonConfig {
1208 pub json_rendered: HumanReadableErrorType,
1209 pub json_artifact_notifications: bool,
1210 pub json_unused_externs: bool,
1213 /// Parse the `--json` flag.
1215 /// The first value returned is how to render JSON diagnostics, and the second
1216 /// is whether or not artifact notifications are enabled.
1217 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1218 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1219 HumanReadableErrorType::Default;
1220 let mut json_color = ColorConfig::Never;
1221 let mut json_artifact_notifications = false;
1222 let mut json_unused_externs = false;
1223 for option in matches.opt_strs("json") {
1224 // For now conservatively forbid `--color` with `--json` since `--json`
1225 // won't actually be emitting any colors and anything colorized is
1226 // embedded in a diagnostic message anyway.
1227 if matches.opt_str("color").is_some() {
1229 ErrorOutputType::default(),
1230 "cannot specify the `--color` option with `--json`",
1234 for sub_option in option.split(',') {
1236 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1237 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1238 "artifacts" => json_artifact_notifications = true,
1239 "unused-externs" => json_unused_externs = true,
1241 ErrorOutputType::default(),
1242 &format!("unknown `--json` option `{}`", s),
1249 json_rendered: json_rendered(json_color),
1250 json_artifact_notifications,
1251 json_unused_externs,
1255 /// Parses the `--error-format` flag.
1256 pub fn parse_error_format(
1257 matches: &getopts::Matches,
1259 json_rendered: HumanReadableErrorType,
1260 ) -> ErrorOutputType {
1261 // We need the `opts_present` check because the driver will send us Matches
1262 // with only stable options if no unstable options are used. Since error-format
1263 // is unstable, it will not be present. We have to use `opts_present` not
1264 // `opt_present` because the latter will panic.
1265 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1266 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1267 None | Some("human") => {
1268 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1270 Some("human-annotate-rs") => {
1271 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1273 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1274 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1275 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1277 Some(arg) => early_error(
1278 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1280 "argument for `--error-format` must be `human`, `json` or \
1281 `short` (instead was `{}`)",
1287 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1290 match error_format {
1291 ErrorOutputType::Json { .. } => {}
1293 // Conservatively require that the `--json` argument is coupled with
1294 // `--error-format=json`. This means that `--json` is specified we
1295 // should actually be emitting JSON blobs.
1296 _ if !matches.opt_strs("json").is_empty() => {
1298 ErrorOutputType::default(),
1299 "using `--json` requires also using `--error-format=json`",
1309 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1310 let edition = match matches.opt_str("edition") {
1311 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1313 ErrorOutputType::default(),
1315 "argument for `--edition` must be one of: \
1316 {}. (instead was `{}`)",
1317 EDITION_NAME_LIST, arg
1321 None => DEFAULT_EDITION,
1324 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1325 let is_nightly = nightly_options::match_is_nightly_build(matches);
1326 let msg = if !is_nightly {
1328 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1329 edition, LATEST_STABLE_EDITION
1332 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1334 early_error(ErrorOutputType::default(), &msg)
1340 fn check_debug_option_stability(
1341 debugging_opts: &DebuggingOptions,
1342 error_format: ErrorOutputType,
1343 json_rendered: HumanReadableErrorType,
1345 if !debugging_opts.unstable_options {
1346 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1348 ErrorOutputType::Json { pretty: false, json_rendered },
1349 "`--error-format=pretty-json` is unstable",
1352 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1356 ErrorOutputType::Json { pretty: false, json_rendered },
1357 "`--error-format=human-annotate-rs` is unstable",
1363 fn parse_output_types(
1364 debugging_opts: &DebuggingOptions,
1365 matches: &getopts::Matches,
1366 error_format: ErrorOutputType,
1368 let mut output_types = BTreeMap::new();
1369 if !debugging_opts.parse_only {
1370 for list in matches.opt_strs("emit") {
1371 for output_type in list.split(',') {
1372 let (shorthand, path) = match output_type.split_once('=') {
1373 None => (output_type, None),
1374 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1376 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1380 "unknown emission type: `{}` - expected one of: {}",
1382 OutputType::shorthands_display(),
1386 output_types.insert(output_type, path);
1390 if output_types.is_empty() {
1391 output_types.insert(OutputType::Exe, None);
1393 OutputTypes(output_types)
1396 fn should_override_cgus_and_disable_thinlto(
1397 output_types: &OutputTypes,
1398 matches: &getopts::Matches,
1399 error_format: ErrorOutputType,
1400 mut codegen_units: Option<usize>,
1401 ) -> (bool, Option<usize>) {
1402 let mut disable_thinlto = false;
1403 // Issue #30063: if user requests LLVM-related output to one
1404 // particular path, disable codegen-units.
1405 let incompatible: Vec<_> = output_types
1408 .map(|ot_path| ot_path.0)
1409 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1410 .map(|ot| ot.shorthand())
1412 if !incompatible.is_empty() {
1413 match codegen_units {
1414 Some(n) if n > 1 => {
1415 if matches.opt_present("o") {
1416 for ot in &incompatible {
1420 "`--emit={}` with `-o` incompatible with \
1421 `-C codegen-units=N` for N > 1",
1426 early_warn(error_format, "resetting to default -C codegen-units=1");
1427 codegen_units = Some(1);
1428 disable_thinlto = true;
1432 codegen_units = Some(1);
1433 disable_thinlto = true;
1438 if codegen_units == Some(0) {
1439 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1442 (disable_thinlto, codegen_units)
1445 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1446 if debugging_opts.threads == 0 {
1447 early_error(error_format, "value for threads must be a positive non-zero integer");
1450 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1451 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1455 fn collect_print_requests(
1456 cg: &mut CodegenOptions,
1457 dopts: &mut DebuggingOptions,
1458 matches: &getopts::Matches,
1459 error_format: ErrorOutputType,
1460 ) -> Vec<PrintRequest> {
1461 let mut prints = Vec::<PrintRequest>::new();
1462 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1463 prints.push(PrintRequest::TargetCPUs);
1464 cg.target_cpu = None;
1466 if cg.target_feature == "help" {
1467 prints.push(PrintRequest::TargetFeatures);
1468 cg.target_feature = String::new();
1471 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1472 "crate-name" => PrintRequest::CrateName,
1473 "file-names" => PrintRequest::FileNames,
1474 "sysroot" => PrintRequest::Sysroot,
1475 "target-libdir" => PrintRequest::TargetLibdir,
1476 "cfg" => PrintRequest::Cfg,
1477 "target-list" => PrintRequest::TargetList,
1478 "target-cpus" => PrintRequest::TargetCPUs,
1479 "target-features" => PrintRequest::TargetFeatures,
1480 "relocation-models" => PrintRequest::RelocationModels,
1481 "code-models" => PrintRequest::CodeModels,
1482 "tls-models" => PrintRequest::TlsModels,
1483 "native-static-libs" => PrintRequest::NativeStaticLibs,
1484 "target-spec-json" => {
1485 if dopts.unstable_options {
1486 PrintRequest::TargetSpec
1490 "the `-Z unstable-options` flag must also be passed to \
1491 enable the target-spec-json print option",
1495 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1501 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1502 match matches.opt_str("target") {
1503 Some(target) if target.ends_with(".json") => {
1504 let path = Path::new(&target);
1505 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1506 early_error(error_format, &format!("target file {:?} does not exist", path))
1509 Some(target) => TargetTriple::TargetTriple(target),
1510 _ => TargetTriple::from_triple(host_triple()),
1515 matches: &getopts::Matches,
1516 cg: &CodegenOptions,
1517 error_format: ErrorOutputType,
1519 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1520 // to use them interchangeably. However, because they're technically different flags,
1521 // we need to work out manually which should take precedence if both are supplied (i.e.
1522 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1523 // comparing them. Note that if a flag is not found, its position will be `None`, which
1524 // always compared less than `Some(_)`.
1525 let max_o = matches.opt_positions("O").into_iter().max();
1529 .flat_map(|(i, s)| {
1530 // NB: This can match a string without `=`.
1531 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1537 match cg.opt_level.as_ref() {
1538 "0" => OptLevel::No,
1539 "1" => OptLevel::Less,
1540 "2" => OptLevel::Default,
1541 "3" => OptLevel::Aggressive,
1542 "s" => OptLevel::Size,
1543 "z" => OptLevel::SizeMin,
1548 "optimization level needs to be \
1549 between 0-3, s or z (instead was `{}`)",
1558 fn select_debuginfo(
1559 matches: &getopts::Matches,
1560 cg: &CodegenOptions,
1561 error_format: ErrorOutputType,
1563 let max_g = matches.opt_positions("g").into_iter().max();
1567 .flat_map(|(i, s)| {
1568 // NB: This can match a string without `=`.
1569 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1575 match cg.debuginfo {
1576 0 => DebugInfo::None,
1577 1 => DebugInfo::Limited,
1578 2 => DebugInfo::Full,
1583 "debug info level needs to be between \
1584 0-2 (instead was `{}`)",
1594 matches: &getopts::Matches,
1595 error_format: ErrorOutputType,
1596 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1601 // Parse string of the form "[KIND=]lib[:new_name]",
1602 // where KIND is one of "dylib", "framework", "static".
1603 let (name, kind) = match s.split_once('=') {
1604 None => (s, NativeLibKind::Unspecified),
1605 Some((kind, name)) => {
1606 let kind = match kind {
1607 "dylib" => NativeLibKind::Dylib,
1608 "framework" => NativeLibKind::Framework,
1609 "static" => NativeLibKind::StaticBundle,
1610 "static-nobundle" => NativeLibKind::StaticNoBundle,
1615 "unknown library kind `{}`, expected \
1616 one of dylib, framework, or static",
1622 (name.to_string(), kind)
1625 if kind == NativeLibKind::StaticNoBundle
1626 && !nightly_options::match_is_nightly_build(matches)
1630 "the library kind 'static-nobundle' is only \
1631 accepted on the nightly compiler",
1634 let (name, new_name) = match name.split_once(':') {
1635 None => (name, None),
1636 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1638 (name, new_name, kind)
1643 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1644 match dopts.borrowck.as_ref() {
1645 "migrate" => BorrowckMode::Migrate,
1646 "mir" => BorrowckMode::Mir,
1647 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1651 pub fn parse_externs(
1652 matches: &getopts::Matches,
1653 debugging_opts: &DebuggingOptions,
1654 error_format: ErrorOutputType,
1656 let is_unstable_enabled = debugging_opts.unstable_options;
1657 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1658 for arg in matches.opt_strs("extern") {
1659 let (name, path) = match arg.split_once('=') {
1660 None => (arg, None),
1661 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1663 let (options, name) = match name.split_once(':') {
1664 None => (None, name),
1665 Some((opts, name)) => (Some(opts), name.to_string()),
1668 let path = path.map(|p| CanonicalizedPath::new(p));
1670 let entry = externs.entry(name.to_owned());
1672 use std::collections::btree_map::Entry;
1674 let entry = if let Some(path) = path {
1675 // --extern prelude_name=some_file.rlib
1677 Entry::Vacant(vacant) => {
1678 let files = BTreeSet::from_iter(iter::once(path));
1679 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1681 Entry::Occupied(occupied) => {
1682 let ext_ent = occupied.into_mut();
1684 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1688 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1691 // Exact paths take precedence over search directories.
1692 let files = BTreeSet::from_iter(iter::once(path));
1693 *location = ExternLocation::ExactPaths(files);
1700 // --extern prelude_name
1702 Entry::Vacant(vacant) => {
1703 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1705 Entry::Occupied(occupied) => {
1706 // Ignore if already specified.
1712 let mut is_private_dep = false;
1713 let mut add_prelude = true;
1714 if let Some(opts) = options {
1715 if !is_unstable_enabled {
1718 "the `-Z unstable-options` flag must also be passed to \
1719 enable `--extern options",
1722 for opt in opts.split(',') {
1724 "priv" => is_private_dep = true,
1726 if let ExternLocation::ExactPaths(_) = &entry.location {
1727 add_prelude = false;
1731 "the `noprelude` --extern option requires a file path",
1735 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1740 // Crates start out being not private, and go to being private `priv`
1742 entry.is_private_dep |= is_private_dep;
1743 // If any flag is missing `noprelude`, then add to the prelude.
1744 entry.add_prelude |= add_prelude;
1749 fn parse_extern_dep_specs(
1750 matches: &getopts::Matches,
1751 debugging_opts: &DebuggingOptions,
1752 error_format: ErrorOutputType,
1753 ) -> ExternDepSpecs {
1754 let is_unstable_enabled = debugging_opts.unstable_options;
1755 let mut map = BTreeMap::new();
1757 for arg in matches.opt_strs("extern-location") {
1758 if !is_unstable_enabled {
1761 "`--extern-location` option is unstable: set `-Z unstable-options`",
1765 let mut parts = arg.splitn(2, '=');
1766 let name = parts.next().unwrap_or_else(|| {
1767 early_error(error_format, "`--extern-location` value must not be empty")
1769 let loc = parts.next().unwrap_or_else(|| {
1772 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1776 let locparts: Vec<_> = loc.split(":").collect();
1777 let spec = match &locparts[..] {
1779 // Don't want `:` split string
1780 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1781 early_error(error_format, "`--extern-location`: missing `raw` location")
1783 ExternDepSpec::Raw(raw.to_string())
1786 // Don't want `:` split string
1787 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1788 early_error(error_format, "`--extern-location`: missing `json` location")
1790 let json = json::from_str(raw).unwrap_or_else(|_| {
1793 &format!("`--extern-location`: malformed json location `{}`", raw),
1796 ExternDepSpec::Json(json)
1798 [bad, ..] => early_error(
1800 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1802 [] => early_error(error_format, "missing location specification"),
1805 map.insert(name.to_string(), spec);
1808 ExternDepSpecs::new(map)
1811 fn parse_remap_path_prefix(
1812 matches: &getopts::Matches,
1813 error_format: ErrorOutputType,
1814 ) -> Vec<(PathBuf, PathBuf)> {
1816 .opt_strs("remap-path-prefix")
1818 .map(|remap| match remap.rsplit_once('=') {
1819 None => early_error(
1821 "--remap-path-prefix must contain '=' between FROM and TO",
1823 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1828 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1829 let color = parse_color(matches);
1831 let edition = parse_crate_edition(matches);
1833 let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
1834 parse_json(matches);
1836 let error_format = parse_error_format(matches, color, json_rendered);
1838 let unparsed_crate_types = matches.opt_strs("crate-type");
1839 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1840 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1842 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1844 let mut debugging_opts = build_debugging_options(matches, error_format);
1845 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1847 if !debugging_opts.unstable_options && json_unused_externs {
1850 "the `-Z unstable-options` flag must also be passed to enable \
1851 the flag `--json=unused-externs`",
1855 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1857 let mut cg = build_codegen_options(matches, error_format);
1858 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1865 check_thread_count(&debugging_opts, error_format);
1867 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1869 if debugging_opts.profile && incremental.is_some() {
1872 "can't instrument with gcov profiling when compiling incrementally",
1875 if debugging_opts.profile {
1876 match codegen_units {
1878 None => codegen_units = Some(1),
1879 Some(_) => early_error(
1881 "can't instrument with gcov profiling with multiple codegen units",
1886 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1889 "options `-C profile-generate` and `-C profile-use` are exclusive",
1893 if debugging_opts.instrument_coverage.is_some()
1894 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
1896 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1899 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1900 or `-C profile-generate`",
1904 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
1905 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
1906 // multiple runs, including some changes to source code; so mangled names must be consistent
1907 // across compilations.
1908 match debugging_opts.symbol_mangling_version {
1910 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
1912 Some(SymbolManglingVersion::Legacy) => {
1915 "-Z instrument-coverage requires symbol mangling version `v0`, \
1916 but `-Z symbol-mangling-version=legacy` was specified",
1919 Some(SymbolManglingVersion::V0) => {}
1923 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
1924 debugging_opts.graphviz_font = graphviz_font;
1927 if !cg.embed_bitcode {
1929 LtoCli::No | LtoCli::Unspecified => {}
1930 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1932 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1937 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1941 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1942 let target_triple = parse_target_triple(matches, error_format);
1943 let opt_level = parse_opt_level(matches, &cg, error_format);
1944 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1945 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1946 // for more details.
1947 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1948 let debuginfo = select_debuginfo(matches, &cg, error_format);
1950 let mut search_paths = vec![];
1951 for s in &matches.opt_strs("L") {
1952 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1955 let libs = parse_libs(matches, error_format);
1957 let test = matches.opt_present("test");
1959 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1961 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1962 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1965 let externs = parse_externs(matches, &debugging_opts, error_format);
1966 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
1968 let crate_name = matches.opt_str("crate-name");
1970 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1972 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1974 if !debugging_opts.unstable_options
1975 && !target_triple.triple().contains("apple")
1976 && cg.split_debuginfo.is_some()
1979 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
1985 optimize: opt_level,
1992 maybe_sysroot: sysroot_opt,
2002 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2008 actually_rustdoc: false,
2009 trimmed_def_paths: TrimmedDefPaths::default(),
2010 cli_forced_codegen_units: codegen_units,
2011 cli_forced_thinlto_off: disable_thinlto,
2014 json_artifact_notifications,
2015 json_unused_externs,
2021 matches: &getopts::Matches,
2022 debugging_opts: &DebuggingOptions,
2023 efmt: ErrorOutputType,
2024 ) -> Option<PpMode> {
2025 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
2027 let first = match (name, extended) {
2028 ("normal", _) => Source(PpSourceMode::Normal),
2029 ("identified", _) => Source(PpSourceMode::Identified),
2030 ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
2031 ("expanded", _) => Source(PpSourceMode::Expanded),
2032 ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
2033 ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
2034 ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
2035 ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
2036 ("hir", true) => Hir(PpHirMode::Normal),
2037 ("hir,identified", true) => Hir(PpHirMode::Identified),
2038 ("hir,typed", true) => Hir(PpHirMode::Typed),
2039 ("hir-tree", true) => HirTree,
2040 ("thir-tree", true) => ThirTree,
2041 ("mir", true) => Mir,
2042 ("mir-cfg", true) => MirCFG,
2048 "argument to `unpretty` must be one of `normal`, \
2049 `expanded`, `identified`, `expanded,identified`, \
2050 `expanded,hygiene`, `everybody_loops`, \
2051 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2052 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2060 "argument to `pretty` must be one of `normal`, \
2061 `expanded`, `identified`, or `expanded,identified`; got {}",
2068 tracing::debug!("got unpretty option: {:?}", first);
2072 if debugging_opts.unstable_options {
2073 if let Some(a) = matches.opt_default("pretty", "normal") {
2074 // stable pretty-print variants only
2075 return Some(parse_pretty_inner(efmt, &a, false));
2079 debugging_opts.unpretty.as_ref().map(|a| {
2080 // extended with unstable pretty-print variants
2081 parse_pretty_inner(efmt, &a, true)
2085 pub fn make_crate_type_option() -> RustcOptGroup {
2089 "Comma separated list of types of crates
2090 for the compiler to emit",
2091 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2095 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2096 let mut crate_types: Vec<CrateType> = Vec::new();
2097 for unparsed_crate_type in &list_list {
2098 for part in unparsed_crate_type.split(',') {
2099 let new_part = match part {
2100 "lib" => default_lib_output(),
2101 "rlib" => CrateType::Rlib,
2102 "staticlib" => CrateType::Staticlib,
2103 "dylib" => CrateType::Dylib,
2104 "cdylib" => CrateType::Cdylib,
2105 "bin" => CrateType::Executable,
2106 "proc-macro" => CrateType::ProcMacro,
2107 _ => return Err(format!("unknown crate type: `{}`", part)),
2109 if !crate_types.contains(&new_part) {
2110 crate_types.push(new_part)
2118 pub mod nightly_options {
2119 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2120 use crate::early_error;
2121 use rustc_feature::UnstableFeatures;
2123 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2124 match_is_nightly_build(matches)
2125 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2128 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2129 is_nightly_build(matches.opt_str("crate-name").as_deref())
2132 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2133 UnstableFeatures::from_environment(krate).is_nightly_build()
2136 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2137 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2138 let really_allows_unstable_options = match_is_nightly_build(matches);
2140 for opt in flags.iter() {
2141 if opt.stability == OptionStability::Stable {
2144 if !matches.opt_present(opt.name) {
2147 if opt.name != "Z" && !has_z_unstable_option {
2149 ErrorOutputType::default(),
2151 "the `-Z unstable-options` flag must also be passed to enable \
2157 if really_allows_unstable_options {
2160 match opt.stability {
2161 OptionStability::Unstable => {
2163 "the option `{}` is only accepted on the \
2167 early_error(ErrorOutputType::default(), &msg);
2169 OptionStability::Stable => {}
2175 impl fmt::Display for CrateType {
2176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2178 CrateType::Executable => "bin".fmt(f),
2179 CrateType::Dylib => "dylib".fmt(f),
2180 CrateType::Rlib => "rlib".fmt(f),
2181 CrateType::Staticlib => "staticlib".fmt(f),
2182 CrateType::Cdylib => "cdylib".fmt(f),
2183 CrateType::ProcMacro => "proc-macro".fmt(f),
2188 #[derive(Copy, Clone, PartialEq, Debug)]
2189 pub enum PpSourceMode {
2190 /// `--pretty=normal`
2192 /// `-Zunpretty=everybody_loops`
2194 /// `--pretty=expanded`
2196 /// `--pretty=identified`
2198 /// `--pretty=expanded,identified`
2200 /// `--pretty=expanded,hygiene`
2204 #[derive(Copy, Clone, PartialEq, Debug)]
2205 pub enum PpAstTreeMode {
2206 /// `-Zunpretty=ast`
2208 /// `-Zunpretty=ast,expanded`
2212 #[derive(Copy, Clone, PartialEq, Debug)]
2213 pub enum PpHirMode {
2214 /// `-Zunpretty=hir`
2216 /// `-Zunpretty=hir,identified`
2218 /// `-Zunpretty=hir,typed`
2222 #[derive(Copy, Clone, PartialEq, Debug)]
2224 /// Options that print the source code, i.e.
2225 /// `--pretty` and `-Zunpretty=everybody_loops`
2226 Source(PpSourceMode),
2227 AstTree(PpAstTreeMode),
2228 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2230 /// `-Zunpretty=hir-tree`
2232 /// `-Zunpretty=thir-tree`
2234 /// `-Zunpretty=mir`
2236 /// `-Zunpretty=mir-cfg`
2241 pub fn needs_ast_map(&self) -> bool {
2243 use PpSourceMode::*;
2245 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2247 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2248 | AstTree(PpAstTreeMode::Expanded)
2257 pub fn needs_analysis(&self) -> bool {
2259 matches!(*self, Mir | MirCFG | ThirTree)
2263 /// Command-line arguments passed to the compiler have to be incorporated with
2264 /// the dependency tracking system for incremental compilation. This module
2265 /// provides some utilities to make this more convenient.
2267 /// The values of all command-line arguments that are relevant for dependency
2268 /// tracking are hashed into a single value that determines whether the
2269 /// incremental compilation cache can be re-used or not. This hashing is done
2270 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2271 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2272 /// the hash of which is order dependent, but we might not want the order of
2273 /// arguments to make a difference for the hash).
2275 /// However, since the value provided by `Hash::hash` often *is* suitable,
2276 /// especially for primitive types, there is the
2277 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2278 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2279 /// we have an opt-in scheme here, so one is hopefully forced to think about
2280 /// how the hash should be calculated when adding a new command-line argument.
2281 crate mod dep_tracking {
2283 CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2284 LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
2285 SymbolManglingVersion, TrimmedDefPaths,
2288 use crate::options::WasiExecModel;
2289 use crate::utils::NativeLibKind;
2290 use rustc_feature::UnstableFeatures;
2291 use rustc_span::edition::Edition;
2292 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2293 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
2294 use std::collections::hash_map::DefaultHasher;
2295 use std::collections::BTreeMap;
2296 use std::hash::Hash;
2297 use std::num::NonZeroUsize;
2298 use std::path::PathBuf;
2300 pub trait DepTrackingHash {
2301 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2304 macro_rules! impl_dep_tracking_hash_via_hash {
2306 impl DepTrackingHash for $t {
2307 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2308 Hash::hash(self, hasher);
2314 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2316 impl DepTrackingHash for Vec<$t> {
2317 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2318 let mut elems: Vec<&$t> = self.iter().collect();
2320 Hash::hash(&elems.len(), hasher);
2321 for (index, elem) in elems.iter().enumerate() {
2322 Hash::hash(&index, hasher);
2323 DepTrackingHash::hash(*elem, hasher, error_format);
2330 impl_dep_tracking_hash_via_hash!(bool);
2331 impl_dep_tracking_hash_via_hash!(usize);
2332 impl_dep_tracking_hash_via_hash!(u64);
2333 impl_dep_tracking_hash_via_hash!(String);
2334 impl_dep_tracking_hash_via_hash!(PathBuf);
2335 impl_dep_tracking_hash_via_hash!(lint::Level);
2336 impl_dep_tracking_hash_via_hash!(Option<bool>);
2337 impl_dep_tracking_hash_via_hash!(Option<u32>);
2338 impl_dep_tracking_hash_via_hash!(Option<usize>);
2339 impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
2340 impl_dep_tracking_hash_via_hash!(Option<String>);
2341 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2342 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2343 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2344 impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2345 impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
2346 impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2347 impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>);
2348 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2349 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2350 impl_dep_tracking_hash_via_hash!(Option<InstrumentCoverage>);
2351 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2352 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2353 impl_dep_tracking_hash_via_hash!(CrateType);
2354 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2355 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2356 impl_dep_tracking_hash_via_hash!(RelroLevel);
2357 impl_dep_tracking_hash_via_hash!(Passes);
2358 impl_dep_tracking_hash_via_hash!(OptLevel);
2359 impl_dep_tracking_hash_via_hash!(LtoCli);
2360 impl_dep_tracking_hash_via_hash!(DebugInfo);
2361 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2362 impl_dep_tracking_hash_via_hash!(OutputTypes);
2363 impl_dep_tracking_hash_via_hash!(NativeLibKind);
2364 impl_dep_tracking_hash_via_hash!(SanitizerSet);
2365 impl_dep_tracking_hash_via_hash!(CFGuard);
2366 impl_dep_tracking_hash_via_hash!(TargetTriple);
2367 impl_dep_tracking_hash_via_hash!(Edition);
2368 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2369 impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
2370 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2371 impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
2372 impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2373 impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
2375 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2376 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2377 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2378 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2379 impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
2380 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2382 impl<T1, T2> DepTrackingHash for (T1, T2)
2384 T1: DepTrackingHash,
2385 T2: DepTrackingHash,
2387 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2388 Hash::hash(&0, hasher);
2389 DepTrackingHash::hash(&self.0, hasher, error_format);
2390 Hash::hash(&1, hasher);
2391 DepTrackingHash::hash(&self.1, hasher, error_format);
2395 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2397 T1: DepTrackingHash,
2398 T2: DepTrackingHash,
2399 T3: DepTrackingHash,
2401 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2402 Hash::hash(&0, hasher);
2403 DepTrackingHash::hash(&self.0, hasher, error_format);
2404 Hash::hash(&1, hasher);
2405 DepTrackingHash::hash(&self.1, hasher, error_format);
2406 Hash::hash(&2, hasher);
2407 DepTrackingHash::hash(&self.2, hasher, error_format);
2411 // This is a stable hash because BTreeMap is a sorted container
2412 crate fn stable_hash(
2413 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2414 hasher: &mut DefaultHasher,
2415 error_format: ErrorOutputType,
2417 for (key, sub_hash) in sub_hashes {
2418 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2419 // the keys, as they are just plain strings
2420 Hash::hash(&key.len(), hasher);
2421 Hash::hash(key, hasher);
2422 sub_hash.hash(hasher, error_format);