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 #[derive(Clone, PartialEq, Hash, Debug)]
178 pub enum SwitchWithOptPath {
179 Enabled(Option<PathBuf>),
183 impl SwitchWithOptPath {
184 pub fn enabled(&self) -> bool {
186 SwitchWithOptPath::Enabled(_) => true,
187 SwitchWithOptPath::Disabled => false,
192 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
193 #[derive(Encodable, Decodable)]
194 pub enum SymbolManglingVersion {
199 impl_stable_hash_via_hash!(SymbolManglingVersion);
201 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
208 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
209 #[derive(Encodable, Decodable)]
210 pub enum OutputType {
221 impl_stable_hash_via_hash!(OutputType);
224 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
226 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
228 | OutputType::Assembly
229 | OutputType::LlvmAssembly
231 | OutputType::Object => false,
235 fn shorthand(&self) -> &'static str {
237 OutputType::Bitcode => "llvm-bc",
238 OutputType::Assembly => "asm",
239 OutputType::LlvmAssembly => "llvm-ir",
240 OutputType::Mir => "mir",
241 OutputType::Object => "obj",
242 OutputType::Metadata => "metadata",
243 OutputType::Exe => "link",
244 OutputType::DepInfo => "dep-info",
248 fn from_shorthand(shorthand: &str) -> Option<Self> {
249 Some(match shorthand {
250 "asm" => OutputType::Assembly,
251 "llvm-ir" => OutputType::LlvmAssembly,
252 "mir" => OutputType::Mir,
253 "llvm-bc" => OutputType::Bitcode,
254 "obj" => OutputType::Object,
255 "metadata" => OutputType::Metadata,
256 "link" => OutputType::Exe,
257 "dep-info" => OutputType::DepInfo,
262 fn shorthands_display() -> String {
264 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
265 OutputType::Bitcode.shorthand(),
266 OutputType::Assembly.shorthand(),
267 OutputType::LlvmAssembly.shorthand(),
268 OutputType::Mir.shorthand(),
269 OutputType::Object.shorthand(),
270 OutputType::Metadata.shorthand(),
271 OutputType::Exe.shorthand(),
272 OutputType::DepInfo.shorthand(),
276 pub fn extension(&self) -> &'static str {
278 OutputType::Bitcode => "bc",
279 OutputType::Assembly => "s",
280 OutputType::LlvmAssembly => "ll",
281 OutputType::Mir => "mir",
282 OutputType::Object => "o",
283 OutputType::Metadata => "rmeta",
284 OutputType::DepInfo => "d",
285 OutputType::Exe => "",
290 /// The type of diagnostics output to generate.
291 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
292 pub enum ErrorOutputType {
293 /// Output meant for the consumption of humans.
294 HumanReadable(HumanReadableErrorType),
295 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
297 /// Render the JSON in a human readable way (with indents and newlines).
299 /// The JSON output includes a `rendered` field that includes the rendered
301 json_rendered: HumanReadableErrorType,
305 impl Default for ErrorOutputType {
306 fn default() -> Self {
307 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
311 /// Parameter to control path trimming.
312 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
313 pub enum TrimmedDefPaths {
314 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
316 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
318 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
322 impl Default for TrimmedDefPaths {
323 fn default() -> Self {
328 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
329 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
330 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
331 /// should only depend on the output types, not the paths they're written to.
332 #[derive(Clone, Debug, Hash)]
333 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
336 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
337 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
340 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
344 pub fn contains_key(&self, key: &OutputType) -> bool {
345 self.0.contains_key(key)
348 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
352 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
356 pub fn len(&self) -> usize {
360 // Returns `true` if any of the output types require codegen or linking.
361 pub fn should_codegen(&self) -> bool {
362 self.0.keys().any(|k| match *k {
364 | OutputType::Assembly
365 | OutputType::LlvmAssembly
368 | OutputType::Exe => true,
369 OutputType::Metadata | OutputType::DepInfo => false,
373 // Returns `true` if any of the output types require linking.
374 pub fn should_link(&self) -> bool {
375 self.0.keys().any(|k| match *k {
377 | OutputType::Assembly
378 | OutputType::LlvmAssembly
380 | OutputType::Metadata
382 | OutputType::DepInfo => false,
383 OutputType::Exe => true,
388 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
389 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
390 /// would break dependency tracking for command-line arguments.
392 pub struct Externs(BTreeMap<String, ExternEntry>);
395 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
397 #[derive(Clone, Debug)]
398 pub struct ExternEntry {
399 pub location: ExternLocation,
400 /// Indicates this is a "private" dependency for the
401 /// `exported_private_dependencies` lint.
403 /// This can be set with the `priv` option like
404 /// `--extern priv:name=foo.rlib`.
405 pub is_private_dep: bool,
406 /// Add the extern entry to the extern prelude.
408 /// This can be disabled with the `noprelude` option like
409 /// `--extern noprelude:name`.
410 pub add_prelude: bool,
413 #[derive(Clone, Debug)]
414 pub enum ExternLocation {
415 /// Indicates to look for the library in the search paths.
417 /// Added via `--extern name`.
418 FoundInLibrarySearchDirectories,
419 /// The locations where this extern entry must be found.
421 /// The `CrateLoader` is responsible for loading these and figuring out
422 /// which one to use.
424 /// Added via `--extern prelude_name=some_file.rlib`
425 ExactPaths(BTreeSet<CanonicalizedPath>),
428 /// Supplied source location of a dependency - for example in a build specification
429 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
430 /// a file and line, then the build system can specify that. On the other hand, it may
431 /// make more sense to have an arbitrary raw string.
432 #[derive(Clone, PartialEq)]
433 pub enum ExternDepSpec {
436 /// Raw data in json format
440 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
441 fn from(from: &'a ExternDepSpec) -> Self {
443 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
444 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
450 /// Used for testing.
451 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
455 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
459 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
463 pub fn len(&self) -> usize {
469 fn new(location: ExternLocation) -> ExternEntry {
470 ExternEntry { location, is_private_dep: false, add_prelude: false }
473 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
474 match &self.location {
475 ExternLocation::ExactPaths(set) => Some(set.iter()),
481 impl ExternDepSpecs {
482 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
486 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
491 impl fmt::Display for ExternDepSpec {
492 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
494 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
495 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
500 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
501 pub enum PrintRequest {
517 #[derive(Copy, Clone)]
518 pub enum BorrowckMode {
524 /// Returns whether we should run the MIR-based borrow check, but also fall back
525 /// on the AST borrow check if the MIR-based one errors.
526 pub fn migrate(self) -> bool {
528 BorrowckMode::Mir => false,
529 BorrowckMode::Migrate => true,
535 /// Load source code from a file.
537 /// Load source code from a string.
539 /// A string that is shown in place of a filename.
541 /// An anonymous string containing the source code.
547 pub fn filestem(&self) -> &str {
549 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
550 Input::Str { .. } => "rust_out",
554 pub fn source_name(&self) -> FileName {
556 Input::File(ref ifile) => ifile.clone().into(),
557 Input::Str { ref name, .. } => name.clone(),
562 #[derive(Clone, Hash, Debug)]
563 pub struct OutputFilenames {
564 pub out_directory: PathBuf,
566 pub single_output_file: Option<PathBuf>,
567 pub outputs: OutputTypes,
570 impl_stable_hash_via_hash!(OutputFilenames);
572 pub const RLINK_EXT: &str = "rlink";
573 pub const RUST_CGU_EXT: &str = "rcgu";
574 pub const DWARF_OBJECT_EXT: &str = "dwo";
576 impl OutputFilenames {
578 out_directory: PathBuf,
579 out_filestem: String,
580 single_output_file: Option<PathBuf>,
582 outputs: OutputTypes,
588 filestem: format!("{}{}", out_filestem, extra),
592 pub fn path(&self, flavor: OutputType) -> PathBuf {
595 .and_then(|p| p.to_owned())
596 .or_else(|| self.single_output_file.clone())
597 .unwrap_or_else(|| self.temp_path(flavor, None))
600 /// Gets the path where a compilation artifact of the given type for the
601 /// given codegen unit should be placed on disk. If codegen_unit_name is
602 /// None, a path distinct from those of any codegen unit will be generated.
603 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
604 let extension = flavor.extension();
605 self.temp_path_ext(extension, codegen_unit_name)
608 /// Like `temp_path`, but specifically for dwarf objects.
609 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
610 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
613 /// Like `temp_path`, but also supports things where there is no corresponding
614 /// OutputType, like noopt-bitcode or lto-bitcode.
615 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
616 let mut extension = String::new();
618 if let Some(codegen_unit_name) = codegen_unit_name {
619 extension.push_str(codegen_unit_name);
623 if !extension.is_empty() {
625 extension.push_str(RUST_CGU_EXT);
629 extension.push_str(ext);
632 self.with_extension(&extension)
635 pub fn with_extension(&self, extension: &str) -> PathBuf {
636 let mut path = self.out_directory.join(&self.filestem);
637 path.set_extension(extension);
641 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
642 /// mode is being used, which is the logic that this function is intended to encapsulate.
643 pub fn split_dwarf_path(
645 split_debuginfo_kind: SplitDebuginfo,
646 cgu_name: Option<&str>,
647 ) -> Option<PathBuf> {
648 let obj_out = self.temp_path(OutputType::Object, cgu_name);
649 let dwo_out = self.temp_path_dwo(cgu_name);
650 match split_debuginfo_kind {
651 SplitDebuginfo::Off => None,
652 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
653 // (pointing at the path which is being determined here). Use the path to the current
655 SplitDebuginfo::Packed => Some(obj_out),
656 // Split mode emits the DWARF into a different file, use that path.
657 SplitDebuginfo::Unpacked => Some(dwo_out),
662 pub fn host_triple() -> &'static str {
663 // Get the host triple out of the build environment. This ensures that our
664 // idea of the host triple is the same as for the set of libraries we've
665 // actually built. We can't just take LLVM's host triple because they
666 // normalize all ix86 architectures to i386.
668 // Instead of grabbing the host triple (for the current host), we grab (at
669 // compile time) the target triple that this rustc is built with and
670 // calling that (at runtime) the host triple.
671 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
674 impl Default for Options {
675 fn default() -> Options {
677 crate_types: Vec::new(),
678 optimize: OptLevel::No,
679 debuginfo: DebugInfo::None,
680 lint_opts: Vec::new(),
682 describe_lints: false,
683 output_types: OutputTypes(BTreeMap::new()),
684 search_paths: vec![],
686 target_triple: TargetTriple::from_triple(host_triple()),
689 debugging_opts: Default::default(),
691 borrowck_mode: BorrowckMode::Migrate,
692 cg: Default::default(),
693 error_format: ErrorOutputType::default(),
694 externs: Externs(BTreeMap::new()),
695 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
699 unstable_features: UnstableFeatures::Disallow,
700 debug_assertions: true,
701 actually_rustdoc: false,
702 trimmed_def_paths: TrimmedDefPaths::default(),
703 cli_forced_codegen_units: None,
704 cli_forced_thinlto_off: false,
705 remap_path_prefix: Vec::new(),
706 real_rust_source_base_dir: None,
707 edition: DEFAULT_EDITION,
708 json_artifact_notifications: false,
709 json_unused_externs: false,
711 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
717 /// Returns `true` if there is a reason to build the dep graph.
718 pub fn build_dep_graph(&self) -> bool {
719 self.incremental.is_some()
720 || self.debugging_opts.dump_dep_graph
721 || self.debugging_opts.query_dep_graph
724 pub fn file_path_mapping(&self) -> FilePathMapping {
725 FilePathMapping::new(self.remap_path_prefix.clone())
728 /// Returns `true` if there will be an output file generated.
729 pub fn will_create_output_file(&self) -> bool {
730 !self.debugging_opts.parse_only && // The file is just being parsed
731 !self.debugging_opts.ls // The file is just being queried
735 pub fn share_generics(&self) -> bool {
736 match self.debugging_opts.share_generics {
737 Some(setting) => setting,
738 None => match self.optimize {
739 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
740 OptLevel::Default | OptLevel::Aggressive => false,
746 impl DebuggingOptions {
747 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
750 treat_err_as_bug: self.treat_err_as_bug,
751 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
752 report_delayed_bugs: self.report_delayed_bugs,
753 macro_backtrace: self.macro_backtrace,
754 deduplicate_diagnostics: self.deduplicate_diagnostics,
758 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
759 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
763 // The type of entry function, so users can have their own entry functions
764 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
765 pub enum EntryFnType {
770 impl_stable_hash_via_hash!(EntryFnType);
772 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
782 impl_stable_hash_via_hash!(CrateType);
784 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
791 pub fn is_empty(&self) -> bool {
793 Passes::Some(ref v) => v.is_empty(),
794 Passes::All => false,
799 pub const fn default_lib_output() -> CrateType {
803 fn default_configuration(sess: &Session) -> CrateConfig {
804 let end = &sess.target.endian;
805 let arch = &sess.target.arch;
806 let wordsz = sess.target.pointer_width.to_string();
807 let os = &sess.target.os;
808 let env = &sess.target.env;
809 let abi = &sess.target.abi;
810 let vendor = &sess.target.vendor;
811 let min_atomic_width = sess.target.min_atomic_width();
812 let max_atomic_width = sess.target.max_atomic_width();
813 let atomic_cas = sess.target.atomic_cas;
814 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
818 let mut ret = FxHashSet::default();
819 ret.reserve(7); // the minimum number of insertions
821 ret.insert((sym::target_os, Some(Symbol::intern(os))));
822 for fam in &sess.target.families {
823 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
824 if fam == "windows" {
825 ret.insert((sym::windows, None));
826 } else if fam == "unix" {
827 ret.insert((sym::unix, None));
830 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
831 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
832 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
833 ret.insert((sym::target_env, Some(Symbol::intern(env))));
834 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
835 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
836 if sess.target.has_elf_tls {
837 ret.insert((sym::target_thread_local, None));
840 (8, layout.i8_align.abi),
841 (16, layout.i16_align.abi),
842 (32, layout.i32_align.abi),
843 (64, layout.i64_align.abi),
844 (128, layout.i128_align.abi),
846 if i >= min_atomic_width && i <= max_atomic_width {
847 let mut insert_atomic = |s, align: Align| {
848 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
850 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
852 if align.bits() == i {
853 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
856 let s = i.to_string();
857 insert_atomic(&s, align);
859 insert_atomic("ptr", layout.pointer_align.abi);
864 let panic_strategy = sess.panic_strategy();
865 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
867 for s in sess.opts.debugging_opts.sanitizer {
868 let symbol = Symbol::intern(&s.to_string());
869 ret.insert((sym::sanitize, Some(symbol)));
872 if sess.opts.debug_assertions {
873 ret.insert((sym::debug_assertions, None));
875 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
876 ret.insert((sym::proc_macro, None));
881 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
882 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
883 /// but the symbol interner is not yet set up then, so we must convert it later.
884 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
885 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
888 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
889 // Combine the configuration requested by the session (command line) with
890 // some default and generated configuration items.
891 let default_cfg = default_configuration(sess);
892 // If the user wants a test runner, then add the test cfg.
894 user_cfg.insert((sym::test, None));
896 user_cfg.extend(default_cfg.iter().cloned());
900 pub(super) fn build_target_config(
902 target_override: Option<Target>,
905 let target_result = target_override.map_or_else(
906 || Target::search(&opts.target_triple, sysroot),
907 |t| Ok((t, TargetWarnings::empty())),
909 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
913 "Error loading target specification: {}. \
914 Run `rustc --print target-list` for a list of built-in targets",
919 for warning in target_warnings.warning_messages() {
920 early_warn(opts.error_format, &warning)
923 if !matches!(target.pointer_width, 16 | 32 | 64) {
927 "target specification was invalid: \
928 unrecognized target-pointer-width {}",
937 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
938 pub enum OptionStability {
943 pub struct RustcOptGroup {
944 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
945 pub name: &'static str,
946 pub stability: OptionStability,
950 pub fn is_stable(&self) -> bool {
951 self.stability == OptionStability::Stable
954 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
956 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
958 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
961 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
963 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
965 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
969 // The `opt` local module holds wrappers around the `getopts` API that
970 // adds extra rustc-specific metadata to each option; such metadata
971 // is exposed by . The public
972 // functions below ending with `_u` are the functions that return
973 // *unstable* options, i.e., options that are only enabled when the
974 // user also passes the `-Z unstable-options` debugging flag.
976 // The `fn flag*` etc below are written so that we can use them
977 // in the future; do not warn about them not being used right now.
980 use super::RustcOptGroup;
982 pub type R = RustcOptGroup;
983 pub type S = &'static str;
985 fn stable<F>(name: S, f: F) -> R
987 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
989 RustcOptGroup::stable(name, f)
992 fn unstable<F>(name: S, f: F) -> R
994 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
996 RustcOptGroup::unstable(name, f)
999 fn longer(a: S, b: S) -> S {
1000 if a.len() > b.len() { a } else { b }
1003 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1004 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1006 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1007 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1009 pub fn flag_s(a: S, b: S, c: S) -> R {
1010 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1012 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1013 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1016 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1017 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1019 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1020 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1024 /// Returns the "short" subset of the rustc command line options,
1025 /// including metadata for each option, such as whether the option is
1026 /// part of the stable long-term interface for rustc.
1027 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1029 opt::flag_s("h", "help", "Display this message"),
1030 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1034 "Add a directory to the library search path. The
1035 optional KIND can be one of dependency, crate, native,
1036 framework, or all (the default).",
1042 "Link the generated crate(s) to the specified native
1043 library NAME. The optional KIND can be one of
1044 static, framework, or dylib (the default).
1045 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1046 may be specified each with a prefix of either '+' to
1047 enable or '-' to disable.",
1048 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1050 make_crate_type_option(),
1051 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1055 "Specify which edition of the compiler to use when compiling code.",
1061 "Comma separated list of types of output for \
1062 the compiler to emit",
1063 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1068 "Compiler information to print on stdout",
1069 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1070 target-cpus|target-features|relocation-models|\
1071 code-models|tls-models|target-spec-json|native-static-libs]",
1073 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1074 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1075 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1079 "Write output to compiler-chosen filename \
1086 "Provide a detailed explanation of an error \
1090 opt::flag_s("", "test", "Build a test harness"),
1091 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1092 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1093 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1094 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1095 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1096 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1100 "Set the most restrictive lint level. \
1101 More restrictive lints are capped at this \
1105 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1106 opt::flag_s("V", "version", "Print version info and exit"),
1107 opt::flag_s("v", "verbose", "Use verbose output"),
1111 /// Returns all rustc command line options, including metadata for
1112 /// each option, such as whether the option is part of the stable
1113 /// long-term interface for rustc.
1114 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1115 let mut opts = rustc_short_optgroups();
1120 "Specify where an external rust library is located",
1126 "Location where an external crate dependency is specified",
1129 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1130 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1134 "How errors and other messages are produced",
1137 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1141 "Configure coloring of output:
1142 auto = colorize, if output goes to a tty (default);
1143 always = always colorize output;
1144 never = never colorize output",
1145 "auto|always|never",
1149 "remap-path-prefix",
1150 "Remap source names in all output (compiler messages and output files)",
1157 pub fn get_cmd_lint_options(
1158 matches: &getopts::Matches,
1159 error_format: ErrorOutputType,
1160 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1161 let mut lint_opts_with_position = vec![];
1162 let mut describe_lints = false;
1164 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1165 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1166 if lint_name == "help" {
1167 describe_lints = true;
1169 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1174 lint_opts_with_position.sort_by_key(|x| x.0);
1175 let lint_opts = lint_opts_with_position
1178 .map(|(_, lint_name, level)| (lint_name, level))
1181 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1182 lint::Level::from_str(&cap)
1183 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1186 (lint_opts, describe_lints, lint_cap)
1189 /// Parses the `--color` flag.
1190 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1191 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1192 Some("auto") => ColorConfig::Auto,
1193 Some("always") => ColorConfig::Always,
1194 Some("never") => ColorConfig::Never,
1196 None => ColorConfig::Auto,
1198 Some(arg) => early_error(
1199 ErrorOutputType::default(),
1201 "argument for `--color` must be auto, \
1202 always or never (instead was `{}`)",
1209 /// Possible json config files
1210 pub struct JsonConfig {
1211 pub json_rendered: HumanReadableErrorType,
1212 pub json_artifact_notifications: bool,
1213 pub json_unused_externs: bool,
1216 /// Parse the `--json` flag.
1218 /// The first value returned is how to render JSON diagnostics, and the second
1219 /// is whether or not artifact notifications are enabled.
1220 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1221 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1222 HumanReadableErrorType::Default;
1223 let mut json_color = ColorConfig::Never;
1224 let mut json_artifact_notifications = false;
1225 let mut json_unused_externs = false;
1226 for option in matches.opt_strs("json") {
1227 // For now conservatively forbid `--color` with `--json` since `--json`
1228 // won't actually be emitting any colors and anything colorized is
1229 // embedded in a diagnostic message anyway.
1230 if matches.opt_str("color").is_some() {
1232 ErrorOutputType::default(),
1233 "cannot specify the `--color` option with `--json`",
1237 for sub_option in option.split(',') {
1239 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1240 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1241 "artifacts" => json_artifact_notifications = true,
1242 "unused-externs" => json_unused_externs = true,
1244 ErrorOutputType::default(),
1245 &format!("unknown `--json` option `{}`", s),
1252 json_rendered: json_rendered(json_color),
1253 json_artifact_notifications,
1254 json_unused_externs,
1258 /// Parses the `--error-format` flag.
1259 pub fn parse_error_format(
1260 matches: &getopts::Matches,
1262 json_rendered: HumanReadableErrorType,
1263 ) -> ErrorOutputType {
1264 // We need the `opts_present` check because the driver will send us Matches
1265 // with only stable options if no unstable options are used. Since error-format
1266 // is unstable, it will not be present. We have to use `opts_present` not
1267 // `opt_present` because the latter will panic.
1268 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1269 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1270 None | Some("human") => {
1271 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1273 Some("human-annotate-rs") => {
1274 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1276 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1277 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1278 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1280 Some(arg) => early_error(
1281 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1283 "argument for `--error-format` must be `human`, `json` or \
1284 `short` (instead was `{}`)",
1290 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1293 match error_format {
1294 ErrorOutputType::Json { .. } => {}
1296 // Conservatively require that the `--json` argument is coupled with
1297 // `--error-format=json`. This means that `--json` is specified we
1298 // should actually be emitting JSON blobs.
1299 _ if !matches.opt_strs("json").is_empty() => {
1301 ErrorOutputType::default(),
1302 "using `--json` requires also using `--error-format=json`",
1312 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1313 let edition = match matches.opt_str("edition") {
1314 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1316 ErrorOutputType::default(),
1318 "argument for `--edition` must be one of: \
1319 {}. (instead was `{}`)",
1320 EDITION_NAME_LIST, arg
1324 None => DEFAULT_EDITION,
1327 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1328 let is_nightly = nightly_options::match_is_nightly_build(matches);
1329 let msg = if !is_nightly {
1331 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1332 edition, LATEST_STABLE_EDITION
1335 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1337 early_error(ErrorOutputType::default(), &msg)
1343 fn check_debug_option_stability(
1344 debugging_opts: &DebuggingOptions,
1345 error_format: ErrorOutputType,
1346 json_rendered: HumanReadableErrorType,
1348 if !debugging_opts.unstable_options {
1349 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1351 ErrorOutputType::Json { pretty: false, json_rendered },
1352 "`--error-format=pretty-json` is unstable",
1355 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1359 ErrorOutputType::Json { pretty: false, json_rendered },
1360 "`--error-format=human-annotate-rs` is unstable",
1366 fn parse_output_types(
1367 debugging_opts: &DebuggingOptions,
1368 matches: &getopts::Matches,
1369 error_format: ErrorOutputType,
1371 let mut output_types = BTreeMap::new();
1372 if !debugging_opts.parse_only {
1373 for list in matches.opt_strs("emit") {
1374 for output_type in list.split(',') {
1375 let (shorthand, path) = match output_type.split_once('=') {
1376 None => (output_type, None),
1377 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1379 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1383 "unknown emission type: `{}` - expected one of: {}",
1385 OutputType::shorthands_display(),
1389 output_types.insert(output_type, path);
1393 if output_types.is_empty() {
1394 output_types.insert(OutputType::Exe, None);
1396 OutputTypes(output_types)
1399 fn should_override_cgus_and_disable_thinlto(
1400 output_types: &OutputTypes,
1401 matches: &getopts::Matches,
1402 error_format: ErrorOutputType,
1403 mut codegen_units: Option<usize>,
1404 ) -> (bool, Option<usize>) {
1405 let mut disable_thinlto = false;
1406 // Issue #30063: if user requests LLVM-related output to one
1407 // particular path, disable codegen-units.
1408 let incompatible: Vec<_> = output_types
1411 .map(|ot_path| ot_path.0)
1412 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1413 .map(|ot| ot.shorthand())
1415 if !incompatible.is_empty() {
1416 match codegen_units {
1417 Some(n) if n > 1 => {
1418 if matches.opt_present("o") {
1419 for ot in &incompatible {
1423 "`--emit={}` with `-o` incompatible with \
1424 `-C codegen-units=N` for N > 1",
1429 early_warn(error_format, "resetting to default -C codegen-units=1");
1430 codegen_units = Some(1);
1431 disable_thinlto = true;
1435 codegen_units = Some(1);
1436 disable_thinlto = true;
1441 if codegen_units == Some(0) {
1442 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1445 (disable_thinlto, codegen_units)
1448 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1449 if debugging_opts.threads == 0 {
1450 early_error(error_format, "value for threads must be a positive non-zero integer");
1453 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1454 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1458 fn collect_print_requests(
1459 cg: &mut CodegenOptions,
1460 dopts: &mut DebuggingOptions,
1461 matches: &getopts::Matches,
1462 error_format: ErrorOutputType,
1463 ) -> Vec<PrintRequest> {
1464 let mut prints = Vec::<PrintRequest>::new();
1465 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1466 prints.push(PrintRequest::TargetCPUs);
1467 cg.target_cpu = None;
1469 if cg.target_feature == "help" {
1470 prints.push(PrintRequest::TargetFeatures);
1471 cg.target_feature = String::new();
1474 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1475 "crate-name" => PrintRequest::CrateName,
1476 "file-names" => PrintRequest::FileNames,
1477 "sysroot" => PrintRequest::Sysroot,
1478 "target-libdir" => PrintRequest::TargetLibdir,
1479 "cfg" => PrintRequest::Cfg,
1480 "target-list" => PrintRequest::TargetList,
1481 "target-cpus" => PrintRequest::TargetCPUs,
1482 "target-features" => PrintRequest::TargetFeatures,
1483 "relocation-models" => PrintRequest::RelocationModels,
1484 "code-models" => PrintRequest::CodeModels,
1485 "tls-models" => PrintRequest::TlsModels,
1486 "native-static-libs" => PrintRequest::NativeStaticLibs,
1487 "target-spec-json" => {
1488 if dopts.unstable_options {
1489 PrintRequest::TargetSpec
1493 "the `-Z unstable-options` flag must also be passed to \
1494 enable the target-spec-json print option",
1498 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1504 pub fn parse_target_triple(
1505 matches: &getopts::Matches,
1506 error_format: ErrorOutputType,
1508 match matches.opt_str("target") {
1509 Some(target) if target.ends_with(".json") => {
1510 let path = Path::new(&target);
1511 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1512 early_error(error_format, &format!("target file {:?} does not exist", path))
1515 Some(target) => TargetTriple::TargetTriple(target),
1516 _ => TargetTriple::from_triple(host_triple()),
1521 matches: &getopts::Matches,
1522 cg: &CodegenOptions,
1523 error_format: ErrorOutputType,
1525 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1526 // to use them interchangeably. However, because they're technically different flags,
1527 // we need to work out manually which should take precedence if both are supplied (i.e.
1528 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1529 // comparing them. Note that if a flag is not found, its position will be `None`, which
1530 // always compared less than `Some(_)`.
1531 let max_o = matches.opt_positions("O").into_iter().max();
1535 .flat_map(|(i, s)| {
1536 // NB: This can match a string without `=`.
1537 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1543 match cg.opt_level.as_ref() {
1544 "0" => OptLevel::No,
1545 "1" => OptLevel::Less,
1546 "2" => OptLevel::Default,
1547 "3" => OptLevel::Aggressive,
1548 "s" => OptLevel::Size,
1549 "z" => OptLevel::SizeMin,
1554 "optimization level needs to be \
1555 between 0-3, s or z (instead was `{}`)",
1564 fn select_debuginfo(
1565 matches: &getopts::Matches,
1566 cg: &CodegenOptions,
1567 error_format: ErrorOutputType,
1569 let max_g = matches.opt_positions("g").into_iter().max();
1573 .flat_map(|(i, s)| {
1574 // NB: This can match a string without `=`.
1575 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1581 match cg.debuginfo {
1582 0 => DebugInfo::None,
1583 1 => DebugInfo::Limited,
1584 2 => DebugInfo::Full,
1589 "debug info level needs to be between \
1590 0-2 (instead was `{}`)",
1599 fn parse_native_lib_kind(
1600 matches: &getopts::Matches,
1602 error_format: ErrorOutputType,
1603 ) -> (NativeLibKind, Option<bool>) {
1604 let is_nightly = nightly_options::match_is_nightly_build(matches);
1605 let enable_unstable = nightly_options::is_unstable_enabled(matches);
1607 let (kind, modifiers) = match kind.split_once(':') {
1608 None => (kind, None),
1609 Some((kind, modifiers)) => (kind, Some(modifiers)),
1612 let kind = match kind {
1613 "dylib" => NativeLibKind::Dylib { as_needed: None },
1614 "framework" => NativeLibKind::Framework { as_needed: None },
1615 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1616 "static-nobundle" => {
1619 "library kind `static-nobundle` has been superseded by specifying \
1620 `-bundle` on library kind `static`. Try `static:-bundle`",
1622 if modifiers.is_some() {
1625 "linking modifier can't be used with library kind `static-nobundle`",
1631 "library kind `static-nobundle` are currently unstable and only accepted on \
1632 the nightly compiler",
1635 NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1639 &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1643 None => (kind, None),
1644 Some(modifiers) => {
1648 "linking modifiers are currently unstable and only accepted on \
1649 the nightly compiler",
1652 if !enable_unstable {
1655 "linking modifiers are currently unstable, \
1656 the `-Z unstable-options` flag must also be passed to use it",
1659 parse_native_lib_modifiers(kind, modifiers, error_format)
1664 fn parse_native_lib_modifiers(
1665 mut kind: NativeLibKind,
1667 error_format: ErrorOutputType,
1668 ) -> (NativeLibKind, Option<bool>) {
1669 let mut verbatim = None;
1670 for modifier in modifiers.split(',') {
1671 let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
1672 Some(m) => (m, modifier.starts_with('+')),
1673 None => early_error(
1675 "invalid linking modifier syntax, expected '+' or '-' prefix \
1676 before one of: bundle, verbatim, whole-archive, as-needed",
1680 match (modifier, &mut kind) {
1681 ("bundle", NativeLibKind::Static { bundle, .. }) => {
1682 *bundle = Some(value);
1684 ("bundle", _) => early_error(
1686 "bundle linking modifier is only compatible with \
1687 `static` linking kind",
1690 ("verbatim", _) => verbatim = Some(value),
1692 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1693 *whole_archive = Some(value);
1695 ("whole-archive", _) => early_error(
1697 "whole-archive linking modifier is only compatible with \
1698 `static` linking kind",
1701 ("as-needed", NativeLibKind::Dylib { as_needed })
1702 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1703 *as_needed = Some(value);
1705 ("as-needed", _) => early_error(
1707 "as-needed linking modifier is only compatible with \
1708 `dylib` and `framework` linking kinds",
1714 "unrecognized linking modifier `{}`, expected one \
1715 of: bundle, verbatim, whole-archive, as-needed",
1725 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1730 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1731 // where KIND is one of "dylib", "framework", "static" and
1732 // where MODIFIERS are a comma separated list of supported modifiers
1733 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1734 // with either + or - to indicate whether it is enabled or disabled.
1735 // The last value specified for a given modifier wins.
1736 let (name, kind, verbatim) = match s.split_once('=') {
1737 None => (s, NativeLibKind::Unspecified, None),
1738 Some((kind, name)) => {
1739 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
1740 (name.to_string(), kind, verbatim)
1744 let (name, new_name) = match name.split_once(':') {
1745 None => (name, None),
1746 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1748 NativeLib { name, new_name, kind, verbatim }
1753 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1754 match dopts.borrowck.as_ref() {
1755 "migrate" => BorrowckMode::Migrate,
1756 "mir" => BorrowckMode::Mir,
1757 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1761 pub fn parse_externs(
1762 matches: &getopts::Matches,
1763 debugging_opts: &DebuggingOptions,
1764 error_format: ErrorOutputType,
1766 let is_unstable_enabled = debugging_opts.unstable_options;
1767 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1768 for arg in matches.opt_strs("extern") {
1769 let (name, path) = match arg.split_once('=') {
1770 None => (arg, None),
1771 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1773 let (options, name) = match name.split_once(':') {
1774 None => (None, name),
1775 Some((opts, name)) => (Some(opts), name.to_string()),
1778 let path = path.map(|p| CanonicalizedPath::new(p));
1780 let entry = externs.entry(name.to_owned());
1782 use std::collections::btree_map::Entry;
1784 let entry = if let Some(path) = path {
1785 // --extern prelude_name=some_file.rlib
1787 Entry::Vacant(vacant) => {
1788 let files = BTreeSet::from_iter(iter::once(path));
1789 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1791 Entry::Occupied(occupied) => {
1792 let ext_ent = occupied.into_mut();
1794 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1798 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1801 // Exact paths take precedence over search directories.
1802 let files = BTreeSet::from_iter(iter::once(path));
1803 *location = ExternLocation::ExactPaths(files);
1810 // --extern prelude_name
1812 Entry::Vacant(vacant) => {
1813 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1815 Entry::Occupied(occupied) => {
1816 // Ignore if already specified.
1822 let mut is_private_dep = false;
1823 let mut add_prelude = true;
1824 if let Some(opts) = options {
1825 if !is_unstable_enabled {
1828 "the `-Z unstable-options` flag must also be passed to \
1829 enable `--extern options",
1832 for opt in opts.split(',') {
1834 "priv" => is_private_dep = true,
1836 if let ExternLocation::ExactPaths(_) = &entry.location {
1837 add_prelude = false;
1841 "the `noprelude` --extern option requires a file path",
1845 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1850 // Crates start out being not private, and go to being private `priv`
1852 entry.is_private_dep |= is_private_dep;
1853 // If any flag is missing `noprelude`, then add to the prelude.
1854 entry.add_prelude |= add_prelude;
1859 fn parse_extern_dep_specs(
1860 matches: &getopts::Matches,
1861 debugging_opts: &DebuggingOptions,
1862 error_format: ErrorOutputType,
1863 ) -> ExternDepSpecs {
1864 let is_unstable_enabled = debugging_opts.unstable_options;
1865 let mut map = BTreeMap::new();
1867 for arg in matches.opt_strs("extern-location") {
1868 if !is_unstable_enabled {
1871 "`--extern-location` option is unstable: set `-Z unstable-options`",
1875 let mut parts = arg.splitn(2, '=');
1876 let name = parts.next().unwrap_or_else(|| {
1877 early_error(error_format, "`--extern-location` value must not be empty")
1879 let loc = parts.next().unwrap_or_else(|| {
1882 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1886 let locparts: Vec<_> = loc.split(':').collect();
1887 let spec = match &locparts[..] {
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 `raw` location")
1893 ExternDepSpec::Raw(raw.to_string())
1896 // Don't want `:` split string
1897 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1898 early_error(error_format, "`--extern-location`: missing `json` location")
1900 let json = json::from_str(raw).unwrap_or_else(|_| {
1903 &format!("`--extern-location`: malformed json location `{}`", raw),
1906 ExternDepSpec::Json(json)
1908 [bad, ..] => early_error(
1910 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1912 [] => early_error(error_format, "missing location specification"),
1915 map.insert(name.to_string(), spec);
1918 ExternDepSpecs::new(map)
1921 fn parse_remap_path_prefix(
1922 matches: &getopts::Matches,
1923 debugging_opts: &DebuggingOptions,
1924 error_format: ErrorOutputType,
1925 ) -> Vec<(PathBuf, PathBuf)> {
1926 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
1927 .opt_strs("remap-path-prefix")
1929 .map(|remap| match remap.rsplit_once('=') {
1930 None => early_error(
1932 "--remap-path-prefix must contain '=' between FROM and TO",
1934 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1937 match &debugging_opts.remap_cwd_prefix {
1938 Some(to) => match std::env::current_dir() {
1939 Ok(cwd) => mapping.push((cwd, to.clone())),
1947 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1948 let color = parse_color(matches);
1950 let edition = parse_crate_edition(matches);
1952 let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
1953 parse_json(matches);
1955 let error_format = parse_error_format(matches, color, json_rendered);
1957 let unparsed_crate_types = matches.opt_strs("crate-type");
1958 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1959 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1961 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
1962 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1964 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1966 if !debugging_opts.unstable_options && json_unused_externs {
1969 "the `-Z unstable-options` flag must also be passed to enable \
1970 the flag `--json=unused-externs`",
1974 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1976 let mut cg = CodegenOptions::build(matches, error_format);
1977 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1984 check_thread_count(&debugging_opts, error_format);
1986 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1988 if debugging_opts.profile && incremental.is_some() {
1991 "can't instrument with gcov profiling when compiling incrementally",
1994 if debugging_opts.profile {
1995 match codegen_units {
1997 None => codegen_units = Some(1),
1998 Some(_) => early_error(
2000 "can't instrument with gcov profiling with multiple codegen units",
2005 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2008 "options `-C profile-generate` and `-C profile-use` are exclusive",
2012 if debugging_opts.instrument_coverage.is_some()
2013 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
2015 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2018 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2019 or `-C profile-generate`",
2023 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
2024 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2025 // multiple runs, including some changes to source code; so mangled names must be consistent
2026 // across compilations.
2027 match debugging_opts.symbol_mangling_version {
2029 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
2031 Some(SymbolManglingVersion::Legacy) => {
2034 "-Z instrument-coverage requires symbol mangling version `v0`, \
2035 but `-Z symbol-mangling-version=legacy` was specified",
2038 Some(SymbolManglingVersion::V0) => {}
2042 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2043 debugging_opts.graphviz_font = graphviz_font;
2046 if !cg.embed_bitcode {
2048 LtoCli::No | LtoCli::Unspecified => {}
2049 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2051 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2056 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2060 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2061 let target_triple = parse_target_triple(matches, error_format);
2062 let opt_level = parse_opt_level(matches, &cg, error_format);
2063 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2064 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2065 // for more details.
2066 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2067 let debuginfo = select_debuginfo(matches, &cg, error_format);
2069 let mut search_paths = vec![];
2070 for s in &matches.opt_strs("L") {
2071 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2074 let libs = parse_libs(matches, error_format);
2076 let test = matches.opt_present("test");
2078 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2080 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2081 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2084 let externs = parse_externs(matches, &debugging_opts, error_format);
2085 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2087 let crate_name = matches.opt_str("crate-name");
2089 let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2091 let pretty = parse_pretty(&debugging_opts, error_format);
2093 if !debugging_opts.unstable_options
2094 && !target_triple.triple().contains("apple")
2095 && cg.split_debuginfo.is_some()
2098 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2102 // Try to find a directory containing the Rust `src`, for more details see
2103 // the doc comment on the `real_rust_source_base_dir` field.
2105 let sysroot = match &sysroot_opt {
2108 tmp_buf = crate::filesearch::get_or_default_sysroot();
2112 let real_rust_source_base_dir = {
2113 // This is the location used by the `rust-src` `rustup` component.
2114 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2115 if let Ok(metadata) = candidate.symlink_metadata() {
2116 // Replace the symlink rustbuild creates, with its destination.
2117 // We could try to use `fs::canonicalize` instead, but that might
2118 // produce unnecessarily verbose path.
2119 if metadata.file_type().is_symlink() {
2120 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2121 candidate = symlink_dest;
2126 // Only use this directory if it has a file we can expect to always find.
2127 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2130 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2131 early_error(error_format, &format!("Current directory is invalid: {}", e));
2134 let (path, remapped) =
2135 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2136 let working_dir = if remapped {
2137 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2139 RealFileName::LocalPath(path)
2144 optimize: opt_level,
2151 maybe_sysroot: sysroot_opt,
2161 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2167 actually_rustdoc: false,
2168 trimmed_def_paths: TrimmedDefPaths::default(),
2169 cli_forced_codegen_units: codegen_units,
2170 cli_forced_thinlto_off: disable_thinlto,
2172 real_rust_source_base_dir,
2174 json_artifact_notifications,
2175 json_unused_externs,
2181 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2184 let first = match debugging_opts.unpretty.as_deref()? {
2185 "normal" => Source(PpSourceMode::Normal),
2186 "identified" => Source(PpSourceMode::Identified),
2187 "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
2188 "expanded" => Source(PpSourceMode::Expanded),
2189 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2190 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2191 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2192 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2193 "hir" => Hir(PpHirMode::Normal),
2194 "hir,identified" => Hir(PpHirMode::Identified),
2195 "hir,typed" => Hir(PpHirMode::Typed),
2196 "hir-tree" => HirTree,
2197 "thir-tree" => ThirTree,
2199 "mir-cfg" => MirCFG,
2200 name => early_error(
2203 "argument to `unpretty` must be one of `normal`, \
2204 `expanded`, `identified`, `expanded,identified`, \
2205 `expanded,hygiene`, `everybody_loops`, \
2206 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2207 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2212 tracing::debug!("got unpretty option: {:?}", first);
2216 pub fn make_crate_type_option() -> RustcOptGroup {
2220 "Comma separated list of types of crates
2221 for the compiler to emit",
2222 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2226 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2227 let mut crate_types: Vec<CrateType> = Vec::new();
2228 for unparsed_crate_type in &list_list {
2229 for part in unparsed_crate_type.split(',') {
2230 let new_part = match part {
2231 "lib" => default_lib_output(),
2232 "rlib" => CrateType::Rlib,
2233 "staticlib" => CrateType::Staticlib,
2234 "dylib" => CrateType::Dylib,
2235 "cdylib" => CrateType::Cdylib,
2236 "bin" => CrateType::Executable,
2237 "proc-macro" => CrateType::ProcMacro,
2238 _ => return Err(format!("unknown crate type: `{}`", part)),
2240 if !crate_types.contains(&new_part) {
2241 crate_types.push(new_part)
2249 pub mod nightly_options {
2250 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2251 use crate::early_error;
2252 use rustc_feature::UnstableFeatures;
2254 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2255 match_is_nightly_build(matches)
2256 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2259 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2260 is_nightly_build(matches.opt_str("crate-name").as_deref())
2263 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2264 UnstableFeatures::from_environment(krate).is_nightly_build()
2267 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2268 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2269 let really_allows_unstable_options = match_is_nightly_build(matches);
2271 for opt in flags.iter() {
2272 if opt.stability == OptionStability::Stable {
2275 if !matches.opt_present(opt.name) {
2278 if opt.name != "Z" && !has_z_unstable_option {
2280 ErrorOutputType::default(),
2282 "the `-Z unstable-options` flag must also be passed to enable \
2288 if really_allows_unstable_options {
2291 match opt.stability {
2292 OptionStability::Unstable => {
2294 "the option `{}` is only accepted on the \
2298 early_error(ErrorOutputType::default(), &msg);
2300 OptionStability::Stable => {}
2306 impl fmt::Display for CrateType {
2307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2309 CrateType::Executable => "bin".fmt(f),
2310 CrateType::Dylib => "dylib".fmt(f),
2311 CrateType::Rlib => "rlib".fmt(f),
2312 CrateType::Staticlib => "staticlib".fmt(f),
2313 CrateType::Cdylib => "cdylib".fmt(f),
2314 CrateType::ProcMacro => "proc-macro".fmt(f),
2319 #[derive(Copy, Clone, PartialEq, Debug)]
2320 pub enum PpSourceMode {
2321 /// `-Zunpretty=normal`
2323 /// `-Zunpretty=everybody_loops`
2325 /// `-Zunpretty=expanded`
2327 /// `-Zunpretty=identified`
2329 /// `-Zunpretty=expanded,identified`
2331 /// `-Zunpretty=expanded,hygiene`
2335 #[derive(Copy, Clone, PartialEq, Debug)]
2336 pub enum PpAstTreeMode {
2337 /// `-Zunpretty=ast`
2339 /// `-Zunpretty=ast,expanded`
2343 #[derive(Copy, Clone, PartialEq, Debug)]
2344 pub enum PpHirMode {
2345 /// `-Zunpretty=hir`
2347 /// `-Zunpretty=hir,identified`
2349 /// `-Zunpretty=hir,typed`
2353 #[derive(Copy, Clone, PartialEq, Debug)]
2355 /// Options that print the source code, i.e.
2356 /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
2357 Source(PpSourceMode),
2358 AstTree(PpAstTreeMode),
2359 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2361 /// `-Zunpretty=hir-tree`
2363 /// `-Zunpretty=thir-tree`
2365 /// `-Zunpretty=mir`
2367 /// `-Zunpretty=mir-cfg`
2372 pub fn needs_ast_map(&self) -> bool {
2374 use PpSourceMode::*;
2376 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2378 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2379 | AstTree(PpAstTreeMode::Expanded)
2388 pub fn needs_analysis(&self) -> bool {
2390 matches!(*self, Mir | MirCFG | ThirTree)
2394 /// Command-line arguments passed to the compiler have to be incorporated with
2395 /// the dependency tracking system for incremental compilation. This module
2396 /// provides some utilities to make this more convenient.
2398 /// The values of all command-line arguments that are relevant for dependency
2399 /// tracking are hashed into a single value that determines whether the
2400 /// incremental compilation cache can be re-used or not. This hashing is done
2401 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2402 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2403 /// the hash of which is order dependent, but we might not want the order of
2404 /// arguments to make a difference for the hash).
2406 /// However, since the value provided by `Hash::hash` often *is* suitable,
2407 /// especially for primitive types, there is the
2408 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2409 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2410 /// we have an opt-in scheme here, so one is hopefully forced to think about
2411 /// how the hash should be calculated when adding a new command-line argument.
2412 crate mod dep_tracking {
2415 CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2416 LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
2417 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2420 use crate::options::WasiExecModel;
2421 use crate::utils::{NativeLib, NativeLibKind};
2422 use rustc_feature::UnstableFeatures;
2423 use rustc_span::edition::Edition;
2424 use rustc_span::RealFileName;
2425 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2426 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
2427 use std::collections::hash_map::DefaultHasher;
2428 use std::collections::BTreeMap;
2429 use std::hash::Hash;
2430 use std::num::NonZeroUsize;
2431 use std::path::PathBuf;
2433 pub trait DepTrackingHash {
2436 hasher: &mut DefaultHasher,
2437 error_format: ErrorOutputType,
2438 for_crate_hash: bool,
2442 macro_rules! impl_dep_tracking_hash_via_hash {
2443 ($($t:ty),+ $(,)?) => {$(
2444 impl DepTrackingHash for $t {
2445 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2446 Hash::hash(self, hasher);
2452 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2455 hasher: &mut DefaultHasher,
2456 error_format: ErrorOutputType,
2457 for_crate_hash: bool,
2461 Hash::hash(&1, hasher);
2462 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2464 None => Hash::hash(&0, hasher),
2469 impl_dep_tracking_hash_via_hash!(
2501 SymbolManglingVersion,
2502 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);