1 // ignore-tidy-filelength
3 //! Contains infrastructure for configuring the compiler, including parsing
4 //! command-line options.
7 use crate::utils::NativeLibraryKind;
8 use crate::{early_error, early_warn, Session};
9 use crate::search_paths::SearchPath;
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
14 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
15 use rustc_target::spec::{Target, TargetTriple};
17 use syntax_pos::source_map::{FileName, FilePathMapping};
18 use syntax_pos::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
19 use syntax_pos::symbol::{sym, Symbol};
20 use rustc_feature::UnstableFeatures;
21 use crate::parse::CrateConfig;
23 use rustc_errors::emitter::HumanReadableErrorType;
24 use rustc_errors::{ColorConfig, FatalError, Handler};
28 use std::collections::{BTreeMap, BTreeSet};
29 use std::collections::btree_map::{
30 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
33 use std::str::{self, FromStr};
34 use std::hash::Hasher;
35 use std::collections::hash_map::DefaultHasher;
36 use std::iter::{self, FromIterator};
37 use std::path::{Path, PathBuf};
44 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
52 impl fmt::Display for Sanitizer {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 Sanitizer::Address => "address".fmt(f),
56 Sanitizer::Leak => "leak".fmt(f),
57 Sanitizer::Memory => "memory".fmt(f),
58 Sanitizer::Thread => "thread".fmt(f),
63 impl FromStr for Sanitizer {
65 fn from_str(s: &str) -> Result<Sanitizer, ()> {
67 "address" => Ok(Sanitizer::Address),
68 "leak" => Ok(Sanitizer::Leak),
69 "memory" => Ok(Sanitizer::Memory),
70 "thread" => Ok(Sanitizer::Thread),
76 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
86 impl_stable_hash_via_hash!(OptLevel);
88 /// This is what the `LtoCli` values get mapped to after resolving defaults and
89 /// and taking other command line options into account.
90 #[derive(Clone, PartialEq)]
92 /// Don't do any LTO whatsoever
95 /// Do a full crate graph LTO with ThinLTO
98 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
102 /// Do a full crate graph LTO with "fat" LTO
106 /// The different settings that the `-C lto` flag can have.
107 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
119 /// No `-C lto` flag passed
123 #[derive(Clone, PartialEq, Hash)]
124 pub enum LinkerPluginLto {
125 LinkerPlugin(PathBuf),
130 impl LinkerPluginLto {
131 pub fn enabled(&self) -> bool {
133 LinkerPluginLto::LinkerPlugin(_) |
134 LinkerPluginLto::LinkerPluginAuto => true,
135 LinkerPluginLto::Disabled => false,
140 #[derive(Clone, PartialEq, Hash)]
141 pub enum SwitchWithOptPath {
142 Enabled(Option<PathBuf>),
146 impl SwitchWithOptPath {
147 pub fn enabled(&self) -> bool {
149 SwitchWithOptPath::Enabled(_) => true,
150 SwitchWithOptPath::Disabled => false,
155 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
156 pub enum SymbolManglingVersion {
161 impl_stable_hash_via_hash!(SymbolManglingVersion);
163 #[derive(Clone, Copy, PartialEq, Hash)]
170 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
171 pub enum OutputType {
182 impl_stable_hash_via_hash!(OutputType);
185 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
187 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
189 | OutputType::Assembly
190 | OutputType::LlvmAssembly
192 | OutputType::Object => false,
196 fn shorthand(&self) -> &'static str {
198 OutputType::Bitcode => "llvm-bc",
199 OutputType::Assembly => "asm",
200 OutputType::LlvmAssembly => "llvm-ir",
201 OutputType::Mir => "mir",
202 OutputType::Object => "obj",
203 OutputType::Metadata => "metadata",
204 OutputType::Exe => "link",
205 OutputType::DepInfo => "dep-info",
209 fn from_shorthand(shorthand: &str) -> Option<Self> {
210 Some(match shorthand {
211 "asm" => OutputType::Assembly,
212 "llvm-ir" => OutputType::LlvmAssembly,
213 "mir" => OutputType::Mir,
214 "llvm-bc" => OutputType::Bitcode,
215 "obj" => OutputType::Object,
216 "metadata" => OutputType::Metadata,
217 "link" => OutputType::Exe,
218 "dep-info" => OutputType::DepInfo,
223 fn shorthands_display() -> String {
225 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
226 OutputType::Bitcode.shorthand(),
227 OutputType::Assembly.shorthand(),
228 OutputType::LlvmAssembly.shorthand(),
229 OutputType::Mir.shorthand(),
230 OutputType::Object.shorthand(),
231 OutputType::Metadata.shorthand(),
232 OutputType::Exe.shorthand(),
233 OutputType::DepInfo.shorthand(),
237 pub fn extension(&self) -> &'static str {
239 OutputType::Bitcode => "bc",
240 OutputType::Assembly => "s",
241 OutputType::LlvmAssembly => "ll",
242 OutputType::Mir => "mir",
243 OutputType::Object => "o",
244 OutputType::Metadata => "rmeta",
245 OutputType::DepInfo => "d",
246 OutputType::Exe => "",
251 /// The type of diagnostics output to generate.
252 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
253 pub enum ErrorOutputType {
254 /// Output meant for the consumption of humans.
255 HumanReadable(HumanReadableErrorType),
256 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
258 /// Render the JSON in a human readable way (with indents and newlines).
260 /// The JSON output includes a `rendered` field that includes the rendered
262 json_rendered: HumanReadableErrorType,
266 impl Default for ErrorOutputType {
267 fn default() -> Self {
268 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
272 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
273 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
274 /// dependency tracking for command-line arguments.
275 #[derive(Clone, Hash)]
276 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
278 impl_stable_hash_via_hash!(OutputTypes);
281 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
282 OutputTypes(BTreeMap::from_iter(
283 entries.iter().map(|&(k, ref v)| (k, v.clone())),
287 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
291 pub fn contains_key(&self, key: &OutputType) -> bool {
292 self.0.contains_key(key)
295 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
299 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
303 pub fn len(&self) -> usize {
307 // Returns `true` if any of the output types require codegen or linking.
308 pub fn should_codegen(&self) -> bool {
309 self.0.keys().any(|k| match *k {
311 | OutputType::Assembly
312 | OutputType::LlvmAssembly
315 | OutputType::Exe => true,
316 OutputType::Metadata | OutputType::DepInfo => false,
321 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
322 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
323 /// would break dependency tracking for command-line arguments.
325 pub struct Externs(BTreeMap<String, ExternEntry>);
327 #[derive(Clone, Debug)]
328 pub struct ExternEntry {
329 pub location: ExternLocation,
330 /// Indicates this is a "private" dependency for the
331 /// `exported_private_dependencies` lint.
333 /// This can be set with the `priv` option like
334 /// `--extern priv:name=foo.rlib`.
335 pub is_private_dep: bool,
336 /// Add the extern entry to the extern prelude.
338 /// This can be disabled with the `noprelude` option like
339 /// `--extern noprelude:name`.
340 pub add_prelude: bool,
343 #[derive(Clone, Debug)]
344 pub enum ExternLocation {
345 /// Indicates to look for the library in the search paths.
347 /// Added via `--extern name`.
348 FoundInLibrarySearchDirectories,
349 /// The locations where this extern entry must be found.
351 /// The `CrateLoader` is responsible for loading these and figuring out
352 /// which one to use.
354 /// Added via `--extern prelude_name=some_file.rlib`
355 ExactPaths(BTreeSet<String>),
359 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
363 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
367 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
373 fn new(location: ExternLocation) -> ExternEntry {
374 ExternEntry { location, is_private_dep: false, add_prelude: false }
377 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
378 match &self.location {
379 ExternLocation::ExactPaths(set) => Some(set.iter()),
385 macro_rules! hash_option {
386 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
387 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
388 if $sub_hashes.insert(stringify!($opt_name),
389 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
390 panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
395 macro_rules! top_level_options {
396 (pub struct Options { $(
397 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
405 pub fn dep_tracking_hash(&self) -> u64 {
406 let mut sub_hashes = BTreeMap::new();
411 [$dep_tracking_marker $($warn_val,
413 self.error_format)*]);
415 let mut hasher = DefaultHasher::new();
416 dep_tracking::stable_hash(sub_hashes,
425 // The top-level command-line options struct.
427 // For each option, one has to specify how it behaves with regard to the
428 // dependency tracking system of incremental compilation. This is done via the
429 // square-bracketed directive after the field type. The options are:
432 // A change in the given field will cause the compiler to completely clear the
433 // incremental compilation cache before proceeding.
436 // Incremental compilation is not influenced by this option.
438 // If you add a new option to this struct or one of the sub-structs like
439 // `CodegenOptions`, think about how it influences incremental compilation. If in
440 // doubt, specify [TRACKED], which is always "correct" but might lead to
441 // unnecessary re-compilation.
444 // The crate config requested for the session, which may be combined
445 // with additional crate configurations during the compile process.
446 crate_types: Vec<CrateType> [TRACKED],
447 optimize: OptLevel [TRACKED],
448 // Include the `debug_assertions` flag in dependency tracking, since it
449 // can influence whether overflow checks are done or not.
450 debug_assertions: bool [TRACKED],
451 debuginfo: DebugInfo [TRACKED],
452 lint_opts: Vec<(String, lint::Level)> [TRACKED],
453 lint_cap: Option<lint::Level> [TRACKED],
454 describe_lints: bool [UNTRACKED],
455 output_types: OutputTypes [TRACKED],
456 search_paths: Vec<SearchPath> [UNTRACKED],
457 libs: Vec<(String, Option<String>, Option<NativeLibraryKind>)> [TRACKED],
458 maybe_sysroot: Option<PathBuf> [UNTRACKED],
460 target_triple: TargetTriple [TRACKED],
462 test: bool [TRACKED],
463 error_format: ErrorOutputType [UNTRACKED],
465 // If `Some`, enable incremental compilation, using the given
466 // directory to store intermediate results.
467 incremental: Option<PathBuf> [UNTRACKED],
469 debugging_opts: DebuggingOptions [TRACKED],
470 prints: Vec<PrintRequest> [UNTRACKED],
471 // Determines which borrow checker(s) to run. This is the parsed, sanitized
472 // version of `debugging_opts.borrowck`, which is just a plain string.
473 borrowck_mode: BorrowckMode [UNTRACKED],
474 cg: CodegenOptions [TRACKED],
475 externs: Externs [UNTRACKED],
476 crate_name: Option<String> [TRACKED],
477 // An optional name to use as the crate for std during std injection,
478 // written `extern crate name as std`. Defaults to `std`. Used by
479 // out-of-tree drivers.
480 alt_std_name: Option<String> [TRACKED],
481 // Indicates how the compiler should treat unstable features.
482 unstable_features: UnstableFeatures [TRACKED],
484 // Indicates whether this run of the compiler is actually rustdoc. This
485 // is currently just a hack and will be removed eventually, so please
486 // try to not rely on this too much.
487 actually_rustdoc: bool [TRACKED],
489 // Specifications of codegen units / ThinLTO which are forced as a
490 // result of parsing command line options. These are not necessarily
491 // what rustc was invoked with, but massaged a bit to agree with
492 // commands like `--emit llvm-ir` which they're often incompatible with
493 // if we otherwise use the defaults of rustc.
494 cli_forced_codegen_units: Option<usize> [UNTRACKED],
495 cli_forced_thinlto_off: bool [UNTRACKED],
497 // Remap source path prefixes in all output (messages, object files, debug, etc.).
498 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
500 edition: Edition [TRACKED],
502 // `true` if we're emitting JSON blobs about each artifact produced
504 json_artifact_notifications: bool [TRACKED],
506 pretty: Option<PpMode> [UNTRACKED],
510 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
511 pub enum PrintRequest {
526 #[derive(Copy, Clone)]
527 pub enum BorrowckMode {
533 /// Returns whether we should run the MIR-based borrow check, but also fall back
534 /// on the AST borrow check if the MIR-based one errors.
535 pub fn migrate(self) -> bool {
537 BorrowckMode::Mir => false,
538 BorrowckMode::Migrate => true,
544 /// Load source code from a file.
546 /// Load source code from a string.
548 /// A string that is shown in place of a filename.
550 /// An anonymous string containing the source code.
556 pub fn filestem(&self) -> &str {
558 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
559 Input::Str { .. } => "rust_out",
563 pub fn get_input(&mut self) -> Option<&mut String> {
565 Input::File(_) => None,
566 Input::Str { ref mut input, .. } => Some(input),
570 pub fn source_name(&self) -> FileName {
572 Input::File(ref ifile) => ifile.clone().into(),
573 Input::Str { ref name, .. } => name.clone(),
578 #[derive(Clone, Hash)]
579 pub struct OutputFilenames {
580 pub out_directory: PathBuf,
581 pub out_filestem: String,
582 pub single_output_file: Option<PathBuf>,
584 pub outputs: OutputTypes,
587 impl_stable_hash_via_hash!(OutputFilenames);
589 pub const RUST_CGU_EXT: &str = "rcgu";
591 impl OutputFilenames {
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 also supports things where there is no corresponding
609 /// OutputType, like noopt-bitcode or lto-bitcode.
610 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
611 let base = self.out_directory.join(&self.filestem());
613 let mut extension = String::new();
615 if let Some(codegen_unit_name) = codegen_unit_name {
616 extension.push_str(codegen_unit_name);
620 if !extension.is_empty() {
621 extension.push_str(".");
622 extension.push_str(RUST_CGU_EXT);
623 extension.push_str(".");
626 extension.push_str(ext);
629 let path = base.with_extension(&extension[..]);
633 pub fn with_extension(&self, extension: &str) -> PathBuf {
635 .join(&self.filestem())
636 .with_extension(extension)
639 pub fn filestem(&self) -> String {
640 format!("{}{}", self.out_filestem, self.extra)
644 pub fn host_triple() -> &'static str {
645 // Get the host triple out of the build environment. This ensures that our
646 // idea of the host triple is the same as for the set of libraries we've
647 // actually built. We can't just take LLVM's host triple because they
648 // normalize all ix86 architectures to i386.
650 // Instead of grabbing the host triple (for the current host), we grab (at
651 // compile time) the target triple that this rustc is built with and
652 // calling that (at runtime) the host triple.
653 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
656 impl Default for Options {
657 fn default() -> Options {
659 crate_types: Vec::new(),
660 optimize: OptLevel::No,
661 debuginfo: DebugInfo::None,
662 lint_opts: Vec::new(),
664 describe_lints: false,
665 output_types: OutputTypes(BTreeMap::new()),
666 search_paths: vec![],
668 target_triple: TargetTriple::from_triple(host_triple()),
671 debugging_opts: basic_debugging_options(),
673 borrowck_mode: BorrowckMode::Migrate,
674 cg: basic_codegen_options(),
675 error_format: ErrorOutputType::default(),
676 externs: Externs(BTreeMap::new()),
680 unstable_features: UnstableFeatures::Disallow,
681 debug_assertions: true,
682 actually_rustdoc: false,
683 cli_forced_codegen_units: None,
684 cli_forced_thinlto_off: false,
685 remap_path_prefix: Vec::new(),
686 edition: DEFAULT_EDITION,
687 json_artifact_notifications: false,
694 /// Returns `true` if there is a reason to build the dep graph.
695 pub fn build_dep_graph(&self) -> bool {
696 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
697 || self.debugging_opts.query_dep_graph
701 pub fn enable_dep_node_debug_strs(&self) -> bool {
702 cfg!(debug_assertions)
703 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
706 pub fn file_path_mapping(&self) -> FilePathMapping {
707 FilePathMapping::new(self.remap_path_prefix.clone())
710 /// Returns `true` if there will be an output file generated.
711 pub fn will_create_output_file(&self) -> bool {
712 !self.debugging_opts.parse_only && // The file is just being parsed
713 !self.debugging_opts.ls // The file is just being queried
717 pub fn share_generics(&self) -> bool {
718 match self.debugging_opts.share_generics {
719 Some(setting) => setting,
721 match self.optimize {
725 OptLevel::SizeMin => true,
727 OptLevel::Aggressive => false,
734 // The type of entry function, so users can have their own entry functions
735 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
736 pub enum EntryFnType {
741 impl_stable_hash_via_hash!(EntryFnType);
743 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
753 impl_stable_hash_via_hash!(CrateType);
755 #[derive(Clone, Hash)]
762 pub fn is_empty(&self) -> bool {
764 Passes::Some(ref v) => v.is_empty(),
765 Passes::All => false,
770 /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
771 /// macro is to define an interface that can be programmatically used by the option parser
772 /// to initialize the struct without hardcoding field names all over the place.
774 /// The goal is to invoke this macro once with the correct fields, and then this macro generates all
775 /// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
776 /// generated code to parse an option into its respective field in the struct. There are a few
777 /// hand-written parsers for parsing specific types of values in this module.
778 macro_rules! options {
779 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
780 $buildfn:ident, $prefix:expr, $outputname:expr,
781 $stat:ident, $mod_desc:ident, $mod_set:ident,
782 $($opt:ident : $t:ty = (
785 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
790 pub struct $struct_name { $(pub $opt: $t),* }
792 pub fn $defaultfn() -> $struct_name {
793 $struct_name { $($opt: $init),* }
796 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
798 let mut op = $defaultfn();
799 for option in matches.opt_strs($prefix) {
800 let mut iter = option.splitn(2, '=');
801 let key = iter.next().unwrap();
802 let value = iter.next();
803 let option_to_lookup = key.replace("-", "_");
804 let mut found = false;
805 for &(candidate, setter, opt_type_desc, _) in $stat {
806 if option_to_lookup != candidate { continue }
807 if !setter(&mut op, value) {
808 match (value, opt_type_desc) {
809 (Some(..), None) => {
810 early_error(error_format, &format!("{} option `{}` takes no \
811 value", $outputname, key))
813 (None, Some(type_desc)) => {
814 early_error(error_format, &format!("{0} option `{1}` requires \
815 {2} ({3} {1}=<value>)",
819 (Some(value), Some(type_desc)) => {
820 early_error(error_format, &format!("incorrect value `{}` for {} \
821 option `{}` - {} was expected",
825 (None, None) => panic!()
832 early_error(error_format, &format!("unknown {} option: `{}`",
839 impl dep_tracking::DepTrackingHash for $struct_name {
840 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
841 let mut sub_hashes = BTreeMap::new();
846 [$dep_tracking_marker $($dep_warn_val,
850 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
854 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
855 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
856 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
858 #[allow(non_upper_case_globals, dead_code)]
860 pub const parse_bool: Option<&str> = None;
861 pub const parse_opt_bool: Option<&str> =
862 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
863 pub const parse_string: Option<&str> = Some("a string");
864 pub const parse_string_push: Option<&str> = Some("a string");
865 pub const parse_pathbuf_push: Option<&str> = Some("a path");
866 pub const parse_opt_string: Option<&str> = Some("a string");
867 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
868 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
869 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
870 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
871 pub const parse_threads: Option<&str> = Some("a number");
872 pub const parse_uint: Option<&str> = Some("a number");
873 pub const parse_passes: Option<&str> =
874 Some("a space-separated list of passes, or `all`");
875 pub const parse_opt_uint: Option<&str> =
877 pub const parse_panic_strategy: Option<&str> =
878 Some("either `unwind` or `abort`");
879 pub const parse_relro_level: Option<&str> =
880 Some("one of: `full`, `partial`, or `off`");
881 pub const parse_sanitizer: Option<&str> =
882 Some("one of: `address`, `leak`, `memory` or `thread`");
883 pub const parse_sanitizer_list: Option<&str> =
884 Some("comma separated list of sanitizers");
885 pub const parse_sanitizer_memory_track_origins: Option<&str> = None;
886 pub const parse_linker_flavor: Option<&str> =
887 Some(::rustc_target::spec::LinkerFlavor::one_of());
888 pub const parse_optimization_fuel: Option<&str> =
889 Some("crate=integer");
890 pub const parse_unpretty: Option<&str> =
891 Some("`string` or `string=string`");
892 pub const parse_treat_err_as_bug: Option<&str> =
893 Some("either no value or a number bigger than 0");
894 pub const parse_lto: Option<&str> =
895 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
897 pub const parse_linker_plugin_lto: Option<&str> =
898 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
899 or the path to the linker plugin");
900 pub const parse_switch_with_opt_path: Option<&str> =
901 Some("an optional path to the profiling data output directory");
902 pub const parse_merge_functions: Option<&str> =
903 Some("one of: `disabled`, `trampolines`, or `aliases`");
904 pub const parse_symbol_mangling_version: Option<&str> =
905 Some("either `legacy` or `v0` (RFC 2603)");
910 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
911 SymbolManglingVersion};
912 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
913 use std::path::PathBuf;
914 use std::str::FromStr;
917 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
918 $parse(&mut cg.$opt, v)
922 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
925 None => { *slot = true; true }
929 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
933 "n" | "no" | "off" => {
936 "y" | "yes" | "on" => {
939 _ => { return false; }
944 None => { *slot = Some(true); true }
948 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
950 Some(s) => { *slot = Some(s.to_string()); true },
955 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
957 Some(s) => { *slot = Some(PathBuf::from(s)); true },
962 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
964 Some(s) => { *slot = s.to_string(); true },
969 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
971 Some(s) => { slot.push(s.to_string()); true },
976 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
978 Some(s) => { slot.push(PathBuf::from(s)); true },
983 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
987 slot.extend(s.split_whitespace().map(|s| s.to_string()));
994 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
998 let v = s.split_whitespace().map(|s| s.to_string()).collect();
1006 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
1010 let v = s.split(',').map(|s| s.to_string()).collect();
1018 fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
1019 match v.and_then(|s| s.parse().ok()) {
1020 Some(0) => { *slot = ::num_cpus::get(); true },
1021 Some(i) => { *slot = i; true },
1026 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
1027 match v.and_then(|s| s.parse().ok()) {
1028 Some(i) => { *slot = i; true },
1033 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1035 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
1036 None => { *slot = None; false }
1040 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
1043 *slot = Passes::All;
1047 let mut passes = vec![];
1048 if parse_list(&mut passes, v) {
1049 *slot = Passes::Some(passes);
1058 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
1060 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
1061 Some("abort") => *slot = Some(PanicStrategy::Abort),
1067 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1070 match s.parse::<RelroLevel>() {
1071 Ok(level) => *slot = Some(level),
1080 fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1081 if let Some(Ok(s)) = v.map(str::parse) {
1089 fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
1090 if let Some(v) = v {
1091 for s in v.split(',').map(str::parse) {
1093 if !slot.contains(&s) {
1106 fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
1107 match v.map(|s| s.parse()) {
1112 Some(Ok(i)) if i <= 2 => {
1122 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1123 match v.and_then(LinkerFlavor::from_str) {
1124 Some(lf) => *slote = Some(lf),
1130 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1134 let parts = s.split('=').collect::<Vec<_>>();
1135 if parts.len() != 2 { return false; }
1136 let crate_name = parts[0].to_string();
1137 let fuel = parts[1].parse::<u64>();
1138 if fuel.is_err() { return false; }
1139 *slot = Some((crate_name, fuel.unwrap()));
1145 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1148 Some(s) if s.split('=').count() <= 2 => {
1149 *slot = Some(s.to_string());
1156 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1158 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1159 None => { *slot = Some(1); true }
1163 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1165 let mut bool_arg = None;
1166 if parse_opt_bool(&mut bool_arg, v) {
1167 *slot = if bool_arg.unwrap() {
1177 None => LtoCli::NoParam,
1178 Some("thin") => LtoCli::Thin,
1179 Some("fat") => LtoCli::Fat,
1180 Some(_) => return false,
1185 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1187 let mut bool_arg = None;
1188 if parse_opt_bool(&mut bool_arg, v) {
1189 *slot = if bool_arg.unwrap() {
1190 LinkerPluginLto::LinkerPluginAuto
1192 LinkerPluginLto::Disabled
1199 None => LinkerPluginLto::LinkerPluginAuto,
1200 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1205 fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1207 None => SwitchWithOptPath::Enabled(None),
1208 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1213 fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1214 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1215 Some(mergefunc) => *slot = Some(mergefunc),
1221 fn parse_symbol_mangling_version(
1222 slot: &mut SymbolManglingVersion,
1226 Some("legacy") => SymbolManglingVersion::Legacy,
1227 Some("v0") => SymbolManglingVersion::V0,
1235 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1236 build_codegen_options, "C", "codegen",
1237 CG_OPTIONS, cg_type_desc, cgsetters,
1238 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1239 "this option is deprecated and does nothing"),
1240 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1241 "system linker to link outputs with"),
1242 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1243 "a single extra argument to append to the linker invocation (can be used several times)"),
1244 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1245 "extra arguments to append to the linker invocation (space separated)"),
1246 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1247 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1248 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1249 "perform LLVM link-time optimizations"),
1250 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1251 "select target processor (`rustc --print target-cpus` for details)"),
1252 target_feature: String = (String::new(), parse_string, [TRACKED],
1253 "target specific attributes. (`rustc --print target-features` for details). \
1254 This feature is unsafe."),
1255 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1256 "a list of extra LLVM passes to run (space separated)"),
1257 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1258 "a list of arguments to pass to LLVM (space separated)"),
1259 save_temps: bool = (false, parse_bool, [UNTRACKED],
1260 "save all temporary output files during compilation"),
1261 rpath: bool = (false, parse_bool, [UNTRACKED],
1262 "set rpath values in libs/exes"),
1263 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1264 "use overflow checks for integer arithmetic"),
1265 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1266 "don't pre-populate the pass manager with a list of passes"),
1267 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1268 "don't run the loop vectorization optimization passes"),
1269 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1270 "don't run LLVM's SLP vectorization pass"),
1271 soft_float: bool = (false, parse_bool, [TRACKED],
1272 "use soft float ABI (*eabihf targets only)"),
1273 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1274 "prefer dynamic linking to static linking"),
1275 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1276 "use an external assembler rather than LLVM's integrated one"),
1277 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1278 "disable the use of the redzone"),
1279 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1280 "choose the relocation model to use (`rustc --print relocation-models` for details)"),
1281 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1282 "choose the code model to use (`rustc --print code-models` for details)"),
1283 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1284 "metadata to mangle symbol names with"),
1285 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1286 "extra data to put in each output filename"),
1287 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1288 "divide crate into N units to optimize in parallel"),
1289 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1290 "print remarks for these optimization passes (space separated, or \"all\")"),
1291 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1292 "the `--no-stack-check` flag is deprecated and does nothing"),
1293 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1294 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1295 2 = full debug info with variable and type information"),
1296 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1297 "optimize with possible levels 0-3, s, or z"),
1298 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1299 "force use of the frame pointers"),
1300 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1301 "explicitly enable the `cfg(debug_assertions)` directive"),
1302 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1303 "set the threshold for inlining a function (default: 225)"),
1304 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1305 [TRACKED], "panic strategy to compile crate with"),
1306 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1307 "enable incremental compilation"),
1308 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1309 "allow the linker to link its default libraries"),
1310 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1312 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1313 parse_linker_plugin_lto, [TRACKED],
1314 "generate build artifacts that are compatible with linker-based LTO."),
1315 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1316 parse_switch_with_opt_path, [TRACKED],
1317 "compile the program with profiling instrumentation"),
1318 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1319 "use the given `.profdata` file for profile-guided optimization"),
1322 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1323 build_debugging_options, "Z", "debugging",
1324 DB_OPTIONS, db_type_desc, dbsetters,
1325 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1326 "the backend to use"),
1327 verbose: bool = (false, parse_bool, [UNTRACKED],
1328 "in general, enable more debug printouts"),
1329 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1330 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1331 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1332 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1333 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1334 "select which borrowck is used (`mir` or `migrate`)"),
1335 time_passes: bool = (false, parse_bool, [UNTRACKED],
1336 "measure time of each rustc pass"),
1337 time: bool = (false, parse_bool, [UNTRACKED],
1338 "measure time of rustc processes"),
1339 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1340 "measure time of each LLVM pass"),
1341 input_stats: bool = (false, parse_bool, [UNTRACKED],
1342 "gather statistics about the input"),
1343 asm_comments: bool = (false, parse_bool, [TRACKED],
1344 "generate comments into the assembly (may change behavior)"),
1345 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1347 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1348 "gather borrowck statistics"),
1349 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1350 "omit landing pads for unwinding"),
1351 fewer_names: bool = (false, parse_bool, [TRACKED],
1352 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1353 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1354 "gather metadata statistics"),
1355 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1356 "print the arguments passed to the linker"),
1357 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1358 "prints the LLVM optimization passes being run"),
1359 ast_json: bool = (false, parse_bool, [UNTRACKED],
1360 "print the AST as JSON and halt"),
1361 // We default to 1 here since we want to behave like
1362 // a sequential compiler for now. This'll likely be adjusted
1363 // in the future. Note that -Zthreads=0 is the way to get
1364 // the num_cpus behavior.
1365 threads: usize = (1, parse_threads, [UNTRACKED],
1366 "use a thread pool with N threads"),
1367 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1368 "print the pre-expansion AST as JSON and halt"),
1369 ls: bool = (false, parse_bool, [UNTRACKED],
1370 "list the symbols defined by a library crate"),
1371 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1372 "write syntax and type analysis (in JSON format) information, in \
1373 addition to normal output"),
1374 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1375 "prints region inference graph. \
1376 Use with RUST_REGION_GRAPH=help for more info"),
1377 parse_only: bool = (false, parse_bool, [UNTRACKED],
1378 "parse only; do not compile, assemble, or link"),
1379 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1380 "load proc macros for both target and host, but only link to the target"),
1381 no_codegen: bool = (false, parse_bool, [TRACKED],
1382 "run all passes except codegen; no output"),
1383 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1384 "treat error number `val` that occurs as bug"),
1385 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1386 "immediately print bugs registered with `delay_span_bug`"),
1387 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1388 "show macro backtraces even for non-local macros"),
1389 teach: bool = (false, parse_bool, [TRACKED],
1390 "show extended diagnostic help"),
1391 terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1392 "set the current terminal width"),
1393 panic_abort_tests: bool = (false, parse_bool, [TRACKED],
1394 "support compiling tests with panic=abort"),
1395 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1396 "attempt to recover from parse errors (experimental)"),
1397 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1398 "print tasks that execute and the color their dep node gets (requires debug build)"),
1399 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1400 "enable incremental compilation (experimental)"),
1401 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1402 "enable incremental compilation support for queries (experimental)"),
1403 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1404 "print high-level information about incremental reuse (or the lack thereof)"),
1405 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1406 "dump hash information in textual format to stdout"),
1407 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1408 "verify incr. comp. hashes of green query instances"),
1409 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1410 "ignore spans during ICH computation -- used for testing"),
1411 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1412 "insert function instrument code for mcount-based tracing"),
1413 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1414 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1415 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1416 "enable queries of the dependency graph for regression testing"),
1417 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1418 "parse and expand the source, but run no analysis"),
1419 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1420 "adds unstable command line options to rustc interface"),
1421 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1422 "force overflow checks on or off"),
1423 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1424 "for every macro invocation, print its name and arguments"),
1425 debug_macros: bool = (false, parse_bool, [TRACKED],
1426 "emit line numbers debug info inside macros"),
1427 generate_arange_section: bool = (true, parse_bool, [TRACKED],
1428 "generate DWARF address ranges for faster lookups"),
1429 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1430 "don't clear the hygiene data after analysis"),
1431 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1432 "keep the AST after lowering it to HIR"),
1433 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1434 "show spans for compiler debugging (expr|pat|ty)"),
1435 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1436 "print layout information for each type encountered"),
1437 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1438 "print the result of the monomorphization collection pass"),
1439 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1440 "set the MIR optimization level (0-3, default: 1)"),
1441 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1442 "emit noalias metadata for mutable references (default: no)"),
1443 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1444 "dump MIR state to file.
1445 `val` is used to select which passes and functions to dump. For example:
1446 `all` matches all passes and functions,
1447 `foo` matches all passes for functions whose name contains 'foo',
1448 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1449 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1451 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1452 "the directory the MIR is dumped into"),
1453 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1454 "in addition to `.mir` files, create graphviz `.dot` files"),
1455 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1456 "if set, exclude the pass number when dumping MIR (used in tests)"),
1457 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1458 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1459 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1460 "print some performance-related statistics"),
1461 query_stats: bool = (false, parse_bool, [UNTRACKED],
1462 "print some statistics about the query system"),
1463 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1464 "print some statistics about AST and HIR"),
1465 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1466 "encode MIR of all functions into the crate metadata"),
1467 json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1468 "describes how to render the `rendered` field of json diagnostics"),
1469 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1470 "take the breaks off const evaluation. NOTE: this is unsound"),
1471 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1472 "pass `-install_name @rpath/...` to the macOS linker"),
1473 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1475 sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
1476 "Enable recovery for selected sanitizers"),
1477 sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
1478 "Enable origins tracking in MemorySanitizer"),
1479 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1480 "set the optimization fuel quota for a crate"),
1481 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1482 "make rustc print the total optimization fuel used by a crate"),
1483 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1484 "force all crates to be `rustc_private` unstable"),
1485 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1486 "a single extra argument to prepend the linker invocation (can be used several times)"),
1487 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1488 "extra arguments to prepend to the linker invocation (space separated)"),
1489 profile: bool = (false, parse_bool, [TRACKED],
1490 "insert profiling code"),
1491 disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1492 "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1493 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1494 "choose which RELRO level to use"),
1495 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1496 "dump facts from NLL analysis into side files"),
1497 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1498 "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1499 dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1500 "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1501 polonius: bool = (false, parse_bool, [UNTRACKED],
1502 "enable polonius-based borrow-checker"),
1503 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1504 "generate a graphical HTML report of time spent in codegen and LLVM"),
1505 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1506 "enable ThinLTO when possible"),
1507 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1508 "control whether `#[inline]` functions are in all CGUs"),
1509 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1510 "choose the TLS model to use (`rustc --print tls-models` for details)"),
1511 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1512 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1513 the max/min integer respectively, and NaN is mapped to 0"),
1514 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1515 "generate human-readable, predictable names for codegen units"),
1516 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1517 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1519 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1520 "present the input source, unstable (and less-pretty) variants;
1521 valid types are any of the types for `--pretty`, as well as:
1522 `expanded`, `expanded,identified`,
1523 `expanded,hygiene` (with internal representations),
1524 `everybody_loops` (all function bodies replaced with `loop {}`),
1525 `hir` (the HIR), `hir,identified`,
1526 `hir,typed` (HIR with types for each node),
1527 `hir-tree` (dump the raw HIR),
1528 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1529 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1530 "run `dsymutil` and delete intermediate object files"),
1531 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1532 "format compiler diagnostics in a way that's better suitable for UI testing"),
1533 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1534 "embed LLVM bitcode in object files"),
1535 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1536 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1537 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1538 "make the current crate share its generic instantiations"),
1539 chalk: bool = (false, parse_bool, [TRACKED],
1540 "enable the experimental Chalk-based trait solving engine"),
1541 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1542 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1543 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1544 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1545 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1546 "don't interleave execution of lints; allows benchmarking individual lints"),
1547 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1548 "inject the given attribute in the crate"),
1549 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1550 parse_switch_with_opt_path, [UNTRACKED],
1551 "run the self profiler and output the raw event data"),
1552 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1553 "specifies which kinds of events get recorded by the self profiler"),
1554 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1555 "emits a section containing stack size metadata"),
1556 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1557 "whether to use the PLT when calling into shared libraries;
1558 only has effect for PIC code on systems with ELF binaries
1559 (default: PLT is disabled if full relro is enabled)"),
1560 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1561 "control the operation of the MergeFunctions LLVM pass, taking
1562 the same values as the target option of the same name"),
1563 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1564 "only allow the listed language features to be enabled in code (space separated)"),
1565 symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1566 parse_symbol_mangling_version, [TRACKED],
1567 "which mangling version to use for symbol names"),
1568 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
1569 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
1570 insert_sideeffect: bool = (false, parse_bool, [TRACKED],
1571 "fix undefined behavior when a thread doesn't eventually make progress \
1572 (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
1575 pub const fn default_lib_output() -> CrateType {
1579 pub fn default_configuration(sess: &Session) -> CrateConfig {
1580 let end = &sess.target.target.target_endian;
1581 let arch = &sess.target.target.arch;
1582 let wordsz = &sess.target.target.target_pointer_width;
1583 let os = &sess.target.target.target_os;
1584 let env = &sess.target.target.target_env;
1585 let vendor = &sess.target.target.target_vendor;
1586 let min_atomic_width = sess.target.target.min_atomic_width();
1587 let max_atomic_width = sess.target.target.max_atomic_width();
1588 let atomic_cas = sess.target.target.options.atomic_cas;
1590 let mut ret = FxHashSet::default();
1591 ret.reserve(6); // the minimum number of insertions
1593 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1594 if let Some(ref fam) = sess.target.target.options.target_family {
1595 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1596 if fam == "windows" || fam == "unix" {
1597 ret.insert((Symbol::intern(fam), None));
1600 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1601 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1603 Symbol::intern("target_pointer_width"),
1604 Some(Symbol::intern(wordsz)),
1606 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1608 Symbol::intern("target_vendor"),
1609 Some(Symbol::intern(vendor)),
1611 if sess.target.target.options.has_elf_tls {
1612 ret.insert((sym::target_thread_local, None));
1614 for &i in &[8, 16, 32, 64, 128] {
1615 if i >= min_atomic_width && i <= max_atomic_width {
1616 let mut insert_atomic = |s| {
1618 sym::target_has_atomic_load_store,
1619 Some(Symbol::intern(s)),
1623 sym::target_has_atomic,
1624 Some(Symbol::intern(s))
1628 let s = i.to_string();
1631 insert_atomic("ptr");
1635 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
1636 let symbol = Symbol::intern(&s.to_string());
1637 ret.insert((sym::sanitize, Some(symbol)));
1639 if sess.opts.debug_assertions {
1640 ret.insert((Symbol::intern("debug_assertions"), None));
1642 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1643 ret.insert((sym::proc_macro, None));
1648 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1649 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1650 /// but the symbol interner is not yet set up then, so we must convert it later.
1651 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
1653 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1657 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1658 // Combine the configuration requested by the session (command line) with
1659 // some default and generated configuration items.
1660 let default_cfg = default_configuration(sess);
1661 // If the user wants a test runner, then add the test cfg.
1663 user_cfg.insert((sym::test, None));
1665 user_cfg.extend(default_cfg.iter().cloned());
1669 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1670 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1671 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1672 .help("Use `--print target-list` for a list of built-in targets")
1677 let ptr_width = match &target.target_pointer_width[..] {
1681 w => sp.fatal(&format!(
1682 "target specification was invalid: \
1683 unrecognized target-pointer-width {}",
1694 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1695 pub enum OptionStability {
1700 pub struct RustcOptGroup {
1701 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1702 pub name: &'static str,
1703 pub stability: OptionStability,
1706 impl RustcOptGroup {
1707 pub fn is_stable(&self) -> bool {
1708 self.stability == OptionStability::Stable
1711 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1713 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1718 stability: OptionStability::Stable,
1722 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1724 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1729 stability: OptionStability::Unstable,
1734 // The `opt` local module holds wrappers around the `getopts` API that
1735 // adds extra rustc-specific metadata to each option; such metadata
1736 // is exposed by . The public
1737 // functions below ending with `_u` are the functions that return
1738 // *unstable* options, i.e., options that are only enabled when the
1739 // user also passes the `-Z unstable-options` debugging flag.
1741 // The `fn flag*` etc below are written so that we can use them
1742 // in the future; do not warn about them not being used right now.
1743 #![allow(dead_code)]
1746 use super::RustcOptGroup;
1748 pub type R = RustcOptGroup;
1749 pub type S = &'static str;
1751 fn stable<F>(name: S, f: F) -> R
1753 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1755 RustcOptGroup::stable(name, f)
1758 fn unstable<F>(name: S, f: F) -> R
1760 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1762 RustcOptGroup::unstable(name, f)
1765 fn longer(a: S, b: S) -> S {
1766 if a.len() > b.len() {
1773 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1774 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1776 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1777 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1779 pub fn flag_s(a: S, b: S, c: S) -> R {
1780 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1782 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1783 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1785 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1786 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1789 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1790 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1792 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1793 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1795 pub fn flag(a: S, b: S, c: S) -> R {
1796 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1798 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1799 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1801 pub fn flagmulti(a: S, b: S, c: S) -> R {
1802 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1806 /// Returns the "short" subset of the rustc command line options,
1807 /// including metadata for each option, such as whether the option is
1808 /// part of the stable long-term interface for rustc.
1809 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1811 opt::flag_s("h", "help", "Display this message"),
1812 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1816 "Add a directory to the library search path. The
1817 optional KIND can be one of dependency, crate, native,
1818 framework, or all (the default).",
1824 "Link the generated crate(s) to the specified native
1825 library NAME. The optional KIND can be one of
1826 static, framework, or dylib (the default).",
1829 make_crate_type_option(),
1833 "Specify the name of the crate being built",
1839 "Specify which edition of the compiler to use when compiling code.",
1845 "Comma separated list of types of output for \
1846 the compiler to emit",
1847 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1852 "Compiler information to print on stdout",
1853 "[crate-name|file-names|sysroot|cfg|target-list|\
1854 target-cpus|target-features|relocation-models|\
1855 code-models|tls-models|target-spec-json|native-static-libs]",
1857 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1858 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1859 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1863 "Write output to compiler-chosen filename \
1870 "Provide a detailed explanation of an error \
1874 opt::flag_s("", "test", "Build a test harness"),
1878 "Target triple for which the code is compiled",
1881 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1882 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1883 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1884 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1888 "Set the most restrictive lint level. \
1889 More restrictive lints are capped at this \
1893 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1894 opt::flag_s("V", "version", "Print version info and exit"),
1895 opt::flag_s("v", "verbose", "Use verbose output"),
1899 /// Returns all rustc command line options, including metadata for
1900 /// each option, such as whether the option is part of the stable
1901 /// long-term interface for rustc.
1902 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1903 let mut opts = rustc_short_optgroups();
1908 "Specify where an external rust library is located",
1911 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1912 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1916 "How errors and other messages are produced",
1922 "Configure the JSON output of the compiler",
1928 "Configure coloring of output:
1929 auto = colorize, if output goes to a tty (default);
1930 always = always colorize output;
1931 never = never colorize output",
1932 "auto|always|never",
1937 "Pretty-print the input instead of compiling;
1938 valid types are: `normal` (un-annotated source),
1939 `expanded` (crates expanded), or
1940 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1945 "remap-path-prefix",
1946 "Remap source names in all output (compiler messages and output files)",
1953 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1954 error_format: ErrorOutputType)
1955 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1956 let mut lint_opts = vec![];
1957 let mut describe_lints = false;
1959 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1960 for lint_name in matches.opt_strs(level.as_str()) {
1961 if lint_name == "help" {
1962 describe_lints = true;
1964 lint_opts.push((lint_name.replace("-", "_"), level));
1969 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1970 lint::Level::from_str(&cap)
1971 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1973 (lint_opts, describe_lints, lint_cap)
1976 /// Parses the `--color` flag.
1977 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1978 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1979 Some("auto") => ColorConfig::Auto,
1980 Some("always") => ColorConfig::Always,
1981 Some("never") => ColorConfig::Never,
1983 None => ColorConfig::Auto,
1985 Some(arg) => early_error(
1986 ErrorOutputType::default(),
1988 "argument for `--color` must be auto, \
1989 always or never (instead was `{}`)",
1996 /// Parse the `--json` flag.
1998 /// The first value returned is how to render JSON diagnostics, and the second
1999 /// is whether or not artifact notifications are enabled.
2000 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
2001 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
2002 HumanReadableErrorType::Default;
2003 let mut json_color = ColorConfig::Never;
2004 let mut json_artifact_notifications = false;
2005 for option in matches.opt_strs("json") {
2006 // For now conservatively forbid `--color` with `--json` since `--json`
2007 // won't actually be emitting any colors and anything colorized is
2008 // embedded in a diagnostic message anyway.
2009 if matches.opt_str("color").is_some() {
2011 ErrorOutputType::default(),
2012 "cannot specify the `--color` option with `--json`",
2016 for sub_option in option.split(',') {
2018 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
2019 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
2020 "artifacts" => json_artifact_notifications = true,
2023 ErrorOutputType::default(),
2024 &format!("unknown `--json` option `{}`", s),
2030 (json_rendered(json_color), json_artifact_notifications)
2033 /// Parses the `--error-format` flag.
2034 pub fn parse_error_format(
2035 matches: &getopts::Matches,
2037 json_rendered: HumanReadableErrorType,
2038 ) -> ErrorOutputType {
2039 // We need the `opts_present` check because the driver will send us Matches
2040 // with only stable options if no unstable options are used. Since error-format
2041 // is unstable, it will not be present. We have to use `opts_present` not
2042 // `opt_present` because the latter will panic.
2043 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
2044 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
2046 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2047 Some("human-annotate-rs") => {
2048 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
2050 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
2051 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
2052 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
2054 Some(arg) => early_error(
2055 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2057 "argument for `--error-format` must be `human`, `json` or \
2058 `short` (instead was `{}`)",
2064 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
2067 match error_format {
2068 ErrorOutputType::Json { .. } => {}
2070 // Conservatively require that the `--json` argument is coupled with
2071 // `--error-format=json`. This means that `--json` is specified we
2072 // should actually be emitting JSON blobs.
2073 _ if matches.opt_strs("json").len() > 0 => {
2075 ErrorOutputType::default(),
2076 "using `--json` requires also using `--error-format=json`",
2083 return error_format;
2086 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
2087 let edition = match matches.opt_str("edition") {
2088 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
2090 ErrorOutputType::default(),
2092 "argument for `--edition` must be one of: \
2093 {}. (instead was `{}`)",
2099 None => DEFAULT_EDITION,
2102 if !edition.is_stable() && !nightly_options::is_nightly_build() {
2104 ErrorOutputType::default(),
2106 "edition {} is unstable and only \
2107 available for nightly builds of rustc.",
2116 fn check_debug_option_stability(
2117 debugging_opts: &DebuggingOptions,
2118 error_format: ErrorOutputType,
2119 json_rendered: HumanReadableErrorType,
2121 if !debugging_opts.unstable_options {
2122 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2124 ErrorOutputType::Json { pretty: false, json_rendered },
2125 "`--error-format=pretty-json` is unstable",
2128 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
2131 ErrorOutputType::Json { pretty: false, json_rendered },
2132 "`--error-format=human-annotate-rs` is unstable",
2138 fn parse_output_types(
2139 debugging_opts: &DebuggingOptions,
2140 matches: &getopts::Matches,
2141 error_format: ErrorOutputType,
2143 let mut output_types = BTreeMap::new();
2144 if !debugging_opts.parse_only {
2145 for list in matches.opt_strs("emit") {
2146 for output_type in list.split(',') {
2147 let mut parts = output_type.splitn(2, '=');
2148 let shorthand = parts.next().unwrap();
2149 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2153 "unknown emission type: `{}` - expected one of: {}",
2155 OutputType::shorthands_display(),
2159 let path = parts.next().map(PathBuf::from);
2160 output_types.insert(output_type, path);
2164 if output_types.is_empty() {
2165 output_types.insert(OutputType::Exe, None);
2167 OutputTypes(output_types)
2170 fn should_override_cgus_and_disable_thinlto(
2171 output_types: &OutputTypes,
2172 matches: &getopts::Matches,
2173 error_format: ErrorOutputType,
2174 mut codegen_units: Option<usize>,
2175 ) -> (bool, Option<usize>) {
2176 let mut disable_thinlto = false;
2177 // Issue #30063: if user requests LLVM-related output to one
2178 // particular path, disable codegen-units.
2179 let incompatible: Vec<_> = output_types.0
2181 .map(|ot_path| ot_path.0)
2182 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2183 .map(|ot| ot.shorthand())
2185 if !incompatible.is_empty() {
2186 match codegen_units {
2187 Some(n) if n > 1 => {
2188 if matches.opt_present("o") {
2189 for ot in &incompatible {
2193 "`--emit={}` with `-o` incompatible with \
2194 `-C codegen-units=N` for N > 1",
2199 early_warn(error_format, "resetting to default -C codegen-units=1");
2200 codegen_units = Some(1);
2201 disable_thinlto = true;
2205 codegen_units = Some(1);
2206 disable_thinlto = true;
2211 if codegen_units == Some(0) {
2214 "value for codegen units must be a positive non-zero integer",
2218 (disable_thinlto, codegen_units)
2221 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
2222 if debugging_opts.threads == 0 {
2225 "value for threads must be a positive non-zero integer",
2229 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
2232 "optimization fuel is incompatible with multiple threads",
2237 fn select_incremental_path(
2238 debugging_opts: &DebuggingOptions,
2239 cg: &CodegenOptions,
2240 error_format: ErrorOutputType,
2241 ) -> Option<PathBuf> {
2242 match (&debugging_opts.incremental, &cg.incremental) {
2243 (Some(path1), Some(path2)) => {
2248 "conflicting paths for `-Z incremental` and \
2249 `-C incremental` specified: {} versus {}",
2257 (Some(path), None) => Some(path),
2258 (None, Some(path)) => Some(path),
2259 (None, None) => None,
2260 }.map(|m| PathBuf::from(m))
2263 fn collect_print_requests(
2264 cg: &mut CodegenOptions,
2265 dopts: &mut DebuggingOptions,
2266 matches: &getopts::Matches,
2267 error_format: ErrorOutputType,
2268 ) -> Vec<PrintRequest> {
2269 let mut prints = Vec::<PrintRequest>::new();
2270 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2271 prints.push(PrintRequest::TargetCPUs);
2272 cg.target_cpu = None;
2274 if cg.target_feature == "help" {
2275 prints.push(PrintRequest::TargetFeatures);
2276 cg.target_feature = String::new();
2278 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2279 prints.push(PrintRequest::RelocationModels);
2280 cg.relocation_model = None;
2282 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2283 prints.push(PrintRequest::CodeModels);
2284 cg.code_model = None;
2289 .map_or(false, |s| s == "help")
2291 prints.push(PrintRequest::TlsModels);
2292 dopts.tls_model = None;
2295 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2296 "crate-name" => PrintRequest::CrateName,
2297 "file-names" => PrintRequest::FileNames,
2298 "sysroot" => PrintRequest::Sysroot,
2299 "cfg" => PrintRequest::Cfg,
2300 "target-list" => PrintRequest::TargetList,
2301 "target-cpus" => PrintRequest::TargetCPUs,
2302 "target-features" => PrintRequest::TargetFeatures,
2303 "relocation-models" => PrintRequest::RelocationModels,
2304 "code-models" => PrintRequest::CodeModels,
2305 "tls-models" => PrintRequest::TlsModels,
2306 "native-static-libs" => PrintRequest::NativeStaticLibs,
2307 "target-spec-json" => {
2308 if dopts.unstable_options {
2309 PrintRequest::TargetSpec
2313 "the `-Z unstable-options` flag must also be passed to \
2314 enable the target-spec-json print option",
2318 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2324 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
2325 match matches.opt_str("target") {
2326 Some(target) if target.ends_with(".json") => {
2327 let path = Path::new(&target);
2328 TargetTriple::from_path(&path).unwrap_or_else(|_|
2329 early_error(error_format, &format!("target file {:?} does not exist", path)))
2331 Some(target) => TargetTriple::TargetTriple(target),
2332 _ => TargetTriple::from_triple(host_triple()),
2337 matches: &getopts::Matches,
2338 cg: &CodegenOptions,
2339 error_format: ErrorOutputType,
2341 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2342 // to use them interchangeably. However, because they're technically different flags,
2343 // we need to work out manually which should take precedence if both are supplied (i.e.
2344 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2345 // comparing them. Note that if a flag is not found, its position will be `None`, which
2346 // always compared less than `Some(_)`.
2347 let max_o = matches.opt_positions("O").into_iter().max();
2348 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2349 if let Some("opt-level") = s.splitn(2, '=').next() {
2358 match cg.opt_level.as_ref().map(String::as_ref) {
2359 None => OptLevel::No,
2360 Some("0") => OptLevel::No,
2361 Some("1") => OptLevel::Less,
2362 Some("2") => OptLevel::Default,
2363 Some("3") => OptLevel::Aggressive,
2364 Some("s") => OptLevel::Size,
2365 Some("z") => OptLevel::SizeMin,
2370 "optimization level needs to be \
2371 between 0-3, s or z (instead was `{}`)",
2380 fn select_debuginfo(
2381 matches: &getopts::Matches,
2382 cg: &CodegenOptions,
2383 error_format: ErrorOutputType,
2385 let max_g = matches.opt_positions("g").into_iter().max();
2386 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2387 if let Some("debuginfo") = s.splitn(2, '=').next() {
2396 match cg.debuginfo {
2397 None | Some(0) => DebugInfo::None,
2398 Some(1) => DebugInfo::Limited,
2399 Some(2) => DebugInfo::Full,
2404 "debug info level needs to be between \
2405 0-2 (instead was `{}`)",
2415 matches: &getopts::Matches,
2416 error_format: ErrorOutputType,
2417 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
2422 // Parse string of the form "[KIND=]lib[:new_name]",
2423 // where KIND is one of "dylib", "framework", "static".
2424 let mut parts = s.splitn(2, '=');
2425 let kind = parts.next().unwrap();
2426 let (name, kind) = match (parts.next(), kind) {
2427 (None, name) => (name, None),
2428 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
2429 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
2430 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
2431 (Some(name), "static-nobundle") => {
2432 (name, Some(NativeLibraryKind::NativeStaticNobundle))
2438 "unknown library kind `{}`, expected \
2439 one of dylib, framework, or static",
2445 if kind == Some(NativeLibraryKind::NativeStaticNobundle) &&
2446 !nightly_options::is_nightly_build() {
2450 "the library kind 'static-nobundle' is only \
2451 accepted on the nightly compiler"
2455 let mut name_parts = name.splitn(2, ':');
2456 let name = name_parts.next().unwrap();
2457 let new_name = name_parts.next();
2458 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2463 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2464 match dopts.borrowck.as_ref().map(|s| &s[..]) {
2465 None | Some("migrate") => BorrowckMode::Migrate,
2466 Some("mir") => BorrowckMode::Mir,
2467 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2471 pub fn parse_externs(
2472 matches: &getopts::Matches,
2473 debugging_opts: &DebuggingOptions,
2474 error_format: ErrorOutputType,
2476 let is_unstable_enabled = debugging_opts.unstable_options;
2477 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2478 for arg in matches.opt_strs("extern") {
2479 let mut parts = arg.splitn(2, '=');
2482 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
2483 let path = parts.next().map(|s| s.to_string());
2485 let mut name_parts = name.splitn(2, ':');
2486 let first_part = name_parts.next();
2487 let second_part = name_parts.next();
2488 let (options, name) = match (first_part, second_part) {
2489 (Some(opts), Some(name)) => (Some(opts), name),
2490 (Some(name), None) => (None, name),
2491 (None, None) => early_error(error_format, "--extern name must not be empty"),
2492 _ => unreachable!(),
2495 let entry = externs.entry(name.to_owned());
2497 use std::collections::btree_map::Entry;
2499 let entry = if let Some(path) = path {
2500 // --extern prelude_name=some_file.rlib
2502 Entry::Vacant(vacant) => {
2503 let files = BTreeSet::from_iter(iter::once(path));
2504 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2506 Entry::Occupied(occupied) => {
2507 let ext_ent = occupied.into_mut();
2509 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2513 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2516 // Exact paths take precedence over search directories.
2517 let files = BTreeSet::from_iter(iter::once(path));
2518 *location = ExternLocation::ExactPaths(files);
2525 // --extern prelude_name
2527 Entry::Vacant(vacant) => {
2528 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2530 Entry::Occupied(occupied) => {
2531 // Ignore if already specified.
2537 let mut is_private_dep = false;
2538 let mut add_prelude = true;
2539 if let Some(opts) = options {
2540 if !is_unstable_enabled {
2543 "the `-Z unstable-options` flag must also be passed to \
2544 enable `--extern options",
2547 for opt in opts.split(',') {
2549 "priv" => is_private_dep = true,
2551 if let ExternLocation::ExactPaths(_) = &entry.location {
2552 add_prelude = false;
2556 "the `noprelude` --extern option requires a file path",
2560 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
2565 // Crates start out being not private, and go to being private `priv`
2567 entry.is_private_dep |= is_private_dep;
2568 // If any flag is missing `noprelude`, then add to the prelude.
2569 entry.add_prelude |= add_prelude;
2574 fn parse_remap_path_prefix(
2575 matches: &getopts::Matches,
2576 error_format: ErrorOutputType
2577 ) -> Vec<(PathBuf, PathBuf)> {
2579 .opt_strs("remap-path-prefix")
2582 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2583 let to = parts.next();
2584 let from = parts.next();
2586 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2589 "--remap-path-prefix must contain '=' between FROM and TO",
2596 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2597 let color = parse_color(matches);
2599 let edition = parse_crate_edition(matches);
2601 let (json_rendered, json_artifact_notifications) = parse_json(matches);
2603 let error_format = parse_error_format(matches, color, json_rendered);
2605 let unparsed_crate_types = matches.opt_strs("crate-type");
2606 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2607 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2609 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2611 let mut debugging_opts = build_debugging_options(matches, error_format);
2612 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2614 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2616 let mut cg = build_codegen_options(matches, error_format);
2617 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2624 check_thread_count(&debugging_opts, error_format);
2626 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
2628 if debugging_opts.profile && incremental.is_some() {
2631 "can't instrument with gcov profiling when compiling incrementally",
2635 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2638 "options `-C profile-generate` and `-C profile-use` are exclusive",
2642 let prints = collect_print_requests(
2644 &mut debugging_opts,
2651 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2652 let target_triple = parse_target_triple(matches, error_format);
2653 let opt_level = parse_opt_level(matches, &cg, error_format);
2654 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2655 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2656 // for more details.
2657 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2658 let debuginfo = select_debuginfo(matches, &cg, error_format);
2660 let mut search_paths = vec![];
2661 for s in &matches.opt_strs("L") {
2662 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2665 let libs = parse_libs(matches, error_format);
2667 let test = matches.opt_present("test");
2669 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2671 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2674 "-C remark requires \"-C debuginfo=n\" to show source locations",
2678 let externs = parse_externs(matches, &debugging_opts, error_format);
2680 let crate_name = matches.opt_str("crate-name");
2682 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2684 let pretty = parse_pretty(matches, &debugging_opts, error_format);
2688 optimize: opt_level,
2695 maybe_sysroot: sysroot_opt,
2708 unstable_features: UnstableFeatures::from_environment(),
2710 actually_rustdoc: false,
2711 cli_forced_codegen_units: codegen_units,
2712 cli_forced_thinlto_off: disable_thinlto,
2715 json_artifact_notifications,
2721 matches: &getopts::Matches,
2722 debugging_opts: &DebuggingOptions,
2723 efmt: ErrorOutputType,
2724 ) -> Option<PpMode> {
2725 let pretty = if debugging_opts.unstable_options {
2726 matches.opt_default("pretty", "normal").map(|a| {
2727 // stable pretty-print variants only
2728 parse_pretty_inner(efmt, &a, false)
2734 return if pretty.is_none() {
2735 debugging_opts.unpretty.as_ref().map(|a| {
2736 // extended with unstable pretty-print variants
2737 parse_pretty_inner(efmt, &a, true)
2743 fn parse_pretty_inner(
2744 efmt: ErrorOutputType,
2749 use PpSourceMode::*;
2750 let first = match (name, extended) {
2751 ("normal", _) => PpmSource(PpmNormal),
2752 ("identified", _) => PpmSource(PpmIdentified),
2753 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
2754 ("expanded", _) => PpmSource(PpmExpanded),
2755 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
2756 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
2757 ("hir", true) => PpmHir(PpmNormal),
2758 ("hir,identified", true) => PpmHir(PpmIdentified),
2759 ("hir,typed", true) => PpmHir(PpmTyped),
2760 ("hir-tree", true) => PpmHirTree(PpmNormal),
2761 ("mir", true) => PpmMir,
2762 ("mir-cfg", true) => PpmMirCFG,
2765 early_error(efmt, &format!("argument to `unpretty` must be one of `normal`, \
2766 `expanded`, `identified`, `expanded,identified`, \
2767 `expanded,hygiene`, `everybody_loops`, \
2768 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
2769 `mir` or `mir-cfg`; got {}",
2772 early_error(efmt, &format!("argument to `pretty` must be one of `normal`, \
2773 `expanded`, `identified`, or `expanded,identified`; got {}",
2782 pub fn make_crate_type_option() -> RustcOptGroup {
2786 "Comma separated list of types of crates
2787 for the compiler to emit",
2788 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2792 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2793 let mut crate_types: Vec<CrateType> = Vec::new();
2794 for unparsed_crate_type in &list_list {
2795 for part in unparsed_crate_type.split(',') {
2796 let new_part = match part {
2797 "lib" => default_lib_output(),
2798 "rlib" => CrateType::Rlib,
2799 "staticlib" => CrateType::Staticlib,
2800 "dylib" => CrateType::Dylib,
2801 "cdylib" => CrateType::Cdylib,
2802 "bin" => CrateType::Executable,
2803 "proc-macro" => CrateType::ProcMacro,
2804 _ => return Err(format!("unknown crate type: `{}`", part))
2806 if !crate_types.contains(&new_part) {
2807 crate_types.push(new_part)
2815 pub mod nightly_options {
2817 use rustc_feature::UnstableFeatures;
2818 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2819 use crate::early_error;
2821 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2826 .any(|x| *x == "unstable-options")
2829 pub fn is_nightly_build() -> bool {
2830 UnstableFeatures::from_environment().is_nightly_build()
2833 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2834 let has_z_unstable_option = matches
2837 .any(|x| *x == "unstable-options");
2838 let really_allows_unstable_options =
2839 UnstableFeatures::from_environment().is_nightly_build();
2841 for opt in flags.iter() {
2842 if opt.stability == OptionStability::Stable {
2845 if !matches.opt_present(opt.name) {
2848 if opt.name != "Z" && !has_z_unstable_option {
2850 ErrorOutputType::default(),
2852 "the `-Z unstable-options` flag must also be passed to enable \
2858 if really_allows_unstable_options {
2861 match opt.stability {
2862 OptionStability::Unstable => {
2864 "the option `{}` is only accepted on the \
2868 early_error(ErrorOutputType::default(), &msg);
2870 OptionStability::Stable => {}
2876 impl fmt::Display for CrateType {
2877 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2879 CrateType::Executable => "bin".fmt(f),
2880 CrateType::Dylib => "dylib".fmt(f),
2881 CrateType::Rlib => "rlib".fmt(f),
2882 CrateType::Staticlib => "staticlib".fmt(f),
2883 CrateType::Cdylib => "cdylib".fmt(f),
2884 CrateType::ProcMacro => "proc-macro".fmt(f),
2889 #[derive(Copy, Clone, PartialEq, Debug)]
2890 pub enum PpSourceMode {
2895 PpmExpandedIdentified,
2900 #[derive(Copy, Clone, PartialEq, Debug)]
2902 PpmSource(PpSourceMode),
2903 PpmHir(PpSourceMode),
2904 PpmHirTree(PpSourceMode),
2910 pub fn needs_ast_map(&self) -> bool {
2912 use PpSourceMode::*;
2914 PpmSource(PpmNormal) |
2915 PpmSource(PpmEveryBodyLoops) |
2916 PpmSource(PpmIdentified) => false,
2918 PpmSource(PpmExpanded) |
2919 PpmSource(PpmExpandedIdentified) |
2920 PpmSource(PpmExpandedHygiene) |
2925 PpmSource(PpmTyped) => panic!("invalid state"),
2929 pub fn needs_analysis(&self) -> bool {
2932 PpmMir | PpmMirCFG => true,
2938 /// Command-line arguments passed to the compiler have to be incorporated with
2939 /// the dependency tracking system for incremental compilation. This module
2940 /// provides some utilities to make this more convenient.
2942 /// The values of all command-line arguments that are relevant for dependency
2943 /// tracking are hashed into a single value that determines whether the
2944 /// incremental compilation cache can be re-used or not. This hashing is done
2945 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2946 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2947 /// the hash of which is order dependent, but we might not want the order of
2948 /// arguments to make a difference for the hash).
2950 /// However, since the value provided by `Hash::hash` often *is* suitable,
2951 /// especially for primitive types, there is the
2952 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2953 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2954 /// we have an opt-in scheme here, so one is hopefully forced to think about
2955 /// how the hash should be calculated when adding a new command-line argument.
2958 use crate::utils::NativeLibraryKind;
2959 use std::collections::BTreeMap;
2960 use std::hash::Hash;
2961 use std::path::PathBuf;
2962 use std::collections::hash_map::DefaultHasher;
2963 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2964 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2965 SymbolManglingVersion};
2966 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2967 use syntax_pos::edition::Edition;
2968 use rustc_feature::UnstableFeatures;
2970 pub trait DepTrackingHash {
2971 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2974 macro_rules! impl_dep_tracking_hash_via_hash {
2976 impl DepTrackingHash for $t {
2977 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2978 Hash::hash(self, hasher);
2984 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2986 impl DepTrackingHash for Vec<$t> {
2987 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2988 let mut elems: Vec<&$t> = self.iter().collect();
2990 Hash::hash(&elems.len(), hasher);
2991 for (index, elem) in elems.iter().enumerate() {
2992 Hash::hash(&index, hasher);
2993 DepTrackingHash::hash(*elem, hasher, error_format);
3000 impl_dep_tracking_hash_via_hash!(bool);
3001 impl_dep_tracking_hash_via_hash!(usize);
3002 impl_dep_tracking_hash_via_hash!(u64);
3003 impl_dep_tracking_hash_via_hash!(String);
3004 impl_dep_tracking_hash_via_hash!(PathBuf);
3005 impl_dep_tracking_hash_via_hash!(lint::Level);
3006 impl_dep_tracking_hash_via_hash!(Option<bool>);
3007 impl_dep_tracking_hash_via_hash!(Option<usize>);
3008 impl_dep_tracking_hash_via_hash!(Option<String>);
3009 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
3010 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
3011 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
3012 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
3013 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
3014 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
3015 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
3016 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
3017 impl_dep_tracking_hash_via_hash!(CrateType);
3018 impl_dep_tracking_hash_via_hash!(MergeFunctions);
3019 impl_dep_tracking_hash_via_hash!(PanicStrategy);
3020 impl_dep_tracking_hash_via_hash!(RelroLevel);
3021 impl_dep_tracking_hash_via_hash!(Passes);
3022 impl_dep_tracking_hash_via_hash!(OptLevel);
3023 impl_dep_tracking_hash_via_hash!(LtoCli);
3024 impl_dep_tracking_hash_via_hash!(DebugInfo);
3025 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
3026 impl_dep_tracking_hash_via_hash!(OutputTypes);
3027 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
3028 impl_dep_tracking_hash_via_hash!(Sanitizer);
3029 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
3030 impl_dep_tracking_hash_via_hash!(TargetTriple);
3031 impl_dep_tracking_hash_via_hash!(Edition);
3032 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
3033 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
3034 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
3036 impl_dep_tracking_hash_for_sortable_vec_of!(String);
3037 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
3038 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
3039 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
3040 impl_dep_tracking_hash_for_sortable_vec_of!((
3043 Option<NativeLibraryKind>
3045 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
3046 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
3048 impl<T1, T2> DepTrackingHash for (T1, T2)
3050 T1: DepTrackingHash,
3051 T2: DepTrackingHash,
3053 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
3054 Hash::hash(&0, hasher);
3055 DepTrackingHash::hash(&self.0, hasher, error_format);
3056 Hash::hash(&1, hasher);
3057 DepTrackingHash::hash(&self.1, hasher, error_format);
3061 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
3063 T1: DepTrackingHash,
3064 T2: DepTrackingHash,
3065 T3: DepTrackingHash,
3067 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
3068 Hash::hash(&0, hasher);
3069 DepTrackingHash::hash(&self.0, hasher, error_format);
3070 Hash::hash(&1, hasher);
3071 DepTrackingHash::hash(&self.1, hasher, error_format);
3072 Hash::hash(&2, hasher);
3073 DepTrackingHash::hash(&self.2, hasher, error_format);
3077 // This is a stable hash because BTreeMap is a sorted container
3079 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
3080 hasher: &mut DefaultHasher,
3081 error_format: ErrorOutputType,
3083 for (key, sub_hash) in sub_hashes {
3084 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
3085 // the keys, as they are just plain strings
3086 Hash::hash(&key.len(), hasher);
3087 Hash::hash(key, hasher);
3088 sub_hash.hash(hasher, error_format);