1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command line options.
6 use crate::session::{early_error, early_warn, Session};
7 use crate::session::search_paths::SearchPath;
9 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
10 use rustc_target::spec::{Target, TargetTriple};
12 use crate::middle::cstore;
15 use syntax::ast::{self, IntTy, UintTy, MetaItemKind};
16 use syntax::source_map::{FileName, FilePathMapping};
17 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
18 use syntax::parse::token;
20 use syntax::symbol::Symbol;
21 use syntax::feature_gate::UnstableFeatures;
22 use errors::emitter::HumanReadableErrorType;
24 use errors::{ColorConfig, FatalError, Handler};
27 use std::collections::{BTreeMap, BTreeSet};
28 use std::collections::btree_map::Iter as BTreeMapIter;
29 use std::collections::btree_map::Keys as BTreeMapKeysIter;
30 use std::collections::btree_map::Values as BTreeMapValuesIter;
32 use rustc_data_structures::fx::FxHashSet;
34 use std::hash::Hasher;
35 use std::collections::hash_map::DefaultHasher;
36 use std::iter::FromIterator;
37 use std::path::{Path, PathBuf};
45 #[derive(Clone, Hash, Debug)]
53 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
63 impl_stable_hash_via_hash!(OptLevel);
65 /// This is what the `LtoCli` values get mapped to after resolving defaults and
66 /// and taking other command line options into account.
67 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
69 /// Don't do any LTO whatsoever
72 /// Do a full crate graph LTO with ThinLTO
75 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
79 /// Do a full crate graph LTO with "fat" LTO
83 /// The different settings that the `-C lto` flag can have.
84 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
96 /// No `-C lto` flag passed
100 #[derive(Clone, PartialEq, Hash)]
101 pub enum LinkerPluginLto {
102 LinkerPlugin(PathBuf),
107 impl LinkerPluginLto {
108 pub fn enabled(&self) -> bool {
110 LinkerPluginLto::LinkerPlugin(_) |
111 LinkerPluginLto::LinkerPluginAuto => true,
112 LinkerPluginLto::Disabled => false,
117 #[derive(Clone, Copy, PartialEq, Hash)]
124 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
125 pub enum OutputType {
136 impl_stable_hash_via_hash!(OutputType);
139 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
141 OutputType::Exe | OutputType::DepInfo => true,
143 | OutputType::Assembly
144 | OutputType::LlvmAssembly
147 | OutputType::Metadata => false,
151 fn shorthand(&self) -> &'static str {
153 OutputType::Bitcode => "llvm-bc",
154 OutputType::Assembly => "asm",
155 OutputType::LlvmAssembly => "llvm-ir",
156 OutputType::Mir => "mir",
157 OutputType::Object => "obj",
158 OutputType::Metadata => "metadata",
159 OutputType::Exe => "link",
160 OutputType::DepInfo => "dep-info",
164 fn from_shorthand(shorthand: &str) -> Option<Self> {
165 Some(match shorthand {
166 "asm" => OutputType::Assembly,
167 "llvm-ir" => OutputType::LlvmAssembly,
168 "mir" => OutputType::Mir,
169 "llvm-bc" => OutputType::Bitcode,
170 "obj" => OutputType::Object,
171 "metadata" => OutputType::Metadata,
172 "link" => OutputType::Exe,
173 "dep-info" => OutputType::DepInfo,
178 fn shorthands_display() -> String {
180 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
181 OutputType::Bitcode.shorthand(),
182 OutputType::Assembly.shorthand(),
183 OutputType::LlvmAssembly.shorthand(),
184 OutputType::Mir.shorthand(),
185 OutputType::Object.shorthand(),
186 OutputType::Metadata.shorthand(),
187 OutputType::Exe.shorthand(),
188 OutputType::DepInfo.shorthand(),
192 pub fn extension(&self) -> &'static str {
194 OutputType::Bitcode => "bc",
195 OutputType::Assembly => "s",
196 OutputType::LlvmAssembly => "ll",
197 OutputType::Mir => "mir",
198 OutputType::Object => "o",
199 OutputType::Metadata => "rmeta",
200 OutputType::DepInfo => "d",
201 OutputType::Exe => "",
206 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
207 pub enum ErrorOutputType {
208 HumanReadable(HumanReadableErrorType),
210 /// Render the json in a human readable way (with indents and newlines)
212 /// The way the `rendered` field is created
213 json_rendered: HumanReadableErrorType,
217 impl Default for ErrorOutputType {
218 fn default() -> ErrorOutputType {
219 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
223 // Use tree-based collections to cheaply get a deterministic Hash implementation.
224 // DO NOT switch BTreeMap out for an unsorted container type! That would break
225 // dependency tracking for command-line arguments.
226 #[derive(Clone, Hash)]
227 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
229 impl_stable_hash_via_hash!(OutputTypes);
232 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
233 OutputTypes(BTreeMap::from_iter(
234 entries.iter().map(|&(k, ref v)| (k, v.clone())),
238 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
242 pub fn contains_key(&self, key: &OutputType) -> bool {
243 self.0.contains_key(key)
246 pub fn keys<'a>(&'a self) -> BTreeMapKeysIter<'a, OutputType, Option<PathBuf>> {
250 pub fn values<'a>(&'a self) -> BTreeMapValuesIter<'a, OutputType, Option<PathBuf>> {
254 pub fn len(&self) -> usize {
258 // True if any of the output types require codegen or linking.
259 pub fn should_codegen(&self) -> bool {
260 self.0.keys().any(|k| match *k {
262 | OutputType::Assembly
263 | OutputType::LlvmAssembly
266 | OutputType::Exe => true,
267 OutputType::Metadata | OutputType::DepInfo => false,
272 // Use tree-based collections to cheaply get a deterministic Hash implementation.
273 // DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
274 // would break dependency tracking for command-line arguments.
275 #[derive(Clone, Hash)]
276 pub struct Externs(BTreeMap<String, BTreeSet<Option<String>>>);
279 pub fn new(data: BTreeMap<String, BTreeSet<Option<String>>>) -> Externs {
283 pub fn get(&self, key: &str) -> Option<&BTreeSet<Option<String>>> {
287 pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<Option<String>>> {
292 macro_rules! hash_option {
293 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
294 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
295 if $sub_hashes.insert(stringify!($opt_name),
296 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
297 bug!("Duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
303 [UNTRACKED_WITH_WARNING $warn_val:expr, $warn_text:expr, $error_format:expr]) => ({
304 if *$opt_expr == $warn_val {
305 early_warn($error_format, $warn_text)
310 macro_rules! top_level_options {
311 (pub struct Options { $(
312 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
320 pub fn dep_tracking_hash(&self) -> u64 {
321 let mut sub_hashes = BTreeMap::new();
326 [$dep_tracking_marker $($warn_val,
328 self.error_format)*]);
330 let mut hasher = DefaultHasher::new();
331 dep_tracking::stable_hash(sub_hashes,
340 // The top-level command-line options struct
342 // For each option, one has to specify how it behaves with regard to the
343 // dependency tracking system of incremental compilation. This is done via the
344 // square-bracketed directive after the field type. The options are:
347 // A change in the given field will cause the compiler to completely clear the
348 // incremental compilation cache before proceeding.
351 // Incremental compilation is not influenced by this option.
353 // [UNTRACKED_WITH_WARNING(val, warning)]
354 // The option is incompatible with incremental compilation in some way. If it
355 // has the value `val`, the string `warning` is emitted as a warning.
357 // If you add a new option to this struct or one of the sub-structs like
358 // CodegenOptions, think about how it influences incremental compilation. If in
359 // doubt, specify [TRACKED], which is always "correct" but might lead to
360 // unnecessary re-compilation.
363 // The crate config requested for the session, which may be combined
364 // with additional crate configurations during the compile process
365 crate_types: Vec<CrateType> [TRACKED],
366 optimize: OptLevel [TRACKED],
367 // Include the debug_assertions flag into dependency tracking, since it
368 // can influence whether overflow checks are done or not.
369 debug_assertions: bool [TRACKED],
370 debuginfo: DebugInfo [TRACKED],
371 lint_opts: Vec<(String, lint::Level)> [TRACKED],
372 lint_cap: Option<lint::Level> [TRACKED],
373 describe_lints: bool [UNTRACKED],
374 output_types: OutputTypes [TRACKED],
375 search_paths: Vec<SearchPath> [UNTRACKED],
376 libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
377 maybe_sysroot: Option<PathBuf> [TRACKED],
379 target_triple: TargetTriple [TRACKED],
381 test: bool [TRACKED],
382 error_format: ErrorOutputType [UNTRACKED],
384 // if Some, enable incremental compilation, using the given
385 // directory to store intermediate results
386 incremental: Option<PathBuf> [UNTRACKED],
388 debugging_opts: DebuggingOptions [TRACKED],
389 prints: Vec<PrintRequest> [UNTRACKED],
390 // Determines which borrow checker(s) to run. This is the parsed, sanitized
391 // version of `debugging_opts.borrowck`, which is just a plain string.
392 borrowck_mode: BorrowckMode [UNTRACKED],
393 cg: CodegenOptions [TRACKED],
394 externs: Externs [UNTRACKED],
395 crate_name: Option<String> [TRACKED],
396 // An optional name to use as the crate for std during std injection,
397 // written `extern crate name as std`. Defaults to `std`. Used by
398 // out-of-tree drivers.
399 alt_std_name: Option<String> [TRACKED],
400 // Indicates how the compiler should treat unstable features
401 unstable_features: UnstableFeatures [TRACKED],
403 // Indicates whether this run of the compiler is actually rustdoc. This
404 // is currently just a hack and will be removed eventually, so please
405 // try to not rely on this too much.
406 actually_rustdoc: bool [TRACKED],
408 // Specifications of codegen units / ThinLTO which are forced as a
409 // result of parsing command line options. These are not necessarily
410 // what rustc was invoked with, but massaged a bit to agree with
411 // commands like `--emit llvm-ir` which they're often incompatible with
412 // if we otherwise use the defaults of rustc.
413 cli_forced_codegen_units: Option<usize> [UNTRACKED],
414 cli_forced_thinlto_off: bool [UNTRACKED],
416 // Remap source path prefixes in all output (messages, object files, debug, etc)
417 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
419 edition: Edition [TRACKED],
421 // The list of crates to consider private when
422 // checking leaked private dependency types in public interfaces
423 extern_private: Vec<String> [TRACKED],
427 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
428 pub enum PrintRequest {
443 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
444 pub enum BorrowckMode {
452 /// Should we run the MIR-based borrow check, but also fall back
453 /// on the AST borrow check if the MIR-based one errors.
454 pub fn migrate(self) -> bool {
456 BorrowckMode::Ast => false,
457 BorrowckMode::Compare => false,
458 BorrowckMode::Mir => false,
459 BorrowckMode::Migrate => true,
463 /// Should we emit the AST-based borrow checker errors?
464 pub fn use_ast(self) -> bool {
466 BorrowckMode::Ast => true,
467 BorrowckMode::Compare => true,
468 BorrowckMode::Mir => false,
469 BorrowckMode::Migrate => false,
472 /// Should we emit the MIR-based borrow checker errors?
473 pub fn use_mir(self) -> bool {
475 BorrowckMode::Ast => false,
476 BorrowckMode::Compare => true,
477 BorrowckMode::Mir => true,
478 BorrowckMode::Migrate => true,
484 /// Loads source from file
487 /// String that is shown in place of a filename
489 /// Anonymous source string
495 pub fn filestem(&self) -> &str {
497 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
498 Input::Str { .. } => "rust_out",
502 pub fn get_input(&mut self) -> Option<&mut String> {
504 Input::File(_) => None,
505 Input::Str { ref mut input, .. } => Some(input),
509 pub fn source_name(&self) -> FileName {
511 Input::File(ref ifile) => ifile.clone().into(),
512 Input::Str { ref name, .. } => name.clone(),
517 #[derive(Clone, Hash)]
518 pub struct OutputFilenames {
519 pub out_directory: PathBuf,
520 pub out_filestem: String,
521 pub single_output_file: Option<PathBuf>,
523 pub outputs: OutputTypes,
526 impl_stable_hash_via_hash!(OutputFilenames);
528 pub const RUST_CGU_EXT: &str = "rcgu";
530 impl OutputFilenames {
531 pub fn path(&self, flavor: OutputType) -> PathBuf {
534 .and_then(|p| p.to_owned())
535 .or_else(|| self.single_output_file.clone())
536 .unwrap_or_else(|| self.temp_path(flavor, None))
539 /// Gets the path where a compilation artifact of the given type for the
540 /// given codegen unit should be placed on disk. If codegen_unit_name is
541 /// None, a path distinct from those of any codegen unit will be generated.
542 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
543 let extension = flavor.extension();
544 self.temp_path_ext(extension, codegen_unit_name)
547 /// Like temp_path, but also supports things where there is no corresponding
548 /// OutputType, like noopt-bitcode or lto-bitcode.
549 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
550 let base = self.out_directory.join(&self.filestem());
552 let mut extension = String::new();
554 if let Some(codegen_unit_name) = codegen_unit_name {
555 extension.push_str(codegen_unit_name);
559 if !extension.is_empty() {
560 extension.push_str(".");
561 extension.push_str(RUST_CGU_EXT);
562 extension.push_str(".");
565 extension.push_str(ext);
568 let path = base.with_extension(&extension[..]);
572 pub fn with_extension(&self, extension: &str) -> PathBuf {
574 .join(&self.filestem())
575 .with_extension(extension)
578 pub fn filestem(&self) -> String {
579 format!("{}{}", self.out_filestem, self.extra)
583 pub fn host_triple() -> &'static str {
584 // Get the host triple out of the build environment. This ensures that our
585 // idea of the host triple is the same as for the set of libraries we've
586 // actually built. We can't just take LLVM's host triple because they
587 // normalize all ix86 architectures to i386.
589 // Instead of grabbing the host triple (for the current host), we grab (at
590 // compile time) the target triple that this rustc is built with and
591 // calling that (at runtime) the host triple.
592 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
595 impl Default for Options {
596 fn default() -> Options {
598 crate_types: Vec::new(),
599 optimize: OptLevel::No,
600 debuginfo: DebugInfo::None,
601 lint_opts: Vec::new(),
603 describe_lints: false,
604 output_types: OutputTypes(BTreeMap::new()),
605 search_paths: vec![],
607 target_triple: TargetTriple::from_triple(host_triple()),
610 debugging_opts: basic_debugging_options(),
612 borrowck_mode: BorrowckMode::Ast,
613 cg: basic_codegen_options(),
614 error_format: ErrorOutputType::default(),
615 externs: Externs(BTreeMap::new()),
619 unstable_features: UnstableFeatures::Disallow,
620 debug_assertions: true,
621 actually_rustdoc: false,
622 cli_forced_codegen_units: None,
623 cli_forced_thinlto_off: false,
624 remap_path_prefix: Vec::new(),
625 edition: DEFAULT_EDITION,
626 extern_private: Vec::new()
632 /// Returns `true` if there is a reason to build the dep graph.
633 pub fn build_dep_graph(&self) -> bool {
634 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
635 || self.debugging_opts.query_dep_graph
639 pub fn enable_dep_node_debug_strs(&self) -> bool {
640 cfg!(debug_assertions)
641 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
644 pub fn file_path_mapping(&self) -> FilePathMapping {
645 FilePathMapping::new(self.remap_path_prefix.clone())
648 /// Returns `true` if there will be an output file generated
649 pub fn will_create_output_file(&self) -> bool {
650 !self.debugging_opts.parse_only && // The file is just being parsed
651 !self.debugging_opts.ls // The file is just being queried
655 pub fn share_generics(&self) -> bool {
656 match self.debugging_opts.share_generics {
657 Some(setting) => setting,
659 match self.optimize {
663 OptLevel::SizeMin => true,
665 OptLevel::Aggressive => false,
672 // The type of entry function, so users can have their own entry functions
673 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
674 pub enum EntryFnType {
679 impl_stable_hash_via_hash!(EntryFnType);
681 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
691 #[derive(Clone, Hash)]
698 pub fn is_empty(&self) -> bool {
700 Passes::Some(ref v) => v.is_empty(),
701 Passes::All => false,
706 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
707 /// at once. The goal of this macro is to define an interface that can be
708 /// programmatically used by the option parser in order to initialize the struct
709 /// without hardcoding field names all over the place.
711 /// The goal is to invoke this macro once with the correct fields, and then this
712 /// macro generates all necessary code. The main gotcha of this macro is the
713 /// cgsetters module which is a bunch of generated code to parse an option into
714 /// its respective field in the struct. There are a few hand-written parsers for
715 /// parsing specific types of values in this module.
716 macro_rules! options {
717 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
718 $buildfn:ident, $prefix:expr, $outputname:expr,
719 $stat:ident, $mod_desc:ident, $mod_set:ident,
720 $($opt:ident : $t:ty = (
723 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
728 pub struct $struct_name { $(pub $opt: $t),* }
730 pub fn $defaultfn() -> $struct_name {
731 $struct_name { $($opt: $init),* }
734 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
736 let mut op = $defaultfn();
737 for option in matches.opt_strs($prefix) {
738 let mut iter = option.splitn(2, '=');
739 let key = iter.next().unwrap();
740 let value = iter.next();
741 let option_to_lookup = key.replace("-", "_");
742 let mut found = false;
743 for &(candidate, setter, opt_type_desc, _) in $stat {
744 if option_to_lookup != candidate { continue }
745 if !setter(&mut op, value) {
746 match (value, opt_type_desc) {
747 (Some(..), None) => {
748 early_error(error_format, &format!("{} option `{}` takes no \
749 value", $outputname, key))
751 (None, Some(type_desc)) => {
752 early_error(error_format, &format!("{0} option `{1}` requires \
753 {2} ({3} {1}=<value>)",
757 (Some(value), Some(type_desc)) => {
758 early_error(error_format, &format!("incorrect value `{}` for {} \
759 option `{}` - {} was expected",
763 (None, None) => bug!()
770 early_error(error_format, &format!("unknown {} option: `{}`",
777 impl<'a> dep_tracking::DepTrackingHash for $struct_name {
778 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
779 let mut sub_hashes = BTreeMap::new();
784 [$dep_tracking_marker $($dep_warn_val,
788 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
792 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
793 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
794 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
796 #[allow(non_upper_case_globals, dead_code)]
798 pub const parse_bool: Option<&str> = None;
799 pub const parse_opt_bool: Option<&str> =
800 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
801 pub const parse_string: Option<&str> = Some("a string");
802 pub const parse_string_push: Option<&str> = Some("a string");
803 pub const parse_pathbuf_push: Option<&str> = Some("a path");
804 pub const parse_opt_string: Option<&str> = Some("a string");
805 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
806 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
807 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
808 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
809 pub const parse_uint: Option<&str> = Some("a number");
810 pub const parse_passes: Option<&str> =
811 Some("a space-separated list of passes, or `all`");
812 pub const parse_opt_uint: Option<&str> =
814 pub const parse_panic_strategy: Option<&str> =
815 Some("either `unwind` or `abort`");
816 pub const parse_relro_level: Option<&str> =
817 Some("one of: `full`, `partial`, or `off`");
818 pub const parse_sanitizer: Option<&str> =
819 Some("one of: `address`, `leak`, `memory` or `thread`");
820 pub const parse_linker_flavor: Option<&str> =
821 Some(::rustc_target::spec::LinkerFlavor::one_of());
822 pub const parse_optimization_fuel: Option<&str> =
823 Some("crate=integer");
824 pub const parse_unpretty: Option<&str> =
825 Some("`string` or `string=string`");
826 pub const parse_treat_err_as_bug: Option<&str> =
827 Some("either no value or a number bigger than 0");
828 pub const parse_lto: Option<&str> =
829 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
831 pub const parse_linker_plugin_lto: Option<&str> =
832 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
833 or the path to the linker plugin");
834 pub const parse_merge_functions: Option<&str> =
835 Some("one of: `disabled`, `trampolines`, or `aliases`");
840 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto};
841 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
842 use std::path::PathBuf;
843 use std::str::FromStr;
846 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
847 $parse(&mut cg.$opt, v)
851 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
854 None => { *slot = true; true }
858 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
862 "n" | "no" | "off" => {
865 "y" | "yes" | "on" => {
868 _ => { return false; }
873 None => { *slot = Some(true); true }
877 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
879 Some(s) => { *slot = Some(s.to_string()); true },
884 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
886 Some(s) => { *slot = Some(PathBuf::from(s)); true },
891 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
893 Some(s) => { *slot = s.to_string(); true },
898 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
900 Some(s) => { slot.push(s.to_string()); true },
905 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
907 Some(s) => { slot.push(PathBuf::from(s)); true },
912 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
916 slot.extend(s.split_whitespace().map(|s| s.to_string()));
923 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
927 let v = s.split_whitespace().map(|s| s.to_string()).collect();
935 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
939 let v = s.split(',').map(|s| s.to_string()).collect();
947 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
948 match v.and_then(|s| s.parse().ok()) {
949 Some(i) => { *slot = i; true },
954 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
956 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
957 None => { *slot = None; false }
961 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
968 let mut passes = vec![];
969 if parse_list(&mut passes, v) {
970 *slot = Passes::Some(passes);
979 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
981 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
982 Some("abort") => *slot = Some(PanicStrategy::Abort),
988 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
991 match s.parse::<RelroLevel>() {
992 Ok(level) => *slot = Some(level),
1001 fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1003 Some("address") => *slote = Some(Sanitizer::Address),
1004 Some("leak") => *slote = Some(Sanitizer::Leak),
1005 Some("memory") => *slote = Some(Sanitizer::Memory),
1006 Some("thread") => *slote = Some(Sanitizer::Thread),
1012 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1013 match v.and_then(LinkerFlavor::from_str) {
1014 Some(lf) => *slote = Some(lf),
1020 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1024 let parts = s.split('=').collect::<Vec<_>>();
1025 if parts.len() != 2 { return false; }
1026 let crate_name = parts[0].to_string();
1027 let fuel = parts[1].parse::<u64>();
1028 if fuel.is_err() { return false; }
1029 *slot = Some((crate_name, fuel.unwrap()));
1035 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1038 Some(s) if s.split('=').count() <= 2 => {
1039 *slot = Some(s.to_string());
1046 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1048 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1049 None => { *slot = Some(1); true }
1053 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1055 let mut bool_arg = None;
1056 if parse_opt_bool(&mut bool_arg, v) {
1057 *slot = if bool_arg.unwrap() {
1067 None => LtoCli::NoParam,
1068 Some("thin") => LtoCli::Thin,
1069 Some("fat") => LtoCli::Fat,
1070 Some(_) => return false,
1075 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1077 let mut bool_arg = None;
1078 if parse_opt_bool(&mut bool_arg, v) {
1079 *slot = if bool_arg.unwrap() {
1080 LinkerPluginLto::LinkerPluginAuto
1082 LinkerPluginLto::Disabled
1089 None => LinkerPluginLto::LinkerPluginAuto,
1090 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1095 fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1096 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1097 Some(mergefunc) => *slot = Some(mergefunc),
1105 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1106 build_codegen_options, "C", "codegen",
1107 CG_OPTIONS, cg_type_desc, cgsetters,
1108 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1109 "this option is deprecated and does nothing"),
1110 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1111 "system linker to link outputs with"),
1112 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1113 "a single extra argument to append to the linker invocation (can be used several times)"),
1114 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1115 "extra arguments to append to the linker invocation (space separated)"),
1116 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1117 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1118 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1119 "perform LLVM link-time optimizations"),
1120 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1121 "select target processor (rustc --print target-cpus for details)"),
1122 target_feature: String = (String::new(), parse_string, [TRACKED],
1123 "target specific attributes (rustc --print target-features for details)"),
1124 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1125 "a list of extra LLVM passes to run (space separated)"),
1126 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1127 "a list of arguments to pass to llvm (space separated)"),
1128 save_temps: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1129 "`-C save-temps` might not produce all requested temporary products \
1130 when incremental compilation is enabled.")],
1131 "save all temporary output files during compilation"),
1132 rpath: bool = (false, parse_bool, [UNTRACKED],
1133 "set rpath values in libs/exes"),
1134 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1135 "use overflow checks for integer arithmetic"),
1136 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1137 "don't pre-populate the pass manager with a list of passes"),
1138 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1139 "don't run the loop vectorization optimization passes"),
1140 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1141 "don't run LLVM's SLP vectorization pass"),
1142 soft_float: bool = (false, parse_bool, [TRACKED],
1143 "use soft float ABI (*eabihf targets only)"),
1144 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1145 "prefer dynamic linking to static linking"),
1146 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1147 "use an external assembler rather than LLVM's integrated one"),
1148 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1149 "disable the use of the redzone"),
1150 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1151 "choose the relocation model to use (rustc --print relocation-models for details)"),
1152 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1153 "choose the code model to use (rustc --print code-models for details)"),
1154 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1155 "metadata to mangle symbol names with"),
1156 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1157 "extra data to put in each output filename"),
1158 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1159 "divide crate into N units to optimize in parallel"),
1160 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1161 "print remarks for these optimization passes (space separated, or \"all\")"),
1162 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1163 "the --no-stack-check flag is deprecated and does nothing"),
1164 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1165 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1166 2 = full debug info with variable and type information"),
1167 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1168 "optimize with possible levels 0-3, s, or z"),
1169 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1170 "force use of the frame pointers"),
1171 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1172 "explicitly enable the cfg(debug_assertions) directive"),
1173 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1174 "set the threshold for inlining a function (default: 225)"),
1175 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1176 [TRACKED], "panic strategy to compile crate with"),
1177 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1178 "enable incremental compilation"),
1179 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1180 "allow the linker to link its default libraries"),
1181 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1183 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1184 parse_linker_plugin_lto, [TRACKED],
1185 "generate build artifacts that are compatible with linker-based LTO."),
1189 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1190 build_debugging_options, "Z", "debugging",
1191 DB_OPTIONS, db_type_desc, dbsetters,
1192 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1193 "the backend to use"),
1194 verbose: bool = (false, parse_bool, [UNTRACKED],
1195 "in general, enable more debug printouts"),
1196 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1197 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1198 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1199 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1200 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1201 "select which borrowck is used (`ast`, `mir`, `migrate`, or `compare`)"),
1202 two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
1203 "use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"),
1204 two_phase_beyond_autoref: bool = (false, parse_bool, [UNTRACKED],
1205 "when using two-phase-borrows, allow two phases even for non-autoref `&mut` borrows"),
1206 time_passes: bool = (false, parse_bool, [UNTRACKED],
1207 "measure time of each rustc pass"),
1208 time: bool = (false, parse_bool, [UNTRACKED],
1209 "measure time of rustc processes"),
1210 count_llvm_insns: bool = (false, parse_bool,
1211 [UNTRACKED_WITH_WARNING(true,
1212 "The output generated by `-Z count_llvm_insns` might not be reliable \
1213 when used with incremental compilation")],
1214 "count where LLVM instrs originate"),
1215 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1216 "The output of `-Z time-llvm-passes` will only reflect timings of \
1217 re-codegened modules when used with incremental compilation" )],
1218 "measure time of each LLVM pass"),
1219 input_stats: bool = (false, parse_bool, [UNTRACKED],
1220 "gather statistics about the input"),
1221 codegen_stats: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1222 "The output of `-Z codegen-stats` might not be accurate when incremental \
1223 compilation is enabled")],
1224 "gather codegen statistics"),
1225 asm_comments: bool = (false, parse_bool, [TRACKED],
1226 "generate comments into the assembly (may change behavior)"),
1227 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1229 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1230 "gather borrowck statistics"),
1231 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1232 "omit landing pads for unwinding"),
1233 fewer_names: bool = (false, parse_bool, [TRACKED],
1234 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1235 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1236 "gather metadata statistics"),
1237 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1238 "print the arguments passed to the linker"),
1239 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1240 "prints the llvm optimization passes being run"),
1241 ast_json: bool = (false, parse_bool, [UNTRACKED],
1242 "print the AST as JSON and halt"),
1243 threads: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1244 "use a thread pool with N threads"),
1245 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1246 "print the pre-expansion AST as JSON and halt"),
1247 ls: bool = (false, parse_bool, [UNTRACKED],
1248 "list the symbols defined by a library crate"),
1249 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1250 "write syntax and type analysis (in JSON format) information, in \
1251 addition to normal output"),
1252 flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED],
1253 "include loan analysis data in -Z unpretty flowgraph output"),
1254 flowgraph_print_moves: bool = (false, parse_bool, [UNTRACKED],
1255 "include move analysis data in -Z unpretty flowgraph output"),
1256 flowgraph_print_assigns: bool = (false, parse_bool, [UNTRACKED],
1257 "include assignment analysis data in -Z unpretty flowgraph output"),
1258 flowgraph_print_all: bool = (false, parse_bool, [UNTRACKED],
1259 "include all dataflow analysis data in -Z unpretty flowgraph output"),
1260 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1261 "prints region inference graph. \
1262 Use with RUST_REGION_GRAPH=help for more info"),
1263 parse_only: bool = (false, parse_bool, [UNTRACKED],
1264 "parse only; do not compile, assemble, or link"),
1265 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1266 "load proc macros for both target and host, but only link to the target"),
1267 no_codegen: bool = (false, parse_bool, [TRACKED],
1268 "run all passes except codegen; no output"),
1269 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1270 "treat error number `val` that occurs as bug"),
1271 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1272 "immediately print bugs registered with `delay_span_bug`"),
1273 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1274 "show macro backtraces even for non-local macros"),
1275 teach: bool = (false, parse_bool, [TRACKED],
1276 "show extended diagnostic help"),
1277 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1278 "attempt to recover from parse errors (experimental)"),
1279 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1280 "print tasks that execute and the color their dep node gets (requires debug build)"),
1281 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1282 "enable incremental compilation (experimental)"),
1283 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1284 "enable incremental compilation support for queries (experimental)"),
1285 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1286 "print high-level information about incremental reuse (or the lack thereof)"),
1287 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1288 "dump hash information in textual format to stdout"),
1289 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1290 "verify incr. comp. hashes of green query instances"),
1291 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1292 "ignore spans during ICH computation -- used for testing"),
1293 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1294 "insert function instrument code for mcount-based tracing"),
1295 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1296 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1297 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1298 "enable queries of the dependency graph for regression testing"),
1299 profile_queries: bool = (false, parse_bool, [UNTRACKED],
1300 "trace and profile the queries of the incremental compilation framework"),
1301 profile_queries_and_keys: bool = (false, parse_bool, [UNTRACKED],
1302 "trace and profile the queries and keys of the incremental compilation framework"),
1303 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1304 "parse and expand the source, but run no analysis"),
1305 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1306 "load extra plugins"),
1307 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1308 "adds unstable command line options to rustc interface"),
1309 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1310 "force overflow checks on or off"),
1311 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1312 "for every macro invocation, print its name and arguments"),
1313 debug_macros: bool = (false, parse_bool, [TRACKED],
1314 "emit line numbers debug info inside macros"),
1315 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1316 "don't clear the hygiene data after analysis"),
1317 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1318 "keep the AST after lowering it to HIR"),
1319 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1320 "show spans for compiler debugging (expr|pat|ty)"),
1321 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1322 "print layout information for each type encountered"),
1323 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1324 "print the result of the monomorphization collection pass"),
1325 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1326 "set the MIR optimization level (0-3, default: 1)"),
1327 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1328 "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"),
1329 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1330 "dump MIR state to file.
1331 `val` is used to select which passes and functions to dump. For example:
1332 `all` matches all passes and functions,
1333 `foo` matches all passes for functions whose name contains 'foo',
1334 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1335 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1337 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1338 "the directory the MIR is dumped into"),
1339 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1340 "in addition to `.mir` files, create graphviz `.dot` files"),
1341 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1342 "if set, exclude the pass number when dumping MIR (used in tests)"),
1343 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1344 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1345 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1346 "print some performance-related statistics"),
1347 query_stats: bool = (false, parse_bool, [UNTRACKED],
1348 "print some statistics about the query system"),
1349 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1350 "print some statistics about AST and HIR"),
1351 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1352 "encode MIR of all functions into the crate metadata"),
1353 json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1354 "describes how to render the `rendered` field of json diagnostics"),
1355 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1356 "take the breaks off const evaluation. NOTE: this is unsound"),
1357 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1358 "pass `-install_name @rpath/...` to the macOS linker"),
1359 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1361 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1362 "set the optimization fuel quota for a crate"),
1363 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1364 "make Rustc print the total optimization fuel used by a crate"),
1365 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1366 "force all crates to be `rustc_private` unstable"),
1367 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1368 "a single extra argument to prepend the linker invocation (can be used several times)"),
1369 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1370 "extra arguments to prepend to the linker invocation (space separated)"),
1371 profile: bool = (false, parse_bool, [TRACKED],
1372 "insert profiling code"),
1373 pgo_gen: Option<String> = (None, parse_opt_string, [TRACKED],
1374 "Generate PGO profile data, to a given file, or to the default location if it's empty."),
1375 pgo_use: String = (String::new(), parse_string, [TRACKED],
1376 "Use PGO profile data from the given profile file."),
1377 disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1378 "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1379 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1380 "choose which RELRO level to use"),
1381 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1382 "dump facts from NLL analysis into side files"),
1383 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1384 "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1385 dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1386 "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1387 polonius: bool = (false, parse_bool, [UNTRACKED],
1388 "enable polonius-based borrow-checker"),
1389 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1390 "generate a graphical HTML report of time spent in codegen and LLVM"),
1391 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1392 "enable ThinLTO when possible"),
1393 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1394 "control whether #[inline] functions are in all cgus"),
1395 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1396 "choose the TLS model to use (rustc --print tls-models for details)"),
1397 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1398 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1399 the max/min integer respectively, and NaN is mapped to 0"),
1400 lower_128bit_ops: Option<bool> = (None, parse_opt_bool, [TRACKED],
1401 "rewrite operators on i128 and u128 into lang item calls (typically provided \
1402 by compiler-builtins) so codegen doesn't need to support them,
1403 overriding the default for the current target"),
1404 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1405 "generate human-readable, predictable names for codegen units"),
1406 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1407 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1409 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1410 "Present the input source, unstable (and less-pretty) variants;
1411 valid types are any of the types for `--pretty`, as well as:
1412 `expanded`, `expanded,identified`,
1413 `expanded,hygiene` (with internal representations),
1414 `flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
1415 `flowgraph,unlabelled=<nodeid>` (unlabelled graphviz formatted flowgraph for node),
1416 `everybody_loops` (all function bodies replaced with `loop {}`),
1417 `hir` (the HIR), `hir,identified`,
1418 `hir,typed` (HIR with types for each node),
1419 `hir-tree` (dump the raw HIR),
1420 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1421 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1422 "run `dsymutil` and delete intermediate object files"),
1423 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1424 "format compiler diagnostics in a way that's better suitable for UI testing"),
1425 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1426 "embed LLVM bitcode in object files"),
1427 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1428 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1429 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1430 "make the current crate share its generic instantiations"),
1431 chalk: bool = (false, parse_bool, [TRACKED],
1432 "enable the experimental Chalk-based trait solving engine"),
1433 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1434 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1435 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1436 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1437 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1438 "don't interleave execution of lints; allows benchmarking individual lints"),
1439 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1440 "inject the given attribute in the crate"),
1441 self_profile: bool = (false, parse_bool, [UNTRACKED],
1442 "run the self profiler and output the raw event data"),
1443 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1444 "emits a section containing stack size metadata"),
1445 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1446 "whether to use the PLT when calling into shared libraries;
1447 only has effect for PIC code on systems with ELF binaries
1448 (default: PLT is disabled if full relro is enabled)"),
1449 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1450 "control the operation of the MergeFunctions LLVM pass, taking
1451 the same values as the target option of the same name"),
1452 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1453 "only allow the listed language features to be enabled in code (space separated)"),
1456 pub fn default_lib_output() -> CrateType {
1460 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1461 let end = &sess.target.target.target_endian;
1462 let arch = &sess.target.target.arch;
1463 let wordsz = &sess.target.target.target_pointer_width;
1464 let os = &sess.target.target.target_os;
1465 let env = &sess.target.target.target_env;
1466 let vendor = &sess.target.target.target_vendor;
1467 let min_atomic_width = sess.target.target.min_atomic_width();
1468 let max_atomic_width = sess.target.target.max_atomic_width();
1469 let atomic_cas = sess.target.target.options.atomic_cas;
1471 let mut ret = FxHashSet::default();
1472 ret.reserve(6); // the minimum number of insertions
1474 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1475 if let Some(ref fam) = sess.target.target.options.target_family {
1476 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1477 if fam == "windows" || fam == "unix" {
1478 ret.insert((Symbol::intern(fam), None));
1481 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1482 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1484 Symbol::intern("target_pointer_width"),
1485 Some(Symbol::intern(wordsz)),
1487 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1489 Symbol::intern("target_vendor"),
1490 Some(Symbol::intern(vendor)),
1492 if sess.target.target.options.has_elf_tls {
1493 ret.insert((Symbol::intern("target_thread_local"), None));
1495 for &i in &[8, 16, 32, 64, 128] {
1496 if i >= min_atomic_width && i <= max_atomic_width {
1497 let s = i.to_string();
1499 Symbol::intern("target_has_atomic"),
1500 Some(Symbol::intern(&s)),
1504 Symbol::intern("target_has_atomic"),
1505 Some(Symbol::intern("ptr")),
1511 ret.insert((Symbol::intern("target_has_atomic"), Some(Symbol::intern("cas"))));
1513 if sess.opts.debug_assertions {
1514 ret.insert((Symbol::intern("debug_assertions"), None));
1516 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1517 ret.insert((Symbol::intern("proc_macro"), None));
1522 /// Converts the crate cfg! configuration from String to Symbol.
1523 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1524 /// but the symbol interner is not yet set up then, so we must convert it later.
1525 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
1527 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1531 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1532 // Combine the configuration requested by the session (command line) with
1533 // some default and generated configuration items
1534 let default_cfg = default_configuration(sess);
1535 // If the user wants a test runner, then add the test cfg
1537 user_cfg.insert((Symbol::intern("test"), None));
1539 user_cfg.extend(default_cfg.iter().cloned());
1543 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1544 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1545 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1546 .help("Use `--print target-list` for a list of built-in targets")
1551 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1552 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1553 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1554 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1555 w => sp.fatal(&format!(
1556 "target specification was invalid: \
1557 unrecognized target-pointer-width {}",
1569 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1570 pub enum OptionStability {
1575 pub struct RustcOptGroup {
1576 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1577 pub name: &'static str,
1578 pub stability: OptionStability,
1581 impl RustcOptGroup {
1582 pub fn is_stable(&self) -> bool {
1583 self.stability == OptionStability::Stable
1586 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1588 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1593 stability: OptionStability::Stable,
1597 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1599 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1604 stability: OptionStability::Unstable,
1609 // The `opt` local module holds wrappers around the `getopts` API that
1610 // adds extra rustc-specific metadata to each option; such metadata
1611 // is exposed by . The public
1612 // functions below ending with `_u` are the functions that return
1613 // *unstable* options, i.e., options that are only enabled when the
1614 // user also passes the `-Z unstable-options` debugging flag.
1616 // The `fn opt_u` etc below are written so that we can use them
1617 // in the future; do not warn about them not being used right now.
1618 #![allow(dead_code)]
1621 use super::RustcOptGroup;
1623 pub type R = RustcOptGroup;
1624 pub type S = &'static str;
1626 fn stable<F>(name: S, f: F) -> R
1628 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1630 RustcOptGroup::stable(name, f)
1633 fn unstable<F>(name: S, f: F) -> R
1635 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1637 RustcOptGroup::unstable(name, f)
1640 fn longer(a: S, b: S) -> S {
1641 if a.len() > b.len() {
1648 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1649 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1651 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1652 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1654 pub fn flag_s(a: S, b: S, c: S) -> R {
1655 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1657 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1658 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1660 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1661 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1664 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1665 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1667 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1668 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1670 pub fn flag(a: S, b: S, c: S) -> R {
1671 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1673 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1674 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1676 pub fn flagmulti(a: S, b: S, c: S) -> R {
1677 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1681 /// Returns the "short" subset of the rustc command line options,
1682 /// including metadata for each option, such as whether the option is
1683 /// part of the stable long-term interface for rustc.
1684 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1686 opt::flag_s("h", "help", "Display this message"),
1687 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1691 "Add a directory to the library search path. The
1692 optional KIND can be one of dependency, crate, native,
1693 framework or all (the default).",
1699 "Link the generated crate(s) to the specified native
1700 library NAME. The optional KIND can be one of
1701 static, dylib, or framework. If omitted, dylib is
1708 "Comma separated list of types of crates
1709 for the compiler to emit",
1710 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1715 "Specify the name of the crate being built",
1721 "Specify which edition of the compiler to use when compiling code.",
1727 "Comma separated list of types of output for \
1728 the compiler to emit",
1729 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1734 "Comma separated list of compiler information to \
1736 "[crate-name|file-names|sysroot|cfg|target-list|\
1737 target-cpus|target-features|relocation-models|\
1738 code-models|tls-models|target-spec-json|native-static-libs]",
1740 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1741 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1742 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1746 "Write output to compiler-chosen filename \
1753 "Provide a detailed explanation of an error \
1757 opt::flag_s("", "test", "Build a test harness"),
1761 "Target triple for which the code is compiled",
1764 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1765 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1766 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1767 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1771 "Set the most restrictive lint level. \
1772 More restrictive lints are capped at this \
1776 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1777 opt::flag_s("V", "version", "Print version info and exit"),
1778 opt::flag_s("v", "verbose", "Use verbose output"),
1782 /// Returns all rustc command line options, including metadata for
1783 /// each option, such as whether the option is part of the stable
1784 /// long-term interface for rustc.
1785 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1786 let mut opts = rustc_short_optgroups();
1791 "Specify where an external rust library is located",
1797 "Specify where an extern rust library is located, marking it as a private dependency",
1800 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1801 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1805 "How errors and other messages are produced",
1811 "Choose `rendered` field of json diagnostics render scheme",
1817 "Configure coloring of output:
1818 auto = colorize, if output goes to a tty (default);
1819 always = always colorize output;
1820 never = never colorize output",
1821 "auto|always|never",
1826 "Pretty-print the input instead of compiling;
1827 valid types are: `normal` (un-annotated source),
1828 `expanded` (crates expanded), or
1829 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1834 "remap-path-prefix",
1835 "Remap source names in all output (compiler messages and output files)",
1842 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
1843 pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
1844 syntax::with_globals(move || {
1845 let cfg = cfgspecs.into_iter().map(|s| {
1846 let sess = parse::ParseSess::new(FilePathMapping::empty());
1847 let filename = FileName::cfg_spec_source_code(&s);
1848 let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string());
1850 macro_rules! error {($reason: expr) => {
1851 early_error(ErrorOutputType::default(),
1852 &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s));
1855 match &mut parser.parse_meta_item() {
1856 Ok(meta_item) if parser.token == token::Eof => {
1857 if meta_item.path.segments.len() != 1 {
1858 error!("argument key must be an identifier");
1860 match &meta_item.node {
1861 MetaItemKind::List(..) => {
1862 error!(r#"expected `key` or `key="value"`"#);
1864 MetaItemKind::NameValue(lit) if !lit.node.is_str() => {
1865 error!("argument value must be a string");
1867 MetaItemKind::NameValue(..) | MetaItemKind::Word => {
1868 let ident = meta_item.ident().expect("multi-segment cfg key");
1869 return (ident.name, meta_item.value_str());
1874 Err(err) => err.cancel(),
1877 error!(r#"expected `key` or `key="value"`"#);
1878 }).collect::<ast::CrateConfig>();
1879 cfg.into_iter().map(|(a, b)| {
1880 (a.to_string(), b.map(|b| b.to_string()))
1885 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1886 error_format: ErrorOutputType)
1887 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1888 let mut lint_opts = vec![];
1889 let mut describe_lints = false;
1891 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1892 for lint_name in matches.opt_strs(level.as_str()) {
1893 if lint_name == "help" {
1894 describe_lints = true;
1896 lint_opts.push((lint_name.replace("-", "_"), level));
1901 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1902 lint::Level::from_str(&cap)
1903 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1905 (lint_opts, describe_lints, lint_cap)
1908 pub fn build_session_options_and_crate_config(
1909 matches: &getopts::Matches,
1910 ) -> (Options, FxHashSet<(String, Option<String>)>) {
1911 let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1912 Some("auto") => ColorConfig::Auto,
1913 Some("always") => ColorConfig::Always,
1914 Some("never") => ColorConfig::Never,
1916 None => ColorConfig::Auto,
1918 Some(arg) => early_error(
1919 ErrorOutputType::default(),
1921 "argument for --color must be auto, \
1922 always or never (instead was `{}`)",
1928 let edition = match matches.opt_str("edition") {
1929 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
1931 ErrorOutputType::default(),
1933 "argument for --edition must be one of: \
1934 {}. (instead was `{}`)",
1940 None => DEFAULT_EDITION,
1943 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1945 ErrorOutputType::default(),
1947 "Edition {} is unstable and only \
1948 available for nightly builds of rustc.",
1954 let json_rendered = matches.opt_str("json-rendered").and_then(|s| match s.as_str() {
1956 "termcolor" => Some(HumanReadableErrorType::Default(ColorConfig::Always)),
1958 ErrorOutputType::default(),
1960 "argument for --json-rendered must be `plain` or `termcolor` (instead was `{}`)",
1964 }).unwrap_or(HumanReadableErrorType::Default(ColorConfig::Never));
1966 // We need the opts_present check because the driver will send us Matches
1967 // with only stable options if no unstable options are used. Since error-format
1968 // is unstable, it will not be present. We have to use opts_present not
1969 // opt_present because the latter will panic.
1970 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1971 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1973 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1974 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1975 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1976 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1978 Some(arg) => early_error(
1979 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1981 "argument for --error-format must be `human`, `json` or \
1982 `short` (instead was `{}`)",
1988 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1991 let unparsed_crate_types = matches.opt_strs("crate-type");
1992 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1993 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1996 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1998 let mut debugging_opts = build_debugging_options(matches, error_format);
2000 if !debugging_opts.unstable_options {
2001 if matches.opt_str("json-rendered").is_some() {
2002 early_error(error_format, "`--json-rendered=x` is unstable");
2004 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2006 ErrorOutputType::Json { pretty: false, json_rendered },
2007 "--error-format=pretty-json is unstable",
2012 if debugging_opts.pgo_gen.is_some() && !debugging_opts.pgo_use.is_empty() {
2015 "options `-Z pgo-gen` and `-Z pgo-use` are exclusive",
2019 let mut output_types = BTreeMap::new();
2020 if !debugging_opts.parse_only {
2021 for list in matches.opt_strs("emit") {
2022 for output_type in list.split(',') {
2023 let mut parts = output_type.splitn(2, '=');
2024 let shorthand = parts.next().unwrap();
2025 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2029 "unknown emission type: `{}` - expected one of: {}",
2031 OutputType::shorthands_display(),
2035 let path = parts.next().map(PathBuf::from);
2036 output_types.insert(output_type, path);
2040 if output_types.is_empty() {
2041 output_types.insert(OutputType::Exe, None);
2044 let mut cg = build_codegen_options(matches, error_format);
2045 let mut codegen_units = cg.codegen_units;
2046 let mut disable_thinlto = false;
2048 // Issue #30063: if user requests llvm-related output to one
2049 // particular path, disable codegen-units.
2050 let incompatible: Vec<_> = output_types
2052 .map(|ot_path| ot_path.0)
2053 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2054 .map(|ot| ot.shorthand())
2056 if !incompatible.is_empty() {
2057 match codegen_units {
2058 Some(n) if n > 1 => {
2059 if matches.opt_present("o") {
2060 for ot in &incompatible {
2064 "--emit={} with -o incompatible with \
2065 -C codegen-units=N for N > 1",
2070 early_warn(error_format, "resetting to default -C codegen-units=1");
2071 codegen_units = Some(1);
2072 disable_thinlto = true;
2076 codegen_units = Some(1);
2077 disable_thinlto = true;
2082 if debugging_opts.threads == Some(0) {
2085 "Value for threads must be a positive nonzero integer",
2089 if debugging_opts.threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() {
2092 "Optimization fuel is incompatible with multiple threads",
2096 if codegen_units == Some(0) {
2099 "Value for codegen units must be a positive nonzero integer",
2103 let incremental = match (&debugging_opts.incremental, &cg.incremental) {
2104 (&Some(ref path1), &Some(ref path2)) => {
2109 "conflicting paths for `-Z incremental` and \
2110 `-C incremental` specified: {} versus {}",
2118 (&Some(ref path), &None) => Some(path),
2119 (&None, &Some(ref path)) => Some(path),
2120 (&None, &None) => None,
2121 }.map(|m| PathBuf::from(m));
2123 if debugging_opts.profile && incremental.is_some() {
2126 "can't instrument with gcov profiling when compiling incrementally",
2130 let mut prints = Vec::<PrintRequest>::new();
2131 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2132 prints.push(PrintRequest::TargetCPUs);
2133 cg.target_cpu = None;
2135 if cg.target_feature == "help" {
2136 prints.push(PrintRequest::TargetFeatures);
2137 cg.target_feature = String::new();
2139 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2140 prints.push(PrintRequest::RelocationModels);
2141 cg.relocation_model = None;
2143 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2144 prints.push(PrintRequest::CodeModels);
2145 cg.code_model = None;
2150 .map_or(false, |s| s == "help")
2152 prints.push(PrintRequest::TlsModels);
2153 debugging_opts.tls_model = None;
2158 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2159 let target_triple = if let Some(target) = matches.opt_str("target") {
2160 if target.ends_with(".json") {
2161 let path = Path::new(&target);
2162 TargetTriple::from_path(&path).unwrap_or_else(|_|
2163 early_error(error_format, &format!("target file {:?} does not exist", path)))
2165 TargetTriple::TargetTriple(target)
2168 TargetTriple::from_triple(host_triple())
2171 if matches.opt_present("O") {
2172 if cg.opt_level.is_some() {
2173 early_error(error_format, "-O and -C opt-level both provided");
2177 match cg.opt_level.as_ref().map(String::as_ref) {
2178 None => OptLevel::No,
2179 Some("0") => OptLevel::No,
2180 Some("1") => OptLevel::Less,
2181 Some("2") => OptLevel::Default,
2182 Some("3") => OptLevel::Aggressive,
2183 Some("s") => OptLevel::Size,
2184 Some("z") => OptLevel::SizeMin,
2189 "optimization level needs to be \
2190 between 0-3, s or z (instead was `{}`)",
2198 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2199 let debuginfo = if matches.opt_present("g") {
2200 if cg.debuginfo.is_some() {
2201 early_error(error_format, "-g and -C debuginfo both provided");
2205 match cg.debuginfo {
2206 None | Some(0) => DebugInfo::None,
2207 Some(1) => DebugInfo::Limited,
2208 Some(2) => DebugInfo::Full,
2213 "debug info level needs to be between \
2214 0-2 (instead was `{}`)",
2222 let mut search_paths = vec![];
2223 for s in &matches.opt_strs("L") {
2224 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2231 // Parse string of the form "[KIND=]lib[:new_name]",
2232 // where KIND is one of "dylib", "framework", "static".
2233 let mut parts = s.splitn(2, '=');
2234 let kind = parts.next().unwrap();
2235 let (name, kind) = match (parts.next(), kind) {
2236 (None, name) => (name, None),
2237 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2238 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2239 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2240 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2245 "unknown library kind `{}`, expected \
2246 one of dylib, framework, or static",
2252 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2256 "the library kind 'static-nobundle' is only \
2257 accepted on the nightly compiler"
2261 let mut name_parts = name.splitn(2, ':');
2262 let name = name_parts.next().unwrap();
2263 let new_name = name_parts.next();
2264 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2268 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
2269 let test = matches.opt_present("test");
2271 let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
2273 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2274 "crate-name" => PrintRequest::CrateName,
2275 "file-names" => PrintRequest::FileNames,
2276 "sysroot" => PrintRequest::Sysroot,
2277 "cfg" => PrintRequest::Cfg,
2278 "target-list" => PrintRequest::TargetList,
2279 "target-cpus" => PrintRequest::TargetCPUs,
2280 "target-features" => PrintRequest::TargetFeatures,
2281 "relocation-models" => PrintRequest::RelocationModels,
2282 "code-models" => PrintRequest::CodeModels,
2283 "tls-models" => PrintRequest::TlsModels,
2284 "native-static-libs" => PrintRequest::NativeStaticLibs,
2285 "target-spec-json" => {
2286 if is_unstable_enabled {
2287 PrintRequest::TargetSpec
2291 "the `-Z unstable-options` flag must also be passed to \
2292 enable the target-spec-json print option",
2296 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2299 let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) {
2300 None | Some("ast") => BorrowckMode::Ast,
2301 Some("mir") => BorrowckMode::Mir,
2302 Some("compare") => BorrowckMode::Compare,
2303 Some("migrate") => BorrowckMode::Migrate,
2304 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2307 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2310 "-C remark requires \"-C debuginfo=n\" to show source locations",
2314 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2316 ErrorOutputType::default(),
2317 "'--extern-private' is unstable and only \
2318 available for nightly builds of rustc."
2322 let extern_private = matches.opt_strs("extern-private");
2324 let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
2325 for arg in matches.opt_strs("extern").into_iter().chain(matches.opt_strs("extern-private")) {
2326 let mut parts = arg.splitn(2, '=');
2327 let name = parts.next().unwrap_or_else(||
2328 early_error(error_format, "--extern value must not be empty"));
2329 let location = parts.next().map(|s| s.to_string());
2330 if location.is_none() && !is_unstable_enabled {
2333 "the `-Z unstable-options` flag must also be passed to \
2334 enable `--extern crate_name` without `=path`",
2339 .entry(name.to_owned())
2344 let crate_name = matches.opt_str("crate-name");
2346 let remap_path_prefix = matches
2347 .opt_strs("remap-path-prefix")
2350 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2351 let to = parts.next();
2352 let from = parts.next();
2354 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2357 "--remap-path-prefix must contain '=' between FROM and TO",
2366 optimize: opt_level,
2371 output_types: OutputTypes(output_types),
2373 maybe_sysroot: sysroot_opt,
2382 externs: Externs(externs),
2386 unstable_features: UnstableFeatures::from_environment(),
2388 actually_rustdoc: false,
2389 cli_forced_codegen_units: codegen_units,
2390 cli_forced_thinlto_off: disable_thinlto,
2399 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2400 let mut crate_types: Vec<CrateType> = Vec::new();
2401 for unparsed_crate_type in &list_list {
2402 for part in unparsed_crate_type.split(',') {
2403 let new_part = match part {
2404 "lib" => default_lib_output(),
2405 "rlib" => CrateType::Rlib,
2406 "staticlib" => CrateType::Staticlib,
2407 "dylib" => CrateType::Dylib,
2408 "cdylib" => CrateType::Cdylib,
2409 "bin" => CrateType::Executable,
2410 "proc-macro" => CrateType::ProcMacro,
2411 _ => return Err(format!("unknown crate type: `{}`", part))
2413 if !crate_types.contains(&new_part) {
2414 crate_types.push(new_part)
2422 pub mod nightly_options {
2424 use syntax::feature_gate::UnstableFeatures;
2425 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2426 use crate::session::early_error;
2428 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2433 .any(|x| *x == "unstable-options")
2436 pub fn is_nightly_build() -> bool {
2437 UnstableFeatures::from_environment().is_nightly_build()
2440 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2441 let has_z_unstable_option = matches
2444 .any(|x| *x == "unstable-options");
2445 let really_allows_unstable_options =
2446 UnstableFeatures::from_environment().is_nightly_build();
2448 for opt in flags.iter() {
2449 if opt.stability == OptionStability::Stable {
2452 if !matches.opt_present(opt.name) {
2455 if opt.name != "Z" && !has_z_unstable_option {
2457 ErrorOutputType::default(),
2459 "the `-Z unstable-options` flag must also be passed to enable \
2465 if really_allows_unstable_options {
2468 match opt.stability {
2469 OptionStability::Unstable => {
2471 "the option `{}` is only accepted on the \
2475 early_error(ErrorOutputType::default(), &msg);
2477 OptionStability::Stable => {}
2483 impl fmt::Display for CrateType {
2484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2486 CrateType::Executable => "bin".fmt(f),
2487 CrateType::Dylib => "dylib".fmt(f),
2488 CrateType::Rlib => "rlib".fmt(f),
2489 CrateType::Staticlib => "staticlib".fmt(f),
2490 CrateType::Cdylib => "cdylib".fmt(f),
2491 CrateType::ProcMacro => "proc-macro".fmt(f),
2496 /// Command-line arguments passed to the compiler have to be incorporated with
2497 /// the dependency tracking system for incremental compilation. This module
2498 /// provides some utilities to make this more convenient.
2500 /// The values of all command-line arguments that are relevant for dependency
2501 /// tracking are hashed into a single value that determines whether the
2502 /// incremental compilation cache can be re-used or not. This hashing is done
2503 /// via the DepTrackingHash trait defined below, since the standard Hash
2504 /// implementation might not be suitable (e.g., arguments are stored in a Vec,
2505 /// the hash of which is order dependent, but we might not want the order of
2506 /// arguments to make a difference for the hash).
2508 /// However, since the value provided by Hash::hash often *is* suitable,
2509 /// especially for primitive types, there is the
2510 /// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
2511 /// Hash implementation for DepTrackingHash. It's important though that
2512 /// we have an opt-in scheme here, so one is hopefully forced to think about
2513 /// how the hash should be calculated when adding a new command-line argument.
2516 use crate::middle::cstore;
2517 use std::collections::BTreeMap;
2518 use std::hash::Hash;
2519 use std::path::PathBuf;
2520 use std::collections::hash_map::DefaultHasher;
2521 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2522 Passes, Sanitizer, LtoCli, LinkerPluginLto};
2523 use syntax::feature_gate::UnstableFeatures;
2524 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2525 use syntax::edition::Edition;
2527 pub trait DepTrackingHash {
2528 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2531 macro_rules! impl_dep_tracking_hash_via_hash {
2533 impl DepTrackingHash for $t {
2534 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2535 Hash::hash(self, hasher);
2541 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2543 impl DepTrackingHash for Vec<$t> {
2544 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2545 let mut elems: Vec<&$t> = self.iter().collect();
2547 Hash::hash(&elems.len(), hasher);
2548 for (index, elem) in elems.iter().enumerate() {
2549 Hash::hash(&index, hasher);
2550 DepTrackingHash::hash(*elem, hasher, error_format);
2557 impl_dep_tracking_hash_via_hash!(bool);
2558 impl_dep_tracking_hash_via_hash!(usize);
2559 impl_dep_tracking_hash_via_hash!(u64);
2560 impl_dep_tracking_hash_via_hash!(String);
2561 impl_dep_tracking_hash_via_hash!(PathBuf);
2562 impl_dep_tracking_hash_via_hash!(lint::Level);
2563 impl_dep_tracking_hash_via_hash!(Option<bool>);
2564 impl_dep_tracking_hash_via_hash!(Option<usize>);
2565 impl_dep_tracking_hash_via_hash!(Option<String>);
2566 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2567 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2568 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2569 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2570 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2571 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2572 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2573 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2574 impl_dep_tracking_hash_via_hash!(CrateType);
2575 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2576 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2577 impl_dep_tracking_hash_via_hash!(RelroLevel);
2578 impl_dep_tracking_hash_via_hash!(Passes);
2579 impl_dep_tracking_hash_via_hash!(OptLevel);
2580 impl_dep_tracking_hash_via_hash!(LtoCli);
2581 impl_dep_tracking_hash_via_hash!(DebugInfo);
2582 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2583 impl_dep_tracking_hash_via_hash!(OutputTypes);
2584 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2585 impl_dep_tracking_hash_via_hash!(Sanitizer);
2586 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2587 impl_dep_tracking_hash_via_hash!(TargetTriple);
2588 impl_dep_tracking_hash_via_hash!(Edition);
2589 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2591 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2592 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2593 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2594 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2595 impl_dep_tracking_hash_for_sortable_vec_of!((
2598 Option<cstore::NativeLibraryKind>
2600 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2602 impl<T1, T2> DepTrackingHash for (T1, T2)
2604 T1: DepTrackingHash,
2605 T2: DepTrackingHash,
2607 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2608 Hash::hash(&0, hasher);
2609 DepTrackingHash::hash(&self.0, hasher, error_format);
2610 Hash::hash(&1, hasher);
2611 DepTrackingHash::hash(&self.1, hasher, error_format);
2615 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2617 T1: DepTrackingHash,
2618 T2: DepTrackingHash,
2619 T3: DepTrackingHash,
2621 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2622 Hash::hash(&0, hasher);
2623 DepTrackingHash::hash(&self.0, hasher, error_format);
2624 Hash::hash(&1, hasher);
2625 DepTrackingHash::hash(&self.1, hasher, error_format);
2626 Hash::hash(&2, hasher);
2627 DepTrackingHash::hash(&self.2, hasher, error_format);
2631 // This is a stable hash because BTreeMap is a sorted container
2633 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2634 hasher: &mut DefaultHasher,
2635 error_format: ErrorOutputType,
2637 for (key, sub_hash) in sub_hashes {
2638 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2639 // the keys, as they are just plain strings
2640 Hash::hash(&key.len(), hasher);
2641 Hash::hash(key, hasher);
2642 sub_hash.hash(hasher, error_format);
2651 use crate::middle::cstore;
2652 use crate::session::config::{
2653 build_configuration,
2654 build_session_options_and_crate_config,
2657 use crate::session::config::{LtoCli, LinkerPluginLto};
2658 use crate::session::build_session;
2659 use crate::session::search_paths::SearchPath;
2660 use std::collections::{BTreeMap, BTreeSet};
2661 use std::iter::FromIterator;
2662 use std::path::PathBuf;
2663 use super::{Externs, OutputType, OutputTypes};
2664 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
2665 use syntax::symbol::Symbol;
2666 use syntax::edition::{Edition, DEFAULT_EDITION};
2670 fn optgroups() -> getopts::Options {
2671 let mut opts = getopts::Options::new();
2672 for group in super::rustc_optgroups() {
2673 (group.apply)(&mut opts);
2678 fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
2679 BTreeMap::from_iter(entries.into_iter())
2682 fn mk_set<V: Ord>(entries: Vec<V>) -> BTreeSet<V> {
2683 BTreeSet::from_iter(entries.into_iter())
2686 // When the user supplies --test we should implicitly supply --cfg test
2688 fn test_switch_implies_cfg_test() {
2689 syntax::with_globals(|| {
2690 let matches = &match optgroups().parse(&["--test".to_string()]) {
2692 Err(f) => panic!("test_switch_implies_cfg_test: {}", f),
2694 let registry = errors::registry::Registry::new(&[]);
2695 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2696 let sess = build_session(sessopts, None, registry);
2697 let cfg = build_configuration(&sess, to_crate_config(cfg));
2698 assert!(cfg.contains(&(Symbol::intern("test"), None)));
2702 // When the user supplies --test and --cfg test, don't implicitly add
2703 // another --cfg test
2705 fn test_switch_implies_cfg_test_unless_cfg_test() {
2706 syntax::with_globals(|| {
2707 let matches = &match optgroups().parse(&["--test".to_string(),
2708 "--cfg=test".to_string()]) {
2710 Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f),
2712 let registry = errors::registry::Registry::new(&[]);
2713 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2714 let sess = build_session(sessopts, None, registry);
2715 let cfg = build_configuration(&sess, to_crate_config(cfg));
2716 let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
2717 assert!(test_items.next().is_some());
2718 assert!(test_items.next().is_none());
2723 fn test_can_print_warnings() {
2724 syntax::with_globals(|| {
2725 let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
2726 let registry = errors::registry::Registry::new(&[]);
2727 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2728 let sess = build_session(sessopts, None, registry);
2729 assert!(!sess.diagnostic().flags.can_emit_warnings);
2732 syntax::with_globals(|| {
2733 let matches = optgroups()
2734 .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()])
2736 let registry = errors::registry::Registry::new(&[]);
2737 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2738 let sess = build_session(sessopts, None, registry);
2739 assert!(sess.diagnostic().flags.can_emit_warnings);
2742 syntax::with_globals(|| {
2743 let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
2744 let registry = errors::registry::Registry::new(&[]);
2745 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2746 let sess = build_session(sessopts, None, registry);
2747 assert!(sess.diagnostic().flags.can_emit_warnings);
2752 fn test_output_types_tracking_hash_different_paths() {
2753 let mut v1 = Options::default();
2754 let mut v2 = Options::default();
2755 let mut v3 = Options::default();
2758 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
2760 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
2761 v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
2763 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2764 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2765 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2768 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2769 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2770 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2774 fn test_output_types_tracking_hash_different_construction_order() {
2775 let mut v1 = Options::default();
2776 let mut v2 = Options::default();
2778 v1.output_types = OutputTypes::new(&[
2779 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2780 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2783 v2.output_types = OutputTypes::new(&[
2784 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2785 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2788 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2791 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2795 fn test_externs_tracking_hash_different_construction_order() {
2796 let mut v1 = Options::default();
2797 let mut v2 = Options::default();
2798 let mut v3 = Options::default();
2800 v1.externs = Externs::new(mk_map(vec![
2803 mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
2807 mk_set(vec![Some(String::from("e")), Some(String::from("f"))]),
2811 v2.externs = Externs::new(mk_map(vec![
2814 mk_set(vec![Some(String::from("e")), Some(String::from("f"))]),
2818 mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
2822 v3.externs = Externs::new(mk_map(vec![
2825 mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
2829 mk_set(vec![Some(String::from("f")), Some(String::from("e"))]),
2833 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2834 assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
2835 assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
2838 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2839 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2840 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2844 fn test_lints_tracking_hash_different_values() {
2845 let mut v1 = Options::default();
2846 let mut v2 = Options::default();
2847 let mut v3 = Options::default();
2849 v1.lint_opts = vec![
2850 (String::from("a"), lint::Allow),
2851 (String::from("b"), lint::Warn),
2852 (String::from("c"), lint::Deny),
2853 (String::from("d"), lint::Forbid),
2856 v2.lint_opts = vec![
2857 (String::from("a"), lint::Allow),
2858 (String::from("b"), lint::Warn),
2859 (String::from("X"), lint::Deny),
2860 (String::from("d"), lint::Forbid),
2863 v3.lint_opts = vec![
2864 (String::from("a"), lint::Allow),
2865 (String::from("b"), lint::Warn),
2866 (String::from("c"), lint::Forbid),
2867 (String::from("d"), lint::Deny),
2870 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2871 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2872 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2875 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2876 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2877 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2881 fn test_lints_tracking_hash_different_construction_order() {
2882 let mut v1 = Options::default();
2883 let mut v2 = Options::default();
2885 v1.lint_opts = vec![
2886 (String::from("a"), lint::Allow),
2887 (String::from("b"), lint::Warn),
2888 (String::from("c"), lint::Deny),
2889 (String::from("d"), lint::Forbid),
2892 v2.lint_opts = vec![
2893 (String::from("a"), lint::Allow),
2894 (String::from("c"), lint::Deny),
2895 (String::from("b"), lint::Warn),
2896 (String::from("d"), lint::Forbid),
2899 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2902 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2903 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2907 fn test_search_paths_tracking_hash_different_order() {
2908 let mut v1 = Options::default();
2909 let mut v2 = Options::default();
2910 let mut v3 = Options::default();
2911 let mut v4 = Options::default();
2913 const JSON: super::ErrorOutputType = super::ErrorOutputType::Json {
2915 json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never),
2920 .push(SearchPath::from_cli_opt("native=abc", JSON));
2922 .push(SearchPath::from_cli_opt("crate=def", JSON));
2924 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2926 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2928 .push(SearchPath::from_cli_opt("all=mno", JSON));
2931 .push(SearchPath::from_cli_opt("native=abc", JSON));
2933 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2935 .push(SearchPath::from_cli_opt("crate=def", JSON));
2937 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2939 .push(SearchPath::from_cli_opt("all=mno", JSON));
2942 .push(SearchPath::from_cli_opt("crate=def", JSON));
2944 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2946 .push(SearchPath::from_cli_opt("native=abc", JSON));
2948 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2950 .push(SearchPath::from_cli_opt("all=mno", JSON));
2953 .push(SearchPath::from_cli_opt("all=mno", JSON));
2955 .push(SearchPath::from_cli_opt("native=abc", JSON));
2957 .push(SearchPath::from_cli_opt("crate=def", JSON));
2959 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2961 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2963 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
2964 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
2965 assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
2968 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2969 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2970 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2971 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
2975 fn test_native_libs_tracking_hash_different_values() {
2976 let mut v1 = Options::default();
2977 let mut v2 = Options::default();
2978 let mut v3 = Options::default();
2979 let mut v4 = Options::default();
2983 (String::from("a"), None, Some(cstore::NativeStatic)),
2984 (String::from("b"), None, Some(cstore::NativeFramework)),
2985 (String::from("c"), None, Some(cstore::NativeUnknown)),
2990 (String::from("a"), None, Some(cstore::NativeStatic)),
2991 (String::from("X"), None, Some(cstore::NativeFramework)),
2992 (String::from("c"), None, Some(cstore::NativeUnknown)),
2997 (String::from("a"), None, Some(cstore::NativeStatic)),
2998 (String::from("b"), None, Some(cstore::NativeStatic)),
2999 (String::from("c"), None, Some(cstore::NativeUnknown)),
3004 (String::from("a"), None, Some(cstore::NativeStatic)),
3007 Some(String::from("X")),
3008 Some(cstore::NativeFramework),
3010 (String::from("c"), None, Some(cstore::NativeUnknown)),
3013 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
3014 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
3015 assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
3018 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3019 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3020 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3021 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
3025 fn test_native_libs_tracking_hash_different_order() {
3026 let mut v1 = Options::default();
3027 let mut v2 = Options::default();
3028 let mut v3 = Options::default();
3032 (String::from("a"), None, Some(cstore::NativeStatic)),
3033 (String::from("b"), None, Some(cstore::NativeFramework)),
3034 (String::from("c"), None, Some(cstore::NativeUnknown)),
3038 (String::from("b"), None, Some(cstore::NativeFramework)),
3039 (String::from("a"), None, Some(cstore::NativeStatic)),
3040 (String::from("c"), None, Some(cstore::NativeUnknown)),
3044 (String::from("c"), None, Some(cstore::NativeUnknown)),
3045 (String::from("a"), None, Some(cstore::NativeStatic)),
3046 (String::from("b"), None, Some(cstore::NativeFramework)),
3049 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
3050 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
3051 assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
3054 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3055 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3056 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3060 fn test_codegen_options_tracking_hash() {
3061 let reference = Options::default();
3062 let mut opts = Options::default();
3064 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3065 opts.cg.ar = Some(String::from("abc"));
3066 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3068 opts.cg.linker = Some(PathBuf::from("linker"));
3069 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3071 opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
3072 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3074 opts.cg.link_dead_code = true;
3075 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3077 opts.cg.rpath = true;
3078 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3080 opts.cg.extra_filename = String::from("extra-filename");
3081 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3083 opts.cg.codegen_units = Some(42);
3084 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3086 opts.cg.remark = super::Passes::Some(vec![String::from("pass1"), String::from("pass2")]);
3087 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3089 opts.cg.save_temps = true;
3090 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3092 opts.cg.incremental = Some(String::from("abc"));
3093 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3095 // Make sure changing a [TRACKED] option changes the hash
3096 opts = reference.clone();
3097 opts.cg.lto = LtoCli::Fat;
3098 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3100 opts = reference.clone();
3101 opts.cg.target_cpu = Some(String::from("abc"));
3102 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3104 opts = reference.clone();
3105 opts.cg.target_feature = String::from("all the features, all of them");
3106 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3108 opts = reference.clone();
3109 opts.cg.passes = vec![String::from("1"), String::from("2")];
3110 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3112 opts = reference.clone();
3113 opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
3114 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3116 opts = reference.clone();
3117 opts.cg.overflow_checks = Some(true);
3118 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3120 opts = reference.clone();
3121 opts.cg.no_prepopulate_passes = true;
3122 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3124 opts = reference.clone();
3125 opts.cg.no_vectorize_loops = true;
3126 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3128 opts = reference.clone();
3129 opts.cg.no_vectorize_slp = true;
3130 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3132 opts = reference.clone();
3133 opts.cg.soft_float = true;
3134 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3136 opts = reference.clone();
3137 opts.cg.prefer_dynamic = true;
3138 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3140 opts = reference.clone();
3141 opts.cg.no_integrated_as = true;
3142 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3144 opts = reference.clone();
3145 opts.cg.no_redzone = Some(true);
3146 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3148 opts = reference.clone();
3149 opts.cg.relocation_model = Some(String::from("relocation model"));
3150 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3152 opts = reference.clone();
3153 opts.cg.code_model = Some(String::from("code model"));
3154 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3156 opts = reference.clone();
3157 opts.debugging_opts.tls_model = Some(String::from("tls model"));
3158 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3160 opts = reference.clone();
3161 opts.debugging_opts.pgo_gen = Some(String::from("abc"));
3162 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3164 opts = reference.clone();
3165 opts.debugging_opts.pgo_use = String::from("abc");
3166 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3168 opts = reference.clone();
3169 opts.cg.metadata = vec![String::from("A"), String::from("B")];
3170 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3172 opts = reference.clone();
3173 opts.cg.debuginfo = Some(0xdeadbeef);
3174 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3176 opts = reference.clone();
3177 opts.cg.debuginfo = Some(0xba5eba11);
3178 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3180 opts = reference.clone();
3181 opts.cg.force_frame_pointers = Some(false);
3182 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3184 opts = reference.clone();
3185 opts.cg.debug_assertions = Some(true);
3186 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3188 opts = reference.clone();
3189 opts.cg.inline_threshold = Some(0xf007ba11);
3190 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3192 opts = reference.clone();
3193 opts.cg.panic = Some(PanicStrategy::Abort);
3194 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3196 opts = reference.clone();
3197 opts.cg.linker_plugin_lto = LinkerPluginLto::LinkerPluginAuto;
3198 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3202 fn test_debugging_options_tracking_hash() {
3203 let reference = Options::default();
3204 let mut opts = Options::default();
3206 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3207 opts.debugging_opts.verbose = true;
3208 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3209 opts.debugging_opts.time_passes = true;
3210 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3211 opts.debugging_opts.count_llvm_insns = true;
3212 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3213 opts.debugging_opts.time_llvm_passes = true;
3214 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3215 opts.debugging_opts.input_stats = true;
3216 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3217 opts.debugging_opts.codegen_stats = true;
3218 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3219 opts.debugging_opts.borrowck_stats = true;
3220 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3221 opts.debugging_opts.meta_stats = true;
3222 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3223 opts.debugging_opts.print_link_args = true;
3224 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3225 opts.debugging_opts.print_llvm_passes = true;
3226 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3227 opts.debugging_opts.ast_json = true;
3228 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3229 opts.debugging_opts.ast_json_noexpand = true;
3230 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3231 opts.debugging_opts.ls = true;
3232 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3233 opts.debugging_opts.save_analysis = true;
3234 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3235 opts.debugging_opts.flowgraph_print_loans = true;
3236 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3237 opts.debugging_opts.flowgraph_print_moves = true;
3238 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3239 opts.debugging_opts.flowgraph_print_assigns = true;
3240 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3241 opts.debugging_opts.flowgraph_print_all = true;
3242 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3243 opts.debugging_opts.print_region_graph = true;
3244 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3245 opts.debugging_opts.parse_only = true;
3246 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3247 opts.debugging_opts.incremental = Some(String::from("abc"));
3248 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3249 opts.debugging_opts.dump_dep_graph = true;
3250 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3251 opts.debugging_opts.query_dep_graph = true;
3252 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3253 opts.debugging_opts.no_analysis = true;
3254 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3255 opts.debugging_opts.unstable_options = true;
3256 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3257 opts.debugging_opts.trace_macros = true;
3258 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3259 opts.debugging_opts.keep_hygiene_data = true;
3260 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3261 opts.debugging_opts.keep_ast = true;
3262 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3263 opts.debugging_opts.print_mono_items = Some(String::from("abc"));
3264 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3265 opts.debugging_opts.dump_mir = Some(String::from("abc"));
3266 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3267 opts.debugging_opts.dump_mir_dir = String::from("abc");
3268 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3269 opts.debugging_opts.dump_mir_graphviz = true;
3270 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3272 // Make sure changing a [TRACKED] option changes the hash
3273 opts = reference.clone();
3274 opts.debugging_opts.asm_comments = true;
3275 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3277 opts = reference.clone();
3278 opts.debugging_opts.verify_llvm_ir = true;
3279 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3281 opts = reference.clone();
3282 opts.debugging_opts.no_landing_pads = true;
3283 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3285 opts = reference.clone();
3286 opts.debugging_opts.fewer_names = true;
3287 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3289 opts = reference.clone();
3290 opts.debugging_opts.no_codegen = true;
3291 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3293 opts = reference.clone();
3294 opts.debugging_opts.treat_err_as_bug = Some(1);
3295 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3297 opts = reference.clone();
3298 opts.debugging_opts.report_delayed_bugs = true;
3299 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3301 opts = reference.clone();
3302 opts.debugging_opts.continue_parse_after_error = true;
3303 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3305 opts = reference.clone();
3306 opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
3307 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3309 opts = reference.clone();
3310 opts.debugging_opts.force_overflow_checks = Some(true);
3311 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3313 opts = reference.clone();
3314 opts.debugging_opts.show_span = Some(String::from("abc"));
3315 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3317 opts = reference.clone();
3318 opts.debugging_opts.mir_opt_level = 3;
3319 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3321 opts = reference.clone();
3322 opts.debugging_opts.relro_level = Some(RelroLevel::Full);
3323 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3325 opts = reference.clone();
3326 opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
3327 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3329 opts = reference.clone();
3330 opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
3331 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3335 fn test_edition_parsing() {
3336 // test default edition
3337 let options = Options::default();
3338 assert!(options.edition == DEFAULT_EDITION);
3340 let matches = optgroups()
3341 .parse(&["--edition=2018".to_string()])
3343 let (sessopts, _) = build_session_options_and_crate_config(&matches);
3344 assert!(sessopts.edition == Edition::Edition2018)