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::SourceFileHashAlgorithm;
26 use rustc_errors::emitter::HumanReadableErrorType;
27 use rustc_errors::{ColorConfig, HandlerFlags};
29 use std::collections::btree_map::{
30 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
32 use std::collections::{BTreeMap, BTreeSet};
35 use std::iter::{self, FromIterator};
36 use std::path::{Path, PathBuf};
37 use std::str::{self, FromStr};
39 /// The different settings that the `-Z strip` flag can have.
40 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
42 /// Do not strip at all.
48 /// Strip all symbols.
52 /// The different settings that the `-C control-flow-guard` flag can have.
53 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
55 /// Do not emit Control Flow Guard metadata or checks.
58 /// Emit Control Flow Guard metadata but no checks.
61 /// Emit Control Flow Guard metadata and checks.
65 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
75 impl_stable_hash_via_hash!(OptLevel);
77 /// This is what the `LtoCli` values get mapped to after resolving defaults and
78 /// and taking other command line options into account.
80 /// Note that linker plugin-based LTO is a different mechanism entirely.
81 #[derive(Clone, PartialEq)]
83 /// Don't do any LTO whatsoever.
86 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
89 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
90 /// only relevant if multiple CGUs are used.
93 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
97 /// The different settings that the `-C lto` flag can have.
98 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
110 /// No `-C lto` flag passed
114 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
115 /// document highlighting each span of every statement (including terminators). `Terminator` and
116 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
117 /// computed span for the block, representing the entire range, covering the block's terminator and
118 /// all of its statements.
119 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
120 pub enum MirSpanview {
121 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
123 /// `-Z dump_mir_spanview=terminator`
125 /// `-Z dump_mir_spanview=block`
129 /// The different settings that the `-Z instrument-coverage` flag can have.
131 /// Coverage instrumentation now supports combining `-Z instrument-coverage`
132 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
133 /// and higher). Nevertheless, there are many variables, depending on options
134 /// selected, code structure, and enabled attributes. If errors are encountered,
135 /// either while compiling or when generating `llvm-cov show` reports, consider
136 /// lowering the optimization level, including or excluding `-C link-dead-code`,
137 /// or using `-Z instrument-coverage=except-unused-functions` or `-Z
138 /// instrument-coverage=except-unused-generics`.
140 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
141 /// coverage map, it will not attempt to generate synthetic functions for unused
142 /// (and not code-generated) functions (whether they are generic or not). As a
143 /// result, non-codegenned functions will not be included in the coverage map,
144 /// and will not appear, as covered or uncovered, in coverage reports.
146 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
147 /// unless the function has type parameters.
148 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
149 pub enum InstrumentCoverage {
150 /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
152 /// `-Z instrument-coverage=except-unused-generics`
153 ExceptUnusedGenerics,
154 /// `-Z instrument-coverage=except-unused-functions`
155 ExceptUnusedFunctions,
156 /// `-Z instrument-coverage=off` (or `no`, etc.)
160 #[derive(Clone, PartialEq, Hash, Debug)]
161 pub enum LinkerPluginLto {
162 LinkerPlugin(PathBuf),
167 impl LinkerPluginLto {
168 pub fn enabled(&self) -> bool {
170 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
171 LinkerPluginLto::Disabled => false,
176 #[derive(Clone, PartialEq, Hash, Debug)]
177 pub enum SwitchWithOptPath {
178 Enabled(Option<PathBuf>),
182 impl SwitchWithOptPath {
183 pub fn enabled(&self) -> bool {
185 SwitchWithOptPath::Enabled(_) => true,
186 SwitchWithOptPath::Disabled => false,
191 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
192 #[derive(Encodable, Decodable)]
193 pub enum SymbolManglingVersion {
198 impl_stable_hash_via_hash!(SymbolManglingVersion);
200 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
207 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
208 #[derive(Encodable, Decodable)]
209 pub enum OutputType {
220 impl_stable_hash_via_hash!(OutputType);
223 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
225 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
227 | OutputType::Assembly
228 | OutputType::LlvmAssembly
230 | OutputType::Object => false,
234 fn shorthand(&self) -> &'static str {
236 OutputType::Bitcode => "llvm-bc",
237 OutputType::Assembly => "asm",
238 OutputType::LlvmAssembly => "llvm-ir",
239 OutputType::Mir => "mir",
240 OutputType::Object => "obj",
241 OutputType::Metadata => "metadata",
242 OutputType::Exe => "link",
243 OutputType::DepInfo => "dep-info",
247 fn from_shorthand(shorthand: &str) -> Option<Self> {
248 Some(match shorthand {
249 "asm" => OutputType::Assembly,
250 "llvm-ir" => OutputType::LlvmAssembly,
251 "mir" => OutputType::Mir,
252 "llvm-bc" => OutputType::Bitcode,
253 "obj" => OutputType::Object,
254 "metadata" => OutputType::Metadata,
255 "link" => OutputType::Exe,
256 "dep-info" => OutputType::DepInfo,
261 fn shorthands_display() -> String {
263 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
264 OutputType::Bitcode.shorthand(),
265 OutputType::Assembly.shorthand(),
266 OutputType::LlvmAssembly.shorthand(),
267 OutputType::Mir.shorthand(),
268 OutputType::Object.shorthand(),
269 OutputType::Metadata.shorthand(),
270 OutputType::Exe.shorthand(),
271 OutputType::DepInfo.shorthand(),
275 pub fn extension(&self) -> &'static str {
277 OutputType::Bitcode => "bc",
278 OutputType::Assembly => "s",
279 OutputType::LlvmAssembly => "ll",
280 OutputType::Mir => "mir",
281 OutputType::Object => "o",
282 OutputType::Metadata => "rmeta",
283 OutputType::DepInfo => "d",
284 OutputType::Exe => "",
289 /// The type of diagnostics output to generate.
290 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
291 pub enum ErrorOutputType {
292 /// Output meant for the consumption of humans.
293 HumanReadable(HumanReadableErrorType),
294 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
296 /// Render the JSON in a human readable way (with indents and newlines).
298 /// The JSON output includes a `rendered` field that includes the rendered
300 json_rendered: HumanReadableErrorType,
304 impl Default for ErrorOutputType {
305 fn default() -> Self {
306 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
310 /// Parameter to control path trimming.
311 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
312 pub enum TrimmedDefPaths {
313 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
315 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
317 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
321 impl Default for TrimmedDefPaths {
322 fn default() -> Self {
327 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
328 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
329 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
330 /// should only depend on the output types, not the paths they're written to.
331 #[derive(Clone, Debug, Hash)]
332 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
335 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
336 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
339 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
343 pub fn contains_key(&self, key: &OutputType) -> bool {
344 self.0.contains_key(key)
347 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
351 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
355 pub fn len(&self) -> usize {
359 // Returns `true` if any of the output types require codegen or linking.
360 pub fn should_codegen(&self) -> bool {
361 self.0.keys().any(|k| match *k {
363 | OutputType::Assembly
364 | OutputType::LlvmAssembly
367 | OutputType::Exe => true,
368 OutputType::Metadata | OutputType::DepInfo => false,
372 // Returns `true` if any of the output types require linking.
373 pub fn should_link(&self) -> bool {
374 self.0.keys().any(|k| match *k {
376 | OutputType::Assembly
377 | OutputType::LlvmAssembly
379 | OutputType::Metadata
381 | OutputType::DepInfo => false,
382 OutputType::Exe => true,
387 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
388 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
389 /// would break dependency tracking for command-line arguments.
391 pub struct Externs(BTreeMap<String, ExternEntry>);
394 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
396 #[derive(Clone, Debug)]
397 pub struct ExternEntry {
398 pub location: ExternLocation,
399 /// Indicates this is a "private" dependency for the
400 /// `exported_private_dependencies` lint.
402 /// This can be set with the `priv` option like
403 /// `--extern priv:name=foo.rlib`.
404 pub is_private_dep: bool,
405 /// Add the extern entry to the extern prelude.
407 /// This can be disabled with the `noprelude` option like
408 /// `--extern noprelude:name`.
409 pub add_prelude: bool,
412 #[derive(Clone, Debug)]
413 pub enum ExternLocation {
414 /// Indicates to look for the library in the search paths.
416 /// Added via `--extern name`.
417 FoundInLibrarySearchDirectories,
418 /// The locations where this extern entry must be found.
420 /// The `CrateLoader` is responsible for loading these and figuring out
421 /// which one to use.
423 /// Added via `--extern prelude_name=some_file.rlib`
424 ExactPaths(BTreeSet<CanonicalizedPath>),
427 /// Supplied source location of a dependency - for example in a build specification
428 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
429 /// a file and line, then the build system can specify that. On the other hand, it may
430 /// make more sense to have an arbitrary raw string.
431 #[derive(Clone, PartialEq)]
432 pub enum ExternDepSpec {
435 /// Raw data in json format
439 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
440 fn from(from: &'a ExternDepSpec) -> Self {
442 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
443 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
449 /// Used for testing.
450 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
454 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
458 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
462 pub fn len(&self) -> usize {
468 fn new(location: ExternLocation) -> ExternEntry {
469 ExternEntry { location, is_private_dep: false, add_prelude: false }
472 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
473 match &self.location {
474 ExternLocation::ExactPaths(set) => Some(set.iter()),
480 impl ExternDepSpecs {
481 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
485 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
490 impl fmt::Display for ExternDepSpec {
491 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
493 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
494 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
499 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
500 pub enum PrintRequest {
516 #[derive(Copy, Clone)]
517 pub enum BorrowckMode {
523 /// Returns whether we should run the MIR-based borrow check, but also fall back
524 /// on the AST borrow check if the MIR-based one errors.
525 pub fn migrate(self) -> bool {
527 BorrowckMode::Mir => false,
528 BorrowckMode::Migrate => true,
534 /// Load source code from a file.
536 /// Load source code from a string.
538 /// A string that is shown in place of a filename.
540 /// An anonymous string containing the source code.
546 pub fn filestem(&self) -> &str {
548 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
549 Input::Str { .. } => "rust_out",
553 pub fn source_name(&self) -> FileName {
555 Input::File(ref ifile) => ifile.clone().into(),
556 Input::Str { ref name, .. } => name.clone(),
561 #[derive(Clone, Hash, Debug)]
562 pub struct OutputFilenames {
563 pub out_directory: PathBuf,
565 pub single_output_file: Option<PathBuf>,
566 pub outputs: OutputTypes,
569 impl_stable_hash_via_hash!(OutputFilenames);
571 pub const RLINK_EXT: &str = "rlink";
572 pub const RUST_CGU_EXT: &str = "rcgu";
573 pub const DWARF_OBJECT_EXT: &str = "dwo";
575 impl OutputFilenames {
577 out_directory: PathBuf,
578 out_filestem: String,
579 single_output_file: Option<PathBuf>,
581 outputs: OutputTypes,
587 filestem: format!("{}{}", out_filestem, extra),
591 pub fn path(&self, flavor: OutputType) -> PathBuf {
594 .and_then(|p| p.to_owned())
595 .or_else(|| self.single_output_file.clone())
596 .unwrap_or_else(|| self.temp_path(flavor, None))
599 /// Gets the path where a compilation artifact of the given type for the
600 /// given codegen unit should be placed on disk. If codegen_unit_name is
601 /// None, a path distinct from those of any codegen unit will be generated.
602 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
603 let extension = flavor.extension();
604 self.temp_path_ext(extension, codegen_unit_name)
607 /// Like `temp_path`, but specifically for dwarf objects.
608 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
609 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
612 /// Like `temp_path`, but also supports things where there is no corresponding
613 /// OutputType, like noopt-bitcode or lto-bitcode.
614 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
615 let mut extension = String::new();
617 if let Some(codegen_unit_name) = codegen_unit_name {
618 extension.push_str(codegen_unit_name);
622 if !extension.is_empty() {
624 extension.push_str(RUST_CGU_EXT);
628 extension.push_str(ext);
631 self.with_extension(&extension)
634 pub fn with_extension(&self, extension: &str) -> PathBuf {
635 let mut path = self.out_directory.join(&self.filestem);
636 path.set_extension(extension);
640 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
641 /// mode is being used, which is the logic that this function is intended to encapsulate.
642 pub fn split_dwarf_path(
644 split_debuginfo_kind: SplitDebuginfo,
645 cgu_name: Option<&str>,
646 ) -> Option<PathBuf> {
647 let obj_out = self.temp_path(OutputType::Object, cgu_name);
648 let dwo_out = self.temp_path_dwo(cgu_name);
649 match split_debuginfo_kind {
650 SplitDebuginfo::Off => None,
651 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
652 // (pointing at the path which is being determined here). Use the path to the current
654 SplitDebuginfo::Packed => Some(obj_out),
655 // Split mode emits the DWARF into a different file, use that path.
656 SplitDebuginfo::Unpacked => Some(dwo_out),
661 pub fn host_triple() -> &'static str {
662 // Get the host triple out of the build environment. This ensures that our
663 // idea of the host triple is the same as for the set of libraries we've
664 // actually built. We can't just take LLVM's host triple because they
665 // normalize all ix86 architectures to i386.
667 // Instead of grabbing the host triple (for the current host), we grab (at
668 // compile time) the target triple that this rustc is built with and
669 // calling that (at runtime) the host triple.
670 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
673 impl Default for Options {
674 fn default() -> Options {
676 crate_types: Vec::new(),
677 optimize: OptLevel::No,
678 debuginfo: DebugInfo::None,
679 lint_opts: Vec::new(),
681 describe_lints: false,
682 output_types: OutputTypes(BTreeMap::new()),
683 search_paths: vec![],
685 target_triple: TargetTriple::from_triple(host_triple()),
688 debugging_opts: Default::default(),
690 borrowck_mode: BorrowckMode::Migrate,
691 cg: Default::default(),
692 error_format: ErrorOutputType::default(),
693 externs: Externs(BTreeMap::new()),
694 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
698 unstable_features: UnstableFeatures::Disallow,
699 debug_assertions: true,
700 actually_rustdoc: false,
701 trimmed_def_paths: TrimmedDefPaths::default(),
702 cli_forced_codegen_units: None,
703 cli_forced_thinlto_off: false,
704 remap_path_prefix: Vec::new(),
705 real_rust_source_base_dir: None,
706 edition: DEFAULT_EDITION,
707 json_artifact_notifications: false,
708 json_unused_externs: false,
715 /// Returns `true` if there is a reason to build the dep graph.
716 pub fn build_dep_graph(&self) -> bool {
717 self.incremental.is_some()
718 || self.debugging_opts.dump_dep_graph
719 || self.debugging_opts.query_dep_graph
722 pub fn file_path_mapping(&self) -> FilePathMapping {
723 FilePathMapping::new(self.remap_path_prefix.clone())
726 /// Returns `true` if there will be an output file generated.
727 pub fn will_create_output_file(&self) -> bool {
728 !self.debugging_opts.parse_only && // The file is just being parsed
729 !self.debugging_opts.ls // The file is just being queried
733 pub fn share_generics(&self) -> bool {
734 match self.debugging_opts.share_generics {
735 Some(setting) => setting,
736 None => match self.optimize {
737 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
738 OptLevel::Default | OptLevel::Aggressive => false,
744 impl DebuggingOptions {
745 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
748 treat_err_as_bug: self.treat_err_as_bug,
749 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
750 report_delayed_bugs: self.report_delayed_bugs,
751 macro_backtrace: self.macro_backtrace,
752 deduplicate_diagnostics: self.deduplicate_diagnostics,
756 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
757 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
761 // The type of entry function, so users can have their own entry functions
762 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
763 pub enum EntryFnType {
768 impl_stable_hash_via_hash!(EntryFnType);
770 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
780 impl_stable_hash_via_hash!(CrateType);
782 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
789 pub fn is_empty(&self) -> bool {
791 Passes::Some(ref v) => v.is_empty(),
792 Passes::All => false,
797 pub const fn default_lib_output() -> CrateType {
801 fn default_configuration(sess: &Session) -> CrateConfig {
802 let end = &sess.target.endian;
803 let arch = &sess.target.arch;
804 let wordsz = sess.target.pointer_width.to_string();
805 let os = &sess.target.os;
806 let env = &sess.target.env;
807 let abi = &sess.target.abi;
808 let vendor = &sess.target.vendor;
809 let min_atomic_width = sess.target.min_atomic_width();
810 let max_atomic_width = sess.target.max_atomic_width();
811 let atomic_cas = sess.target.atomic_cas;
812 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
816 let mut ret = FxHashSet::default();
817 ret.reserve(7); // the minimum number of insertions
819 ret.insert((sym::target_os, Some(Symbol::intern(os))));
820 for fam in &sess.target.families {
821 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
822 if fam == "windows" {
823 ret.insert((sym::windows, None));
824 } else if fam == "unix" {
825 ret.insert((sym::unix, None));
828 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
829 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
830 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
831 ret.insert((sym::target_env, Some(Symbol::intern(env))));
832 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
833 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
834 if sess.target.has_elf_tls {
835 ret.insert((sym::target_thread_local, None));
838 (8, layout.i8_align.abi),
839 (16, layout.i16_align.abi),
840 (32, layout.i32_align.abi),
841 (64, layout.i64_align.abi),
842 (128, layout.i128_align.abi),
844 if i >= min_atomic_width && i <= max_atomic_width {
845 let mut insert_atomic = |s, align: Align| {
846 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
848 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
850 if align.bits() == i {
851 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
854 let s = i.to_string();
855 insert_atomic(&s, align);
857 insert_atomic("ptr", layout.pointer_align.abi);
862 let panic_strategy = sess.panic_strategy();
863 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
865 for s in sess.opts.debugging_opts.sanitizer {
866 let symbol = Symbol::intern(&s.to_string());
867 ret.insert((sym::sanitize, Some(symbol)));
870 if sess.opts.debug_assertions {
871 ret.insert((sym::debug_assertions, None));
873 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
874 ret.insert((sym::proc_macro, None));
879 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
880 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
881 /// but the symbol interner is not yet set up then, so we must convert it later.
882 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
883 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
886 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
887 // Combine the configuration requested by the session (command line) with
888 // some default and generated configuration items.
889 let default_cfg = default_configuration(sess);
890 // If the user wants a test runner, then add the test cfg.
892 user_cfg.insert((sym::test, None));
894 user_cfg.extend(default_cfg.iter().cloned());
898 pub(super) fn build_target_config(
900 target_override: Option<Target>,
903 let target_result = target_override.map_or_else(
904 || Target::search(&opts.target_triple, sysroot),
905 |t| Ok((t, TargetWarnings::empty())),
907 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
911 "Error loading target specification: {}. \
912 Run `rustc --print target-list` for a list of built-in targets",
917 for warning in target_warnings.warning_messages() {
918 early_warn(opts.error_format, &warning)
921 if !matches!(target.pointer_width, 16 | 32 | 64) {
925 "target specification was invalid: \
926 unrecognized target-pointer-width {}",
935 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
936 pub enum OptionStability {
941 pub struct RustcOptGroup {
942 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
943 pub name: &'static str,
944 pub stability: OptionStability,
948 pub fn is_stable(&self) -> bool {
949 self.stability == OptionStability::Stable
952 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
954 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
956 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
959 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
961 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
963 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
967 // The `opt` local module holds wrappers around the `getopts` API that
968 // adds extra rustc-specific metadata to each option; such metadata
969 // is exposed by . The public
970 // functions below ending with `_u` are the functions that return
971 // *unstable* options, i.e., options that are only enabled when the
972 // user also passes the `-Z unstable-options` debugging flag.
974 // The `fn flag*` etc below are written so that we can use them
975 // in the future; do not warn about them not being used right now.
978 use super::RustcOptGroup;
980 pub type R = RustcOptGroup;
981 pub type S = &'static str;
983 fn stable<F>(name: S, f: F) -> R
985 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
987 RustcOptGroup::stable(name, f)
990 fn unstable<F>(name: S, f: F) -> R
992 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
994 RustcOptGroup::unstable(name, f)
997 fn longer(a: S, b: S) -> S {
998 if a.len() > b.len() { a } else { b }
1001 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1002 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1004 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1005 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1007 pub fn flag_s(a: S, b: S, c: S) -> R {
1008 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1010 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1011 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1014 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1015 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1017 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1018 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1022 /// Returns the "short" subset of the rustc command line options,
1023 /// including metadata for each option, such as whether the option is
1024 /// part of the stable long-term interface for rustc.
1025 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1027 opt::flag_s("h", "help", "Display this message"),
1028 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1032 "Add a directory to the library search path. The
1033 optional KIND can be one of dependency, crate, native,
1034 framework, or all (the default).",
1040 "Link the generated crate(s) to the specified native
1041 library NAME. The optional KIND can be one of
1042 static, framework, or dylib (the default).
1043 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1044 may be specified each with a prefix of either '+' to
1045 enable or '-' to disable.",
1046 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1048 make_crate_type_option(),
1049 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1053 "Specify which edition of the compiler to use when compiling code.",
1059 "Comma separated list of types of output for \
1060 the compiler to emit",
1061 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1066 "Compiler information to print on stdout",
1067 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1068 target-cpus|target-features|relocation-models|\
1069 code-models|tls-models|target-spec-json|native-static-libs]",
1071 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1072 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1073 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1077 "Write output to compiler-chosen filename \
1084 "Provide a detailed explanation of an error \
1088 opt::flag_s("", "test", "Build a test harness"),
1089 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1090 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1091 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1092 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1093 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1097 "Set the most restrictive lint level. \
1098 More restrictive lints are capped at this \
1105 "Specifiy lints that should warn even if \
1106 they are allowed somewhere else",
1109 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1110 opt::flag_s("V", "version", "Print version info and exit"),
1111 opt::flag_s("v", "verbose", "Use verbose output"),
1115 /// Returns all rustc command line options, including metadata for
1116 /// each option, such as whether the option is part of the stable
1117 /// long-term interface for rustc.
1118 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1119 let mut opts = rustc_short_optgroups();
1124 "Specify where an external rust library is located",
1130 "Location where an external crate dependency is specified",
1133 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1134 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1138 "How errors and other messages are produced",
1141 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1145 "Configure coloring of output:
1146 auto = colorize, if output goes to a tty (default);
1147 always = always colorize output;
1148 never = never colorize output",
1149 "auto|always|never",
1154 "Pretty-print the input instead of compiling;
1155 valid types are: `normal` (un-annotated source),
1156 `expanded` (crates expanded), or
1157 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1162 "remap-path-prefix",
1163 "Remap source names in all output (compiler messages and output files)",
1170 pub fn get_cmd_lint_options(
1171 matches: &getopts::Matches,
1172 error_format: ErrorOutputType,
1173 debugging_opts: &DebuggingOptions,
1174 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1175 let mut lint_opts_with_position = vec![];
1176 let mut describe_lints = false;
1178 if !debugging_opts.unstable_options && matches.opt_present("force-warn") {
1181 "the `-Z unstable-options` flag must also be passed to enable \
1182 the flag `--force-warn=lints`",
1186 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1187 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1188 if lint_name == "help" {
1189 describe_lints = true;
1191 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1196 lint_opts_with_position.sort_by_key(|x| x.0);
1197 let lint_opts = lint_opts_with_position
1200 .map(|(_, lint_name, level)| (lint_name, level))
1203 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1204 lint::Level::from_str(&cap)
1205 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1208 (lint_opts, describe_lints, lint_cap)
1211 /// Parses the `--color` flag.
1212 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1213 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1214 Some("auto") => ColorConfig::Auto,
1215 Some("always") => ColorConfig::Always,
1216 Some("never") => ColorConfig::Never,
1218 None => ColorConfig::Auto,
1220 Some(arg) => early_error(
1221 ErrorOutputType::default(),
1223 "argument for `--color` must be auto, \
1224 always or never (instead was `{}`)",
1231 /// Possible json config files
1232 pub struct JsonConfig {
1233 pub json_rendered: HumanReadableErrorType,
1234 pub json_artifact_notifications: bool,
1235 pub json_unused_externs: bool,
1238 /// Parse the `--json` flag.
1240 /// The first value returned is how to render JSON diagnostics, and the second
1241 /// is whether or not artifact notifications are enabled.
1242 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1243 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1244 HumanReadableErrorType::Default;
1245 let mut json_color = ColorConfig::Never;
1246 let mut json_artifact_notifications = false;
1247 let mut json_unused_externs = false;
1248 for option in matches.opt_strs("json") {
1249 // For now conservatively forbid `--color` with `--json` since `--json`
1250 // won't actually be emitting any colors and anything colorized is
1251 // embedded in a diagnostic message anyway.
1252 if matches.opt_str("color").is_some() {
1254 ErrorOutputType::default(),
1255 "cannot specify the `--color` option with `--json`",
1259 for sub_option in option.split(',') {
1261 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1262 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1263 "artifacts" => json_artifact_notifications = true,
1264 "unused-externs" => json_unused_externs = true,
1266 ErrorOutputType::default(),
1267 &format!("unknown `--json` option `{}`", s),
1274 json_rendered: json_rendered(json_color),
1275 json_artifact_notifications,
1276 json_unused_externs,
1280 /// Parses the `--error-format` flag.
1281 pub fn parse_error_format(
1282 matches: &getopts::Matches,
1284 json_rendered: HumanReadableErrorType,
1285 ) -> ErrorOutputType {
1286 // We need the `opts_present` check because the driver will send us Matches
1287 // with only stable options if no unstable options are used. Since error-format
1288 // is unstable, it will not be present. We have to use `opts_present` not
1289 // `opt_present` because the latter will panic.
1290 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1291 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1292 None | Some("human") => {
1293 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1295 Some("human-annotate-rs") => {
1296 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1298 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1299 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1300 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1302 Some(arg) => early_error(
1303 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1305 "argument for `--error-format` must be `human`, `json` or \
1306 `short` (instead was `{}`)",
1312 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1315 match error_format {
1316 ErrorOutputType::Json { .. } => {}
1318 // Conservatively require that the `--json` argument is coupled with
1319 // `--error-format=json`. This means that `--json` is specified we
1320 // should actually be emitting JSON blobs.
1321 _ if !matches.opt_strs("json").is_empty() => {
1323 ErrorOutputType::default(),
1324 "using `--json` requires also using `--error-format=json`",
1334 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1335 let edition = match matches.opt_str("edition") {
1336 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1338 ErrorOutputType::default(),
1340 "argument for `--edition` must be one of: \
1341 {}. (instead was `{}`)",
1342 EDITION_NAME_LIST, arg
1346 None => DEFAULT_EDITION,
1349 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1350 let is_nightly = nightly_options::match_is_nightly_build(matches);
1351 let msg = if !is_nightly {
1353 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1354 edition, LATEST_STABLE_EDITION
1357 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1359 early_error(ErrorOutputType::default(), &msg)
1365 fn check_debug_option_stability(
1366 debugging_opts: &DebuggingOptions,
1367 error_format: ErrorOutputType,
1368 json_rendered: HumanReadableErrorType,
1370 if !debugging_opts.unstable_options {
1371 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1373 ErrorOutputType::Json { pretty: false, json_rendered },
1374 "`--error-format=pretty-json` is unstable",
1377 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1381 ErrorOutputType::Json { pretty: false, json_rendered },
1382 "`--error-format=human-annotate-rs` is unstable",
1388 fn parse_output_types(
1389 debugging_opts: &DebuggingOptions,
1390 matches: &getopts::Matches,
1391 error_format: ErrorOutputType,
1393 let mut output_types = BTreeMap::new();
1394 if !debugging_opts.parse_only {
1395 for list in matches.opt_strs("emit") {
1396 for output_type in list.split(',') {
1397 let (shorthand, path) = match output_type.split_once('=') {
1398 None => (output_type, None),
1399 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1401 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1405 "unknown emission type: `{}` - expected one of: {}",
1407 OutputType::shorthands_display(),
1411 output_types.insert(output_type, path);
1415 if output_types.is_empty() {
1416 output_types.insert(OutputType::Exe, None);
1418 OutputTypes(output_types)
1421 fn should_override_cgus_and_disable_thinlto(
1422 output_types: &OutputTypes,
1423 matches: &getopts::Matches,
1424 error_format: ErrorOutputType,
1425 mut codegen_units: Option<usize>,
1426 ) -> (bool, Option<usize>) {
1427 let mut disable_thinlto = false;
1428 // Issue #30063: if user requests LLVM-related output to one
1429 // particular path, disable codegen-units.
1430 let incompatible: Vec<_> = output_types
1433 .map(|ot_path| ot_path.0)
1434 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1435 .map(|ot| ot.shorthand())
1437 if !incompatible.is_empty() {
1438 match codegen_units {
1439 Some(n) if n > 1 => {
1440 if matches.opt_present("o") {
1441 for ot in &incompatible {
1445 "`--emit={}` with `-o` incompatible with \
1446 `-C codegen-units=N` for N > 1",
1451 early_warn(error_format, "resetting to default -C codegen-units=1");
1452 codegen_units = Some(1);
1453 disable_thinlto = true;
1457 codegen_units = Some(1);
1458 disable_thinlto = true;
1463 if codegen_units == Some(0) {
1464 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1467 (disable_thinlto, codegen_units)
1470 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1471 if debugging_opts.threads == 0 {
1472 early_error(error_format, "value for threads must be a positive non-zero integer");
1475 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1476 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1480 fn collect_print_requests(
1481 cg: &mut CodegenOptions,
1482 dopts: &mut DebuggingOptions,
1483 matches: &getopts::Matches,
1484 error_format: ErrorOutputType,
1485 ) -> Vec<PrintRequest> {
1486 let mut prints = Vec::<PrintRequest>::new();
1487 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1488 prints.push(PrintRequest::TargetCPUs);
1489 cg.target_cpu = None;
1491 if cg.target_feature == "help" {
1492 prints.push(PrintRequest::TargetFeatures);
1493 cg.target_feature = String::new();
1496 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1497 "crate-name" => PrintRequest::CrateName,
1498 "file-names" => PrintRequest::FileNames,
1499 "sysroot" => PrintRequest::Sysroot,
1500 "target-libdir" => PrintRequest::TargetLibdir,
1501 "cfg" => PrintRequest::Cfg,
1502 "target-list" => PrintRequest::TargetList,
1503 "target-cpus" => PrintRequest::TargetCPUs,
1504 "target-features" => PrintRequest::TargetFeatures,
1505 "relocation-models" => PrintRequest::RelocationModels,
1506 "code-models" => PrintRequest::CodeModels,
1507 "tls-models" => PrintRequest::TlsModels,
1508 "native-static-libs" => PrintRequest::NativeStaticLibs,
1509 "target-spec-json" => {
1510 if dopts.unstable_options {
1511 PrintRequest::TargetSpec
1515 "the `-Z unstable-options` flag must also be passed to \
1516 enable the target-spec-json print option",
1520 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1526 pub fn parse_target_triple(
1527 matches: &getopts::Matches,
1528 error_format: ErrorOutputType,
1530 match matches.opt_str("target") {
1531 Some(target) if target.ends_with(".json") => {
1532 let path = Path::new(&target);
1533 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1534 early_error(error_format, &format!("target file {:?} does not exist", path))
1537 Some(target) => TargetTriple::TargetTriple(target),
1538 _ => TargetTriple::from_triple(host_triple()),
1543 matches: &getopts::Matches,
1544 cg: &CodegenOptions,
1545 error_format: ErrorOutputType,
1547 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1548 // to use them interchangeably. However, because they're technically different flags,
1549 // we need to work out manually which should take precedence if both are supplied (i.e.
1550 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1551 // comparing them. Note that if a flag is not found, its position will be `None`, which
1552 // always compared less than `Some(_)`.
1553 let max_o = matches.opt_positions("O").into_iter().max();
1557 .flat_map(|(i, s)| {
1558 // NB: This can match a string without `=`.
1559 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1565 match cg.opt_level.as_ref() {
1566 "0" => OptLevel::No,
1567 "1" => OptLevel::Less,
1568 "2" => OptLevel::Default,
1569 "3" => OptLevel::Aggressive,
1570 "s" => OptLevel::Size,
1571 "z" => OptLevel::SizeMin,
1576 "optimization level needs to be \
1577 between 0-3, s or z (instead was `{}`)",
1586 fn select_debuginfo(
1587 matches: &getopts::Matches,
1588 cg: &CodegenOptions,
1589 error_format: ErrorOutputType,
1591 let max_g = matches.opt_positions("g").into_iter().max();
1595 .flat_map(|(i, s)| {
1596 // NB: This can match a string without `=`.
1597 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1603 match cg.debuginfo {
1604 0 => DebugInfo::None,
1605 1 => DebugInfo::Limited,
1606 2 => DebugInfo::Full,
1611 "debug info level needs to be between \
1612 0-2 (instead was `{}`)",
1621 fn parse_native_lib_kind(kind: &str, error_format: ErrorOutputType) -> NativeLibKind {
1623 "dylib" => NativeLibKind::Dylib { as_needed: None },
1624 "framework" => NativeLibKind::Framework { as_needed: None },
1625 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1626 "static-nobundle" => {
1629 "library kind `static-nobundle` has been superseded by specifying \
1630 `-bundle` on library kind `static`. Try `static:-bundle`",
1632 NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1636 &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1641 fn parse_native_lib_modifiers(
1643 mut kind: NativeLibKind,
1645 error_format: ErrorOutputType,
1646 ) -> (NativeLibKind, Option<bool>) {
1647 let mut verbatim = None;
1648 for modifier in modifiers.split(',') {
1649 let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
1650 Some(m) => (m, modifier.starts_with('+')),
1651 None => early_error(
1653 "invalid linking modifier syntax, expected '+' or '-' prefix \
1654 before one of: bundle, verbatim, whole-archive, as-needed",
1661 "linking modifiers are currently unstable and only accepted on \
1662 the nightly compiler",
1666 match (modifier, &mut kind) {
1667 ("bundle", NativeLibKind::Static { bundle, .. }) => {
1668 *bundle = Some(value);
1670 ("bundle", _) => early_error(
1672 "bundle linking modifier is only compatible with \
1673 `static` linking kind",
1676 ("verbatim", _) => verbatim = Some(value),
1678 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1679 *whole_archive = Some(value);
1681 ("whole-archive", _) => early_error(
1683 "whole-archive linking modifier is only compatible with \
1684 `static` linking kind",
1687 ("as-needed", NativeLibKind::Dylib { as_needed })
1688 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1689 *as_needed = Some(value);
1691 ("as-needed", _) => early_error(
1693 "as-needed linking modifier is only compatible with \
1694 `dylib` and `framework` linking kinds",
1700 "unrecognized linking modifier `{}`, expected one \
1701 of: bundle, verbatim, whole-archive, as-needed",
1711 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1712 let is_nightly = nightly_options::match_is_nightly_build(matches);
1717 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1718 // where KIND is one of "dylib", "framework", "static" and
1719 // where MODIFIERS are a comma separated list of supported modifiers
1720 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1721 // with either + or - to indicate whether it is enabled or disabled.
1722 // The last value specified for a given modifier wins.
1723 let (name, kind, verbatim) = match s.split_once('=') {
1724 None => (s, NativeLibKind::Unspecified, None),
1725 Some((kind, name)) => {
1726 let (kind, verbatim) = match kind.split_once(':') {
1727 None => (parse_native_lib_kind(kind, error_format), None),
1728 Some((kind, modifiers)) => {
1729 let kind = parse_native_lib_kind(kind, error_format);
1730 parse_native_lib_modifiers(is_nightly, kind, modifiers, error_format)
1733 (name.to_string(), kind, verbatim)
1737 let (name, new_name) = match name.split_once(':') {
1738 None => (name, None),
1739 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1741 NativeLib { name, new_name, kind, verbatim }
1746 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1747 match dopts.borrowck.as_ref() {
1748 "migrate" => BorrowckMode::Migrate,
1749 "mir" => BorrowckMode::Mir,
1750 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1754 pub fn parse_externs(
1755 matches: &getopts::Matches,
1756 debugging_opts: &DebuggingOptions,
1757 error_format: ErrorOutputType,
1759 let is_unstable_enabled = debugging_opts.unstable_options;
1760 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1761 for arg in matches.opt_strs("extern") {
1762 let (name, path) = match arg.split_once('=') {
1763 None => (arg, None),
1764 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1766 let (options, name) = match name.split_once(':') {
1767 None => (None, name),
1768 Some((opts, name)) => (Some(opts), name.to_string()),
1771 let path = path.map(|p| CanonicalizedPath::new(p));
1773 let entry = externs.entry(name.to_owned());
1775 use std::collections::btree_map::Entry;
1777 let entry = if let Some(path) = path {
1778 // --extern prelude_name=some_file.rlib
1780 Entry::Vacant(vacant) => {
1781 let files = BTreeSet::from_iter(iter::once(path));
1782 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1784 Entry::Occupied(occupied) => {
1785 let ext_ent = occupied.into_mut();
1787 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1791 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1794 // Exact paths take precedence over search directories.
1795 let files = BTreeSet::from_iter(iter::once(path));
1796 *location = ExternLocation::ExactPaths(files);
1803 // --extern prelude_name
1805 Entry::Vacant(vacant) => {
1806 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1808 Entry::Occupied(occupied) => {
1809 // Ignore if already specified.
1815 let mut is_private_dep = false;
1816 let mut add_prelude = true;
1817 if let Some(opts) = options {
1818 if !is_unstable_enabled {
1821 "the `-Z unstable-options` flag must also be passed to \
1822 enable `--extern options",
1825 for opt in opts.split(',') {
1827 "priv" => is_private_dep = true,
1829 if let ExternLocation::ExactPaths(_) = &entry.location {
1830 add_prelude = false;
1834 "the `noprelude` --extern option requires a file path",
1838 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1843 // Crates start out being not private, and go to being private `priv`
1845 entry.is_private_dep |= is_private_dep;
1846 // If any flag is missing `noprelude`, then add to the prelude.
1847 entry.add_prelude |= add_prelude;
1852 fn parse_extern_dep_specs(
1853 matches: &getopts::Matches,
1854 debugging_opts: &DebuggingOptions,
1855 error_format: ErrorOutputType,
1856 ) -> ExternDepSpecs {
1857 let is_unstable_enabled = debugging_opts.unstable_options;
1858 let mut map = BTreeMap::new();
1860 for arg in matches.opt_strs("extern-location") {
1861 if !is_unstable_enabled {
1864 "`--extern-location` option is unstable: set `-Z unstable-options`",
1868 let mut parts = arg.splitn(2, '=');
1869 let name = parts.next().unwrap_or_else(|| {
1870 early_error(error_format, "`--extern-location` value must not be empty")
1872 let loc = parts.next().unwrap_or_else(|| {
1875 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1879 let locparts: Vec<_> = loc.split(":").collect();
1880 let spec = match &locparts[..] {
1882 // Don't want `:` split string
1883 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1884 early_error(error_format, "`--extern-location`: missing `raw` location")
1886 ExternDepSpec::Raw(raw.to_string())
1889 // Don't want `:` split string
1890 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1891 early_error(error_format, "`--extern-location`: missing `json` location")
1893 let json = json::from_str(raw).unwrap_or_else(|_| {
1896 &format!("`--extern-location`: malformed json location `{}`", raw),
1899 ExternDepSpec::Json(json)
1901 [bad, ..] => early_error(
1903 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1905 [] => early_error(error_format, "missing location specification"),
1908 map.insert(name.to_string(), spec);
1911 ExternDepSpecs::new(map)
1914 fn parse_remap_path_prefix(
1915 matches: &getopts::Matches,
1916 error_format: ErrorOutputType,
1917 ) -> Vec<(PathBuf, PathBuf)> {
1919 .opt_strs("remap-path-prefix")
1921 .map(|remap| match remap.rsplit_once('=') {
1922 None => early_error(
1924 "--remap-path-prefix must contain '=' between FROM and TO",
1926 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1931 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1932 let color = parse_color(matches);
1934 let edition = parse_crate_edition(matches);
1936 let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
1937 parse_json(matches);
1939 let error_format = parse_error_format(matches, color, json_rendered);
1941 let unparsed_crate_types = matches.opt_strs("crate-type");
1942 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1943 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1945 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
1946 let (lint_opts, describe_lints, lint_cap) =
1947 get_cmd_lint_options(matches, error_format, &debugging_opts);
1949 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1951 if !debugging_opts.unstable_options && json_unused_externs {
1954 "the `-Z unstable-options` flag must also be passed to enable \
1955 the flag `--json=unused-externs`",
1959 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1961 let mut cg = CodegenOptions::build(matches, error_format);
1962 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1969 check_thread_count(&debugging_opts, error_format);
1971 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1973 if debugging_opts.profile && incremental.is_some() {
1976 "can't instrument with gcov profiling when compiling incrementally",
1979 if debugging_opts.profile {
1980 match codegen_units {
1982 None => codegen_units = Some(1),
1983 Some(_) => early_error(
1985 "can't instrument with gcov profiling with multiple codegen units",
1990 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1993 "options `-C profile-generate` and `-C profile-use` are exclusive",
1997 if debugging_opts.instrument_coverage.is_some()
1998 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
2000 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2003 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2004 or `-C profile-generate`",
2008 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
2009 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2010 // multiple runs, including some changes to source code; so mangled names must be consistent
2011 // across compilations.
2012 match debugging_opts.symbol_mangling_version {
2014 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
2016 Some(SymbolManglingVersion::Legacy) => {
2019 "-Z instrument-coverage requires symbol mangling version `v0`, \
2020 but `-Z symbol-mangling-version=legacy` was specified",
2023 Some(SymbolManglingVersion::V0) => {}
2027 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2028 debugging_opts.graphviz_font = graphviz_font;
2031 if !cg.embed_bitcode {
2033 LtoCli::No | LtoCli::Unspecified => {}
2034 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2036 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2041 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2045 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2046 let target_triple = parse_target_triple(matches, error_format);
2047 let opt_level = parse_opt_level(matches, &cg, error_format);
2048 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2049 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2050 // for more details.
2051 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2052 let debuginfo = select_debuginfo(matches, &cg, error_format);
2054 let mut search_paths = vec![];
2055 for s in &matches.opt_strs("L") {
2056 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2059 let libs = parse_libs(matches, error_format);
2061 let test = matches.opt_present("test");
2063 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2065 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2066 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2069 let externs = parse_externs(matches, &debugging_opts, error_format);
2070 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2072 let crate_name = matches.opt_str("crate-name");
2074 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2076 let pretty = parse_pretty(matches, &debugging_opts, error_format);
2078 if !debugging_opts.unstable_options
2079 && !target_triple.triple().contains("apple")
2080 && cg.split_debuginfo.is_some()
2083 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2087 // Try to find a directory containing the Rust `src`, for more details see
2088 // the doc comment on the `real_rust_source_base_dir` field.
2090 let sysroot = match &sysroot_opt {
2093 tmp_buf = crate::filesearch::get_or_default_sysroot();
2097 let real_rust_source_base_dir = {
2098 // This is the location used by the `rust-src` `rustup` component.
2099 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2100 if let Ok(metadata) = candidate.symlink_metadata() {
2101 // Replace the symlink rustbuild creates, with its destination.
2102 // We could try to use `fs::canonicalize` instead, but that might
2103 // produce unnecessarily verbose path.
2104 if metadata.file_type().is_symlink() {
2105 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2106 candidate = symlink_dest;
2111 // Only use this directory if it has a file we can expect to always find.
2112 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2117 optimize: opt_level,
2124 maybe_sysroot: sysroot_opt,
2134 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2140 actually_rustdoc: false,
2141 trimmed_def_paths: TrimmedDefPaths::default(),
2142 cli_forced_codegen_units: codegen_units,
2143 cli_forced_thinlto_off: disable_thinlto,
2145 real_rust_source_base_dir,
2147 json_artifact_notifications,
2148 json_unused_externs,
2154 matches: &getopts::Matches,
2155 debugging_opts: &DebuggingOptions,
2156 efmt: ErrorOutputType,
2157 ) -> Option<PpMode> {
2158 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
2160 let first = match (name, extended) {
2161 ("normal", _) => Source(PpSourceMode::Normal),
2162 ("identified", _) => Source(PpSourceMode::Identified),
2163 ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
2164 ("expanded", _) => Source(PpSourceMode::Expanded),
2165 ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
2166 ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
2167 ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
2168 ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
2169 ("hir", true) => Hir(PpHirMode::Normal),
2170 ("hir,identified", true) => Hir(PpHirMode::Identified),
2171 ("hir,typed", true) => Hir(PpHirMode::Typed),
2172 ("hir-tree", true) => HirTree,
2173 ("thir-tree", true) => ThirTree,
2174 ("mir", true) => Mir,
2175 ("mir-cfg", true) => MirCFG,
2181 "argument to `unpretty` must be one of `normal`, \
2182 `expanded`, `identified`, `expanded,identified`, \
2183 `expanded,hygiene`, `everybody_loops`, \
2184 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2185 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2193 "argument to `pretty` must be one of `normal`, \
2194 `expanded`, `identified`, or `expanded,identified`; got {}",
2201 tracing::debug!("got unpretty option: {:?}", first);
2205 if debugging_opts.unstable_options {
2206 if let Some(a) = matches.opt_default("pretty", "normal") {
2207 // stable pretty-print variants only
2208 return Some(parse_pretty_inner(efmt, &a, false));
2212 debugging_opts.unpretty.as_ref().map(|a| {
2213 // extended with unstable pretty-print variants
2214 parse_pretty_inner(efmt, &a, true)
2218 pub fn make_crate_type_option() -> RustcOptGroup {
2222 "Comma separated list of types of crates
2223 for the compiler to emit",
2224 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2228 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2229 let mut crate_types: Vec<CrateType> = Vec::new();
2230 for unparsed_crate_type in &list_list {
2231 for part in unparsed_crate_type.split(',') {
2232 let new_part = match part {
2233 "lib" => default_lib_output(),
2234 "rlib" => CrateType::Rlib,
2235 "staticlib" => CrateType::Staticlib,
2236 "dylib" => CrateType::Dylib,
2237 "cdylib" => CrateType::Cdylib,
2238 "bin" => CrateType::Executable,
2239 "proc-macro" => CrateType::ProcMacro,
2240 _ => return Err(format!("unknown crate type: `{}`", part)),
2242 if !crate_types.contains(&new_part) {
2243 crate_types.push(new_part)
2251 pub mod nightly_options {
2252 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2253 use crate::early_error;
2254 use rustc_feature::UnstableFeatures;
2256 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2257 match_is_nightly_build(matches)
2258 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2261 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2262 is_nightly_build(matches.opt_str("crate-name").as_deref())
2265 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2266 UnstableFeatures::from_environment(krate).is_nightly_build()
2269 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2270 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2271 let really_allows_unstable_options = match_is_nightly_build(matches);
2273 for opt in flags.iter() {
2274 if opt.stability == OptionStability::Stable {
2277 if !matches.opt_present(opt.name) {
2280 if opt.name != "Z" && !has_z_unstable_option {
2282 ErrorOutputType::default(),
2284 "the `-Z unstable-options` flag must also be passed to enable \
2290 if really_allows_unstable_options {
2293 match opt.stability {
2294 OptionStability::Unstable => {
2296 "the option `{}` is only accepted on the \
2300 early_error(ErrorOutputType::default(), &msg);
2302 OptionStability::Stable => {}
2308 impl fmt::Display for CrateType {
2309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2311 CrateType::Executable => "bin".fmt(f),
2312 CrateType::Dylib => "dylib".fmt(f),
2313 CrateType::Rlib => "rlib".fmt(f),
2314 CrateType::Staticlib => "staticlib".fmt(f),
2315 CrateType::Cdylib => "cdylib".fmt(f),
2316 CrateType::ProcMacro => "proc-macro".fmt(f),
2321 #[derive(Copy, Clone, PartialEq, Debug)]
2322 pub enum PpSourceMode {
2323 /// `--pretty=normal`
2325 /// `-Zunpretty=everybody_loops`
2327 /// `--pretty=expanded`
2329 /// `--pretty=identified`
2331 /// `--pretty=expanded,identified`
2333 /// `--pretty=expanded,hygiene`
2337 #[derive(Copy, Clone, PartialEq, Debug)]
2338 pub enum PpAstTreeMode {
2339 /// `-Zunpretty=ast`
2341 /// `-Zunpretty=ast,expanded`
2345 #[derive(Copy, Clone, PartialEq, Debug)]
2346 pub enum PpHirMode {
2347 /// `-Zunpretty=hir`
2349 /// `-Zunpretty=hir,identified`
2351 /// `-Zunpretty=hir,typed`
2355 #[derive(Copy, Clone, PartialEq, Debug)]
2357 /// Options that print the source code, i.e.
2358 /// `--pretty` and `-Zunpretty=everybody_loops`
2359 Source(PpSourceMode),
2360 AstTree(PpAstTreeMode),
2361 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2363 /// `-Zunpretty=hir-tree`
2365 /// `-Zunpretty=thir-tree`
2367 /// `-Zunpretty=mir`
2369 /// `-Zunpretty=mir-cfg`
2374 pub fn needs_ast_map(&self) -> bool {
2376 use PpSourceMode::*;
2378 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2380 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2381 | AstTree(PpAstTreeMode::Expanded)
2390 pub fn needs_analysis(&self) -> bool {
2392 matches!(*self, Mir | MirCFG | ThirTree)
2396 /// Command-line arguments passed to the compiler have to be incorporated with
2397 /// the dependency tracking system for incremental compilation. This module
2398 /// provides some utilities to make this more convenient.
2400 /// The values of all command-line arguments that are relevant for dependency
2401 /// tracking are hashed into a single value that determines whether the
2402 /// incremental compilation cache can be re-used or not. This hashing is done
2403 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2404 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2405 /// the hash of which is order dependent, but we might not want the order of
2406 /// arguments to make a difference for the hash).
2408 /// However, since the value provided by `Hash::hash` often *is* suitable,
2409 /// especially for primitive types, there is the
2410 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2411 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2412 /// we have an opt-in scheme here, so one is hopefully forced to think about
2413 /// how the hash should be calculated when adding a new command-line argument.
2414 crate mod dep_tracking {
2417 CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2418 LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
2419 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2422 use crate::options::WasiExecModel;
2423 use crate::utils::{NativeLib, NativeLibKind};
2424 use rustc_feature::UnstableFeatures;
2425 use rustc_span::edition::Edition;
2426 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2427 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
2428 use std::collections::hash_map::DefaultHasher;
2429 use std::collections::BTreeMap;
2430 use std::hash::Hash;
2431 use std::num::NonZeroUsize;
2432 use std::path::PathBuf;
2434 pub trait DepTrackingHash {
2437 hasher: &mut DefaultHasher,
2438 error_format: ErrorOutputType,
2439 for_crate_hash: bool,
2443 macro_rules! impl_dep_tracking_hash_via_hash {
2444 ($($t:ty),+ $(,)?) => {$(
2445 impl DepTrackingHash for $t {
2446 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2447 Hash::hash(self, hasher);
2453 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2456 hasher: &mut DefaultHasher,
2457 error_format: ErrorOutputType,
2458 for_crate_hash: bool,
2462 Hash::hash(&1, hasher);
2463 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2465 None => Hash::hash(&0, hasher),
2470 impl_dep_tracking_hash_via_hash!(
2502 SymbolManglingVersion,
2503 SourceFileHashAlgorithm,
2509 impl<T1, T2> DepTrackingHash for (T1, T2)
2511 T1: DepTrackingHash,
2512 T2: DepTrackingHash,
2516 hasher: &mut DefaultHasher,
2517 error_format: ErrorOutputType,
2518 for_crate_hash: bool,
2520 Hash::hash(&0, hasher);
2521 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2522 Hash::hash(&1, hasher);
2523 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2527 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2529 T1: DepTrackingHash,
2530 T2: DepTrackingHash,
2531 T3: DepTrackingHash,
2535 hasher: &mut DefaultHasher,
2536 error_format: ErrorOutputType,
2537 for_crate_hash: bool,
2539 Hash::hash(&0, hasher);
2540 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2541 Hash::hash(&1, hasher);
2542 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2543 Hash::hash(&2, hasher);
2544 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2548 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2551 hasher: &mut DefaultHasher,
2552 error_format: ErrorOutputType,
2553 for_crate_hash: bool,
2555 Hash::hash(&self.len(), hasher);
2556 for (index, elem) in self.iter().enumerate() {
2557 Hash::hash(&index, hasher);
2558 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2563 impl DepTrackingHash for OutputTypes {
2566 hasher: &mut DefaultHasher,
2567 error_format: ErrorOutputType,
2568 for_crate_hash: bool,
2570 Hash::hash(&self.0.len(), hasher);
2571 for (key, val) in &self.0 {
2572 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2573 if !for_crate_hash {
2574 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2580 // This is a stable hash because BTreeMap is a sorted container
2581 crate fn stable_hash(
2582 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2583 hasher: &mut DefaultHasher,
2584 error_format: ErrorOutputType,
2585 for_crate_hash: bool,
2587 for (key, sub_hash) in sub_hashes {
2588 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2589 // the keys, as they are just plain strings
2590 Hash::hash(&key.len(), hasher);
2591 Hash::hash(key, hasher);
2592 sub_hash.hash(hasher, error_format, for_crate_hash);