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 outputs: OutputTypes,
584 impl_stable_hash_via_hash!(OutputFilenames);
586 pub const RLINK_EXT: &str = "rlink";
587 pub const RUST_CGU_EXT: &str = "rcgu";
588 pub const DWARF_OBJECT_EXT: &str = "dwo";
590 impl OutputFilenames {
592 out_directory: PathBuf,
593 out_filestem: String,
594 single_output_file: Option<PathBuf>,
596 outputs: OutputTypes,
602 filestem: format!("{}{}", out_filestem, extra),
606 pub fn path(&self, flavor: OutputType) -> PathBuf {
609 .and_then(|p| p.to_owned())
610 .or_else(|| self.single_output_file.clone())
611 .unwrap_or_else(|| self.temp_path(flavor, None))
614 /// Gets the path where a compilation artifact of the given type for the
615 /// given codegen unit should be placed on disk. If codegen_unit_name is
616 /// None, a path distinct from those of any codegen unit will be generated.
617 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
618 let extension = flavor.extension();
619 self.temp_path_ext(extension, codegen_unit_name)
622 /// Like `temp_path`, but specifically for dwarf objects.
623 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
624 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
627 /// Like `temp_path`, but also supports things where there is no corresponding
628 /// OutputType, like noopt-bitcode or lto-bitcode.
629 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
630 let mut extension = String::new();
632 if let Some(codegen_unit_name) = codegen_unit_name {
633 extension.push_str(codegen_unit_name);
637 if !extension.is_empty() {
639 extension.push_str(RUST_CGU_EXT);
643 extension.push_str(ext);
646 self.with_extension(&extension)
649 pub fn with_extension(&self, extension: &str) -> PathBuf {
650 let mut path = self.out_directory.join(&self.filestem);
651 path.set_extension(extension);
655 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
656 /// mode is being used, which is the logic that this function is intended to encapsulate.
657 pub fn split_dwarf_path(
659 split_debuginfo_kind: SplitDebuginfo,
660 cgu_name: Option<&str>,
661 ) -> Option<PathBuf> {
662 let obj_out = self.temp_path(OutputType::Object, cgu_name);
663 let dwo_out = self.temp_path_dwo(cgu_name);
664 match split_debuginfo_kind {
665 SplitDebuginfo::Off => None,
666 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
667 // (pointing at the path which is being determined here). Use the path to the current
669 SplitDebuginfo::Packed => Some(obj_out),
670 // Split mode emits the DWARF into a different file, use that path.
671 SplitDebuginfo::Unpacked => Some(dwo_out),
676 pub fn host_triple() -> &'static str {
677 // Get the host triple out of the build environment. This ensures that our
678 // idea of the host triple is the same as for the set of libraries we've
679 // actually built. We can't just take LLVM's host triple because they
680 // normalize all ix86 architectures to i386.
682 // Instead of grabbing the host triple (for the current host), we grab (at
683 // compile time) the target triple that this rustc is built with and
684 // calling that (at runtime) the host triple.
685 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
688 impl Default for Options {
689 fn default() -> Options {
691 crate_types: Vec::new(),
692 optimize: OptLevel::No,
693 debuginfo: DebugInfo::None,
694 lint_opts: Vec::new(),
696 describe_lints: false,
697 output_types: OutputTypes(BTreeMap::new()),
698 search_paths: vec![],
700 target_triple: TargetTriple::from_triple(host_triple()),
703 debugging_opts: Default::default(),
705 borrowck_mode: BorrowckMode::Migrate,
706 cg: Default::default(),
707 error_format: ErrorOutputType::default(),
708 externs: Externs(BTreeMap::new()),
709 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
713 unstable_features: UnstableFeatures::Disallow,
714 debug_assertions: true,
715 actually_rustdoc: false,
716 trimmed_def_paths: TrimmedDefPaths::default(),
717 cli_forced_codegen_units: None,
718 cli_forced_thinlto_off: false,
719 remap_path_prefix: Vec::new(),
720 real_rust_source_base_dir: None,
721 edition: DEFAULT_EDITION,
722 json_artifact_notifications: false,
723 json_unused_externs: false,
725 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
731 /// Returns `true` if there is a reason to build the dep graph.
732 pub fn build_dep_graph(&self) -> bool {
733 self.incremental.is_some()
734 || self.debugging_opts.dump_dep_graph
735 || self.debugging_opts.query_dep_graph
738 pub fn file_path_mapping(&self) -> FilePathMapping {
739 FilePathMapping::new(self.remap_path_prefix.clone())
742 /// Returns `true` if there will be an output file generated.
743 pub fn will_create_output_file(&self) -> bool {
744 !self.debugging_opts.parse_only && // The file is just being parsed
745 !self.debugging_opts.ls // The file is just being queried
749 pub fn share_generics(&self) -> bool {
750 match self.debugging_opts.share_generics {
751 Some(setting) => setting,
752 None => match self.optimize {
753 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
754 OptLevel::Default | OptLevel::Aggressive => false,
760 impl DebuggingOptions {
761 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
764 treat_err_as_bug: self.treat_err_as_bug,
765 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
766 report_delayed_bugs: self.report_delayed_bugs,
767 macro_backtrace: self.macro_backtrace,
768 deduplicate_diagnostics: self.deduplicate_diagnostics,
772 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
773 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
777 // The type of entry function, so users can have their own entry functions
778 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
779 pub enum EntryFnType {
784 impl_stable_hash_via_hash!(EntryFnType);
786 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
796 impl_stable_hash_via_hash!(CrateType);
798 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
805 pub fn is_empty(&self) -> bool {
807 Passes::Some(ref v) => v.is_empty(),
808 Passes::All => false,
813 pub const fn default_lib_output() -> CrateType {
817 fn default_configuration(sess: &Session) -> CrateConfig {
818 let end = &sess.target.endian;
819 let arch = &sess.target.arch;
820 let wordsz = sess.target.pointer_width.to_string();
821 let os = &sess.target.os;
822 let env = &sess.target.env;
823 let abi = &sess.target.abi;
824 let vendor = &sess.target.vendor;
825 let min_atomic_width = sess.target.min_atomic_width();
826 let max_atomic_width = sess.target.max_atomic_width();
827 let atomic_cas = sess.target.atomic_cas;
828 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
832 let mut ret = FxHashSet::default();
833 ret.reserve(7); // the minimum number of insertions
835 ret.insert((sym::target_os, Some(Symbol::intern(os))));
836 for fam in &sess.target.families {
837 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
838 if fam == "windows" {
839 ret.insert((sym::windows, None));
840 } else if fam == "unix" {
841 ret.insert((sym::unix, None));
844 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
845 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
846 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
847 ret.insert((sym::target_env, Some(Symbol::intern(env))));
848 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
849 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
850 if sess.target.has_elf_tls {
851 ret.insert((sym::target_thread_local, None));
854 (8, layout.i8_align.abi),
855 (16, layout.i16_align.abi),
856 (32, layout.i32_align.abi),
857 (64, layout.i64_align.abi),
858 (128, layout.i128_align.abi),
860 if i >= min_atomic_width && i <= max_atomic_width {
861 let mut insert_atomic = |s, align: Align| {
862 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
864 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
866 if align.bits() == i {
867 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
870 let s = i.to_string();
871 insert_atomic(&s, align);
873 insert_atomic("ptr", layout.pointer_align.abi);
878 let panic_strategy = sess.panic_strategy();
879 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
881 for s in sess.opts.debugging_opts.sanitizer {
882 let symbol = Symbol::intern(&s.to_string());
883 ret.insert((sym::sanitize, Some(symbol)));
886 if sess.opts.debug_assertions {
887 ret.insert((sym::debug_assertions, None));
889 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
890 ret.insert((sym::proc_macro, None));
895 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
896 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
897 /// but the symbol interner is not yet set up then, so we must convert it later.
898 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
899 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
902 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
903 // Combine the configuration requested by the session (command line) with
904 // some default and generated configuration items.
905 let default_cfg = default_configuration(sess);
906 // If the user wants a test runner, then add the test cfg.
908 user_cfg.insert((sym::test, None));
910 user_cfg.extend(default_cfg.iter().cloned());
914 pub(super) fn build_target_config(
916 target_override: Option<Target>,
919 let target_result = target_override.map_or_else(
920 || Target::search(&opts.target_triple, sysroot),
921 |t| Ok((t, TargetWarnings::empty())),
923 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
927 "Error loading target specification: {}. \
928 Run `rustc --print target-list` for a list of built-in targets",
933 for warning in target_warnings.warning_messages() {
934 early_warn(opts.error_format, &warning)
937 if !matches!(target.pointer_width, 16 | 32 | 64) {
941 "target specification was invalid: \
942 unrecognized target-pointer-width {}",
951 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
952 pub enum OptionStability {
957 pub struct RustcOptGroup {
958 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
959 pub name: &'static str,
960 pub stability: OptionStability,
964 pub fn is_stable(&self) -> bool {
965 self.stability == OptionStability::Stable
968 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
970 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
972 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
975 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
977 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
979 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
983 // The `opt` local module holds wrappers around the `getopts` API that
984 // adds extra rustc-specific metadata to each option; such metadata
985 // is exposed by . The public
986 // functions below ending with `_u` are the functions that return
987 // *unstable* options, i.e., options that are only enabled when the
988 // user also passes the `-Z unstable-options` debugging flag.
990 // The `fn flag*` etc below are written so that we can use them
991 // in the future; do not warn about them not being used right now.
994 use super::RustcOptGroup;
996 pub type R = RustcOptGroup;
997 pub type S = &'static str;
999 fn stable<F>(name: S, f: F) -> R
1001 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1003 RustcOptGroup::stable(name, f)
1006 fn unstable<F>(name: S, f: F) -> R
1008 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1010 RustcOptGroup::unstable(name, f)
1013 fn longer(a: S, b: S) -> S {
1014 if a.len() > b.len() { a } else { b }
1017 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1018 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1020 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1021 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1023 pub fn flag_s(a: S, b: S, c: S) -> R {
1024 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1026 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1027 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1030 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1031 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1033 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1034 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1038 /// Returns the "short" subset of the rustc command line options,
1039 /// including metadata for each option, such as whether the option is
1040 /// part of the stable long-term interface for rustc.
1041 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1043 opt::flag_s("h", "help", "Display this message"),
1044 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1048 "Add a directory to the library search path. The
1049 optional KIND can be one of dependency, crate, native,
1050 framework, or all (the default).",
1056 "Link the generated crate(s) to the specified native
1057 library NAME. The optional KIND can be one of
1058 static, framework, or dylib (the default).
1059 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1060 may be specified each with a prefix of either '+' to
1061 enable or '-' to disable.",
1062 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1064 make_crate_type_option(),
1065 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1069 "Specify which edition of the compiler to use when compiling code.",
1075 "Comma separated list of types of output for \
1076 the compiler to emit",
1077 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1082 "Compiler information to print on stdout",
1083 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1084 target-cpus|target-features|relocation-models|\
1085 code-models|tls-models|target-spec-json|native-static-libs]",
1087 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1088 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1089 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1093 "Write output to compiler-chosen filename \
1100 "Provide a detailed explanation of an error \
1104 opt::flag_s("", "test", "Build a test harness"),
1105 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1106 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1107 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1108 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1109 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1110 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1114 "Set the most restrictive lint level. \
1115 More restrictive lints are capped at this \
1119 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1120 opt::flag_s("V", "version", "Print version info and exit"),
1121 opt::flag_s("v", "verbose", "Use verbose output"),
1125 /// Returns all rustc command line options, including metadata for
1126 /// each option, such as whether the option is part of the stable
1127 /// long-term interface for rustc.
1128 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1129 let mut opts = rustc_short_optgroups();
1134 "Specify where an external rust library is located",
1140 "Location where an external crate dependency is specified",
1143 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1144 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1148 "How errors and other messages are produced",
1151 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1155 "Configure coloring of output:
1156 auto = colorize, if output goes to a tty (default);
1157 always = always colorize output;
1158 never = never colorize output",
1159 "auto|always|never",
1163 "remap-path-prefix",
1164 "Remap source names in all output (compiler messages and output files)",
1171 pub fn get_cmd_lint_options(
1172 matches: &getopts::Matches,
1173 error_format: ErrorOutputType,
1174 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1175 let mut lint_opts_with_position = vec![];
1176 let mut describe_lints = false;
1178 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1179 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1180 if lint_name == "help" {
1181 describe_lints = true;
1183 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1188 lint_opts_with_position.sort_by_key(|x| x.0);
1189 let lint_opts = lint_opts_with_position
1192 .map(|(_, lint_name, level)| (lint_name, level))
1195 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1196 lint::Level::from_str(&cap)
1197 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1200 (lint_opts, describe_lints, lint_cap)
1203 /// Parses the `--color` flag.
1204 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1205 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1206 Some("auto") => ColorConfig::Auto,
1207 Some("always") => ColorConfig::Always,
1208 Some("never") => ColorConfig::Never,
1210 None => ColorConfig::Auto,
1212 Some(arg) => early_error(
1213 ErrorOutputType::default(),
1215 "argument for `--color` must be auto, \
1216 always or never (instead was `{}`)",
1223 /// Possible json config files
1224 pub struct JsonConfig {
1225 pub json_rendered: HumanReadableErrorType,
1226 pub json_artifact_notifications: bool,
1227 pub json_unused_externs: bool,
1230 /// Parse the `--json` flag.
1232 /// The first value returned is how to render JSON diagnostics, and the second
1233 /// is whether or not artifact notifications are enabled.
1234 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1235 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1236 HumanReadableErrorType::Default;
1237 let mut json_color = ColorConfig::Never;
1238 let mut json_artifact_notifications = false;
1239 let mut json_unused_externs = false;
1240 for option in matches.opt_strs("json") {
1241 // For now conservatively forbid `--color` with `--json` since `--json`
1242 // won't actually be emitting any colors and anything colorized is
1243 // embedded in a diagnostic message anyway.
1244 if matches.opt_str("color").is_some() {
1246 ErrorOutputType::default(),
1247 "cannot specify the `--color` option with `--json`",
1251 for sub_option in option.split(',') {
1253 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1254 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1255 "artifacts" => json_artifact_notifications = true,
1256 "unused-externs" => json_unused_externs = true,
1258 ErrorOutputType::default(),
1259 &format!("unknown `--json` option `{}`", s),
1266 json_rendered: json_rendered(json_color),
1267 json_artifact_notifications,
1268 json_unused_externs,
1272 /// Parses the `--error-format` flag.
1273 pub fn parse_error_format(
1274 matches: &getopts::Matches,
1276 json_rendered: HumanReadableErrorType,
1277 ) -> ErrorOutputType {
1278 // We need the `opts_present` check because the driver will send us Matches
1279 // with only stable options if no unstable options are used. Since error-format
1280 // is unstable, it will not be present. We have to use `opts_present` not
1281 // `opt_present` because the latter will panic.
1282 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1283 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1284 None | Some("human") => {
1285 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1287 Some("human-annotate-rs") => {
1288 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1290 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1291 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1292 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1294 Some(arg) => early_error(
1295 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1297 "argument for `--error-format` must be `human`, `json` or \
1298 `short` (instead was `{}`)",
1304 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1307 match error_format {
1308 ErrorOutputType::Json { .. } => {}
1310 // Conservatively require that the `--json` argument is coupled with
1311 // `--error-format=json`. This means that `--json` is specified we
1312 // should actually be emitting JSON blobs.
1313 _ if !matches.opt_strs("json").is_empty() => {
1315 ErrorOutputType::default(),
1316 "using `--json` requires also using `--error-format=json`",
1326 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1327 let edition = match matches.opt_str("edition") {
1328 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1330 ErrorOutputType::default(),
1332 "argument for `--edition` must be one of: \
1333 {}. (instead was `{}`)",
1334 EDITION_NAME_LIST, arg
1338 None => DEFAULT_EDITION,
1341 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1342 let is_nightly = nightly_options::match_is_nightly_build(matches);
1343 let msg = if !is_nightly {
1345 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1346 edition, LATEST_STABLE_EDITION
1349 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1351 early_error(ErrorOutputType::default(), &msg)
1357 fn check_debug_option_stability(
1358 debugging_opts: &DebuggingOptions,
1359 error_format: ErrorOutputType,
1360 json_rendered: HumanReadableErrorType,
1362 if !debugging_opts.unstable_options {
1363 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1365 ErrorOutputType::Json { pretty: false, json_rendered },
1366 "`--error-format=pretty-json` is unstable",
1369 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1373 ErrorOutputType::Json { pretty: false, json_rendered },
1374 "`--error-format=human-annotate-rs` is unstable",
1380 fn parse_output_types(
1381 debugging_opts: &DebuggingOptions,
1382 matches: &getopts::Matches,
1383 error_format: ErrorOutputType,
1385 let mut output_types = BTreeMap::new();
1386 if !debugging_opts.parse_only {
1387 for list in matches.opt_strs("emit") {
1388 for output_type in list.split(',') {
1389 let (shorthand, path) = match output_type.split_once('=') {
1390 None => (output_type, None),
1391 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1393 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1397 "unknown emission type: `{}` - expected one of: {}",
1399 OutputType::shorthands_display(),
1403 output_types.insert(output_type, path);
1407 if output_types.is_empty() {
1408 output_types.insert(OutputType::Exe, None);
1410 OutputTypes(output_types)
1413 fn should_override_cgus_and_disable_thinlto(
1414 output_types: &OutputTypes,
1415 matches: &getopts::Matches,
1416 error_format: ErrorOutputType,
1417 mut codegen_units: Option<usize>,
1418 ) -> (bool, Option<usize>) {
1419 let mut disable_thinlto = false;
1420 // Issue #30063: if user requests LLVM-related output to one
1421 // particular path, disable codegen-units.
1422 let incompatible: Vec<_> = output_types
1425 .map(|ot_path| ot_path.0)
1426 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1427 .map(|ot| ot.shorthand())
1429 if !incompatible.is_empty() {
1430 match codegen_units {
1431 Some(n) if n > 1 => {
1432 if matches.opt_present("o") {
1433 for ot in &incompatible {
1437 "`--emit={}` with `-o` incompatible with \
1438 `-C codegen-units=N` for N > 1",
1443 early_warn(error_format, "resetting to default -C codegen-units=1");
1444 codegen_units = Some(1);
1445 disable_thinlto = true;
1449 codegen_units = Some(1);
1450 disable_thinlto = true;
1455 if codegen_units == Some(0) {
1456 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1459 (disable_thinlto, codegen_units)
1462 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1463 if debugging_opts.threads == 0 {
1464 early_error(error_format, "value for threads must be a positive non-zero integer");
1467 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1468 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1472 fn collect_print_requests(
1473 cg: &mut CodegenOptions,
1474 dopts: &mut DebuggingOptions,
1475 matches: &getopts::Matches,
1476 error_format: ErrorOutputType,
1477 ) -> Vec<PrintRequest> {
1478 let mut prints = Vec::<PrintRequest>::new();
1479 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1480 prints.push(PrintRequest::TargetCPUs);
1481 cg.target_cpu = None;
1483 if cg.target_feature == "help" {
1484 prints.push(PrintRequest::TargetFeatures);
1485 cg.target_feature = String::new();
1488 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1489 "crate-name" => PrintRequest::CrateName,
1490 "file-names" => PrintRequest::FileNames,
1491 "sysroot" => PrintRequest::Sysroot,
1492 "target-libdir" => PrintRequest::TargetLibdir,
1493 "cfg" => PrintRequest::Cfg,
1494 "target-list" => PrintRequest::TargetList,
1495 "target-cpus" => PrintRequest::TargetCPUs,
1496 "target-features" => PrintRequest::TargetFeatures,
1497 "relocation-models" => PrintRequest::RelocationModels,
1498 "code-models" => PrintRequest::CodeModels,
1499 "tls-models" => PrintRequest::TlsModels,
1500 "native-static-libs" => PrintRequest::NativeStaticLibs,
1501 "target-spec-json" => {
1502 if dopts.unstable_options {
1503 PrintRequest::TargetSpec
1507 "the `-Z unstable-options` flag must also be passed to \
1508 enable the target-spec-json print option",
1512 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1518 pub fn parse_target_triple(
1519 matches: &getopts::Matches,
1520 error_format: ErrorOutputType,
1522 match matches.opt_str("target") {
1523 Some(target) if target.ends_with(".json") => {
1524 let path = Path::new(&target);
1525 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1526 early_error(error_format, &format!("target file {:?} does not exist", path))
1529 Some(target) => TargetTriple::TargetTriple(target),
1530 _ => TargetTriple::from_triple(host_triple()),
1535 matches: &getopts::Matches,
1536 cg: &CodegenOptions,
1537 error_format: ErrorOutputType,
1539 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1540 // to use them interchangeably. However, because they're technically different flags,
1541 // we need to work out manually which should take precedence if both are supplied (i.e.
1542 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1543 // comparing them. Note that if a flag is not found, its position will be `None`, which
1544 // always compared less than `Some(_)`.
1545 let max_o = matches.opt_positions("O").into_iter().max();
1549 .flat_map(|(i, s)| {
1550 // NB: This can match a string without `=`.
1551 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1557 match cg.opt_level.as_ref() {
1558 "0" => OptLevel::No,
1559 "1" => OptLevel::Less,
1560 "2" => OptLevel::Default,
1561 "3" => OptLevel::Aggressive,
1562 "s" => OptLevel::Size,
1563 "z" => OptLevel::SizeMin,
1568 "optimization level needs to be \
1569 between 0-3, s or z (instead was `{}`)",
1578 fn select_debuginfo(
1579 matches: &getopts::Matches,
1580 cg: &CodegenOptions,
1581 error_format: ErrorOutputType,
1583 let max_g = matches.opt_positions("g").into_iter().max();
1587 .flat_map(|(i, s)| {
1588 // NB: This can match a string without `=`.
1589 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1595 match cg.debuginfo {
1596 0 => DebugInfo::None,
1597 1 => DebugInfo::Limited,
1598 2 => DebugInfo::Full,
1603 "debug info level needs to be between \
1604 0-2 (instead was `{}`)",
1613 fn parse_native_lib_kind(
1614 matches: &getopts::Matches,
1616 error_format: ErrorOutputType,
1617 ) -> (NativeLibKind, Option<bool>) {
1618 let is_nightly = nightly_options::match_is_nightly_build(matches);
1619 let enable_unstable = nightly_options::is_unstable_enabled(matches);
1621 let (kind, modifiers) = match kind.split_once(':') {
1622 None => (kind, None),
1623 Some((kind, modifiers)) => (kind, Some(modifiers)),
1626 let kind = match kind {
1627 "dylib" => NativeLibKind::Dylib { as_needed: None },
1628 "framework" => NativeLibKind::Framework { as_needed: None },
1629 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1630 "static-nobundle" => {
1633 "library kind `static-nobundle` has been superseded by specifying \
1634 `-bundle` on library kind `static`. Try `static:-bundle`",
1636 if modifiers.is_some() {
1639 "linking modifier can't be used with library kind `static-nobundle`",
1645 "library kind `static-nobundle` are currently unstable and only accepted on \
1646 the nightly compiler",
1649 NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1653 &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1657 None => (kind, None),
1658 Some(modifiers) => {
1662 "linking modifiers are currently unstable and only accepted on \
1663 the nightly compiler",
1666 if !enable_unstable {
1669 "linking modifiers are currently unstable, \
1670 the `-Z unstable-options` flag must also be passed to use it",
1673 parse_native_lib_modifiers(kind, modifiers, error_format)
1678 fn parse_native_lib_modifiers(
1679 mut kind: NativeLibKind,
1681 error_format: ErrorOutputType,
1682 ) -> (NativeLibKind, Option<bool>) {
1683 let mut verbatim = None;
1684 for modifier in modifiers.split(',') {
1685 let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
1686 Some(m) => (m, modifier.starts_with('+')),
1687 None => early_error(
1689 "invalid linking modifier syntax, expected '+' or '-' prefix \
1690 before one of: bundle, verbatim, whole-archive, as-needed",
1694 match (modifier, &mut kind) {
1695 ("bundle", NativeLibKind::Static { bundle, .. }) => {
1696 *bundle = Some(value);
1698 ("bundle", _) => early_error(
1700 "bundle linking modifier is only compatible with \
1701 `static` linking kind",
1704 ("verbatim", _) => verbatim = Some(value),
1706 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1707 *whole_archive = Some(value);
1709 ("whole-archive", _) => early_error(
1711 "whole-archive linking modifier is only compatible with \
1712 `static` linking kind",
1715 ("as-needed", NativeLibKind::Dylib { as_needed })
1716 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1717 *as_needed = Some(value);
1719 ("as-needed", _) => early_error(
1721 "as-needed linking modifier is only compatible with \
1722 `dylib` and `framework` linking kinds",
1728 "unrecognized linking modifier `{}`, expected one \
1729 of: bundle, verbatim, whole-archive, as-needed",
1739 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1744 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1745 // where KIND is one of "dylib", "framework", "static" and
1746 // where MODIFIERS are a comma separated list of supported modifiers
1747 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1748 // with either + or - to indicate whether it is enabled or disabled.
1749 // The last value specified for a given modifier wins.
1750 let (name, kind, verbatim) = match s.split_once('=') {
1751 None => (s, NativeLibKind::Unspecified, None),
1752 Some((kind, name)) => {
1753 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
1754 (name.to_string(), kind, verbatim)
1758 let (name, new_name) = match name.split_once(':') {
1759 None => (name, None),
1760 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1762 NativeLib { name, new_name, kind, verbatim }
1767 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1768 match dopts.borrowck.as_ref() {
1769 "migrate" => BorrowckMode::Migrate,
1770 "mir" => BorrowckMode::Mir,
1771 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1775 pub fn parse_externs(
1776 matches: &getopts::Matches,
1777 debugging_opts: &DebuggingOptions,
1778 error_format: ErrorOutputType,
1780 let is_unstable_enabled = debugging_opts.unstable_options;
1781 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1782 for arg in matches.opt_strs("extern") {
1783 let (name, path) = match arg.split_once('=') {
1784 None => (arg, None),
1785 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1787 let (options, name) = match name.split_once(':') {
1788 None => (None, name),
1789 Some((opts, name)) => (Some(opts), name.to_string()),
1792 let path = path.map(|p| CanonicalizedPath::new(p));
1794 let entry = externs.entry(name.to_owned());
1796 use std::collections::btree_map::Entry;
1798 let entry = if let Some(path) = path {
1799 // --extern prelude_name=some_file.rlib
1801 Entry::Vacant(vacant) => {
1802 let files = BTreeSet::from_iter(iter::once(path));
1803 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1805 Entry::Occupied(occupied) => {
1806 let ext_ent = occupied.into_mut();
1808 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1812 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1815 // Exact paths take precedence over search directories.
1816 let files = BTreeSet::from_iter(iter::once(path));
1817 *location = ExternLocation::ExactPaths(files);
1824 // --extern prelude_name
1826 Entry::Vacant(vacant) => {
1827 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1829 Entry::Occupied(occupied) => {
1830 // Ignore if already specified.
1836 let mut is_private_dep = false;
1837 let mut add_prelude = true;
1838 if let Some(opts) = options {
1839 if !is_unstable_enabled {
1842 "the `-Z unstable-options` flag must also be passed to \
1843 enable `--extern options",
1846 for opt in opts.split(',') {
1848 "priv" => is_private_dep = true,
1850 if let ExternLocation::ExactPaths(_) = &entry.location {
1851 add_prelude = false;
1855 "the `noprelude` --extern option requires a file path",
1859 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1864 // Crates start out being not private, and go to being private `priv`
1866 entry.is_private_dep |= is_private_dep;
1867 // If any flag is missing `noprelude`, then add to the prelude.
1868 entry.add_prelude |= add_prelude;
1873 fn parse_extern_dep_specs(
1874 matches: &getopts::Matches,
1875 debugging_opts: &DebuggingOptions,
1876 error_format: ErrorOutputType,
1877 ) -> ExternDepSpecs {
1878 let is_unstable_enabled = debugging_opts.unstable_options;
1879 let mut map = BTreeMap::new();
1881 for arg in matches.opt_strs("extern-location") {
1882 if !is_unstable_enabled {
1885 "`--extern-location` option is unstable: set `-Z unstable-options`",
1889 let mut parts = arg.splitn(2, '=');
1890 let name = parts.next().unwrap_or_else(|| {
1891 early_error(error_format, "`--extern-location` value must not be empty")
1893 let loc = parts.next().unwrap_or_else(|| {
1896 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1900 let locparts: Vec<_> = loc.split(':').collect();
1901 let spec = match &locparts[..] {
1903 // Don't want `:` split string
1904 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1905 early_error(error_format, "`--extern-location`: missing `raw` location")
1907 ExternDepSpec::Raw(raw.to_string())
1910 // Don't want `:` split string
1911 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1912 early_error(error_format, "`--extern-location`: missing `json` location")
1914 let json = json::from_str(raw).unwrap_or_else(|_| {
1917 &format!("`--extern-location`: malformed json location `{}`", raw),
1920 ExternDepSpec::Json(json)
1922 [bad, ..] => early_error(
1924 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1926 [] => early_error(error_format, "missing location specification"),
1929 map.insert(name.to_string(), spec);
1932 ExternDepSpecs::new(map)
1935 fn parse_remap_path_prefix(
1936 matches: &getopts::Matches,
1937 debugging_opts: &DebuggingOptions,
1938 error_format: ErrorOutputType,
1939 ) -> Vec<(PathBuf, PathBuf)> {
1940 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
1941 .opt_strs("remap-path-prefix")
1943 .map(|remap| match remap.rsplit_once('=') {
1944 None => early_error(
1946 "--remap-path-prefix must contain '=' between FROM and TO",
1948 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1951 match &debugging_opts.remap_cwd_prefix {
1952 Some(to) => match std::env::current_dir() {
1953 Ok(cwd) => mapping.push((cwd, to.clone())),
1961 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1962 let color = parse_color(matches);
1964 let edition = parse_crate_edition(matches);
1966 let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
1967 parse_json(matches);
1969 let error_format = parse_error_format(matches, color, json_rendered);
1971 let unparsed_crate_types = matches.opt_strs("crate-type");
1972 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1973 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1975 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
1976 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1978 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1980 if !debugging_opts.unstable_options && json_unused_externs {
1983 "the `-Z unstable-options` flag must also be passed to enable \
1984 the flag `--json=unused-externs`",
1988 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1990 let mut cg = CodegenOptions::build(matches, error_format);
1991 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1998 check_thread_count(&debugging_opts, error_format);
2000 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2002 if debugging_opts.profile && incremental.is_some() {
2005 "can't instrument with gcov profiling when compiling incrementally",
2008 if debugging_opts.profile {
2009 match codegen_units {
2011 None => codegen_units = Some(1),
2012 Some(_) => early_error(
2014 "can't instrument with gcov profiling with multiple codegen units",
2019 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2022 "options `-C profile-generate` and `-C profile-use` are exclusive",
2026 if debugging_opts.profile_sample_use.is_some()
2027 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2031 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2035 if debugging_opts.instrument_coverage.is_some()
2036 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
2038 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2041 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2042 or `-C profile-generate`",
2046 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
2047 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2048 // multiple runs, including some changes to source code; so mangled names must be consistent
2049 // across compilations.
2050 match debugging_opts.symbol_mangling_version {
2052 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
2054 Some(SymbolManglingVersion::Legacy) => {
2057 "-Z instrument-coverage requires symbol mangling version `v0`, \
2058 but `-Z symbol-mangling-version=legacy` was specified",
2061 Some(SymbolManglingVersion::V0) => {}
2065 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2066 debugging_opts.graphviz_font = graphviz_font;
2069 if !cg.embed_bitcode {
2071 LtoCli::No | LtoCli::Unspecified => {}
2072 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2074 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2079 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2083 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2084 let target_triple = parse_target_triple(matches, error_format);
2085 let opt_level = parse_opt_level(matches, &cg, error_format);
2086 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2087 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2088 // for more details.
2089 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2090 let debuginfo = select_debuginfo(matches, &cg, error_format);
2092 let mut search_paths = vec![];
2093 for s in &matches.opt_strs("L") {
2094 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2097 let libs = parse_libs(matches, error_format);
2099 let test = matches.opt_present("test");
2101 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2103 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2104 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2107 let externs = parse_externs(matches, &debugging_opts, error_format);
2108 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2110 let crate_name = matches.opt_str("crate-name");
2112 let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2114 let pretty = parse_pretty(&debugging_opts, error_format);
2116 if !debugging_opts.unstable_options
2117 && !target_triple.triple().contains("apple")
2118 && cg.split_debuginfo.is_some()
2121 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2125 // Try to find a directory containing the Rust `src`, for more details see
2126 // the doc comment on the `real_rust_source_base_dir` field.
2128 let sysroot = match &sysroot_opt {
2131 tmp_buf = crate::filesearch::get_or_default_sysroot();
2135 let real_rust_source_base_dir = {
2136 // This is the location used by the `rust-src` `rustup` component.
2137 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2138 if let Ok(metadata) = candidate.symlink_metadata() {
2139 // Replace the symlink rustbuild creates, with its destination.
2140 // We could try to use `fs::canonicalize` instead, but that might
2141 // produce unnecessarily verbose path.
2142 if metadata.file_type().is_symlink() {
2143 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2144 candidate = symlink_dest;
2149 // Only use this directory if it has a file we can expect to always find.
2150 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2153 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2154 early_error(error_format, &format!("Current directory is invalid: {}", e));
2157 let (path, remapped) =
2158 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2159 let working_dir = if remapped {
2160 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2162 RealFileName::LocalPath(path)
2167 optimize: opt_level,
2174 maybe_sysroot: sysroot_opt,
2184 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2190 actually_rustdoc: false,
2191 trimmed_def_paths: TrimmedDefPaths::default(),
2192 cli_forced_codegen_units: codegen_units,
2193 cli_forced_thinlto_off: disable_thinlto,
2195 real_rust_source_base_dir,
2197 json_artifact_notifications,
2198 json_unused_externs,
2204 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2207 let first = match debugging_opts.unpretty.as_deref()? {
2208 "normal" => Source(PpSourceMode::Normal),
2209 "identified" => Source(PpSourceMode::Identified),
2210 "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
2211 "expanded" => Source(PpSourceMode::Expanded),
2212 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2213 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2214 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2215 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2216 "hir" => Hir(PpHirMode::Normal),
2217 "hir,identified" => Hir(PpHirMode::Identified),
2218 "hir,typed" => Hir(PpHirMode::Typed),
2219 "hir-tree" => HirTree,
2220 "thir-tree" => ThirTree,
2222 "mir-cfg" => MirCFG,
2223 name => early_error(
2226 "argument to `unpretty` must be one of `normal`, \
2227 `expanded`, `identified`, `expanded,identified`, \
2228 `expanded,hygiene`, `everybody_loops`, \
2229 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2230 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2235 tracing::debug!("got unpretty option: {:?}", first);
2239 pub fn make_crate_type_option() -> RustcOptGroup {
2243 "Comma separated list of types of crates
2244 for the compiler to emit",
2245 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2249 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2250 let mut crate_types: Vec<CrateType> = Vec::new();
2251 for unparsed_crate_type in &list_list {
2252 for part in unparsed_crate_type.split(',') {
2253 let new_part = match part {
2254 "lib" => default_lib_output(),
2255 "rlib" => CrateType::Rlib,
2256 "staticlib" => CrateType::Staticlib,
2257 "dylib" => CrateType::Dylib,
2258 "cdylib" => CrateType::Cdylib,
2259 "bin" => CrateType::Executable,
2260 "proc-macro" => CrateType::ProcMacro,
2261 _ => return Err(format!("unknown crate type: `{}`", part)),
2263 if !crate_types.contains(&new_part) {
2264 crate_types.push(new_part)
2272 pub mod nightly_options {
2273 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2274 use crate::early_error;
2275 use rustc_feature::UnstableFeatures;
2277 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2278 match_is_nightly_build(matches)
2279 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2282 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2283 is_nightly_build(matches.opt_str("crate-name").as_deref())
2286 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2287 UnstableFeatures::from_environment(krate).is_nightly_build()
2290 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2291 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2292 let really_allows_unstable_options = match_is_nightly_build(matches);
2294 for opt in flags.iter() {
2295 if opt.stability == OptionStability::Stable {
2298 if !matches.opt_present(opt.name) {
2301 if opt.name != "Z" && !has_z_unstable_option {
2303 ErrorOutputType::default(),
2305 "the `-Z unstable-options` flag must also be passed to enable \
2311 if really_allows_unstable_options {
2314 match opt.stability {
2315 OptionStability::Unstable => {
2317 "the option `{}` is only accepted on the \
2321 early_error(ErrorOutputType::default(), &msg);
2323 OptionStability::Stable => {}
2329 impl fmt::Display for CrateType {
2330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2332 CrateType::Executable => "bin".fmt(f),
2333 CrateType::Dylib => "dylib".fmt(f),
2334 CrateType::Rlib => "rlib".fmt(f),
2335 CrateType::Staticlib => "staticlib".fmt(f),
2336 CrateType::Cdylib => "cdylib".fmt(f),
2337 CrateType::ProcMacro => "proc-macro".fmt(f),
2342 #[derive(Copy, Clone, PartialEq, Debug)]
2343 pub enum PpSourceMode {
2344 /// `-Zunpretty=normal`
2346 /// `-Zunpretty=everybody_loops`
2348 /// `-Zunpretty=expanded`
2350 /// `-Zunpretty=identified`
2352 /// `-Zunpretty=expanded,identified`
2354 /// `-Zunpretty=expanded,hygiene`
2358 #[derive(Copy, Clone, PartialEq, Debug)]
2359 pub enum PpAstTreeMode {
2360 /// `-Zunpretty=ast`
2362 /// `-Zunpretty=ast,expanded`
2366 #[derive(Copy, Clone, PartialEq, Debug)]
2367 pub enum PpHirMode {
2368 /// `-Zunpretty=hir`
2370 /// `-Zunpretty=hir,identified`
2372 /// `-Zunpretty=hir,typed`
2376 #[derive(Copy, Clone, PartialEq, Debug)]
2378 /// Options that print the source code, i.e.
2379 /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
2380 Source(PpSourceMode),
2381 AstTree(PpAstTreeMode),
2382 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2384 /// `-Zunpretty=hir-tree`
2386 /// `-Zunpretty=thir-tree`
2388 /// `-Zunpretty=mir`
2390 /// `-Zunpretty=mir-cfg`
2395 pub fn needs_ast_map(&self) -> bool {
2397 use PpSourceMode::*;
2399 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2401 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2402 | AstTree(PpAstTreeMode::Expanded)
2411 pub fn needs_analysis(&self) -> bool {
2413 matches!(*self, Mir | MirCFG | ThirTree)
2417 /// Command-line arguments passed to the compiler have to be incorporated with
2418 /// the dependency tracking system for incremental compilation. This module
2419 /// provides some utilities to make this more convenient.
2421 /// The values of all command-line arguments that are relevant for dependency
2422 /// tracking are hashed into a single value that determines whether the
2423 /// incremental compilation cache can be re-used or not. This hashing is done
2424 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2425 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2426 /// the hash of which is order dependent, but we might not want the order of
2427 /// arguments to make a difference for the hash).
2429 /// However, since the value provided by `Hash::hash` often *is* suitable,
2430 /// especially for primitive types, there is the
2431 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2432 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2433 /// we have an opt-in scheme here, so one is hopefully forced to think about
2434 /// how the hash should be calculated when adding a new command-line argument.
2435 crate mod dep_tracking {
2438 CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2439 LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
2440 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2443 use crate::options::WasiExecModel;
2444 use crate::utils::{NativeLib, NativeLibKind};
2445 use rustc_feature::UnstableFeatures;
2446 use rustc_span::edition::Edition;
2447 use rustc_span::RealFileName;
2448 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2449 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
2450 use std::collections::hash_map::DefaultHasher;
2451 use std::collections::BTreeMap;
2452 use std::hash::Hash;
2453 use std::num::NonZeroUsize;
2454 use std::path::PathBuf;
2456 pub trait DepTrackingHash {
2459 hasher: &mut DefaultHasher,
2460 error_format: ErrorOutputType,
2461 for_crate_hash: bool,
2465 macro_rules! impl_dep_tracking_hash_via_hash {
2466 ($($t:ty),+ $(,)?) => {$(
2467 impl DepTrackingHash for $t {
2468 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2469 Hash::hash(self, hasher);
2475 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2478 hasher: &mut DefaultHasher,
2479 error_format: ErrorOutputType,
2480 for_crate_hash: bool,
2484 Hash::hash(&1, hasher);
2485 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2487 None => Hash::hash(&0, hasher),
2492 impl_dep_tracking_hash_via_hash!(
2524 SymbolManglingVersion,
2525 SourceFileHashAlgorithm,
2533 impl<T1, T2> DepTrackingHash for (T1, T2)
2535 T1: DepTrackingHash,
2536 T2: DepTrackingHash,
2540 hasher: &mut DefaultHasher,
2541 error_format: ErrorOutputType,
2542 for_crate_hash: bool,
2544 Hash::hash(&0, hasher);
2545 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2546 Hash::hash(&1, hasher);
2547 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2551 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2553 T1: DepTrackingHash,
2554 T2: DepTrackingHash,
2555 T3: DepTrackingHash,
2559 hasher: &mut DefaultHasher,
2560 error_format: ErrorOutputType,
2561 for_crate_hash: bool,
2563 Hash::hash(&0, hasher);
2564 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2565 Hash::hash(&1, hasher);
2566 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2567 Hash::hash(&2, hasher);
2568 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2572 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2575 hasher: &mut DefaultHasher,
2576 error_format: ErrorOutputType,
2577 for_crate_hash: bool,
2579 Hash::hash(&self.len(), hasher);
2580 for (index, elem) in self.iter().enumerate() {
2581 Hash::hash(&index, hasher);
2582 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2587 impl DepTrackingHash for OutputTypes {
2590 hasher: &mut DefaultHasher,
2591 error_format: ErrorOutputType,
2592 for_crate_hash: bool,
2594 Hash::hash(&self.0.len(), hasher);
2595 for (key, val) in &self.0 {
2596 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2597 if !for_crate_hash {
2598 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2604 // This is a stable hash because BTreeMap is a sorted container
2605 crate fn stable_hash(
2606 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2607 hasher: &mut DefaultHasher,
2608 error_format: ErrorOutputType,
2609 for_crate_hash: bool,
2611 for (key, sub_hash) in sub_hashes {
2612 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2613 // the keys, as they are just plain strings
2614 Hash::hash(&key.len(), hasher);
2615 Hash::hash(key, hasher);
2616 sub_hash.hash(hasher, error_format, for_crate_hash);