1 // ignore-tidy-filelength
3 //! Contains infrastructure for configuring the compiler, including parsing
4 //! command line options.
8 use crate::session::{early_error, early_warn, Session};
9 use crate::session::search_paths::SearchPath;
11 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
12 use rustc_target::spec::{Target, TargetTriple};
14 use crate::middle::cstore;
17 use syntax::ast::{self, IntTy, UintTy, MetaItemKind};
18 use syntax::source_map::{FileName, FilePathMapping};
19 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
20 use syntax::parse::token;
22 use syntax::symbol::{sym, Symbol};
23 use syntax::feature_gate::UnstableFeatures;
24 use errors::emitter::HumanReadableErrorType;
26 use errors::{ColorConfig, FatalError, Handler};
29 use std::collections::{BTreeMap, BTreeSet};
30 use std::collections::btree_map::Iter as BTreeMapIter;
31 use std::collections::btree_map::Keys as BTreeMapKeysIter;
32 use std::collections::btree_map::Values as BTreeMapValuesIter;
34 use rustc_data_structures::fx::FxHashSet;
36 use std::hash::Hasher;
37 use std::collections::hash_map::DefaultHasher;
38 use std::iter::FromIterator;
39 use std::path::{Path, PathBuf};
47 #[derive(Clone, Hash, Debug)]
55 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
65 impl_stable_hash_via_hash!(OptLevel);
67 /// This is what the `LtoCli` values get mapped to after resolving defaults and
68 /// and taking other command line options into account.
69 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
71 /// Don't do any LTO whatsoever
74 /// Do a full crate graph LTO with ThinLTO
77 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
81 /// Do a full crate graph LTO with "fat" LTO
85 /// The different settings that the `-C lto` flag can have.
86 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
98 /// No `-C lto` flag passed
102 #[derive(Clone, PartialEq, Hash)]
103 pub enum LinkerPluginLto {
104 LinkerPlugin(PathBuf),
109 impl LinkerPluginLto {
110 pub fn enabled(&self) -> bool {
112 LinkerPluginLto::LinkerPlugin(_) |
113 LinkerPluginLto::LinkerPluginAuto => true,
114 LinkerPluginLto::Disabled => false,
119 #[derive(Clone, PartialEq, Hash)]
120 pub enum SwitchWithOptPath {
121 Enabled(Option<PathBuf>),
125 impl SwitchWithOptPath {
126 pub fn enabled(&self) -> bool {
128 SwitchWithOptPath::Enabled(_) => true,
129 SwitchWithOptPath::Disabled => false,
134 #[derive(Clone, Copy, PartialEq, Hash)]
141 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
142 pub enum OutputType {
153 impl_stable_hash_via_hash!(OutputType);
156 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
158 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
160 | OutputType::Assembly
161 | OutputType::LlvmAssembly
163 | OutputType::Object => false,
167 fn shorthand(&self) -> &'static str {
169 OutputType::Bitcode => "llvm-bc",
170 OutputType::Assembly => "asm",
171 OutputType::LlvmAssembly => "llvm-ir",
172 OutputType::Mir => "mir",
173 OutputType::Object => "obj",
174 OutputType::Metadata => "metadata",
175 OutputType::Exe => "link",
176 OutputType::DepInfo => "dep-info",
180 fn from_shorthand(shorthand: &str) -> Option<Self> {
181 Some(match shorthand {
182 "asm" => OutputType::Assembly,
183 "llvm-ir" => OutputType::LlvmAssembly,
184 "mir" => OutputType::Mir,
185 "llvm-bc" => OutputType::Bitcode,
186 "obj" => OutputType::Object,
187 "metadata" => OutputType::Metadata,
188 "link" => OutputType::Exe,
189 "dep-info" => OutputType::DepInfo,
194 fn shorthands_display() -> String {
196 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
197 OutputType::Bitcode.shorthand(),
198 OutputType::Assembly.shorthand(),
199 OutputType::LlvmAssembly.shorthand(),
200 OutputType::Mir.shorthand(),
201 OutputType::Object.shorthand(),
202 OutputType::Metadata.shorthand(),
203 OutputType::Exe.shorthand(),
204 OutputType::DepInfo.shorthand(),
208 pub fn extension(&self) -> &'static str {
210 OutputType::Bitcode => "bc",
211 OutputType::Assembly => "s",
212 OutputType::LlvmAssembly => "ll",
213 OutputType::Mir => "mir",
214 OutputType::Object => "o",
215 OutputType::Metadata => "rmeta",
216 OutputType::DepInfo => "d",
217 OutputType::Exe => "",
222 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
223 pub enum ErrorOutputType {
224 HumanReadable(HumanReadableErrorType),
226 /// Render the json in a human readable way (with indents and newlines)
228 /// The way the `rendered` field is created
229 json_rendered: HumanReadableErrorType,
233 impl Default for ErrorOutputType {
234 fn default() -> ErrorOutputType {
235 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
239 // Use tree-based collections to cheaply get a deterministic Hash implementation.
240 // DO NOT switch BTreeMap out for an unsorted container type! That would break
241 // dependency tracking for command-line arguments.
242 #[derive(Clone, Hash)]
243 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
245 impl_stable_hash_via_hash!(OutputTypes);
248 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
249 OutputTypes(BTreeMap::from_iter(
250 entries.iter().map(|&(k, ref v)| (k, v.clone())),
254 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
258 pub fn contains_key(&self, key: &OutputType) -> bool {
259 self.0.contains_key(key)
262 pub fn keys<'a>(&'a self) -> BTreeMapKeysIter<'a, OutputType, Option<PathBuf>> {
266 pub fn values<'a>(&'a self) -> BTreeMapValuesIter<'a, OutputType, Option<PathBuf>> {
270 pub fn len(&self) -> usize {
274 // True if any of the output types require codegen or linking.
275 pub fn should_codegen(&self) -> bool {
276 self.0.keys().any(|k| match *k {
278 | OutputType::Assembly
279 | OutputType::LlvmAssembly
282 | OutputType::Exe => true,
283 OutputType::Metadata | OutputType::DepInfo => false,
288 // Use tree-based collections to cheaply get a deterministic Hash implementation.
289 // DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
290 // would break dependency tracking for command-line arguments.
291 #[derive(Clone, Hash)]
292 pub struct Externs(BTreeMap<String, ExternEntry>);
294 #[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default)]
295 pub struct ExternEntry {
296 pub locations: BTreeSet<Option<String>>,
297 pub is_private_dep: bool
301 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
305 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
309 pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, ExternEntry> {
315 macro_rules! hash_option {
316 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
317 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
318 if $sub_hashes.insert(stringify!($opt_name),
319 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
320 bug!("Duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
326 [UNTRACKED_WITH_WARNING $warn_val:expr, $warn_text:expr, $error_format:expr]) => ({
327 if *$opt_expr == $warn_val {
328 early_warn($error_format, $warn_text)
333 macro_rules! top_level_options {
334 (pub struct Options { $(
335 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
343 pub fn dep_tracking_hash(&self) -> u64 {
344 let mut sub_hashes = BTreeMap::new();
349 [$dep_tracking_marker $($warn_val,
351 self.error_format)*]);
353 let mut hasher = DefaultHasher::new();
354 dep_tracking::stable_hash(sub_hashes,
363 // The top-level command-line options struct
365 // For each option, one has to specify how it behaves with regard to the
366 // dependency tracking system of incremental compilation. This is done via the
367 // square-bracketed directive after the field type. The options are:
370 // A change in the given field will cause the compiler to completely clear the
371 // incremental compilation cache before proceeding.
374 // Incremental compilation is not influenced by this option.
376 // [UNTRACKED_WITH_WARNING(val, warning)]
377 // The option is incompatible with incremental compilation in some way. If it
378 // has the value `val`, the string `warning` is emitted as a warning.
380 // If you add a new option to this struct or one of the sub-structs like
381 // CodegenOptions, think about how it influences incremental compilation. If in
382 // doubt, specify [TRACKED], which is always "correct" but might lead to
383 // unnecessary re-compilation.
386 // The crate config requested for the session, which may be combined
387 // with additional crate configurations during the compile process
388 crate_types: Vec<CrateType> [TRACKED],
389 optimize: OptLevel [TRACKED],
390 // Include the debug_assertions flag into dependency tracking, since it
391 // can influence whether overflow checks are done or not.
392 debug_assertions: bool [TRACKED],
393 debuginfo: DebugInfo [TRACKED],
394 lint_opts: Vec<(String, lint::Level)> [TRACKED],
395 lint_cap: Option<lint::Level> [TRACKED],
396 describe_lints: bool [UNTRACKED],
397 output_types: OutputTypes [TRACKED],
398 search_paths: Vec<SearchPath> [UNTRACKED],
399 libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
400 maybe_sysroot: Option<PathBuf> [TRACKED],
402 target_triple: TargetTriple [TRACKED],
404 test: bool [TRACKED],
405 error_format: ErrorOutputType [UNTRACKED],
407 // if Some, enable incremental compilation, using the given
408 // directory to store intermediate results
409 incremental: Option<PathBuf> [UNTRACKED],
411 debugging_opts: DebuggingOptions [TRACKED],
412 prints: Vec<PrintRequest> [UNTRACKED],
413 // Determines which borrow checker(s) to run. This is the parsed, sanitized
414 // version of `debugging_opts.borrowck`, which is just a plain string.
415 borrowck_mode: BorrowckMode [UNTRACKED],
416 cg: CodegenOptions [TRACKED],
417 externs: Externs [UNTRACKED],
418 crate_name: Option<String> [TRACKED],
419 // An optional name to use as the crate for std during std injection,
420 // written `extern crate name as std`. Defaults to `std`. Used by
421 // out-of-tree drivers.
422 alt_std_name: Option<String> [TRACKED],
423 // Indicates how the compiler should treat unstable features
424 unstable_features: UnstableFeatures [TRACKED],
426 // Indicates whether this run of the compiler is actually rustdoc. This
427 // is currently just a hack and will be removed eventually, so please
428 // try to not rely on this too much.
429 actually_rustdoc: bool [TRACKED],
431 // Specifications of codegen units / ThinLTO which are forced as a
432 // result of parsing command line options. These are not necessarily
433 // what rustc was invoked with, but massaged a bit to agree with
434 // commands like `--emit llvm-ir` which they're often incompatible with
435 // if we otherwise use the defaults of rustc.
436 cli_forced_codegen_units: Option<usize> [UNTRACKED],
437 cli_forced_thinlto_off: bool [UNTRACKED],
439 // Remap source path prefixes in all output (messages, object files, debug, etc)
440 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
442 edition: Edition [TRACKED],
446 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
447 pub enum PrintRequest {
462 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
463 pub enum BorrowckMode {
469 /// Should we run the MIR-based borrow check, but also fall back
470 /// on the AST borrow check if the MIR-based one errors.
471 pub fn migrate(self) -> bool {
473 BorrowckMode::Mir => false,
474 BorrowckMode::Migrate => true,
478 /// Should we emit the AST-based borrow checker errors?
479 pub fn use_ast(self) -> bool {
481 BorrowckMode::Mir => false,
482 BorrowckMode::Migrate => false,
488 /// Loads source from file
491 /// String that is shown in place of a filename
493 /// Anonymous source string
499 pub fn filestem(&self) -> &str {
501 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
502 Input::Str { .. } => "rust_out",
506 pub fn get_input(&mut self) -> Option<&mut String> {
508 Input::File(_) => None,
509 Input::Str { ref mut input, .. } => Some(input),
513 pub fn source_name(&self) -> FileName {
515 Input::File(ref ifile) => ifile.clone().into(),
516 Input::Str { ref name, .. } => name.clone(),
521 #[derive(Clone, Hash)]
522 pub struct OutputFilenames {
523 pub out_directory: PathBuf,
524 pub out_filestem: String,
525 pub single_output_file: Option<PathBuf>,
527 pub outputs: OutputTypes,
530 impl_stable_hash_via_hash!(OutputFilenames);
532 pub const RUST_CGU_EXT: &str = "rcgu";
534 impl OutputFilenames {
535 pub fn path(&self, flavor: OutputType) -> PathBuf {
538 .and_then(|p| p.to_owned())
539 .or_else(|| self.single_output_file.clone())
540 .unwrap_or_else(|| self.temp_path(flavor, None))
543 /// Gets the path where a compilation artifact of the given type for the
544 /// given codegen unit should be placed on disk. If codegen_unit_name is
545 /// None, a path distinct from those of any codegen unit will be generated.
546 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
547 let extension = flavor.extension();
548 self.temp_path_ext(extension, codegen_unit_name)
551 /// Like temp_path, but also supports things where there is no corresponding
552 /// OutputType, like noopt-bitcode or lto-bitcode.
553 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
554 let base = self.out_directory.join(&self.filestem());
556 let mut extension = String::new();
558 if let Some(codegen_unit_name) = codegen_unit_name {
559 extension.push_str(codegen_unit_name);
563 if !extension.is_empty() {
564 extension.push_str(".");
565 extension.push_str(RUST_CGU_EXT);
566 extension.push_str(".");
569 extension.push_str(ext);
572 let path = base.with_extension(&extension[..]);
576 pub fn with_extension(&self, extension: &str) -> PathBuf {
578 .join(&self.filestem())
579 .with_extension(extension)
582 pub fn filestem(&self) -> String {
583 format!("{}{}", self.out_filestem, self.extra)
587 pub fn host_triple() -> &'static str {
588 // Get the host triple out of the build environment. This ensures that our
589 // idea of the host triple is the same as for the set of libraries we've
590 // actually built. We can't just take LLVM's host triple because they
591 // normalize all ix86 architectures to i386.
593 // Instead of grabbing the host triple (for the current host), we grab (at
594 // compile time) the target triple that this rustc is built with and
595 // calling that (at runtime) the host triple.
596 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
599 impl Default for Options {
600 fn default() -> Options {
602 crate_types: Vec::new(),
603 optimize: OptLevel::No,
604 debuginfo: DebugInfo::None,
605 lint_opts: Vec::new(),
607 describe_lints: false,
608 output_types: OutputTypes(BTreeMap::new()),
609 search_paths: vec![],
611 target_triple: TargetTriple::from_triple(host_triple()),
614 debugging_opts: basic_debugging_options(),
616 borrowck_mode: BorrowckMode::Migrate,
617 cg: basic_codegen_options(),
618 error_format: ErrorOutputType::default(),
619 externs: Externs(BTreeMap::new()),
623 unstable_features: UnstableFeatures::Disallow,
624 debug_assertions: true,
625 actually_rustdoc: false,
626 cli_forced_codegen_units: None,
627 cli_forced_thinlto_off: false,
628 remap_path_prefix: Vec::new(),
629 edition: DEFAULT_EDITION,
635 /// Returns `true` if there is a reason to build the dep graph.
636 pub fn build_dep_graph(&self) -> bool {
637 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
638 || self.debugging_opts.query_dep_graph
642 pub fn enable_dep_node_debug_strs(&self) -> bool {
643 cfg!(debug_assertions)
644 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
647 pub fn file_path_mapping(&self) -> FilePathMapping {
648 FilePathMapping::new(self.remap_path_prefix.clone())
651 /// Returns `true` if there will be an output file generated
652 pub fn will_create_output_file(&self) -> bool {
653 !self.debugging_opts.parse_only && // The file is just being parsed
654 !self.debugging_opts.ls // The file is just being queried
658 pub fn share_generics(&self) -> bool {
659 match self.debugging_opts.share_generics {
660 Some(setting) => setting,
662 match self.optimize {
666 OptLevel::SizeMin => true,
668 OptLevel::Aggressive => false,
675 // The type of entry function, so users can have their own entry functions
676 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
677 pub enum EntryFnType {
682 impl_stable_hash_via_hash!(EntryFnType);
684 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
694 #[derive(Clone, Hash)]
701 pub fn is_empty(&self) -> bool {
703 Passes::Some(ref v) => v.is_empty(),
704 Passes::All => false,
709 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
710 /// at once. The goal of this macro is to define an interface that can be
711 /// programmatically used by the option parser in order to initialize the struct
712 /// without hardcoding field names all over the place.
714 /// The goal is to invoke this macro once with the correct fields, and then this
715 /// macro generates all necessary code. The main gotcha of this macro is the
716 /// cgsetters module which is a bunch of generated code to parse an option into
717 /// its respective field in the struct. There are a few hand-written parsers for
718 /// parsing specific types of values in this module.
719 macro_rules! options {
720 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
721 $buildfn:ident, $prefix:expr, $outputname:expr,
722 $stat:ident, $mod_desc:ident, $mod_set:ident,
723 $($opt:ident : $t:ty = (
726 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
731 pub struct $struct_name { $(pub $opt: $t),* }
733 pub fn $defaultfn() -> $struct_name {
734 $struct_name { $($opt: $init),* }
737 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
739 let mut op = $defaultfn();
740 for option in matches.opt_strs($prefix) {
741 let mut iter = option.splitn(2, '=');
742 let key = iter.next().unwrap();
743 let value = iter.next();
744 let option_to_lookup = key.replace("-", "_");
745 let mut found = false;
746 for &(candidate, setter, opt_type_desc, _) in $stat {
747 if option_to_lookup != candidate { continue }
748 if !setter(&mut op, value) {
749 match (value, opt_type_desc) {
750 (Some(..), None) => {
751 early_error(error_format, &format!("{} option `{}` takes no \
752 value", $outputname, key))
754 (None, Some(type_desc)) => {
755 early_error(error_format, &format!("{0} option `{1}` requires \
756 {2} ({3} {1}=<value>)",
760 (Some(value), Some(type_desc)) => {
761 early_error(error_format, &format!("incorrect value `{}` for {} \
762 option `{}` - {} was expected",
766 (None, None) => bug!()
773 early_error(error_format, &format!("unknown {} option: `{}`",
780 impl<'a> dep_tracking::DepTrackingHash for $struct_name {
781 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
782 let mut sub_hashes = BTreeMap::new();
787 [$dep_tracking_marker $($dep_warn_val,
791 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
795 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
796 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
797 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
799 #[allow(non_upper_case_globals, dead_code)]
801 pub const parse_bool: Option<&str> = None;
802 pub const parse_opt_bool: Option<&str> =
803 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
804 pub const parse_string: Option<&str> = Some("a string");
805 pub const parse_string_push: Option<&str> = Some("a string");
806 pub const parse_pathbuf_push: Option<&str> = Some("a path");
807 pub const parse_opt_string: Option<&str> = Some("a string");
808 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
809 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
810 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
811 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
812 pub const parse_uint: Option<&str> = Some("a number");
813 pub const parse_passes: Option<&str> =
814 Some("a space-separated list of passes, or `all`");
815 pub const parse_opt_uint: Option<&str> =
817 pub const parse_panic_strategy: Option<&str> =
818 Some("either `unwind` or `abort`");
819 pub const parse_relro_level: Option<&str> =
820 Some("one of: `full`, `partial`, or `off`");
821 pub const parse_sanitizer: Option<&str> =
822 Some("one of: `address`, `leak`, `memory` or `thread`");
823 pub const parse_linker_flavor: Option<&str> =
824 Some(::rustc_target::spec::LinkerFlavor::one_of());
825 pub const parse_optimization_fuel: Option<&str> =
826 Some("crate=integer");
827 pub const parse_unpretty: Option<&str> =
828 Some("`string` or `string=string`");
829 pub const parse_treat_err_as_bug: Option<&str> =
830 Some("either no value or a number bigger than 0");
831 pub const parse_lto: Option<&str> =
832 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
834 pub const parse_linker_plugin_lto: Option<&str> =
835 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
836 or the path to the linker plugin");
837 pub const parse_switch_with_opt_path: Option<&str> =
838 Some("an optional path to the profiling data output directory");
839 pub const parse_merge_functions: Option<&str> =
840 Some("one of: `disabled`, `trampolines`, or `aliases`");
845 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath};
846 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
847 use std::path::PathBuf;
848 use std::str::FromStr;
851 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
852 $parse(&mut cg.$opt, v)
856 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
859 None => { *slot = true; true }
863 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
867 "n" | "no" | "off" => {
870 "y" | "yes" | "on" => {
873 _ => { return false; }
878 None => { *slot = Some(true); true }
882 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
884 Some(s) => { *slot = Some(s.to_string()); true },
889 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
891 Some(s) => { *slot = Some(PathBuf::from(s)); true },
896 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
898 Some(s) => { *slot = s.to_string(); true },
903 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
905 Some(s) => { slot.push(s.to_string()); true },
910 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
912 Some(s) => { slot.push(PathBuf::from(s)); true },
917 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
921 slot.extend(s.split_whitespace().map(|s| s.to_string()));
928 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
932 let v = s.split_whitespace().map(|s| s.to_string()).collect();
940 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
944 let v = s.split(',').map(|s| s.to_string()).collect();
952 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
953 match v.and_then(|s| s.parse().ok()) {
954 Some(i) => { *slot = i; true },
959 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
961 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
962 None => { *slot = None; false }
966 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
973 let mut passes = vec![];
974 if parse_list(&mut passes, v) {
975 *slot = Passes::Some(passes);
984 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
986 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
987 Some("abort") => *slot = Some(PanicStrategy::Abort),
993 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
996 match s.parse::<RelroLevel>() {
997 Ok(level) => *slot = Some(level),
1006 fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1008 Some("address") => *slote = Some(Sanitizer::Address),
1009 Some("leak") => *slote = Some(Sanitizer::Leak),
1010 Some("memory") => *slote = Some(Sanitizer::Memory),
1011 Some("thread") => *slote = Some(Sanitizer::Thread),
1017 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1018 match v.and_then(LinkerFlavor::from_str) {
1019 Some(lf) => *slote = Some(lf),
1025 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1029 let parts = s.split('=').collect::<Vec<_>>();
1030 if parts.len() != 2 { return false; }
1031 let crate_name = parts[0].to_string();
1032 let fuel = parts[1].parse::<u64>();
1033 if fuel.is_err() { return false; }
1034 *slot = Some((crate_name, fuel.unwrap()));
1040 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1043 Some(s) if s.split('=').count() <= 2 => {
1044 *slot = Some(s.to_string());
1051 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1053 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1054 None => { *slot = Some(1); true }
1058 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1060 let mut bool_arg = None;
1061 if parse_opt_bool(&mut bool_arg, v) {
1062 *slot = if bool_arg.unwrap() {
1072 None => LtoCli::NoParam,
1073 Some("thin") => LtoCli::Thin,
1074 Some("fat") => LtoCli::Fat,
1075 Some(_) => return false,
1080 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1082 let mut bool_arg = None;
1083 if parse_opt_bool(&mut bool_arg, v) {
1084 *slot = if bool_arg.unwrap() {
1085 LinkerPluginLto::LinkerPluginAuto
1087 LinkerPluginLto::Disabled
1094 None => LinkerPluginLto::LinkerPluginAuto,
1095 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1100 fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1102 None => SwitchWithOptPath::Enabled(None),
1103 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1108 fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1109 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1110 Some(mergefunc) => *slot = Some(mergefunc),
1118 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1119 build_codegen_options, "C", "codegen",
1120 CG_OPTIONS, cg_type_desc, cgsetters,
1121 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1122 "this option is deprecated and does nothing"),
1123 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1124 "system linker to link outputs with"),
1125 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1126 "a single extra argument to append to the linker invocation (can be used several times)"),
1127 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1128 "extra arguments to append to the linker invocation (space separated)"),
1129 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1130 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1131 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1132 "perform LLVM link-time optimizations"),
1133 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1134 "select target processor (rustc --print target-cpus for details)"),
1135 target_feature: String = (String::new(), parse_string, [TRACKED],
1136 "target specific attributes (rustc --print target-features for details)"),
1137 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1138 "a list of extra LLVM passes to run (space separated)"),
1139 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1140 "a list of arguments to pass to llvm (space separated)"),
1141 save_temps: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1142 "`-C save-temps` might not produce all requested temporary products \
1143 when incremental compilation is enabled.")],
1144 "save all temporary output files during compilation"),
1145 rpath: bool = (false, parse_bool, [UNTRACKED],
1146 "set rpath values in libs/exes"),
1147 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1148 "use overflow checks for integer arithmetic"),
1149 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1150 "don't pre-populate the pass manager with a list of passes"),
1151 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1152 "don't run the loop vectorization optimization passes"),
1153 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1154 "don't run LLVM's SLP vectorization pass"),
1155 soft_float: bool = (false, parse_bool, [TRACKED],
1156 "use soft float ABI (*eabihf targets only)"),
1157 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1158 "prefer dynamic linking to static linking"),
1159 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1160 "use an external assembler rather than LLVM's integrated one"),
1161 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1162 "disable the use of the redzone"),
1163 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1164 "choose the relocation model to use (rustc --print relocation-models for details)"),
1165 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1166 "choose the code model to use (rustc --print code-models for details)"),
1167 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1168 "metadata to mangle symbol names with"),
1169 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1170 "extra data to put in each output filename"),
1171 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1172 "divide crate into N units to optimize in parallel"),
1173 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1174 "print remarks for these optimization passes (space separated, or \"all\")"),
1175 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1176 "the --no-stack-check flag is deprecated and does nothing"),
1177 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1178 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1179 2 = full debug info with variable and type information"),
1180 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1181 "optimize with possible levels 0-3, s, or z"),
1182 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1183 "force use of the frame pointers"),
1184 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1185 "explicitly enable the cfg(debug_assertions) directive"),
1186 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1187 "set the threshold for inlining a function (default: 225)"),
1188 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1189 [TRACKED], "panic strategy to compile crate with"),
1190 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1191 "enable incremental compilation"),
1192 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1193 "allow the linker to link its default libraries"),
1194 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1196 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1197 parse_linker_plugin_lto, [TRACKED],
1198 "generate build artifacts that are compatible with linker-based LTO."),
1202 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1203 build_debugging_options, "Z", "debugging",
1204 DB_OPTIONS, db_type_desc, dbsetters,
1205 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1206 "the backend to use"),
1207 verbose: bool = (false, parse_bool, [UNTRACKED],
1208 "in general, enable more debug printouts"),
1209 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1210 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1211 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1212 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1213 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1214 "select which borrowck is used (`mir` or `migrate`)"),
1215 time_passes: bool = (false, parse_bool, [UNTRACKED],
1216 "measure time of each rustc pass"),
1217 time: bool = (false, parse_bool, [UNTRACKED],
1218 "measure time of rustc processes"),
1219 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1220 "The output of `-Z time-llvm-passes` will only reflect timings of \
1221 re-codegened modules when used with incremental compilation" )],
1222 "measure time of each LLVM pass"),
1223 input_stats: bool = (false, parse_bool, [UNTRACKED],
1224 "gather statistics about the input"),
1225 asm_comments: bool = (false, parse_bool, [TRACKED],
1226 "generate comments into the assembly (may change behavior)"),
1227 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1229 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1230 "gather borrowck statistics"),
1231 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1232 "omit landing pads for unwinding"),
1233 fewer_names: bool = (false, parse_bool, [TRACKED],
1234 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1235 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1236 "gather metadata statistics"),
1237 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1238 "print the arguments passed to the linker"),
1239 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1240 "prints the llvm optimization passes being run"),
1241 ast_json: bool = (false, parse_bool, [UNTRACKED],
1242 "print the AST as JSON and halt"),
1243 threads: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1244 "use a thread pool with N threads"),
1245 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1246 "print the pre-expansion AST as JSON and halt"),
1247 ls: bool = (false, parse_bool, [UNTRACKED],
1248 "list the symbols defined by a library crate"),
1249 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1250 "write syntax and type analysis (in JSON format) information, in \
1251 addition to normal output"),
1252 flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED],
1253 "include loan analysis data in -Z unpretty flowgraph output"),
1254 flowgraph_print_moves: bool = (false, parse_bool, [UNTRACKED],
1255 "include move analysis data in -Z unpretty flowgraph output"),
1256 flowgraph_print_assigns: bool = (false, parse_bool, [UNTRACKED],
1257 "include assignment analysis data in -Z unpretty flowgraph output"),
1258 flowgraph_print_all: bool = (false, parse_bool, [UNTRACKED],
1259 "include all dataflow analysis data in -Z unpretty flowgraph output"),
1260 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1261 "prints region inference graph. \
1262 Use with RUST_REGION_GRAPH=help for more info"),
1263 parse_only: bool = (false, parse_bool, [UNTRACKED],
1264 "parse only; do not compile, assemble, or link"),
1265 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1266 "load proc macros for both target and host, but only link to the target"),
1267 no_codegen: bool = (false, parse_bool, [TRACKED],
1268 "run all passes except codegen; no output"),
1269 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1270 "treat error number `val` that occurs as bug"),
1271 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1272 "immediately print bugs registered with `delay_span_bug`"),
1273 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1274 "show macro backtraces even for non-local macros"),
1275 teach: bool = (false, parse_bool, [TRACKED],
1276 "show extended diagnostic help"),
1277 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1278 "attempt to recover from parse errors (experimental)"),
1279 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1280 "print tasks that execute and the color their dep node gets (requires debug build)"),
1281 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1282 "enable incremental compilation (experimental)"),
1283 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1284 "enable incremental compilation support for queries (experimental)"),
1285 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1286 "print high-level information about incremental reuse (or the lack thereof)"),
1287 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1288 "dump hash information in textual format to stdout"),
1289 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1290 "verify incr. comp. hashes of green query instances"),
1291 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1292 "ignore spans during ICH computation -- used for testing"),
1293 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1294 "insert function instrument code for mcount-based tracing"),
1295 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1296 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1297 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1298 "enable queries of the dependency graph for regression testing"),
1299 profile_queries: bool = (false, parse_bool, [UNTRACKED],
1300 "trace and profile the queries of the incremental compilation framework"),
1301 profile_queries_and_keys: bool = (false, parse_bool, [UNTRACKED],
1302 "trace and profile the queries and keys of the incremental compilation framework"),
1303 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1304 "parse and expand the source, but run no analysis"),
1305 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1306 "load extra plugins"),
1307 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1308 "adds unstable command line options to rustc interface"),
1309 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1310 "force overflow checks on or off"),
1311 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1312 "for every macro invocation, print its name and arguments"),
1313 debug_macros: bool = (false, parse_bool, [TRACKED],
1314 "emit line numbers debug info inside macros"),
1315 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1316 "don't clear the hygiene data after analysis"),
1317 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1318 "keep the AST after lowering it to HIR"),
1319 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1320 "show spans for compiler debugging (expr|pat|ty)"),
1321 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1322 "print layout information for each type encountered"),
1323 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1324 "print the result of the monomorphization collection pass"),
1325 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1326 "set the MIR optimization level (0-3, default: 1)"),
1327 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1328 "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"),
1329 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1330 "dump MIR state to file.
1331 `val` is used to select which passes and functions to dump. For example:
1332 `all` matches all passes and functions,
1333 `foo` matches all passes for functions whose name contains 'foo',
1334 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1335 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1337 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1338 "the directory the MIR is dumped into"),
1339 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1340 "in addition to `.mir` files, create graphviz `.dot` files"),
1341 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1342 "if set, exclude the pass number when dumping MIR (used in tests)"),
1343 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1344 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1345 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1346 "print some performance-related statistics"),
1347 query_stats: bool = (false, parse_bool, [UNTRACKED],
1348 "print some statistics about the query system"),
1349 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1350 "print some statistics about AST and HIR"),
1351 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1352 "encode MIR of all functions into the crate metadata"),
1353 json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1354 "describes how to render the `rendered` field of json diagnostics"),
1355 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1356 "take the breaks off const evaluation. NOTE: this is unsound"),
1357 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1358 "pass `-install_name @rpath/...` to the macOS linker"),
1359 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1361 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1362 "set the optimization fuel quota for a crate"),
1363 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1364 "make Rustc print the total optimization fuel used by a crate"),
1365 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1366 "force all crates to be `rustc_private` unstable"),
1367 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1368 "a single extra argument to prepend the linker invocation (can be used several times)"),
1369 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1370 "extra arguments to prepend to the linker invocation (space separated)"),
1371 profile: bool = (false, parse_bool, [TRACKED],
1372 "insert profiling code"),
1373 pgo_gen: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1374 parse_switch_with_opt_path, [TRACKED],
1375 "Generate PGO profile data, to a given file, or to the default location if it's empty."),
1376 pgo_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1377 "Use PGO profile data from the given profile file."),
1378 disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1379 "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1380 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1381 "choose which RELRO level to use"),
1382 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1383 "dump facts from NLL analysis into side files"),
1384 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1385 "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1386 dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1387 "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1388 polonius: bool = (false, parse_bool, [UNTRACKED],
1389 "enable polonius-based borrow-checker"),
1390 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1391 "generate a graphical HTML report of time spent in codegen and LLVM"),
1392 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1393 "enable ThinLTO when possible"),
1394 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1395 "control whether #[inline] functions are in all cgus"),
1396 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1397 "choose the TLS model to use (rustc --print tls-models for details)"),
1398 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1399 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1400 the max/min integer respectively, and NaN is mapped to 0"),
1401 lower_128bit_ops: Option<bool> = (None, parse_opt_bool, [TRACKED],
1402 "rewrite operators on i128 and u128 into lang item calls (typically provided \
1403 by compiler-builtins) so codegen doesn't need to support them,
1404 overriding the default for the current target"),
1405 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1406 "generate human-readable, predictable names for codegen units"),
1407 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1408 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1410 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1411 "Present the input source, unstable (and less-pretty) variants;
1412 valid types are any of the types for `--pretty`, as well as:
1413 `expanded`, `expanded,identified`,
1414 `expanded,hygiene` (with internal representations),
1415 `flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
1416 `flowgraph,unlabelled=<nodeid>` (unlabelled graphviz formatted flowgraph for node),
1417 `everybody_loops` (all function bodies replaced with `loop {}`),
1418 `hir` (the HIR), `hir,identified`,
1419 `hir,typed` (HIR with types for each node),
1420 `hir-tree` (dump the raw HIR),
1421 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1422 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1423 "run `dsymutil` and delete intermediate object files"),
1424 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1425 "format compiler diagnostics in a way that's better suitable for UI testing"),
1426 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1427 "embed LLVM bitcode in object files"),
1428 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1429 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1430 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1431 "make the current crate share its generic instantiations"),
1432 chalk: bool = (false, parse_bool, [TRACKED],
1433 "enable the experimental Chalk-based trait solving engine"),
1434 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1435 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1436 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1437 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1438 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1439 "don't interleave execution of lints; allows benchmarking individual lints"),
1440 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1441 "inject the given attribute in the crate"),
1442 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1443 parse_switch_with_opt_path, [UNTRACKED],
1444 "run the self profiler and output the raw event data"),
1445 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1446 "specifies which kinds of events get recorded by the self profiler"),
1447 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1448 "emits a section containing stack size metadata"),
1449 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1450 "whether to use the PLT when calling into shared libraries;
1451 only has effect for PIC code on systems with ELF binaries
1452 (default: PLT is disabled if full relro is enabled)"),
1453 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1454 "control the operation of the MergeFunctions LLVM pass, taking
1455 the same values as the target option of the same name"),
1456 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1457 "only allow the listed language features to be enabled in code (space separated)"),
1458 emit_artifact_notifications: bool = (false, parse_bool, [UNTRACKED],
1459 "emit notifications after each artifact has been output (only in the JSON format)"),
1462 pub fn default_lib_output() -> CrateType {
1466 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1467 let end = &sess.target.target.target_endian;
1468 let arch = &sess.target.target.arch;
1469 let wordsz = &sess.target.target.target_pointer_width;
1470 let os = &sess.target.target.target_os;
1471 let env = &sess.target.target.target_env;
1472 let vendor = &sess.target.target.target_vendor;
1473 let min_atomic_width = sess.target.target.min_atomic_width();
1474 let max_atomic_width = sess.target.target.max_atomic_width();
1475 let atomic_cas = sess.target.target.options.atomic_cas;
1477 let mut ret = FxHashSet::default();
1478 ret.reserve(6); // the minimum number of insertions
1480 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1481 if let Some(ref fam) = sess.target.target.options.target_family {
1482 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1483 if fam == "windows" || fam == "unix" {
1484 ret.insert((Symbol::intern(fam), None));
1487 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1488 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1490 Symbol::intern("target_pointer_width"),
1491 Some(Symbol::intern(wordsz)),
1493 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1495 Symbol::intern("target_vendor"),
1496 Some(Symbol::intern(vendor)),
1498 if sess.target.target.options.has_elf_tls {
1499 ret.insert((sym::target_thread_local, None));
1501 for &i in &[8, 16, 32, 64, 128] {
1502 if i >= min_atomic_width && i <= max_atomic_width {
1503 let s = i.to_string();
1505 sym::target_has_atomic,
1506 Some(Symbol::intern(&s)),
1510 sym::target_has_atomic,
1511 Some(Symbol::intern("ptr")),
1517 ret.insert((sym::target_has_atomic, Some(Symbol::intern("cas"))));
1519 if sess.opts.debug_assertions {
1520 ret.insert((Symbol::intern("debug_assertions"), None));
1522 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1523 ret.insert((sym::proc_macro, None));
1528 /// Converts the crate cfg! configuration from String to Symbol.
1529 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1530 /// but the symbol interner is not yet set up then, so we must convert it later.
1531 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
1533 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1537 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1538 // Combine the configuration requested by the session (command line) with
1539 // some default and generated configuration items
1540 let default_cfg = default_configuration(sess);
1541 // If the user wants a test runner, then add the test cfg
1543 user_cfg.insert((sym::test, None));
1545 user_cfg.extend(default_cfg.iter().cloned());
1549 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1550 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1551 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1552 .help("Use `--print target-list` for a list of built-in targets")
1557 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1558 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1559 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1560 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1561 w => sp.fatal(&format!(
1562 "target specification was invalid: \
1563 unrecognized target-pointer-width {}",
1575 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1576 pub enum OptionStability {
1581 pub struct RustcOptGroup {
1582 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1583 pub name: &'static str,
1584 pub stability: OptionStability,
1587 impl RustcOptGroup {
1588 pub fn is_stable(&self) -> bool {
1589 self.stability == OptionStability::Stable
1592 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1594 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1599 stability: OptionStability::Stable,
1603 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1605 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1610 stability: OptionStability::Unstable,
1615 // The `opt` local module holds wrappers around the `getopts` API that
1616 // adds extra rustc-specific metadata to each option; such metadata
1617 // is exposed by . The public
1618 // functions below ending with `_u` are the functions that return
1619 // *unstable* options, i.e., options that are only enabled when the
1620 // user also passes the `-Z unstable-options` debugging flag.
1622 // The `fn opt_u` etc below are written so that we can use them
1623 // in the future; do not warn about them not being used right now.
1624 #![allow(dead_code)]
1627 use super::RustcOptGroup;
1629 pub type R = RustcOptGroup;
1630 pub type S = &'static str;
1632 fn stable<F>(name: S, f: F) -> R
1634 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1636 RustcOptGroup::stable(name, f)
1639 fn unstable<F>(name: S, f: F) -> R
1641 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1643 RustcOptGroup::unstable(name, f)
1646 fn longer(a: S, b: S) -> S {
1647 if a.len() > b.len() {
1654 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1655 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1657 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1658 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1660 pub fn flag_s(a: S, b: S, c: S) -> R {
1661 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1663 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1664 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1666 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1667 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1670 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1671 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1673 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1674 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1676 pub fn flag(a: S, b: S, c: S) -> R {
1677 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1679 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1680 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1682 pub fn flagmulti(a: S, b: S, c: S) -> R {
1683 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1687 /// Returns the "short" subset of the rustc command line options,
1688 /// including metadata for each option, such as whether the option is
1689 /// part of the stable long-term interface for rustc.
1690 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1692 opt::flag_s("h", "help", "Display this message"),
1693 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1697 "Add a directory to the library search path. The
1698 optional KIND can be one of dependency, crate, native,
1699 framework or all (the default).",
1705 "Link the generated crate(s) to the specified native
1706 library NAME. The optional KIND can be one of
1707 static, dylib, or framework. If omitted, dylib is
1714 "Comma separated list of types of crates
1715 for the compiler to emit",
1716 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1721 "Specify the name of the crate being built",
1727 "Specify which edition of the compiler to use when compiling code.",
1733 "Comma separated list of types of output for \
1734 the compiler to emit",
1735 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1740 "Compiler information to print on stdout",
1741 "[crate-name|file-names|sysroot|cfg|target-list|\
1742 target-cpus|target-features|relocation-models|\
1743 code-models|tls-models|target-spec-json|native-static-libs]",
1745 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1746 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1747 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1751 "Write output to compiler-chosen filename \
1758 "Provide a detailed explanation of an error \
1762 opt::flag_s("", "test", "Build a test harness"),
1766 "Target triple for which the code is compiled",
1769 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1770 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1771 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1772 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1776 "Set the most restrictive lint level. \
1777 More restrictive lints are capped at this \
1781 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1782 opt::flag_s("V", "version", "Print version info and exit"),
1783 opt::flag_s("v", "verbose", "Use verbose output"),
1787 /// Returns all rustc command line options, including metadata for
1788 /// each option, such as whether the option is part of the stable
1789 /// long-term interface for rustc.
1790 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1791 let mut opts = rustc_short_optgroups();
1796 "Specify where an external rust library is located",
1802 "Specify where an extern rust library is located, marking it as a private dependency",
1805 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1806 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1810 "How errors and other messages are produced",
1816 "Choose `rendered` field of json diagnostics render scheme",
1822 "Configure coloring of output:
1823 auto = colorize, if output goes to a tty (default);
1824 always = always colorize output;
1825 never = never colorize output",
1826 "auto|always|never",
1831 "Pretty-print the input instead of compiling;
1832 valid types are: `normal` (un-annotated source),
1833 `expanded` (crates expanded), or
1834 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1839 "remap-path-prefix",
1840 "Remap source names in all output (compiler messages and output files)",
1847 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
1848 pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
1849 syntax::with_default_globals(move || {
1850 let cfg = cfgspecs.into_iter().map(|s| {
1851 let sess = parse::ParseSess::new(FilePathMapping::empty());
1852 let filename = FileName::cfg_spec_source_code(&s);
1853 let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string());
1855 macro_rules! error {($reason: expr) => {
1856 early_error(ErrorOutputType::default(),
1857 &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s));
1860 match &mut parser.parse_meta_item() {
1861 Ok(meta_item) if parser.token == token::Eof => {
1862 if meta_item.path.segments.len() != 1 {
1863 error!("argument key must be an identifier");
1865 match &meta_item.node {
1866 MetaItemKind::List(..) => {
1867 error!(r#"expected `key` or `key="value"`"#);
1869 MetaItemKind::NameValue(lit) if !lit.node.is_str() => {
1870 error!("argument value must be a string");
1872 MetaItemKind::NameValue(..) | MetaItemKind::Word => {
1873 let ident = meta_item.ident().expect("multi-segment cfg key");
1874 return (ident.name, meta_item.value_str());
1879 Err(err) => err.cancel(),
1882 error!(r#"expected `key` or `key="value"`"#);
1883 }).collect::<ast::CrateConfig>();
1884 cfg.into_iter().map(|(a, b)| {
1885 (a.to_string(), b.map(|b| b.to_string()))
1890 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1891 error_format: ErrorOutputType)
1892 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1893 let mut lint_opts = vec![];
1894 let mut describe_lints = false;
1896 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1897 for lint_name in matches.opt_strs(level.as_str()) {
1898 if lint_name == "help" {
1899 describe_lints = true;
1901 lint_opts.push((lint_name.replace("-", "_"), level));
1906 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1907 lint::Level::from_str(&cap)
1908 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1910 (lint_opts, describe_lints, lint_cap)
1913 pub fn build_session_options_and_crate_config(
1914 matches: &getopts::Matches,
1915 ) -> (Options, FxHashSet<(String, Option<String>)>) {
1916 let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1917 Some("auto") => ColorConfig::Auto,
1918 Some("always") => ColorConfig::Always,
1919 Some("never") => ColorConfig::Never,
1921 None => ColorConfig::Auto,
1923 Some(arg) => early_error(
1924 ErrorOutputType::default(),
1926 "argument for --color must be auto, \
1927 always or never (instead was `{}`)",
1933 let edition = match matches.opt_str("edition") {
1934 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
1936 ErrorOutputType::default(),
1938 "argument for --edition must be one of: \
1939 {}. (instead was `{}`)",
1945 None => DEFAULT_EDITION,
1948 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1950 ErrorOutputType::default(),
1952 "Edition {} is unstable and only \
1953 available for nightly builds of rustc.",
1959 let json_rendered = matches.opt_str("json-rendered").and_then(|s| match s.as_str() {
1961 "termcolor" => Some(HumanReadableErrorType::Default(ColorConfig::Always)),
1963 ErrorOutputType::default(),
1965 "argument for --json-rendered must be `plain` or `termcolor` (instead was `{}`)",
1969 }).unwrap_or(HumanReadableErrorType::Default(ColorConfig::Never));
1971 // We need the opts_present check because the driver will send us Matches
1972 // with only stable options if no unstable options are used. Since error-format
1973 // is unstable, it will not be present. We have to use opts_present not
1974 // opt_present because the latter will panic.
1975 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1976 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1978 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1979 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1980 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1981 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1983 Some(arg) => early_error(
1984 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1986 "argument for --error-format must be `human`, `json` or \
1987 `short` (instead was `{}`)",
1993 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1996 let unparsed_crate_types = matches.opt_strs("crate-type");
1997 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1998 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2001 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2003 let mut debugging_opts = build_debugging_options(matches, error_format);
2005 if !debugging_opts.unstable_options {
2006 if matches.opt_str("json-rendered").is_some() {
2007 early_error(error_format, "`--json-rendered=x` is unstable");
2009 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2011 ErrorOutputType::Json { pretty: false, json_rendered },
2012 "--error-format=pretty-json is unstable",
2017 if debugging_opts.pgo_gen.enabled() && debugging_opts.pgo_use.is_some() {
2020 "options `-Z pgo-gen` and `-Z pgo-use` are exclusive",
2024 let mut output_types = BTreeMap::new();
2025 if !debugging_opts.parse_only {
2026 for list in matches.opt_strs("emit") {
2027 for output_type in list.split(',') {
2028 let mut parts = output_type.splitn(2, '=');
2029 let shorthand = parts.next().unwrap();
2030 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2034 "unknown emission type: `{}` - expected one of: {}",
2036 OutputType::shorthands_display(),
2040 let path = parts.next().map(PathBuf::from);
2041 output_types.insert(output_type, path);
2045 if output_types.is_empty() {
2046 output_types.insert(OutputType::Exe, None);
2049 let mut cg = build_codegen_options(matches, error_format);
2050 let mut codegen_units = cg.codegen_units;
2051 let mut disable_thinlto = false;
2053 // Issue #30063: if user requests llvm-related output to one
2054 // particular path, disable codegen-units.
2055 let incompatible: Vec<_> = output_types
2057 .map(|ot_path| ot_path.0)
2058 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2059 .map(|ot| ot.shorthand())
2061 if !incompatible.is_empty() {
2062 match codegen_units {
2063 Some(n) if n > 1 => {
2064 if matches.opt_present("o") {
2065 for ot in &incompatible {
2069 "--emit={} with -o incompatible with \
2070 -C codegen-units=N for N > 1",
2075 early_warn(error_format, "resetting to default -C codegen-units=1");
2076 codegen_units = Some(1);
2077 disable_thinlto = true;
2081 codegen_units = Some(1);
2082 disable_thinlto = true;
2087 if debugging_opts.threads == Some(0) {
2090 "Value for threads must be a positive nonzero integer",
2094 if debugging_opts.threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() {
2097 "Optimization fuel is incompatible with multiple threads",
2101 if codegen_units == Some(0) {
2104 "Value for codegen units must be a positive nonzero integer",
2108 let incremental = match (&debugging_opts.incremental, &cg.incremental) {
2109 (&Some(ref path1), &Some(ref path2)) => {
2114 "conflicting paths for `-Z incremental` and \
2115 `-C incremental` specified: {} versus {}",
2123 (&Some(ref path), &None) => Some(path),
2124 (&None, &Some(ref path)) => Some(path),
2125 (&None, &None) => None,
2126 }.map(|m| PathBuf::from(m));
2128 if debugging_opts.profile && incremental.is_some() {
2131 "can't instrument with gcov profiling when compiling incrementally",
2135 let mut prints = Vec::<PrintRequest>::new();
2136 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2137 prints.push(PrintRequest::TargetCPUs);
2138 cg.target_cpu = None;
2140 if cg.target_feature == "help" {
2141 prints.push(PrintRequest::TargetFeatures);
2142 cg.target_feature = String::new();
2144 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2145 prints.push(PrintRequest::RelocationModels);
2146 cg.relocation_model = None;
2148 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2149 prints.push(PrintRequest::CodeModels);
2150 cg.code_model = None;
2155 .map_or(false, |s| s == "help")
2157 prints.push(PrintRequest::TlsModels);
2158 debugging_opts.tls_model = None;
2163 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2164 let target_triple = if let Some(target) = matches.opt_str("target") {
2165 if target.ends_with(".json") {
2166 let path = Path::new(&target);
2167 TargetTriple::from_path(&path).unwrap_or_else(|_|
2168 early_error(error_format, &format!("target file {:?} does not exist", path)))
2170 TargetTriple::TargetTriple(target)
2173 TargetTriple::from_triple(host_triple())
2176 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2177 // to use them interchangeably. However, because they're technically different flags,
2178 // we need to work out manually which should take precedence if both are supplied (i.e.
2179 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2180 // comparing them. Note that if a flag is not found, its position will be `None`, which
2181 // always compared less than `Some(_)`.
2182 let max_o = matches.opt_positions("O").into_iter().max();
2183 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2184 if let Some("opt-level") = s.splitn(2, '=').next() {
2193 match cg.opt_level.as_ref().map(String::as_ref) {
2194 None => OptLevel::No,
2195 Some("0") => OptLevel::No,
2196 Some("1") => OptLevel::Less,
2197 Some("2") => OptLevel::Default,
2198 Some("3") => OptLevel::Aggressive,
2199 Some("s") => OptLevel::Size,
2200 Some("z") => OptLevel::SizeMin,
2205 "optimization level needs to be \
2206 between 0-3, s or z (instead was `{}`)",
2214 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2215 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2216 // for more details.
2217 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2218 let max_g = matches.opt_positions("g").into_iter().max();
2219 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2220 if let Some("debuginfo") = s.splitn(2, '=').next() {
2226 let debuginfo = if max_g > max_c {
2229 match cg.debuginfo {
2230 None | Some(0) => DebugInfo::None,
2231 Some(1) => DebugInfo::Limited,
2232 Some(2) => DebugInfo::Full,
2237 "debug info level needs to be between \
2238 0-2 (instead was `{}`)",
2246 let mut search_paths = vec![];
2247 for s in &matches.opt_strs("L") {
2248 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2255 // Parse string of the form "[KIND=]lib[:new_name]",
2256 // where KIND is one of "dylib", "framework", "static".
2257 let mut parts = s.splitn(2, '=');
2258 let kind = parts.next().unwrap();
2259 let (name, kind) = match (parts.next(), kind) {
2260 (None, name) => (name, None),
2261 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2262 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2263 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2264 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2269 "unknown library kind `{}`, expected \
2270 one of dylib, framework, or static",
2276 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2280 "the library kind 'static-nobundle' is only \
2281 accepted on the nightly compiler"
2285 let mut name_parts = name.splitn(2, ':');
2286 let name = name_parts.next().unwrap();
2287 let new_name = name_parts.next();
2288 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2292 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
2293 let test = matches.opt_present("test");
2295 let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
2297 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2298 "crate-name" => PrintRequest::CrateName,
2299 "file-names" => PrintRequest::FileNames,
2300 "sysroot" => PrintRequest::Sysroot,
2301 "cfg" => PrintRequest::Cfg,
2302 "target-list" => PrintRequest::TargetList,
2303 "target-cpus" => PrintRequest::TargetCPUs,
2304 "target-features" => PrintRequest::TargetFeatures,
2305 "relocation-models" => PrintRequest::RelocationModels,
2306 "code-models" => PrintRequest::CodeModels,
2307 "tls-models" => PrintRequest::TlsModels,
2308 "native-static-libs" => PrintRequest::NativeStaticLibs,
2309 "target-spec-json" => {
2310 if is_unstable_enabled {
2311 PrintRequest::TargetSpec
2315 "the `-Z unstable-options` flag must also be passed to \
2316 enable the target-spec-json print option",
2320 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2323 let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) {
2324 None | Some("migrate") => BorrowckMode::Migrate,
2325 Some("mir") => BorrowckMode::Mir,
2326 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2329 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2332 "-C remark requires \"-C debuginfo=n\" to show source locations",
2336 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2338 ErrorOutputType::default(),
2339 "'--extern-private' is unstable and only \
2340 available for nightly builds of rustc."
2344 // We start out with a Vec<(Option<String>, bool)>>,
2345 // and later convert it into a BTreeSet<(Option<String>, bool)>
2346 // This allows to modify entries in-place to set their correct
2348 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2349 for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
2350 .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
2352 let mut parts = arg.splitn(2, '=');
2353 let name = parts.next().unwrap_or_else(||
2354 early_error(error_format, "--extern value must not be empty"));
2355 let location = parts.next().map(|s| s.to_string());
2356 if location.is_none() && !is_unstable_enabled {
2359 "the `-Z unstable-options` flag must also be passed to \
2360 enable `--extern crate_name` without `=path`",
2365 .entry(name.to_owned())
2369 entry.locations.insert(location.clone());
2371 // Crates start out being not private,
2372 // and go to being private if we see an '--extern-private'
2374 entry.is_private_dep |= private;
2377 let crate_name = matches.opt_str("crate-name");
2379 let remap_path_prefix = matches
2380 .opt_strs("remap-path-prefix")
2383 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2384 let to = parts.next();
2385 let from = parts.next();
2387 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2390 "--remap-path-prefix must contain '=' between FROM and TO",
2399 optimize: opt_level,
2404 output_types: OutputTypes(output_types),
2406 maybe_sysroot: sysroot_opt,
2415 externs: Externs(externs),
2419 unstable_features: UnstableFeatures::from_environment(),
2421 actually_rustdoc: false,
2422 cli_forced_codegen_units: codegen_units,
2423 cli_forced_thinlto_off: disable_thinlto,
2431 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2432 let mut crate_types: Vec<CrateType> = Vec::new();
2433 for unparsed_crate_type in &list_list {
2434 for part in unparsed_crate_type.split(',') {
2435 let new_part = match part {
2436 "lib" => default_lib_output(),
2437 "rlib" => CrateType::Rlib,
2438 "staticlib" => CrateType::Staticlib,
2439 "dylib" => CrateType::Dylib,
2440 "cdylib" => CrateType::Cdylib,
2441 "bin" => CrateType::Executable,
2442 "proc-macro" => CrateType::ProcMacro,
2443 _ => return Err(format!("unknown crate type: `{}`", part))
2445 if !crate_types.contains(&new_part) {
2446 crate_types.push(new_part)
2454 pub mod nightly_options {
2456 use syntax::feature_gate::UnstableFeatures;
2457 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2458 use crate::session::early_error;
2460 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2465 .any(|x| *x == "unstable-options")
2468 pub fn is_nightly_build() -> bool {
2469 UnstableFeatures::from_environment().is_nightly_build()
2472 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2473 let has_z_unstable_option = matches
2476 .any(|x| *x == "unstable-options");
2477 let really_allows_unstable_options =
2478 UnstableFeatures::from_environment().is_nightly_build();
2480 for opt in flags.iter() {
2481 if opt.stability == OptionStability::Stable {
2484 if !matches.opt_present(opt.name) {
2487 if opt.name != "Z" && !has_z_unstable_option {
2489 ErrorOutputType::default(),
2491 "the `-Z unstable-options` flag must also be passed to enable \
2497 if really_allows_unstable_options {
2500 match opt.stability {
2501 OptionStability::Unstable => {
2503 "the option `{}` is only accepted on the \
2507 early_error(ErrorOutputType::default(), &msg);
2509 OptionStability::Stable => {}
2515 impl fmt::Display for CrateType {
2516 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2518 CrateType::Executable => "bin".fmt(f),
2519 CrateType::Dylib => "dylib".fmt(f),
2520 CrateType::Rlib => "rlib".fmt(f),
2521 CrateType::Staticlib => "staticlib".fmt(f),
2522 CrateType::Cdylib => "cdylib".fmt(f),
2523 CrateType::ProcMacro => "proc-macro".fmt(f),
2528 /// Command-line arguments passed to the compiler have to be incorporated with
2529 /// the dependency tracking system for incremental compilation. This module
2530 /// provides some utilities to make this more convenient.
2532 /// The values of all command-line arguments that are relevant for dependency
2533 /// tracking are hashed into a single value that determines whether the
2534 /// incremental compilation cache can be re-used or not. This hashing is done
2535 /// via the DepTrackingHash trait defined below, since the standard Hash
2536 /// implementation might not be suitable (e.g., arguments are stored in a Vec,
2537 /// the hash of which is order dependent, but we might not want the order of
2538 /// arguments to make a difference for the hash).
2540 /// However, since the value provided by Hash::hash often *is* suitable,
2541 /// especially for primitive types, there is the
2542 /// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
2543 /// Hash implementation for DepTrackingHash. It's important though that
2544 /// we have an opt-in scheme here, so one is hopefully forced to think about
2545 /// how the hash should be calculated when adding a new command-line argument.
2548 use crate::middle::cstore;
2549 use std::collections::BTreeMap;
2550 use std::hash::Hash;
2551 use std::path::PathBuf;
2552 use std::collections::hash_map::DefaultHasher;
2553 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2554 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath};
2555 use syntax::feature_gate::UnstableFeatures;
2556 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2557 use syntax::edition::Edition;
2559 pub trait DepTrackingHash {
2560 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2563 macro_rules! impl_dep_tracking_hash_via_hash {
2565 impl DepTrackingHash for $t {
2566 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2567 Hash::hash(self, hasher);
2573 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2575 impl DepTrackingHash for Vec<$t> {
2576 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2577 let mut elems: Vec<&$t> = self.iter().collect();
2579 Hash::hash(&elems.len(), hasher);
2580 for (index, elem) in elems.iter().enumerate() {
2581 Hash::hash(&index, hasher);
2582 DepTrackingHash::hash(*elem, hasher, error_format);
2589 impl_dep_tracking_hash_via_hash!(bool);
2590 impl_dep_tracking_hash_via_hash!(usize);
2591 impl_dep_tracking_hash_via_hash!(u64);
2592 impl_dep_tracking_hash_via_hash!(String);
2593 impl_dep_tracking_hash_via_hash!(PathBuf);
2594 impl_dep_tracking_hash_via_hash!(lint::Level);
2595 impl_dep_tracking_hash_via_hash!(Option<bool>);
2596 impl_dep_tracking_hash_via_hash!(Option<usize>);
2597 impl_dep_tracking_hash_via_hash!(Option<String>);
2598 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2599 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2600 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2601 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2602 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2603 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2604 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2605 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2606 impl_dep_tracking_hash_via_hash!(CrateType);
2607 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2608 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2609 impl_dep_tracking_hash_via_hash!(RelroLevel);
2610 impl_dep_tracking_hash_via_hash!(Passes);
2611 impl_dep_tracking_hash_via_hash!(OptLevel);
2612 impl_dep_tracking_hash_via_hash!(LtoCli);
2613 impl_dep_tracking_hash_via_hash!(DebugInfo);
2614 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2615 impl_dep_tracking_hash_via_hash!(OutputTypes);
2616 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2617 impl_dep_tracking_hash_via_hash!(Sanitizer);
2618 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2619 impl_dep_tracking_hash_via_hash!(TargetTriple);
2620 impl_dep_tracking_hash_via_hash!(Edition);
2621 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2622 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2624 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2625 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2626 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2627 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2628 impl_dep_tracking_hash_for_sortable_vec_of!((
2631 Option<cstore::NativeLibraryKind>
2633 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2635 impl<T1, T2> DepTrackingHash for (T1, T2)
2637 T1: DepTrackingHash,
2638 T2: DepTrackingHash,
2640 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2641 Hash::hash(&0, hasher);
2642 DepTrackingHash::hash(&self.0, hasher, error_format);
2643 Hash::hash(&1, hasher);
2644 DepTrackingHash::hash(&self.1, hasher, error_format);
2648 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2650 T1: DepTrackingHash,
2651 T2: DepTrackingHash,
2652 T3: DepTrackingHash,
2654 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2655 Hash::hash(&0, hasher);
2656 DepTrackingHash::hash(&self.0, hasher, error_format);
2657 Hash::hash(&1, hasher);
2658 DepTrackingHash::hash(&self.1, hasher, error_format);
2659 Hash::hash(&2, hasher);
2660 DepTrackingHash::hash(&self.2, hasher, error_format);
2664 // This is a stable hash because BTreeMap is a sorted container
2666 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2667 hasher: &mut DefaultHasher,
2668 error_format: ErrorOutputType,
2670 for (key, sub_hash) in sub_hashes {
2671 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2672 // the keys, as they are just plain strings
2673 Hash::hash(&key.len(), hasher);
2674 Hash::hash(key, hasher);
2675 sub_hash.hash(hasher, error_format);
2684 use crate::middle::cstore;
2685 use crate::session::config::{
2686 build_configuration,
2687 build_session_options_and_crate_config,
2690 use crate::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry};
2691 use crate::session::build_session;
2692 use crate::session::search_paths::SearchPath;
2693 use std::collections::{BTreeMap, BTreeSet};
2694 use std::iter::FromIterator;
2695 use std::path::PathBuf;
2696 use super::{Externs, OutputType, OutputTypes};
2697 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
2698 use syntax::symbol::sym;
2699 use syntax::edition::{Edition, DEFAULT_EDITION};
2704 fn new_public<S: Into<String>,
2705 I: IntoIterator<Item = Option<S>>>(locations: I) -> ExternEntry {
2706 let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into()))
2711 is_private_dep: false
2716 fn optgroups() -> getopts::Options {
2717 let mut opts = getopts::Options::new();
2718 for group in super::rustc_optgroups() {
2719 (group.apply)(&mut opts);
2724 fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
2725 BTreeMap::from_iter(entries.into_iter())
2728 // When the user supplies --test we should implicitly supply --cfg test
2730 fn test_switch_implies_cfg_test() {
2731 syntax::with_default_globals(|| {
2732 let matches = &match optgroups().parse(&["--test".to_string()]) {
2734 Err(f) => panic!("test_switch_implies_cfg_test: {}", f),
2736 let registry = errors::registry::Registry::new(&[]);
2737 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2738 let sess = build_session(sessopts, None, registry);
2739 let cfg = build_configuration(&sess, to_crate_config(cfg));
2740 assert!(cfg.contains(&(sym::test, None)));
2744 // When the user supplies --test and --cfg test, don't implicitly add
2745 // another --cfg test
2747 fn test_switch_implies_cfg_test_unless_cfg_test() {
2748 syntax::with_default_globals(|| {
2749 let matches = &match optgroups().parse(&["--test".to_string(),
2750 "--cfg=test".to_string()]) {
2752 Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f),
2754 let registry = errors::registry::Registry::new(&[]);
2755 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2756 let sess = build_session(sessopts, None, registry);
2757 let cfg = build_configuration(&sess, to_crate_config(cfg));
2758 let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
2759 assert!(test_items.next().is_some());
2760 assert!(test_items.next().is_none());
2765 fn test_can_print_warnings() {
2766 syntax::with_default_globals(|| {
2767 let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
2768 let registry = errors::registry::Registry::new(&[]);
2769 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2770 let sess = build_session(sessopts, None, registry);
2771 assert!(!sess.diagnostic().flags.can_emit_warnings);
2774 syntax::with_default_globals(|| {
2775 let matches = optgroups()
2776 .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()])
2778 let registry = errors::registry::Registry::new(&[]);
2779 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2780 let sess = build_session(sessopts, None, registry);
2781 assert!(sess.diagnostic().flags.can_emit_warnings);
2784 syntax::with_default_globals(|| {
2785 let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
2786 let registry = errors::registry::Registry::new(&[]);
2787 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2788 let sess = build_session(sessopts, None, registry);
2789 assert!(sess.diagnostic().flags.can_emit_warnings);
2794 fn test_output_types_tracking_hash_different_paths() {
2795 let mut v1 = Options::default();
2796 let mut v2 = Options::default();
2797 let mut v3 = Options::default();
2800 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
2802 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
2803 v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
2805 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2806 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2807 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2810 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2811 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2812 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2816 fn test_output_types_tracking_hash_different_construction_order() {
2817 let mut v1 = Options::default();
2818 let mut v2 = Options::default();
2820 v1.output_types = OutputTypes::new(&[
2821 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2822 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2825 v2.output_types = OutputTypes::new(&[
2826 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2827 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2830 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2833 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2837 fn test_externs_tracking_hash_different_construction_order() {
2838 let mut v1 = Options::default();
2839 let mut v2 = Options::default();
2840 let mut v3 = Options::default();
2842 v1.externs = Externs::new(mk_map(vec![
2845 ExternEntry::new_public(vec![Some("b"), Some("c")])
2849 ExternEntry::new_public(vec![Some("e"), Some("f")])
2853 v2.externs = Externs::new(mk_map(vec![
2856 ExternEntry::new_public(vec![Some("e"), Some("f")])
2860 ExternEntry::new_public(vec![Some("b"), Some("c")])
2864 v3.externs = Externs::new(mk_map(vec![
2867 ExternEntry::new_public(vec![Some("b"), Some("c")])
2871 ExternEntry::new_public(vec![Some("f"), Some("e")])
2875 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2876 assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
2877 assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
2880 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2881 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2882 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2886 fn test_lints_tracking_hash_different_values() {
2887 let mut v1 = Options::default();
2888 let mut v2 = Options::default();
2889 let mut v3 = Options::default();
2891 v1.lint_opts = vec![
2892 (String::from("a"), lint::Allow),
2893 (String::from("b"), lint::Warn),
2894 (String::from("c"), lint::Deny),
2895 (String::from("d"), lint::Forbid),
2898 v2.lint_opts = vec![
2899 (String::from("a"), lint::Allow),
2900 (String::from("b"), lint::Warn),
2901 (String::from("X"), lint::Deny),
2902 (String::from("d"), lint::Forbid),
2905 v3.lint_opts = vec![
2906 (String::from("a"), lint::Allow),
2907 (String::from("b"), lint::Warn),
2908 (String::from("c"), lint::Forbid),
2909 (String::from("d"), lint::Deny),
2912 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2913 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2914 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2917 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2918 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2919 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2923 fn test_lints_tracking_hash_different_construction_order() {
2924 let mut v1 = Options::default();
2925 let mut v2 = Options::default();
2927 v1.lint_opts = vec![
2928 (String::from("a"), lint::Allow),
2929 (String::from("b"), lint::Warn),
2930 (String::from("c"), lint::Deny),
2931 (String::from("d"), lint::Forbid),
2934 v2.lint_opts = vec![
2935 (String::from("a"), lint::Allow),
2936 (String::from("c"), lint::Deny),
2937 (String::from("b"), lint::Warn),
2938 (String::from("d"), lint::Forbid),
2941 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2944 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2945 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2949 fn test_search_paths_tracking_hash_different_order() {
2950 let mut v1 = Options::default();
2951 let mut v2 = Options::default();
2952 let mut v3 = Options::default();
2953 let mut v4 = Options::default();
2955 const JSON: super::ErrorOutputType = super::ErrorOutputType::Json {
2957 json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never),
2962 .push(SearchPath::from_cli_opt("native=abc", JSON));
2964 .push(SearchPath::from_cli_opt("crate=def", JSON));
2966 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2968 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2970 .push(SearchPath::from_cli_opt("all=mno", JSON));
2973 .push(SearchPath::from_cli_opt("native=abc", JSON));
2975 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2977 .push(SearchPath::from_cli_opt("crate=def", JSON));
2979 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2981 .push(SearchPath::from_cli_opt("all=mno", JSON));
2984 .push(SearchPath::from_cli_opt("crate=def", JSON));
2986 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
2988 .push(SearchPath::from_cli_opt("native=abc", JSON));
2990 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
2992 .push(SearchPath::from_cli_opt("all=mno", JSON));
2995 .push(SearchPath::from_cli_opt("all=mno", JSON));
2997 .push(SearchPath::from_cli_opt("native=abc", JSON));
2999 .push(SearchPath::from_cli_opt("crate=def", JSON));
3001 .push(SearchPath::from_cli_opt("dependency=ghi", JSON));
3003 .push(SearchPath::from_cli_opt("framework=jkl", JSON));
3005 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
3006 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
3007 assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
3010 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3011 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3012 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3013 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
3017 fn test_native_libs_tracking_hash_different_values() {
3018 let mut v1 = Options::default();
3019 let mut v2 = Options::default();
3020 let mut v3 = Options::default();
3021 let mut v4 = Options::default();
3025 (String::from("a"), None, Some(cstore::NativeStatic)),
3026 (String::from("b"), None, Some(cstore::NativeFramework)),
3027 (String::from("c"), None, Some(cstore::NativeUnknown)),
3032 (String::from("a"), None, Some(cstore::NativeStatic)),
3033 (String::from("X"), None, Some(cstore::NativeFramework)),
3034 (String::from("c"), None, Some(cstore::NativeUnknown)),
3039 (String::from("a"), None, Some(cstore::NativeStatic)),
3040 (String::from("b"), None, Some(cstore::NativeStatic)),
3041 (String::from("c"), None, Some(cstore::NativeUnknown)),
3046 (String::from("a"), None, Some(cstore::NativeStatic)),
3049 Some(String::from("X")),
3050 Some(cstore::NativeFramework),
3052 (String::from("c"), None, Some(cstore::NativeUnknown)),
3055 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
3056 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
3057 assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
3060 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3061 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3062 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3063 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
3067 fn test_native_libs_tracking_hash_different_order() {
3068 let mut v1 = Options::default();
3069 let mut v2 = Options::default();
3070 let mut v3 = Options::default();
3074 (String::from("a"), None, Some(cstore::NativeStatic)),
3075 (String::from("b"), None, Some(cstore::NativeFramework)),
3076 (String::from("c"), None, Some(cstore::NativeUnknown)),
3080 (String::from("b"), None, Some(cstore::NativeFramework)),
3081 (String::from("a"), None, Some(cstore::NativeStatic)),
3082 (String::from("c"), None, Some(cstore::NativeUnknown)),
3086 (String::from("c"), None, Some(cstore::NativeUnknown)),
3087 (String::from("a"), None, Some(cstore::NativeStatic)),
3088 (String::from("b"), None, Some(cstore::NativeFramework)),
3091 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
3092 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
3093 assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
3096 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
3097 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
3098 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
3102 fn test_codegen_options_tracking_hash() {
3103 let reference = Options::default();
3104 let mut opts = Options::default();
3106 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3107 opts.cg.ar = Some(String::from("abc"));
3108 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3110 opts.cg.linker = Some(PathBuf::from("linker"));
3111 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3113 opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
3114 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3116 opts.cg.link_dead_code = true;
3117 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3119 opts.cg.rpath = true;
3120 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3122 opts.cg.extra_filename = String::from("extra-filename");
3123 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3125 opts.cg.codegen_units = Some(42);
3126 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3128 opts.cg.remark = super::Passes::Some(vec![String::from("pass1"), String::from("pass2")]);
3129 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3131 opts.cg.save_temps = true;
3132 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3134 opts.cg.incremental = Some(String::from("abc"));
3135 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3137 // Make sure changing a [TRACKED] option changes the hash
3138 opts = reference.clone();
3139 opts.cg.lto = LtoCli::Fat;
3140 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3142 opts = reference.clone();
3143 opts.cg.target_cpu = Some(String::from("abc"));
3144 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3146 opts = reference.clone();
3147 opts.cg.target_feature = String::from("all the features, all of them");
3148 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3150 opts = reference.clone();
3151 opts.cg.passes = vec![String::from("1"), String::from("2")];
3152 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3154 opts = reference.clone();
3155 opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
3156 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3158 opts = reference.clone();
3159 opts.cg.overflow_checks = Some(true);
3160 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3162 opts = reference.clone();
3163 opts.cg.no_prepopulate_passes = true;
3164 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3166 opts = reference.clone();
3167 opts.cg.no_vectorize_loops = true;
3168 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3170 opts = reference.clone();
3171 opts.cg.no_vectorize_slp = true;
3172 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3174 opts = reference.clone();
3175 opts.cg.soft_float = true;
3176 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3178 opts = reference.clone();
3179 opts.cg.prefer_dynamic = true;
3180 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3182 opts = reference.clone();
3183 opts.cg.no_integrated_as = true;
3184 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3186 opts = reference.clone();
3187 opts.cg.no_redzone = Some(true);
3188 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3190 opts = reference.clone();
3191 opts.cg.relocation_model = Some(String::from("relocation model"));
3192 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3194 opts = reference.clone();
3195 opts.cg.code_model = Some(String::from("code model"));
3196 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3198 opts = reference.clone();
3199 opts.debugging_opts.tls_model = Some(String::from("tls model"));
3200 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3202 opts = reference.clone();
3203 opts.debugging_opts.pgo_gen = SwitchWithOptPath::Enabled(None);
3204 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3206 opts = reference.clone();
3207 opts.debugging_opts.pgo_use = Some(PathBuf::from("abc"));
3208 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3210 opts = reference.clone();
3211 opts.cg.metadata = vec![String::from("A"), String::from("B")];
3212 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3214 opts = reference.clone();
3215 opts.cg.debuginfo = Some(0xdeadbeef);
3216 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3218 opts = reference.clone();
3219 opts.cg.debuginfo = Some(0xba5eba11);
3220 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3222 opts = reference.clone();
3223 opts.cg.force_frame_pointers = Some(false);
3224 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3226 opts = reference.clone();
3227 opts.cg.debug_assertions = Some(true);
3228 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3230 opts = reference.clone();
3231 opts.cg.inline_threshold = Some(0xf007ba11);
3232 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3234 opts = reference.clone();
3235 opts.cg.panic = Some(PanicStrategy::Abort);
3236 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3238 opts = reference.clone();
3239 opts.cg.linker_plugin_lto = LinkerPluginLto::LinkerPluginAuto;
3240 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3244 fn test_debugging_options_tracking_hash() {
3245 let reference = Options::default();
3246 let mut opts = Options::default();
3248 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3249 opts.debugging_opts.verbose = true;
3250 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3251 opts.debugging_opts.time_passes = true;
3252 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3253 opts.debugging_opts.time_llvm_passes = true;
3254 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3255 opts.debugging_opts.input_stats = true;
3256 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3257 opts.debugging_opts.borrowck_stats = true;
3258 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3259 opts.debugging_opts.meta_stats = true;
3260 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3261 opts.debugging_opts.print_link_args = true;
3262 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3263 opts.debugging_opts.print_llvm_passes = true;
3264 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3265 opts.debugging_opts.ast_json = true;
3266 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3267 opts.debugging_opts.ast_json_noexpand = true;
3268 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3269 opts.debugging_opts.ls = true;
3270 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3271 opts.debugging_opts.save_analysis = true;
3272 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3273 opts.debugging_opts.flowgraph_print_loans = true;
3274 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3275 opts.debugging_opts.flowgraph_print_moves = true;
3276 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3277 opts.debugging_opts.flowgraph_print_assigns = true;
3278 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3279 opts.debugging_opts.flowgraph_print_all = true;
3280 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3281 opts.debugging_opts.print_region_graph = true;
3282 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3283 opts.debugging_opts.parse_only = true;
3284 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3285 opts.debugging_opts.incremental = Some(String::from("abc"));
3286 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3287 opts.debugging_opts.dump_dep_graph = true;
3288 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3289 opts.debugging_opts.query_dep_graph = true;
3290 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3291 opts.debugging_opts.no_analysis = true;
3292 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3293 opts.debugging_opts.unstable_options = true;
3294 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3295 opts.debugging_opts.trace_macros = true;
3296 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3297 opts.debugging_opts.keep_hygiene_data = true;
3298 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3299 opts.debugging_opts.keep_ast = true;
3300 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3301 opts.debugging_opts.print_mono_items = Some(String::from("abc"));
3302 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3303 opts.debugging_opts.dump_mir = Some(String::from("abc"));
3304 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3305 opts.debugging_opts.dump_mir_dir = String::from("abc");
3306 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3307 opts.debugging_opts.dump_mir_graphviz = true;
3308 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3310 // Make sure changing a [TRACKED] option changes the hash
3311 opts = reference.clone();
3312 opts.debugging_opts.asm_comments = true;
3313 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3315 opts = reference.clone();
3316 opts.debugging_opts.verify_llvm_ir = true;
3317 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3319 opts = reference.clone();
3320 opts.debugging_opts.no_landing_pads = true;
3321 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3323 opts = reference.clone();
3324 opts.debugging_opts.fewer_names = true;
3325 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3327 opts = reference.clone();
3328 opts.debugging_opts.no_codegen = true;
3329 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3331 opts = reference.clone();
3332 opts.debugging_opts.treat_err_as_bug = Some(1);
3333 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3335 opts = reference.clone();
3336 opts.debugging_opts.report_delayed_bugs = true;
3337 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3339 opts = reference.clone();
3340 opts.debugging_opts.continue_parse_after_error = true;
3341 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3343 opts = reference.clone();
3344 opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
3345 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3347 opts = reference.clone();
3348 opts.debugging_opts.force_overflow_checks = Some(true);
3349 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3351 opts = reference.clone();
3352 opts.debugging_opts.show_span = Some(String::from("abc"));
3353 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3355 opts = reference.clone();
3356 opts.debugging_opts.mir_opt_level = 3;
3357 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3359 opts = reference.clone();
3360 opts.debugging_opts.relro_level = Some(RelroLevel::Full);
3361 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3363 opts = reference.clone();
3364 opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
3365 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3367 opts = reference.clone();
3368 opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
3369 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3373 fn test_edition_parsing() {
3374 // test default edition
3375 let options = Options::default();
3376 assert!(options.edition == DEFAULT_EDITION);
3378 let matches = optgroups()
3379 .parse(&["--edition=2018".to_string()])
3381 let (sessopts, _) = build_session_options_and_crate_config(&matches);
3382 assert!(sessopts.edition == Edition::Edition2018)