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, NativeLib, 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, TargetWarnings};
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::RealFileName;
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};
36 use std::iter::{self, FromIterator};
37 use std::path::{Path, PathBuf};
38 use std::str::{self, FromStr};
40 /// The different settings that the `-Z strip` flag can have.
41 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
43 /// Do not strip at all.
49 /// Strip all symbols.
53 /// The different settings that the `-C control-flow-guard` flag can have.
54 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
56 /// Do not emit Control Flow Guard metadata or checks.
59 /// Emit Control Flow Guard metadata but no checks.
62 /// Emit Control Flow Guard metadata and checks.
66 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
76 impl_stable_hash_via_hash!(OptLevel);
78 /// This is what the `LtoCli` values get mapped to after resolving defaults and
79 /// and taking other command line options into account.
81 /// Note that linker plugin-based LTO is a different mechanism entirely.
82 #[derive(Clone, PartialEq)]
84 /// Don't do any LTO whatsoever.
87 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
90 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
91 /// only relevant if multiple CGUs are used.
94 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
98 /// The different settings that the `-C lto` flag can have.
99 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
111 /// No `-C lto` flag passed
115 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
116 /// document highlighting each span of every statement (including terminators). `Terminator` and
117 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
118 /// computed span for the block, representing the entire range, covering the block's terminator and
119 /// all of its statements.
120 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
121 pub enum MirSpanview {
122 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
124 /// `-Z dump_mir_spanview=terminator`
126 /// `-Z dump_mir_spanview=block`
130 /// The different settings that the `-Z instrument-coverage` flag can have.
132 /// Coverage instrumentation now supports combining `-Z instrument-coverage`
133 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
134 /// and higher). Nevertheless, there are many variables, depending on options
135 /// selected, code structure, and enabled attributes. If errors are encountered,
136 /// either while compiling or when generating `llvm-cov show` reports, consider
137 /// lowering the optimization level, including or excluding `-C link-dead-code`,
138 /// or using `-Z instrument-coverage=except-unused-functions` or `-Z
139 /// instrument-coverage=except-unused-generics`.
141 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
142 /// coverage map, it will not attempt to generate synthetic functions for unused
143 /// (and not code-generated) functions (whether they are generic or not). As a
144 /// result, non-codegenned functions will not be included in the coverage map,
145 /// and will not appear, as covered or uncovered, in coverage reports.
147 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
148 /// unless the function has type parameters.
149 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
150 pub enum InstrumentCoverage {
151 /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
153 /// `-Z instrument-coverage=except-unused-generics`
154 ExceptUnusedGenerics,
155 /// `-Z instrument-coverage=except-unused-functions`
156 ExceptUnusedFunctions,
157 /// `-Z instrument-coverage=off` (or `no`, etc.)
161 #[derive(Clone, PartialEq, Hash, Debug)]
162 pub enum LinkerPluginLto {
163 LinkerPlugin(PathBuf),
168 impl LinkerPluginLto {
169 pub fn enabled(&self) -> bool {
171 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
172 LinkerPluginLto::Disabled => false,
177 /// The different settings that can be enabled via the `-Z location-detail` flag.
178 #[derive(Clone, PartialEq, Hash, Debug)]
179 pub struct LocationDetail {
185 impl LocationDetail {
186 pub fn all() -> Self {
187 Self { file: true, line: true, column: true }
191 #[derive(Clone, PartialEq, Hash, Debug)]
192 pub enum SwitchWithOptPath {
193 Enabled(Option<PathBuf>),
197 impl SwitchWithOptPath {
198 pub fn enabled(&self) -> bool {
200 SwitchWithOptPath::Enabled(_) => true,
201 SwitchWithOptPath::Disabled => false,
206 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
207 #[derive(Encodable, Decodable)]
208 pub enum SymbolManglingVersion {
213 impl_stable_hash_via_hash!(SymbolManglingVersion);
215 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
222 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
223 #[derive(Encodable, Decodable)]
224 pub enum OutputType {
235 impl_stable_hash_via_hash!(OutputType);
238 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
240 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
242 | OutputType::Assembly
243 | OutputType::LlvmAssembly
245 | OutputType::Object => false,
249 fn shorthand(&self) -> &'static str {
251 OutputType::Bitcode => "llvm-bc",
252 OutputType::Assembly => "asm",
253 OutputType::LlvmAssembly => "llvm-ir",
254 OutputType::Mir => "mir",
255 OutputType::Object => "obj",
256 OutputType::Metadata => "metadata",
257 OutputType::Exe => "link",
258 OutputType::DepInfo => "dep-info",
262 fn from_shorthand(shorthand: &str) -> Option<Self> {
263 Some(match shorthand {
264 "asm" => OutputType::Assembly,
265 "llvm-ir" => OutputType::LlvmAssembly,
266 "mir" => OutputType::Mir,
267 "llvm-bc" => OutputType::Bitcode,
268 "obj" => OutputType::Object,
269 "metadata" => OutputType::Metadata,
270 "link" => OutputType::Exe,
271 "dep-info" => OutputType::DepInfo,
276 fn shorthands_display() -> String {
278 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
279 OutputType::Bitcode.shorthand(),
280 OutputType::Assembly.shorthand(),
281 OutputType::LlvmAssembly.shorthand(),
282 OutputType::Mir.shorthand(),
283 OutputType::Object.shorthand(),
284 OutputType::Metadata.shorthand(),
285 OutputType::Exe.shorthand(),
286 OutputType::DepInfo.shorthand(),
290 pub fn extension(&self) -> &'static str {
292 OutputType::Bitcode => "bc",
293 OutputType::Assembly => "s",
294 OutputType::LlvmAssembly => "ll",
295 OutputType::Mir => "mir",
296 OutputType::Object => "o",
297 OutputType::Metadata => "rmeta",
298 OutputType::DepInfo => "d",
299 OutputType::Exe => "",
304 /// The type of diagnostics output to generate.
305 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
306 pub enum ErrorOutputType {
307 /// Output meant for the consumption of humans.
308 HumanReadable(HumanReadableErrorType),
309 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
311 /// Render the JSON in a human readable way (with indents and newlines).
313 /// The JSON output includes a `rendered` field that includes the rendered
315 json_rendered: HumanReadableErrorType,
319 impl Default for ErrorOutputType {
320 fn default() -> Self {
321 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
325 /// Parameter to control path trimming.
326 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
327 pub enum TrimmedDefPaths {
328 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
330 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
332 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
336 impl Default for TrimmedDefPaths {
337 fn default() -> Self {
342 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
343 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
344 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
345 /// should only depend on the output types, not the paths they're written to.
346 #[derive(Clone, Debug, Hash)]
347 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
350 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
351 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
354 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
358 pub fn contains_key(&self, key: &OutputType) -> bool {
359 self.0.contains_key(key)
362 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
366 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
370 pub fn len(&self) -> usize {
374 // Returns `true` if any of the output types require codegen or linking.
375 pub fn should_codegen(&self) -> bool {
376 self.0.keys().any(|k| match *k {
378 | OutputType::Assembly
379 | OutputType::LlvmAssembly
382 | OutputType::Exe => true,
383 OutputType::Metadata | OutputType::DepInfo => false,
387 // Returns `true` if any of the output types require linking.
388 pub fn should_link(&self) -> bool {
389 self.0.keys().any(|k| match *k {
391 | OutputType::Assembly
392 | OutputType::LlvmAssembly
394 | OutputType::Metadata
396 | OutputType::DepInfo => false,
397 OutputType::Exe => true,
402 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
403 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
404 /// would break dependency tracking for command-line arguments.
406 pub struct Externs(BTreeMap<String, ExternEntry>);
409 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
411 #[derive(Clone, Debug)]
412 pub struct ExternEntry {
413 pub location: ExternLocation,
414 /// Indicates this is a "private" dependency for the
415 /// `exported_private_dependencies` lint.
417 /// This can be set with the `priv` option like
418 /// `--extern priv:name=foo.rlib`.
419 pub is_private_dep: bool,
420 /// Add the extern entry to the extern prelude.
422 /// This can be disabled with the `noprelude` option like
423 /// `--extern noprelude:name`.
424 pub add_prelude: bool,
427 #[derive(Clone, Debug)]
428 pub enum ExternLocation {
429 /// Indicates to look for the library in the search paths.
431 /// Added via `--extern name`.
432 FoundInLibrarySearchDirectories,
433 /// The locations where this extern entry must be found.
435 /// The `CrateLoader` is responsible for loading these and figuring out
436 /// which one to use.
438 /// Added via `--extern prelude_name=some_file.rlib`
439 ExactPaths(BTreeSet<CanonicalizedPath>),
442 /// Supplied source location of a dependency - for example in a build specification
443 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
444 /// a file and line, then the build system can specify that. On the other hand, it may
445 /// make more sense to have an arbitrary raw string.
446 #[derive(Clone, PartialEq)]
447 pub enum ExternDepSpec {
450 /// Raw data in json format
454 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
455 fn from(from: &'a ExternDepSpec) -> Self {
457 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
458 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
464 /// Used for testing.
465 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
469 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
473 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
477 pub fn len(&self) -> usize {
483 fn new(location: ExternLocation) -> ExternEntry {
484 ExternEntry { location, is_private_dep: false, add_prelude: false }
487 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
488 match &self.location {
489 ExternLocation::ExactPaths(set) => Some(set.iter()),
495 impl ExternDepSpecs {
496 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
500 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
505 impl fmt::Display for ExternDepSpec {
506 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
508 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
509 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
514 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
515 pub enum PrintRequest {
531 #[derive(Copy, Clone)]
532 pub enum BorrowckMode {
538 /// Returns whether we should run the MIR-based borrow check, but also fall back
539 /// on the AST borrow check if the MIR-based one errors.
540 pub fn migrate(self) -> bool {
542 BorrowckMode::Mir => false,
543 BorrowckMode::Migrate => true,
549 /// Load source code from a file.
551 /// Load source code from a string.
553 /// A string that is shown in place of a filename.
555 /// An anonymous string containing the source code.
561 pub fn filestem(&self) -> &str {
563 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
564 Input::Str { .. } => "rust_out",
568 pub fn source_name(&self) -> FileName {
570 Input::File(ref ifile) => ifile.clone().into(),
571 Input::Str { ref name, .. } => name.clone(),
576 #[derive(Clone, Hash, Debug)]
577 pub struct OutputFilenames {
578 pub out_directory: PathBuf,
580 pub single_output_file: Option<PathBuf>,
581 pub temps_directory: Option<PathBuf>,
582 pub outputs: OutputTypes,
585 impl_stable_hash_via_hash!(OutputFilenames);
587 pub const RLINK_EXT: &str = "rlink";
588 pub const RUST_CGU_EXT: &str = "rcgu";
589 pub const DWARF_OBJECT_EXT: &str = "dwo";
591 impl OutputFilenames {
593 out_directory: PathBuf,
594 out_filestem: String,
595 single_output_file: Option<PathBuf>,
596 temps_directory: Option<PathBuf>,
598 outputs: OutputTypes,
605 filestem: format!("{}{}", out_filestem, extra),
609 pub fn path(&self, flavor: OutputType) -> PathBuf {
612 .and_then(|p| p.to_owned())
613 .or_else(|| self.single_output_file.clone())
614 .unwrap_or_else(|| self.output_path(flavor))
617 /// Gets the output path where a compilation artifact of the given type
618 /// should be placed on disk.
619 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
620 let extension = flavor.extension();
621 self.with_directory_and_extension(&self.out_directory, &extension)
624 /// Gets the path where a compilation artifact of the given type for the
625 /// given codegen unit should be placed on disk. If codegen_unit_name is
626 /// None, a path distinct from those of any codegen unit will be generated.
627 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
628 let extension = flavor.extension();
629 self.temp_path_ext(extension, codegen_unit_name)
632 /// Like `temp_path`, but specifically for dwarf objects.
633 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
634 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
637 /// Like `temp_path`, but also supports things where there is no corresponding
638 /// OutputType, like noopt-bitcode or lto-bitcode.
639 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
640 let mut extension = String::new();
642 if let Some(codegen_unit_name) = codegen_unit_name {
643 extension.push_str(codegen_unit_name);
647 if !extension.is_empty() {
649 extension.push_str(RUST_CGU_EXT);
653 extension.push_str(ext);
656 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
658 self.with_directory_and_extension(&temps_directory, &extension)
661 pub fn with_extension(&self, extension: &str) -> PathBuf {
662 self.with_directory_and_extension(&self.out_directory, extension)
665 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
666 let mut path = directory.join(&self.filestem);
667 path.set_extension(extension);
671 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
672 /// mode is being used, which is the logic that this function is intended to encapsulate.
673 pub fn split_dwarf_path(
675 split_debuginfo_kind: SplitDebuginfo,
676 cgu_name: Option<&str>,
677 ) -> Option<PathBuf> {
678 let obj_out = self.temp_path(OutputType::Object, cgu_name);
679 let dwo_out = self.temp_path_dwo(cgu_name);
680 match split_debuginfo_kind {
681 SplitDebuginfo::Off => None,
682 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
683 // (pointing at the path which is being determined here). Use the path to the current
685 SplitDebuginfo::Packed => Some(obj_out),
686 // Split mode emits the DWARF into a different file, use that path.
687 SplitDebuginfo::Unpacked => Some(dwo_out),
692 pub fn host_triple() -> &'static str {
693 // Get the host triple out of the build environment. This ensures that our
694 // idea of the host triple is the same as for the set of libraries we've
695 // actually built. We can't just take LLVM's host triple because they
696 // normalize all ix86 architectures to i386.
698 // Instead of grabbing the host triple (for the current host), we grab (at
699 // compile time) the target triple that this rustc is built with and
700 // calling that (at runtime) the host triple.
701 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
704 impl Default for Options {
705 fn default() -> Options {
707 crate_types: Vec::new(),
708 optimize: OptLevel::No,
709 debuginfo: DebugInfo::None,
710 lint_opts: Vec::new(),
712 describe_lints: false,
713 output_types: OutputTypes(BTreeMap::new()),
714 search_paths: vec![],
716 target_triple: TargetTriple::from_triple(host_triple()),
719 debugging_opts: Default::default(),
721 borrowck_mode: BorrowckMode::Migrate,
722 cg: Default::default(),
723 error_format: ErrorOutputType::default(),
724 externs: Externs(BTreeMap::new()),
725 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
729 unstable_features: UnstableFeatures::Disallow,
730 debug_assertions: true,
731 actually_rustdoc: false,
732 trimmed_def_paths: TrimmedDefPaths::default(),
733 cli_forced_codegen_units: None,
734 cli_forced_thinlto_off: false,
735 remap_path_prefix: Vec::new(),
736 real_rust_source_base_dir: None,
737 edition: DEFAULT_EDITION,
738 json_artifact_notifications: false,
739 json_unused_externs: false,
741 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
747 /// Returns `true` if there is a reason to build the dep graph.
748 pub fn build_dep_graph(&self) -> bool {
749 self.incremental.is_some()
750 || self.debugging_opts.dump_dep_graph
751 || self.debugging_opts.query_dep_graph
754 pub fn file_path_mapping(&self) -> FilePathMapping {
755 FilePathMapping::new(self.remap_path_prefix.clone())
758 /// Returns `true` if there will be an output file generated.
759 pub fn will_create_output_file(&self) -> bool {
760 !self.debugging_opts.parse_only && // The file is just being parsed
761 !self.debugging_opts.ls // The file is just being queried
765 pub fn share_generics(&self) -> bool {
766 match self.debugging_opts.share_generics {
767 Some(setting) => setting,
768 None => match self.optimize {
769 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
770 OptLevel::Default | OptLevel::Aggressive => false,
776 impl DebuggingOptions {
777 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
780 treat_err_as_bug: self.treat_err_as_bug,
781 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
782 report_delayed_bugs: self.report_delayed_bugs,
783 macro_backtrace: self.macro_backtrace,
784 deduplicate_diagnostics: self.deduplicate_diagnostics,
788 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
789 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
793 // The type of entry function, so users can have their own entry functions
794 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
795 pub enum EntryFnType {
800 impl_stable_hash_via_hash!(EntryFnType);
802 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
812 impl_stable_hash_via_hash!(CrateType);
814 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
821 pub fn is_empty(&self) -> bool {
823 Passes::Some(ref v) => v.is_empty(),
824 Passes::All => false,
829 pub const fn default_lib_output() -> CrateType {
833 fn default_configuration(sess: &Session) -> CrateConfig {
834 let end = &sess.target.endian;
835 let arch = &sess.target.arch;
836 let wordsz = sess.target.pointer_width.to_string();
837 let os = &sess.target.os;
838 let env = &sess.target.env;
839 let abi = &sess.target.abi;
840 let vendor = &sess.target.vendor;
841 let min_atomic_width = sess.target.min_atomic_width();
842 let max_atomic_width = sess.target.max_atomic_width();
843 let atomic_cas = sess.target.atomic_cas;
844 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
848 let mut ret = FxHashSet::default();
849 ret.reserve(7); // the minimum number of insertions
851 ret.insert((sym::target_os, Some(Symbol::intern(os))));
852 for fam in &sess.target.families {
853 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
854 if fam == "windows" {
855 ret.insert((sym::windows, None));
856 } else if fam == "unix" {
857 ret.insert((sym::unix, None));
860 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
861 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
862 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
863 ret.insert((sym::target_env, Some(Symbol::intern(env))));
864 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
865 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
866 if sess.target.has_elf_tls {
867 ret.insert((sym::target_thread_local, None));
870 (8, layout.i8_align.abi),
871 (16, layout.i16_align.abi),
872 (32, layout.i32_align.abi),
873 (64, layout.i64_align.abi),
874 (128, layout.i128_align.abi),
876 if i >= min_atomic_width && i <= max_atomic_width {
877 let mut insert_atomic = |s, align: Align| {
878 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
880 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
882 if align.bits() == i {
883 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
886 let s = i.to_string();
887 insert_atomic(&s, align);
889 insert_atomic("ptr", layout.pointer_align.abi);
894 let panic_strategy = sess.panic_strategy();
895 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
897 for s in sess.opts.debugging_opts.sanitizer {
898 let symbol = Symbol::intern(&s.to_string());
899 ret.insert((sym::sanitize, Some(symbol)));
902 if sess.opts.debug_assertions {
903 ret.insert((sym::debug_assertions, None));
905 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
906 ret.insert((sym::proc_macro, None));
911 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
912 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
913 /// but the symbol interner is not yet set up then, so we must convert it later.
914 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
915 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
918 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
919 // Combine the configuration requested by the session (command line) with
920 // some default and generated configuration items.
921 let default_cfg = default_configuration(sess);
922 // If the user wants a test runner, then add the test cfg.
924 user_cfg.insert((sym::test, None));
926 user_cfg.extend(default_cfg.iter().cloned());
930 pub(super) fn build_target_config(
932 target_override: Option<Target>,
935 let target_result = target_override.map_or_else(
936 || Target::search(&opts.target_triple, sysroot),
937 |t| Ok((t, TargetWarnings::empty())),
939 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
943 "Error loading target specification: {}. \
944 Run `rustc --print target-list` for a list of built-in targets",
949 for warning in target_warnings.warning_messages() {
950 early_warn(opts.error_format, &warning)
953 if !matches!(target.pointer_width, 16 | 32 | 64) {
957 "target specification was invalid: \
958 unrecognized target-pointer-width {}",
967 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
968 pub enum OptionStability {
973 pub struct RustcOptGroup {
974 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
975 pub name: &'static str,
976 pub stability: OptionStability,
980 pub fn is_stable(&self) -> bool {
981 self.stability == OptionStability::Stable
984 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
986 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
988 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
991 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
993 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
995 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
999 // The `opt` local module holds wrappers around the `getopts` API that
1000 // adds extra rustc-specific metadata to each option; such metadata
1001 // is exposed by . The public
1002 // functions below ending with `_u` are the functions that return
1003 // *unstable* options, i.e., options that are only enabled when the
1004 // user also passes the `-Z unstable-options` debugging flag.
1006 // The `fn flag*` etc below are written so that we can use them
1007 // in the future; do not warn about them not being used right now.
1008 #![allow(dead_code)]
1010 use super::RustcOptGroup;
1012 pub type R = RustcOptGroup;
1013 pub type S = &'static str;
1015 fn stable<F>(name: S, f: F) -> R
1017 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1019 RustcOptGroup::stable(name, f)
1022 fn unstable<F>(name: S, f: F) -> R
1024 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1026 RustcOptGroup::unstable(name, f)
1029 fn longer(a: S, b: S) -> S {
1030 if a.len() > b.len() { a } else { b }
1033 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1034 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1036 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1037 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1039 pub fn flag_s(a: S, b: S, c: S) -> R {
1040 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1042 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1043 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1046 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1047 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1049 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1050 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1054 /// Returns the "short" subset of the rustc command line options,
1055 /// including metadata for each option, such as whether the option is
1056 /// part of the stable long-term interface for rustc.
1057 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1059 opt::flag_s("h", "help", "Display this message"),
1060 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1064 "Add a directory to the library search path. The
1065 optional KIND can be one of dependency, crate, native,
1066 framework, or all (the default).",
1072 "Link the generated crate(s) to the specified native
1073 library NAME. The optional KIND can be one of
1074 static, framework, or dylib (the default).
1075 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1076 may be specified each with a prefix of either '+' to
1077 enable or '-' to disable.",
1078 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1080 make_crate_type_option(),
1081 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1085 "Specify which edition of the compiler to use when compiling code.",
1091 "Comma separated list of types of output for \
1092 the compiler to emit",
1093 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1098 "Compiler information to print on stdout",
1099 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1100 target-cpus|target-features|relocation-models|\
1101 code-models|tls-models|target-spec-json|native-static-libs]",
1103 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1104 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1105 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1109 "Write output to compiler-chosen filename \
1116 "Provide a detailed explanation of an error \
1120 opt::flag_s("", "test", "Build a test harness"),
1121 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1122 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1123 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1124 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1125 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1126 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1130 "Set the most restrictive lint level. \
1131 More restrictive lints are capped at this \
1135 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1136 opt::flag_s("V", "version", "Print version info and exit"),
1137 opt::flag_s("v", "verbose", "Use verbose output"),
1141 /// Returns all rustc command line options, including metadata for
1142 /// each option, such as whether the option is part of the stable
1143 /// long-term interface for rustc.
1144 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1145 let mut opts = rustc_short_optgroups();
1150 "Specify where an external rust library is located",
1156 "Location where an external crate dependency is specified",
1159 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1160 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1164 "How errors and other messages are produced",
1167 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1171 "Configure coloring of output:
1172 auto = colorize, if output goes to a tty (default);
1173 always = always colorize output;
1174 never = never colorize output",
1175 "auto|always|never",
1179 "remap-path-prefix",
1180 "Remap source names in all output (compiler messages and output files)",
1187 pub fn get_cmd_lint_options(
1188 matches: &getopts::Matches,
1189 error_format: ErrorOutputType,
1190 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1191 let mut lint_opts_with_position = vec![];
1192 let mut describe_lints = false;
1194 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1195 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1196 if lint_name == "help" {
1197 describe_lints = true;
1199 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1204 lint_opts_with_position.sort_by_key(|x| x.0);
1205 let lint_opts = lint_opts_with_position
1208 .map(|(_, lint_name, level)| (lint_name, level))
1211 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1212 lint::Level::from_str(&cap)
1213 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1216 (lint_opts, describe_lints, lint_cap)
1219 /// Parses the `--color` flag.
1220 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1221 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1222 Some("auto") => ColorConfig::Auto,
1223 Some("always") => ColorConfig::Always,
1224 Some("never") => ColorConfig::Never,
1226 None => ColorConfig::Auto,
1228 Some(arg) => early_error(
1229 ErrorOutputType::default(),
1231 "argument for `--color` must be auto, \
1232 always or never (instead was `{}`)",
1239 /// Possible json config files
1240 pub struct JsonConfig {
1241 pub json_rendered: HumanReadableErrorType,
1242 pub json_artifact_notifications: bool,
1243 pub json_unused_externs: bool,
1246 /// Parse the `--json` flag.
1248 /// The first value returned is how to render JSON diagnostics, and the second
1249 /// is whether or not artifact notifications are enabled.
1250 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1251 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1252 HumanReadableErrorType::Default;
1253 let mut json_color = ColorConfig::Never;
1254 let mut json_artifact_notifications = false;
1255 let mut json_unused_externs = false;
1256 for option in matches.opt_strs("json") {
1257 // For now conservatively forbid `--color` with `--json` since `--json`
1258 // won't actually be emitting any colors and anything colorized is
1259 // embedded in a diagnostic message anyway.
1260 if matches.opt_str("color").is_some() {
1262 ErrorOutputType::default(),
1263 "cannot specify the `--color` option with `--json`",
1267 for sub_option in option.split(',') {
1269 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1270 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1271 "artifacts" => json_artifact_notifications = true,
1272 "unused-externs" => json_unused_externs = true,
1274 ErrorOutputType::default(),
1275 &format!("unknown `--json` option `{}`", s),
1282 json_rendered: json_rendered(json_color),
1283 json_artifact_notifications,
1284 json_unused_externs,
1288 /// Parses the `--error-format` flag.
1289 pub fn parse_error_format(
1290 matches: &getopts::Matches,
1292 json_rendered: HumanReadableErrorType,
1293 ) -> ErrorOutputType {
1294 // We need the `opts_present` check because the driver will send us Matches
1295 // with only stable options if no unstable options are used. Since error-format
1296 // is unstable, it will not be present. We have to use `opts_present` not
1297 // `opt_present` because the latter will panic.
1298 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1299 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1300 None | Some("human") => {
1301 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1303 Some("human-annotate-rs") => {
1304 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1306 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1307 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1308 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1310 Some(arg) => early_error(
1311 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1313 "argument for `--error-format` must be `human`, `json` or \
1314 `short` (instead was `{}`)",
1320 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1323 match error_format {
1324 ErrorOutputType::Json { .. } => {}
1326 // Conservatively require that the `--json` argument is coupled with
1327 // `--error-format=json`. This means that `--json` is specified we
1328 // should actually be emitting JSON blobs.
1329 _ if !matches.opt_strs("json").is_empty() => {
1331 ErrorOutputType::default(),
1332 "using `--json` requires also using `--error-format=json`",
1342 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1343 let edition = match matches.opt_str("edition") {
1344 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1346 ErrorOutputType::default(),
1348 "argument for `--edition` must be one of: \
1349 {}. (instead was `{}`)",
1350 EDITION_NAME_LIST, arg
1354 None => DEFAULT_EDITION,
1357 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1358 let is_nightly = nightly_options::match_is_nightly_build(matches);
1359 let msg = if !is_nightly {
1361 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1362 edition, LATEST_STABLE_EDITION
1365 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1367 early_error(ErrorOutputType::default(), &msg)
1373 fn check_debug_option_stability(
1374 debugging_opts: &DebuggingOptions,
1375 error_format: ErrorOutputType,
1376 json_rendered: HumanReadableErrorType,
1378 if !debugging_opts.unstable_options {
1379 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1381 ErrorOutputType::Json { pretty: false, json_rendered },
1382 "`--error-format=pretty-json` is unstable",
1385 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1389 ErrorOutputType::Json { pretty: false, json_rendered },
1390 "`--error-format=human-annotate-rs` is unstable",
1396 fn parse_output_types(
1397 debugging_opts: &DebuggingOptions,
1398 matches: &getopts::Matches,
1399 error_format: ErrorOutputType,
1401 let mut output_types = BTreeMap::new();
1402 if !debugging_opts.parse_only {
1403 for list in matches.opt_strs("emit") {
1404 for output_type in list.split(',') {
1405 let (shorthand, path) = match output_type.split_once('=') {
1406 None => (output_type, None),
1407 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1409 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1413 "unknown emission type: `{}` - expected one of: {}",
1415 OutputType::shorthands_display(),
1419 output_types.insert(output_type, path);
1423 if output_types.is_empty() {
1424 output_types.insert(OutputType::Exe, None);
1426 OutputTypes(output_types)
1429 fn should_override_cgus_and_disable_thinlto(
1430 output_types: &OutputTypes,
1431 matches: &getopts::Matches,
1432 error_format: ErrorOutputType,
1433 mut codegen_units: Option<usize>,
1434 ) -> (bool, Option<usize>) {
1435 let mut disable_thinlto = false;
1436 // Issue #30063: if user requests LLVM-related output to one
1437 // particular path, disable codegen-units.
1438 let incompatible: Vec<_> = output_types
1441 .map(|ot_path| ot_path.0)
1442 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1443 .map(|ot| ot.shorthand())
1445 if !incompatible.is_empty() {
1446 match codegen_units {
1447 Some(n) if n > 1 => {
1448 if matches.opt_present("o") {
1449 for ot in &incompatible {
1453 "`--emit={}` with `-o` incompatible with \
1454 `-C codegen-units=N` for N > 1",
1459 early_warn(error_format, "resetting to default -C codegen-units=1");
1460 codegen_units = Some(1);
1461 disable_thinlto = true;
1465 codegen_units = Some(1);
1466 disable_thinlto = true;
1471 if codegen_units == Some(0) {
1472 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1475 (disable_thinlto, codegen_units)
1478 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1479 if debugging_opts.threads == 0 {
1480 early_error(error_format, "value for threads must be a positive non-zero integer");
1483 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1484 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1488 fn collect_print_requests(
1489 cg: &mut CodegenOptions,
1490 dopts: &mut DebuggingOptions,
1491 matches: &getopts::Matches,
1492 error_format: ErrorOutputType,
1493 ) -> Vec<PrintRequest> {
1494 let mut prints = Vec::<PrintRequest>::new();
1495 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1496 prints.push(PrintRequest::TargetCPUs);
1497 cg.target_cpu = None;
1499 if cg.target_feature == "help" {
1500 prints.push(PrintRequest::TargetFeatures);
1501 cg.target_feature = String::new();
1504 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1505 "crate-name" => PrintRequest::CrateName,
1506 "file-names" => PrintRequest::FileNames,
1507 "sysroot" => PrintRequest::Sysroot,
1508 "target-libdir" => PrintRequest::TargetLibdir,
1509 "cfg" => PrintRequest::Cfg,
1510 "target-list" => PrintRequest::TargetList,
1511 "target-cpus" => PrintRequest::TargetCPUs,
1512 "target-features" => PrintRequest::TargetFeatures,
1513 "relocation-models" => PrintRequest::RelocationModels,
1514 "code-models" => PrintRequest::CodeModels,
1515 "tls-models" => PrintRequest::TlsModels,
1516 "native-static-libs" => PrintRequest::NativeStaticLibs,
1517 "target-spec-json" => {
1518 if dopts.unstable_options {
1519 PrintRequest::TargetSpec
1523 "the `-Z unstable-options` flag must also be passed to \
1524 enable the target-spec-json print option",
1528 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1534 pub fn parse_target_triple(
1535 matches: &getopts::Matches,
1536 error_format: ErrorOutputType,
1538 match matches.opt_str("target") {
1539 Some(target) if target.ends_with(".json") => {
1540 let path = Path::new(&target);
1541 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1542 early_error(error_format, &format!("target file {:?} does not exist", path))
1545 Some(target) => TargetTriple::TargetTriple(target),
1546 _ => TargetTriple::from_triple(host_triple()),
1551 matches: &getopts::Matches,
1552 cg: &CodegenOptions,
1553 error_format: ErrorOutputType,
1555 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1556 // to use them interchangeably. However, because they're technically different flags,
1557 // we need to work out manually which should take precedence if both are supplied (i.e.
1558 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1559 // comparing them. Note that if a flag is not found, its position will be `None`, which
1560 // always compared less than `Some(_)`.
1561 let max_o = matches.opt_positions("O").into_iter().max();
1565 .flat_map(|(i, s)| {
1566 // NB: This can match a string without `=`.
1567 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1573 match cg.opt_level.as_ref() {
1574 "0" => OptLevel::No,
1575 "1" => OptLevel::Less,
1576 "2" => OptLevel::Default,
1577 "3" => OptLevel::Aggressive,
1578 "s" => OptLevel::Size,
1579 "z" => OptLevel::SizeMin,
1584 "optimization level needs to be \
1585 between 0-3, s or z (instead was `{}`)",
1594 fn select_debuginfo(
1595 matches: &getopts::Matches,
1596 cg: &CodegenOptions,
1597 error_format: ErrorOutputType,
1599 let max_g = matches.opt_positions("g").into_iter().max();
1603 .flat_map(|(i, s)| {
1604 // NB: This can match a string without `=`.
1605 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1611 match cg.debuginfo {
1612 0 => DebugInfo::None,
1613 1 => DebugInfo::Limited,
1614 2 => DebugInfo::Full,
1619 "debug info level needs to be between \
1620 0-2 (instead was `{}`)",
1629 fn parse_native_lib_kind(
1630 matches: &getopts::Matches,
1632 error_format: ErrorOutputType,
1633 ) -> (NativeLibKind, Option<bool>) {
1634 let is_nightly = nightly_options::match_is_nightly_build(matches);
1635 let enable_unstable = nightly_options::is_unstable_enabled(matches);
1637 let (kind, modifiers) = match kind.split_once(':') {
1638 None => (kind, None),
1639 Some((kind, modifiers)) => (kind, Some(modifiers)),
1642 let kind = match kind {
1643 "dylib" => NativeLibKind::Dylib { as_needed: None },
1644 "framework" => NativeLibKind::Framework { as_needed: None },
1645 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1646 "static-nobundle" => {
1649 "library kind `static-nobundle` has been superseded by specifying \
1650 `-bundle` on library kind `static`. Try `static:-bundle`",
1652 if modifiers.is_some() {
1655 "linking modifier can't be used with library kind `static-nobundle`",
1661 "library kind `static-nobundle` are currently unstable and only accepted on \
1662 the nightly compiler",
1665 NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1669 &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1673 None => (kind, None),
1674 Some(modifiers) => {
1678 "linking modifiers are currently unstable and only accepted on \
1679 the nightly compiler",
1682 if !enable_unstable {
1685 "linking modifiers are currently unstable, \
1686 the `-Z unstable-options` flag must also be passed to use it",
1689 parse_native_lib_modifiers(kind, modifiers, error_format)
1694 fn parse_native_lib_modifiers(
1695 mut kind: NativeLibKind,
1697 error_format: ErrorOutputType,
1698 ) -> (NativeLibKind, Option<bool>) {
1699 let mut verbatim = None;
1700 for modifier in modifiers.split(',') {
1701 let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
1702 Some(m) => (m, modifier.starts_with('+')),
1703 None => early_error(
1705 "invalid linking modifier syntax, expected '+' or '-' prefix \
1706 before one of: bundle, verbatim, whole-archive, as-needed",
1710 match (modifier, &mut kind) {
1711 ("bundle", NativeLibKind::Static { bundle, .. }) => {
1712 *bundle = Some(value);
1714 ("bundle", _) => early_error(
1716 "bundle linking modifier is only compatible with \
1717 `static` linking kind",
1720 ("verbatim", _) => verbatim = Some(value),
1722 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1723 *whole_archive = Some(value);
1725 ("whole-archive", _) => early_error(
1727 "whole-archive linking modifier is only compatible with \
1728 `static` linking kind",
1731 ("as-needed", NativeLibKind::Dylib { as_needed })
1732 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1733 *as_needed = Some(value);
1735 ("as-needed", _) => early_error(
1737 "as-needed linking modifier is only compatible with \
1738 `dylib` and `framework` linking kinds",
1744 "unrecognized linking modifier `{}`, expected one \
1745 of: bundle, verbatim, whole-archive, as-needed",
1755 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1760 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1761 // where KIND is one of "dylib", "framework", "static" and
1762 // where MODIFIERS are a comma separated list of supported modifiers
1763 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1764 // with either + or - to indicate whether it is enabled or disabled.
1765 // The last value specified for a given modifier wins.
1766 let (name, kind, verbatim) = match s.split_once('=') {
1767 None => (s, NativeLibKind::Unspecified, None),
1768 Some((kind, name)) => {
1769 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
1770 (name.to_string(), kind, verbatim)
1774 let (name, new_name) = match name.split_once(':') {
1775 None => (name, None),
1776 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1778 NativeLib { name, new_name, kind, verbatim }
1783 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1784 match dopts.borrowck.as_ref() {
1785 "migrate" => BorrowckMode::Migrate,
1786 "mir" => BorrowckMode::Mir,
1787 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1791 pub fn parse_externs(
1792 matches: &getopts::Matches,
1793 debugging_opts: &DebuggingOptions,
1794 error_format: ErrorOutputType,
1796 let is_unstable_enabled = debugging_opts.unstable_options;
1797 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1798 for arg in matches.opt_strs("extern") {
1799 let (name, path) = match arg.split_once('=') {
1800 None => (arg, None),
1801 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1803 let (options, name) = match name.split_once(':') {
1804 None => (None, name),
1805 Some((opts, name)) => (Some(opts), name.to_string()),
1808 let path = path.map(|p| CanonicalizedPath::new(p));
1810 let entry = externs.entry(name.to_owned());
1812 use std::collections::btree_map::Entry;
1814 let entry = if let Some(path) = path {
1815 // --extern prelude_name=some_file.rlib
1817 Entry::Vacant(vacant) => {
1818 let files = BTreeSet::from_iter(iter::once(path));
1819 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1821 Entry::Occupied(occupied) => {
1822 let ext_ent = occupied.into_mut();
1824 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1828 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1831 // Exact paths take precedence over search directories.
1832 let files = BTreeSet::from_iter(iter::once(path));
1833 *location = ExternLocation::ExactPaths(files);
1840 // --extern prelude_name
1842 Entry::Vacant(vacant) => {
1843 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1845 Entry::Occupied(occupied) => {
1846 // Ignore if already specified.
1852 let mut is_private_dep = false;
1853 let mut add_prelude = true;
1854 if let Some(opts) = options {
1855 if !is_unstable_enabled {
1858 "the `-Z unstable-options` flag must also be passed to \
1859 enable `--extern options",
1862 for opt in opts.split(',') {
1864 "priv" => is_private_dep = true,
1866 if let ExternLocation::ExactPaths(_) = &entry.location {
1867 add_prelude = false;
1871 "the `noprelude` --extern option requires a file path",
1875 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1880 // Crates start out being not private, and go to being private `priv`
1882 entry.is_private_dep |= is_private_dep;
1883 // If any flag is missing `noprelude`, then add to the prelude.
1884 entry.add_prelude |= add_prelude;
1889 fn parse_extern_dep_specs(
1890 matches: &getopts::Matches,
1891 debugging_opts: &DebuggingOptions,
1892 error_format: ErrorOutputType,
1893 ) -> ExternDepSpecs {
1894 let is_unstable_enabled = debugging_opts.unstable_options;
1895 let mut map = BTreeMap::new();
1897 for arg in matches.opt_strs("extern-location") {
1898 if !is_unstable_enabled {
1901 "`--extern-location` option is unstable: set `-Z unstable-options`",
1905 let mut parts = arg.splitn(2, '=');
1906 let name = parts.next().unwrap_or_else(|| {
1907 early_error(error_format, "`--extern-location` value must not be empty")
1909 let loc = parts.next().unwrap_or_else(|| {
1912 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1916 let locparts: Vec<_> = loc.split(':').collect();
1917 let spec = match &locparts[..] {
1919 // Don't want `:` split string
1920 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1921 early_error(error_format, "`--extern-location`: missing `raw` location")
1923 ExternDepSpec::Raw(raw.to_string())
1926 // Don't want `:` split string
1927 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1928 early_error(error_format, "`--extern-location`: missing `json` location")
1930 let json = json::from_str(raw).unwrap_or_else(|_| {
1933 &format!("`--extern-location`: malformed json location `{}`", raw),
1936 ExternDepSpec::Json(json)
1938 [bad, ..] => early_error(
1940 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1942 [] => early_error(error_format, "missing location specification"),
1945 map.insert(name.to_string(), spec);
1948 ExternDepSpecs::new(map)
1951 fn parse_remap_path_prefix(
1952 matches: &getopts::Matches,
1953 debugging_opts: &DebuggingOptions,
1954 error_format: ErrorOutputType,
1955 ) -> Vec<(PathBuf, PathBuf)> {
1956 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
1957 .opt_strs("remap-path-prefix")
1959 .map(|remap| match remap.rsplit_once('=') {
1960 None => early_error(
1962 "--remap-path-prefix must contain '=' between FROM and TO",
1964 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1967 match &debugging_opts.remap_cwd_prefix {
1968 Some(to) => match std::env::current_dir() {
1969 Ok(cwd) => mapping.push((cwd, to.clone())),
1977 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1978 let color = parse_color(matches);
1980 let edition = parse_crate_edition(matches);
1982 let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
1983 parse_json(matches);
1985 let error_format = parse_error_format(matches, color, json_rendered);
1987 let unparsed_crate_types = matches.opt_strs("crate-type");
1988 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1989 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1991 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
1992 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1994 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1996 if !debugging_opts.unstable_options && json_unused_externs {
1999 "the `-Z unstable-options` flag must also be passed to enable \
2000 the flag `--json=unused-externs`",
2004 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2006 let mut cg = CodegenOptions::build(matches, error_format);
2007 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2014 check_thread_count(&debugging_opts, error_format);
2016 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2018 if debugging_opts.profile && incremental.is_some() {
2021 "can't instrument with gcov profiling when compiling incrementally",
2024 if debugging_opts.profile {
2025 match codegen_units {
2027 None => codegen_units = Some(1),
2028 Some(_) => early_error(
2030 "can't instrument with gcov profiling with multiple codegen units",
2035 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2038 "options `-C profile-generate` and `-C profile-use` are exclusive",
2042 if debugging_opts.profile_sample_use.is_some()
2043 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2047 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2051 if debugging_opts.instrument_coverage.is_some()
2052 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
2054 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2057 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2058 or `-C profile-generate`",
2062 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
2063 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2064 // multiple runs, including some changes to source code; so mangled names must be consistent
2065 // across compilations.
2066 match debugging_opts.symbol_mangling_version {
2068 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
2070 Some(SymbolManglingVersion::Legacy) => {
2073 "-Z instrument-coverage requires symbol mangling version `v0`, \
2074 but `-Z symbol-mangling-version=legacy` was specified",
2077 Some(SymbolManglingVersion::V0) => {}
2081 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2082 debugging_opts.graphviz_font = graphviz_font;
2085 if !cg.embed_bitcode {
2087 LtoCli::No | LtoCli::Unspecified => {}
2088 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2090 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2095 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2099 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2100 let target_triple = parse_target_triple(matches, error_format);
2101 let opt_level = parse_opt_level(matches, &cg, error_format);
2102 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2103 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2104 // for more details.
2105 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2106 let debuginfo = select_debuginfo(matches, &cg, error_format);
2108 let mut search_paths = vec![];
2109 for s in &matches.opt_strs("L") {
2110 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2113 let libs = parse_libs(matches, error_format);
2115 let test = matches.opt_present("test");
2117 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2119 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2120 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2123 let externs = parse_externs(matches, &debugging_opts, error_format);
2124 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2126 let crate_name = matches.opt_str("crate-name");
2128 let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2130 let pretty = parse_pretty(&debugging_opts, error_format);
2132 if !debugging_opts.unstable_options
2133 && !target_triple.triple().contains("apple")
2134 && cg.split_debuginfo.is_some()
2137 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2141 // Try to find a directory containing the Rust `src`, for more details see
2142 // the doc comment on the `real_rust_source_base_dir` field.
2144 let sysroot = match &sysroot_opt {
2147 tmp_buf = crate::filesearch::get_or_default_sysroot();
2151 let real_rust_source_base_dir = {
2152 // This is the location used by the `rust-src` `rustup` component.
2153 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2154 if let Ok(metadata) = candidate.symlink_metadata() {
2155 // Replace the symlink rustbuild creates, with its destination.
2156 // We could try to use `fs::canonicalize` instead, but that might
2157 // produce unnecessarily verbose path.
2158 if metadata.file_type().is_symlink() {
2159 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2160 candidate = symlink_dest;
2165 // Only use this directory if it has a file we can expect to always find.
2166 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2169 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2170 early_error(error_format, &format!("Current directory is invalid: {}", e));
2173 let (path, remapped) =
2174 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2175 let working_dir = if remapped {
2176 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2178 RealFileName::LocalPath(path)
2183 optimize: opt_level,
2190 maybe_sysroot: sysroot_opt,
2200 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2206 actually_rustdoc: false,
2207 trimmed_def_paths: TrimmedDefPaths::default(),
2208 cli_forced_codegen_units: codegen_units,
2209 cli_forced_thinlto_off: disable_thinlto,
2211 real_rust_source_base_dir,
2213 json_artifact_notifications,
2214 json_unused_externs,
2220 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2223 let first = match debugging_opts.unpretty.as_deref()? {
2224 "normal" => Source(PpSourceMode::Normal),
2225 "identified" => Source(PpSourceMode::Identified),
2226 "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
2227 "expanded" => Source(PpSourceMode::Expanded),
2228 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2229 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2230 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2231 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2232 "hir" => Hir(PpHirMode::Normal),
2233 "hir,identified" => Hir(PpHirMode::Identified),
2234 "hir,typed" => Hir(PpHirMode::Typed),
2235 "hir-tree" => HirTree,
2236 "thir-tree" => ThirTree,
2238 "mir-cfg" => MirCFG,
2239 name => early_error(
2242 "argument to `unpretty` must be one of `normal`, \
2243 `expanded`, `identified`, `expanded,identified`, \
2244 `expanded,hygiene`, `everybody_loops`, \
2245 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2246 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2251 tracing::debug!("got unpretty option: {:?}", first);
2255 pub fn make_crate_type_option() -> RustcOptGroup {
2259 "Comma separated list of types of crates
2260 for the compiler to emit",
2261 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2265 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2266 let mut crate_types: Vec<CrateType> = Vec::new();
2267 for unparsed_crate_type in &list_list {
2268 for part in unparsed_crate_type.split(',') {
2269 let new_part = match part {
2270 "lib" => default_lib_output(),
2271 "rlib" => CrateType::Rlib,
2272 "staticlib" => CrateType::Staticlib,
2273 "dylib" => CrateType::Dylib,
2274 "cdylib" => CrateType::Cdylib,
2275 "bin" => CrateType::Executable,
2276 "proc-macro" => CrateType::ProcMacro,
2277 _ => return Err(format!("unknown crate type: `{}`", part)),
2279 if !crate_types.contains(&new_part) {
2280 crate_types.push(new_part)
2288 pub mod nightly_options {
2289 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2290 use crate::early_error;
2291 use rustc_feature::UnstableFeatures;
2293 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2294 match_is_nightly_build(matches)
2295 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2298 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2299 is_nightly_build(matches.opt_str("crate-name").as_deref())
2302 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2303 UnstableFeatures::from_environment(krate).is_nightly_build()
2306 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2307 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2308 let really_allows_unstable_options = match_is_nightly_build(matches);
2310 for opt in flags.iter() {
2311 if opt.stability == OptionStability::Stable {
2314 if !matches.opt_present(opt.name) {
2317 if opt.name != "Z" && !has_z_unstable_option {
2319 ErrorOutputType::default(),
2321 "the `-Z unstable-options` flag must also be passed to enable \
2327 if really_allows_unstable_options {
2330 match opt.stability {
2331 OptionStability::Unstable => {
2333 "the option `{}` is only accepted on the \
2337 early_error(ErrorOutputType::default(), &msg);
2339 OptionStability::Stable => {}
2345 impl fmt::Display for CrateType {
2346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2348 CrateType::Executable => "bin".fmt(f),
2349 CrateType::Dylib => "dylib".fmt(f),
2350 CrateType::Rlib => "rlib".fmt(f),
2351 CrateType::Staticlib => "staticlib".fmt(f),
2352 CrateType::Cdylib => "cdylib".fmt(f),
2353 CrateType::ProcMacro => "proc-macro".fmt(f),
2358 #[derive(Copy, Clone, PartialEq, Debug)]
2359 pub enum PpSourceMode {
2360 /// `-Zunpretty=normal`
2362 /// `-Zunpretty=everybody_loops`
2364 /// `-Zunpretty=expanded`
2366 /// `-Zunpretty=identified`
2368 /// `-Zunpretty=expanded,identified`
2370 /// `-Zunpretty=expanded,hygiene`
2374 #[derive(Copy, Clone, PartialEq, Debug)]
2375 pub enum PpAstTreeMode {
2376 /// `-Zunpretty=ast`
2378 /// `-Zunpretty=ast,expanded`
2382 #[derive(Copy, Clone, PartialEq, Debug)]
2383 pub enum PpHirMode {
2384 /// `-Zunpretty=hir`
2386 /// `-Zunpretty=hir,identified`
2388 /// `-Zunpretty=hir,typed`
2392 #[derive(Copy, Clone, PartialEq, Debug)]
2394 /// Options that print the source code, i.e.
2395 /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
2396 Source(PpSourceMode),
2397 AstTree(PpAstTreeMode),
2398 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2400 /// `-Zunpretty=hir-tree`
2402 /// `-Zunpretty=thir-tree`
2404 /// `-Zunpretty=mir`
2406 /// `-Zunpretty=mir-cfg`
2411 pub fn needs_ast_map(&self) -> bool {
2413 use PpSourceMode::*;
2415 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2417 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2418 | AstTree(PpAstTreeMode::Expanded)
2427 pub fn needs_analysis(&self) -> bool {
2429 matches!(*self, Mir | MirCFG | ThirTree)
2433 /// Command-line arguments passed to the compiler have to be incorporated with
2434 /// the dependency tracking system for incremental compilation. This module
2435 /// provides some utilities to make this more convenient.
2437 /// The values of all command-line arguments that are relevant for dependency
2438 /// tracking are hashed into a single value that determines whether the
2439 /// incremental compilation cache can be re-used or not. This hashing is done
2440 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2441 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2442 /// the hash of which is order dependent, but we might not want the order of
2443 /// arguments to make a difference for the hash).
2445 /// However, since the value provided by `Hash::hash` often *is* suitable,
2446 /// especially for primitive types, there is the
2447 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2448 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2449 /// we have an opt-in scheme here, so one is hopefully forced to think about
2450 /// how the hash should be calculated when adding a new command-line argument.
2451 crate mod dep_tracking {
2454 CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2455 LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
2456 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2459 use crate::options::WasiExecModel;
2460 use crate::utils::{NativeLib, NativeLibKind};
2461 use rustc_feature::UnstableFeatures;
2462 use rustc_span::edition::Edition;
2463 use rustc_span::RealFileName;
2464 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2465 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
2466 use std::collections::hash_map::DefaultHasher;
2467 use std::collections::BTreeMap;
2468 use std::hash::Hash;
2469 use std::num::NonZeroUsize;
2470 use std::path::PathBuf;
2472 pub trait DepTrackingHash {
2475 hasher: &mut DefaultHasher,
2476 error_format: ErrorOutputType,
2477 for_crate_hash: bool,
2481 macro_rules! impl_dep_tracking_hash_via_hash {
2482 ($($t:ty),+ $(,)?) => {$(
2483 impl DepTrackingHash for $t {
2484 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2485 Hash::hash(self, hasher);
2491 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2494 hasher: &mut DefaultHasher,
2495 error_format: ErrorOutputType,
2496 for_crate_hash: bool,
2500 Hash::hash(&1, hasher);
2501 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2503 None => Hash::hash(&0, hasher),
2508 impl_dep_tracking_hash_via_hash!(
2540 SymbolManglingVersion,
2541 SourceFileHashAlgorithm,
2549 impl<T1, T2> DepTrackingHash for (T1, T2)
2551 T1: DepTrackingHash,
2552 T2: DepTrackingHash,
2556 hasher: &mut DefaultHasher,
2557 error_format: ErrorOutputType,
2558 for_crate_hash: bool,
2560 Hash::hash(&0, hasher);
2561 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2562 Hash::hash(&1, hasher);
2563 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2567 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2569 T1: DepTrackingHash,
2570 T2: DepTrackingHash,
2571 T3: DepTrackingHash,
2575 hasher: &mut DefaultHasher,
2576 error_format: ErrorOutputType,
2577 for_crate_hash: bool,
2579 Hash::hash(&0, hasher);
2580 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2581 Hash::hash(&1, hasher);
2582 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2583 Hash::hash(&2, hasher);
2584 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2588 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2591 hasher: &mut DefaultHasher,
2592 error_format: ErrorOutputType,
2593 for_crate_hash: bool,
2595 Hash::hash(&self.len(), hasher);
2596 for (index, elem) in self.iter().enumerate() {
2597 Hash::hash(&index, hasher);
2598 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2603 impl DepTrackingHash for OutputTypes {
2606 hasher: &mut DefaultHasher,
2607 error_format: ErrorOutputType,
2608 for_crate_hash: bool,
2610 Hash::hash(&self.0.len(), hasher);
2611 for (key, val) in &self.0 {
2612 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2613 if !for_crate_hash {
2614 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2620 // This is a stable hash because BTreeMap is a sorted container
2621 crate fn stable_hash(
2622 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2623 hasher: &mut DefaultHasher,
2624 error_format: ErrorOutputType,
2625 for_crate_hash: bool,
2627 for (key, sub_hash) in sub_hashes {
2628 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2629 // the keys, as they are just plain strings
2630 Hash::hash(&key.len(), hasher);
2631 Hash::hash(key, hasher);
2632 sub_hash.hash(hasher, error_format, for_crate_hash);