use syntax::parse::token::InternedString;
use syntax::feature_gate::UnstableFeatures;
-use errors::{ColorConfig, Handler};
+use errors::{ColorConfig, FatalError, Handler};
use getopts;
-use std::collections::HashMap;
+use std::collections::{BTreeMap, BTreeSet};
+use std::collections::btree_map::Iter as BTreeMapIter;
+use std::collections::btree_map::Keys as BTreeMapKeysIter;
+use std::collections::btree_map::Values as BTreeMapValuesIter;
+
use std::env;
use std::fmt;
+use std::hash::{Hasher, SipHasher};
+use std::iter::FromIterator;
use std::path::PathBuf;
pub struct Config {
pub uint_type: UintTy,
}
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Hash)]
pub enum OptLevel {
No, // -O0
Less, // -O1
SizeMin, // -Oz
}
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Hash)]
pub enum DebugInfoLevel {
NoDebugInfo,
LimitedDebugInfo,
FullDebugInfo,
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord,
+ RustcEncodable, RustcDecodable)]
pub enum OutputType {
Bitcode,
Assembly,
OutputType::DepInfo => "dep-info",
}
}
+
+ pub fn extension(&self) -> &'static str {
+ match *self {
+ OutputType::Bitcode => "bc",
+ OutputType::Assembly => "s",
+ OutputType::LlvmAssembly => "ll",
+ OutputType::Object => "o",
+ OutputType::DepInfo => "d",
+ OutputType::Exe => "",
+ }
+ }
}
-#[derive(Clone)]
-pub struct Options {
- // The crate config requested for the session, which may be combined
- // with additional crate configurations during the compile process
- pub crate_types: Vec<CrateType>,
-
- pub optimize: OptLevel,
- pub debug_assertions: bool,
- pub debuginfo: DebugInfoLevel,
- pub lint_opts: Vec<(String, lint::Level)>,
- pub lint_cap: Option<lint::Level>,
- pub describe_lints: bool,
- pub output_types: HashMap<OutputType, Option<PathBuf>>,
- // This was mutable for rustpkg, which updates search paths based on the
- // parsed code. It remains mutable in case its replacements wants to use
- // this.
- pub search_paths: SearchPaths,
- pub libs: Vec<(String, cstore::NativeLibraryKind)>,
- pub maybe_sysroot: Option<PathBuf>,
- pub target_triple: String,
- // User-specified cfg meta items. The compiler itself will add additional
- // items to the crate config, and during parsing the entire crate config
- // will be added to the crate AST node. This should not be used for
- // anything except building the full crate config prior to parsing.
- pub cfg: ast::CrateConfig,
- pub test: bool,
- pub parse_only: bool,
- pub no_trans: bool,
- pub error_format: ErrorOutputType,
- pub treat_err_as_bug: bool,
- pub continue_parse_after_error: bool,
- pub mir_opt_level: usize,
-
- /// if Some, enable incremental compilation, using the given
- /// directory to store intermediate results
- pub incremental: Option<PathBuf>,
-
- pub no_analysis: bool,
- pub debugging_opts: DebuggingOptions,
- pub prints: Vec<PrintRequest>,
- pub cg: CodegenOptions,
- pub externs: HashMap<String, Vec<String>>,
- pub crate_name: Option<String>,
- /// An optional name to use as the crate for std during std injection,
- /// written `extern crate std = "name"`. Default to "std". Used by
- /// out-of-tree drivers.
- pub alt_std_name: Option<String>,
- /// Indicates how the compiler should treat unstable features
- pub unstable_features: UnstableFeatures
+// Use tree-based collections to cheaply get a deterministic Hash implementation.
+// DO NOT switch BTreeMap out for an unsorted container type! That would break
+// dependency tracking for commandline arguments.
+#[derive(Clone, Hash)]
+pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
+
+impl OutputTypes {
+ pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
+ OutputTypes(BTreeMap::from_iter(entries.iter()
+ .map(|&(k, ref v)| (k, v.clone()))))
+ }
+
+ pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
+ self.0.get(key)
+ }
+
+ pub fn contains_key(&self, key: &OutputType) -> bool {
+ self.0.contains_key(key)
+ }
+
+ pub fn keys<'a>(&'a self) -> BTreeMapKeysIter<'a, OutputType, Option<PathBuf>> {
+ self.0.keys()
+ }
+
+ pub fn values<'a>(&'a self) -> BTreeMapValuesIter<'a, OutputType, Option<PathBuf>> {
+ self.0.values()
+ }
+}
+
+
+// Use tree-based collections to cheaply get a deterministic Hash implementation.
+// DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
+// would break dependency tracking for commandline arguments.
+#[derive(Clone, Hash)]
+pub struct Externs(BTreeMap<String, BTreeSet<String>>);
+
+impl Externs {
+ pub fn new(data: BTreeMap<String, BTreeSet<String>>) -> Externs {
+ Externs(data)
+ }
+
+ pub fn get(&self, key: &str) -> Option<&BTreeSet<String>> {
+ self.0.get(key)
+ }
+
+ pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<String>> {
+ self.0.iter()
+ }
}
+macro_rules! hash_option {
+ ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
+ ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
+ if $sub_hashes.insert(stringify!($opt_name),
+ $opt_expr as &dep_tracking::DepTrackingHash).is_some() {
+ bug!("Duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
+ }
+ });
+ ($opt_name:ident,
+ $opt_expr:expr,
+ $sub_hashes:expr,
+ [UNTRACKED_WITH_WARNING $warn_val:expr, $warn_text:expr, $error_format:expr]) => ({
+ if *$opt_expr == $warn_val {
+ early_warn($error_format, $warn_text)
+ }
+ });
+}
+
+macro_rules! top_level_options {
+ (pub struct Options { $(
+ $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
+ )* } ) => (
+ #[derive(Clone)]
+ pub struct Options {
+ $(pub $opt: $t),*
+ }
+
+ impl Options {
+ pub fn dep_tracking_hash(&self) -> u64 {
+ let mut sub_hashes = BTreeMap::new();
+ $({
+ hash_option!($opt,
+ &self.$opt,
+ &mut sub_hashes,
+ [$dep_tracking_marker $($warn_val,
+ $warn_text,
+ self.error_format)*]);
+ })*
+ let mut hasher = SipHasher::new();
+ dep_tracking::stable_hash(sub_hashes,
+ &mut hasher,
+ self.error_format);
+ hasher.finish()
+ }
+ }
+ );
+}
+
+// The top-level commandline options struct
+//
+// For each option, one has to specify how it behaves with regard to the
+// dependency tracking system of incremental compilation. This is done via the
+// square-bracketed directive after the field type. The options are:
+//
+// [TRACKED]
+// A change in the given field will cause the compiler to completely clear the
+// incremental compilation cache before proceeding.
+//
+// [UNTRACKED]
+// Incremental compilation is not influenced by this option.
+//
+// [UNTRACKED_WITH_WARNING(val, warning)]
+// The option is incompatible with incremental compilation in some way. If it
+// has the value `val`, the string `warning` is emitted as a warning.
+//
+// If you add a new option to this struct or one of the sub-structs like
+// CodegenOptions, think about how it influences incremental compilation. If in
+// doubt, specify [TRACKED], which is always "correct" but might lead to
+// unnecessary re-compilation.
+top_level_options!(
+ pub struct Options {
+ // The crate config requested for the session, which may be combined
+ // with additional crate configurations during the compile process
+ crate_types: Vec<CrateType> [TRACKED],
+ optimize: OptLevel [TRACKED],
+ // Include the debug_assertions flag into dependency tracking, since it
+ // can influence whether overflow checks are done or not.
+ debug_assertions: bool [TRACKED],
+ debuginfo: DebugInfoLevel [TRACKED],
+ lint_opts: Vec<(String, lint::Level)> [TRACKED],
+ lint_cap: Option<lint::Level> [TRACKED],
+ describe_lints: bool [UNTRACKED],
+ output_types: OutputTypes [TRACKED],
+ // FIXME(mw): We track this for now but it actually doesn't make too
+ // much sense: The search path can stay the same while the
+ // things discovered there might have changed on disk.
+ search_paths: SearchPaths [TRACKED],
+ libs: Vec<(String, cstore::NativeLibraryKind)> [TRACKED],
+ maybe_sysroot: Option<PathBuf> [TRACKED],
+
+ target_triple: String [TRACKED],
+
+ test: bool [TRACKED],
+ error_format: ErrorOutputType [UNTRACKED],
+ mir_opt_level: usize [TRACKED],
+
+ // if Some, enable incremental compilation, using the given
+ // directory to store intermediate results
+ incremental: Option<PathBuf> [UNTRACKED],
+
+ debugging_opts: DebuggingOptions [TRACKED],
+ prints: Vec<PrintRequest> [UNTRACKED],
+ cg: CodegenOptions [TRACKED],
+ // FIXME(mw): We track this for now but it actually doesn't make too
+ // much sense: The value of this option can stay the same
+ // while the files they refer to might have changed on disk.
+ externs: Externs [TRACKED],
+ crate_name: Option<String> [TRACKED],
+ // An optional name to use as the crate for std during std injection,
+ // written `extern crate std = "name"`. Default to "std". Used by
+ // out-of-tree drivers.
+ alt_std_name: Option<String> [TRACKED],
+ // Indicates how the compiler should treat unstable features
+ unstable_features: UnstableFeatures [TRACKED],
+ }
+);
+
#[derive(Clone, PartialEq, Eq)]
pub enum PrintRequest {
FileNames,
CrateName,
Cfg,
TargetList,
+ TargetCPUs,
+ TargetFeatures,
+ RelocationModels,
+ CodeModels,
}
pub enum Input {
pub out_filestem: String,
pub single_output_file: Option<PathBuf>,
pub extra: String,
- pub outputs: HashMap<OutputType, Option<PathBuf>>,
+ pub outputs: OutputTypes,
}
+/// Codegen unit names generated by the numbered naming scheme will contain this
+/// marker right before the index of the codegen unit.
+pub const NUMBERED_CODEGEN_UNIT_MARKER: &'static str = ".cgu-";
+
impl OutputFilenames {
pub fn path(&self, flavor: OutputType) -> PathBuf {
self.outputs.get(&flavor).and_then(|p| p.to_owned())
.or_else(|| self.single_output_file.clone())
- .unwrap_or_else(|| self.temp_path(flavor))
+ .unwrap_or_else(|| self.temp_path(flavor, None))
+ }
+
+ /// Get the path where a compilation artifact of the given type for the
+ /// given codegen unit should be placed on disk. If codegen_unit_name is
+ /// None, a path distinct from those of any codegen unit will be generated.
+ pub fn temp_path(&self,
+ flavor: OutputType,
+ codegen_unit_name: Option<&str>)
+ -> PathBuf {
+ let extension = flavor.extension();
+ self.temp_path_ext(extension, codegen_unit_name)
}
- pub fn temp_path(&self, flavor: OutputType) -> PathBuf {
+ /// Like temp_path, but also supports things where there is no corresponding
+ /// OutputType, like no-opt-bitcode or lto-bitcode.
+ pub fn temp_path_ext(&self,
+ ext: &str,
+ codegen_unit_name: Option<&str>)
+ -> PathBuf {
let base = self.out_directory.join(&self.filestem());
- match flavor {
- OutputType::Bitcode => base.with_extension("bc"),
- OutputType::Assembly => base.with_extension("s"),
- OutputType::LlvmAssembly => base.with_extension("ll"),
- OutputType::Object => base.with_extension("o"),
- OutputType::DepInfo => base.with_extension("d"),
- OutputType::Exe => base,
+
+ let mut extension = String::new();
+
+ if let Some(codegen_unit_name) = codegen_unit_name {
+ if codegen_unit_name.contains(NUMBERED_CODEGEN_UNIT_MARKER) {
+ // If we use the numbered naming scheme for modules, we don't want
+ // the files to look like <crate-name><extra>.<crate-name>.<index>.<ext>
+ // but simply <crate-name><extra>.<index>.<ext>
+ let marker_offset = codegen_unit_name.rfind(NUMBERED_CODEGEN_UNIT_MARKER)
+ .unwrap();
+ let index_offset = marker_offset + NUMBERED_CODEGEN_UNIT_MARKER.len();
+ extension.push_str(&codegen_unit_name[index_offset .. ]);
+ } else {
+ extension.push_str(codegen_unit_name);
+ };
}
+
+ if !ext.is_empty() {
+ if !extension.is_empty() {
+ extension.push_str(".");
+ }
+
+ extension.push_str(ext);
+ }
+
+ let path = base.with_extension(&extension[..]);
+ path
}
pub fn with_extension(&self, extension: &str) -> PathBuf {
lint_opts: Vec::new(),
lint_cap: None,
describe_lints: false,
- output_types: HashMap::new(),
+ output_types: OutputTypes(BTreeMap::new()),
search_paths: SearchPaths::new(),
maybe_sysroot: None,
target_triple: host_triple().to_string(),
- cfg: Vec::new(),
test: false,
- parse_only: false,
- no_trans: false,
- treat_err_as_bug: false,
- continue_parse_after_error: false,
mir_opt_level: 1,
incremental: None,
- no_analysis: false,
debugging_opts: basic_debugging_options(),
prints: Vec::new(),
cg: basic_codegen_options(),
error_format: ErrorOutputType::default(),
- externs: HashMap::new(),
+ externs: Externs(BTreeMap::new()),
crate_name: None,
alt_std_name: None,
libs: Vec::new(),
self.debugging_opts.dump_dep_graph ||
self.debugging_opts.query_dep_graph
}
+
+ pub fn single_codegen_unit(&self) -> bool {
+ self.incremental.is_none() ||
+ self.cg.codegen_units == 1
+ }
}
// The type of entry function, so
CrateTypeCdylib,
}
-#[derive(Clone)]
+#[derive(Clone, Hash)]
pub enum Passes {
SomePasses(Vec<String>),
AllPasses,
}
}
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Hash)]
pub enum PanicStrategy {
Unwind,
Abort,
($struct_name:ident, $setter_name:ident, $defaultfn:ident,
$buildfn:ident, $prefix:expr, $outputname:expr,
$stat:ident, $mod_desc:ident, $mod_set:ident,
- $($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) =>
+ $($opt:ident : $t:ty = (
+ $init:expr,
+ $parse:ident,
+ [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
+ $desc:expr)
+ ),* ,) =>
(
#[derive(Clone)]
pub struct $struct_name { $(pub $opt: $t),* }
return op;
}
+ impl<'a> dep_tracking::DepTrackingHash for $struct_name {
+
+ fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) {
+ let mut sub_hashes = BTreeMap::new();
+ $({
+ hash_option!($opt,
+ &self.$opt,
+ &mut sub_hashes,
+ [$dep_tracking_marker $($dep_warn_val,
+ $dep_warn_text,
+ error_format)*]);
+ })*
+ dep_tracking::stable_hash(sub_hashes, hasher, error_format);
+ }
+ }
+
pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
pub const $stat: &'static [(&'static str, $setter_name,
Option<&'static str>, &'static str)] =
pub const parse_bool: Option<&'static str> = None;
pub const parse_opt_bool: Option<&'static str> =
Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
+ pub const parse_all_bool: Option<&'static str> =
+ Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
pub const parse_string: Option<&'static str> = Some("a string");
pub const parse_opt_string: Option<&'static str> = Some("a string");
pub const parse_list: Option<&'static str> = Some("a space-separated list of strings");
}
}
+ fn parse_all_bool(slot: &mut bool, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ match s {
+ "n" | "no" | "off" => {
+ *slot = false;
+ }
+ "y" | "yes" | "on" => {
+ *slot = true;
+ }
+ _ => { return false; }
+ }
+
+ true
+ },
+ None => { *slot = true; true }
+ }
+ }
+
fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
match v {
Some(s) => { *slot = Some(s.to_string()); true },
options! {CodegenOptions, CodegenSetter, basic_codegen_options,
build_codegen_options, "C", "codegen",
CG_OPTIONS, cg_type_desc, cgsetters,
- ar: Option<String> = (None, parse_opt_string,
+ ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
"tool to assemble archives with"),
- linker: Option<String> = (None, parse_opt_string,
+ linker: Option<String> = (None, parse_opt_string, [UNTRACKED],
"system linker to link outputs with"),
- link_args: Option<Vec<String>> = (None, parse_opt_list,
+ link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
"extra arguments to pass to the linker (space separated)"),
- link_dead_code: bool = (false, parse_bool,
+ link_dead_code: bool = (false, parse_bool, [UNTRACKED],
"don't let linker strip dead code (turning it on can be used for code coverage)"),
- lto: bool = (false, parse_bool,
+ lto: bool = (false, parse_bool, [TRACKED],
"perform LLVM link-time optimizations"),
- target_cpu: Option<String> = (None, parse_opt_string,
- "select target processor (llc -mcpu=help for details)"),
- target_feature: String = ("".to_string(), parse_string,
- "target specific attributes (llc -mattr=help for details)"),
- passes: Vec<String> = (Vec::new(), parse_list,
+ target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
+ "select target processor (rustc --print target-cpus for details)"),
+ target_feature: String = ("".to_string(), parse_string, [TRACKED],
+ "target specific attributes (rustc --print target-features for details)"),
+ passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
"a list of extra LLVM passes to run (space separated)"),
- llvm_args: Vec<String> = (Vec::new(), parse_list,
+ llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
"a list of arguments to pass to llvm (space separated)"),
- save_temps: bool = (false, parse_bool,
+ save_temps: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
+ "`-C save-temps` might not produce all requested temporary products \
+ when incremental compilation is enabled.")],
"save all temporary output files during compilation"),
- rpath: bool = (false, parse_bool,
+ rpath: bool = (false, parse_bool, [UNTRACKED],
"set rpath values in libs/exes"),
- no_prepopulate_passes: bool = (false, parse_bool,
+ no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
"don't pre-populate the pass manager with a list of passes"),
- no_vectorize_loops: bool = (false, parse_bool,
+ no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
"don't run the loop vectorization optimization passes"),
- no_vectorize_slp: bool = (false, parse_bool,
+ no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
"don't run LLVM's SLP vectorization pass"),
- soft_float: bool = (false, parse_bool,
+ soft_float: bool = (false, parse_bool, [TRACKED],
"generate software floating point library calls"),
- prefer_dynamic: bool = (false, parse_bool,
+ prefer_dynamic: bool = (false, parse_bool, [TRACKED],
"prefer dynamic linking to static linking"),
- no_integrated_as: bool = (false, parse_bool,
+ no_integrated_as: bool = (false, parse_bool, [TRACKED],
"use an external assembler rather than LLVM's integrated one"),
- no_redzone: Option<bool> = (None, parse_opt_bool,
+ no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
"disable the use of the redzone"),
- relocation_model: Option<String> = (None, parse_opt_string,
- "choose the relocation model to use (llc -relocation-model for details)"),
- code_model: Option<String> = (None, parse_opt_string,
- "choose the code model to use (llc -code-model for details)"),
- metadata: Vec<String> = (Vec::new(), parse_list,
+ relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
+ "choose the relocation model to use (rustc --print relocation-models for details)"),
+ code_model: Option<String> = (None, parse_opt_string, [TRACKED],
+ "choose the code model to use (rustc --print code-models for details)"),
+ metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
"metadata to mangle symbol names with"),
- extra_filename: String = ("".to_string(), parse_string,
+ extra_filename: String = ("".to_string(), parse_string, [UNTRACKED],
"extra data to put in each output filename"),
- codegen_units: usize = (1, parse_uint,
+ codegen_units: usize = (1, parse_uint, [UNTRACKED],
"divide crate into N units to optimize in parallel"),
- remark: Passes = (SomePasses(Vec::new()), parse_passes,
+ remark: Passes = (SomePasses(Vec::new()), parse_passes, [UNTRACKED],
"print remarks for these optimization passes (space separated, or \"all\")"),
- no_stack_check: bool = (false, parse_bool,
+ no_stack_check: bool = (false, parse_bool, [UNTRACKED],
"disable checks for stack exhaustion (a memory-safety hazard!)"),
- debuginfo: Option<usize> = (None, parse_opt_uint,
+ debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
"debug info emission level, 0 = no debug info, 1 = line tables only, \
2 = full debug info with variable and type information"),
- opt_level: Option<String> = (None, parse_opt_string,
+ opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
"optimize with possible levels 0-3, s, or z"),
- debug_assertions: Option<bool> = (None, parse_opt_bool,
+ debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
"explicitly enable the cfg(debug_assertions) directive"),
- inline_threshold: Option<usize> = (None, parse_opt_uint,
+ inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
"set the inlining threshold for"),
panic: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy,
- "panic strategy to compile crate with"),
+ [TRACKED], "panic strategy to compile crate with"),
}
-
options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
build_debugging_options, "Z", "debugging",
DB_OPTIONS, db_type_desc, dbsetters,
- verbose: bool = (false, parse_bool,
+ verbose: bool = (false, parse_bool, [UNTRACKED],
"in general, enable more debug printouts"),
- time_passes: bool = (false, parse_bool,
+ time_passes: bool = (false, parse_bool, [UNTRACKED],
"measure time of each rustc pass"),
count_llvm_insns: bool = (false, parse_bool,
+ [UNTRACKED_WITH_WARNING(true,
+ "The output generated by `-Z count_llvm_insns` might not be reliable \
+ when used with incremental compilation")],
"count where LLVM instrs originate"),
- time_llvm_passes: bool = (false, parse_bool,
+ time_llvm_passes: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
+ "The output of `-Z time-llvm-passes` will only reflect timings of \
+ re-translated modules when used with incremental compilation" )],
"measure time of each LLVM pass"),
- input_stats: bool = (false, parse_bool,
+ input_stats: bool = (false, parse_bool, [UNTRACKED],
"gather statistics about the input"),
- trans_stats: bool = (false, parse_bool,
+ trans_stats: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
+ "The output of `-Z trans-stats` might not be accurate when incremental \
+ compilation is enabled")],
"gather trans statistics"),
- asm_comments: bool = (false, parse_bool,
+ asm_comments: bool = (false, parse_bool, [TRACKED],
"generate comments into the assembly (may change behavior)"),
- no_verify: bool = (false, parse_bool,
+ no_verify: bool = (false, parse_bool, [TRACKED],
"skip LLVM verification"),
- borrowck_stats: bool = (false, parse_bool,
+ borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
"gather borrowck statistics"),
- no_landing_pads: bool = (false, parse_bool,
+ no_landing_pads: bool = (false, parse_bool, [TRACKED],
"omit landing pads for unwinding"),
- debug_llvm: bool = (false, parse_bool,
+ debug_llvm: bool = (false, parse_bool, [UNTRACKED],
"enable debug output from LLVM"),
- meta_stats: bool = (false, parse_bool,
+ meta_stats: bool = (false, parse_bool, [UNTRACKED],
"gather metadata statistics"),
- print_link_args: bool = (false, parse_bool,
+ print_link_args: bool = (false, parse_bool, [UNTRACKED],
"print the arguments passed to the linker"),
- print_llvm_passes: bool = (false, parse_bool,
+ print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
"prints the llvm optimization passes being run"),
- ast_json: bool = (false, parse_bool,
+ ast_json: bool = (false, parse_bool, [UNTRACKED],
"print the AST as JSON and halt"),
- ast_json_noexpand: bool = (false, parse_bool,
+ ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
"print the pre-expansion AST as JSON and halt"),
- ls: bool = (false, parse_bool,
+ ls: bool = (false, parse_bool, [UNTRACKED],
"list the symbols defined by a library crate"),
- save_analysis: bool = (false, parse_bool,
+ save_analysis: bool = (false, parse_bool, [UNTRACKED],
"write syntax and type analysis (in JSON format) information in addition to normal output"),
- save_analysis_csv: bool = (false, parse_bool,
+ save_analysis_csv: bool = (false, parse_bool, [UNTRACKED],
"write syntax and type analysis (in CSV format) information in addition to normal output"),
- print_move_fragments: bool = (false, parse_bool,
+ print_move_fragments: bool = (false, parse_bool, [UNTRACKED],
"print out move-fragment data for every fn"),
- flowgraph_print_loans: bool = (false, parse_bool,
+ flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED],
"include loan analysis data in --unpretty flowgraph output"),
- flowgraph_print_moves: bool = (false, parse_bool,
+ flowgraph_print_moves: bool = (false, parse_bool, [UNTRACKED],
"include move analysis data in --unpretty flowgraph output"),
- flowgraph_print_assigns: bool = (false, parse_bool,
+ flowgraph_print_assigns: bool = (false, parse_bool, [UNTRACKED],
"include assignment analysis data in --unpretty flowgraph output"),
- flowgraph_print_all: bool = (false, parse_bool,
+ flowgraph_print_all: bool = (false, parse_bool, [UNTRACKED],
"include all dataflow analysis data in --unpretty flowgraph output"),
- print_region_graph: bool = (false, parse_bool,
+ print_region_graph: bool = (false, parse_bool, [UNTRACKED],
"prints region inference graph. \
Use with RUST_REGION_GRAPH=help for more info"),
- parse_only: bool = (false, parse_bool,
+ parse_only: bool = (false, parse_bool, [UNTRACKED],
"parse only; do not compile, assemble, or link"),
- no_trans: bool = (false, parse_bool,
+ no_trans: bool = (false, parse_bool, [TRACKED],
"run all passes except translation; no output"),
- treat_err_as_bug: bool = (false, parse_bool,
+ treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
"treat all errors that occur as bugs"),
- continue_parse_after_error: bool = (false, parse_bool,
+ continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
"attempt to recover from parse errors (experimental)"),
- incremental: Option<String> = (None, parse_opt_string,
+ incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
"enable incremental compilation (experimental)"),
- dump_dep_graph: bool = (false, parse_bool,
+ incremental_info: bool = (false, parse_bool, [UNTRACKED],
+ "print high-level information about incremental reuse (or the lack thereof)"),
+ dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
- query_dep_graph: bool = (false, parse_bool,
+ query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
"enable queries of the dependency graph for regression testing"),
- no_analysis: bool = (false, parse_bool,
+ no_analysis: bool = (false, parse_bool, [UNTRACKED],
"parse and expand the source, but run no analysis"),
- extra_plugins: Vec<String> = (Vec::new(), parse_list,
+ extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
"load extra plugins"),
- unstable_options: bool = (false, parse_bool,
+ unstable_options: bool = (false, parse_bool, [UNTRACKED],
"adds unstable command line options to rustc interface"),
- print_enum_sizes: bool = (false, parse_bool,
- "print the size of enums and their variants"),
- force_overflow_checks: Option<bool> = (None, parse_opt_bool,
+ force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
"force overflow checks on or off"),
- force_dropflag_checks: Option<bool> = (None, parse_opt_bool,
+ force_dropflag_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
"force drop flag checks on or off"),
- trace_macros: bool = (false, parse_bool,
+ trace_macros: bool = (false, parse_bool, [UNTRACKED],
"for every macro invocation, print its name and arguments"),
- enable_nonzeroing_move_hints: bool = (false, parse_bool,
+ enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED],
"force nonzeroing move optimization on"),
- keep_mtwt_tables: bool = (false, parse_bool,
- "don't clear the resolution tables after analysis"),
- keep_ast: bool = (false, parse_bool,
+ keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
+ "don't clear the hygiene data after analysis"),
+ keep_ast: bool = (false, parse_bool, [UNTRACKED],
"keep the AST after lowering it to HIR"),
- show_span: Option<String> = (None, parse_opt_string,
+ show_span: Option<String> = (None, parse_opt_string, [TRACKED],
"show spans for compiler debugging (expr|pat|ty)"),
- print_trans_items: Option<String> = (None, parse_opt_string,
+ print_trans_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
"print the result of the translation item collection pass"),
- mir_opt_level: Option<usize> = (None, parse_opt_uint,
+ mir_opt_level: Option<usize> = (None, parse_opt_uint, [TRACKED],
"set the MIR optimization level (0-3)"),
- dump_mir: Option<String> = (None, parse_opt_string,
+ dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"dump MIR state at various points in translation"),
- orbit: bool = (false, parse_bool,
+ dump_mir_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
+ "the directory the MIR is dumped into"),
+ orbit: bool = (true, parse_all_bool, [UNTRACKED],
"get MIR where it belongs - everywhere; most importantly, in orbit"),
}
}
}
-pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
+pub fn build_configuration(sess: &Session,
+ mut user_cfg: ast::CrateConfig)
+ -> ast::CrateConfig {
// Combine the configuration requested by the session (command line) with
// some default and generated configuration items
let default_cfg = default_configuration(sess);
- let mut user_cfg = sess.opts.cfg.clone();
// If the user wants a test runner, then add the test cfg
if sess.opts.test {
append_configuration(&mut user_cfg, InternedString::new("test"))
let target = match Target::search(&opts.target_triple) {
Ok(t) => t,
Err(e) => {
- panic!(sp.fatal(&format!("Error loading target specification: {}", e)));
+ sp.struct_fatal(&format!("Error loading target specification: {}", e))
+ .help("Use `--print target-list` for a list of built-in targets")
+ .emit();
+ panic!(FatalError);
}
};
assumed.", "[KIND=]NAME"),
opt::multi_s("", "crate-type", "Comma separated list of types of crates
for the compiler to emit",
- "[bin|lib|rlib|dylib|staticlib]"),
+ "[bin|lib|rlib|dylib|cdylib|staticlib]"),
opt::opt_s("", "crate-name", "Specify the name of the crate being built",
"NAME"),
opt::multi_s("", "emit", "Comma separated list of types of output for \
"[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
opt::multi_s("", "print", "Comma separated list of compiler information to \
print on stdout",
- "[crate-name|file-names|sysroot|cfg|target-list]"),
+ "[crate-name|file-names|sysroot|cfg|target-list|target-cpus|\
+ target-features|relocation-models|code-models]"),
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
"NAME=PATH"),
opt::opt_s("", "sysroot", "Override the system root", "PATH"),
opt::multi_ubnr("Z", "", "Set internal debugging options", "FLAG"),
- opt::opt_ubnr("", "error-format",
+ opt::opt_s("", "error-format",
"How errors and other messages are produced",
"human|json"),
opt::opt_s("", "color", "Configure coloring of output:
}).collect::<ast::CrateConfig>()
}
-pub fn build_session_options(matches: &getopts::Matches) -> Options {
+pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
+ -> (Options, ast::CrateConfig) {
let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
Some("auto") => ColorConfig::Auto,
Some("always") => ColorConfig::Always,
})
});
- let debugging_opts = build_debugging_options(matches, error_format);
+ let mut debugging_opts = build_debugging_options(matches, error_format);
+
+ // Incremental compilation only works reliably when translation is done via
+ // MIR, so let's enable -Z orbit if necessary (see #34973).
+ if debugging_opts.incremental.is_some() && !debugging_opts.orbit {
+ early_warn(error_format, "Automatically enabling `-Z orbit` because \
+ `-Z incremental` was specified");
+ debugging_opts.orbit = true;
+ }
- let parse_only = debugging_opts.parse_only;
- let no_trans = debugging_opts.no_trans;
- let treat_err_as_bug = debugging_opts.treat_err_as_bug;
- let continue_parse_after_error = debugging_opts.continue_parse_after_error;
let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
- let no_analysis = debugging_opts.no_analysis;
- let mut output_types = HashMap::new();
+ let mut output_types = BTreeMap::new();
if !debugging_opts.parse_only {
for list in matches.opt_strs("emit") {
for output_type in list.split(',') {
early_error(error_format, "Value for codegen units must be a positive nonzero integer");
}
+ let mut prints = Vec::<PrintRequest>::new();
+ if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
+ prints.push(PrintRequest::TargetCPUs);
+ cg.target_cpu = None;
+ };
+ if cg.target_feature == "help" {
+ prints.push(PrintRequest::TargetFeatures);
+ cg.target_feature = "".to_string();
+ }
+ if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
+ prints.push(PrintRequest::RelocationModels);
+ cg.relocation_model = None;
+ }
+ if cg.code_model.as_ref().map_or(false, |s| s == "help") {
+ prints.push(PrintRequest::CodeModels);
+ cg.code_model = None;
+ }
+
let cg = cg;
let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
let test = matches.opt_present("test");
- let prints = matches.opt_strs("print").into_iter().map(|s| {
+ prints.extend(matches.opt_strs("print").into_iter().map(|s| {
match &*s {
"crate-name" => PrintRequest::CrateName,
"file-names" => PrintRequest::FileNames,
"sysroot" => PrintRequest::Sysroot,
"cfg" => PrintRequest::Cfg,
"target-list" => PrintRequest::TargetList,
+ "target-cpus" => PrintRequest::TargetCPUs,
+ "target-features" => PrintRequest::TargetFeatures,
+ "relocation-models" => PrintRequest::RelocationModels,
+ "code-models" => PrintRequest::CodeModels,
req => {
early_error(error_format, &format!("unknown print request `{}`", req))
}
}
- }).collect::<Vec<_>>();
+ }));
if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
early_warn(error_format, "-C remark will not show source locations without \
--debuginfo");
}
- let mut externs = HashMap::new();
+ let mut externs = BTreeMap::new();
for arg in &matches.opt_strs("extern") {
let mut parts = arg.splitn(2, '=');
let name = match parts.next() {
None => early_error(error_format, "--extern value must be of the format `foo=bar`"),
};
- externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
+ externs.entry(name.to_string())
+ .or_insert_with(BTreeSet::new)
+ .insert(location.to_string());
}
let crate_name = matches.opt_str("crate-name");
let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m));
- Options {
+ (Options {
crate_types: crate_types,
optimize: opt_level,
debuginfo: debuginfo,
lint_opts: lint_opts,
lint_cap: lint_cap,
describe_lints: describe_lints,
- output_types: output_types,
+ output_types: OutputTypes(output_types),
search_paths: search_paths,
maybe_sysroot: sysroot_opt,
target_triple: target,
- cfg: cfg,
test: test,
- parse_only: parse_only,
- no_trans: no_trans,
- treat_err_as_bug: treat_err_as_bug,
- continue_parse_after_error: continue_parse_after_error,
mir_opt_level: mir_opt_level,
incremental: incremental,
- no_analysis: no_analysis,
debugging_opts: debugging_opts,
prints: prints,
cg: cg,
error_format: error_format,
- externs: externs,
+ externs: Externs(externs),
crate_name: crate_name,
alt_std_name: None,
libs: libs,
unstable_features: get_unstable_features_setting(),
debug_assertions: debug_assertions,
- }
+ },
+ cfg)
}
pub fn get_unstable_features_setting() -> UnstableFeatures {
}
}
+/// Commandline arguments passed to the compiler have to be incorporated with
+/// the dependency tracking system for incremental compilation. This module
+/// provides some utilities to make this more convenient.
+///
+/// The values of all commandline arguments that are relevant for dependency
+/// tracking are hashed into a single value that determines whether the
+/// incremental compilation cache can be re-used or not. This hashing is done
+/// via the DepTrackingHash trait defined below, since the standard Hash
+/// implementation might not be suitable (e.g. arguments are stored in a Vec,
+/// the hash of which is order dependent, but we might not want the order of
+/// arguments to make a difference for the hash).
+///
+/// However, since the value provided by Hash::hash often *is* suitable,
+/// especially for primitive types, there is the
+/// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
+/// Hash implementation for DepTrackingHash. It's important though that
+/// we have an opt-in scheme here, so one is hopefully forced to think about
+/// how the hash should be calculated when adding a new commandline argument.
+mod dep_tracking {
+ use lint;
+ use middle::cstore;
+ use session::search_paths::{PathKind, SearchPaths};
+ use std::collections::BTreeMap;
+ use std::hash::{Hash, SipHasher};
+ use std::path::PathBuf;
+ use super::{Passes, PanicStrategy, CrateType, OptLevel, DebugInfoLevel,
+ OutputTypes, Externs, ErrorOutputType};
+ use syntax::feature_gate::UnstableFeatures;
+
+ pub trait DepTrackingHash {
+ fn hash(&self, &mut SipHasher, ErrorOutputType);
+ }
+
+ macro_rules! impl_dep_tracking_hash_via_hash {
+ ($t:ty) => (
+ impl DepTrackingHash for $t {
+ fn hash(&self, hasher: &mut SipHasher, _: ErrorOutputType) {
+ Hash::hash(self, hasher);
+ }
+ }
+ )
+ }
+
+ macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
+ ($t:ty) => (
+ impl DepTrackingHash for Vec<$t> {
+ fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) {
+ let mut elems: Vec<&$t> = self.iter().collect();
+ elems.sort();
+ Hash::hash(&elems.len(), hasher);
+ for (index, elem) in elems.iter().enumerate() {
+ Hash::hash(&index, hasher);
+ DepTrackingHash::hash(*elem, hasher, error_format);
+ }
+ }
+ }
+ );
+ }
+
+ impl_dep_tracking_hash_via_hash!(bool);
+ impl_dep_tracking_hash_via_hash!(usize);
+ impl_dep_tracking_hash_via_hash!(String);
+ impl_dep_tracking_hash_via_hash!(lint::Level);
+ impl_dep_tracking_hash_via_hash!(Option<bool>);
+ impl_dep_tracking_hash_via_hash!(Option<usize>);
+ impl_dep_tracking_hash_via_hash!(Option<String>);
+ impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
+ impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
+ impl_dep_tracking_hash_via_hash!(CrateType);
+ impl_dep_tracking_hash_via_hash!(PanicStrategy);
+ impl_dep_tracking_hash_via_hash!(Passes);
+ impl_dep_tracking_hash_via_hash!(OptLevel);
+ impl_dep_tracking_hash_via_hash!(DebugInfoLevel);
+ impl_dep_tracking_hash_via_hash!(UnstableFeatures);
+ impl_dep_tracking_hash_via_hash!(Externs);
+ impl_dep_tracking_hash_via_hash!(OutputTypes);
+ impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
+
+ impl_dep_tracking_hash_for_sortable_vec_of!(String);
+ impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
+ impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
+ impl_dep_tracking_hash_for_sortable_vec_of!((String, cstore::NativeLibraryKind));
+
+ impl DepTrackingHash for SearchPaths {
+ fn hash(&self, hasher: &mut SipHasher, _: ErrorOutputType) {
+ let mut elems: Vec<_> = self
+ .iter(PathKind::All)
+ .collect();
+ elems.sort();
+ Hash::hash(&elems, hasher);
+ }
+ }
+
+ impl<T1, T2> DepTrackingHash for (T1, T2)
+ where T1: DepTrackingHash,
+ T2: DepTrackingHash
+ {
+ fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) {
+ Hash::hash(&0, hasher);
+ DepTrackingHash::hash(&self.0, hasher, error_format);
+ Hash::hash(&1, hasher);
+ DepTrackingHash::hash(&self.1, hasher, error_format);
+ }
+ }
+
+ // This is a stable hash because BTreeMap is a sorted container
+ pub fn stable_hash(sub_hashes: BTreeMap<&'static str, &DepTrackingHash>,
+ hasher: &mut SipHasher,
+ error_format: ErrorOutputType) {
+ for (key, sub_hash) in sub_hashes {
+ // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
+ // the keys, as they are just plain strings
+ Hash::hash(&key.len(), hasher);
+ Hash::hash(key, hasher);
+ sub_hash.hash(hasher, error_format);
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use dep_graph::DepGraph;
- use middle::cstore::DummyCrateStore;
- use session::config::{build_configuration, build_session_options};
- use session::build_session;
use errors;
- use std::rc::Rc;
use getopts::{getopts, OptGroup};
+ use lint;
+ use middle::cstore::{self, DummyCrateStore};
+ use session::config::{build_configuration, build_session_options_and_crate_config};
+ use session::build_session;
+ use std::collections::{BTreeMap, BTreeSet};
+ use std::iter::FromIterator;
+ use std::path::PathBuf;
+ use std::rc::Rc;
+ use super::{OutputType, OutputTypes, Externs, PanicStrategy};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
.collect()
}
+ fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
+ BTreeMap::from_iter(entries.into_iter())
+ }
+
+ fn mk_set<V: Ord>(entries: Vec<V>) -> BTreeSet<V> {
+ BTreeSet::from_iter(entries.into_iter())
+ }
+
// When the user supplies --test we should implicitly supply --cfg test
#[test]
fn test_switch_implies_cfg_test() {
Err(f) => panic!("test_switch_implies_cfg_test: {}", f)
};
let registry = errors::registry::Registry::new(&[]);
- let sessopts = build_session_options(matches);
+ let (sessopts, cfg) = build_session_options_and_crate_config(matches);
let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore));
- let cfg = build_configuration(&sess);
+ let cfg = build_configuration(&sess, cfg);
assert!((attr::contains_name(&cfg[..], "test")));
}
}
};
let registry = errors::registry::Registry::new(&[]);
- let sessopts = build_session_options(matches);
+ let (sessopts, cfg) = build_session_options_and_crate_config(matches);
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
- let cfg = build_configuration(&sess);
+ let cfg = build_configuration(&sess, cfg);
let mut test_items = cfg.iter().filter(|m| m.name() == "test");
assert!(test_items.next().is_some());
assert!(test_items.next().is_none());
"-Awarnings".to_string()
], &optgroups()).unwrap();
let registry = errors::registry::Registry::new(&[]);
- let sessopts = build_session_options(&matches);
+ let (sessopts, _) = build_session_options_and_crate_config(&matches);
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
assert!(!sess.diagnostic().can_emit_warnings);
"-Dwarnings".to_string()
], &optgroups()).unwrap();
let registry = errors::registry::Registry::new(&[]);
- let sessopts = build_session_options(&matches);
+ let (sessopts, _) = build_session_options_and_crate_config(&matches);
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
assert!(sess.diagnostic().can_emit_warnings);
"-Adead_code".to_string()
], &optgroups()).unwrap();
let registry = errors::registry::Registry::new(&[]);
- let sessopts = build_session_options(&matches);
+ let (sessopts, _) = build_session_options_and_crate_config(&matches);
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
assert!(sess.diagnostic().can_emit_warnings);
}
}
+
+ #[test]
+ fn test_output_types_tracking_hash_different_paths() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+ let mut v3 = super::basic_options();
+
+ v1.output_types = OutputTypes::new(&[(OutputType::Exe,
+ Some(PathBuf::from("./some/thing")))]);
+ v2.output_types = OutputTypes::new(&[(OutputType::Exe,
+ Some(PathBuf::from("/some/thing")))]);
+ v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
+
+ assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
+ assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+ assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_output_types_tracking_hash_different_construction_order() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+
+ v1.output_types = OutputTypes::new(&[
+ (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
+ (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
+ ]);
+
+ v2.output_types = OutputTypes::new(&[
+ (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
+ (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
+ ]);
+
+ assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_externs_tracking_hash_different_values() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+ let mut v3 = super::basic_options();
+
+ v1.externs = Externs::new(mk_map(vec![
+ (String::from("a"), mk_set(vec![String::from("b"),
+ String::from("c")])),
+ (String::from("d"), mk_set(vec![String::from("e"),
+ String::from("f")])),
+ ]));
+
+ v2.externs = Externs::new(mk_map(vec![
+ (String::from("a"), mk_set(vec![String::from("b"),
+ String::from("c")])),
+ (String::from("X"), mk_set(vec![String::from("e"),
+ String::from("f")])),
+ ]));
+
+ v3.externs = Externs::new(mk_map(vec![
+ (String::from("a"), mk_set(vec![String::from("b"),
+ String::from("c")])),
+ (String::from("d"), mk_set(vec![String::from("X"),
+ String::from("f")])),
+ ]));
+
+ assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
+ assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+ assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_externs_tracking_hash_different_construction_order() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+ let mut v3 = super::basic_options();
+
+ v1.externs = Externs::new(mk_map(vec![
+ (String::from("a"), mk_set(vec![String::from("b"),
+ String::from("c")])),
+ (String::from("d"), mk_set(vec![String::from("e"),
+ String::from("f")])),
+ ]));
+
+ v2.externs = Externs::new(mk_map(vec![
+ (String::from("d"), mk_set(vec![String::from("e"),
+ String::from("f")])),
+ (String::from("a"), mk_set(vec![String::from("b"),
+ String::from("c")])),
+ ]));
+
+ v3.externs = Externs::new(mk_map(vec![
+ (String::from("a"), mk_set(vec![String::from("b"),
+ String::from("c")])),
+ (String::from("d"), mk_set(vec![String::from("f"),
+ String::from("e")])),
+ ]));
+
+ assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
+ assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+ assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_lints_tracking_hash_different_values() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+ let mut v3 = super::basic_options();
+
+ v1.lint_opts = vec![(String::from("a"), lint::Allow),
+ (String::from("b"), lint::Warn),
+ (String::from("c"), lint::Deny),
+ (String::from("d"), lint::Forbid)];
+
+ v2.lint_opts = vec![(String::from("a"), lint::Allow),
+ (String::from("b"), lint::Warn),
+ (String::from("X"), lint::Deny),
+ (String::from("d"), lint::Forbid)];
+
+ v3.lint_opts = vec![(String::from("a"), lint::Allow),
+ (String::from("b"), lint::Warn),
+ (String::from("c"), lint::Forbid),
+ (String::from("d"), lint::Deny)];
+
+ assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
+ assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+ assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_lints_tracking_hash_different_construction_order() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+
+ v1.lint_opts = vec![(String::from("a"), lint::Allow),
+ (String::from("b"), lint::Warn),
+ (String::from("c"), lint::Deny),
+ (String::from("d"), lint::Forbid)];
+
+ v2.lint_opts = vec![(String::from("a"), lint::Allow),
+ (String::from("c"), lint::Deny),
+ (String::from("b"), lint::Warn),
+ (String::from("d"), lint::Forbid)];
+
+ assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_search_paths_tracking_hash_different_values() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+ let mut v3 = super::basic_options();
+ let mut v4 = super::basic_options();
+ let mut v5 = super::basic_options();
+
+ // Reference
+ v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+
+ // Native changed
+ v2.search_paths.add_path("native=XXX", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+
+ // Crate changed
+ v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("crate=XXX", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+
+ // Dependency changed
+ v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
+ v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
+ v3.search_paths.add_path("dependency=XXX", super::ErrorOutputType::Json);
+ v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+ v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+
+ // Framework changed
+ v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
+ v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
+ v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
+ v4.search_paths.add_path("framework=XXX", super::ErrorOutputType::Json);
+ v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+
+ // All changed
+ v5.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
+ v5.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
+ v5.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
+ v5.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+ v5.search_paths.add_path("all=XXX", super::ErrorOutputType::Json);
+
+ assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() != v5.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+ assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+ assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
+ assert_eq!(v5.dep_tracking_hash(), v5.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_search_paths_tracking_hash_different_order() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+ let mut v3 = super::basic_options();
+ let mut v4 = super::basic_options();
+
+ // Reference
+ v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+
+ v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+
+ v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
+ v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+ v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
+ v3.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
+ v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+
+ v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+ v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
+ v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
+ v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
+ v4.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+
+ assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+ assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+ assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_native_libs_tracking_hash_different_values() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+ let mut v3 = super::basic_options();
+
+ // Reference
+ v1.libs = vec![(String::from("a"), cstore::NativeStatic),
+ (String::from("b"), cstore::NativeFramework),
+ (String::from("c"), cstore::NativeUnknown)];
+
+ // Change label
+ v2.libs = vec![(String::from("a"), cstore::NativeStatic),
+ (String::from("X"), cstore::NativeFramework),
+ (String::from("c"), cstore::NativeUnknown)];
+
+ // Change kind
+ v3.libs = vec![(String::from("a"), cstore::NativeStatic),
+ (String::from("b"), cstore::NativeStatic),
+ (String::from("c"), cstore::NativeUnknown)];
+
+ assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+ assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_native_libs_tracking_hash_different_order() {
+ let mut v1 = super::basic_options();
+ let mut v2 = super::basic_options();
+ let mut v3 = super::basic_options();
+
+ // Reference
+ v1.libs = vec![(String::from("a"), cstore::NativeStatic),
+ (String::from("b"), cstore::NativeFramework),
+ (String::from("c"), cstore::NativeUnknown)];
+
+ v2.libs = vec![(String::from("b"), cstore::NativeFramework),
+ (String::from("a"), cstore::NativeStatic),
+ (String::from("c"), cstore::NativeUnknown)];
+
+ v3.libs = vec![(String::from("c"), cstore::NativeUnknown),
+ (String::from("a"), cstore::NativeStatic),
+ (String::from("b"), cstore::NativeFramework)];
+
+ assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
+ assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
+ assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
+
+ // Check clone
+ assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+ assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+ assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_codegen_options_tracking_hash() {
+ let reference = super::basic_options();
+ let mut opts = super::basic_options();
+
+ // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
+ opts.cg.ar = Some(String::from("abc"));
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+ opts.cg.linker = Some(String::from("linker"));
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+ opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+ opts.cg.link_dead_code = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+ opts.cg.rpath = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+ opts.cg.extra_filename = String::from("extra-filename");
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+ opts.cg.codegen_units = 42;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+ opts.cg.remark = super::SomePasses(vec![String::from("pass1"),
+ String::from("pass2")]);
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+ opts.cg.save_temps = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+
+ // Make sure changing a [TRACKED] option changes the hash
+ opts = reference.clone();
+ opts.cg.lto = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.target_cpu = Some(String::from("abc"));
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.target_feature = String::from("all the features, all of them");
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.passes = vec![String::from("1"), String::from("2")];
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.no_prepopulate_passes = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.no_vectorize_loops = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.no_vectorize_slp = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.soft_float = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.prefer_dynamic = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.no_integrated_as = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.no_redzone = Some(true);
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.relocation_model = Some(String::from("relocation model"));
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.code_model = Some(String::from("code model"));
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.metadata = vec![String::from("A"), String::from("B")];
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.debuginfo = Some(0xdeadbeef);
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.debuginfo = Some(0xba5eba11);
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.debug_assertions = Some(true);
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.inline_threshold = Some(0xf007ba11);
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.cg.panic = PanicStrategy::Abort;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+ }
+
+ #[test]
+ fn test_debugging_options_tracking_hash() {
+ let reference = super::basic_options();
+ let mut opts = super::basic_options();
+
+ // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
+ opts.debugging_opts.verbose = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.time_passes = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.count_llvm_insns = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.time_llvm_passes = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.input_stats = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.trans_stats = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.borrowck_stats = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.debug_llvm = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.meta_stats = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.print_link_args = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.print_llvm_passes = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.ast_json = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.ast_json_noexpand = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.ls = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.save_analysis = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.save_analysis_csv = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.print_move_fragments = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.flowgraph_print_loans = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.flowgraph_print_moves = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.flowgraph_print_assigns = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.flowgraph_print_all = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.print_region_graph = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.parse_only = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.incremental = Some(String::from("abc"));
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.dump_dep_graph = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.query_dep_graph = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.no_analysis = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.unstable_options = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.trace_macros = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.keep_hygiene_data = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.keep_ast = true;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.print_trans_items = Some(String::from("abc"));
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.dump_mir = Some(String::from("abc"));
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.dump_mir_dir = Some(String::from("abc"));
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+ opts.debugging_opts.orbit = false;
+ assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+
+ // Make sure changing a [TRACKED] option changes the hash
+ opts = reference.clone();
+ opts.debugging_opts.asm_comments = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.no_verify = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.no_landing_pads = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.no_trans = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.treat_err_as_bug = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.continue_parse_after_error = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.force_overflow_checks = Some(true);
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.force_dropflag_checks = Some(true);
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.enable_nonzeroing_move_hints = true;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.show_span = Some(String::from("abc"));
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.mir_opt_level = Some(1);
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+ }
}