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;
23 use errors::{ColorConfig, FatalError, Handler};
26 use std::collections::{BTreeMap, BTreeSet};
27 use std::collections::btree_map::Iter as BTreeMapIter;
28 use std::collections::btree_map::Keys as BTreeMapKeysIter;
29 use std::collections::btree_map::Values as BTreeMapValuesIter;
31 use rustc_data_structures::fx::FxHashSet;
33 use std::hash::Hasher;
34 use std::collections::hash_map::DefaultHasher;
35 use std::iter::FromIterator;
36 use std::path::{Path, PathBuf};
44 #[derive(Clone, Hash, Debug)]
52 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
62 impl_stable_hash_via_hash!(OptLevel);
64 /// This is what the `LtoCli` values get mapped to after resolving defaults and
65 /// and taking other command line options into account.
66 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
68 /// Don't do any LTO whatsoever
71 /// Do a full crate graph LTO with ThinLTO
74 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
78 /// Do a full crate graph LTO with "fat" LTO
82 /// The different settings that the `-C lto` flag can have.
83 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
95 /// No `-C lto` flag passed
99 #[derive(Clone, PartialEq, Hash)]
100 pub enum LinkerPluginLto {
101 LinkerPlugin(PathBuf),
106 impl LinkerPluginLto {
107 pub fn enabled(&self) -> bool {
109 LinkerPluginLto::LinkerPlugin(_) |
110 LinkerPluginLto::LinkerPluginAuto => true,
111 LinkerPluginLto::Disabled => false,
116 #[derive(Clone, Copy, PartialEq, Hash)]
123 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
124 pub enum OutputType {
135 impl_stable_hash_via_hash!(OutputType);
138 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
140 OutputType::Exe | OutputType::DepInfo => true,
142 | OutputType::Assembly
143 | OutputType::LlvmAssembly
146 | OutputType::Metadata => false,
150 fn shorthand(&self) -> &'static str {
152 OutputType::Bitcode => "llvm-bc",
153 OutputType::Assembly => "asm",
154 OutputType::LlvmAssembly => "llvm-ir",
155 OutputType::Mir => "mir",
156 OutputType::Object => "obj",
157 OutputType::Metadata => "metadata",
158 OutputType::Exe => "link",
159 OutputType::DepInfo => "dep-info",
163 fn from_shorthand(shorthand: &str) -> Option<Self> {
164 Some(match shorthand {
165 "asm" => OutputType::Assembly,
166 "llvm-ir" => OutputType::LlvmAssembly,
167 "mir" => OutputType::Mir,
168 "llvm-bc" => OutputType::Bitcode,
169 "obj" => OutputType::Object,
170 "metadata" => OutputType::Metadata,
171 "link" => OutputType::Exe,
172 "dep-info" => OutputType::DepInfo,
177 fn shorthands_display() -> String {
179 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
180 OutputType::Bitcode.shorthand(),
181 OutputType::Assembly.shorthand(),
182 OutputType::LlvmAssembly.shorthand(),
183 OutputType::Mir.shorthand(),
184 OutputType::Object.shorthand(),
185 OutputType::Metadata.shorthand(),
186 OutputType::Exe.shorthand(),
187 OutputType::DepInfo.shorthand(),
191 pub fn extension(&self) -> &'static str {
193 OutputType::Bitcode => "bc",
194 OutputType::Assembly => "s",
195 OutputType::LlvmAssembly => "ll",
196 OutputType::Mir => "mir",
197 OutputType::Object => "o",
198 OutputType::Metadata => "rmeta",
199 OutputType::DepInfo => "d",
200 OutputType::Exe => "",
205 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
206 pub enum ErrorOutputType {
207 HumanReadable(ColorConfig),
209 /// Render the json in a human readable way (with indents and newlines)
211 /// The `rendered` field with the command line diagnostics include color codes
212 colorful_rendered: bool,
217 impl Default for ErrorOutputType {
218 fn default() -> ErrorOutputType {
219 ErrorOutputType::HumanReadable(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 colorful_json: bool = (false, parse_bool, [UNTRACKED],
1354 "encode color codes in 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 "Emit ansi color codes to the `rendered` field of json diagnostics",
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 colorful_rendered = matches.opt_present("colorful-json");
1956 // We need the opts_present check because the driver will send us Matches
1957 // with only stable options if no unstable options are used. Since error-format
1958 // is unstable, it will not be present. We have to use opts_present not
1959 // opt_present because the latter will panic.
1960 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1961 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1962 Some("human") => ErrorOutputType::HumanReadable(color),
1963 Some("json") => ErrorOutputType::Json { pretty: false, colorful_rendered },
1964 Some("pretty-json") => ErrorOutputType::Json { pretty: true, colorful_rendered },
1965 Some("short") => ErrorOutputType::Short(color),
1966 None => ErrorOutputType::HumanReadable(color),
1968 Some(arg) => early_error(
1969 ErrorOutputType::HumanReadable(color),
1971 "argument for --error-format must be `human`, `json` or \
1972 `short` (instead was `{}`)",
1978 ErrorOutputType::HumanReadable(color)
1981 let unparsed_crate_types = matches.opt_strs("crate-type");
1982 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1983 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1986 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1988 let mut debugging_opts = build_debugging_options(matches, error_format);
1990 if !debugging_opts.unstable_options {
1991 if colorful_rendered {
1992 early_error(error_format, "--colorful-json=true is unstable");
1994 if let ErrorOutputType::Json { pretty: true, .. } = error_format {
1996 ErrorOutputType::Json { pretty: false, colorful_rendered: false },
1997 "--error-format=pretty-json is unstable",
2002 if debugging_opts.pgo_gen.is_some() && !debugging_opts.pgo_use.is_empty() {
2005 "options `-Z pgo-gen` and `-Z pgo-use` are exclusive",
2009 let mut output_types = BTreeMap::new();
2010 if !debugging_opts.parse_only {
2011 for list in matches.opt_strs("emit") {
2012 for output_type in list.split(',') {
2013 let mut parts = output_type.splitn(2, '=');
2014 let shorthand = parts.next().unwrap();
2015 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2019 "unknown emission type: `{}` - expected one of: {}",
2021 OutputType::shorthands_display(),
2025 let path = parts.next().map(PathBuf::from);
2026 output_types.insert(output_type, path);
2030 if output_types.is_empty() {
2031 output_types.insert(OutputType::Exe, None);
2034 let mut cg = build_codegen_options(matches, error_format);
2035 let mut codegen_units = cg.codegen_units;
2036 let mut disable_thinlto = false;
2038 // Issue #30063: if user requests llvm-related output to one
2039 // particular path, disable codegen-units.
2040 let incompatible: Vec<_> = output_types
2042 .map(|ot_path| ot_path.0)
2043 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2044 .map(|ot| ot.shorthand())
2046 if !incompatible.is_empty() {
2047 match codegen_units {
2048 Some(n) if n > 1 => {
2049 if matches.opt_present("o") {
2050 for ot in &incompatible {
2054 "--emit={} with -o incompatible with \
2055 -C codegen-units=N for N > 1",
2060 early_warn(error_format, "resetting to default -C codegen-units=1");
2061 codegen_units = Some(1);
2062 disable_thinlto = true;
2066 codegen_units = Some(1);
2067 disable_thinlto = true;
2072 if debugging_opts.threads == Some(0) {
2075 "Value for threads must be a positive nonzero integer",
2079 if debugging_opts.threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() {
2082 "Optimization fuel is incompatible with multiple threads",
2086 if codegen_units == Some(0) {
2089 "Value for codegen units must be a positive nonzero integer",
2093 let incremental = match (&debugging_opts.incremental, &cg.incremental) {
2094 (&Some(ref path1), &Some(ref path2)) => {
2099 "conflicting paths for `-Z incremental` and \
2100 `-C incremental` specified: {} versus {}",
2108 (&Some(ref path), &None) => Some(path),
2109 (&None, &Some(ref path)) => Some(path),
2110 (&None, &None) => None,
2111 }.map(|m| PathBuf::from(m));
2113 if debugging_opts.profile && incremental.is_some() {
2116 "can't instrument with gcov profiling when compiling incrementally",
2120 let mut prints = Vec::<PrintRequest>::new();
2121 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2122 prints.push(PrintRequest::TargetCPUs);
2123 cg.target_cpu = None;
2125 if cg.target_feature == "help" {
2126 prints.push(PrintRequest::TargetFeatures);
2127 cg.target_feature = String::new();
2129 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2130 prints.push(PrintRequest::RelocationModels);
2131 cg.relocation_model = None;
2133 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2134 prints.push(PrintRequest::CodeModels);
2135 cg.code_model = None;
2140 .map_or(false, |s| s == "help")
2142 prints.push(PrintRequest::TlsModels);
2143 debugging_opts.tls_model = None;
2148 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2149 let target_triple = if let Some(target) = matches.opt_str("target") {
2150 if target.ends_with(".json") {
2151 let path = Path::new(&target);
2152 TargetTriple::from_path(&path).unwrap_or_else(|_|
2153 early_error(error_format, &format!("target file {:?} does not exist", path)))
2155 TargetTriple::TargetTriple(target)
2158 TargetTriple::from_triple(host_triple())
2161 if matches.opt_present("O") {
2162 if cg.opt_level.is_some() {
2163 early_error(error_format, "-O and -C opt-level both provided");
2167 match cg.opt_level.as_ref().map(String::as_ref) {
2168 None => OptLevel::No,
2169 Some("0") => OptLevel::No,
2170 Some("1") => OptLevel::Less,
2171 Some("2") => OptLevel::Default,
2172 Some("3") => OptLevel::Aggressive,
2173 Some("s") => OptLevel::Size,
2174 Some("z") => OptLevel::SizeMin,
2179 "optimization level needs to be \
2180 between 0-3, s or z (instead was `{}`)",
2188 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2189 let debuginfo = if matches.opt_present("g") {
2190 if cg.debuginfo.is_some() {
2191 early_error(error_format, "-g and -C debuginfo both provided");
2195 match cg.debuginfo {
2196 None | Some(0) => DebugInfo::None,
2197 Some(1) => DebugInfo::Limited,
2198 Some(2) => DebugInfo::Full,
2203 "debug info level needs to be between \
2204 0-2 (instead was `{}`)",
2212 let mut search_paths = vec![];
2213 for s in &matches.opt_strs("L") {
2214 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2221 // Parse string of the form "[KIND=]lib[:new_name]",
2222 // where KIND is one of "dylib", "framework", "static".
2223 let mut parts = s.splitn(2, '=');
2224 let kind = parts.next().unwrap();
2225 let (name, kind) = match (parts.next(), kind) {
2226 (None, name) => (name, None),
2227 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2228 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2229 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2230 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2235 "unknown library kind `{}`, expected \
2236 one of dylib, framework, or static",
2242 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2246 "the library kind 'static-nobundle' is only \
2247 accepted on the nightly compiler"
2251 let mut name_parts = name.splitn(2, ':');
2252 let name = name_parts.next().unwrap();
2253 let new_name = name_parts.next();
2254 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2258 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
2259 let test = matches.opt_present("test");
2261 let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
2263 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2264 "crate-name" => PrintRequest::CrateName,
2265 "file-names" => PrintRequest::FileNames,
2266 "sysroot" => PrintRequest::Sysroot,
2267 "cfg" => PrintRequest::Cfg,
2268 "target-list" => PrintRequest::TargetList,
2269 "target-cpus" => PrintRequest::TargetCPUs,
2270 "target-features" => PrintRequest::TargetFeatures,
2271 "relocation-models" => PrintRequest::RelocationModels,
2272 "code-models" => PrintRequest::CodeModels,
2273 "tls-models" => PrintRequest::TlsModels,
2274 "native-static-libs" => PrintRequest::NativeStaticLibs,
2275 "target-spec-json" => {
2276 if is_unstable_enabled {
2277 PrintRequest::TargetSpec
2281 "the `-Z unstable-options` flag must also be passed to \
2282 enable the target-spec-json print option",
2286 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2289 let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) {
2290 None | Some("ast") => BorrowckMode::Ast,
2291 Some("mir") => BorrowckMode::Mir,
2292 Some("compare") => BorrowckMode::Compare,
2293 Some("migrate") => BorrowckMode::Migrate,
2294 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2297 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2300 "-C remark requires \"-C debuginfo=n\" to show source locations",
2304 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2306 ErrorOutputType::default(),
2307 "'--extern-private' is unstable and only \
2308 available for nightly builds of rustc."
2312 let extern_private = matches.opt_strs("extern-private");
2314 let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
2315 for arg in matches.opt_strs("extern").into_iter().chain(matches.opt_strs("extern-private")) {
2316 let mut parts = arg.splitn(2, '=');
2317 let name = parts.next().unwrap_or_else(||
2318 early_error(error_format, "--extern value must not be empty"));
2319 let location = parts.next().map(|s| s.to_string());
2320 if location.is_none() && !is_unstable_enabled {
2323 "the `-Z unstable-options` flag must also be passed to \
2324 enable `--extern crate_name` without `=path`",
2329 .entry(name.to_owned())
2334 let crate_name = matches.opt_str("crate-name");
2336 let remap_path_prefix = matches
2337 .opt_strs("remap-path-prefix")
2340 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2341 let to = parts.next();
2342 let from = parts.next();
2344 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2347 "--remap-path-prefix must contain '=' between FROM and TO",
2356 optimize: opt_level,
2361 output_types: OutputTypes(output_types),
2363 maybe_sysroot: sysroot_opt,
2372 externs: Externs(externs),
2376 unstable_features: UnstableFeatures::from_environment(),
2378 actually_rustdoc: false,
2379 cli_forced_codegen_units: codegen_units,
2380 cli_forced_thinlto_off: disable_thinlto,
2389 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2390 let mut crate_types: Vec<CrateType> = Vec::new();
2391 for unparsed_crate_type in &list_list {
2392 for part in unparsed_crate_type.split(',') {
2393 let new_part = match part {
2394 "lib" => default_lib_output(),
2395 "rlib" => CrateType::Rlib,
2396 "staticlib" => CrateType::Staticlib,
2397 "dylib" => CrateType::Dylib,
2398 "cdylib" => CrateType::Cdylib,
2399 "bin" => CrateType::Executable,
2400 "proc-macro" => CrateType::ProcMacro,
2401 _ => return Err(format!("unknown crate type: `{}`", part))
2403 if !crate_types.contains(&new_part) {
2404 crate_types.push(new_part)
2412 pub mod nightly_options {
2414 use syntax::feature_gate::UnstableFeatures;
2415 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2416 use crate::session::early_error;
2418 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2423 .any(|x| *x == "unstable-options")
2426 pub fn is_nightly_build() -> bool {
2427 UnstableFeatures::from_environment().is_nightly_build()
2430 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2431 let has_z_unstable_option = matches
2434 .any(|x| *x == "unstable-options");
2435 let really_allows_unstable_options =
2436 UnstableFeatures::from_environment().is_nightly_build();
2438 for opt in flags.iter() {
2439 if opt.stability == OptionStability::Stable {
2442 if !matches.opt_present(opt.name) {
2445 if opt.name != "Z" && !has_z_unstable_option {
2447 ErrorOutputType::default(),
2449 "the `-Z unstable-options` flag must also be passed to enable \
2455 if really_allows_unstable_options {
2458 match opt.stability {
2459 OptionStability::Unstable => {
2461 "the option `{}` is only accepted on the \
2465 early_error(ErrorOutputType::default(), &msg);
2467 OptionStability::Stable => {}
2473 impl fmt::Display for CrateType {
2474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2476 CrateType::Executable => "bin".fmt(f),
2477 CrateType::Dylib => "dylib".fmt(f),
2478 CrateType::Rlib => "rlib".fmt(f),
2479 CrateType::Staticlib => "staticlib".fmt(f),
2480 CrateType::Cdylib => "cdylib".fmt(f),
2481 CrateType::ProcMacro => "proc-macro".fmt(f),
2486 /// Command-line arguments passed to the compiler have to be incorporated with
2487 /// the dependency tracking system for incremental compilation. This module
2488 /// provides some utilities to make this more convenient.
2490 /// The values of all command-line arguments that are relevant for dependency
2491 /// tracking are hashed into a single value that determines whether the
2492 /// incremental compilation cache can be re-used or not. This hashing is done
2493 /// via the DepTrackingHash trait defined below, since the standard Hash
2494 /// implementation might not be suitable (e.g., arguments are stored in a Vec,
2495 /// the hash of which is order dependent, but we might not want the order of
2496 /// arguments to make a difference for the hash).
2498 /// However, since the value provided by Hash::hash often *is* suitable,
2499 /// especially for primitive types, there is the
2500 /// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
2501 /// Hash implementation for DepTrackingHash. It's important though that
2502 /// we have an opt-in scheme here, so one is hopefully forced to think about
2503 /// how the hash should be calculated when adding a new command-line argument.
2506 use crate::middle::cstore;
2507 use std::collections::BTreeMap;
2508 use std::hash::Hash;
2509 use std::path::PathBuf;
2510 use std::collections::hash_map::DefaultHasher;
2511 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2512 Passes, Sanitizer, LtoCli, LinkerPluginLto};
2513 use syntax::feature_gate::UnstableFeatures;
2514 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2515 use syntax::edition::Edition;
2517 pub trait DepTrackingHash {
2518 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2521 macro_rules! impl_dep_tracking_hash_via_hash {
2523 impl DepTrackingHash for $t {
2524 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2525 Hash::hash(self, hasher);
2531 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2533 impl DepTrackingHash for Vec<$t> {
2534 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2535 let mut elems: Vec<&$t> = self.iter().collect();
2537 Hash::hash(&elems.len(), hasher);
2538 for (index, elem) in elems.iter().enumerate() {
2539 Hash::hash(&index, hasher);
2540 DepTrackingHash::hash(*elem, hasher, error_format);
2547 impl_dep_tracking_hash_via_hash!(bool);
2548 impl_dep_tracking_hash_via_hash!(usize);
2549 impl_dep_tracking_hash_via_hash!(u64);
2550 impl_dep_tracking_hash_via_hash!(String);
2551 impl_dep_tracking_hash_via_hash!(PathBuf);
2552 impl_dep_tracking_hash_via_hash!(lint::Level);
2553 impl_dep_tracking_hash_via_hash!(Option<bool>);
2554 impl_dep_tracking_hash_via_hash!(Option<usize>);
2555 impl_dep_tracking_hash_via_hash!(Option<String>);
2556 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2557 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2558 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2559 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2560 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2561 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2562 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2563 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2564 impl_dep_tracking_hash_via_hash!(CrateType);
2565 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2566 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2567 impl_dep_tracking_hash_via_hash!(RelroLevel);
2568 impl_dep_tracking_hash_via_hash!(Passes);
2569 impl_dep_tracking_hash_via_hash!(OptLevel);
2570 impl_dep_tracking_hash_via_hash!(LtoCli);
2571 impl_dep_tracking_hash_via_hash!(DebugInfo);
2572 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2573 impl_dep_tracking_hash_via_hash!(OutputTypes);
2574 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2575 impl_dep_tracking_hash_via_hash!(Sanitizer);
2576 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2577 impl_dep_tracking_hash_via_hash!(TargetTriple);
2578 impl_dep_tracking_hash_via_hash!(Edition);
2579 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2581 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2582 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2583 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2584 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2585 impl_dep_tracking_hash_for_sortable_vec_of!((
2588 Option<cstore::NativeLibraryKind>
2590 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2592 impl<T1, T2> DepTrackingHash for (T1, T2)
2594 T1: DepTrackingHash,
2595 T2: DepTrackingHash,
2597 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2598 Hash::hash(&0, hasher);
2599 DepTrackingHash::hash(&self.0, hasher, error_format);
2600 Hash::hash(&1, hasher);
2601 DepTrackingHash::hash(&self.1, hasher, error_format);
2605 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2607 T1: DepTrackingHash,
2608 T2: DepTrackingHash,
2609 T3: DepTrackingHash,
2611 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2612 Hash::hash(&0, hasher);
2613 DepTrackingHash::hash(&self.0, hasher, error_format);
2614 Hash::hash(&1, hasher);
2615 DepTrackingHash::hash(&self.1, hasher, error_format);
2616 Hash::hash(&2, hasher);
2617 DepTrackingHash::hash(&self.2, hasher, error_format);
2621 // This is a stable hash because BTreeMap is a sorted container
2623 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2624 hasher: &mut DefaultHasher,
2625 error_format: ErrorOutputType,
2627 for (key, sub_hash) in sub_hashes {
2628 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2629 // the keys, as they are just plain strings
2630 Hash::hash(&key.len(), hasher);
2631 Hash::hash(key, hasher);
2632 sub_hash.hash(hasher, error_format);
2641 use crate::middle::cstore;
2642 use crate::session::config::{
2643 build_configuration,
2644 build_session_options_and_crate_config,
2647 use crate::session::config::{LtoCli, LinkerPluginLto};
2648 use crate::session::build_session;
2649 use crate::session::search_paths::SearchPath;
2650 use std::collections::{BTreeMap, BTreeSet};
2651 use std::iter::FromIterator;
2652 use std::path::PathBuf;
2653 use super::{Externs, OutputType, OutputTypes};
2654 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
2655 use syntax::symbol::Symbol;
2656 use syntax::edition::{Edition, DEFAULT_EDITION};
2660 fn optgroups() -> getopts::Options {
2661 let mut opts = getopts::Options::new();
2662 for group in super::rustc_optgroups() {
2663 (group.apply)(&mut opts);
2668 fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
2669 BTreeMap::from_iter(entries.into_iter())
2672 fn mk_set<V: Ord>(entries: Vec<V>) -> BTreeSet<V> {
2673 BTreeSet::from_iter(entries.into_iter())
2676 // When the user supplies --test we should implicitly supply --cfg test
2678 fn test_switch_implies_cfg_test() {
2679 syntax::with_globals(|| {
2680 let matches = &match optgroups().parse(&["--test".to_string()]) {
2682 Err(f) => panic!("test_switch_implies_cfg_test: {}", f),
2684 let registry = errors::registry::Registry::new(&[]);
2685 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2686 let sess = build_session(sessopts, None, registry);
2687 let cfg = build_configuration(&sess, to_crate_config(cfg));
2688 assert!(cfg.contains(&(Symbol::intern("test"), None)));
2692 // When the user supplies --test and --cfg test, don't implicitly add
2693 // another --cfg test
2695 fn test_switch_implies_cfg_test_unless_cfg_test() {
2696 syntax::with_globals(|| {
2697 let matches = &match optgroups().parse(&["--test".to_string(),
2698 "--cfg=test".to_string()]) {
2700 Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f),
2702 let registry = errors::registry::Registry::new(&[]);
2703 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2704 let sess = build_session(sessopts, None, registry);
2705 let cfg = build_configuration(&sess, to_crate_config(cfg));
2706 let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
2707 assert!(test_items.next().is_some());
2708 assert!(test_items.next().is_none());
2713 fn test_can_print_warnings() {
2714 syntax::with_globals(|| {
2715 let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
2716 let registry = errors::registry::Registry::new(&[]);
2717 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2718 let sess = build_session(sessopts, None, registry);
2719 assert!(!sess.diagnostic().flags.can_emit_warnings);
2722 syntax::with_globals(|| {
2723 let matches = optgroups()
2724 .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()])
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().parse(&["-Adead_code".to_string()]).unwrap();
2734 let registry = errors::registry::Registry::new(&[]);
2735 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2736 let sess = build_session(sessopts, None, registry);
2737 assert!(sess.diagnostic().flags.can_emit_warnings);
2742 fn test_output_types_tracking_hash_different_paths() {
2743 let mut v1 = Options::default();
2744 let mut v2 = Options::default();
2745 let mut v3 = Options::default();
2748 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
2750 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
2751 v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
2753 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2754 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2755 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2758 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2759 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2760 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2764 fn test_output_types_tracking_hash_different_construction_order() {
2765 let mut v1 = Options::default();
2766 let mut v2 = Options::default();
2768 v1.output_types = OutputTypes::new(&[
2769 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2770 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2773 v2.output_types = OutputTypes::new(&[
2774 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2775 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2778 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2781 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2785 fn test_externs_tracking_hash_different_construction_order() {
2786 let mut v1 = Options::default();
2787 let mut v2 = Options::default();
2788 let mut v3 = Options::default();
2790 v1.externs = Externs::new(mk_map(vec![
2793 mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
2797 mk_set(vec![Some(String::from("e")), Some(String::from("f"))]),
2801 v2.externs = Externs::new(mk_map(vec![
2804 mk_set(vec![Some(String::from("e")), Some(String::from("f"))]),
2808 mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
2812 v3.externs = Externs::new(mk_map(vec![
2815 mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
2819 mk_set(vec![Some(String::from("f")), Some(String::from("e"))]),
2823 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2824 assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
2825 assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
2828 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2829 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2830 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2834 fn test_lints_tracking_hash_different_values() {
2835 let mut v1 = Options::default();
2836 let mut v2 = Options::default();
2837 let mut v3 = Options::default();
2839 v1.lint_opts = vec![
2840 (String::from("a"), lint::Allow),
2841 (String::from("b"), lint::Warn),
2842 (String::from("c"), lint::Deny),
2843 (String::from("d"), lint::Forbid),
2846 v2.lint_opts = vec![
2847 (String::from("a"), lint::Allow),
2848 (String::from("b"), lint::Warn),
2849 (String::from("X"), lint::Deny),
2850 (String::from("d"), lint::Forbid),
2853 v3.lint_opts = vec![
2854 (String::from("a"), lint::Allow),
2855 (String::from("b"), lint::Warn),
2856 (String::from("c"), lint::Forbid),
2857 (String::from("d"), lint::Deny),
2860 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2861 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2862 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2865 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2866 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2867 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2871 fn test_lints_tracking_hash_different_construction_order() {
2872 let mut v1 = Options::default();
2873 let mut v2 = Options::default();
2875 v1.lint_opts = vec![
2876 (String::from("a"), lint::Allow),
2877 (String::from("b"), lint::Warn),
2878 (String::from("c"), lint::Deny),
2879 (String::from("d"), lint::Forbid),
2882 v2.lint_opts = vec![
2883 (String::from("a"), lint::Allow),
2884 (String::from("c"), lint::Deny),
2885 (String::from("b"), lint::Warn),
2886 (String::from("d"), lint::Forbid),
2889 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2892 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2893 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2897 fn test_search_paths_tracking_hash_different_order() {
2898 let mut v1 = Options::default();
2899 let mut v2 = Options::default();
2900 let mut v3 = Options::default();
2901 let mut v4 = Options::default();
2903 const JSON: super::ErrorOutputType = super::ErrorOutputType::Json {
2905 colorful_rendered: false,
2910 .push(SearchPath::from_cli_opt("native=abc", JSON));
2912 .push(SearchPath::from_cli_opt("crate=def", JSON));
2914 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2916 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2918 .push(SearchPath::from_cli_opt("all=mno", JSON));
2921 .push(SearchPath::from_cli_opt("native=abc", JSON));
2923 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2925 .push(SearchPath::from_cli_opt("crate=def", JSON));
2927 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2929 .push(SearchPath::from_cli_opt("all=mno", JSON));
2932 .push(SearchPath::from_cli_opt("crate=def", JSON));
2934 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2936 .push(SearchPath::from_cli_opt("native=abc", JSON));
2938 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2940 .push(SearchPath::from_cli_opt("all=mno", JSON));
2943 .push(SearchPath::from_cli_opt("all=mno", json));
2945 .push(SearchPath::from_cli_opt("native=abc", json));
2947 .push(SearchPath::from_cli_opt("crate=def", json));
2949 .push(SearchPath::from_cli_opt("dependency=ghi", json));
2951 .push(SearchPath::from_cli_opt("framework=jkl", json));
2953 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
2954 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
2955 assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
2958 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2959 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2960 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2961 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
2965 fn test_native_libs_tracking_hash_different_values() {
2966 let mut v1 = Options::default();
2967 let mut v2 = Options::default();
2968 let mut v3 = Options::default();
2969 let mut v4 = Options::default();
2973 (String::from("a"), None, Some(cstore::NativeStatic)),
2974 (String::from("b"), None, Some(cstore::NativeFramework)),
2975 (String::from("c"), None, Some(cstore::NativeUnknown)),
2980 (String::from("a"), None, Some(cstore::NativeStatic)),
2981 (String::from("X"), None, Some(cstore::NativeFramework)),
2982 (String::from("c"), None, Some(cstore::NativeUnknown)),
2987 (String::from("a"), None, Some(cstore::NativeStatic)),
2988 (String::from("b"), None, Some(cstore::NativeStatic)),
2989 (String::from("c"), None, Some(cstore::NativeUnknown)),
2994 (String::from("a"), None, Some(cstore::NativeStatic)),
2997 Some(String::from("X")),
2998 Some(cstore::NativeFramework),
3000 (String::from("c"), None, Some(cstore::NativeUnknown)),
3003 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
3004 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
3005 assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
3008 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3009 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3010 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3011 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
3015 fn test_native_libs_tracking_hash_different_order() {
3016 let mut v1 = Options::default();
3017 let mut v2 = Options::default();
3018 let mut v3 = Options::default();
3022 (String::from("a"), None, Some(cstore::NativeStatic)),
3023 (String::from("b"), None, Some(cstore::NativeFramework)),
3024 (String::from("c"), None, Some(cstore::NativeUnknown)),
3028 (String::from("b"), None, Some(cstore::NativeFramework)),
3029 (String::from("a"), None, Some(cstore::NativeStatic)),
3030 (String::from("c"), None, Some(cstore::NativeUnknown)),
3034 (String::from("c"), None, Some(cstore::NativeUnknown)),
3035 (String::from("a"), None, Some(cstore::NativeStatic)),
3036 (String::from("b"), None, Some(cstore::NativeFramework)),
3039 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
3040 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
3041 assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
3044 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3045 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3046 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3050 fn test_codegen_options_tracking_hash() {
3051 let reference = Options::default();
3052 let mut opts = Options::default();
3054 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3055 opts.cg.ar = Some(String::from("abc"));
3056 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3058 opts.cg.linker = Some(PathBuf::from("linker"));
3059 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3061 opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
3062 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3064 opts.cg.link_dead_code = true;
3065 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3067 opts.cg.rpath = true;
3068 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3070 opts.cg.extra_filename = String::from("extra-filename");
3071 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3073 opts.cg.codegen_units = Some(42);
3074 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3076 opts.cg.remark = super::Passes::Some(vec![String::from("pass1"), String::from("pass2")]);
3077 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3079 opts.cg.save_temps = true;
3080 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3082 opts.cg.incremental = Some(String::from("abc"));
3083 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3085 // Make sure changing a [TRACKED] option changes the hash
3086 opts = reference.clone();
3087 opts.cg.lto = LtoCli::Fat;
3088 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3090 opts = reference.clone();
3091 opts.cg.target_cpu = Some(String::from("abc"));
3092 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3094 opts = reference.clone();
3095 opts.cg.target_feature = String::from("all the features, all of them");
3096 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3098 opts = reference.clone();
3099 opts.cg.passes = vec![String::from("1"), String::from("2")];
3100 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3102 opts = reference.clone();
3103 opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
3104 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3106 opts = reference.clone();
3107 opts.cg.overflow_checks = Some(true);
3108 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3110 opts = reference.clone();
3111 opts.cg.no_prepopulate_passes = true;
3112 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3114 opts = reference.clone();
3115 opts.cg.no_vectorize_loops = true;
3116 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3118 opts = reference.clone();
3119 opts.cg.no_vectorize_slp = true;
3120 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3122 opts = reference.clone();
3123 opts.cg.soft_float = true;
3124 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3126 opts = reference.clone();
3127 opts.cg.prefer_dynamic = true;
3128 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3130 opts = reference.clone();
3131 opts.cg.no_integrated_as = true;
3132 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3134 opts = reference.clone();
3135 opts.cg.no_redzone = Some(true);
3136 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3138 opts = reference.clone();
3139 opts.cg.relocation_model = Some(String::from("relocation model"));
3140 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3142 opts = reference.clone();
3143 opts.cg.code_model = Some(String::from("code model"));
3144 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3146 opts = reference.clone();
3147 opts.debugging_opts.tls_model = Some(String::from("tls model"));
3148 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3150 opts = reference.clone();
3151 opts.debugging_opts.pgo_gen = Some(String::from("abc"));
3152 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3154 opts = reference.clone();
3155 opts.debugging_opts.pgo_use = String::from("abc");
3156 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3158 opts = reference.clone();
3159 opts.cg.metadata = vec![String::from("A"), String::from("B")];
3160 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3162 opts = reference.clone();
3163 opts.cg.debuginfo = Some(0xdeadbeef);
3164 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3166 opts = reference.clone();
3167 opts.cg.debuginfo = Some(0xba5eba11);
3168 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3170 opts = reference.clone();
3171 opts.cg.force_frame_pointers = Some(false);
3172 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3174 opts = reference.clone();
3175 opts.cg.debug_assertions = Some(true);
3176 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3178 opts = reference.clone();
3179 opts.cg.inline_threshold = Some(0xf007ba11);
3180 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3182 opts = reference.clone();
3183 opts.cg.panic = Some(PanicStrategy::Abort);
3184 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3186 opts = reference.clone();
3187 opts.cg.linker_plugin_lto = LinkerPluginLto::LinkerPluginAuto;
3188 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3192 fn test_debugging_options_tracking_hash() {
3193 let reference = Options::default();
3194 let mut opts = Options::default();
3196 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3197 opts.debugging_opts.verbose = true;
3198 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3199 opts.debugging_opts.time_passes = true;
3200 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3201 opts.debugging_opts.count_llvm_insns = true;
3202 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3203 opts.debugging_opts.time_llvm_passes = true;
3204 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3205 opts.debugging_opts.input_stats = true;
3206 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3207 opts.debugging_opts.codegen_stats = true;
3208 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3209 opts.debugging_opts.borrowck_stats = true;
3210 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3211 opts.debugging_opts.meta_stats = true;
3212 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3213 opts.debugging_opts.print_link_args = true;
3214 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3215 opts.debugging_opts.print_llvm_passes = true;
3216 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3217 opts.debugging_opts.ast_json = true;
3218 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3219 opts.debugging_opts.ast_json_noexpand = true;
3220 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3221 opts.debugging_opts.ls = true;
3222 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3223 opts.debugging_opts.save_analysis = true;
3224 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3225 opts.debugging_opts.flowgraph_print_loans = true;
3226 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3227 opts.debugging_opts.flowgraph_print_moves = true;
3228 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3229 opts.debugging_opts.flowgraph_print_assigns = true;
3230 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3231 opts.debugging_opts.flowgraph_print_all = true;
3232 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3233 opts.debugging_opts.print_region_graph = true;
3234 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3235 opts.debugging_opts.parse_only = true;
3236 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3237 opts.debugging_opts.incremental = Some(String::from("abc"));
3238 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3239 opts.debugging_opts.dump_dep_graph = true;
3240 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3241 opts.debugging_opts.query_dep_graph = true;
3242 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3243 opts.debugging_opts.no_analysis = true;
3244 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3245 opts.debugging_opts.unstable_options = true;
3246 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3247 opts.debugging_opts.trace_macros = true;
3248 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3249 opts.debugging_opts.keep_hygiene_data = true;
3250 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3251 opts.debugging_opts.keep_ast = true;
3252 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3253 opts.debugging_opts.print_mono_items = Some(String::from("abc"));
3254 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3255 opts.debugging_opts.dump_mir = Some(String::from("abc"));
3256 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3257 opts.debugging_opts.dump_mir_dir = String::from("abc");
3258 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3259 opts.debugging_opts.dump_mir_graphviz = true;
3260 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3262 // Make sure changing a [TRACKED] option changes the hash
3263 opts = reference.clone();
3264 opts.debugging_opts.asm_comments = true;
3265 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3267 opts = reference.clone();
3268 opts.debugging_opts.verify_llvm_ir = true;
3269 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3271 opts = reference.clone();
3272 opts.debugging_opts.no_landing_pads = true;
3273 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3275 opts = reference.clone();
3276 opts.debugging_opts.fewer_names = true;
3277 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3279 opts = reference.clone();
3280 opts.debugging_opts.no_codegen = true;
3281 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3283 opts = reference.clone();
3284 opts.debugging_opts.treat_err_as_bug = Some(1);
3285 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3287 opts = reference.clone();
3288 opts.debugging_opts.report_delayed_bugs = true;
3289 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3291 opts = reference.clone();
3292 opts.debugging_opts.continue_parse_after_error = true;
3293 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3295 opts = reference.clone();
3296 opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
3297 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3299 opts = reference.clone();
3300 opts.debugging_opts.force_overflow_checks = Some(true);
3301 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3303 opts = reference.clone();
3304 opts.debugging_opts.show_span = Some(String::from("abc"));
3305 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3307 opts = reference.clone();
3308 opts.debugging_opts.mir_opt_level = 3;
3309 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3311 opts = reference.clone();
3312 opts.debugging_opts.relro_level = Some(RelroLevel::Full);
3313 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3315 opts = reference.clone();
3316 opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
3317 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3319 opts = reference.clone();
3320 opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
3321 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3325 fn test_edition_parsing() {
3326 // test default edition
3327 let options = Options::default();
3328 assert!(options.edition == DEFAULT_EDITION);
3330 let matches = optgroups()
3331 .parse(&["--edition=2018".to_string()])
3333 let (sessopts, _) = build_session_options_and_crate_config(&matches);
3334 assert!(sessopts.edition == Edition::Edition2018)