1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 // ignore-tidy-filelength
7 use crate::middle::cstore;
8 use crate::session::{early_error, early_warn, Session};
9 use crate::session::search_paths::SearchPath;
10 use crate::hir::map as hir_map;
12 use rustc_data_structures::fx::FxHashSet;
14 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
15 use rustc_target::spec::{Target, TargetTriple};
18 use syntax::ast::{self, IntTy, UintTy};
19 use syntax::source_map::{FileName, FilePathMapping};
20 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
21 use syntax::symbol::{sym, Symbol};
22 use syntax::feature_gate::UnstableFeatures;
24 use errors::emitter::HumanReadableErrorType;
25 use errors::{ColorConfig, FatalError, Handler};
29 use std::collections::{BTreeMap, BTreeSet};
30 use std::collections::btree_map::{
31 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
34 use std::str::{self, FromStr};
35 use std::hash::Hasher;
36 use std::collections::hash_map::DefaultHasher;
37 use std::iter::FromIterator;
38 use std::path::{Path, PathBuf};
46 #[derive(Clone, Hash, Debug)]
54 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
64 impl_stable_hash_via_hash!(OptLevel);
66 /// This is what the `LtoCli` values get mapped to after resolving defaults and
67 /// and taking other command line options into account.
68 #[derive(Clone, PartialEq)]
70 /// Don't do any LTO whatsoever
73 /// Do a full crate graph LTO with ThinLTO
76 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
80 /// Do a full crate graph LTO with "fat" LTO
84 /// The different settings that the `-C lto` flag can have.
85 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
97 /// No `-C lto` flag passed
101 #[derive(Clone, PartialEq, Hash)]
102 pub enum LinkerPluginLto {
103 LinkerPlugin(PathBuf),
108 impl LinkerPluginLto {
109 pub fn enabled(&self) -> bool {
111 LinkerPluginLto::LinkerPlugin(_) |
112 LinkerPluginLto::LinkerPluginAuto => true,
113 LinkerPluginLto::Disabled => false,
118 #[derive(Clone, PartialEq, Hash)]
119 pub enum SwitchWithOptPath {
120 Enabled(Option<PathBuf>),
124 impl SwitchWithOptPath {
125 pub fn enabled(&self) -> bool {
127 SwitchWithOptPath::Enabled(_) => true,
128 SwitchWithOptPath::Disabled => false,
133 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
134 pub enum SymbolManglingVersion {
139 impl_stable_hash_via_hash!(SymbolManglingVersion);
141 #[derive(Clone, Copy, PartialEq, Hash)]
148 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
149 pub enum OutputType {
160 impl_stable_hash_via_hash!(OutputType);
163 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
165 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
167 | OutputType::Assembly
168 | OutputType::LlvmAssembly
170 | OutputType::Object => false,
174 fn shorthand(&self) -> &'static str {
176 OutputType::Bitcode => "llvm-bc",
177 OutputType::Assembly => "asm",
178 OutputType::LlvmAssembly => "llvm-ir",
179 OutputType::Mir => "mir",
180 OutputType::Object => "obj",
181 OutputType::Metadata => "metadata",
182 OutputType::Exe => "link",
183 OutputType::DepInfo => "dep-info",
187 fn from_shorthand(shorthand: &str) -> Option<Self> {
188 Some(match shorthand {
189 "asm" => OutputType::Assembly,
190 "llvm-ir" => OutputType::LlvmAssembly,
191 "mir" => OutputType::Mir,
192 "llvm-bc" => OutputType::Bitcode,
193 "obj" => OutputType::Object,
194 "metadata" => OutputType::Metadata,
195 "link" => OutputType::Exe,
196 "dep-info" => OutputType::DepInfo,
201 fn shorthands_display() -> String {
203 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
204 OutputType::Bitcode.shorthand(),
205 OutputType::Assembly.shorthand(),
206 OutputType::LlvmAssembly.shorthand(),
207 OutputType::Mir.shorthand(),
208 OutputType::Object.shorthand(),
209 OutputType::Metadata.shorthand(),
210 OutputType::Exe.shorthand(),
211 OutputType::DepInfo.shorthand(),
215 pub fn extension(&self) -> &'static str {
217 OutputType::Bitcode => "bc",
218 OutputType::Assembly => "s",
219 OutputType::LlvmAssembly => "ll",
220 OutputType::Mir => "mir",
221 OutputType::Object => "o",
222 OutputType::Metadata => "rmeta",
223 OutputType::DepInfo => "d",
224 OutputType::Exe => "",
229 /// The type of diagnostics output to generate.
230 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
231 pub enum ErrorOutputType {
232 /// Output meant for the consumption of humans.
233 HumanReadable(HumanReadableErrorType),
234 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
236 /// Render the JSON in a human readable way (with indents and newlines).
238 /// The JSON output includes a `rendered` field that includes the rendered
240 json_rendered: HumanReadableErrorType,
244 impl Default for ErrorOutputType {
245 fn default() -> Self {
246 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
250 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
251 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
252 /// dependency tracking for command-line arguments.
253 #[derive(Clone, Hash)]
254 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
256 impl_stable_hash_via_hash!(OutputTypes);
259 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
260 OutputTypes(BTreeMap::from_iter(
261 entries.iter().map(|&(k, ref v)| (k, v.clone())),
265 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
269 pub fn contains_key(&self, key: &OutputType) -> bool {
270 self.0.contains_key(key)
273 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
277 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
281 pub fn len(&self) -> usize {
285 // Returns `true` if any of the output types require codegen or linking.
286 pub fn should_codegen(&self) -> bool {
287 self.0.keys().any(|k| match *k {
289 | OutputType::Assembly
290 | OutputType::LlvmAssembly
293 | OutputType::Exe => true,
294 OutputType::Metadata | OutputType::DepInfo => false,
299 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
300 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
301 /// would break dependency tracking for command-line arguments.
303 pub struct Externs(BTreeMap<String, ExternEntry>);
305 #[derive(Clone, Debug, Default)]
306 pub struct ExternEntry {
307 pub locations: BTreeSet<Option<String>>,
308 pub is_private_dep: bool
312 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
316 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
320 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
326 macro_rules! hash_option {
327 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
328 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
329 if $sub_hashes.insert(stringify!($opt_name),
330 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
331 bug!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
336 macro_rules! top_level_options {
337 (pub struct Options { $(
338 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
346 pub fn dep_tracking_hash(&self) -> u64 {
347 let mut sub_hashes = BTreeMap::new();
352 [$dep_tracking_marker $($warn_val,
354 self.error_format)*]);
356 let mut hasher = DefaultHasher::new();
357 dep_tracking::stable_hash(sub_hashes,
366 // The top-level command-line options struct.
368 // For each option, one has to specify how it behaves with regard to the
369 // dependency tracking system of incremental compilation. This is done via the
370 // square-bracketed directive after the field type. The options are:
373 // A change in the given field will cause the compiler to completely clear the
374 // incremental compilation cache before proceeding.
377 // Incremental compilation is not influenced by this option.
379 // If you add a new option to this struct or one of the sub-structs like
380 // `CodegenOptions`, think about how it influences incremental compilation. If in
381 // doubt, specify [TRACKED], which is always "correct" but might lead to
382 // unnecessary re-compilation.
385 // The crate config requested for the session, which may be combined
386 // with additional crate configurations during the compile process.
387 crate_types: Vec<CrateType> [TRACKED],
388 optimize: OptLevel [TRACKED],
389 // Include the `debug_assertions` flag in dependency tracking, since it
390 // can influence whether overflow checks are done or not.
391 debug_assertions: bool [TRACKED],
392 debuginfo: DebugInfo [TRACKED],
393 lint_opts: Vec<(String, lint::Level)> [TRACKED],
394 lint_cap: Option<lint::Level> [TRACKED],
395 describe_lints: bool [UNTRACKED],
396 output_types: OutputTypes [TRACKED],
397 search_paths: Vec<SearchPath> [UNTRACKED],
398 libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
399 maybe_sysroot: Option<PathBuf> [UNTRACKED],
401 target_triple: TargetTriple [TRACKED],
403 test: bool [TRACKED],
404 error_format: ErrorOutputType [UNTRACKED],
406 // If `Some`, enable incremental compilation, using the given
407 // directory to store intermediate results.
408 incremental: Option<PathBuf> [UNTRACKED],
410 debugging_opts: DebuggingOptions [TRACKED],
411 prints: Vec<PrintRequest> [UNTRACKED],
412 // Determines which borrow checker(s) to run. This is the parsed, sanitized
413 // version of `debugging_opts.borrowck`, which is just a plain string.
414 borrowck_mode: BorrowckMode [UNTRACKED],
415 cg: CodegenOptions [TRACKED],
416 externs: Externs [UNTRACKED],
417 crate_name: Option<String> [TRACKED],
418 // An optional name to use as the crate for std during std injection,
419 // written `extern crate name as std`. Defaults to `std`. Used by
420 // out-of-tree drivers.
421 alt_std_name: Option<String> [TRACKED],
422 // Indicates how the compiler should treat unstable features.
423 unstable_features: UnstableFeatures [TRACKED],
425 // Indicates whether this run of the compiler is actually rustdoc. This
426 // is currently just a hack and will be removed eventually, so please
427 // try to not rely on this too much.
428 actually_rustdoc: bool [TRACKED],
430 // Specifications of codegen units / ThinLTO which are forced as a
431 // result of parsing command line options. These are not necessarily
432 // what rustc was invoked with, but massaged a bit to agree with
433 // commands like `--emit llvm-ir` which they're often incompatible with
434 // if we otherwise use the defaults of rustc.
435 cli_forced_codegen_units: Option<usize> [UNTRACKED],
436 cli_forced_thinlto_off: bool [UNTRACKED],
438 // Remap source path prefixes in all output (messages, object files, debug, etc.).
439 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
441 edition: Edition [TRACKED],
443 // `true` if we're emitting JSON blobs about each artifact produced
445 json_artifact_notifications: bool [TRACKED],
447 pretty: Option<(PpMode, Option<UserIdentifiedItem>)> [UNTRACKED],
451 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
452 pub enum PrintRequest {
467 #[derive(Copy, Clone)]
468 pub enum BorrowckMode {
474 /// Returns whether we should run the MIR-based borrow check, but also fall back
475 /// on the AST borrow check if the MIR-based one errors.
476 pub fn migrate(self) -> bool {
478 BorrowckMode::Mir => false,
479 BorrowckMode::Migrate => true,
485 /// Load source code from a file.
487 /// Load source code from a string.
489 /// A string that is shown in place of a filename.
491 /// An anonymous string containing the source code.
497 pub fn filestem(&self) -> &str {
499 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
500 Input::Str { .. } => "rust_out",
504 pub fn get_input(&mut self) -> Option<&mut String> {
506 Input::File(_) => None,
507 Input::Str { ref mut input, .. } => Some(input),
511 pub fn source_name(&self) -> FileName {
513 Input::File(ref ifile) => ifile.clone().into(),
514 Input::Str { ref name, .. } => name.clone(),
519 #[derive(Clone, Hash)]
520 pub struct OutputFilenames {
521 pub out_directory: PathBuf,
522 pub out_filestem: String,
523 pub single_output_file: Option<PathBuf>,
525 pub outputs: OutputTypes,
528 impl_stable_hash_via_hash!(OutputFilenames);
530 pub const RUST_CGU_EXT: &str = "rcgu";
532 impl OutputFilenames {
533 pub fn path(&self, flavor: OutputType) -> PathBuf {
536 .and_then(|p| p.to_owned())
537 .or_else(|| self.single_output_file.clone())
538 .unwrap_or_else(|| self.temp_path(flavor, None))
541 /// Gets the path where a compilation artifact of the given type for the
542 /// given codegen unit should be placed on disk. If codegen_unit_name is
543 /// None, a path distinct from those of any codegen unit will be generated.
544 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
545 let extension = flavor.extension();
546 self.temp_path_ext(extension, codegen_unit_name)
549 /// Like temp_path, but also supports things where there is no corresponding
550 /// OutputType, like noopt-bitcode or lto-bitcode.
551 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
552 let base = self.out_directory.join(&self.filestem());
554 let mut extension = String::new();
556 if let Some(codegen_unit_name) = codegen_unit_name {
557 extension.push_str(codegen_unit_name);
561 if !extension.is_empty() {
562 extension.push_str(".");
563 extension.push_str(RUST_CGU_EXT);
564 extension.push_str(".");
567 extension.push_str(ext);
570 let path = base.with_extension(&extension[..]);
574 pub fn with_extension(&self, extension: &str) -> PathBuf {
576 .join(&self.filestem())
577 .with_extension(extension)
580 pub fn filestem(&self) -> String {
581 format!("{}{}", self.out_filestem, self.extra)
585 pub fn host_triple() -> &'static str {
586 // Get the host triple out of the build environment. This ensures that our
587 // idea of the host triple is the same as for the set of libraries we've
588 // actually built. We can't just take LLVM's host triple because they
589 // normalize all ix86 architectures to i386.
591 // Instead of grabbing the host triple (for the current host), we grab (at
592 // compile time) the target triple that this rustc is built with and
593 // calling that (at runtime) the host triple.
594 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
597 impl Default for Options {
598 fn default() -> Options {
600 crate_types: Vec::new(),
601 optimize: OptLevel::No,
602 debuginfo: DebugInfo::None,
603 lint_opts: Vec::new(),
605 describe_lints: false,
606 output_types: OutputTypes(BTreeMap::new()),
607 search_paths: vec![],
609 target_triple: TargetTriple::from_triple(host_triple()),
612 debugging_opts: basic_debugging_options(),
614 borrowck_mode: BorrowckMode::Migrate,
615 cg: basic_codegen_options(),
616 error_format: ErrorOutputType::default(),
617 externs: Externs(BTreeMap::new()),
621 unstable_features: UnstableFeatures::Disallow,
622 debug_assertions: true,
623 actually_rustdoc: false,
624 cli_forced_codegen_units: None,
625 cli_forced_thinlto_off: false,
626 remap_path_prefix: Vec::new(),
627 edition: DEFAULT_EDITION,
628 json_artifact_notifications: false,
635 /// Returns `true` if there is a reason to build the dep graph.
636 pub fn build_dep_graph(&self) -> bool {
637 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
638 || self.debugging_opts.query_dep_graph
642 pub fn enable_dep_node_debug_strs(&self) -> bool {
643 cfg!(debug_assertions)
644 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
647 pub fn file_path_mapping(&self) -> FilePathMapping {
648 FilePathMapping::new(self.remap_path_prefix.clone())
651 /// Returns `true` if there will be an output file generated.
652 pub fn will_create_output_file(&self) -> bool {
653 !self.debugging_opts.parse_only && // The file is just being parsed
654 !self.debugging_opts.ls // The file is just being queried
658 pub fn share_generics(&self) -> bool {
659 match self.debugging_opts.share_generics {
660 Some(setting) => setting,
662 match self.optimize {
666 OptLevel::SizeMin => true,
668 OptLevel::Aggressive => false,
675 // The type of entry function, so users can have their own entry functions
676 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
677 pub enum EntryFnType {
682 impl_stable_hash_via_hash!(EntryFnType);
684 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, HashStable)]
694 #[derive(Clone, Hash)]
701 pub fn is_empty(&self) -> bool {
703 Passes::Some(ref v) => v.is_empty(),
704 Passes::All => false,
709 /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
710 /// macro is to define an interface that can be programmatically used by the option parser
711 /// to initialize the struct without hardcoding field names all over the place.
713 /// The goal is to invoke this macro once with the correct fields, and then this macro generates all
714 /// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
715 /// generated code to parse an option into its respective field in the struct. There are a few
716 /// hand-written parsers for parsing specific types of values in this module.
717 macro_rules! options {
718 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
719 $buildfn:ident, $prefix:expr, $outputname:expr,
720 $stat:ident, $mod_desc:ident, $mod_set:ident,
721 $($opt:ident : $t:ty = (
724 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
729 pub struct $struct_name { $(pub $opt: $t),* }
731 pub fn $defaultfn() -> $struct_name {
732 $struct_name { $($opt: $init),* }
735 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
737 let mut op = $defaultfn();
738 for option in matches.opt_strs($prefix) {
739 let mut iter = option.splitn(2, '=');
740 let key = iter.next().unwrap();
741 let value = iter.next();
742 let option_to_lookup = key.replace("-", "_");
743 let mut found = false;
744 for &(candidate, setter, opt_type_desc, _) in $stat {
745 if option_to_lookup != candidate { continue }
746 if !setter(&mut op, value) {
747 match (value, opt_type_desc) {
748 (Some(..), None) => {
749 early_error(error_format, &format!("{} option `{}` takes no \
750 value", $outputname, key))
752 (None, Some(type_desc)) => {
753 early_error(error_format, &format!("{0} option `{1}` requires \
754 {2} ({3} {1}=<value>)",
758 (Some(value), Some(type_desc)) => {
759 early_error(error_format, &format!("incorrect value `{}` for {} \
760 option `{}` - {} was expected",
764 (None, None) => bug!()
771 early_error(error_format, &format!("unknown {} option: `{}`",
778 impl dep_tracking::DepTrackingHash for $struct_name {
779 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
780 let mut sub_hashes = BTreeMap::new();
785 [$dep_tracking_marker $($dep_warn_val,
789 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
793 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
794 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
795 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
797 #[allow(non_upper_case_globals, dead_code)]
799 pub const parse_bool: Option<&str> = None;
800 pub const parse_opt_bool: Option<&str> =
801 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
802 pub const parse_string: Option<&str> = Some("a string");
803 pub const parse_string_push: Option<&str> = Some("a string");
804 pub const parse_pathbuf_push: Option<&str> = Some("a path");
805 pub const parse_opt_string: Option<&str> = Some("a string");
806 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
807 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
808 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
809 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
810 pub const parse_threads: Option<&str> = Some("a number");
811 pub const parse_uint: Option<&str> = Some("a number");
812 pub const parse_passes: Option<&str> =
813 Some("a space-separated list of passes, or `all`");
814 pub const parse_opt_uint: Option<&str> =
816 pub const parse_panic_strategy: Option<&str> =
817 Some("either `unwind` or `abort`");
818 pub const parse_relro_level: Option<&str> =
819 Some("one of: `full`, `partial`, or `off`");
820 pub const parse_sanitizer: Option<&str> =
821 Some("one of: `address`, `leak`, `memory` or `thread`");
822 pub const parse_linker_flavor: Option<&str> =
823 Some(::rustc_target::spec::LinkerFlavor::one_of());
824 pub const parse_optimization_fuel: Option<&str> =
825 Some("crate=integer");
826 pub const parse_unpretty: Option<&str> =
827 Some("`string` or `string=string`");
828 pub const parse_treat_err_as_bug: Option<&str> =
829 Some("either no value or a number bigger than 0");
830 pub const parse_lto: Option<&str> =
831 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
833 pub const parse_linker_plugin_lto: Option<&str> =
834 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
835 or the path to the linker plugin");
836 pub const parse_switch_with_opt_path: Option<&str> =
837 Some("an optional path to the profiling data output directory");
838 pub const parse_merge_functions: Option<&str> =
839 Some("one of: `disabled`, `trampolines`, or `aliases`");
840 pub const parse_symbol_mangling_version: Option<&str> =
841 Some("either `legacy` or `v0` (RFC 2603)");
846 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
847 SymbolManglingVersion};
848 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
849 use std::path::PathBuf;
850 use std::str::FromStr;
853 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
854 $parse(&mut cg.$opt, v)
858 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
861 None => { *slot = true; true }
865 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
869 "n" | "no" | "off" => {
872 "y" | "yes" | "on" => {
875 _ => { return false; }
880 None => { *slot = Some(true); true }
884 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
886 Some(s) => { *slot = Some(s.to_string()); true },
891 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
893 Some(s) => { *slot = Some(PathBuf::from(s)); true },
898 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
900 Some(s) => { *slot = s.to_string(); true },
905 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
907 Some(s) => { slot.push(s.to_string()); true },
912 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
914 Some(s) => { slot.push(PathBuf::from(s)); true },
919 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
923 slot.extend(s.split_whitespace().map(|s| s.to_string()));
930 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
934 let v = s.split_whitespace().map(|s| s.to_string()).collect();
942 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
946 let v = s.split(',').map(|s| s.to_string()).collect();
954 fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
955 match v.and_then(|s| s.parse().ok()) {
956 Some(0) => { *slot = ::num_cpus::get(); true },
957 Some(i) => { *slot = i; true },
962 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
963 match v.and_then(|s| s.parse().ok()) {
964 Some(i) => { *slot = i; true },
969 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
971 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
972 None => { *slot = None; false }
976 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
983 let mut passes = vec![];
984 if parse_list(&mut passes, v) {
985 *slot = Passes::Some(passes);
994 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
996 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
997 Some("abort") => *slot = Some(PanicStrategy::Abort),
1003 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1006 match s.parse::<RelroLevel>() {
1007 Ok(level) => *slot = Some(level),
1016 fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1018 Some("address") => *slote = Some(Sanitizer::Address),
1019 Some("leak") => *slote = Some(Sanitizer::Leak),
1020 Some("memory") => *slote = Some(Sanitizer::Memory),
1021 Some("thread") => *slote = Some(Sanitizer::Thread),
1027 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1028 match v.and_then(LinkerFlavor::from_str) {
1029 Some(lf) => *slote = Some(lf),
1035 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1039 let parts = s.split('=').collect::<Vec<_>>();
1040 if parts.len() != 2 { return false; }
1041 let crate_name = parts[0].to_string();
1042 let fuel = parts[1].parse::<u64>();
1043 if fuel.is_err() { return false; }
1044 *slot = Some((crate_name, fuel.unwrap()));
1050 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1053 Some(s) if s.split('=').count() <= 2 => {
1054 *slot = Some(s.to_string());
1061 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1063 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1064 None => { *slot = Some(1); true }
1068 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1070 let mut bool_arg = None;
1071 if parse_opt_bool(&mut bool_arg, v) {
1072 *slot = if bool_arg.unwrap() {
1082 None => LtoCli::NoParam,
1083 Some("thin") => LtoCli::Thin,
1084 Some("fat") => LtoCli::Fat,
1085 Some(_) => return false,
1090 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1092 let mut bool_arg = None;
1093 if parse_opt_bool(&mut bool_arg, v) {
1094 *slot = if bool_arg.unwrap() {
1095 LinkerPluginLto::LinkerPluginAuto
1097 LinkerPluginLto::Disabled
1104 None => LinkerPluginLto::LinkerPluginAuto,
1105 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1110 fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1112 None => SwitchWithOptPath::Enabled(None),
1113 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1118 fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1119 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1120 Some(mergefunc) => *slot = Some(mergefunc),
1126 fn parse_symbol_mangling_version(
1127 slot: &mut SymbolManglingVersion,
1131 Some("legacy") => SymbolManglingVersion::Legacy,
1132 Some("v0") => SymbolManglingVersion::V0,
1140 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1141 build_codegen_options, "C", "codegen",
1142 CG_OPTIONS, cg_type_desc, cgsetters,
1143 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1144 "this option is deprecated and does nothing"),
1145 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1146 "system linker to link outputs with"),
1147 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1148 "a single extra argument to append to the linker invocation (can be used several times)"),
1149 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1150 "extra arguments to append to the linker invocation (space separated)"),
1151 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1152 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1153 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1154 "perform LLVM link-time optimizations"),
1155 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1156 "select target processor (`rustc --print target-cpus` for details)"),
1157 target_feature: String = (String::new(), parse_string, [TRACKED],
1158 "target specific attributes. (`rustc --print target-features` for details). \
1159 This feature is unsafe."),
1160 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1161 "a list of extra LLVM passes to run (space separated)"),
1162 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1163 "a list of arguments to pass to LLVM (space separated)"),
1164 save_temps: bool = (false, parse_bool, [UNTRACKED],
1165 "save all temporary output files during compilation"),
1166 rpath: bool = (false, parse_bool, [UNTRACKED],
1167 "set rpath values in libs/exes"),
1168 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1169 "use overflow checks for integer arithmetic"),
1170 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1171 "don't pre-populate the pass manager with a list of passes"),
1172 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1173 "don't run the loop vectorization optimization passes"),
1174 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1175 "don't run LLVM's SLP vectorization pass"),
1176 soft_float: bool = (false, parse_bool, [TRACKED],
1177 "use soft float ABI (*eabihf targets only)"),
1178 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1179 "prefer dynamic linking to static linking"),
1180 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1181 "use an external assembler rather than LLVM's integrated one"),
1182 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1183 "disable the use of the redzone"),
1184 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1185 "choose the relocation model to use (`rustc --print relocation-models` for details)"),
1186 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1187 "choose the code model to use (`rustc --print code-models` for details)"),
1188 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1189 "metadata to mangle symbol names with"),
1190 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1191 "extra data to put in each output filename"),
1192 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1193 "divide crate into N units to optimize in parallel"),
1194 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1195 "print remarks for these optimization passes (space separated, or \"all\")"),
1196 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1197 "the `--no-stack-check` flag is deprecated and does nothing"),
1198 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1199 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1200 2 = full debug info with variable and type information"),
1201 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1202 "optimize with possible levels 0-3, s, or z"),
1203 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1204 "force use of the frame pointers"),
1205 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1206 "explicitly enable the cfg(debug_assertions) directive"),
1207 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1208 "set the threshold for inlining a function (default: 225)"),
1209 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1210 [TRACKED], "panic strategy to compile crate with"),
1211 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1212 "enable incremental compilation"),
1213 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1214 "allow the linker to link its default libraries"),
1215 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1217 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1218 parse_linker_plugin_lto, [TRACKED],
1219 "generate build artifacts that are compatible with linker-based LTO."),
1220 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1221 parse_switch_with_opt_path, [TRACKED],
1222 "compile the program with profiling instrumentation"),
1223 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1224 "use the given `.profdata` file for profile-guided optimization"),
1227 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1228 build_debugging_options, "Z", "debugging",
1229 DB_OPTIONS, db_type_desc, dbsetters,
1230 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1231 "the backend to use"),
1232 verbose: bool = (false, parse_bool, [UNTRACKED],
1233 "in general, enable more debug printouts"),
1234 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1235 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1236 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1237 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1238 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1239 "select which borrowck is used (`mir` or `migrate`)"),
1240 time_passes: bool = (false, parse_bool, [UNTRACKED],
1241 "measure time of each rustc pass"),
1242 time: bool = (false, parse_bool, [UNTRACKED],
1243 "measure time of rustc processes"),
1244 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1245 "measure time of each LLVM pass"),
1246 input_stats: bool = (false, parse_bool, [UNTRACKED],
1247 "gather statistics about the input"),
1248 asm_comments: bool = (false, parse_bool, [TRACKED],
1249 "generate comments into the assembly (may change behavior)"),
1250 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1252 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1253 "gather borrowck statistics"),
1254 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1255 "omit landing pads for unwinding"),
1256 fewer_names: bool = (false, parse_bool, [TRACKED],
1257 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1258 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1259 "gather metadata statistics"),
1260 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1261 "print the arguments passed to the linker"),
1262 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1263 "prints the LLVM optimization passes being run"),
1264 ast_json: bool = (false, parse_bool, [UNTRACKED],
1265 "print the AST as JSON and halt"),
1266 // We default to 1 here since we want to behave like
1267 // a sequential compiler for now. This'll likely be adjusted
1268 // in the future. Note that -Zthreads=0 is the way to get
1269 // the num_cpus behavior.
1270 threads: usize = (1, parse_threads, [UNTRACKED],
1271 "use a thread pool with N threads"),
1272 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1273 "print the pre-expansion AST as JSON and halt"),
1274 ls: bool = (false, parse_bool, [UNTRACKED],
1275 "list the symbols defined by a library crate"),
1276 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1277 "write syntax and type analysis (in JSON format) information, in \
1278 addition to normal output"),
1279 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1280 "prints region inference graph. \
1281 Use with RUST_REGION_GRAPH=help for more info"),
1282 parse_only: bool = (false, parse_bool, [UNTRACKED],
1283 "parse only; do not compile, assemble, or link"),
1284 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1285 "load proc macros for both target and host, but only link to the target"),
1286 no_codegen: bool = (false, parse_bool, [TRACKED],
1287 "run all passes except codegen; no output"),
1288 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1289 "treat error number `val` that occurs as bug"),
1290 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1291 "immediately print bugs registered with `delay_span_bug`"),
1292 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1293 "show macro backtraces even for non-local macros"),
1294 teach: bool = (false, parse_bool, [TRACKED],
1295 "show extended diagnostic help"),
1296 terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1297 "set the current terminal width"),
1298 panic_abort_tests: bool = (false, parse_bool, [TRACKED],
1299 "support compiling tests with panic=abort"),
1300 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1301 "attempt to recover from parse errors (experimental)"),
1302 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1303 "print tasks that execute and the color their dep node gets (requires debug build)"),
1304 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1305 "enable incremental compilation (experimental)"),
1306 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1307 "enable incremental compilation support for queries (experimental)"),
1308 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1309 "print high-level information about incremental reuse (or the lack thereof)"),
1310 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1311 "dump hash information in textual format to stdout"),
1312 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1313 "verify incr. comp. hashes of green query instances"),
1314 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1315 "ignore spans during ICH computation -- used for testing"),
1316 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1317 "insert function instrument code for mcount-based tracing"),
1318 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1319 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1320 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1321 "enable queries of the dependency graph for regression testing"),
1322 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1323 "parse and expand the source, but run no analysis"),
1324 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1325 "load extra plugins"),
1326 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1327 "adds unstable command line options to rustc interface"),
1328 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1329 "force overflow checks on or off"),
1330 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1331 "for every macro invocation, print its name and arguments"),
1332 debug_macros: bool = (false, parse_bool, [TRACKED],
1333 "emit line numbers debug info inside macros"),
1334 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1335 "don't clear the hygiene data after analysis"),
1336 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1337 "keep the AST after lowering it to HIR"),
1338 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1339 "show spans for compiler debugging (expr|pat|ty)"),
1340 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1341 "print layout information for each type encountered"),
1342 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1343 "print the result of the monomorphization collection pass"),
1344 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1345 "set the MIR optimization level (0-3, default: 1)"),
1346 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1347 "emit noalias metadata for mutable references (default: no)"),
1348 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1349 "dump MIR state to file.
1350 `val` is used to select which passes and functions to dump. For example:
1351 `all` matches all passes and functions,
1352 `foo` matches all passes for functions whose name contains 'foo',
1353 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1354 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1356 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1357 "the directory the MIR is dumped into"),
1358 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1359 "in addition to `.mir` files, create graphviz `.dot` files"),
1360 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1361 "if set, exclude the pass number when dumping MIR (used in tests)"),
1362 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1363 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1364 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1365 "print some performance-related statistics"),
1366 query_stats: bool = (false, parse_bool, [UNTRACKED],
1367 "print some statistics about the query system"),
1368 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1369 "print some statistics about AST and HIR"),
1370 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1371 "encode MIR of all functions into the crate metadata"),
1372 json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1373 "describes how to render the `rendered` field of json diagnostics"),
1374 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1375 "take the breaks off const evaluation. NOTE: this is unsound"),
1376 suppress_const_validation_back_compat_ice: bool = (false, parse_bool, [TRACKED],
1377 "silence ICE triggered when the new const validator disagrees with the old"),
1378 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1379 "pass `-install_name @rpath/...` to the macOS linker"),
1380 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1382 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1383 "set the optimization fuel quota for a crate"),
1384 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1385 "make rustc print the total optimization fuel used by a crate"),
1386 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1387 "force all crates to be `rustc_private` unstable"),
1388 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1389 "a single extra argument to prepend the linker invocation (can be used several times)"),
1390 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1391 "extra arguments to prepend to the linker invocation (space separated)"),
1392 profile: bool = (false, parse_bool, [TRACKED],
1393 "insert profiling code"),
1394 disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1395 "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1396 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1397 "choose which RELRO level to use"),
1398 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1399 "dump facts from NLL analysis into side files"),
1400 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1401 "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1402 dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1403 "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1404 polonius: bool = (false, parse_bool, [UNTRACKED],
1405 "enable polonius-based borrow-checker"),
1406 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1407 "generate a graphical HTML report of time spent in codegen and LLVM"),
1408 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1409 "enable ThinLTO when possible"),
1410 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1411 "control whether `#[inline]` functions are in all CGUs"),
1412 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1413 "choose the TLS model to use (`rustc --print tls-models` for details)"),
1414 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1415 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1416 the max/min integer respectively, and NaN is mapped to 0"),
1417 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1418 "generate human-readable, predictable names for codegen units"),
1419 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1420 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1422 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1423 "present the input source, unstable (and less-pretty) variants;
1424 valid types are any of the types for `--pretty`, as well as:
1425 `expanded`, `expanded,identified`,
1426 `expanded,hygiene` (with internal representations),
1427 `everybody_loops` (all function bodies replaced with `loop {}`),
1428 `hir` (the HIR), `hir,identified`,
1429 `hir,typed` (HIR with types for each node),
1430 `hir-tree` (dump the raw HIR),
1431 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1432 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1433 "run `dsymutil` and delete intermediate object files"),
1434 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1435 "format compiler diagnostics in a way that's better suitable for UI testing"),
1436 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1437 "embed LLVM bitcode in object files"),
1438 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1439 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1440 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1441 "make the current crate share its generic instantiations"),
1442 chalk: bool = (false, parse_bool, [TRACKED],
1443 "enable the experimental Chalk-based trait solving engine"),
1444 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1445 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1446 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1447 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1448 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1449 "don't interleave execution of lints; allows benchmarking individual lints"),
1450 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1451 "inject the given attribute in the crate"),
1452 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1453 parse_switch_with_opt_path, [UNTRACKED],
1454 "run the self profiler and output the raw event data"),
1455 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1456 "specifies which kinds of events get recorded by the self profiler"),
1457 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1458 "emits a section containing stack size metadata"),
1459 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1460 "whether to use the PLT when calling into shared libraries;
1461 only has effect for PIC code on systems with ELF binaries
1462 (default: PLT is disabled if full relro is enabled)"),
1463 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1464 "control the operation of the MergeFunctions LLVM pass, taking
1465 the same values as the target option of the same name"),
1466 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1467 "only allow the listed language features to be enabled in code (space separated)"),
1468 symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1469 parse_symbol_mangling_version, [TRACKED],
1470 "which mangling version to use for symbol names"),
1471 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
1472 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
1473 insert_sideeffect: bool = (false, parse_bool, [TRACKED],
1474 "fix undefined behavior when a thread doesn't eventually make progress \
1475 (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
1478 pub const fn default_lib_output() -> CrateType {
1482 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1483 let end = &sess.target.target.target_endian;
1484 let arch = &sess.target.target.arch;
1485 let wordsz = &sess.target.target.target_pointer_width;
1486 let os = &sess.target.target.target_os;
1487 let env = &sess.target.target.target_env;
1488 let vendor = &sess.target.target.target_vendor;
1489 let min_atomic_width = sess.target.target.min_atomic_width();
1490 let max_atomic_width = sess.target.target.max_atomic_width();
1491 let atomic_cas = sess.target.target.options.atomic_cas;
1493 let mut ret = FxHashSet::default();
1494 ret.reserve(6); // the minimum number of insertions
1496 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1497 if let Some(ref fam) = sess.target.target.options.target_family {
1498 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1499 if fam == "windows" || fam == "unix" {
1500 ret.insert((Symbol::intern(fam), None));
1503 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1504 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1506 Symbol::intern("target_pointer_width"),
1507 Some(Symbol::intern(wordsz)),
1509 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1511 Symbol::intern("target_vendor"),
1512 Some(Symbol::intern(vendor)),
1514 if sess.target.target.options.has_elf_tls {
1515 ret.insert((sym::target_thread_local, None));
1517 for &i in &[8, 16, 32, 64, 128] {
1518 if i >= min_atomic_width && i <= max_atomic_width {
1519 let mut insert_atomic = |s| {
1521 sym::target_has_atomic_load_store,
1522 Some(Symbol::intern(s)),
1526 sym::target_has_atomic,
1527 Some(Symbol::intern(s))
1531 let s = i.to_string();
1534 insert_atomic("ptr");
1538 if sess.opts.debug_assertions {
1539 ret.insert((Symbol::intern("debug_assertions"), None));
1541 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1542 ret.insert((sym::proc_macro, None));
1547 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1548 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1549 /// but the symbol interner is not yet set up then, so we must convert it later.
1550 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
1552 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1556 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1557 // Combine the configuration requested by the session (command line) with
1558 // some default and generated configuration items.
1559 let default_cfg = default_configuration(sess);
1560 // If the user wants a test runner, then add the test cfg.
1562 user_cfg.insert((sym::test, None));
1564 user_cfg.extend(default_cfg.iter().cloned());
1568 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1569 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1570 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1571 .help("Use `--print target-list` for a list of built-in targets")
1576 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1577 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1578 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1579 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1580 w => sp.fatal(&format!(
1581 "target specification was invalid: \
1582 unrecognized target-pointer-width {}",
1594 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1595 pub enum OptionStability {
1600 pub struct RustcOptGroup {
1601 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1602 pub name: &'static str,
1603 pub stability: OptionStability,
1606 impl RustcOptGroup {
1607 pub fn is_stable(&self) -> bool {
1608 self.stability == OptionStability::Stable
1611 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1613 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1618 stability: OptionStability::Stable,
1622 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1624 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1629 stability: OptionStability::Unstable,
1634 // The `opt` local module holds wrappers around the `getopts` API that
1635 // adds extra rustc-specific metadata to each option; such metadata
1636 // is exposed by . The public
1637 // functions below ending with `_u` are the functions that return
1638 // *unstable* options, i.e., options that are only enabled when the
1639 // user also passes the `-Z unstable-options` debugging flag.
1641 // The `fn flag*` etc below are written so that we can use them
1642 // in the future; do not warn about them not being used right now.
1643 #![allow(dead_code)]
1646 use super::RustcOptGroup;
1648 pub type R = RustcOptGroup;
1649 pub type S = &'static str;
1651 fn stable<F>(name: S, f: F) -> R
1653 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1655 RustcOptGroup::stable(name, f)
1658 fn unstable<F>(name: S, f: F) -> R
1660 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1662 RustcOptGroup::unstable(name, f)
1665 fn longer(a: S, b: S) -> S {
1666 if a.len() > b.len() {
1673 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1674 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1676 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1677 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1679 pub fn flag_s(a: S, b: S, c: S) -> R {
1680 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1682 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1683 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1685 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1686 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1689 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1690 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1692 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1693 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1695 pub fn flag(a: S, b: S, c: S) -> R {
1696 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1698 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1699 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1701 pub fn flagmulti(a: S, b: S, c: S) -> R {
1702 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1706 /// Returns the "short" subset of the rustc command line options,
1707 /// including metadata for each option, such as whether the option is
1708 /// part of the stable long-term interface for rustc.
1709 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1711 opt::flag_s("h", "help", "Display this message"),
1712 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1716 "Add a directory to the library search path. The
1717 optional KIND can be one of dependency, crate, native,
1718 framework, or all (the default).",
1724 "Link the generated crate(s) to the specified native
1725 library NAME. The optional KIND can be one of
1726 static, framework, or dylib (the default).",
1729 make_crate_type_option(),
1733 "Specify the name of the crate being built",
1739 "Specify which edition of the compiler to use when compiling code.",
1745 "Comma separated list of types of output for \
1746 the compiler to emit",
1747 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1752 "Compiler information to print on stdout",
1753 "[crate-name|file-names|sysroot|cfg|target-list|\
1754 target-cpus|target-features|relocation-models|\
1755 code-models|tls-models|target-spec-json|native-static-libs]",
1757 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1758 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1759 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1763 "Write output to compiler-chosen filename \
1770 "Provide a detailed explanation of an error \
1774 opt::flag_s("", "test", "Build a test harness"),
1778 "Target triple for which the code is compiled",
1781 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1782 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1783 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1784 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1788 "Set the most restrictive lint level. \
1789 More restrictive lints are capped at this \
1793 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1794 opt::flag_s("V", "version", "Print version info and exit"),
1795 opt::flag_s("v", "verbose", "Use verbose output"),
1799 /// Returns all rustc command line options, including metadata for
1800 /// each option, such as whether the option is part of the stable
1801 /// long-term interface for rustc.
1802 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1803 let mut opts = rustc_short_optgroups();
1808 "Specify where an external rust library is located",
1814 "Specify where an extern rust library is located, marking it as a private dependency",
1817 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1818 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1822 "How errors and other messages are produced",
1828 "Configure the JSON output of the compiler",
1834 "Configure coloring of output:
1835 auto = colorize, if output goes to a tty (default);
1836 always = always colorize output;
1837 never = never colorize output",
1838 "auto|always|never",
1843 "Pretty-print the input instead of compiling;
1844 valid types are: `normal` (un-annotated source),
1845 `expanded` (crates expanded), or
1846 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1851 "remap-path-prefix",
1852 "Remap source names in all output (compiler messages and output files)",
1859 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1860 error_format: ErrorOutputType)
1861 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1862 let mut lint_opts = vec![];
1863 let mut describe_lints = false;
1865 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1866 for lint_name in matches.opt_strs(level.as_str()) {
1867 if lint_name == "help" {
1868 describe_lints = true;
1870 lint_opts.push((lint_name.replace("-", "_"), level));
1875 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1876 lint::Level::from_str(&cap)
1877 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1879 (lint_opts, describe_lints, lint_cap)
1882 /// Parses the `--color` flag.
1883 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1884 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1885 Some("auto") => ColorConfig::Auto,
1886 Some("always") => ColorConfig::Always,
1887 Some("never") => ColorConfig::Never,
1889 None => ColorConfig::Auto,
1891 Some(arg) => early_error(
1892 ErrorOutputType::default(),
1894 "argument for `--color` must be auto, \
1895 always or never (instead was `{}`)",
1902 /// Parse the `--json` flag.
1904 /// The first value returned is how to render JSON diagnostics, and the second
1905 /// is whether or not artifact notifications are enabled.
1906 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1907 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1908 HumanReadableErrorType::Default;
1909 let mut json_color = ColorConfig::Never;
1910 let mut json_artifact_notifications = false;
1911 for option in matches.opt_strs("json") {
1912 // For now conservatively forbid `--color` with `--json` since `--json`
1913 // won't actually be emitting any colors and anything colorized is
1914 // embedded in a diagnostic message anyway.
1915 if matches.opt_str("color").is_some() {
1917 ErrorOutputType::default(),
1918 "cannot specify the `--color` option with `--json`",
1922 for sub_option in option.split(',') {
1924 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1925 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1926 "artifacts" => json_artifact_notifications = true,
1929 ErrorOutputType::default(),
1930 &format!("unknown `--json` option `{}`", s),
1936 (json_rendered(json_color), json_artifact_notifications)
1939 /// Parses the `--error-format` flag.
1940 pub fn parse_error_format(
1941 matches: &getopts::Matches,
1943 json_rendered: HumanReadableErrorType,
1944 ) -> ErrorOutputType {
1945 // We need the `opts_present` check because the driver will send us Matches
1946 // with only stable options if no unstable options are used. Since error-format
1947 // is unstable, it will not be present. We have to use `opts_present` not
1948 // `opt_present` because the latter will panic.
1949 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1950 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1952 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1953 Some("human-annotate-rs") => {
1954 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1956 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1957 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1958 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1960 Some(arg) => early_error(
1961 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1963 "argument for `--error-format` must be `human`, `json` or \
1964 `short` (instead was `{}`)",
1970 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1973 match error_format {
1974 ErrorOutputType::Json { .. } => {}
1976 // Conservatively require that the `--json` argument is coupled with
1977 // `--error-format=json`. This means that `--json` is specified we
1978 // should actually be emitting JSON blobs.
1979 _ if matches.opt_strs("json").len() > 0 => {
1981 ErrorOutputType::default(),
1982 "using `--json` requires also using `--error-format=json`",
1989 return error_format;
1992 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1993 let edition = match matches.opt_str("edition") {
1994 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
1996 ErrorOutputType::default(),
1998 "argument for `--edition` must be one of: \
1999 {}. (instead was `{}`)",
2005 None => DEFAULT_EDITION,
2008 if !edition.is_stable() && !nightly_options::is_nightly_build() {
2010 ErrorOutputType::default(),
2012 "edition {} is unstable and only \
2013 available for nightly builds of rustc.",
2022 fn check_debug_option_stability(
2023 debugging_opts: &DebuggingOptions,
2024 error_format: ErrorOutputType,
2025 json_rendered: HumanReadableErrorType,
2027 if !debugging_opts.unstable_options {
2028 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2030 ErrorOutputType::Json { pretty: false, json_rendered },
2031 "`--error-format=pretty-json` is unstable",
2034 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
2037 ErrorOutputType::Json { pretty: false, json_rendered },
2038 "`--error-format=human-annotate-rs` is unstable",
2044 fn parse_output_types(
2045 debugging_opts: &DebuggingOptions,
2046 matches: &getopts::Matches,
2047 error_format: ErrorOutputType,
2049 let mut output_types = BTreeMap::new();
2050 if !debugging_opts.parse_only {
2051 for list in matches.opt_strs("emit") {
2052 for output_type in list.split(',') {
2053 let mut parts = output_type.splitn(2, '=');
2054 let shorthand = parts.next().unwrap();
2055 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2059 "unknown emission type: `{}` - expected one of: {}",
2061 OutputType::shorthands_display(),
2065 let path = parts.next().map(PathBuf::from);
2066 output_types.insert(output_type, path);
2070 if output_types.is_empty() {
2071 output_types.insert(OutputType::Exe, None);
2073 OutputTypes(output_types)
2076 fn should_override_cgus_and_disable_thinlto(
2077 output_types: &OutputTypes,
2078 matches: &getopts::Matches,
2079 error_format: ErrorOutputType,
2080 mut codegen_units: Option<usize>,
2081 ) -> (bool, Option<usize>) {
2082 let mut disable_thinlto = false;
2083 // Issue #30063: if user requests LLVM-related output to one
2084 // particular path, disable codegen-units.
2085 let incompatible: Vec<_> = output_types.0
2087 .map(|ot_path| ot_path.0)
2088 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2089 .map(|ot| ot.shorthand())
2091 if !incompatible.is_empty() {
2092 match codegen_units {
2093 Some(n) if n > 1 => {
2094 if matches.opt_present("o") {
2095 for ot in &incompatible {
2099 "`--emit={}` with `-o` incompatible with \
2100 `-C codegen-units=N` for N > 1",
2105 early_warn(error_format, "resetting to default -C codegen-units=1");
2106 codegen_units = Some(1);
2107 disable_thinlto = true;
2111 codegen_units = Some(1);
2112 disable_thinlto = true;
2117 if codegen_units == Some(0) {
2120 "value for codegen units must be a positive non-zero integer",
2124 (disable_thinlto, codegen_units)
2127 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
2128 if debugging_opts.threads == 0 {
2131 "value for threads must be a positive non-zero integer",
2135 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
2138 "optimization fuel is incompatible with multiple threads",
2143 fn select_incremental_path(
2144 debugging_opts: &DebuggingOptions,
2145 cg: &CodegenOptions,
2146 error_format: ErrorOutputType,
2147 ) -> Option<PathBuf> {
2148 match (&debugging_opts.incremental, &cg.incremental) {
2149 (Some(path1), Some(path2)) => {
2154 "conflicting paths for `-Z incremental` and \
2155 `-C incremental` specified: {} versus {}",
2163 (Some(path), None) => Some(path),
2164 (None, Some(path)) => Some(path),
2165 (None, None) => None,
2166 }.map(|m| PathBuf::from(m))
2169 fn collect_print_requests(
2170 cg: &mut CodegenOptions,
2171 dopts: &mut DebuggingOptions,
2172 matches: &getopts::Matches,
2173 error_format: ErrorOutputType,
2174 ) -> Vec<PrintRequest> {
2175 let mut prints = Vec::<PrintRequest>::new();
2176 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2177 prints.push(PrintRequest::TargetCPUs);
2178 cg.target_cpu = None;
2180 if cg.target_feature == "help" {
2181 prints.push(PrintRequest::TargetFeatures);
2182 cg.target_feature = String::new();
2184 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2185 prints.push(PrintRequest::RelocationModels);
2186 cg.relocation_model = None;
2188 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2189 prints.push(PrintRequest::CodeModels);
2190 cg.code_model = None;
2195 .map_or(false, |s| s == "help")
2197 prints.push(PrintRequest::TlsModels);
2198 dopts.tls_model = None;
2201 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2202 "crate-name" => PrintRequest::CrateName,
2203 "file-names" => PrintRequest::FileNames,
2204 "sysroot" => PrintRequest::Sysroot,
2205 "cfg" => PrintRequest::Cfg,
2206 "target-list" => PrintRequest::TargetList,
2207 "target-cpus" => PrintRequest::TargetCPUs,
2208 "target-features" => PrintRequest::TargetFeatures,
2209 "relocation-models" => PrintRequest::RelocationModels,
2210 "code-models" => PrintRequest::CodeModels,
2211 "tls-models" => PrintRequest::TlsModels,
2212 "native-static-libs" => PrintRequest::NativeStaticLibs,
2213 "target-spec-json" => {
2214 if dopts.unstable_options {
2215 PrintRequest::TargetSpec
2219 "the `-Z unstable-options` flag must also be passed to \
2220 enable the target-spec-json print option",
2224 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2230 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
2231 match matches.opt_str("target") {
2232 Some(target) if target.ends_with(".json") => {
2233 let path = Path::new(&target);
2234 TargetTriple::from_path(&path).unwrap_or_else(|_|
2235 early_error(error_format, &format!("target file {:?} does not exist", path)))
2237 Some(target) => TargetTriple::TargetTriple(target),
2238 _ => TargetTriple::from_triple(host_triple()),
2243 matches: &getopts::Matches,
2244 cg: &CodegenOptions,
2245 error_format: ErrorOutputType,
2247 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2248 // to use them interchangeably. However, because they're technically different flags,
2249 // we need to work out manually which should take precedence if both are supplied (i.e.
2250 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2251 // comparing them. Note that if a flag is not found, its position will be `None`, which
2252 // always compared less than `Some(_)`.
2253 let max_o = matches.opt_positions("O").into_iter().max();
2254 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2255 if let Some("opt-level") = s.splitn(2, '=').next() {
2264 match cg.opt_level.as_ref().map(String::as_ref) {
2265 None => OptLevel::No,
2266 Some("0") => OptLevel::No,
2267 Some("1") => OptLevel::Less,
2268 Some("2") => OptLevel::Default,
2269 Some("3") => OptLevel::Aggressive,
2270 Some("s") => OptLevel::Size,
2271 Some("z") => OptLevel::SizeMin,
2276 "optimization level needs to be \
2277 between 0-3, s or z (instead was `{}`)",
2286 fn select_debuginfo(
2287 matches: &getopts::Matches,
2288 cg: &CodegenOptions,
2289 error_format: ErrorOutputType,
2291 let max_g = matches.opt_positions("g").into_iter().max();
2292 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2293 if let Some("debuginfo") = s.splitn(2, '=').next() {
2302 match cg.debuginfo {
2303 None | Some(0) => DebugInfo::None,
2304 Some(1) => DebugInfo::Limited,
2305 Some(2) => DebugInfo::Full,
2310 "debug info level needs to be between \
2311 0-2 (instead was `{}`)",
2321 matches: &getopts::Matches,
2322 error_format: ErrorOutputType,
2323 ) -> Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> {
2328 // Parse string of the form "[KIND=]lib[:new_name]",
2329 // where KIND is one of "dylib", "framework", "static".
2330 let mut parts = s.splitn(2, '=');
2331 let kind = parts.next().unwrap();
2332 let (name, kind) = match (parts.next(), kind) {
2333 (None, name) => (name, None),
2334 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2335 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2336 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2337 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2342 "unknown library kind `{}`, expected \
2343 one of dylib, framework, or static",
2349 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2353 "the library kind 'static-nobundle' is only \
2354 accepted on the nightly compiler"
2358 let mut name_parts = name.splitn(2, ':');
2359 let name = name_parts.next().unwrap();
2360 let new_name = name_parts.next();
2361 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2366 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2367 match dopts.borrowck.as_ref().map(|s| &s[..]) {
2368 None | Some("migrate") => BorrowckMode::Migrate,
2369 Some("mir") => BorrowckMode::Mir,
2370 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2375 matches: &getopts::Matches,
2376 debugging_opts: &DebuggingOptions,
2377 error_format: ErrorOutputType,
2379 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2381 ErrorOutputType::default(),
2382 "'--extern-private' is unstable and only \
2383 available for nightly builds of rustc."
2387 // We start out with a `Vec<(Option<String>, bool)>>`,
2388 // and later convert it into a `BTreeSet<(Option<String>, bool)>`
2389 // This allows to modify entries in-place to set their correct
2391 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2392 for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
2393 .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
2395 let mut parts = arg.splitn(2, '=');
2396 let name = parts.next().unwrap_or_else(||
2397 early_error(error_format, "--extern value must not be empty"));
2398 let location = parts.next().map(|s| s.to_string());
2401 .entry(name.to_owned())
2405 entry.locations.insert(location.clone());
2407 // Crates start out being not private,
2408 // and go to being private if we see an '--extern-private'
2410 entry.is_private_dep |= private;
2415 fn parse_remap_path_prefix(
2416 matches: &getopts::Matches,
2417 error_format: ErrorOutputType
2418 ) -> Vec<(PathBuf, PathBuf)> {
2420 .opt_strs("remap-path-prefix")
2423 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2424 let to = parts.next();
2425 let from = parts.next();
2427 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2430 "--remap-path-prefix must contain '=' between FROM and TO",
2437 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2438 let color = parse_color(matches);
2440 let edition = parse_crate_edition(matches);
2442 let (json_rendered, json_artifact_notifications) = parse_json(matches);
2444 let error_format = parse_error_format(matches, color, json_rendered);
2446 let unparsed_crate_types = matches.opt_strs("crate-type");
2447 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2448 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2450 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2452 let mut debugging_opts = build_debugging_options(matches, error_format);
2453 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2455 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2457 let mut cg = build_codegen_options(matches, error_format);
2458 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2465 check_thread_count(&debugging_opts, error_format);
2467 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
2469 if debugging_opts.profile && incremental.is_some() {
2472 "can't instrument with gcov profiling when compiling incrementally",
2476 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2479 "options `-C profile-generate` and `-C profile-use` are exclusive",
2483 let prints = collect_print_requests(
2485 &mut debugging_opts,
2492 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2493 let target_triple = parse_target_triple(matches, error_format);
2494 let opt_level = parse_opt_level(matches, &cg, error_format);
2495 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2496 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2497 // for more details.
2498 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2499 let debuginfo = select_debuginfo(matches, &cg, error_format);
2501 let mut search_paths = vec![];
2502 for s in &matches.opt_strs("L") {
2503 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2506 let libs = parse_libs(matches, error_format);
2508 let test = matches.opt_present("test");
2510 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2512 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2515 "-C remark requires \"-C debuginfo=n\" to show source locations",
2519 let externs = parse_externs(matches, &debugging_opts, error_format);
2521 let crate_name = matches.opt_str("crate-name");
2523 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2525 let pretty = parse_pretty(matches, &debugging_opts, error_format);
2529 optimize: opt_level,
2536 maybe_sysroot: sysroot_opt,
2549 unstable_features: UnstableFeatures::from_environment(),
2551 actually_rustdoc: false,
2552 cli_forced_codegen_units: codegen_units,
2553 cli_forced_thinlto_off: disable_thinlto,
2556 json_artifact_notifications,
2562 matches: &getopts::Matches,
2563 debugging_opts: &DebuggingOptions,
2564 efmt: ErrorOutputType,
2565 ) -> Option<(PpMode, Option<UserIdentifiedItem>)> {
2566 let pretty = if debugging_opts.unstable_options {
2567 matches.opt_default("pretty", "normal").map(|a| {
2568 // stable pretty-print variants only
2569 parse_pretty_inner(efmt, &a, false)
2575 return if pretty.is_none() {
2576 debugging_opts.unpretty.as_ref().map(|a| {
2577 // extended with unstable pretty-print variants
2578 parse_pretty_inner(efmt, &a, true)
2584 fn parse_pretty_inner(
2585 efmt: ErrorOutputType,
2588 ) -> (PpMode, Option<UserIdentifiedItem>) {
2590 use PpSourceMode::*;
2591 let mut split = name.splitn(2, '=');
2592 let first = split.next().unwrap();
2593 let opt_second = split.next();
2594 let first = match (first, extended) {
2595 ("normal", _) => PpmSource(PpmNormal),
2596 ("identified", _) => PpmSource(PpmIdentified),
2597 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
2598 ("expanded", _) => PpmSource(PpmExpanded),
2599 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
2600 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
2601 ("hir", true) => PpmHir(PpmNormal),
2602 ("hir,identified", true) => PpmHir(PpmIdentified),
2603 ("hir,typed", true) => PpmHir(PpmTyped),
2604 ("hir-tree", true) => PpmHirTree(PpmNormal),
2605 ("mir", true) => PpmMir,
2606 ("mir-cfg", true) => PpmMirCFG,
2609 early_error(efmt, &format!("argument to `unpretty` must be one of `normal`, \
2610 `expanded`, `identified`, `expanded,identified`, \
2611 `expanded,hygiene`, `everybody_loops`, \
2612 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
2613 `mir` or `mir-cfg`; got {}",
2616 early_error(efmt, &format!("argument to `pretty` must be one of `normal`, \
2617 `expanded`, `identified`, or `expanded,identified`; got {}",
2622 let opt_second = opt_second.and_then(|s| s.parse::<UserIdentifiedItem>().ok());
2627 pub fn make_crate_type_option() -> RustcOptGroup {
2631 "Comma separated list of types of crates
2632 for the compiler to emit",
2633 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2637 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2638 let mut crate_types: Vec<CrateType> = Vec::new();
2639 for unparsed_crate_type in &list_list {
2640 for part in unparsed_crate_type.split(',') {
2641 let new_part = match part {
2642 "lib" => default_lib_output(),
2643 "rlib" => CrateType::Rlib,
2644 "staticlib" => CrateType::Staticlib,
2645 "dylib" => CrateType::Dylib,
2646 "cdylib" => CrateType::Cdylib,
2647 "bin" => CrateType::Executable,
2648 "proc-macro" => CrateType::ProcMacro,
2649 _ => return Err(format!("unknown crate type: `{}`", part))
2651 if !crate_types.contains(&new_part) {
2652 crate_types.push(new_part)
2660 pub mod nightly_options {
2662 use syntax::feature_gate::UnstableFeatures;
2663 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2664 use crate::session::early_error;
2666 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2671 .any(|x| *x == "unstable-options")
2674 pub fn is_nightly_build() -> bool {
2675 UnstableFeatures::from_environment().is_nightly_build()
2678 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2679 let has_z_unstable_option = matches
2682 .any(|x| *x == "unstable-options");
2683 let really_allows_unstable_options =
2684 UnstableFeatures::from_environment().is_nightly_build();
2686 for opt in flags.iter() {
2687 if opt.stability == OptionStability::Stable {
2690 if !matches.opt_present(opt.name) {
2693 if opt.name != "Z" && !has_z_unstable_option {
2695 ErrorOutputType::default(),
2697 "the `-Z unstable-options` flag must also be passed to enable \
2703 if really_allows_unstable_options {
2706 match opt.stability {
2707 OptionStability::Unstable => {
2709 "the option `{}` is only accepted on the \
2713 early_error(ErrorOutputType::default(), &msg);
2715 OptionStability::Stable => {}
2721 impl fmt::Display for CrateType {
2722 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2724 CrateType::Executable => "bin".fmt(f),
2725 CrateType::Dylib => "dylib".fmt(f),
2726 CrateType::Rlib => "rlib".fmt(f),
2727 CrateType::Staticlib => "staticlib".fmt(f),
2728 CrateType::Cdylib => "cdylib".fmt(f),
2729 CrateType::ProcMacro => "proc-macro".fmt(f),
2734 #[derive(Copy, Clone, PartialEq, Debug)]
2735 pub enum PpSourceMode {
2740 PpmExpandedIdentified,
2745 #[derive(Copy, Clone, PartialEq, Debug)]
2747 PpmSource(PpSourceMode),
2748 PpmHir(PpSourceMode),
2749 PpmHirTree(PpSourceMode),
2755 pub fn needs_ast_map(&self, opt_uii: &Option<UserIdentifiedItem>) -> bool {
2757 use PpSourceMode::*;
2759 PpmSource(PpmNormal) |
2760 PpmSource(PpmEveryBodyLoops) |
2761 PpmSource(PpmIdentified) => opt_uii.is_some(),
2763 PpmSource(PpmExpanded) |
2764 PpmSource(PpmExpandedIdentified) |
2765 PpmSource(PpmExpandedHygiene) |
2770 PpmSource(PpmTyped) => panic!("invalid state"),
2774 pub fn needs_analysis(&self) -> bool {
2777 PpmMir | PpmMirCFG => true,
2783 #[derive(Clone, Debug)]
2784 pub enum UserIdentifiedItem {
2785 ItemViaNode(ast::NodeId),
2786 ItemViaPath(Vec<String>),
2789 impl FromStr for UserIdentifiedItem {
2791 fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
2792 use UserIdentifiedItem::*;
2794 .map(ast::NodeId::from_u32)
2796 .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
2800 pub enum NodesMatchingUII<'a> {
2801 NodesMatchingDirect(std::option::IntoIter<ast::NodeId>),
2802 NodesMatchingSuffix(Box<dyn Iterator<Item = ast::NodeId> + 'a>),
2805 impl<'a> Iterator for NodesMatchingUII<'a> {
2806 type Item = ast::NodeId;
2808 fn next(&mut self) -> Option<ast::NodeId> {
2809 use NodesMatchingUII::*;
2811 &mut NodesMatchingDirect(ref mut iter) => iter.next(),
2812 &mut NodesMatchingSuffix(ref mut iter) => iter.next(),
2816 fn size_hint(&self) -> (usize, Option<usize>) {
2817 use NodesMatchingUII::*;
2819 &NodesMatchingDirect(ref iter) => iter.size_hint(),
2820 &NodesMatchingSuffix(ref iter) => iter.size_hint(),
2825 impl UserIdentifiedItem {
2826 pub fn reconstructed_input(&self) -> String {
2827 use UserIdentifiedItem::*;
2829 ItemViaNode(node_id) => node_id.to_string(),
2830 ItemViaPath(ref parts) => parts.join("::"),
2834 pub fn all_matching_node_ids<'a, 'hir>(&'a self,
2835 map: &'a hir_map::Map<'hir>)
2836 -> NodesMatchingUII<'a> {
2837 use UserIdentifiedItem::*;
2838 use NodesMatchingUII::*;
2840 ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()),
2841 ItemViaPath(ref parts) => {
2842 NodesMatchingSuffix(Box::new(map.nodes_matching_suffix(&parts)))
2847 pub fn to_one_node_id(self,
2850 map: &hir_map::Map<'_>)
2852 let fail_because = |is_wrong_because| -> ast::NodeId {
2853 let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
2856 self.reconstructed_input(),
2858 sess.fatal(&message)
2861 let mut saw_node = ast::DUMMY_NODE_ID;
2863 for node in self.all_matching_node_ids(map) {
2867 fail_because("does not resolve uniquely");
2871 fail_because("does not resolve to any item");
2879 /// Command-line arguments passed to the compiler have to be incorporated with
2880 /// the dependency tracking system for incremental compilation. This module
2881 /// provides some utilities to make this more convenient.
2883 /// The values of all command-line arguments that are relevant for dependency
2884 /// tracking are hashed into a single value that determines whether the
2885 /// incremental compilation cache can be re-used or not. This hashing is done
2886 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2887 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2888 /// the hash of which is order dependent, but we might not want the order of
2889 /// arguments to make a difference for the hash).
2891 /// However, since the value provided by `Hash::hash` often *is* suitable,
2892 /// especially for primitive types, there is the
2893 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2894 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2895 /// we have an opt-in scheme here, so one is hopefully forced to think about
2896 /// how the hash should be calculated when adding a new command-line argument.
2899 use crate::middle::cstore;
2900 use std::collections::BTreeMap;
2901 use std::hash::Hash;
2902 use std::path::PathBuf;
2903 use std::collections::hash_map::DefaultHasher;
2904 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2905 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2906 SymbolManglingVersion};
2907 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2908 use syntax::edition::Edition;
2909 use syntax::feature_gate::UnstableFeatures;
2911 pub trait DepTrackingHash {
2912 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2915 macro_rules! impl_dep_tracking_hash_via_hash {
2917 impl DepTrackingHash for $t {
2918 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2919 Hash::hash(self, hasher);
2925 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2927 impl DepTrackingHash for Vec<$t> {
2928 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2929 let mut elems: Vec<&$t> = self.iter().collect();
2931 Hash::hash(&elems.len(), hasher);
2932 for (index, elem) in elems.iter().enumerate() {
2933 Hash::hash(&index, hasher);
2934 DepTrackingHash::hash(*elem, hasher, error_format);
2941 impl_dep_tracking_hash_via_hash!(bool);
2942 impl_dep_tracking_hash_via_hash!(usize);
2943 impl_dep_tracking_hash_via_hash!(u64);
2944 impl_dep_tracking_hash_via_hash!(String);
2945 impl_dep_tracking_hash_via_hash!(PathBuf);
2946 impl_dep_tracking_hash_via_hash!(lint::Level);
2947 impl_dep_tracking_hash_via_hash!(Option<bool>);
2948 impl_dep_tracking_hash_via_hash!(Option<usize>);
2949 impl_dep_tracking_hash_via_hash!(Option<String>);
2950 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2951 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2952 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2953 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2954 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2955 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2956 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2957 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2958 impl_dep_tracking_hash_via_hash!(CrateType);
2959 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2960 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2961 impl_dep_tracking_hash_via_hash!(RelroLevel);
2962 impl_dep_tracking_hash_via_hash!(Passes);
2963 impl_dep_tracking_hash_via_hash!(OptLevel);
2964 impl_dep_tracking_hash_via_hash!(LtoCli);
2965 impl_dep_tracking_hash_via_hash!(DebugInfo);
2966 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2967 impl_dep_tracking_hash_via_hash!(OutputTypes);
2968 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2969 impl_dep_tracking_hash_via_hash!(Sanitizer);
2970 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2971 impl_dep_tracking_hash_via_hash!(TargetTriple);
2972 impl_dep_tracking_hash_via_hash!(Edition);
2973 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2974 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2975 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2977 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2978 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2979 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2980 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2981 impl_dep_tracking_hash_for_sortable_vec_of!((
2984 Option<cstore::NativeLibraryKind>
2986 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2988 impl<T1, T2> DepTrackingHash for (T1, T2)
2990 T1: DepTrackingHash,
2991 T2: DepTrackingHash,
2993 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2994 Hash::hash(&0, hasher);
2995 DepTrackingHash::hash(&self.0, hasher, error_format);
2996 Hash::hash(&1, hasher);
2997 DepTrackingHash::hash(&self.1, hasher, error_format);
3001 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
3003 T1: DepTrackingHash,
3004 T2: DepTrackingHash,
3005 T3: DepTrackingHash,
3007 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
3008 Hash::hash(&0, hasher);
3009 DepTrackingHash::hash(&self.0, hasher, error_format);
3010 Hash::hash(&1, hasher);
3011 DepTrackingHash::hash(&self.1, hasher, error_format);
3012 Hash::hash(&2, hasher);
3013 DepTrackingHash::hash(&self.2, hasher, error_format);
3017 // This is a stable hash because BTreeMap is a sorted container
3019 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
3020 hasher: &mut DefaultHasher,
3021 error_format: ErrorOutputType,
3023 for (key, sub_hash) in sub_hashes {
3024 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
3025 // the keys, as they are just plain strings
3026 Hash::hash(&key.len(), hasher);
3027 Hash::hash(key, hasher);
3028 sub_hash.hash(hasher, error_format);