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 let mut prints = Vec::<PrintRequest>::new();
1976 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1977 prints.push(PrintRequest::TargetCPUs);
1978 cg.target_cpu = None;
1980 if cg.target_feature == "help" {
1981 prints.push(PrintRequest::TargetFeatures);
1982 cg.target_feature = "".to_string();
1984 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1985 prints.push(PrintRequest::RelocationModels);
1986 cg.relocation_model = None;
1988 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1989 prints.push(PrintRequest::CodeModels);
1990 cg.code_model = None;
1995 .map_or(false, |s| s == "help")
1997 prints.push(PrintRequest::TlsModels);
1998 debugging_opts.tls_model = None;
2003 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2004 let target_triple = if let Some(target) = matches.opt_str("target") {
2005 if target.ends_with(".json") {
2006 let path = Path::new(&target);
2007 match TargetTriple::from_path(&path) {
2008 Ok(triple) => triple,
2010 early_error(error_format, &format!("target file {:?} does not exist", path))
2014 TargetTriple::TargetTriple(target)
2017 TargetTriple::from_triple(host_triple())
2020 if matches.opt_present("O") {
2021 if cg.opt_level.is_some() {
2022 early_error(error_format, "-O and -C opt-level both provided");
2026 match cg.opt_level.as_ref().map(String::as_ref) {
2027 None => OptLevel::No,
2028 Some("0") => OptLevel::No,
2029 Some("1") => OptLevel::Less,
2030 Some("2") => OptLevel::Default,
2031 Some("3") => OptLevel::Aggressive,
2032 Some("s") => OptLevel::Size,
2033 Some("z") => OptLevel::SizeMin,
2038 "optimization level needs to be \
2039 between 0-3 (instead was `{}`)",
2047 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2048 let debuginfo = if matches.opt_present("g") {
2049 if cg.debuginfo.is_some() {
2050 early_error(error_format, "-g and -C debuginfo both provided");
2054 match cg.debuginfo {
2055 None | Some(0) => NoDebugInfo,
2056 Some(1) => LimitedDebugInfo,
2057 Some(2) => FullDebugInfo,
2062 "debug info level needs to be between \
2063 0-2 (instead was `{}`)",
2071 let mut search_paths = SearchPaths::new();
2072 for s in &matches.opt_strs("L") {
2073 search_paths.add_path(&s[..], error_format);
2080 // Parse string of the form "[KIND=]lib[:new_name]",
2081 // where KIND is one of "dylib", "framework", "static".
2082 let mut parts = s.splitn(2, '=');
2083 let kind = parts.next().unwrap();
2084 let (name, kind) = match (parts.next(), kind) {
2085 (None, name) => (name, None),
2086 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2087 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2088 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2089 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2094 "unknown library kind `{}`, expected \
2095 one of dylib, framework, or static",
2101 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2105 "the library kind 'static-nobundle' is only \
2106 accepted on the nightly compiler"
2110 let mut name_parts = name.splitn(2, ':');
2111 let name = name_parts.next().unwrap();
2112 let new_name = name_parts.next();
2113 (name.to_string(), new_name.map(|n| n.to_string()), kind)
2117 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
2118 let test = matches.opt_present("test");
2120 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2121 "crate-name" => PrintRequest::CrateName,
2122 "file-names" => PrintRequest::FileNames,
2123 "sysroot" => PrintRequest::Sysroot,
2124 "cfg" => PrintRequest::Cfg,
2125 "target-list" => PrintRequest::TargetList,
2126 "target-cpus" => PrintRequest::TargetCPUs,
2127 "target-features" => PrintRequest::TargetFeatures,
2128 "relocation-models" => PrintRequest::RelocationModels,
2129 "code-models" => PrintRequest::CodeModels,
2130 "tls-models" => PrintRequest::TlsModels,
2131 "native-static-libs" => PrintRequest::NativeStaticLibs,
2132 "target-spec-json" => {
2133 if nightly_options::is_unstable_enabled(matches) {
2134 PrintRequest::TargetSpec
2139 "the `-Z unstable-options` flag must also be passed to \
2140 enable the target-spec-json print option"
2145 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2148 let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) {
2149 None | Some("ast") => BorrowckMode::Ast,
2150 Some("mir") => BorrowckMode::Mir,
2151 Some("compare") => BorrowckMode::Compare,
2152 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2155 if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
2158 "-C remark will not show source locations without \
2163 let mut externs = BTreeMap::new();
2164 for arg in &matches.opt_strs("extern") {
2165 let mut parts = arg.splitn(2, '=');
2166 let name = match parts.next() {
2168 None => early_error(error_format, "--extern value must not be empty"),
2170 let location = match parts.next() {
2172 None => early_error(
2174 "--extern value must be of the format `foo=bar`",
2179 .entry(name.to_string())
2180 .or_insert_with(BTreeSet::new)
2181 .insert(location.to_string());
2184 let crate_name = matches.opt_str("crate-name");
2186 let remap_path_prefix = matches
2187 .opt_strs("remap-path-prefix")
2190 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2191 let to = parts.next();
2192 let from = parts.next();
2194 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2197 "--remap-path-prefix must contain '=' between FROM and TO",
2206 optimize: opt_level,
2211 output_types: OutputTypes(output_types),
2213 maybe_sysroot: sysroot_opt,
2222 externs: Externs(externs),
2226 unstable_features: UnstableFeatures::from_environment(),
2228 actually_rustdoc: false,
2229 cli_forced_codegen_units: codegen_units,
2230 cli_forced_thinlto_off: disable_thinlto,
2238 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2239 let mut crate_types: Vec<CrateType> = Vec::new();
2240 for unparsed_crate_type in &list_list {
2241 for part in unparsed_crate_type.split(',') {
2242 let new_part = match part {
2243 "lib" => default_lib_output(),
2244 "rlib" => CrateTypeRlib,
2245 "staticlib" => CrateTypeStaticlib,
2246 "dylib" => CrateTypeDylib,
2247 "cdylib" => CrateTypeCdylib,
2248 "bin" => CrateTypeExecutable,
2249 "proc-macro" => CrateTypeProcMacro,
2251 return Err(format!("unknown crate type: `{}`", part));
2254 if !crate_types.contains(&new_part) {
2255 crate_types.push(new_part)
2263 pub mod nightly_options {
2265 use syntax::feature_gate::UnstableFeatures;
2266 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2267 use session::early_error;
2269 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2274 .any(|x| *x == "unstable-options")
2277 pub fn is_nightly_build() -> bool {
2278 UnstableFeatures::from_environment().is_nightly_build()
2281 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2282 let has_z_unstable_option = matches
2285 .any(|x| *x == "unstable-options");
2286 let really_allows_unstable_options =
2287 UnstableFeatures::from_environment().is_nightly_build();
2289 for opt in flags.iter() {
2290 if opt.stability == OptionStability::Stable {
2293 if !matches.opt_present(opt.name) {
2296 if opt.name != "Z" && !has_z_unstable_option {
2298 ErrorOutputType::default(),
2300 "the `-Z unstable-options` flag must also be passed to enable \
2306 if really_allows_unstable_options {
2309 match opt.stability {
2310 OptionStability::Unstable => {
2312 "the option `{}` is only accepted on the \
2316 early_error(ErrorOutputType::default(), &msg);
2318 OptionStability::Stable => {}
2324 impl fmt::Display for CrateType {
2325 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2327 CrateTypeExecutable => "bin".fmt(f),
2328 CrateTypeDylib => "dylib".fmt(f),
2329 CrateTypeRlib => "rlib".fmt(f),
2330 CrateTypeStaticlib => "staticlib".fmt(f),
2331 CrateTypeCdylib => "cdylib".fmt(f),
2332 CrateTypeProcMacro => "proc-macro".fmt(f),
2337 /// Commandline arguments passed to the compiler have to be incorporated with
2338 /// the dependency tracking system for incremental compilation. This module
2339 /// provides some utilities to make this more convenient.
2341 /// The values of all commandline arguments that are relevant for dependency
2342 /// tracking are hashed into a single value that determines whether the
2343 /// incremental compilation cache can be re-used or not. This hashing is done
2344 /// via the DepTrackingHash trait defined below, since the standard Hash
2345 /// implementation might not be suitable (e.g. arguments are stored in a Vec,
2346 /// the hash of which is order dependent, but we might not want the order of
2347 /// arguments to make a difference for the hash).
2349 /// However, since the value provided by Hash::hash often *is* suitable,
2350 /// especially for primitive types, there is the
2351 /// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
2352 /// Hash implementation for DepTrackingHash. It's important though that
2353 /// we have an opt-in scheme here, so one is hopefully forced to think about
2354 /// how the hash should be calculated when adding a new commandline argument.
2358 use std::collections::BTreeMap;
2359 use std::hash::Hash;
2360 use std::path::PathBuf;
2361 use std::collections::hash_map::DefaultHasher;
2362 use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
2363 Passes, Sanitizer, CrossLangLto};
2364 use syntax::feature_gate::UnstableFeatures;
2365 use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
2366 use syntax::edition::Edition;
2368 pub trait DepTrackingHash {
2369 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2372 macro_rules! impl_dep_tracking_hash_via_hash {
2374 impl DepTrackingHash for $t {
2375 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2376 Hash::hash(self, hasher);
2382 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2384 impl DepTrackingHash for Vec<$t> {
2385 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2386 let mut elems: Vec<&$t> = self.iter().collect();
2388 Hash::hash(&elems.len(), hasher);
2389 for (index, elem) in elems.iter().enumerate() {
2390 Hash::hash(&index, hasher);
2391 DepTrackingHash::hash(*elem, hasher, error_format);
2398 impl_dep_tracking_hash_via_hash!(bool);
2399 impl_dep_tracking_hash_via_hash!(usize);
2400 impl_dep_tracking_hash_via_hash!(u64);
2401 impl_dep_tracking_hash_via_hash!(String);
2402 impl_dep_tracking_hash_via_hash!(PathBuf);
2403 impl_dep_tracking_hash_via_hash!(lint::Level);
2404 impl_dep_tracking_hash_via_hash!(Option<bool>);
2405 impl_dep_tracking_hash_via_hash!(Option<usize>);
2406 impl_dep_tracking_hash_via_hash!(Option<String>);
2407 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2408 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2409 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2410 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2411 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2412 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2413 impl_dep_tracking_hash_via_hash!(CrateType);
2414 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2415 impl_dep_tracking_hash_via_hash!(RelroLevel);
2416 impl_dep_tracking_hash_via_hash!(Passes);
2417 impl_dep_tracking_hash_via_hash!(OptLevel);
2418 impl_dep_tracking_hash_via_hash!(Lto);
2419 impl_dep_tracking_hash_via_hash!(DebugInfoLevel);
2420 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2421 impl_dep_tracking_hash_via_hash!(OutputTypes);
2422 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2423 impl_dep_tracking_hash_via_hash!(Sanitizer);
2424 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2425 impl_dep_tracking_hash_via_hash!(TargetTriple);
2426 impl_dep_tracking_hash_via_hash!(Edition);
2427 impl_dep_tracking_hash_via_hash!(CrossLangLto);
2429 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2430 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2431 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2432 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2433 impl_dep_tracking_hash_for_sortable_vec_of!((
2436 Option<cstore::NativeLibraryKind>
2438 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2440 impl<T1, T2> DepTrackingHash for (T1, T2)
2442 T1: DepTrackingHash,
2443 T2: DepTrackingHash,
2445 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2446 Hash::hash(&0, hasher);
2447 DepTrackingHash::hash(&self.0, hasher, error_format);
2448 Hash::hash(&1, hasher);
2449 DepTrackingHash::hash(&self.1, hasher, error_format);
2453 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2455 T1: DepTrackingHash,
2456 T2: DepTrackingHash,
2457 T3: DepTrackingHash,
2459 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2460 Hash::hash(&0, hasher);
2461 DepTrackingHash::hash(&self.0, hasher, error_format);
2462 Hash::hash(&1, hasher);
2463 DepTrackingHash::hash(&self.1, hasher, error_format);
2464 Hash::hash(&2, hasher);
2465 DepTrackingHash::hash(&self.2, hasher, error_format);
2469 // This is a stable hash because BTreeMap is a sorted container
2471 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2472 hasher: &mut DefaultHasher,
2473 error_format: ErrorOutputType,
2475 for (key, sub_hash) in sub_hashes {
2476 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2477 // the keys, as they are just plain strings
2478 Hash::hash(&key.len(), hasher);
2479 Hash::hash(key, hasher);
2480 sub_hash.hash(hasher, error_format);
2491 use session::config::{build_configuration, build_session_options_and_crate_config};
2492 use session::config::{Lto, CrossLangLto};
2493 use session::build_session;
2494 use std::collections::{BTreeMap, BTreeSet};
2495 use std::iter::FromIterator;
2496 use std::path::PathBuf;
2497 use super::{Externs, OutputType, OutputTypes};
2498 use rustc_target::spec::{PanicStrategy, RelroLevel};
2499 use syntax::symbol::Symbol;
2500 use syntax::edition::{Edition, DEFAULT_EDITION};
2503 fn optgroups() -> getopts::Options {
2504 let mut opts = getopts::Options::new();
2505 for group in super::rustc_optgroups() {
2506 (group.apply)(&mut opts);
2511 fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
2512 BTreeMap::from_iter(entries.into_iter())
2515 fn mk_set<V: Ord>(entries: Vec<V>) -> BTreeSet<V> {
2516 BTreeSet::from_iter(entries.into_iter())
2519 // When the user supplies --test we should implicitly supply --cfg test
2521 fn test_switch_implies_cfg_test() {
2522 syntax::with_globals(|| {
2523 let matches = &match optgroups().parse(&["--test".to_string()]) {
2525 Err(f) => panic!("test_switch_implies_cfg_test: {}", f),
2527 let registry = errors::registry::Registry::new(&[]);
2528 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2529 let sess = build_session(sessopts, None, registry);
2530 let cfg = build_configuration(&sess, cfg);
2531 assert!(cfg.contains(&(Symbol::intern("test"), None)));
2535 // When the user supplies --test and --cfg test, don't implicitly add
2536 // another --cfg test
2538 fn test_switch_implies_cfg_test_unless_cfg_test() {
2539 syntax::with_globals(|| {
2540 let matches = &match optgroups().parse(&["--test".to_string(),
2541 "--cfg=test".to_string()]) {
2543 Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f),
2545 let registry = errors::registry::Registry::new(&[]);
2546 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
2547 let sess = build_session(sessopts, None, registry);
2548 let cfg = build_configuration(&sess, cfg);
2549 let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
2550 assert!(test_items.next().is_some());
2551 assert!(test_items.next().is_none());
2556 fn test_can_print_warnings() {
2557 syntax::with_globals(|| {
2558 let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
2559 let registry = errors::registry::Registry::new(&[]);
2560 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2561 let sess = build_session(sessopts, None, registry);
2562 assert!(!sess.diagnostic().flags.can_emit_warnings);
2565 syntax::with_globals(|| {
2566 let matches = optgroups()
2567 .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()])
2569 let registry = errors::registry::Registry::new(&[]);
2570 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2571 let sess = build_session(sessopts, None, registry);
2572 assert!(sess.diagnostic().flags.can_emit_warnings);
2575 syntax::with_globals(|| {
2576 let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
2577 let registry = errors::registry::Registry::new(&[]);
2578 let (sessopts, _) = build_session_options_and_crate_config(&matches);
2579 let sess = build_session(sessopts, None, registry);
2580 assert!(sess.diagnostic().flags.can_emit_warnings);
2585 fn test_output_types_tracking_hash_different_paths() {
2586 let mut v1 = super::basic_options();
2587 let mut v2 = super::basic_options();
2588 let mut v3 = super::basic_options();
2591 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
2593 OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
2594 v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
2596 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2597 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2598 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2601 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2602 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2603 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2607 fn test_output_types_tracking_hash_different_construction_order() {
2608 let mut v1 = super::basic_options();
2609 let mut v2 = super::basic_options();
2611 v1.output_types = OutputTypes::new(&[
2612 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2613 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2616 v2.output_types = OutputTypes::new(&[
2617 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
2618 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
2621 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2624 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2628 fn test_externs_tracking_hash_different_construction_order() {
2629 let mut v1 = super::basic_options();
2630 let mut v2 = super::basic_options();
2631 let mut v3 = super::basic_options();
2633 v1.externs = Externs::new(mk_map(vec![
2636 mk_set(vec![String::from("b"), String::from("c")]),
2640 mk_set(vec![String::from("e"), String::from("f")]),
2644 v2.externs = Externs::new(mk_map(vec![
2647 mk_set(vec![String::from("e"), String::from("f")]),
2651 mk_set(vec![String::from("b"), String::from("c")]),
2655 v3.externs = Externs::new(mk_map(vec![
2658 mk_set(vec![String::from("b"), String::from("c")]),
2662 mk_set(vec![String::from("f"), String::from("e")]),
2666 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2667 assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
2668 assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
2671 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2672 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2673 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2677 fn test_lints_tracking_hash_different_values() {
2678 let mut v1 = super::basic_options();
2679 let mut v2 = super::basic_options();
2680 let mut v3 = super::basic_options();
2682 v1.lint_opts = vec![
2683 (String::from("a"), lint::Allow),
2684 (String::from("b"), lint::Warn),
2685 (String::from("c"), lint::Deny),
2686 (String::from("d"), lint::Forbid),
2689 v2.lint_opts = vec![
2690 (String::from("a"), lint::Allow),
2691 (String::from("b"), lint::Warn),
2692 (String::from("X"), lint::Deny),
2693 (String::from("d"), lint::Forbid),
2696 v3.lint_opts = vec![
2697 (String::from("a"), lint::Allow),
2698 (String::from("b"), lint::Warn),
2699 (String::from("c"), lint::Forbid),
2700 (String::from("d"), lint::Deny),
2703 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2704 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2705 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2708 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2709 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2710 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2714 fn test_lints_tracking_hash_different_construction_order() {
2715 let mut v1 = super::basic_options();
2716 let mut v2 = super::basic_options();
2718 v1.lint_opts = vec![
2719 (String::from("a"), lint::Allow),
2720 (String::from("b"), lint::Warn),
2721 (String::from("c"), lint::Deny),
2722 (String::from("d"), lint::Forbid),
2725 v2.lint_opts = vec![
2726 (String::from("a"), lint::Allow),
2727 (String::from("c"), lint::Deny),
2728 (String::from("b"), lint::Warn),
2729 (String::from("d"), lint::Forbid),
2732 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2735 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2736 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2740 fn test_search_paths_tracking_hash_different_order() {
2741 let mut v1 = super::basic_options();
2742 let mut v2 = super::basic_options();
2743 let mut v3 = super::basic_options();
2744 let mut v4 = super::basic_options();
2748 .add_path("native=abc", super::ErrorOutputType::Json(false));
2750 .add_path("crate=def", super::ErrorOutputType::Json(false));
2752 .add_path("dependency=ghi", super::ErrorOutputType::Json(false));
2754 .add_path("framework=jkl", super::ErrorOutputType::Json(false));
2756 .add_path("all=mno", super::ErrorOutputType::Json(false));
2759 .add_path("native=abc", super::ErrorOutputType::Json(false));
2761 .add_path("dependency=ghi", super::ErrorOutputType::Json(false));
2763 .add_path("crate=def", super::ErrorOutputType::Json(false));
2765 .add_path("framework=jkl", super::ErrorOutputType::Json(false));
2767 .add_path("all=mno", 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("native=abc", super::ErrorOutputType::Json(false));
2776 .add_path("dependency=ghi", super::ErrorOutputType::Json(false));
2778 .add_path("all=mno", super::ErrorOutputType::Json(false));
2781 .add_path("all=mno", super::ErrorOutputType::Json(false));
2783 .add_path("native=abc", super::ErrorOutputType::Json(false));
2785 .add_path("crate=def", super::ErrorOutputType::Json(false));
2787 .add_path("dependency=ghi", super::ErrorOutputType::Json(false));
2789 .add_path("framework=jkl", super::ErrorOutputType::Json(false));
2791 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
2792 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
2793 assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
2796 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2797 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2798 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2799 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
2803 fn test_native_libs_tracking_hash_different_values() {
2804 let mut v1 = super::basic_options();
2805 let mut v2 = super::basic_options();
2806 let mut v3 = super::basic_options();
2807 let mut v4 = super::basic_options();
2811 (String::from("a"), None, Some(cstore::NativeStatic)),
2812 (String::from("b"), None, Some(cstore::NativeFramework)),
2813 (String::from("c"), None, Some(cstore::NativeUnknown)),
2818 (String::from("a"), None, Some(cstore::NativeStatic)),
2819 (String::from("X"), None, Some(cstore::NativeFramework)),
2820 (String::from("c"), None, Some(cstore::NativeUnknown)),
2825 (String::from("a"), None, Some(cstore::NativeStatic)),
2826 (String::from("b"), None, Some(cstore::NativeStatic)),
2827 (String::from("c"), None, Some(cstore::NativeUnknown)),
2832 (String::from("a"), None, Some(cstore::NativeStatic)),
2835 Some(String::from("X")),
2836 Some(cstore::NativeFramework),
2838 (String::from("c"), None, Some(cstore::NativeUnknown)),
2841 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2842 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2843 assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
2846 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2847 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2848 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2849 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
2853 fn test_native_libs_tracking_hash_different_order() {
2854 let mut v1 = super::basic_options();
2855 let mut v2 = super::basic_options();
2856 let mut v3 = super::basic_options();
2860 (String::from("a"), None, Some(cstore::NativeStatic)),
2861 (String::from("b"), None, Some(cstore::NativeFramework)),
2862 (String::from("c"), None, Some(cstore::NativeUnknown)),
2866 (String::from("b"), None, Some(cstore::NativeFramework)),
2867 (String::from("a"), None, Some(cstore::NativeStatic)),
2868 (String::from("c"), None, Some(cstore::NativeUnknown)),
2872 (String::from("c"), None, Some(cstore::NativeUnknown)),
2873 (String::from("a"), None, Some(cstore::NativeStatic)),
2874 (String::from("b"), None, Some(cstore::NativeFramework)),
2877 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
2878 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
2879 assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
2882 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2883 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2884 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2888 fn test_codegen_options_tracking_hash() {
2889 let reference = super::basic_options();
2890 let mut opts = super::basic_options();
2892 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
2893 opts.cg.ar = Some(String::from("abc"));
2894 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2896 opts.cg.linker = Some(PathBuf::from("linker"));
2897 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2899 opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
2900 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2902 opts.cg.link_dead_code = true;
2903 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2905 opts.cg.rpath = true;
2906 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2908 opts.cg.extra_filename = String::from("extra-filename");
2909 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2911 opts.cg.codegen_units = Some(42);
2912 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2914 opts.cg.remark = super::SomePasses(vec![String::from("pass1"), String::from("pass2")]);
2915 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2917 opts.cg.save_temps = true;
2918 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2920 opts.cg.incremental = Some(String::from("abc"));
2921 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2923 // Make sure changing a [TRACKED] option changes the hash
2924 opts = reference.clone();
2925 opts.cg.lto = Lto::Fat;
2926 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2928 opts = reference.clone();
2929 opts.cg.target_cpu = Some(String::from("abc"));
2930 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2932 opts = reference.clone();
2933 opts.cg.target_feature = String::from("all the features, all of them");
2934 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2936 opts = reference.clone();
2937 opts.cg.passes = vec![String::from("1"), String::from("2")];
2938 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2940 opts = reference.clone();
2941 opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
2942 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2944 opts = reference.clone();
2945 opts.cg.overflow_checks = Some(true);
2946 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2948 opts = reference.clone();
2949 opts.cg.no_prepopulate_passes = true;
2950 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2952 opts = reference.clone();
2953 opts.cg.no_vectorize_loops = true;
2954 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2956 opts = reference.clone();
2957 opts.cg.no_vectorize_slp = true;
2958 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2960 opts = reference.clone();
2961 opts.cg.soft_float = true;
2962 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2964 opts = reference.clone();
2965 opts.cg.prefer_dynamic = true;
2966 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2968 opts = reference.clone();
2969 opts.cg.no_integrated_as = true;
2970 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2972 opts = reference.clone();
2973 opts.cg.no_redzone = Some(true);
2974 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2976 opts = reference.clone();
2977 opts.cg.relocation_model = Some(String::from("relocation model"));
2978 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2980 opts = reference.clone();
2981 opts.cg.code_model = Some(String::from("code model"));
2982 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2984 opts = reference.clone();
2985 opts.debugging_opts.tls_model = Some(String::from("tls model"));
2986 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2988 opts = reference.clone();
2989 opts.debugging_opts.pgo_gen = Some(String::from("abc"));
2990 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2992 opts = reference.clone();
2993 opts.debugging_opts.pgo_use = String::from("abc");
2994 assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2996 opts = reference.clone();
2997 opts.cg.metadata = vec![String::from("A"), String::from("B")];
2998 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3000 opts = reference.clone();
3001 opts.cg.debuginfo = Some(0xdeadbeef);
3002 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3004 opts = reference.clone();
3005 opts.cg.debuginfo = Some(0xba5eba11);
3006 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3008 opts = reference.clone();
3009 opts.cg.force_frame_pointers = Some(false);
3010 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3012 opts = reference.clone();
3013 opts.cg.debug_assertions = Some(true);
3014 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3016 opts = reference.clone();
3017 opts.cg.inline_threshold = Some(0xf007ba11);
3018 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3020 opts = reference.clone();
3021 opts.cg.panic = Some(PanicStrategy::Abort);
3022 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3026 fn test_debugging_options_tracking_hash() {
3027 let reference = super::basic_options();
3028 let mut opts = super::basic_options();
3030 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
3031 opts.debugging_opts.verbose = true;
3032 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3033 opts.debugging_opts.time_passes = true;
3034 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3035 opts.debugging_opts.count_llvm_insns = true;
3036 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3037 opts.debugging_opts.time_llvm_passes = true;
3038 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3039 opts.debugging_opts.input_stats = true;
3040 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3041 opts.debugging_opts.codegen_stats = true;
3042 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3043 opts.debugging_opts.borrowck_stats = true;
3044 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3045 opts.debugging_opts.meta_stats = true;
3046 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3047 opts.debugging_opts.print_link_args = true;
3048 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3049 opts.debugging_opts.print_llvm_passes = true;
3050 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3051 opts.debugging_opts.ast_json = true;
3052 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3053 opts.debugging_opts.ast_json_noexpand = true;
3054 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3055 opts.debugging_opts.ls = true;
3056 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3057 opts.debugging_opts.save_analysis = true;
3058 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3059 opts.debugging_opts.flowgraph_print_loans = true;
3060 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3061 opts.debugging_opts.flowgraph_print_moves = true;
3062 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3063 opts.debugging_opts.flowgraph_print_assigns = true;
3064 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3065 opts.debugging_opts.flowgraph_print_all = true;
3066 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3067 opts.debugging_opts.print_region_graph = true;
3068 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3069 opts.debugging_opts.parse_only = true;
3070 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3071 opts.debugging_opts.incremental = Some(String::from("abc"));
3072 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3073 opts.debugging_opts.dump_dep_graph = true;
3074 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3075 opts.debugging_opts.query_dep_graph = true;
3076 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3077 opts.debugging_opts.no_analysis = true;
3078 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3079 opts.debugging_opts.unstable_options = true;
3080 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3081 opts.debugging_opts.trace_macros = true;
3082 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3083 opts.debugging_opts.keep_hygiene_data = true;
3084 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3085 opts.debugging_opts.keep_ast = true;
3086 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3087 opts.debugging_opts.print_mono_items = Some(String::from("abc"));
3088 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3089 opts.debugging_opts.dump_mir = Some(String::from("abc"));
3090 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3091 opts.debugging_opts.dump_mir_dir = String::from("abc");
3092 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3093 opts.debugging_opts.dump_mir_graphviz = true;
3094 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
3096 // Make sure changing a [TRACKED] option changes the hash
3097 opts = reference.clone();
3098 opts.debugging_opts.asm_comments = true;
3099 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3101 opts = reference.clone();
3102 opts.debugging_opts.no_verify = true;
3103 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3105 opts = reference.clone();
3106 opts.debugging_opts.no_landing_pads = true;
3107 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3109 opts = reference.clone();
3110 opts.debugging_opts.fewer_names = true;
3111 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3113 opts = reference.clone();
3114 opts.debugging_opts.no_codegen = true;
3115 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3117 opts = reference.clone();
3118 opts.debugging_opts.treat_err_as_bug = true;
3119 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3121 opts = reference.clone();
3122 opts.debugging_opts.continue_parse_after_error = true;
3123 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3125 opts = reference.clone();
3126 opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
3127 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3129 opts = reference.clone();
3130 opts.debugging_opts.force_overflow_checks = Some(true);
3131 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3133 opts = reference.clone();
3134 opts.debugging_opts.enable_nonzeroing_move_hints = true;
3135 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3137 opts = reference.clone();
3138 opts.debugging_opts.show_span = Some(String::from("abc"));
3139 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3141 opts = reference.clone();
3142 opts.debugging_opts.mir_opt_level = 3;
3143 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3145 opts = reference.clone();
3146 opts.debugging_opts.relro_level = Some(RelroLevel::Full);
3147 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3149 opts = reference.clone();
3150 opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink;
3151 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3155 fn test_edition_parsing() {
3156 // test default edition
3157 let options = super::basic_options();
3158 assert!(options.edition == DEFAULT_EDITION);
3160 let matches = optgroups()
3161 .parse(&["--edition=2018".to_string()])
3163 let (sessopts, _) = build_session_options_and_crate_config(&matches);
3164 assert!(sessopts.edition == Edition::Edition2018)