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 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
512 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
516 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
522 fn new(location: ExternLocation) -> ExternEntry {
523 ExternEntry { location, is_private_dep: false, add_prelude: false }
526 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
527 match &self.location {
528 ExternLocation::ExactPaths(set) => Some(set.iter()),
534 impl ExternDepSpecs {
535 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
539 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
544 impl fmt::Display for ExternDepSpec {
545 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
547 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
548 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
553 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
554 pub enum PrintRequest {
570 #[derive(Copy, Clone)]
571 pub enum BorrowckMode {
577 /// Returns whether we should run the MIR-based borrow check, but also fall back
578 /// on the AST borrow check if the MIR-based one errors.
579 pub fn migrate(self) -> bool {
581 BorrowckMode::Mir => false,
582 BorrowckMode::Migrate => true,
588 /// Load source code from a file.
590 /// Load source code from a string.
592 /// A string that is shown in place of a filename.
594 /// An anonymous string containing the source code.
600 pub fn filestem(&self) -> &str {
602 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
603 Input::Str { .. } => "rust_out",
607 pub fn get_input(&mut self) -> Option<&mut String> {
609 Input::File(_) => None,
610 Input::Str { ref mut input, .. } => Some(input),
614 pub fn source_name(&self) -> FileName {
616 Input::File(ref ifile) => ifile.clone().into(),
617 Input::Str { ref name, .. } => name.clone(),
622 #[derive(Clone, Hash, Debug)]
623 pub struct OutputFilenames {
624 pub out_directory: PathBuf,
626 pub single_output_file: Option<PathBuf>,
627 pub outputs: OutputTypes,
630 impl_stable_hash_via_hash!(OutputFilenames);
632 pub const RLINK_EXT: &str = "rlink";
633 pub const RUST_CGU_EXT: &str = "rcgu";
634 pub const DWARF_OBJECT_EXT: &str = "dwo";
636 impl OutputFilenames {
638 out_directory: PathBuf,
639 out_filestem: String,
640 single_output_file: Option<PathBuf>,
642 outputs: OutputTypes,
648 filestem: format!("{}{}", out_filestem, extra),
652 pub fn path(&self, flavor: OutputType) -> PathBuf {
655 .and_then(|p| p.to_owned())
656 .or_else(|| self.single_output_file.clone())
657 .unwrap_or_else(|| self.temp_path(flavor, None))
660 /// Gets the path where a compilation artifact of the given type for the
661 /// given codegen unit should be placed on disk. If codegen_unit_name is
662 /// None, a path distinct from those of any codegen unit will be generated.
663 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
664 let extension = flavor.extension();
665 self.temp_path_ext(extension, codegen_unit_name)
668 /// Like `temp_path`, but specifically for dwarf objects.
669 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
670 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
673 /// Like `temp_path`, but also supports things where there is no corresponding
674 /// OutputType, like noopt-bitcode or lto-bitcode.
675 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
676 let mut extension = String::new();
678 if let Some(codegen_unit_name) = codegen_unit_name {
679 extension.push_str(codegen_unit_name);
683 if !extension.is_empty() {
685 extension.push_str(RUST_CGU_EXT);
689 extension.push_str(ext);
692 self.with_extension(&extension)
695 pub fn with_extension(&self, extension: &str) -> PathBuf {
696 let mut path = self.out_directory.join(&self.filestem);
697 path.set_extension(extension);
701 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
702 /// mode is being used, which is the logic that this function is intended to encapsulate.
703 pub fn split_dwarf_path(
705 split_debuginfo_kind: SplitDebuginfo,
706 cgu_name: Option<&str>,
707 ) -> Option<PathBuf> {
708 let obj_out = self.temp_path(OutputType::Object, cgu_name);
709 let dwo_out = self.temp_path_dwo(cgu_name);
710 match split_debuginfo_kind {
711 SplitDebuginfo::Off => None,
712 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
713 // (pointing at the path which is being determined here). Use the path to the current
715 SplitDebuginfo::Packed => Some(obj_out),
716 // Split mode emits the DWARF into a different file, use that path.
717 SplitDebuginfo::Unpacked => Some(dwo_out),
722 pub fn host_triple() -> &'static str {
723 // Get the host triple out of the build environment. This ensures that our
724 // idea of the host triple is the same as for the set of libraries we've
725 // actually built. We can't just take LLVM's host triple because they
726 // normalize all ix86 architectures to i386.
728 // Instead of grabbing the host triple (for the current host), we grab (at
729 // compile time) the target triple that this rustc is built with and
730 // calling that (at runtime) the host triple.
731 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
734 impl Default for Options {
735 fn default() -> Options {
737 crate_types: Vec::new(),
738 optimize: OptLevel::No,
739 debuginfo: DebugInfo::None,
740 lint_opts: Vec::new(),
742 describe_lints: false,
743 output_types: OutputTypes(BTreeMap::new()),
744 search_paths: vec![],
746 target_triple: TargetTriple::from_triple(host_triple()),
749 debugging_opts: basic_debugging_options(),
751 borrowck_mode: BorrowckMode::Migrate,
752 cg: basic_codegen_options(),
753 error_format: ErrorOutputType::default(),
754 externs: Externs(BTreeMap::new()),
755 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
759 unstable_features: UnstableFeatures::Disallow,
760 debug_assertions: true,
761 actually_rustdoc: false,
762 trimmed_def_paths: TrimmedDefPaths::default(),
763 cli_forced_codegen_units: None,
764 cli_forced_thinlto_off: false,
765 remap_path_prefix: Vec::new(),
766 edition: DEFAULT_EDITION,
767 json_artifact_notifications: false,
774 /// Returns `true` if there is a reason to build the dep graph.
775 pub fn build_dep_graph(&self) -> bool {
776 self.incremental.is_some()
777 || self.debugging_opts.dump_dep_graph
778 || self.debugging_opts.query_dep_graph
782 pub fn enable_dep_node_debug_strs(&self) -> bool {
783 cfg!(debug_assertions)
784 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
787 pub fn file_path_mapping(&self) -> FilePathMapping {
788 FilePathMapping::new(self.remap_path_prefix.clone())
791 /// Returns `true` if there will be an output file generated.
792 pub fn will_create_output_file(&self) -> bool {
793 !self.debugging_opts.parse_only && // The file is just being parsed
794 !self.debugging_opts.ls // The file is just being queried
798 pub fn share_generics(&self) -> bool {
799 match self.debugging_opts.share_generics {
800 Some(setting) => setting,
801 None => match self.optimize {
802 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
803 OptLevel::Default | OptLevel::Aggressive => false,
809 impl DebuggingOptions {
810 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
813 treat_err_as_bug: self.treat_err_as_bug,
814 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
815 report_delayed_bugs: self.report_delayed_bugs,
816 macro_backtrace: self.macro_backtrace,
817 deduplicate_diagnostics: self.deduplicate_diagnostics,
821 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
822 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
826 // The type of entry function, so users can have their own entry functions
827 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
828 pub enum EntryFnType {
833 impl_stable_hash_via_hash!(EntryFnType);
835 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
845 impl_stable_hash_via_hash!(CrateType);
847 #[derive(Clone, Hash)]
854 pub fn is_empty(&self) -> bool {
856 Passes::Some(ref v) => v.is_empty(),
857 Passes::All => false,
862 pub const fn default_lib_output() -> CrateType {
866 pub fn default_configuration(sess: &Session) -> CrateConfig {
867 let end = &sess.target.endian;
868 let arch = &sess.target.arch;
869 let wordsz = sess.target.pointer_width.to_string();
870 let os = &sess.target.os;
871 let env = &sess.target.env;
872 let vendor = &sess.target.vendor;
873 let min_atomic_width = sess.target.min_atomic_width();
874 let max_atomic_width = sess.target.max_atomic_width();
875 let atomic_cas = sess.target.atomic_cas;
876 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
880 let mut ret = FxHashSet::default();
881 ret.reserve(6); // the minimum number of insertions
883 ret.insert((sym::target_os, Some(Symbol::intern(os))));
884 if let Some(ref fam) = sess.target.os_family {
885 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
886 if fam == "windows" {
887 ret.insert((sym::windows, None));
888 } else if fam == "unix" {
889 ret.insert((sym::unix, None));
892 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
893 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
894 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
895 ret.insert((sym::target_env, Some(Symbol::intern(env))));
896 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
897 if sess.target.has_elf_tls {
898 ret.insert((sym::target_thread_local, None));
900 for &(i, align) in &[
901 (8, layout.i8_align.abi),
902 (16, layout.i16_align.abi),
903 (32, layout.i32_align.abi),
904 (64, layout.i64_align.abi),
905 (128, layout.i128_align.abi),
907 if i >= min_atomic_width && i <= max_atomic_width {
908 let mut insert_atomic = |s, align: Align| {
909 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
911 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
913 if align.bits() == i {
914 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
917 let s = i.to_string();
918 insert_atomic(&s, align);
920 insert_atomic("ptr", layout.pointer_align.abi);
925 let panic_strategy = sess.panic_strategy();
926 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
928 for s in sess.opts.debugging_opts.sanitizer {
929 let symbol = Symbol::intern(&s.to_string());
930 ret.insert((sym::sanitize, Some(symbol)));
933 if sess.opts.debug_assertions {
934 ret.insert((sym::debug_assertions, None));
936 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
937 ret.insert((sym::proc_macro, None));
942 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
943 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
944 /// but the symbol interner is not yet set up then, so we must convert it later.
945 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
946 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
949 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
950 // Combine the configuration requested by the session (command line) with
951 // some default and generated configuration items.
952 let default_cfg = default_configuration(sess);
953 // If the user wants a test runner, then add the test cfg.
955 user_cfg.insert((sym::test, None));
957 user_cfg.extend(default_cfg.iter().cloned());
961 pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
962 let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
963 let target = target_result.unwrap_or_else(|e| {
967 "Error loading target specification: {}. \
968 Use `--print target-list` for a list of built-in targets",
974 if !matches!(target.pointer_width, 16 | 32 | 64) {
978 "target specification was invalid: \
979 unrecognized target-pointer-width {}",
988 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
989 pub enum OptionStability {
994 pub struct RustcOptGroup {
995 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
996 pub name: &'static str,
997 pub stability: OptionStability,
1000 impl RustcOptGroup {
1001 pub fn is_stable(&self) -> bool {
1002 self.stability == OptionStability::Stable
1005 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1007 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1009 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1012 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1014 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1016 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1020 // The `opt` local module holds wrappers around the `getopts` API that
1021 // adds extra rustc-specific metadata to each option; such metadata
1022 // is exposed by . The public
1023 // functions below ending with `_u` are the functions that return
1024 // *unstable* options, i.e., options that are only enabled when the
1025 // user also passes the `-Z unstable-options` debugging flag.
1027 // The `fn flag*` etc below are written so that we can use them
1028 // in the future; do not warn about them not being used right now.
1029 #![allow(dead_code)]
1031 use super::RustcOptGroup;
1033 pub type R = RustcOptGroup;
1034 pub type S = &'static str;
1036 fn stable<F>(name: S, f: F) -> R
1038 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1040 RustcOptGroup::stable(name, f)
1043 fn unstable<F>(name: S, f: F) -> R
1045 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1047 RustcOptGroup::unstable(name, f)
1050 fn longer(a: S, b: S) -> S {
1051 if a.len() > b.len() { a } else { b }
1054 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1055 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1057 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1058 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1060 pub fn flag_s(a: S, b: S, c: S) -> R {
1061 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1063 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1064 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1066 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1067 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1070 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1071 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1073 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1074 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1076 pub fn flag(a: S, b: S, c: S) -> R {
1077 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1079 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1080 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1082 pub fn flagmulti(a: S, b: S, c: S) -> R {
1083 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1087 /// Returns the "short" subset of the rustc command line options,
1088 /// including metadata for each option, such as whether the option is
1089 /// part of the stable long-term interface for rustc.
1090 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1092 opt::flag_s("h", "help", "Display this message"),
1093 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1097 "Add a directory to the library search path. The
1098 optional KIND can be one of dependency, crate, native,
1099 framework, or all (the default).",
1105 "Link the generated crate(s) to the specified native
1106 library NAME. The optional KIND can be one of
1107 static, framework, or dylib (the default).",
1110 make_crate_type_option(),
1111 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1115 "Specify which edition of the compiler to use when compiling code.",
1121 "Comma separated list of types of output for \
1122 the compiler to emit",
1123 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1128 "Compiler information to print on stdout",
1129 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1130 target-cpus|target-features|relocation-models|\
1131 code-models|tls-models|target-spec-json|native-static-libs]",
1133 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1134 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1135 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1139 "Write output to compiler-chosen filename \
1146 "Provide a detailed explanation of an error \
1150 opt::flag_s("", "test", "Build a test harness"),
1151 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1152 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1153 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1154 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1155 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1159 "Set the most restrictive lint level. \
1160 More restrictive lints are capped at this \
1164 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1165 opt::flag_s("V", "version", "Print version info and exit"),
1166 opt::flag_s("v", "verbose", "Use verbose output"),
1170 /// Returns all rustc command line options, including metadata for
1171 /// each option, such as whether the option is part of the stable
1172 /// long-term interface for rustc.
1173 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1174 let mut opts = rustc_short_optgroups();
1179 "Specify where an external rust library is located",
1185 "Location where an external crate dependency is specified",
1188 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1189 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1193 "How errors and other messages are produced",
1196 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1200 "Configure coloring of output:
1201 auto = colorize, if output goes to a tty (default);
1202 always = always colorize output;
1203 never = never colorize output",
1204 "auto|always|never",
1209 "Pretty-print the input instead of compiling;
1210 valid types are: `normal` (un-annotated source),
1211 `expanded` (crates expanded), or
1212 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1217 "remap-path-prefix",
1218 "Remap source names in all output (compiler messages and output files)",
1225 pub fn get_cmd_lint_options(
1226 matches: &getopts::Matches,
1227 error_format: ErrorOutputType,
1228 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1229 let mut lint_opts_with_position = vec![];
1230 let mut describe_lints = false;
1232 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1233 for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1234 let arg_pos = if let lint::Forbid = level {
1235 // HACK: forbid is always specified last, so it can't be overridden.
1236 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1237 // fixed and `forbid` works as expected.
1242 if lint_name == "help" {
1243 describe_lints = true;
1245 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1250 lint_opts_with_position.sort_by_key(|x| x.0);
1251 let lint_opts = lint_opts_with_position
1254 .map(|(_, lint_name, level)| (lint_name, level))
1257 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1258 lint::Level::from_str(&cap)
1259 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1261 (lint_opts, describe_lints, lint_cap)
1264 /// Parses the `--color` flag.
1265 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1266 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1267 Some("auto") => ColorConfig::Auto,
1268 Some("always") => ColorConfig::Always,
1269 Some("never") => ColorConfig::Never,
1271 None => ColorConfig::Auto,
1273 Some(arg) => early_error(
1274 ErrorOutputType::default(),
1276 "argument for `--color` must be auto, \
1277 always or never (instead was `{}`)",
1284 /// Parse the `--json` flag.
1286 /// The first value returned is how to render JSON diagnostics, and the second
1287 /// is whether or not artifact notifications are enabled.
1288 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1289 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1290 HumanReadableErrorType::Default;
1291 let mut json_color = ColorConfig::Never;
1292 let mut json_artifact_notifications = false;
1293 for option in matches.opt_strs("json") {
1294 // For now conservatively forbid `--color` with `--json` since `--json`
1295 // won't actually be emitting any colors and anything colorized is
1296 // embedded in a diagnostic message anyway.
1297 if matches.opt_str("color").is_some() {
1299 ErrorOutputType::default(),
1300 "cannot specify the `--color` option with `--json`",
1304 for sub_option in option.split(',') {
1306 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1307 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1308 "artifacts" => json_artifact_notifications = true,
1310 ErrorOutputType::default(),
1311 &format!("unknown `--json` option `{}`", s),
1316 (json_rendered(json_color), json_artifact_notifications)
1319 /// Parses the `--error-format` flag.
1320 pub fn parse_error_format(
1321 matches: &getopts::Matches,
1323 json_rendered: HumanReadableErrorType,
1324 ) -> ErrorOutputType {
1325 // We need the `opts_present` check because the driver will send us Matches
1326 // with only stable options if no unstable options are used. Since error-format
1327 // is unstable, it will not be present. We have to use `opts_present` not
1328 // `opt_present` because the latter will panic.
1329 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1330 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1331 None | Some("human") => {
1332 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1334 Some("human-annotate-rs") => {
1335 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1337 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1338 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1339 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1341 Some(arg) => early_error(
1342 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1344 "argument for `--error-format` must be `human`, `json` or \
1345 `short` (instead was `{}`)",
1351 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1354 match error_format {
1355 ErrorOutputType::Json { .. } => {}
1357 // Conservatively require that the `--json` argument is coupled with
1358 // `--error-format=json`. This means that `--json` is specified we
1359 // should actually be emitting JSON blobs.
1360 _ if !matches.opt_strs("json").is_empty() => {
1362 ErrorOutputType::default(),
1363 "using `--json` requires also using `--error-format=json`",
1373 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1374 let edition = match matches.opt_str("edition") {
1375 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1377 ErrorOutputType::default(),
1379 "argument for `--edition` must be one of: \
1380 {}. (instead was `{}`)",
1381 EDITION_NAME_LIST, arg
1385 None => DEFAULT_EDITION,
1388 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1390 ErrorOutputType::default(),
1392 "edition {} is unstable and only available with -Z unstable-options.",
1401 fn check_debug_option_stability(
1402 debugging_opts: &DebuggingOptions,
1403 error_format: ErrorOutputType,
1404 json_rendered: HumanReadableErrorType,
1406 if !debugging_opts.unstable_options {
1407 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1409 ErrorOutputType::Json { pretty: false, json_rendered },
1410 "`--error-format=pretty-json` is unstable",
1413 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1417 ErrorOutputType::Json { pretty: false, json_rendered },
1418 "`--error-format=human-annotate-rs` is unstable",
1424 fn parse_output_types(
1425 debugging_opts: &DebuggingOptions,
1426 matches: &getopts::Matches,
1427 error_format: ErrorOutputType,
1429 let mut output_types = BTreeMap::new();
1430 if !debugging_opts.parse_only {
1431 for list in matches.opt_strs("emit") {
1432 for output_type in list.split(',') {
1433 let (shorthand, path) = match output_type.split_once('=') {
1434 None => (output_type, None),
1435 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1437 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1441 "unknown emission type: `{}` - expected one of: {}",
1443 OutputType::shorthands_display(),
1447 output_types.insert(output_type, path);
1451 if output_types.is_empty() {
1452 output_types.insert(OutputType::Exe, None);
1454 OutputTypes(output_types)
1457 fn should_override_cgus_and_disable_thinlto(
1458 output_types: &OutputTypes,
1459 matches: &getopts::Matches,
1460 error_format: ErrorOutputType,
1461 mut codegen_units: Option<usize>,
1462 ) -> (bool, Option<usize>) {
1463 let mut disable_thinlto = false;
1464 // Issue #30063: if user requests LLVM-related output to one
1465 // particular path, disable codegen-units.
1466 let incompatible: Vec<_> = output_types
1469 .map(|ot_path| ot_path.0)
1470 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1471 .map(|ot| ot.shorthand())
1473 if !incompatible.is_empty() {
1474 match codegen_units {
1475 Some(n) if n > 1 => {
1476 if matches.opt_present("o") {
1477 for ot in &incompatible {
1481 "`--emit={}` with `-o` incompatible with \
1482 `-C codegen-units=N` for N > 1",
1487 early_warn(error_format, "resetting to default -C codegen-units=1");
1488 codegen_units = Some(1);
1489 disable_thinlto = true;
1493 codegen_units = Some(1);
1494 disable_thinlto = true;
1499 if codegen_units == Some(0) {
1500 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1503 (disable_thinlto, codegen_units)
1506 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1507 if debugging_opts.threads == 0 {
1508 early_error(error_format, "value for threads must be a positive non-zero integer");
1511 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1512 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1516 fn collect_print_requests(
1517 cg: &mut CodegenOptions,
1518 dopts: &mut DebuggingOptions,
1519 matches: &getopts::Matches,
1520 error_format: ErrorOutputType,
1521 ) -> Vec<PrintRequest> {
1522 let mut prints = Vec::<PrintRequest>::new();
1523 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1524 prints.push(PrintRequest::TargetCPUs);
1525 cg.target_cpu = None;
1527 if cg.target_feature == "help" {
1528 prints.push(PrintRequest::TargetFeatures);
1529 cg.target_feature = String::new();
1532 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1533 "crate-name" => PrintRequest::CrateName,
1534 "file-names" => PrintRequest::FileNames,
1535 "sysroot" => PrintRequest::Sysroot,
1536 "target-libdir" => PrintRequest::TargetLibdir,
1537 "cfg" => PrintRequest::Cfg,
1538 "target-list" => PrintRequest::TargetList,
1539 "target-cpus" => PrintRequest::TargetCPUs,
1540 "target-features" => PrintRequest::TargetFeatures,
1541 "relocation-models" => PrintRequest::RelocationModels,
1542 "code-models" => PrintRequest::CodeModels,
1543 "tls-models" => PrintRequest::TlsModels,
1544 "native-static-libs" => PrintRequest::NativeStaticLibs,
1545 "target-spec-json" => {
1546 if dopts.unstable_options {
1547 PrintRequest::TargetSpec
1551 "the `-Z unstable-options` flag must also be passed to \
1552 enable the target-spec-json print option",
1556 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1562 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1563 match matches.opt_str("target") {
1564 Some(target) if target.ends_with(".json") => {
1565 let path = Path::new(&target);
1566 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1567 early_error(error_format, &format!("target file {:?} does not exist", path))
1570 Some(target) => TargetTriple::TargetTriple(target),
1571 _ => TargetTriple::from_triple(host_triple()),
1576 matches: &getopts::Matches,
1577 cg: &CodegenOptions,
1578 error_format: ErrorOutputType,
1580 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1581 // to use them interchangeably. However, because they're technically different flags,
1582 // we need to work out manually which should take precedence if both are supplied (i.e.
1583 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1584 // comparing them. Note that if a flag is not found, its position will be `None`, which
1585 // always compared less than `Some(_)`.
1586 let max_o = matches.opt_positions("O").into_iter().max();
1590 .flat_map(|(i, s)| {
1591 // NB: This can match a string without `=`.
1592 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1598 match cg.opt_level.as_ref() {
1599 "0" => OptLevel::No,
1600 "1" => OptLevel::Less,
1601 "2" => OptLevel::Default,
1602 "3" => OptLevel::Aggressive,
1603 "s" => OptLevel::Size,
1604 "z" => OptLevel::SizeMin,
1609 "optimization level needs to be \
1610 between 0-3, s or z (instead was `{}`)",
1619 fn select_debuginfo(
1620 matches: &getopts::Matches,
1621 cg: &CodegenOptions,
1622 error_format: ErrorOutputType,
1624 let max_g = matches.opt_positions("g").into_iter().max();
1628 .flat_map(|(i, s)| {
1629 // NB: This can match a string without `=`.
1630 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1636 match cg.debuginfo {
1637 0 => DebugInfo::None,
1638 1 => DebugInfo::Limited,
1639 2 => DebugInfo::Full,
1644 "debug info level needs to be between \
1645 0-2 (instead was `{}`)",
1655 matches: &getopts::Matches,
1656 error_format: ErrorOutputType,
1657 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1662 // Parse string of the form "[KIND=]lib[:new_name]",
1663 // where KIND is one of "dylib", "framework", "static".
1664 let (name, kind) = match s.split_once('=') {
1665 None => (s, NativeLibKind::Unspecified),
1666 Some((kind, name)) => {
1667 let kind = match kind {
1668 "dylib" => NativeLibKind::Dylib,
1669 "framework" => NativeLibKind::Framework,
1670 "static" => NativeLibKind::StaticBundle,
1671 "static-nobundle" => NativeLibKind::StaticNoBundle,
1676 "unknown library kind `{}`, expected \
1677 one of dylib, framework, or static",
1683 (name.to_string(), kind)
1686 if kind == NativeLibKind::StaticNoBundle
1687 && !nightly_options::match_is_nightly_build(matches)
1691 "the library kind 'static-nobundle' is only \
1692 accepted on the nightly compiler",
1695 let (name, new_name) = match name.split_once(':') {
1696 None => (name, None),
1697 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1699 (name, new_name, kind)
1704 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1705 match dopts.borrowck.as_ref() {
1706 "migrate" => BorrowckMode::Migrate,
1707 "mir" => BorrowckMode::Mir,
1708 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1712 pub fn parse_externs(
1713 matches: &getopts::Matches,
1714 debugging_opts: &DebuggingOptions,
1715 error_format: ErrorOutputType,
1717 let is_unstable_enabled = debugging_opts.unstable_options;
1718 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1719 for arg in matches.opt_strs("extern") {
1720 let (name, path) = match arg.split_once('=') {
1721 None => (arg, None),
1722 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1724 let (options, name) = match name.split_once(':') {
1725 None => (None, name),
1726 Some((opts, name)) => (Some(opts), name.to_string()),
1729 let path = path.map(|p| CanonicalizedPath::new(p));
1731 let entry = externs.entry(name.to_owned());
1733 use std::collections::btree_map::Entry;
1735 let entry = if let Some(path) = path {
1736 // --extern prelude_name=some_file.rlib
1738 Entry::Vacant(vacant) => {
1739 let files = BTreeSet::from_iter(iter::once(path));
1740 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1742 Entry::Occupied(occupied) => {
1743 let ext_ent = occupied.into_mut();
1745 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1749 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1752 // Exact paths take precedence over search directories.
1753 let files = BTreeSet::from_iter(iter::once(path));
1754 *location = ExternLocation::ExactPaths(files);
1761 // --extern prelude_name
1763 Entry::Vacant(vacant) => {
1764 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1766 Entry::Occupied(occupied) => {
1767 // Ignore if already specified.
1773 let mut is_private_dep = false;
1774 let mut add_prelude = true;
1775 if let Some(opts) = options {
1776 if !is_unstable_enabled {
1779 "the `-Z unstable-options` flag must also be passed to \
1780 enable `--extern options",
1783 for opt in opts.split(',') {
1785 "priv" => is_private_dep = true,
1787 if let ExternLocation::ExactPaths(_) = &entry.location {
1788 add_prelude = false;
1792 "the `noprelude` --extern option requires a file path",
1796 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1801 // Crates start out being not private, and go to being private `priv`
1803 entry.is_private_dep |= is_private_dep;
1804 // If any flag is missing `noprelude`, then add to the prelude.
1805 entry.add_prelude |= add_prelude;
1810 fn parse_extern_dep_specs(
1811 matches: &getopts::Matches,
1812 debugging_opts: &DebuggingOptions,
1813 error_format: ErrorOutputType,
1814 ) -> ExternDepSpecs {
1815 let is_unstable_enabled = debugging_opts.unstable_options;
1816 let mut map = BTreeMap::new();
1818 for arg in matches.opt_strs("extern-location") {
1819 if !is_unstable_enabled {
1822 "`--extern-location` option is unstable: set `-Z unstable-options`",
1826 let mut parts = arg.splitn(2, '=');
1827 let name = parts.next().unwrap_or_else(|| {
1828 early_error(error_format, "`--extern-location` value must not be empty")
1830 let loc = parts.next().unwrap_or_else(|| {
1833 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1837 let locparts: Vec<_> = loc.split(":").collect();
1838 let spec = match &locparts[..] {
1840 // Don't want `:` split string
1841 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1842 early_error(error_format, "`--extern-location`: missing `raw` location")
1844 ExternDepSpec::Raw(raw.to_string())
1847 // Don't want `:` split string
1848 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1849 early_error(error_format, "`--extern-location`: missing `json` location")
1851 let json = json::from_str(raw).unwrap_or_else(|_| {
1854 &format!("`--extern-location`: malformed json location `{}`", raw),
1857 ExternDepSpec::Json(json)
1859 [bad, ..] => early_error(
1861 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1863 [] => early_error(error_format, "missing location specification"),
1866 map.insert(name.to_string(), spec);
1869 ExternDepSpecs::new(map)
1872 fn parse_remap_path_prefix(
1873 matches: &getopts::Matches,
1874 error_format: ErrorOutputType,
1875 ) -> Vec<(PathBuf, PathBuf)> {
1877 .opt_strs("remap-path-prefix")
1879 .map(|remap| match remap.rsplit_once('=') {
1880 None => early_error(
1882 "--remap-path-prefix must contain '=' between FROM and TO",
1884 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1889 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1890 let color = parse_color(matches);
1892 let edition = parse_crate_edition(matches);
1894 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1896 let error_format = parse_error_format(matches, color, json_rendered);
1898 let unparsed_crate_types = matches.opt_strs("crate-type");
1899 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1900 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1902 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1904 let mut debugging_opts = build_debugging_options(matches, error_format);
1905 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1907 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1909 let mut cg = build_codegen_options(matches, error_format);
1910 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1917 check_thread_count(&debugging_opts, error_format);
1919 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1921 if debugging_opts.profile && incremental.is_some() {
1924 "can't instrument with gcov profiling when compiling incrementally",
1927 if debugging_opts.profile {
1928 match codegen_units {
1930 None => codegen_units = Some(1),
1931 Some(_) => early_error(
1933 "can't instrument with gcov profiling with multiple codegen units",
1938 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1941 "options `-C profile-generate` and `-C profile-use` are exclusive",
1945 if debugging_opts.instrument_coverage.is_some()
1946 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
1948 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1951 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1952 or `-C profile-generate`",
1956 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
1957 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
1958 // multiple runs, including some changes to source code; so mangled names must be consistent
1959 // across compilations.
1960 match debugging_opts.symbol_mangling_version {
1962 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
1964 Some(SymbolManglingVersion::Legacy) => {
1967 "-Z instrument-coverage requires symbol mangling version `v0`, \
1968 but `-Z symbol-mangling-version=legacy` was specified",
1971 Some(SymbolManglingVersion::V0) => {}
1975 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
1976 debugging_opts.graphviz_font = graphviz_font;
1979 if !cg.embed_bitcode {
1981 LtoCli::No | LtoCli::Unspecified => {}
1982 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1984 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1989 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1993 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1994 let target_triple = parse_target_triple(matches, error_format);
1995 let opt_level = parse_opt_level(matches, &cg, error_format);
1996 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1997 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1998 // for more details.
1999 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2000 let debuginfo = select_debuginfo(matches, &cg, error_format);
2002 let mut search_paths = vec![];
2003 for s in &matches.opt_strs("L") {
2004 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2007 let libs = parse_libs(matches, error_format);
2009 let test = matches.opt_present("test");
2011 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2013 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2014 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2017 let externs = parse_externs(matches, &debugging_opts, error_format);
2018 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2020 let crate_name = matches.opt_str("crate-name");
2022 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2024 let pretty = parse_pretty(matches, &debugging_opts, error_format);
2026 if !debugging_opts.unstable_options
2027 && !target_triple.triple().contains("apple")
2028 && cg.split_debuginfo.is_some()
2031 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2037 optimize: opt_level,
2044 maybe_sysroot: sysroot_opt,
2054 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2060 actually_rustdoc: false,
2061 trimmed_def_paths: TrimmedDefPaths::default(),
2062 cli_forced_codegen_units: codegen_units,
2063 cli_forced_thinlto_off: disable_thinlto,
2066 json_artifact_notifications,
2072 matches: &getopts::Matches,
2073 debugging_opts: &DebuggingOptions,
2074 efmt: ErrorOutputType,
2075 ) -> Option<PpMode> {
2076 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
2078 let first = match (name, extended) {
2079 ("normal", _) => Source(PpSourceMode::Normal),
2080 ("identified", _) => Source(PpSourceMode::Identified),
2081 ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
2082 ("expanded", _) => Source(PpSourceMode::Expanded),
2083 ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
2084 ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
2085 ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
2086 ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
2087 ("hir", true) => Hir(PpHirMode::Normal),
2088 ("hir,identified", true) => Hir(PpHirMode::Identified),
2089 ("hir,typed", true) => Hir(PpHirMode::Typed),
2090 ("hir-tree", true) => HirTree,
2091 ("thir-tree", true) => ThirTree,
2092 ("mir", true) => Mir,
2093 ("mir-cfg", true) => MirCFG,
2099 "argument to `unpretty` must be one of `normal`, \
2100 `expanded`, `identified`, `expanded,identified`, \
2101 `expanded,hygiene`, `everybody_loops`, \
2102 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2103 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2111 "argument to `pretty` must be one of `normal`, \
2112 `expanded`, `identified`, or `expanded,identified`; got {}",
2119 tracing::debug!("got unpretty option: {:?}", first);
2123 if debugging_opts.unstable_options {
2124 if let Some(a) = matches.opt_default("pretty", "normal") {
2125 // stable pretty-print variants only
2126 return Some(parse_pretty_inner(efmt, &a, false));
2130 debugging_opts.unpretty.as_ref().map(|a| {
2131 // extended with unstable pretty-print variants
2132 parse_pretty_inner(efmt, &a, true)
2136 pub fn make_crate_type_option() -> RustcOptGroup {
2140 "Comma separated list of types of crates
2141 for the compiler to emit",
2142 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2146 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2147 let mut crate_types: Vec<CrateType> = Vec::new();
2148 for unparsed_crate_type in &list_list {
2149 for part in unparsed_crate_type.split(',') {
2150 let new_part = match part {
2151 "lib" => default_lib_output(),
2152 "rlib" => CrateType::Rlib,
2153 "staticlib" => CrateType::Staticlib,
2154 "dylib" => CrateType::Dylib,
2155 "cdylib" => CrateType::Cdylib,
2156 "bin" => CrateType::Executable,
2157 "proc-macro" => CrateType::ProcMacro,
2158 _ => return Err(format!("unknown crate type: `{}`", part)),
2160 if !crate_types.contains(&new_part) {
2161 crate_types.push(new_part)
2169 pub mod nightly_options {
2170 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2171 use crate::early_error;
2172 use rustc_feature::UnstableFeatures;
2174 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2175 match_is_nightly_build(matches)
2176 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2179 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2180 is_nightly_build(matches.opt_str("crate-name").as_deref())
2183 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2184 UnstableFeatures::from_environment(krate).is_nightly_build()
2187 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2188 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2189 let really_allows_unstable_options = match_is_nightly_build(matches);
2191 for opt in flags.iter() {
2192 if opt.stability == OptionStability::Stable {
2195 if !matches.opt_present(opt.name) {
2198 if opt.name != "Z" && !has_z_unstable_option {
2200 ErrorOutputType::default(),
2202 "the `-Z unstable-options` flag must also be passed to enable \
2208 if really_allows_unstable_options {
2211 match opt.stability {
2212 OptionStability::Unstable => {
2214 "the option `{}` is only accepted on the \
2218 early_error(ErrorOutputType::default(), &msg);
2220 OptionStability::Stable => {}
2226 impl fmt::Display for CrateType {
2227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2229 CrateType::Executable => "bin".fmt(f),
2230 CrateType::Dylib => "dylib".fmt(f),
2231 CrateType::Rlib => "rlib".fmt(f),
2232 CrateType::Staticlib => "staticlib".fmt(f),
2233 CrateType::Cdylib => "cdylib".fmt(f),
2234 CrateType::ProcMacro => "proc-macro".fmt(f),
2239 #[derive(Copy, Clone, PartialEq, Debug)]
2240 pub enum PpSourceMode {
2241 /// `--pretty=normal`
2243 /// `-Zunpretty=everybody_loops`
2245 /// `--pretty=expanded`
2247 /// `--pretty=identified`
2249 /// `--pretty=expanded,identified`
2251 /// `--pretty=expanded,hygiene`
2255 #[derive(Copy, Clone, PartialEq, Debug)]
2256 pub enum PpAstTreeMode {
2257 /// `-Zunpretty=ast`
2259 /// `-Zunpretty=ast,expanded`
2263 #[derive(Copy, Clone, PartialEq, Debug)]
2264 pub enum PpHirMode {
2265 /// `-Zunpretty=hir`
2267 /// `-Zunpretty=hir,identified`
2269 /// `-Zunpretty=hir,typed`
2273 #[derive(Copy, Clone, PartialEq, Debug)]
2275 /// Options that print the source code, i.e.
2276 /// `--pretty` and `-Zunpretty=everybody_loops`
2277 Source(PpSourceMode),
2278 AstTree(PpAstTreeMode),
2279 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2281 /// `-Zunpretty=hir-tree`
2283 /// `-Zunpretty=thir-tree`
2285 /// `-Zunpretty=mir`
2287 /// `-Zunpretty=mir-cfg`
2292 pub fn needs_ast_map(&self) -> bool {
2294 use PpSourceMode::*;
2296 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2298 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2299 | AstTree(PpAstTreeMode::Expanded)
2308 pub fn needs_analysis(&self) -> bool {
2310 matches!(*self, Mir | MirCFG | ThirTree)
2314 /// Command-line arguments passed to the compiler have to be incorporated with
2315 /// the dependency tracking system for incremental compilation. This module
2316 /// provides some utilities to make this more convenient.
2318 /// The values of all command-line arguments that are relevant for dependency
2319 /// tracking are hashed into a single value that determines whether the
2320 /// incremental compilation cache can be re-used or not. This hashing is done
2321 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2322 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2323 /// the hash of which is order dependent, but we might not want the order of
2324 /// arguments to make a difference for the hash).
2326 /// However, since the value provided by `Hash::hash` often *is* suitable,
2327 /// especially for primitive types, there is the
2328 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2329 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2330 /// we have an opt-in scheme here, so one is hopefully forced to think about
2331 /// how the hash should be calculated when adding a new command-line argument.
2332 crate mod dep_tracking {
2334 CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2335 LtoCli, OptLevel, OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm,
2336 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2339 use crate::options::WasiExecModel;
2340 use crate::utils::NativeLibKind;
2341 use rustc_feature::UnstableFeatures;
2342 use rustc_span::edition::Edition;
2343 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2344 use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
2345 use std::collections::hash_map::DefaultHasher;
2346 use std::collections::BTreeMap;
2347 use std::hash::Hash;
2348 use std::num::NonZeroUsize;
2349 use std::path::PathBuf;
2351 pub trait DepTrackingHash {
2352 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2355 macro_rules! impl_dep_tracking_hash_via_hash {
2357 impl DepTrackingHash for $t {
2358 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2359 Hash::hash(self, hasher);
2365 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2367 impl DepTrackingHash for Vec<$t> {
2368 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2369 let mut elems: Vec<&$t> = self.iter().collect();
2371 Hash::hash(&elems.len(), hasher);
2372 for (index, elem) in elems.iter().enumerate() {
2373 Hash::hash(&index, hasher);
2374 DepTrackingHash::hash(*elem, hasher, error_format);
2381 impl_dep_tracking_hash_via_hash!(bool);
2382 impl_dep_tracking_hash_via_hash!(usize);
2383 impl_dep_tracking_hash_via_hash!(u64);
2384 impl_dep_tracking_hash_via_hash!(String);
2385 impl_dep_tracking_hash_via_hash!(PathBuf);
2386 impl_dep_tracking_hash_via_hash!(lint::Level);
2387 impl_dep_tracking_hash_via_hash!(Option<bool>);
2388 impl_dep_tracking_hash_via_hash!(Option<usize>);
2389 impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
2390 impl_dep_tracking_hash_via_hash!(Option<String>);
2391 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2392 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2393 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2394 impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2395 impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
2396 impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2397 impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>);
2398 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2399 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2400 impl_dep_tracking_hash_via_hash!(Option<InstrumentCoverage>);
2401 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2402 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2403 impl_dep_tracking_hash_via_hash!(CrateType);
2404 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2405 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2406 impl_dep_tracking_hash_via_hash!(RelroLevel);
2407 impl_dep_tracking_hash_via_hash!(Passes);
2408 impl_dep_tracking_hash_via_hash!(OptLevel);
2409 impl_dep_tracking_hash_via_hash!(LtoCli);
2410 impl_dep_tracking_hash_via_hash!(DebugInfo);
2411 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2412 impl_dep_tracking_hash_via_hash!(OutputTypes);
2413 impl_dep_tracking_hash_via_hash!(NativeLibKind);
2414 impl_dep_tracking_hash_via_hash!(SanitizerSet);
2415 impl_dep_tracking_hash_via_hash!(CFGuard);
2416 impl_dep_tracking_hash_via_hash!(TargetTriple);
2417 impl_dep_tracking_hash_via_hash!(Edition);
2418 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2419 impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
2420 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2421 impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
2422 impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2423 impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
2425 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2426 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2427 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2428 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2429 impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
2430 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2432 impl<T1, T2> DepTrackingHash for (T1, T2)
2434 T1: DepTrackingHash,
2435 T2: DepTrackingHash,
2437 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2438 Hash::hash(&0, hasher);
2439 DepTrackingHash::hash(&self.0, hasher, error_format);
2440 Hash::hash(&1, hasher);
2441 DepTrackingHash::hash(&self.1, hasher, error_format);
2445 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2447 T1: DepTrackingHash,
2448 T2: DepTrackingHash,
2449 T3: DepTrackingHash,
2451 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2452 Hash::hash(&0, hasher);
2453 DepTrackingHash::hash(&self.0, hasher, error_format);
2454 Hash::hash(&1, hasher);
2455 DepTrackingHash::hash(&self.1, hasher, error_format);
2456 Hash::hash(&2, hasher);
2457 DepTrackingHash::hash(&self.2, hasher, error_format);
2461 // This is a stable hash because BTreeMap is a sorted container
2463 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2464 hasher: &mut DefaultHasher,
2465 error_format: ErrorOutputType,
2467 for (key, sub_hash) in sub_hashes {
2468 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2469 // the keys, as they are just plain strings
2470 Hash::hash(&key.len(), hasher);
2471 Hash::hash(key, hasher);
2472 sub_hash.hash(hasher, error_format);