1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Contains infrastructure for configuring the compiler, including parsing
12 //! command line options.
14 pub use self::EntryFnType::*;
15 pub use self::CrateType::*;
16 pub use self::Passes::*;
17 pub use self::DebugInfoLevel::*;
19 use std::str::FromStr;
21 use session::{early_error, early_warn, Session};
22 use session::search_paths::SearchPaths;
24 use ich::StableHashingContext;
25 use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
26 use rustc_target::spec::{Target, TargetTriple};
27 use rustc_data_structures::stable_hasher::ToStableHashKey;
31 use syntax::ast::{self, IntTy, UintTy};
32 use syntax::codemap::{FileName, FilePathMapping};
33 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
34 use syntax::parse::token;
36 use syntax::symbol::Symbol;
37 use syntax::feature_gate::UnstableFeatures;
39 use errors::{ColorConfig, FatalError, Handler};
42 use std::collections::{BTreeMap, BTreeSet};
43 use std::collections::btree_map::Iter as BTreeMapIter;
44 use std::collections::btree_map::Keys as BTreeMapKeysIter;
45 use std::collections::btree_map::Values as BTreeMapValuesIter;
48 use std::hash::Hasher;
49 use std::collections::hash_map::DefaultHasher;
50 use std::collections::HashSet;
51 use std::iter::FromIterator;
52 use std::path::{Path, PathBuf};
60 #[derive(Clone, Hash, Debug)]
68 #[derive(Clone, Copy, PartialEq, Hash)]
78 #[derive(Clone, Copy, PartialEq, Hash)]
80 /// Don't do any LTO whatsoever
83 /// Do a full crate graph LTO. The flavor is determined by the compiler
84 /// (currently the default is "fat").
87 /// Do a full crate graph LTO with ThinLTO
90 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
94 /// Do a full crate graph LTO with "fat" LTO
98 #[derive(Clone, PartialEq, Hash)]
99 pub enum CrossLangLto {
100 LinkerPlugin(PathBuf),
107 pub fn embed_bitcode(&self) -> bool {
109 CrossLangLto::LinkerPlugin(_) |
110 CrossLangLto::LinkerPluginAuto |
111 CrossLangLto::NoLink => true,
112 CrossLangLto::Disabled => false,
117 #[derive(Clone, Copy, PartialEq, Hash)]
118 pub enum DebugInfoLevel {
124 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
125 pub enum OutputType {
137 impl_stable_hash_for!(enum self::OutputType {
148 impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for OutputType {
149 type KeyType = OutputType;
151 fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> Self::KeyType {
157 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
159 OutputType::Exe | OutputType::DepInfo => true,
161 | OutputType::Assembly
162 | OutputType::LlvmAssembly
165 | OutputType::Metadata => false,
169 fn shorthand(&self) -> &'static str {
171 OutputType::Bitcode => "llvm-bc",
172 OutputType::Assembly => "asm",
173 OutputType::LlvmAssembly => "llvm-ir",
174 OutputType::Mir => "mir",
175 OutputType::Object => "obj",
176 OutputType::Metadata => "metadata",
177 OutputType::Exe => "link",
178 OutputType::DepInfo => "dep-info",
182 fn from_shorthand(shorthand: &str) -> Option<Self> {
183 Some(match shorthand {
184 "asm" => OutputType::Assembly,
185 "llvm-ir" => OutputType::LlvmAssembly,
186 "mir" => OutputType::Mir,
187 "llvm-bc" => OutputType::Bitcode,
188 "obj" => OutputType::Object,
189 "metadata" => OutputType::Metadata,
190 "link" => OutputType::Exe,
191 "dep-info" => OutputType::DepInfo,
196 fn shorthands_display() -> String {
198 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
199 OutputType::Bitcode.shorthand(),
200 OutputType::Assembly.shorthand(),
201 OutputType::LlvmAssembly.shorthand(),
202 OutputType::Mir.shorthand(),
203 OutputType::Object.shorthand(),
204 OutputType::Metadata.shorthand(),
205 OutputType::Exe.shorthand(),
206 OutputType::DepInfo.shorthand(),
210 pub fn extension(&self) -> &'static str {
212 OutputType::Bitcode => "bc",
213 OutputType::Assembly => "s",
214 OutputType::LlvmAssembly => "ll",
215 OutputType::Mir => "mir",
216 OutputType::Object => "o",
217 OutputType::Metadata => "rmeta",
218 OutputType::DepInfo => "d",
219 OutputType::Exe => "",
224 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
225 pub enum ErrorOutputType {
226 HumanReadable(ColorConfig),
231 impl Default for ErrorOutputType {
232 fn default() -> ErrorOutputType {
233 ErrorOutputType::HumanReadable(ColorConfig::Auto)
237 // Use tree-based collections to cheaply get a deterministic Hash implementation.
238 // DO NOT switch BTreeMap out for an unsorted container type! That would break
239 // dependency tracking for commandline arguments.
240 #[derive(Clone, Hash)]
241 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
243 impl_stable_hash_for!(tuple_struct self::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 commandline arguments.
291 #[derive(Clone, Hash)]
292 pub struct Externs(BTreeMap<String, BTreeSet<String>>);
295 pub fn new(data: BTreeMap<String, BTreeSet<String>>) -> Externs {
299 pub fn get(&self, key: &str) -> Option<&BTreeSet<String>> {
303 pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<String>> {
308 macro_rules! hash_option {
309 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
310 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
311 if $sub_hashes.insert(stringify!($opt_name),
312 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
313 bug!("Duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
319 [UNTRACKED_WITH_WARNING $warn_val:expr, $warn_text:expr, $error_format:expr]) => ({
320 if *$opt_expr == $warn_val {
321 early_warn($error_format, $warn_text)
326 macro_rules! top_level_options {
327 (pub struct Options { $(
328 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
336 pub fn dep_tracking_hash(&self) -> u64 {
337 let mut sub_hashes = BTreeMap::new();
342 [$dep_tracking_marker $($warn_val,
344 self.error_format)*]);
346 let mut hasher = DefaultHasher::new();
347 dep_tracking::stable_hash(sub_hashes,
356 // The top-level commandline options struct
358 // For each option, one has to specify how it behaves with regard to the
359 // dependency tracking system of incremental compilation. This is done via the
360 // square-bracketed directive after the field type. The options are:
363 // A change in the given field will cause the compiler to completely clear the
364 // incremental compilation cache before proceeding.
367 // Incremental compilation is not influenced by this option.
369 // [UNTRACKED_WITH_WARNING(val, warning)]
370 // The option is incompatible with incremental compilation in some way. If it
371 // has the value `val`, the string `warning` is emitted as a warning.
373 // If you add a new option to this struct or one of the sub-structs like
374 // CodegenOptions, think about how it influences incremental compilation. If in
375 // doubt, specify [TRACKED], which is always "correct" but might lead to
376 // unnecessary re-compilation.
379 // The crate config requested for the session, which may be combined
380 // with additional crate configurations during the compile process
381 crate_types: Vec<CrateType> [TRACKED],
382 optimize: OptLevel [TRACKED],
383 // Include the debug_assertions flag into dependency tracking, since it
384 // can influence whether overflow checks are done or not.
385 debug_assertions: bool [TRACKED],
386 debuginfo: DebugInfoLevel [TRACKED],
387 lint_opts: Vec<(String, lint::Level)> [TRACKED],
388 lint_cap: Option<lint::Level> [TRACKED],
389 describe_lints: bool [UNTRACKED],
390 output_types: OutputTypes [TRACKED],
391 search_paths: SearchPaths [UNTRACKED],
392 libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
393 maybe_sysroot: Option<PathBuf> [TRACKED],
395 target_triple: TargetTriple [TRACKED],
397 test: bool [TRACKED],
398 error_format: ErrorOutputType [UNTRACKED],
400 // if Some, enable incremental compilation, using the given
401 // directory to store intermediate results
402 incremental: Option<PathBuf> [UNTRACKED],
404 debugging_opts: DebuggingOptions [TRACKED],
405 prints: Vec<PrintRequest> [UNTRACKED],
406 // Determines which borrow checker(s) to run. This is the parsed, sanitized
407 // version of `debugging_opts.borrowck`, which is just a plain string.
408 borrowck_mode: BorrowckMode [UNTRACKED],
409 cg: CodegenOptions [TRACKED],
410 externs: Externs [UNTRACKED],
411 crate_name: Option<String> [TRACKED],
412 // An optional name to use as the crate for std during std injection,
413 // written `extern crate name as std`. Defaults to `std`. Used by
414 // out-of-tree drivers.
415 alt_std_name: Option<String> [TRACKED],
416 // Indicates how the compiler should treat unstable features
417 unstable_features: UnstableFeatures [TRACKED],
419 // Indicates whether this run of the compiler is actually rustdoc. This
420 // is currently just a hack and will be removed eventually, so please
421 // try to not rely on this too much.
422 actually_rustdoc: bool [TRACKED],
424 // Specifications of codegen units / ThinLTO which are forced as a
425 // result of parsing command line options. These are not necessarily
426 // what rustc was invoked with, but massaged a bit to agree with
427 // commands like `--emit llvm-ir` which they're often incompatible with
428 // if we otherwise use the defaults of rustc.
429 cli_forced_codegen_units: Option<usize> [UNTRACKED],
430 cli_forced_thinlto_off: bool [UNTRACKED],
432 // Remap source path prefixes in all output (messages, object files, debug, etc)
433 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
435 edition: Edition [TRACKED],
439 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
440 pub enum PrintRequest {
455 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
456 pub enum BorrowckMode {
463 /// Should we emit the AST-based borrow checker errors?
464 pub fn use_ast(self) -> bool {
466 BorrowckMode::Ast => true,
467 BorrowckMode::Compare => true,
468 BorrowckMode::Mir => false,
471 /// Should we emit the MIR-based borrow checker errors?
472 pub fn use_mir(self) -> bool {
474 BorrowckMode::Ast => false,
475 BorrowckMode::Compare => true,
476 BorrowckMode::Mir => true,
482 /// Load source from file
485 /// String that is shown in place of a filename
487 /// Anonymous source string
493 pub fn filestem(&self) -> String {
495 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap().to_string(),
496 Input::Str { .. } => "rust_out".to_string(),
500 pub fn get_input(&mut self) -> Option<&mut String> {
502 Input::File(_) => None,
503 Input::Str { ref mut input, .. } => Some(input),
509 pub struct OutputFilenames {
510 pub out_directory: PathBuf,
511 pub out_filestem: String,
512 pub single_output_file: Option<PathBuf>,
514 pub outputs: OutputTypes,
517 impl_stable_hash_for!(struct self::OutputFilenames {
525 pub const RUST_CGU_EXT: &str = "rcgu";
527 impl OutputFilenames {
528 pub fn path(&self, flavor: OutputType) -> PathBuf {
531 .and_then(|p| p.to_owned())
532 .or_else(|| self.single_output_file.clone())
533 .unwrap_or_else(|| self.temp_path(flavor, None))
536 /// Get the path where a compilation artifact of the given type for the
537 /// given codegen unit should be placed on disk. If codegen_unit_name is
538 /// None, a path distinct from those of any codegen unit will be generated.
539 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
540 let extension = flavor.extension();
541 self.temp_path_ext(extension, codegen_unit_name)
544 /// Like temp_path, but also supports things where there is no corresponding
545 /// OutputType, like no-opt-bitcode or lto-bitcode.
546 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
547 let base = self.out_directory.join(&self.filestem());
549 let mut extension = String::new();
551 if let Some(codegen_unit_name) = codegen_unit_name {
552 extension.push_str(codegen_unit_name);
556 if !extension.is_empty() {
557 extension.push_str(".");
558 extension.push_str(RUST_CGU_EXT);
559 extension.push_str(".");
562 extension.push_str(ext);
565 let path = base.with_extension(&extension[..]);
569 pub fn with_extension(&self, extension: &str) -> PathBuf {
571 .join(&self.filestem())
572 .with_extension(extension)
575 pub fn filestem(&self) -> String {
576 format!("{}{}", self.out_filestem, self.extra)
580 pub fn host_triple() -> &'static str {
581 // Get the host triple out of the build environment. This ensures that our
582 // idea of the host triple is the same as for the set of libraries we've
583 // actually built. We can't just take LLVM's host triple because they
584 // normalize all ix86 architectures to i386.
586 // Instead of grabbing the host triple (for the current host), we grab (at
587 // compile time) the target triple that this rustc is built with and
588 // calling that (at runtime) the host triple.
589 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
592 /// Some reasonable defaults
593 pub fn basic_options() -> Options {
595 crate_types: Vec::new(),
596 optimize: OptLevel::No,
597 debuginfo: NoDebugInfo,
598 lint_opts: Vec::new(),
600 describe_lints: false,
601 output_types: OutputTypes(BTreeMap::new()),
602 search_paths: SearchPaths::new(),
604 target_triple: TargetTriple::from_triple(host_triple()),
607 debugging_opts: basic_debugging_options(),
609 borrowck_mode: BorrowckMode::Ast,
610 cg: basic_codegen_options(),
611 error_format: ErrorOutputType::default(),
612 externs: Externs(BTreeMap::new()),
616 unstable_features: UnstableFeatures::Disallow,
617 debug_assertions: true,
618 actually_rustdoc: false,
619 cli_forced_codegen_units: None,
620 cli_forced_thinlto_off: false,
621 remap_path_prefix: Vec::new(),
622 edition: DEFAULT_EDITION,
627 /// True if there is a reason to build the dep graph.
628 pub fn build_dep_graph(&self) -> bool {
629 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
630 || self.debugging_opts.query_dep_graph
634 pub fn enable_dep_node_debug_strs(&self) -> bool {
635 cfg!(debug_assertions)
636 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
639 pub fn file_path_mapping(&self) -> FilePathMapping {
640 FilePathMapping::new(self.remap_path_prefix.clone())
643 /// True if there will be an output file generated
644 pub fn will_create_output_file(&self) -> bool {
645 !self.debugging_opts.parse_only && // The file is just being parsed
646 !self.debugging_opts.ls // The file is just being queried
650 // The type of entry function, so
651 // users can have their own entry
653 #[derive(Copy, Clone, PartialEq)]
654 pub enum EntryFnType {
659 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
669 #[derive(Clone, Hash)]
671 SomePasses(Vec<String>),
676 pub fn is_empty(&self) -> bool {
678 SomePasses(ref v) => v.is_empty(),
684 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
685 /// at once. The goal of this macro is to define an interface that can be
686 /// programmatically used by the option parser in order to initialize the struct
687 /// without hardcoding field names all over the place.
689 /// The goal is to invoke this macro once with the correct fields, and then this
690 /// macro generates all necessary code. The main gotcha of this macro is the
691 /// cgsetters module which is a bunch of generated code to parse an option into
692 /// its respective field in the struct. There are a few hand-written parsers for
693 /// parsing specific types of values in this module.
694 macro_rules! options {
695 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
696 $buildfn:ident, $prefix:expr, $outputname:expr,
697 $stat:ident, $mod_desc:ident, $mod_set:ident,
698 $($opt:ident : $t:ty = (
701 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
706 pub struct $struct_name { $(pub $opt: $t),* }
708 pub fn $defaultfn() -> $struct_name {
709 $struct_name { $($opt: $init),* }
712 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
714 let mut op = $defaultfn();
715 for option in matches.opt_strs($prefix) {
716 let mut iter = option.splitn(2, '=');
717 let key = iter.next().unwrap();
718 let value = iter.next();
719 let option_to_lookup = key.replace("-", "_");
720 let mut found = false;
721 for &(candidate, setter, opt_type_desc, _) in $stat {
722 if option_to_lookup != candidate { continue }
723 if !setter(&mut op, value) {
724 match (value, opt_type_desc) {
725 (Some(..), None) => {
726 early_error(error_format, &format!("{} option `{}` takes no \
727 value", $outputname, key))
729 (None, Some(type_desc)) => {
730 early_error(error_format, &format!("{0} option `{1}` requires \
731 {2} ({3} {1}=<value>)",
735 (Some(value), Some(type_desc)) => {
736 early_error(error_format, &format!("incorrect value `{}` for {} \
737 option `{}` - {} was expected",
741 (None, None) => bug!()
748 early_error(error_format, &format!("unknown {} option: `{}`",
755 impl<'a> dep_tracking::DepTrackingHash for $struct_name {
757 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
758 let mut sub_hashes = BTreeMap::new();
763 [$dep_tracking_marker $($dep_warn_val,
767 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
771 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
772 pub const $stat: &'static [(&'static str, $setter_name,
773 Option<&'static str>, &'static str)] =
774 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
776 #[allow(non_upper_case_globals, dead_code)]
778 pub const parse_bool: Option<&'static str> = None;
779 pub const parse_opt_bool: Option<&'static str> =
780 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
781 pub const parse_string: Option<&'static str> = Some("a string");
782 pub const parse_string_push: Option<&'static str> = Some("a string");
783 pub const parse_pathbuf_push: Option<&'static str> = Some("a path");
784 pub const parse_opt_string: Option<&'static str> = Some("a string");
785 pub const parse_opt_pathbuf: Option<&'static str> = Some("a path");
786 pub const parse_list: Option<&'static str> = Some("a space-separated list of strings");
787 pub const parse_opt_list: Option<&'static str> = Some("a space-separated list of strings");
788 pub const parse_uint: Option<&'static str> = Some("a number");
789 pub const parse_passes: Option<&'static str> =
790 Some("a space-separated list of passes, or `all`");
791 pub const parse_opt_uint: Option<&'static str> =
793 pub const parse_panic_strategy: Option<&'static str> =
794 Some("either `panic` or `abort`");
795 pub const parse_relro_level: Option<&'static str> =
796 Some("one of: `full`, `partial`, or `off`");
797 pub const parse_sanitizer: Option<&'static str> =
798 Some("one of: `address`, `leak`, `memory` or `thread`");
799 pub const parse_linker_flavor: Option<&'static str> =
800 Some(::rustc_target::spec::LinkerFlavor::one_of());
801 pub const parse_optimization_fuel: Option<&'static str> =
802 Some("crate=integer");
803 pub const parse_unpretty: Option<&'static str> =
804 Some("`string` or `string=string`");
805 pub const parse_lto: Option<&'static str> =
806 Some("one of `thin`, `fat`, or omitted");
807 pub const parse_cross_lang_lto: Option<&'static str> =
808 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `no-link`, \
809 or the path to the linker plugin");
814 use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto,
816 use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
817 use std::path::PathBuf;
820 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
821 $parse(&mut cg.$opt, v)
825 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
828 None => { *slot = true; true }
832 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
836 "n" | "no" | "off" => {
839 "y" | "yes" | "on" => {
842 _ => { return false; }
847 None => { *slot = Some(true); true }
851 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
853 Some(s) => { *slot = Some(s.to_string()); true },
858 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
860 Some(s) => { *slot = Some(PathBuf::from(s)); true },
865 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
867 Some(s) => { *slot = s.to_string(); true },
872 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
874 Some(s) => { slot.push(s.to_string()); true },
879 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
881 Some(s) => { slot.push(PathBuf::from(s)); true },
886 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
890 for s in s.split_whitespace() {
891 slot.push(s.to_string());
899 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
903 let v = s.split_whitespace().map(|s| s.to_string()).collect();
911 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
912 match v.and_then(|s| s.parse().ok()) {
913 Some(i) => { *slot = i; true },
918 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
920 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
921 None => { *slot = None; false }
925 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
932 let mut passes = vec![];
933 if parse_list(&mut passes, v) {
934 *slot = SomePasses(passes);
943 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
945 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
946 Some("abort") => *slot = Some(PanicStrategy::Abort),
952 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
955 match s.parse::<RelroLevel>() {
956 Ok(level) => *slot = Some(level),
965 fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
967 Some("address") => *slote = Some(Sanitizer::Address),
968 Some("leak") => *slote = Some(Sanitizer::Leak),
969 Some("memory") => *slote = Some(Sanitizer::Memory),
970 Some("thread") => *slote = Some(Sanitizer::Thread),
976 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
977 match v.and_then(LinkerFlavor::from_str) {
978 Some(lf) => *slote = Some(lf),
984 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
988 let parts = s.split('=').collect::<Vec<_>>();
989 if parts.len() != 2 { return false; }
990 let crate_name = parts[0].to_string();
991 let fuel = parts[1].parse::<u64>();
992 if fuel.is_err() { return false; }
993 *slot = Some((crate_name, fuel.unwrap()));
999 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1002 Some(s) if s.split('=').count() <= 2 => {
1003 *slot = Some(s.to_string());
1010 fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
1013 Some("thin") => Lto::Thin,
1014 Some("fat") => Lto::Fat,
1015 Some(_) => return false,
1020 fn parse_cross_lang_lto(slot: &mut CrossLangLto, v: Option<&str>) -> bool {
1022 let mut bool_arg = None;
1023 if parse_opt_bool(&mut bool_arg, v) {
1024 *slot = if bool_arg.unwrap() {
1025 CrossLangLto::LinkerPluginAuto
1027 CrossLangLto::Disabled
1035 Some("no-link") => CrossLangLto::NoLink,
1036 Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)),
1043 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1044 build_codegen_options, "C", "codegen",
1045 CG_OPTIONS, cg_type_desc, cgsetters,
1046 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1047 "this option is deprecated and does nothing"),
1048 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1049 "system linker to link outputs with"),
1050 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1051 "a single extra argument to append to the linker invocation (can be used several times)"),
1052 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1053 "extra arguments to append to the linker invocation (space separated)"),
1054 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1055 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1056 lto: Lto = (Lto::No, parse_lto, [TRACKED],
1057 "perform LLVM link-time optimizations"),
1058 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1059 "select target processor (rustc --print target-cpus for details)"),
1060 target_feature: String = ("".to_string(), parse_string, [TRACKED],
1061 "target specific attributes (rustc --print target-features for details)"),
1062 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1063 "a list of extra LLVM passes to run (space separated)"),
1064 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1065 "a list of arguments to pass to llvm (space separated)"),
1066 save_temps: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1067 "`-C save-temps` might not produce all requested temporary products \
1068 when incremental compilation is enabled.")],
1069 "save all temporary output files during compilation"),
1070 rpath: bool = (false, parse_bool, [UNTRACKED],
1071 "set rpath values in libs/exes"),
1072 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1073 "use overflow checks for integer arithmetic"),
1074 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1075 "don't pre-populate the pass manager with a list of passes"),
1076 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1077 "don't run the loop vectorization optimization passes"),
1078 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1079 "don't run LLVM's SLP vectorization pass"),
1080 soft_float: bool = (false, parse_bool, [TRACKED],
1081 "use soft float ABI (*eabihf targets only)"),
1082 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1083 "prefer dynamic linking to static linking"),
1084 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1085 "use an external assembler rather than LLVM's integrated one"),
1086 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1087 "disable the use of the redzone"),
1088 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1089 "choose the relocation model to use (rustc --print relocation-models for details)"),
1090 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1091 "choose the code model to use (rustc --print code-models for details)"),
1092 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1093 "metadata to mangle symbol names with"),
1094 extra_filename: String = ("".to_string(), parse_string, [UNTRACKED],
1095 "extra data to put in each output filename"),
1096 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1097 "divide crate into N units to optimize in parallel"),
1098 remark: Passes = (SomePasses(Vec::new()), parse_passes, [UNTRACKED],
1099 "print remarks for these optimization passes (space separated, or \"all\")"),
1100 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1101 "the --no-stack-check flag is deprecated and does nothing"),
1102 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1103 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1104 2 = full debug info with variable and type information"),
1105 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1106 "optimize with possible levels 0-3, s, or z"),
1107 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1108 "force use of the frame pointers"),
1109 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1110 "explicitly enable the cfg(debug_assertions) directive"),
1111 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1112 "set the threshold for inlining a function (default: 225)"),
1113 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1114 [TRACKED], "panic strategy to compile crate with"),
1115 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1116 "enable incremental compilation"),
1119 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1120 build_debugging_options, "Z", "debugging",
1121 DB_OPTIONS, db_type_desc, dbsetters,
1122 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1123 "the backend to use"),
1124 verbose: bool = (false, parse_bool, [UNTRACKED],
1125 "in general, enable more debug printouts"),
1126 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1127 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1128 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1129 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1130 emit_end_regions: bool = (false, parse_bool, [UNTRACKED],
1131 "emit EndRegion as part of MIR; enable transforms that solely process EndRegion"),
1132 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1133 "select which borrowck is used (`ast`, `mir`, or `compare`)"),
1134 two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
1135 "use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"),
1136 two_phase_beyond_autoref: bool = (false, parse_bool, [UNTRACKED],
1137 "when using two-phase-borrows, allow two phases even for non-autoref `&mut` borrows"),
1138 time_passes: bool = (false, parse_bool, [UNTRACKED],
1139 "measure time of each rustc pass"),
1140 count_llvm_insns: bool = (false, parse_bool,
1141 [UNTRACKED_WITH_WARNING(true,
1142 "The output generated by `-Z count_llvm_insns` might not be reliable \
1143 when used with incremental compilation")],
1144 "count where LLVM instrs originate"),
1145 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1146 "The output of `-Z time-llvm-passes` will only reflect timings of \
1147 re-codegened modules when used with incremental compilation" )],
1148 "measure time of each LLVM pass"),
1149 input_stats: bool = (false, parse_bool, [UNTRACKED],
1150 "gather statistics about the input"),
1151 codegen_stats: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
1152 "The output of `-Z codegen-stats` might not be accurate when incremental \
1153 compilation is enabled")],
1154 "gather codegen statistics"),
1155 asm_comments: bool = (false, parse_bool, [TRACKED],
1156 "generate comments into the assembly (may change behavior)"),
1157 no_verify: bool = (false, parse_bool, [TRACKED],
1158 "skip LLVM verification"),
1159 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1160 "gather borrowck statistics"),
1161 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1162 "omit landing pads for unwinding"),
1163 fewer_names: bool = (false, parse_bool, [TRACKED],
1164 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1165 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1166 "gather metadata statistics"),
1167 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1168 "print the arguments passed to the linker"),
1169 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1170 "prints the llvm optimization passes being run"),
1171 ast_json: bool = (false, parse_bool, [UNTRACKED],
1172 "print the AST as JSON and halt"),
1173 query_threads: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1174 "execute queries on a thread pool with N threads"),
1175 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1176 "print the pre-expansion AST as JSON and halt"),
1177 ls: bool = (false, parse_bool, [UNTRACKED],
1178 "list the symbols defined by a library crate"),
1179 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1180 "write syntax and type analysis (in JSON format) information, in \
1181 addition to normal output"),
1182 flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED],
1183 "include loan analysis data in -Z unpretty flowgraph output"),
1184 flowgraph_print_moves: bool = (false, parse_bool, [UNTRACKED],
1185 "include move analysis data in -Z unpretty flowgraph output"),
1186 flowgraph_print_assigns: bool = (false, parse_bool, [UNTRACKED],
1187 "include assignment analysis data in -Z unpretty flowgraph output"),
1188 flowgraph_print_all: bool = (false, parse_bool, [UNTRACKED],
1189 "include all dataflow analysis data in -Z unpretty flowgraph output"),
1190 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1191 "prints region inference graph. \
1192 Use with RUST_REGION_GRAPH=help for more info"),
1193 parse_only: bool = (false, parse_bool, [UNTRACKED],
1194 "parse only; do not compile, assemble, or link"),
1195 no_codegen: bool = (false, parse_bool, [TRACKED],
1196 "run all passes except codegen; no output"),
1197 treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
1198 "treat all errors that occur as bugs"),
1199 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1200 "show macro backtraces even for non-local macros"),
1201 teach: bool = (false, parse_bool, [TRACKED],
1202 "show extended diagnostic help"),
1203 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1204 "attempt to recover from parse errors (experimental)"),
1205 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1206 "enable incremental compilation (experimental)"),
1207 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1208 "enable incremental compilation support for queries (experimental)"),
1209 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1210 "print high-level information about incremental reuse (or the lack thereof)"),
1211 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1212 "dump hash information in textual format to stdout"),
1213 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1214 "verify incr. comp. hashes of green query instances"),
1215 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1216 "ignore spans during ICH computation -- used for testing"),
1217 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1218 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1219 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1220 "enable queries of the dependency graph for regression testing"),
1221 profile_queries: bool = (false, parse_bool, [UNTRACKED],
1222 "trace and profile the queries of the incremental compilation framework"),
1223 profile_queries_and_keys: bool = (false, parse_bool, [UNTRACKED],
1224 "trace and profile the queries and keys of the incremental compilation framework"),
1225 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1226 "parse and expand the source, but run no analysis"),
1227 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1228 "load extra plugins"),
1229 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1230 "adds unstable command line options to rustc interface"),
1231 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1232 "force overflow checks on or off"),
1233 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1234 "for every macro invocation, print its name and arguments"),
1235 debug_macros: bool = (false, parse_bool, [TRACKED],
1236 "emit line numbers debug info inside macros"),
1237 enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED],
1238 "force nonzeroing move optimization on"),
1239 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1240 "don't clear the hygiene data after analysis"),
1241 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1242 "keep the AST after lowering it to HIR"),
1243 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1244 "show spans for compiler debugging (expr|pat|ty)"),
1245 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1246 "print layout information for each type encountered"),
1247 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1248 "print the result of the monomorphization collection pass"),
1249 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1250 "set the MIR optimization level (0-3, default: 1)"),
1251 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1252 "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"),
1253 arg_align_attributes: bool = (false, parse_bool, [TRACKED],
1254 "emit align metadata for reference arguments"),
1255 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1256 "dump MIR state at various points in transforms"),
1257 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1258 "the directory the MIR is dumped into"),
1259 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1260 "in addition to `.mir` files, create graphviz `.dot` files"),
1261 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1262 "if set, exclude the pass number when dumping MIR (used in tests)"),
1263 mir_emit_validate: usize = (0, parse_uint, [TRACKED],
1264 "emit Validate MIR statements, interpreted e.g. by miri (0: do not emit; 1: if function \
1265 contains unsafe block, only validate arguments; 2: always emit full validation)"),
1266 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1267 "print some performance-related statistics"),
1268 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1269 "print some statistics about AST and HIR"),
1270 mir_stats: bool = (false, parse_bool, [UNTRACKED],
1271 "print some statistics about MIR"),
1272 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1273 "encode MIR of all functions into the crate metadata"),
1274 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1275 "pass `-install_name @rpath/...` to the macOS linker"),
1276 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1278 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1280 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1281 "set the optimization fuel quota for a crate"),
1282 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1283 "make Rustc print the total optimization fuel used by a crate"),
1284 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1285 "force all crates to be `rustc_private` unstable"),
1286 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1287 "a single extra argument to prepend the linker invocation (can be used several times)"),
1288 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1289 "extra arguments to prepend to the linker invocation (space separated)"),
1290 profile: bool = (false, parse_bool, [TRACKED],
1291 "insert profiling code"),
1292 pgo_gen: Option<String> = (None, parse_opt_string, [TRACKED],
1293 "Generate PGO profile data, to a given file, or to the default \
1294 location if it's empty."),
1295 pgo_use: String = (String::new(), parse_string, [TRACKED],
1296 "Use PGO profile data from the given profile file."),
1297 disable_instrumentation_preinliner: bool =
1298 (false, parse_bool, [TRACKED], "Disable the instrumentation pre-inliner, \
1299 useful for profiling / PGO."),
1300 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1301 "choose which RELRO level to use"),
1302 disable_ast_check_for_mutation_in_guard: bool = (false, parse_bool, [UNTRACKED],
1303 "skip AST-based mutation-in-guard check (mir-borrowck provides more precise check)"),
1304 nll_subminimal_causes: bool = (false, parse_bool, [UNTRACKED],
1305 "when tracking region error causes, accept subminimal results for faster execution."),
1306 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1307 "dump facts from NLL analysis into side files"),
1308 disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED],
1309 "disable user provided type assertion in NLL"),
1310 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1311 "in match codegen, do not include ReadForMatch statements (used by mir-borrowck)"),
1312 polonius: bool = (false, parse_bool, [UNTRACKED],
1313 "enable polonius-based borrow-checker"),
1314 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1315 "generate a graphical HTML report of time spent in codegen and LLVM"),
1316 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1317 "enable ThinLTO when possible"),
1318 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1319 "control whether #[inline] functions are in all cgus"),
1320 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1321 "choose the TLS model to use (rustc --print tls-models for details)"),
1322 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1323 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1324 the max/min integer respectively, and NaN is mapped to 0"),
1325 lower_128bit_ops: Option<bool> = (None, parse_opt_bool, [TRACKED],
1326 "rewrite operators on i128 and u128 into lang item calls (typically provided \
1327 by compiler-builtins) so codegen doesn't need to support them,
1328 overriding the default for the current target"),
1329 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1330 "generate human-readable, predictable names for codegen units"),
1331 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1332 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1334 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1335 "Present the input source, unstable (and less-pretty) variants;
1336 valid types are any of the types for `--pretty`, as well as:
1337 `flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
1338 `everybody_loops` (all function bodies replaced with `loop {}`),
1339 `hir` (the HIR), `hir,identified`, or
1340 `hir,typed` (HIR with types for each node)."),
1341 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1342 "run `dsymutil` and delete intermediate object files"),
1343 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1344 "format compiler diagnostics in a way that's better suitable for UI testing"),
1345 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1346 "embed LLVM bitcode in object files"),
1347 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1348 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1349 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1350 "make the current crate share its generic instantiations"),
1351 chalk: bool = (false, parse_bool, [TRACKED],
1352 "enable the experimental Chalk-based trait solving engine"),
1353 cross_lang_lto: CrossLangLto = (CrossLangLto::Disabled, parse_cross_lang_lto, [TRACKED],
1354 "generate build artifacts that are compatible with linker-based LTO."),
1355 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1356 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1359 pub fn default_lib_output() -> CrateType {
1363 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1364 let end = &sess.target.target.target_endian;
1365 let arch = &sess.target.target.arch;
1366 let wordsz = &sess.target.target.target_pointer_width;
1367 let os = &sess.target.target.target_os;
1368 let env = &sess.target.target.target_env;
1369 let vendor = &sess.target.target.target_vendor;
1370 let min_atomic_width = sess.target.target.min_atomic_width();
1371 let max_atomic_width = sess.target.target.max_atomic_width();
1373 let mut ret = HashSet::new();
1375 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1376 if let Some(ref fam) = sess.target.target.options.target_family {
1377 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1378 if fam == "windows" || fam == "unix" {
1379 ret.insert((Symbol::intern(fam), None));
1382 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1383 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1385 Symbol::intern("target_pointer_width"),
1386 Some(Symbol::intern(wordsz)),
1388 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1390 Symbol::intern("target_vendor"),
1391 Some(Symbol::intern(vendor)),
1393 if sess.target.target.options.has_elf_tls {
1394 ret.insert((Symbol::intern("target_thread_local"), None));
1396 for &i in &[8, 16, 32, 64, 128] {
1397 if i >= min_atomic_width && i <= max_atomic_width {
1398 let s = i.to_string();
1400 Symbol::intern("target_has_atomic"),
1401 Some(Symbol::intern(&s)),
1405 Symbol::intern("target_has_atomic"),
1406 Some(Symbol::intern("ptr")),
1411 if sess.opts.debug_assertions {
1412 ret.insert((Symbol::intern("debug_assertions"), None));
1414 if sess.opts.crate_types.contains(&CrateTypeProcMacro) {
1415 ret.insert((Symbol::intern("proc_macro"), None));
1420 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1421 // Combine the configuration requested by the session (command line) with
1422 // some default and generated configuration items
1423 let default_cfg = default_configuration(sess);
1424 // If the user wants a test runner, then add the test cfg
1426 user_cfg.insert((Symbol::intern("test"), None));
1428 user_cfg.extend(default_cfg.iter().cloned());
1432 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1433 let target = match Target::search(&opts.target_triple) {
1436 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1437 .help("Use `--print target-list` for a list of built-in targets")
1443 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1444 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1445 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1446 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1447 w => sp.fatal(&format!(
1448 "target specification was invalid: \
1449 unrecognized target-pointer-width {}",
1461 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1462 pub enum OptionStability {
1468 pub struct RustcOptGroup {
1469 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1470 pub name: &'static str,
1471 pub stability: OptionStability,
1474 impl RustcOptGroup {
1475 pub fn is_stable(&self) -> bool {
1476 self.stability == OptionStability::Stable
1479 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1481 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1486 stability: OptionStability::Stable,
1490 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1492 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1497 stability: OptionStability::Unstable,
1502 // The `opt` local module holds wrappers around the `getopts` API that
1503 // adds extra rustc-specific metadata to each option; such metadata
1504 // is exposed by . The public
1505 // functions below ending with `_u` are the functions that return
1506 // *unstable* options, i.e. options that are only enabled when the
1507 // user also passes the `-Z unstable-options` debugging flag.
1509 // The `fn opt_u` etc below are written so that we can use them
1510 // in the future; do not warn about them not being used right now.
1511 #![allow(dead_code)]
1514 use super::RustcOptGroup;
1516 pub type R = RustcOptGroup;
1517 pub type S = &'static str;
1519 fn stable<F>(name: S, f: F) -> R
1521 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1523 RustcOptGroup::stable(name, f)
1526 fn unstable<F>(name: S, f: F) -> R
1528 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1530 RustcOptGroup::unstable(name, f)
1533 fn longer(a: S, b: S) -> S {
1534 if a.len() > b.len() {
1541 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1542 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1544 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1545 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1547 pub fn flag_s(a: S, b: S, c: S) -> R {
1548 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1550 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1551 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1553 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1554 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1557 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1558 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1560 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1561 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1563 pub fn flag(a: S, b: S, c: S) -> R {
1564 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1566 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1567 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1569 pub fn flagmulti(a: S, b: S, c: S) -> R {
1570 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1574 /// Returns the "short" subset of the rustc command line options,
1575 /// including metadata for each option, such as whether the option is
1576 /// part of the stable long-term interface for rustc.
1577 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1579 opt::flag_s("h", "help", "Display this message"),
1580 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1584 "Add a directory to the library search path. The
1585 optional KIND can be one of dependency, crate, native,
1586 framework or all (the default).",
1592 "Link the generated crate(s) to the specified native
1593 library NAME. The optional KIND can be one of
1594 static, dylib, or framework. If omitted, dylib is
1601 "Comma separated list of types of crates
1602 for the compiler to emit",
1603 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1608 "Specify the name of the crate being built",
1614 "Comma separated list of types of output for \
1615 the compiler to emit",
1616 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1621 "Comma separated list of compiler information to \
1623 "[crate-name|file-names|sysroot|cfg|target-list|\
1624 target-cpus|target-features|relocation-models|\
1625 code-models|tls-models|target-spec-json|native-static-libs]",
1627 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1628 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1629 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1633 "Write output to compiler-chosen filename \
1640 "Provide a detailed explanation of an error \
1644 opt::flag_s("", "test", "Build a test harness"),
1648 "Target triple for which the code is compiled",
1651 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1652 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1653 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1654 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1658 "Set the most restrictive lint level. \
1659 More restrictive lints are capped at this \
1663 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1664 opt::flag_s("V", "version", "Print version info and exit"),
1665 opt::flag_s("v", "verbose", "Use verbose output"),
1669 /// Returns all rustc command line options, including metadata for
1670 /// each option, such as whether the option is part of the stable
1671 /// long-term interface for rustc.
1672 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1673 let mut opts = rustc_short_optgroups();
1678 "Specify where an external rust library is located",
1681 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1682 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1686 "How errors and other messages are produced",
1692 "Configure coloring of output:
1693 auto = colorize, if output goes to a tty (default);
1694 always = always colorize output;
1695 never = never colorize output",
1696 "auto|always|never",
1701 "Pretty-print the input instead of compiling;
1702 valid types are: `normal` (un-annotated source),
1703 `expanded` (crates expanded), or
1704 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1710 "Specify which edition of the compiler to use when compiling code.",
1715 "remap-path-prefix",
1716 "Remap source names in all output (compiler messages and output files)",
1723 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
1724 pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> ast::CrateConfig {
1728 let sess = parse::ParseSess::new(FilePathMapping::empty());
1730 parse::new_parser_from_source_str(&sess, FileName::CfgSpec, s.to_string());
1732 let meta_item = panictry!(parser.parse_meta_item());
1734 if parser.token != token::Eof {
1736 ErrorOutputType::default(),
1737 &format!("invalid --cfg argument: {}", s),
1739 } else if meta_item.is_meta_item_list() {
1741 "invalid predicate in --cfg command line argument: `{}`",
1744 early_error(ErrorOutputType::default(), &msg)
1747 (meta_item.name(), meta_item.value_str())
1749 .collect::<ast::CrateConfig>()
1752 pub fn build_session_options_and_crate_config(
1753 matches: &getopts::Matches,
1754 ) -> (Options, ast::CrateConfig) {
1755 let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1756 Some("auto") => ColorConfig::Auto,
1757 Some("always") => ColorConfig::Always,
1758 Some("never") => ColorConfig::Never,
1760 None => ColorConfig::Auto,
1762 Some(arg) => early_error(
1763 ErrorOutputType::default(),
1765 "argument for --color must be auto, \
1766 always or never (instead was `{}`)",
1772 let edition = match matches.opt_str("edition") {
1773 Some(arg) => match Edition::from_str(&arg){
1774 Ok(edition) => edition,
1775 Err(_) => early_error(
1776 ErrorOutputType::default(),
1778 "argument for --edition must be one of: \
1779 {}. (instead was `{}`)",
1785 None => DEFAULT_EDITION,
1788 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1790 ErrorOutputType::default(),
1792 "Edition {} is unstable an only\
1793 available for nightly builds of rustc.",
1800 // We need the opts_present check because the driver will send us Matches
1801 // with only stable options if no unstable options are used. Since error-format
1802 // is unstable, it will not be present. We have to use opts_present not
1803 // opt_present because the latter will panic.
1804 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1805 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1806 Some("human") => ErrorOutputType::HumanReadable(color),
1807 Some("json") => ErrorOutputType::Json(false),
1808 Some("pretty-json") => ErrorOutputType::Json(true),
1809 Some("short") => ErrorOutputType::Short(color),
1810 None => ErrorOutputType::HumanReadable(color),
1812 Some(arg) => early_error(
1813 ErrorOutputType::HumanReadable(color),
1815 "argument for --error-format must be `human`, `json` or \
1816 `short` (instead was `{}`)",
1822 ErrorOutputType::HumanReadable(color)
1825 let unparsed_crate_types = matches.opt_strs("crate-type");
1826 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1827 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1829 let mut lint_opts = vec![];
1830 let mut describe_lints = false;
1832 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1833 for lint_name in matches.opt_strs(level.as_str()) {
1834 if lint_name == "help" {
1835 describe_lints = true;
1837 lint_opts.push((lint_name.replace("-", "_"), level));
1842 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1843 lint::Level::from_str(&cap)
1844 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1847 let mut debugging_opts = build_debugging_options(matches, error_format);
1849 if !debugging_opts.unstable_options && error_format == ErrorOutputType::Json(true) {
1851 ErrorOutputType::Json(false),
1852 "--error-format=pretty-json is unstable",
1856 if debugging_opts.pgo_gen.is_some() && !debugging_opts.pgo_use.is_empty() {
1859 "options `-Z pgo-gen` and `-Z pgo-use` are exclusive",
1863 let mut output_types = BTreeMap::new();
1864 if !debugging_opts.parse_only {
1865 for list in matches.opt_strs("emit") {
1866 for output_type in list.split(',') {
1867 let mut parts = output_type.splitn(2, '=');
1868 let shorthand = parts.next().unwrap();
1869 let output_type = match OutputType::from_shorthand(shorthand) {
1870 Some(output_type) => output_type,
1871 None => early_error(
1874 "unknown emission type: `{}` - expected one of: {}",
1876 OutputType::shorthands_display(),
1880 let path = parts.next().map(PathBuf::from);
1881 output_types.insert(output_type, path);
1885 if output_types.is_empty() {
1886 output_types.insert(OutputType::Exe, None);
1889 let mut cg = build_codegen_options(matches, error_format);
1890 let mut codegen_units = cg.codegen_units;
1891 let mut disable_thinlto = false;
1893 // Issue #30063: if user requests llvm-related output to one
1894 // particular path, disable codegen-units.
1895 let incompatible: Vec<_> = output_types
1897 .map(|ot_path| ot_path.0)
1898 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1899 .map(|ot| ot.shorthand())
1901 if !incompatible.is_empty() {
1902 match codegen_units {
1903 Some(n) if n > 1 => {
1904 if matches.opt_present("o") {
1905 for ot in &incompatible {
1909 "--emit={} with -o incompatible with \
1910 -C codegen-units=N for N > 1",
1915 early_warn(error_format, "resetting to default -C codegen-units=1");
1916 codegen_units = Some(1);
1917 disable_thinlto = true;
1921 codegen_units = Some(1);
1922 disable_thinlto = true;
1927 if debugging_opts.query_threads == Some(0) {
1930 "Value for query threads must be a positive nonzero integer",
1934 if debugging_opts.query_threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() {
1937 "Optimization fuel is incompatible with multiple query threads",
1941 if codegen_units == Some(0) {
1944 "Value for codegen units must be a positive nonzero integer",
1948 let incremental = match (&debugging_opts.incremental, &cg.incremental) {
1949 (&Some(ref path1), &Some(ref path2)) => {
1954 "conflicting paths for `-Z incremental` and \
1955 `-C incremental` specified: {} versus {}",
1963 (&Some(ref path), &None) => Some(path),
1964 (&None, &Some(ref path)) => Some(path),
1965 (&None, &None) => None,
1966 }.map(|m| PathBuf::from(m));
1968 if cg.lto != Lto::No && incremental.is_some() {
1971 "can't perform LTO when compiling incrementally",
1975 if debugging_opts.profile && incremental.is_some() {
1978 "can't instrument with gcov profiling when compiling incrementally",
1982 let mut prints = Vec::<PrintRequest>::new();
1983 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1984 prints.push(PrintRequest::TargetCPUs);
1985 cg.target_cpu = None;
1987 if cg.target_feature == "help" {
1988 prints.push(PrintRequest::TargetFeatures);
1989 cg.target_feature = "".to_string();
1991 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1992 prints.push(PrintRequest::RelocationModels);
1993 cg.relocation_model = None;
1995 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1996 prints.push(PrintRequest::CodeModels);
1997 cg.code_model = None;
2002 .map_or(false, |s| s == "help")
2004 prints.push(PrintRequest::TlsModels);
2005 debugging_opts.tls_model = None;
2010 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2011 let target_triple = if let Some(target) = matches.opt_str("target") {
2012 if target.ends_with(".json") {
2013 let path = Path::new(&target);
2014 match TargetTriple::from_path(&path) {
2015 Ok(triple) => triple,
2017 early_error(error_format, &format!("target file {:?} does not exist", path))
2021 TargetTriple::TargetTriple(target)
2024 TargetTriple::from_triple(host_triple())
2027 if matches.opt_present("O") {
2028 if cg.opt_level.is_some() {
2029 early_error(error_format, "-O and -C opt-level both provided");
2033 match cg.opt_level.as_ref().map(String::as_ref) {
2034 None => OptLevel::No,
2035 Some("0") => OptLevel::No,
2036 Some("1") => OptLevel::Less,
2037 Some("2") => OptLevel::Default,
2038 Some("3") => OptLevel::Aggressive,
2039 Some("s") => OptLevel::Size,
2040 Some("z") => OptLevel::SizeMin,
2045 "optimization level needs to be \
2046 between 0-3 (instead was `{}`)",
2054 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2055 let debuginfo = if matches.opt_present("g") {
2056 if cg.debuginfo.is_some() {
2057 early_error(error_format, "-g and -C debuginfo both provided");
2061 match cg.debuginfo {
2062 None | Some(0) => NoDebugInfo,
2063 Some(1) => LimitedDebugInfo,
2064 Some(2) => FullDebugInfo,
2069 "debug info level needs to be between \
2070 0-2 (instead was `{}`)",
2078 let mut search_paths = SearchPaths::new();
2079 for s in &matches.opt_strs("L") {
2080 search_paths.add_path(&s[..], error_format);
2087 // Parse string of the form "[KIND=]lib[:new_name]",
2088 // where KIND is one of "dylib", "framework", "static".
2089 let mut parts = s.splitn(2, '=');
2090 let kind = parts.next().unwrap();
2091 let (name, kind) = match (parts.next(), kind) {
2092 (None, name) => (name, None),
2093 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2094 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2095 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2096 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2101 "unknown library kind `{}`, expected \
2102 one of dylib, framework, or static",
2108 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2112 "the library kind 'static-nobundle' is only \
2113 accepted on the nightly compiler"
2117 let mut name_parts = name.splitn(2, ':');
2118 let name = name_parts.next().unwrap();
2119 let new_name = name_parts.next();
2120 (name.to_string(), new_name.map(|n| n.to_string()), kind)
2124 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
2125 let test = matches.opt_present("test");
2127 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2128 "crate-name" => PrintRequest::CrateName,
2129 "file-names" => PrintRequest::FileNames,
2130 "sysroot" => PrintRequest::Sysroot,
2131 "cfg" => PrintRequest::Cfg,
2132 "target-list" => PrintRequest::TargetList,
2133 "target-cpus" => PrintRequest::TargetCPUs,
2134 "target-features" => PrintRequest::TargetFeatures,
2135 "relocation-models" => PrintRequest::RelocationModels,
2136 "code-models" => PrintRequest::CodeModels,
2137 "tls-models" => PrintRequest::TlsModels,
2138 "native-static-libs" => PrintRequest::NativeStaticLibs,
2139 "target-spec-json" => {
2140 if nightly_options::is_unstable_enabled(matches) {
2141 PrintRequest::TargetSpec
2146 "the `-Z unstable-options` flag must also be passed to \
2147 enable the target-spec-json print option"
2152 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2155 let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) {
2156 None | Some("ast") => BorrowckMode::Ast,
2157 Some("mir") => BorrowckMode::Mir,
2158 Some("compare") => BorrowckMode::Compare,
2159 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2162 if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
2165 "-C remark will not show source locations without \
2170 let mut externs = BTreeMap::new();
2171 for arg in &matches.opt_strs("extern") {
2172 let mut parts = arg.splitn(2, '=');
2173 let name = match parts.next() {
2175 None => early_error(error_format, "--extern value must not be empty"),
2177 let location = match parts.next() {
2179 None => early_error(
2181 "--extern value must be of the format `foo=bar`",
2186 .entry(name.to_string())
2187 .or_insert_with(BTreeSet::new)
2188 .insert(location.to_string());
2191 let crate_name = matches.opt_str("crate-name");
2193 let remap_path_prefix = matches
2194 .opt_strs("remap-path-prefix")
2197 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2198 let to = parts.next();
2199 let from = parts.next();
2201 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2204 "--remap-path-prefix must contain '=' between FROM and TO",
2213 optimize: opt_level,
2218 output_types: OutputTypes(output_types),
2220 maybe_sysroot: sysroot_opt,
2229 externs: Externs(externs),
2233 unstable_features: UnstableFeatures::from_environment(),
2235 actually_rustdoc: false,
2236 cli_forced_codegen_units: codegen_units,
2237 cli_forced_thinlto_off: disable_thinlto,
2245 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2246 let mut crate_types: Vec<CrateType> = Vec::new();
2247 for unparsed_crate_type in &list_list {
2248 for part in unparsed_crate_type.split(',') {
2249 let new_part = match part {
2250 "lib" => default_lib_output(),
2251 "rlib" => CrateTypeRlib,
2252 "staticlib" => CrateTypeStaticlib,
2253 "dylib" => CrateTypeDylib,
2254 "cdylib" => CrateTypeCdylib,
2255 "bin" => CrateTypeExecutable,
2256 "proc-macro" => CrateTypeProcMacro,
2258 return Err(format!("unknown crate type: `{}`", part));
2261 if !crate_types.contains(&new_part) {
2262 crate_types.push(new_part)
2270 pub mod nightly_options {
2272 use syntax::feature_gate::UnstableFeatures;
2273 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2274 use session::early_error;
2276 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2281 .any(|x| *x == "unstable-options")
2284 pub fn is_nightly_build() -> bool {
2285 UnstableFeatures::from_environment().is_nightly_build()
2288 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2289 let has_z_unstable_option = matches
2292 .any(|x| *x == "unstable-options");
2293 let really_allows_unstable_options =
2294 UnstableFeatures::from_environment().is_nightly_build();
2296 for opt in flags.iter() {
2297 if opt.stability == OptionStability::Stable {
2300 if !matches.opt_present(opt.name) {
2303 if opt.name != "Z" && !has_z_unstable_option {
2305 ErrorOutputType::default(),
2307 "the `-Z unstable-options` flag must also be passed to enable \
2313 if really_allows_unstable_options {
2316 match opt.stability {
2317 OptionStability::Unstable => {
2319 "the option `{}` is only accepted on the \
2323 early_error(ErrorOutputType::default(), &msg);
2325 OptionStability::Stable => {}
2331 impl fmt::Display for CrateType {
2332 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2334 CrateTypeExecutable => "bin".fmt(f),
2335 CrateTypeDylib => "dylib".fmt(f),
2336 CrateTypeRlib => "rlib".fmt(f),
2337 CrateTypeStaticlib => "staticlib".fmt(f),
2338 CrateTypeCdylib => "cdylib".fmt(f),
2339 CrateTypeProcMacro => "proc-macro".fmt(f),
2344 /// Commandline arguments passed to the compiler have to be incorporated with
2345 /// the dependency tracking system for incremental compilation. This module
2346 /// provides some utilities to make this more convenient.
2348 /// The values of all commandline arguments that are relevant for dependency
2349 /// tracking are hashed into a single value that determines whether the
2350 /// incremental compilation cache can be re-used or not. This hashing is done
2351 /// via the DepTrackingHash trait defined below, since the standard Hash
2352 /// implementation might not be suitable (e.g. arguments are stored in a Vec,
2353 /// the hash of which is order dependent, but we might not want the order of
2354 /// arguments to make a difference for the hash).
2356 /// However, since the value provided by Hash::hash often *is* suitable,
2357 /// especially for primitive types, there is the
2358 /// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
2359 /// Hash implementation for DepTrackingHash. It's important though that
2360 /// we have an opt-in scheme here, so one is hopefully forced to think about
2361 /// how the hash should be calculated when adding a new commandline argument.
2365 use std::collections::BTreeMap;
2366 use std::hash::Hash;
2367 use std::path::PathBuf;
2368 use std::collections::hash_map::DefaultHasher;
2369 use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
2370 Passes, Sanitizer, CrossLangLto};
2371 use syntax::feature_gate::UnstableFeatures;
2372 use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
2373 use syntax::edition::Edition;
2375 pub trait DepTrackingHash {
2376 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2379 macro_rules! impl_dep_tracking_hash_via_hash {
2381 impl DepTrackingHash for $t {
2382 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2383 Hash::hash(self, hasher);
2389 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2391 impl DepTrackingHash for Vec<$t> {
2392 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2393 let mut elems: Vec<&$t> = self.iter().collect();
2395 Hash::hash(&elems.len(), hasher);
2396 for (index, elem) in elems.iter().enumerate() {
2397 Hash::hash(&index, hasher);
2398 DepTrackingHash::hash(*elem, hasher, error_format);
2405 impl_dep_tracking_hash_via_hash!(bool);
2406 impl_dep_tracking_hash_via_hash!(usize);
2407 impl_dep_tracking_hash_via_hash!(u64);
2408 impl_dep_tracking_hash_via_hash!(String);
2409 impl_dep_tracking_hash_via_hash!(PathBuf);
2410 impl_dep_tracking_hash_via_hash!(lint::Level);
2411 impl_dep_tracking_hash_via_hash!(Option<bool>);
2412 impl_dep_tracking_hash_via_hash!(Option<usize>);
2413 impl_dep_tracking_hash_via_hash!(Option<String>);
2414 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2415 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2416 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2417 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2418 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2419 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2420 impl_dep_tracking_hash_via_hash!(CrateType);
2421 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2422 impl_dep_tracking_hash_via_hash!(RelroLevel);
2423 impl_dep_tracking_hash_via_hash!(Passes);
2424 impl_dep_tracking_hash_via_hash!(OptLevel);
2425 impl_dep_tracking_hash_via_hash!(Lto);
2426 impl_dep_tracking_hash_via_hash!(DebugInfoLevel);
2427 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2428 impl_dep_tracking_hash_via_hash!(OutputTypes);
2429 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2430 impl_dep_tracking_hash_via_hash!(Sanitizer);
2431 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2432 impl_dep_tracking_hash_via_hash!(TargetTriple);
2433 impl_dep_tracking_hash_via_hash!(Edition);
2434 impl_dep_tracking_hash_via_hash!(CrossLangLto);
2436 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2437 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2438 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2439 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2440 impl_dep_tracking_hash_for_sortable_vec_of!((
2443 Option<cstore::NativeLibraryKind>
2445 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2447 impl<T1, T2> DepTrackingHash for (T1, T2)
2449 T1: DepTrackingHash,
2450 T2: DepTrackingHash,
2452 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2453 Hash::hash(&0, hasher);
2454 DepTrackingHash::hash(&self.0, hasher, error_format);
2455 Hash::hash(&1, hasher);
2456 DepTrackingHash::hash(&self.1, hasher, error_format);
2460 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2462 T1: DepTrackingHash,
2463 T2: DepTrackingHash,
2464 T3: DepTrackingHash,
2466 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2467 Hash::hash(&0, hasher);
2468 DepTrackingHash::hash(&self.0, hasher, error_format);
2469 Hash::hash(&1, hasher);
2470 DepTrackingHash::hash(&self.1, hasher, error_format);
2471 Hash::hash(&2, hasher);
2472 DepTrackingHash::hash(&self.2, hasher, error_format);
2476 // This is a stable hash because BTreeMap is a sorted container
2478 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2479 hasher: &mut DefaultHasher,
2480 error_format: ErrorOutputType,
2482 for (key, sub_hash) in sub_hashes {
2483 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2484 // the keys, as they are just plain strings
2485 Hash::hash(&key.len(), hasher);
2486 Hash::hash(key, hasher);
2487 sub_hash.hash(hasher, error_format);
2498 use session::config::{build_configuration, build_session_options_and_crate_config};
2499 use session::config::{Lto, CrossLangLto};
2500 use session::build_session;
2501 use std::collections::{BTreeMap, BTreeSet};
2502 use std::iter::FromIterator;
2503 use std::path::PathBuf;
2504 use super::{Externs, OutputType, OutputTypes};
2505 use rustc_target::spec::{PanicStrategy, RelroLevel};
2506 use syntax::symbol::Symbol;
2507 use syntax::edition::{Edition, DEFAULT_EDITION};
2510 fn optgroups() -> getopts::Options {
2511 let mut opts = getopts::Options::new();
2512 for group in super::rustc_optgroups() {
2513 (group.apply)(&mut opts);
2518 fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
2519 BTreeMap::from_iter(entries.into_iter())
2522 fn mk_set<V: Ord>(entries: Vec<V>) -> BTreeSet<V> {
2523 BTreeSet::from_iter(entries.into_iter())
2526 // When the user supplies --test we should implicitly supply --cfg test
2528 fn test_switch_implies_cfg_test() {
2529 syntax::with_globals(|| {
2530 let matches = &match optgroups().parse(&["--test".to_string()]) {
2532 Err(f) => panic!("test_switch_implies_cfg_test: {}", f),
2534 let registry = errors::registry::Registry::new(&[]);
2535 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2536 let sess = build_session(sessopts, None, registry);
2537 let cfg = build_configuration(&sess, cfg);
2538 assert!(cfg.contains(&(Symbol::intern("test"), None)));
2542 // When the user supplies --test and --cfg test, don't implicitly add
2543 // another --cfg test
2545 fn test_switch_implies_cfg_test_unless_cfg_test() {
2546 syntax::with_globals(|| {
2547 let matches = &match optgroups().parse(&["--test".to_string(),
2548 "--cfg=test".to_string()]) {
2550 Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f),
2552 let registry = errors::registry::Registry::new(&[]);
2553 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2554 let sess = build_session(sessopts, None, registry);
2555 let cfg = build_configuration(&sess, cfg);
2556 let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
2557 assert!(test_items.next().is_some());
2558 assert!(test_items.next().is_none());
2563 fn test_can_print_warnings() {
2564 syntax::with_globals(|| {
2565 let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
2566 let registry = errors::registry::Registry::new(&[]);
2567 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2568 let sess = build_session(sessopts, None, registry);
2569 assert!(!sess.diagnostic().flags.can_emit_warnings);
2572 syntax::with_globals(|| {
2573 let matches = optgroups()
2574 .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()])
2576 let registry = errors::registry::Registry::new(&[]);
2577 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2578 let sess = build_session(sessopts, None, registry);
2579 assert!(sess.diagnostic().flags.can_emit_warnings);
2582 syntax::with_globals(|| {
2583 let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
2584 let registry = errors::registry::Registry::new(&[]);
2585 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2586 let sess = build_session(sessopts, None, registry);
2587 assert!(sess.diagnostic().flags.can_emit_warnings);
2592 fn test_output_types_tracking_hash_different_paths() {
2593 let mut v1 = super::basic_options();
2594 let mut v2 = super::basic_options();
2595 let mut v3 = super::basic_options();
2598 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
2600 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
2601 v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
2603 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2604 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2605 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2608 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2609 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2610 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2614 fn test_output_types_tracking_hash_different_construction_order() {
2615 let mut v1 = super::basic_options();
2616 let mut v2 = super::basic_options();
2618 v1.output_types = OutputTypes::new(&[
2619 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2620 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2623 v2.output_types = OutputTypes::new(&[
2624 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2625 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2628 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2631 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2635 fn test_externs_tracking_hash_different_construction_order() {
2636 let mut v1 = super::basic_options();
2637 let mut v2 = super::basic_options();
2638 let mut v3 = super::basic_options();
2640 v1.externs = Externs::new(mk_map(vec![
2643 mk_set(vec![String::from("b"), String::from("c")]),
2647 mk_set(vec![String::from("e"), String::from("f")]),
2651 v2.externs = Externs::new(mk_map(vec![
2654 mk_set(vec![String::from("e"), String::from("f")]),
2658 mk_set(vec![String::from("b"), String::from("c")]),
2662 v3.externs = Externs::new(mk_map(vec![
2665 mk_set(vec![String::from("b"), String::from("c")]),
2669 mk_set(vec![String::from("f"), String::from("e")]),
2673 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2674 assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
2675 assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
2678 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2679 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2680 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2684 fn test_lints_tracking_hash_different_values() {
2685 let mut v1 = super::basic_options();
2686 let mut v2 = super::basic_options();
2687 let mut v3 = super::basic_options();
2689 v1.lint_opts = vec![
2690 (String::from("a"), lint::Allow),
2691 (String::from("b"), lint::Warn),
2692 (String::from("c"), lint::Deny),
2693 (String::from("d"), lint::Forbid),
2696 v2.lint_opts = vec![
2697 (String::from("a"), lint::Allow),
2698 (String::from("b"), lint::Warn),
2699 (String::from("X"), lint::Deny),
2700 (String::from("d"), lint::Forbid),
2703 v3.lint_opts = vec![
2704 (String::from("a"), lint::Allow),
2705 (String::from("b"), lint::Warn),
2706 (String::from("c"), lint::Forbid),
2707 (String::from("d"), lint::Deny),
2710 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2711 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2712 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2715 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2716 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2717 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2721 fn test_lints_tracking_hash_different_construction_order() {
2722 let mut v1 = super::basic_options();
2723 let mut v2 = super::basic_options();
2725 v1.lint_opts = vec![
2726 (String::from("a"), lint::Allow),
2727 (String::from("b"), lint::Warn),
2728 (String::from("c"), lint::Deny),
2729 (String::from("d"), lint::Forbid),
2732 v2.lint_opts = vec![
2733 (String::from("a"), lint::Allow),
2734 (String::from("c"), lint::Deny),
2735 (String::from("b"), lint::Warn),
2736 (String::from("d"), lint::Forbid),
2739 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2742 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2743 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2747 fn test_search_paths_tracking_hash_different_order() {
2748 let mut v1 = super::basic_options();
2749 let mut v2 = super::basic_options();
2750 let mut v3 = super::basic_options();
2751 let mut v4 = super::basic_options();
2755 .add_path("native=abc", super::ErrorOutputType::Json(false));
2757 .add_path("crate=def", super::ErrorOutputType::Json(false));
2759 .add_path("dependency=ghi", super::ErrorOutputType::Json(false));
2761 .add_path("framework=jkl", super::ErrorOutputType::Json(false));
2763 .add_path("all=mno", super::ErrorOutputType::Json(false));
2766 .add_path("native=abc", super::ErrorOutputType::Json(false));
2768 .add_path("dependency=ghi", super::ErrorOutputType::Json(false));
2770 .add_path("crate=def", super::ErrorOutputType::Json(false));
2772 .add_path("framework=jkl", super::ErrorOutputType::Json(false));
2774 .add_path("all=mno", super::ErrorOutputType::Json(false));
2777 .add_path("crate=def", super::ErrorOutputType::Json(false));
2779 .add_path("framework=jkl", super::ErrorOutputType::Json(false));
2781 .add_path("native=abc", super::ErrorOutputType::Json(false));
2783 .add_path("dependency=ghi", super::ErrorOutputType::Json(false));
2785 .add_path("all=mno", super::ErrorOutputType::Json(false));
2788 .add_path("all=mno", super::ErrorOutputType::Json(false));
2790 .add_path("native=abc", super::ErrorOutputType::Json(false));
2792 .add_path("crate=def", super::ErrorOutputType::Json(false));
2794 .add_path("dependency=ghi", super::ErrorOutputType::Json(false));
2796 .add_path("framework=jkl", super::ErrorOutputType::Json(false));
2798 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
2799 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
2800 assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
2803 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2804 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2805 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2806 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
2810 fn test_native_libs_tracking_hash_different_values() {
2811 let mut v1 = super::basic_options();
2812 let mut v2 = super::basic_options();
2813 let mut v3 = super::basic_options();
2814 let mut v4 = super::basic_options();
2818 (String::from("a"), None, Some(cstore::NativeStatic)),
2819 (String::from("b"), None, Some(cstore::NativeFramework)),
2820 (String::from("c"), None, Some(cstore::NativeUnknown)),
2825 (String::from("a"), None, Some(cstore::NativeStatic)),
2826 (String::from("X"), None, Some(cstore::NativeFramework)),
2827 (String::from("c"), None, Some(cstore::NativeUnknown)),
2832 (String::from("a"), None, Some(cstore::NativeStatic)),
2833 (String::from("b"), None, Some(cstore::NativeStatic)),
2834 (String::from("c"), None, Some(cstore::NativeUnknown)),
2839 (String::from("a"), None, Some(cstore::NativeStatic)),
2842 Some(String::from("X")),
2843 Some(cstore::NativeFramework),
2845 (String::from("c"), None, Some(cstore::NativeUnknown)),
2848 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2849 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2850 assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
2853 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2854 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2855 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2856 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
2860 fn test_native_libs_tracking_hash_different_order() {
2861 let mut v1 = super::basic_options();
2862 let mut v2 = super::basic_options();
2863 let mut v3 = super::basic_options();
2867 (String::from("a"), None, Some(cstore::NativeStatic)),
2868 (String::from("b"), None, Some(cstore::NativeFramework)),
2869 (String::from("c"), None, Some(cstore::NativeUnknown)),
2873 (String::from("b"), None, Some(cstore::NativeFramework)),
2874 (String::from("a"), None, Some(cstore::NativeStatic)),
2875 (String::from("c"), None, Some(cstore::NativeUnknown)),
2879 (String::from("c"), None, Some(cstore::NativeUnknown)),
2880 (String::from("a"), None, Some(cstore::NativeStatic)),
2881 (String::from("b"), None, Some(cstore::NativeFramework)),
2884 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
2885 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
2886 assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
2889 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2890 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2891 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2895 fn test_codegen_options_tracking_hash() {
2896 let reference = super::basic_options();
2897 let mut opts = super::basic_options();
2899 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
2900 opts.cg.ar = Some(String::from("abc"));
2901 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2903 opts.cg.linker = Some(PathBuf::from("linker"));
2904 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2906 opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
2907 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2909 opts.cg.link_dead_code = true;
2910 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2912 opts.cg.rpath = true;
2913 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2915 opts.cg.extra_filename = String::from("extra-filename");
2916 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2918 opts.cg.codegen_units = Some(42);
2919 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2921 opts.cg.remark = super::SomePasses(vec![String::from("pass1"), String::from("pass2")]);
2922 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2924 opts.cg.save_temps = true;
2925 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2927 opts.cg.incremental = Some(String::from("abc"));
2928 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2930 // Make sure changing a [TRACKED] option changes the hash
2931 opts = reference.clone();
2932 opts.cg.lto = Lto::Fat;
2933 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2935 opts = reference.clone();
2936 opts.cg.target_cpu = Some(String::from("abc"));
2937 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2939 opts = reference.clone();
2940 opts.cg.target_feature = String::from("all the features, all of them");
2941 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2943 opts = reference.clone();
2944 opts.cg.passes = vec![String::from("1"), String::from("2")];
2945 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2947 opts = reference.clone();
2948 opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
2949 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2951 opts = reference.clone();
2952 opts.cg.overflow_checks = Some(true);
2953 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2955 opts = reference.clone();
2956 opts.cg.no_prepopulate_passes = true;
2957 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2959 opts = reference.clone();
2960 opts.cg.no_vectorize_loops = true;
2961 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2963 opts = reference.clone();
2964 opts.cg.no_vectorize_slp = true;
2965 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2967 opts = reference.clone();
2968 opts.cg.soft_float = true;
2969 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2971 opts = reference.clone();
2972 opts.cg.prefer_dynamic = true;
2973 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2975 opts = reference.clone();
2976 opts.cg.no_integrated_as = true;
2977 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2979 opts = reference.clone();
2980 opts.cg.no_redzone = Some(true);
2981 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2983 opts = reference.clone();
2984 opts.cg.relocation_model = Some(String::from("relocation model"));
2985 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2987 opts = reference.clone();
2988 opts.cg.code_model = Some(String::from("code model"));
2989 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2991 opts = reference.clone();
2992 opts.debugging_opts.tls_model = Some(String::from("tls model"));
2993 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2995 opts = reference.clone();
2996 opts.debugging_opts.pgo_gen = Some(String::from("abc"));
2997 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2999 opts = reference.clone();
3000 opts.debugging_opts.pgo_use = String::from("abc");
3001 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3003 opts = reference.clone();
3004 opts.cg.metadata = vec![String::from("A"), String::from("B")];
3005 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3007 opts = reference.clone();
3008 opts.cg.debuginfo = Some(0xdeadbeef);
3009 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3011 opts = reference.clone();
3012 opts.cg.debuginfo = Some(0xba5eba11);
3013 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3015 opts = reference.clone();
3016 opts.cg.force_frame_pointers = Some(false);
3017 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3019 opts = reference.clone();
3020 opts.cg.debug_assertions = Some(true);
3021 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3023 opts = reference.clone();
3024 opts.cg.inline_threshold = Some(0xf007ba11);
3025 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3027 opts = reference.clone();
3028 opts.cg.panic = Some(PanicStrategy::Abort);
3029 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3033 fn test_debugging_options_tracking_hash() {
3034 let reference = super::basic_options();
3035 let mut opts = super::basic_options();
3037 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3038 opts.debugging_opts.verbose = true;
3039 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3040 opts.debugging_opts.time_passes = true;
3041 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3042 opts.debugging_opts.count_llvm_insns = true;
3043 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3044 opts.debugging_opts.time_llvm_passes = true;
3045 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3046 opts.debugging_opts.input_stats = true;
3047 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3048 opts.debugging_opts.codegen_stats = true;
3049 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3050 opts.debugging_opts.borrowck_stats = true;
3051 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3052 opts.debugging_opts.meta_stats = true;
3053 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3054 opts.debugging_opts.print_link_args = true;
3055 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3056 opts.debugging_opts.print_llvm_passes = true;
3057 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3058 opts.debugging_opts.ast_json = true;
3059 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3060 opts.debugging_opts.ast_json_noexpand = true;
3061 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3062 opts.debugging_opts.ls = true;
3063 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3064 opts.debugging_opts.save_analysis = true;
3065 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3066 opts.debugging_opts.flowgraph_print_loans = true;
3067 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3068 opts.debugging_opts.flowgraph_print_moves = true;
3069 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3070 opts.debugging_opts.flowgraph_print_assigns = true;
3071 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3072 opts.debugging_opts.flowgraph_print_all = true;
3073 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3074 opts.debugging_opts.print_region_graph = true;
3075 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3076 opts.debugging_opts.parse_only = true;
3077 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3078 opts.debugging_opts.incremental = Some(String::from("abc"));
3079 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3080 opts.debugging_opts.dump_dep_graph = true;
3081 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3082 opts.debugging_opts.query_dep_graph = true;
3083 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3084 opts.debugging_opts.no_analysis = true;
3085 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3086 opts.debugging_opts.unstable_options = true;
3087 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3088 opts.debugging_opts.trace_macros = true;
3089 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3090 opts.debugging_opts.keep_hygiene_data = true;
3091 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3092 opts.debugging_opts.keep_ast = true;
3093 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3094 opts.debugging_opts.print_mono_items = Some(String::from("abc"));
3095 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3096 opts.debugging_opts.dump_mir = Some(String::from("abc"));
3097 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3098 opts.debugging_opts.dump_mir_dir = String::from("abc");
3099 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3100 opts.debugging_opts.dump_mir_graphviz = true;
3101 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3103 // Make sure changing a [TRACKED] option changes the hash
3104 opts = reference.clone();
3105 opts.debugging_opts.asm_comments = true;
3106 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3108 opts = reference.clone();
3109 opts.debugging_opts.no_verify = true;
3110 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3112 opts = reference.clone();
3113 opts.debugging_opts.no_landing_pads = true;
3114 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3116 opts = reference.clone();
3117 opts.debugging_opts.fewer_names = true;
3118 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3120 opts = reference.clone();
3121 opts.debugging_opts.no_codegen = true;
3122 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3124 opts = reference.clone();
3125 opts.debugging_opts.treat_err_as_bug = true;
3126 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3128 opts = reference.clone();
3129 opts.debugging_opts.continue_parse_after_error = true;
3130 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3132 opts = reference.clone();
3133 opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
3134 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3136 opts = reference.clone();
3137 opts.debugging_opts.force_overflow_checks = Some(true);
3138 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3140 opts = reference.clone();
3141 opts.debugging_opts.enable_nonzeroing_move_hints = true;
3142 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3144 opts = reference.clone();
3145 opts.debugging_opts.show_span = Some(String::from("abc"));
3146 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3148 opts = reference.clone();
3149 opts.debugging_opts.mir_opt_level = 3;
3150 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3152 opts = reference.clone();
3153 opts.debugging_opts.relro_level = Some(RelroLevel::Full);
3154 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3156 opts = reference.clone();
3157 opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink;
3158 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3162 fn test_edition_parsing() {
3163 // test default edition
3164 let options = super::basic_options();
3165 assert!(options.edition == DEFAULT_EDITION);
3167 let matches = optgroups()
3168 .parse(&["--edition=2018".to_string()])
3170 let (sessopts, _) = build_session_options_and_crate_config(&matches);
3171 assert!(sessopts.edition == Edition::Edition2018)