diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 121033549c0d5..f34b14224f779 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -269,7 +269,7 @@ impl LintId { } /// Setting for how to handle a lint. -#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug)] +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] pub enum Level { Allow, Warn, Deny, Forbid } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index f1bb3a37e3c27..dec6f360847bf 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -73,7 +73,7 @@ pub enum LinkagePreference { } enum_from_u32! { - #[derive(Copy, Clone, PartialEq)] + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum NativeLibraryKind { NativeStatic, // native static library (.a archive) NativeFramework, // OSX-specific diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 0fb4d0f8fea5e..e988ddcd97b15 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -33,9 +33,15 @@ use syntax::feature_gate::UnstableFeatures; 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 { @@ -44,7 +50,7 @@ pub struct Config { pub uint_type: UintTy, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Hash)] pub enum OptLevel { No, // -O0 Less, // -O1 @@ -54,14 +60,15 @@ pub enum OptLevel { SizeMin, // -Oz } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Hash)] pub enum DebugInfoLevel { NoDebugInfo, LimitedDebugInfo, FullDebugInfo, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, + RustcEncodable, RustcDecodable)] pub enum OutputType { Bitcode, Assembly, @@ -118,57 +125,173 @@ impl OutputType { } } -#[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, - - pub optimize: OptLevel, - pub debug_assertions: bool, - pub debuginfo: DebugInfoLevel, - pub lint_opts: Vec<(String, lint::Level)>, - pub lint_cap: Option, - pub describe_lints: bool, - pub output_types: HashMap>, - // 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, - 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, - - pub no_analysis: bool, - pub debugging_opts: DebuggingOptions, - pub prints: Vec, - pub cg: CodegenOptions, - pub externs: HashMap>, - pub crate_name: Option, - /// 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, - /// 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>); + +impl OutputTypes { + pub fn new(entries: &[(OutputType, Option)]) -> OutputTypes { + OutputTypes(BTreeMap::from_iter(entries.iter() + .map(|&(k, ref v)| (k, v.clone())))) + } + + pub fn get(&self, key: &OutputType) -> Option<&Option> { + 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> { + self.0.keys() + } + + pub fn values<'a>(&'a self) -> BTreeMapValuesIter<'a, OutputType, Option> { + 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>); + +impl Externs { + pub fn new(data: BTreeMap>) -> Externs { + Externs(data) + } + + pub fn get(&self, key: &str) -> Option<&BTreeSet> { + self.0.get(key) + } + + pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet> { + 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 [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 [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 [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 [UNTRACKED], + + debugging_opts: DebuggingOptions [TRACKED], + prints: Vec [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 [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 [TRACKED], + // Indicates how the compiler should treat unstable features + unstable_features: UnstableFeatures [TRACKED], + } +); + #[derive(Clone, PartialEq, Eq)] pub enum PrintRequest { FileNames, @@ -209,7 +332,7 @@ pub struct OutputFilenames { pub out_filestem: String, pub single_output_file: Option, pub extra: String, - pub outputs: HashMap>, + pub outputs: OutputTypes, } /// Codegen unit names generated by the numbered naming scheme will contain this @@ -301,24 +424,18 @@ pub fn basic_options() -> Options { 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(), @@ -361,7 +478,7 @@ pub enum CrateType { CrateTypeCdylib, } -#[derive(Clone)] +#[derive(Clone, Hash)] pub enum Passes { SomePasses(Vec), AllPasses, @@ -376,7 +493,7 @@ impl Passes { } } -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Hash)] pub enum PanicStrategy { Unwind, Abort, @@ -405,7 +522,12 @@ macro_rules! options { ($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),* } @@ -457,6 +579,22 @@ macro_rules! options { 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)] = @@ -622,168 +760,177 @@ macro_rules! options { options! {CodegenOptions, CodegenSetter, basic_codegen_options, build_codegen_options, "C", "codegen", CG_OPTIONS, cg_type_desc, cgsetters, - ar: Option = (None, parse_opt_string, + ar: Option = (None, parse_opt_string, [UNTRACKED], "tool to assemble archives with"), - linker: Option = (None, parse_opt_string, + linker: Option = (None, parse_opt_string, [UNTRACKED], "system linker to link outputs with"), - link_args: Option> = (None, parse_opt_list, + link_args: Option> = (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 = (None, parse_opt_string, + target_cpu: Option = (None, parse_opt_string, [TRACKED], "select target processor (rustc --print target-cpus for details)"), - target_feature: String = ("".to_string(), parse_string, + target_feature: String = ("".to_string(), parse_string, [TRACKED], "target specific attributes (rustc --print target-features for details)"), - passes: Vec = (Vec::new(), parse_list, + passes: Vec = (Vec::new(), parse_list, [TRACKED], "a list of extra LLVM passes to run (space separated)"), - llvm_args: Vec = (Vec::new(), parse_list, + llvm_args: Vec = (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 = (None, parse_opt_bool, + no_redzone: Option = (None, parse_opt_bool, [TRACKED], "disable the use of the redzone"), - relocation_model: Option = (None, parse_opt_string, + relocation_model: Option = (None, parse_opt_string, [TRACKED], "choose the relocation model to use (rustc --print relocation-models for details)"), - code_model: Option = (None, parse_opt_string, + code_model: Option = (None, parse_opt_string, [TRACKED], "choose the code model to use (rustc --print code-models for details)"), - metadata: Vec = (Vec::new(), parse_list, + metadata: Vec = (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 = (None, parse_opt_uint, + debuginfo: Option = (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 = (None, parse_opt_string, + opt_level: Option = (None, parse_opt_string, [TRACKED], "optimize with possible levels 0-3, s, or z"), - debug_assertions: Option = (None, parse_opt_bool, + debug_assertions: Option = (None, parse_opt_bool, [TRACKED], "explicitly enable the cfg(debug_assertions) directive"), - inline_threshold: Option = (None, parse_opt_uint, + inline_threshold: Option = (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 = (None, parse_opt_string, + incremental: Option = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation (experimental)"), - incremental_info: 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, + 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 = (Vec::new(), parse_list, + extra_plugins: Vec = (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"), - force_overflow_checks: Option = (None, parse_opt_bool, + force_overflow_checks: Option = (None, parse_opt_bool, [TRACKED], "force overflow checks on or off"), - force_dropflag_checks: Option = (None, parse_opt_bool, + force_dropflag_checks: Option = (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_hygiene_data: 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, + keep_ast: bool = (false, parse_bool, [UNTRACKED], "keep the AST after lowering it to HIR"), - show_span: Option = (None, parse_opt_string, + show_span: Option = (None, parse_opt_string, [TRACKED], "show spans for compiler debugging (expr|pat|ty)"), - print_trans_items: Option = (None, parse_opt_string, + print_trans_items: Option = (None, parse_opt_string, [UNTRACKED], "print the result of the translation item collection pass"), - mir_opt_level: Option = (None, parse_opt_uint, + mir_opt_level: Option = (None, parse_opt_uint, [TRACKED], "set the MIR optimization level (0-3)"), - dump_mir: Option = (None, parse_opt_string, + dump_mir: Option = (None, parse_opt_string, [UNTRACKED], "dump MIR state at various points in translation"), - dump_mir_dir: Option = (None, parse_opt_string, + dump_mir_dir: Option = (None, parse_opt_string, [UNTRACKED], "the directory the MIR is dumped into"), - orbit: bool = (true, parse_all_bool, + orbit: bool = (true, parse_all_bool, [UNTRACKED], "get MIR where it belongs - everywhere; most importantly, in orbit"), } @@ -849,11 +996,12 @@ pub fn append_configuration(cfg: &mut ast::CrateConfig, } } -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")) @@ -1115,7 +1263,8 @@ pub fn parse_cfgspecs(cfgspecs: Vec ) -> ast::CrateConfig { }).collect::() } -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, @@ -1185,14 +1334,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { 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(',') { @@ -1360,7 +1504,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { --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() { @@ -1372,44 +1516,41 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { 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 { @@ -1530,15 +1671,139 @@ impl fmt::Display for CrateType { } } +/// 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); + impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); + 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 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; @@ -1548,6 +1813,14 @@ mod tests { .collect() } + fn mk_map(entries: Vec<(K, V)>) -> BTreeMap { + BTreeMap::from_iter(entries.into_iter()) + } + + fn mk_set(entries: Vec) -> BTreeSet { + BTreeSet::from_iter(entries.into_iter()) + } + // When the user supplies --test we should implicitly supply --cfg test #[test] fn test_switch_implies_cfg_test() { @@ -1558,9 +1831,9 @@ mod tests { 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"))); } @@ -1578,10 +1851,10 @@ mod tests { } }; 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()); @@ -1595,7 +1868,7 @@ mod tests { "-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); @@ -1607,7 +1880,7 @@ mod tests { "-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); @@ -1618,10 +1891,589 @@ mod tests { "-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()); + } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 9ab75c8a5a20c..c71253aee568f 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -363,7 +363,7 @@ pub fn build_session_with_codemap(sopts: config::Options, .map(|&(_, ref level)| *level != lint::Allow) .last() .unwrap_or(true); - let treat_err_as_bug = sopts.treat_err_as_bug; + let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug; let emitter: Box = match sopts.error_format { config::ErrorOutputType::HumanReadable(color_config) => { diff --git a/src/librustc/session/search_paths.rs b/src/librustc/session/search_paths.rs index 3c6cd26bef6ce..5bbc6841693ea 100644 --- a/src/librustc/session/search_paths.rs +++ b/src/librustc/session/search_paths.rs @@ -22,7 +22,7 @@ pub struct Iter<'a> { iter: slice::Iter<'a, (PathKind, PathBuf)>, } -#[derive(Eq, PartialEq, Clone, Copy, Debug)] +#[derive(Eq, PartialEq, Clone, Copy, Debug, PartialOrd, Ord, Hash)] pub enum PathKind { Native, Crate, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 70b1261730b07..c6100004786be 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -15,7 +15,8 @@ use rustc::hir::lowering::lower_crate; use rustc_mir as mir; use rustc::mir::mir_map::MirMap; use rustc::session::{Session, CompileResult, compile_result_from_err_count}; -use rustc::session::config::{self, Input, OutputFilenames, OutputType}; +use rustc::session::config::{self, Input, OutputFilenames, OutputType, + OutputTypes}; use rustc::session::search_paths::PathKind; use rustc::lint; use rustc::middle::{self, dependency_format, stability, reachable}; @@ -42,7 +43,6 @@ use super::Compilation; use serialize::json; -use std::collections::HashMap; use std::env; use std::ffi::{OsString, OsStr}; use std::fs; @@ -478,7 +478,7 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session, cfg: ast::CrateConfig, input: &Input) -> PResult<'a, ast::Crate> { - let continue_after_error = sess.opts.continue_parse_after_error; + let continue_after_error = sess.opts.debugging_opts.continue_parse_after_error; sess.diagnostic().set_continue_after_error(continue_after_error); let krate = time(sess.time_passes(), "parsing", || { @@ -667,7 +667,10 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, }; - let mut loader = macro_import::MacroLoader::new(sess, &cstore, crate_name); + let mut loader = macro_import::MacroLoader::new(sess, + &cstore, + crate_name, + krate.config.clone()); let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, @@ -1024,11 +1027,10 @@ pub fn phase_5_run_llvm_passes(sess: &Session, trans: &trans::CrateTranslation, outputs: &OutputFilenames) -> CompileResult { if sess.opts.cg.no_integrated_as { - let mut map = HashMap::new(); - map.insert(OutputType::Assembly, None); + let output_types = OutputTypes::new(&[(OutputType::Assembly, None)]); time(sess.time_passes(), "LLVM passes", - || write::run_passes(sess, trans, &map, outputs)); + || write::run_passes(sess, trans, &output_types, outputs)); write::run_assembler(sess, outputs); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 98860c8f900eb..6f57ae2941838 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -181,7 +181,7 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], None => return (Ok(()), None), }; - let sopts = config::build_session_options(&matches); + let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); if sopts.debugging_opts.debug_llvm { unsafe { llvm::LLVMRustSetDebug(1); } @@ -191,6 +191,7 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], do_or_return!(callbacks.early_callback(&matches, &sopts, + &cfg, &descriptions, sopts.error_format), None); @@ -198,7 +199,7 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], let (odir, ofile) = make_output(&matches); let (input, input_file_path) = match make_input(&matches.free) { Some((input, input_file_path)) => callbacks.some_input(input, input_file_path), - None => match callbacks.no_input(&matches, &sopts, &odir, &ofile, &descriptions) { + None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) { Some((input, input_file_path)) => (input, input_file_path), None => return (Ok(()), None), }, @@ -214,10 +215,11 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], cstore.clone(), codemap); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let mut cfg = config::build_configuration(&sess); + let mut cfg = config::build_configuration(&sess, cfg); target_features::add_configuration(&mut cfg, &sess); - do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile), Some(sess)); + do_or_return!(callbacks.late_callback(&matches, &sess, &cfg, &input, &odir, &ofile), + Some(sess)); let plugins = sess.opts.debugging_opts.extra_plugins.clone(); let control = callbacks.build_controller(&sess, &matches); @@ -297,6 +299,7 @@ pub trait CompilerCalls<'a> { fn early_callback(&mut self, _: &getopts::Matches, _: &config::Options, + _: &ast::CrateConfig, _: &errors::registry::Registry, _: ErrorOutputType) -> Compilation { @@ -309,6 +312,7 @@ pub trait CompilerCalls<'a> { fn late_callback(&mut self, _: &getopts::Matches, _: &Session, + _: &ast::CrateConfig, _: &Input, _: &Option, _: &Option) @@ -334,6 +338,7 @@ pub trait CompilerCalls<'a> { fn no_input(&mut self, _: &getopts::Matches, _: &config::Options, + _: &ast::CrateConfig, _: &Option, _: &Option, _: &errors::registry::Registry) @@ -375,7 +380,7 @@ fn handle_explain(code: &str, } } -fn check_cfg(sopts: &config::Options, +fn check_cfg(cfg: &ast::CrateConfig, output: ErrorOutputType) { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(color_config) => { @@ -386,7 +391,7 @@ fn check_cfg(sopts: &config::Options, let handler = errors::Handler::with_emitter(true, false, emitter); let mut saw_invalid_predicate = false; - for item in sopts.cfg.iter() { + for item in cfg.iter() { if item.is_meta_item_list() { saw_invalid_predicate = true; handler.emit(&MultiSpan::new(), @@ -404,7 +409,8 @@ fn check_cfg(sopts: &config::Options, impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn early_callback(&mut self, matches: &getopts::Matches, - sopts: &config::Options, + _: &config::Options, + cfg: &ast::CrateConfig, descriptions: &errors::registry::Registry, output: ErrorOutputType) -> Compilation { @@ -413,13 +419,14 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { return Compilation::Stop; } - check_cfg(sopts, output); + check_cfg(cfg, output); Compilation::Continue } fn no_input(&mut self, matches: &getopts::Matches, sopts: &config::Options, + cfg: &ast::CrateConfig, odir: &Option, ofile: &Option, descriptions: &errors::registry::Registry) @@ -440,7 +447,13 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { descriptions.clone(), cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let should_stop = RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile); + let mut cfg = config::build_configuration(&sess, cfg.clone()); + target_features::add_configuration(&mut cfg, &sess); + let should_stop = RustcDefaultCalls::print_crate_info(&sess, + &cfg, + None, + odir, + ofile); if should_stop == Compilation::Stop { return None; } @@ -456,11 +469,12 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn late_callback(&mut self, matches: &getopts::Matches, sess: &Session, + cfg: &ast::CrateConfig, input: &Input, odir: &Option, ofile: &Option) -> Compilation { - RustcDefaultCalls::print_crate_info(sess, Some(input), odir, ofile) + RustcDefaultCalls::print_crate_info(sess, cfg, Some(input), odir, ofile) .and_then(|| RustcDefaultCalls::list_metadata(sess, matches, input)) } @@ -506,12 +520,14 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { return control; } - if sess.opts.parse_only || sess.opts.debugging_opts.show_span.is_some() || + if sess.opts.debugging_opts.parse_only || + sess.opts.debugging_opts.show_span.is_some() || sess.opts.debugging_opts.ast_json_noexpand { control.after_parse.stop = Compilation::Stop; } - if sess.opts.no_analysis || sess.opts.debugging_opts.ast_json { + if sess.opts.debugging_opts.no_analysis || + sess.opts.debugging_opts.ast_json { control.after_hir_lowering.stop = Compilation::Stop; } @@ -577,6 +593,7 @@ impl RustcDefaultCalls { fn print_crate_info(sess: &Session, + cfg: &ast::CrateConfig, input: Option<&Input>, odir: &Option, ofile: &Option) @@ -629,9 +646,6 @@ impl RustcDefaultCalls { } } PrintRequest::Cfg => { - let mut cfg = config::build_configuration(&sess); - target_features::add_configuration(&mut cfg, &sess); - let allow_unstable_cfg = match get_unstable_features_setting() { UnstableFeatures::Disallow => false, _ => true, diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs index 084b6714b67b9..89a79d1a487e0 100644 --- a/src/librustc_incremental/persist/directory.rs +++ b/src/librustc_incremental/persist/directory.rs @@ -158,6 +158,10 @@ impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> { } } + pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + pub fn add(&mut self, def_id: DefId) -> DefPathIndex { debug!("DefIdDirectoryBuilder: def_id={:?}", def_id); let tcx = self.tcx; diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 79b90b63dc608..c736437df1a9e 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -101,8 +101,25 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, work_products_data: &[u8]) -> Result<(), Error> { + // Decode the list of work_products + let mut work_product_decoder = Decoder::new(work_products_data, 0); + let work_products = try!(>::decode(&mut work_product_decoder)); + // Deserialize the directory and dep-graph. let mut dep_graph_decoder = Decoder::new(dep_graph_data, 0); + let prev_commandline_args_hash = try!(u64::decode(&mut dep_graph_decoder)); + + if prev_commandline_args_hash != tcx.sess.opts.dep_tracking_hash() { + // We can't reuse the cache, purge it. + debug!("decode_dep_graph: differing commandline arg hashes"); + for swp in work_products { + delete_dirty_work_product(tcx, swp); + } + + // No need to do any further work + return Ok(()); + } + let directory = try!(DefIdDirectory::decode(&mut dep_graph_decoder)); let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut dep_graph_decoder)); @@ -179,8 +196,6 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Add in work-products that are still clean, and delete those that are // dirty. - let mut work_product_decoder = Decoder::new(work_products_data, 0); - let work_products = try!(>::decode(&mut work_product_decoder)); reconcile_work_products(tcx, work_products, &dirty_target_nodes); dirty_clean::check_dirty_clean_annotations(tcx, &dirty_raw_source_nodes, &retraced); diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index f296cd3172fb0..a9523a81fbaf7 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -105,6 +105,10 @@ pub fn encode_dep_graph(preds: &Predecessors, builder: &mut DefIdDirectoryBuilder, encoder: &mut Encoder) -> io::Result<()> { + // First encode the commandline arguments hash + let tcx = builder.tcx(); + try!(tcx.sess.opts.dep_tracking_hash().encode(encoder)); + // Create a flat list of (Input, WorkProduct) edges for // serialization. let mut edges = vec![]; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 0b60fc386a7bb..4a656b180f259 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -56,6 +56,7 @@ pub struct CrateReader<'a> { next_crate_num: ast::CrateNum, foreign_item_map: FnvHashMap>, local_crate_name: String, + local_crate_config: ast::CrateConfig, } impl<'a> visit::Visitor for LocalCrateReader<'a> { @@ -152,13 +153,16 @@ enum LoadResult { impl<'a> CrateReader<'a> { pub fn new(sess: &'a Session, cstore: &'a CStore, - local_crate_name: &str) -> CrateReader<'a> { + local_crate_name: &str, + local_crate_config: ast::CrateConfig) + -> CrateReader<'a> { CrateReader { sess: sess, cstore: cstore, next_crate_num: cstore.next_crate_num(), foreign_item_map: FnvHashMap(), local_crate_name: local_crate_name.to_owned(), + local_crate_config: local_crate_config, } } @@ -561,7 +565,7 @@ impl<'a> CrateReader<'a> { // NB: Don't use parse::parse_tts_from_source_str because it parses with // quote_depth > 0. let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, - self.sess.opts.cfg.clone(), + self.local_crate_config.clone(), source_name.clone(), body); let lo = p.span.lo; @@ -863,7 +867,7 @@ impl<'a> LocalCrateReader<'a> { LocalCrateReader { sess: sess, cstore: cstore, - creader: CrateReader::new(sess, cstore, local_crate_name), + creader: CrateReader::new(sess, cstore, local_crate_name, krate.config.clone()), krate: krate, definitions: defs, } diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index cf1dd71a0a12a..2345cd9a92aea 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -400,7 +400,7 @@ impl<'a> Context<'a> { if self.hash.is_none() { self.should_match_name = false; if let Some(s) = self.sess.opts.externs.get(self.crate_name) { - return self.find_commandline_library(s); + return self.find_commandline_library(s.iter()); } self.should_match_name = true; } @@ -661,7 +661,9 @@ impl<'a> Context<'a> { (t.options.staticlib_prefix.clone(), t.options.staticlib_suffix.clone()) } - fn find_commandline_library(&mut self, locs: &[String]) -> Option { + fn find_commandline_library<'b, LOCS> (&mut self, locs: LOCS) -> Option + where LOCS: Iterator + { // First, filter out all libraries that look suspicious. We only accept // files which actually exist that have the correct naming scheme for // rlibs/dylibs. @@ -670,7 +672,7 @@ impl<'a> Context<'a> { let mut rlibs = HashMap::new(); let mut dylibs = HashMap::new(); { - let locs = locs.iter().map(|l| PathBuf::from(l)).filter(|loc| { + let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| { if !loc.exists() { sess.err(&format!("extern location for {} does not exist: {}", self.crate_name, loc.display())); diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 4be044c1df307..b2a2dcf90fa4b 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -29,10 +29,14 @@ pub struct MacroLoader<'a> { } impl<'a> MacroLoader<'a> { - pub fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> { + pub fn new(sess: &'a Session, + cstore: &'a CStore, + crate_name: &str, + crate_config: ast::CrateConfig) + -> MacroLoader<'a> { MacroLoader { sess: sess, - reader: CrateReader::new(sess, cstore, crate_name), + reader: CrateReader::new(sess, cstore, crate_name, crate_config), } } } diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index a3cd9b5da02bc..fb68eae96476f 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -49,7 +49,7 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate, crate_name: &str, addl_plugins: Option>) -> Vec { - let mut loader = PluginLoader::new(sess, cstore, crate_name); + let mut loader = PluginLoader::new(sess, cstore, crate_name, krate.config.clone()); // do not report any error now. since crate attributes are // not touched by expansion, every use of plugin without @@ -90,10 +90,14 @@ pub fn load_plugins(sess: &Session, } impl<'a> PluginLoader<'a> { - fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> PluginLoader<'a> { + fn new(sess: &'a Session, + cstore: &'a CStore, + crate_name: &str, + crate_config: ast::CrateConfig) + -> PluginLoader<'a> { PluginLoader { sess: sess, - reader: CrateReader::new(sess, cstore, crate_name), + reader: CrateReader::new(sess, cstore, crate_name, crate_config), plugins: vec![], } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index a9f3d2f8a1754..f17d1a7f1cf31 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -190,7 +190,8 @@ pub fn link_binary(sess: &Session, let mut out_filenames = Vec::new(); for &crate_type in sess.crate_types.borrow().iter() { // Ignore executable crates if we have -Z no-trans, as they will error. - if sess.opts.no_trans && crate_type == config::CrateTypeExecutable { + if sess.opts.debugging_opts.no_trans && + crate_type == config::CrateTypeExecutable { continue; } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index b5c993b86ecb2..4b9c29d3d7db3 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -11,7 +11,7 @@ use back::lto; use back::link::{get_linker, remove}; use rustc_incremental::save_trans_partition; -use session::config::{OutputFilenames, Passes, SomePasses, AllPasses}; +use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses}; use session::Session; use session::config::{self, OutputType}; use llvm; @@ -26,7 +26,6 @@ use errors::emitter::Emitter; use syntax_pos::MultiSpan; use context::{is_pie_binary, get_reloc_model}; -use std::collections::HashMap; use std::ffi::{CStr, CString}; use std::fs; use std::path::{Path, PathBuf}; @@ -641,7 +640,7 @@ pub fn cleanup_llvm(trans: &CrateTranslation) { pub fn run_passes(sess: &Session, trans: &CrateTranslation, - output_types: &HashMap>, + output_types: &OutputTypes, crate_output: &OutputFilenames) { // It's possible that we have `codegen_units > 1` but only one item in // `trans.modules`. We could theoretically proceed and do LTO in that diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index df893842337c4..30618ff372735 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2576,7 +2576,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert_module_sources::assert_module_sources(tcx, &modules); // Skip crate items and just output metadata in -Z no-trans mode. - if tcx.sess.opts.no_trans { + if tcx.sess.opts.debugging_opts.no_trans { let linker_info = LinkerInfo::new(&shared_ccx, &[]); return CrateTranslation { modules: modules, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7d8ebc403b08f..10736d2c827cd 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -45,7 +45,6 @@ pub enum MaybeTyped<'a, 'tcx: 'a> { NotTyped(&'a session::Session) } -pub type Externs = HashMap>; pub type ExternalPaths = HashMap, clean::TypeKind)>; pub struct DocContext<'a, 'tcx: 'a> { @@ -99,7 +98,7 @@ impl DocAccessLevels for AccessLevels { pub fn run_core(search_paths: SearchPaths, cfgs: Vec, - externs: Externs, + externs: config::Externs, input: Input, triple: Option) -> (clean::Crate, RenderInfo) { @@ -120,7 +119,6 @@ pub fn run_core(search_paths: SearchPaths, lint_cap: Some(lint::Allow), externs: externs, target_triple: triple.unwrap_or(config::host_triple().to_string()), - cfg: config::parse_cfgspecs(cfgs), // Ensure that rustdoc works even if rustc is feature-staged unstable_features: UnstableFeatures::Allow, ..config::basic_options().clone() @@ -139,7 +137,7 @@ pub fn run_core(search_paths: SearchPaths, codemap, cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let mut cfg = config::build_configuration(&sess); + let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs)); target_features::add_configuration(&mut cfg, &sess); let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d0c4f126550ca..255e6b1e786df 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -51,7 +51,7 @@ extern crate rustc_errors as errors; extern crate serialize as rustc_serialize; // used by deriving -use std::collections::HashMap; +use std::collections::{BTreeMap, BTreeSet}; use std::default::Default; use std::env; use std::path::PathBuf; @@ -60,7 +60,8 @@ use std::sync::mpsc::channel; use externalfiles::ExternalHtml; use rustc::session::search_paths::SearchPaths; -use rustc::session::config::{ErrorOutputType, RustcOptGroup, nightly_options}; +use rustc::session::config::{ErrorOutputType, RustcOptGroup, nightly_options, + Externs}; #[macro_use] pub mod externalfiles; @@ -323,7 +324,7 @@ pub fn main_args(args: &[String]) -> isize { /// Looks inside the command line arguments to extract the relevant input format /// and files and then generates the necessary rustdoc output for formatting. fn acquire_input(input: &str, - externs: core::Externs, + externs: Externs, matches: &getopts::Matches) -> Result { match matches.opt_str("r").as_ref().map(|s| &**s) { Some("rust") => Ok(rust_input(input, externs, matches)), @@ -335,10 +336,10 @@ fn acquire_input(input: &str, } /// Extracts `--extern CRATE=PATH` arguments from `matches` and -/// returns a `HashMap` mapping crate names to their paths or else an +/// returns a map mapping crate names to their paths or else an /// error message. -fn parse_externs(matches: &getopts::Matches) -> Result { - let mut externs = HashMap::new(); +fn parse_externs(matches: &getopts::Matches) -> Result { + let mut externs = BTreeMap::new(); for arg in &matches.opt_strs("extern") { let mut parts = arg.splitn(2, '='); let name = parts.next().ok_or("--extern value must not be empty".to_string())?; @@ -346,9 +347,9 @@ fn parse_externs(matches: &getopts::Matches) -> Result { .ok_or("--extern value must be of the format `foo=bar`" .to_string())?; let name = name.to_string(); - externs.entry(name).or_insert(vec![]).push(location.to_string()); + externs.entry(name).or_insert_with(BTreeSet::new).insert(location.to_string()); } - Ok(externs) + Ok(Externs::new(externs)) } /// Interprets the input file as a rust source file, passing it through the @@ -356,7 +357,7 @@ fn parse_externs(matches: &getopts::Matches) -> Result { /// generated from the cleaned AST of the crate. /// /// This form of input will run all of the plug/cleaning passes -fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matches) -> Output { +fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) -> Output { let mut default_passes = !matches.opt_present("no-defaults"); let mut passes = matches.opt_strs("passes"); let mut plugins = matches.opt_strs("plugins"); diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index d21726dd40f08..1421a3c78fc5a 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -14,10 +14,10 @@ use std::io::prelude::*; use std::io; use std::path::{PathBuf, Path}; -use core; use getopts; use testing; use rustc::session::search_paths::SearchPaths; +use rustc::session::config::Externs; use externalfiles::ExternalHtml; @@ -142,7 +142,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, } /// Run any tests/code examples in the markdown file `input`. -pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: core::Externs, +pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, mut test_args: Vec) -> isize { let input_str = load_or_return!(input, 1, 2); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 5f1d28c8d316a..7d1dbbe5dc07d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -26,7 +26,8 @@ use rustc_lint; use rustc::dep_graph::DepGraph; use rustc::hir::map as hir_map; use rustc::session::{self, config}; -use rustc::session::config::{get_unstable_features_setting, OutputType}; +use rustc::session::config::{get_unstable_features_setting, OutputType, + OutputTypes, Externs}; use rustc::session::search_paths::{SearchPaths, PathKind}; use rustc_back::dynamic_lib::DynamicLibrary; use rustc_back::tempdir::TempDir; @@ -55,7 +56,7 @@ pub struct TestOptions { pub fn run(input: &str, cfgs: Vec, libs: SearchPaths, - externs: core::Externs, + externs: Externs, mut test_args: Vec, crate_name: Option) -> isize { @@ -89,8 +90,7 @@ pub fn run(input: &str, cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let mut cfg = config::build_configuration(&sess); - cfg.extend(config::parse_cfgspecs(cfgs.clone())); + let cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); let driver::ExpansionResult { defs, mut hir_forest, .. } = { phase_2_configure_and_expand( @@ -172,7 +172,7 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { } fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, - externs: core::Externs, + externs: Externs, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions) { // the test harness wants its own `main` & top level functions, so @@ -182,8 +182,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, name: driver::anon_src(), input: test.to_owned(), }; - let mut outputs = HashMap::new(); - outputs.insert(OutputType::Exe, None); + let outputs = OutputTypes::new(&[(OutputType::Exe, None)]); let sessopts = config::Options { maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap() @@ -247,8 +246,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir")); let libdir = sess.target_filesearch(PathKind::All).get_lib_path(); let mut control = driver::CompileController::basic(); - let mut cfg = config::build_configuration(&sess); - cfg.extend(config::parse_cfgspecs(cfgs.clone())); + let cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); let out = Some(outdir.lock().unwrap().path().to_path_buf()); if no_run { @@ -396,7 +394,7 @@ pub struct Collector { names: Vec, cfgs: Vec, libs: SearchPaths, - externs: core::Externs, + externs: Externs, cnt: usize, use_headers: bool, current_header: Option, @@ -405,7 +403,7 @@ pub struct Collector { } impl Collector { - pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: core::Externs, + pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions) -> Collector { Collector { tests: Vec::new(), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index afda59c61ff76..a6f0e0ca31e3e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1194,7 +1194,7 @@ pub fn check_crate(krate: &ast::Crate, visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate); } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum UnstableFeatures { /// Hard errors for unstable features are active, as on /// beta/stable channels. diff --git a/src/test/incremental/commandline-args.rs b/src/test/incremental/commandline-args.rs new file mode 100644 index 0000000000000..95187b825be9f --- /dev/null +++ b/src/test/incremental/commandline-args.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that changing a tracked commandline argument invalidates +// the cache while changing an untracked one doesn't. + +// revisions:rpass1 rpass2 rpass3 + +#![feature(rustc_attrs)] + +#![rustc_partition_translated(module="commandline_args", cfg="rpass2")] +#![rustc_partition_reused(module="commandline_args", cfg="rpass3")] + +// Between revisions 1 and 2, we are changing the debuginfo-level, which should +// invalidate the cache. Between revisions 2 and 3, we are adding `--verbose` +// which should have no effect on the cache: +//[rpass1] compile-flags: -C debuginfo=0 +//[rpass2] compile-flags: -C debuginfo=2 +//[rpass3] compile-flags: -C debuginfo=2 --verbose + +pub fn main() { + // empty +} diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index d5220316a20ff..35043bdaddf21 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -19,7 +19,8 @@ extern crate syntax; use rustc::dep_graph::DepGraph; use rustc::session::{build_session, Session}; -use rustc::session::config::{basic_options, build_configuration, Input, OutputType}; +use rustc::session::config::{basic_options, build_configuration, Input, + OutputType, OutputTypes}; use rustc_driver::driver::{compile_input, CompileController, anon_src}; use rustc_metadata::cstore::CStore; use rustc_errors::registry::Registry; @@ -51,7 +52,7 @@ fn main() { fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { let mut opts = basic_options(); - opts.output_types.insert(OutputType::Exe, None); + opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); opts.maybe_sysroot = Some(sysroot); let descriptions = Registry::new(&rustc::DIAGNOSTICS); @@ -64,7 +65,7 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { fn compile(code: String, output: PathBuf, sysroot: PathBuf) { let (sess, cstore) = basic_sess(sysroot); - let cfg = build_configuration(&sess); + let cfg = build_configuration(&sess, vec![]); let control = CompileController::basic(); compile_input(&sess, &cstore, diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs index ff57e9d6b7368..775ba38004e3a 100644 --- a/src/test/run-pass-fulldeps/compiler-calls.rs +++ b/src/test/run-pass-fulldeps/compiler-calls.rs @@ -24,6 +24,7 @@ extern crate rustc_errors as errors; use rustc::session::Session; use rustc::session::config::{self, Input}; use rustc_driver::{driver, CompilerCalls, Compilation}; +use syntax::ast; use std::path::PathBuf; @@ -35,6 +36,7 @@ impl<'a> CompilerCalls<'a> for TestCalls { fn early_callback(&mut self, _: &getopts::Matches, _: &config::Options, + _: &ast::CrateConfig, _: &errors::registry::Registry, _: config::ErrorOutputType) -> Compilation { @@ -45,6 +47,7 @@ impl<'a> CompilerCalls<'a> for TestCalls { fn late_callback(&mut self, _: &getopts::Matches, _: &Session, + _: &ast::CrateConfig, _: &Input, _: &Option, _: &Option) @@ -62,6 +65,7 @@ impl<'a> CompilerCalls<'a> for TestCalls { fn no_input(&mut self, _: &getopts::Matches, _: &config::Options, + _: &ast::CrateConfig, _: &Option, _: &Option, _: &errors::registry::Registry) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e9ccc029bc3cf..0d081b267bb70 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2008,6 +2008,7 @@ actual:\n\ // Add an extra flag pointing at the incremental directory. let mut revision_props = self.props.clone(); revision_props.incremental_dir = Some(incremental_dir); + revision_props.compile_flags.push(String::from("-Zincremental-info")); let revision_cx = TestCx { config: self.config,