From 32414310b7e0b93491ce6243e1ec0c92c6168557 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 2 Aug 2016 16:53:58 -0400 Subject: [PATCH 1/6] Add the notion of a dependency tracking status to commandline arguments. Commandline arguments influence whether incremental compilation can use its compilation cache and thus their changes relative to previous compilation sessions need to be taking into account. This commit makes sure that one has to specify for every commandline argument whether it influences incremental compilation or not. --- src/librustc/lint/mod.rs | 2 +- src/librustc/middle/cstore.rs | 2 +- src/librustc/session/config.rs | 1364 +++++++++++++++++++++++--- src/librustc/session/mod.rs | 2 +- src/librustc/session/search_paths.rs | 2 +- src/librustc_driver/driver.rs | 11 +- src/librustc_driver/lib.rs | 6 +- src/librustc_metadata/loader.rs | 8 +- src/librustc_trans/back/link.rs | 3 +- src/librustc_trans/back/write.rs | 5 +- src/librustc_trans/base.rs | 2 +- src/librustdoc/core.rs | 3 +- src/librustdoc/lib.rs | 19 +- src/librustdoc/markdown.rs | 4 +- src/librustdoc/test.rs | 14 +- src/libsyntax/feature_gate.rs | 2 +- src/test/run-make/issue-19371/foo.rs | 5 +- 17 files changed, 1252 insertions(+), 202 deletions(-) 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..e337c1232aab8 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,183 @@ 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): I'm not entirely sure if this can have any influence on + // incremental compilation apart from what is already handled + // by crate metadata hashes. Better track it. + search_paths: SearchPaths [TRACKED], + // FIXME(mw): Might not need to do dep-tracking for `libs`? + libs: Vec<(String, cstore::NativeLibraryKind)> [TRACKED], + // FIXME(mw): Might not need to do dep-tracking for `maybe_sysroot`? + maybe_sysroot: Option [TRACKED], + + target_triple: String [TRACKED], + + // 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. + // FIXME(mw): If we could be entirely sure that the `cfg` only ever + // influenced which HIR nodes get filtered out, we wouldn't + // need to track this separately. However, we can't rely on + // this (see `debug_assertions` above). + cfg: ast::CrateConfig [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): `externs` might not need to be tracked but let's err on + // the side of caution for now. + 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 +342,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 +434,19 @@ 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 +489,7 @@ pub enum CrateType { CrateTypeCdylib, } -#[derive(Clone)] +#[derive(Clone, Hash)] pub enum Passes { SomePasses(Vec), AllPasses, @@ -376,7 +504,7 @@ impl Passes { } } -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Hash)] pub enum PanicStrategy { Unwind, Abort, @@ -405,7 +533,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 +590,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 +771,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"), } @@ -1185,14 +1343,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 +1513,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,7 +1525,9 @@ 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"); @@ -1386,24 +1541,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { 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, @@ -1530,17 +1680,205 @@ 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::ast; + use syntax::feature_gate::UnstableFeatures; + use syntax::parse::token::InternedString; + use syntax::ptr::P; + + 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 = self.clone(); + elems.sort(); + for (i, e) in elems.iter().enumerate() { + Hash::hash(&i, hasher); + DepTrackingHash::hash(e, 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); + } + } + + fn sorted_meta_items(items: &[P]) -> Vec<&ast::MetaItem> { + // Sort subitems so the hash does not depend on their order + let mut items: Vec<&ast::MetaItem> = items.iter() + .map(|r| &**r) + .collect(); + items.sort_by_key(meta_item_sort_key); + return items; + + fn meta_item_sort_key(item: &&ast::MetaItem) -> InternedString { + match item.node { + ast::MetaItemKind::Word(ref s) | + ast::MetaItemKind::NameValue(ref s, _) | + ast::MetaItemKind::List(ref s, _) => s.clone() + } + } + } + + impl DepTrackingHash for ast::MetaItem { + fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) { + // ignoring span information, it doesn't matter here + match self.node { + ast::MetaItemKind::Word(ref s) => { + Hash::hash("Word", hasher); + Hash::hash(&s.len(), hasher); + Hash::hash(s, hasher); + } + ast::MetaItemKind::NameValue(ref s, ref lit) => { + Hash::hash("NameValue", hasher); + Hash::hash(&s.len(), hasher); + Hash::hash(s, hasher); + Hash::hash(&lit.node, hasher); + } + ast::MetaItemKind::List(ref s, ref items) => { + Hash::hash("List", hasher); + Hash::hash(&s.len(), hasher); + Hash::hash(s, hasher); + // Sort subitems so the hash does not depend on their order + let sorted = sorted_meta_items(&items[..]); + for (index, item) in sorted.iter().enumerate() { + Hash::hash(&index, hasher); + DepTrackingHash::hash(*item, hasher, error_format); + } + } + } + } + } + + impl DepTrackingHash for ast::CrateConfig { + fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) { + // Sort subitems so the hash does not depend on their order + let sorted = sorted_meta_items(&self[..]); + for (index, item) in sorted.iter().enumerate() { + Hash::hash(&index, hasher); + DepTrackingHash::hash(*item, hasher, error_format); + } + } + } + + 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 errors; + use getopts::{getopts, OptGroup}; + use lint; + use middle::cstore::{self, DummyCrateStore}; use session::config::{build_configuration, build_session_options}; use session::build_session; - use errors; + use std::collections::{BTreeMap, BTreeSet}; + use std::iter::FromIterator; + use std::path::PathBuf; use std::rc::Rc; - use getopts::{getopts, OptGroup}; + use super::{OutputType, OutputTypes, Externs, PanicStrategy}; + use syntax::ast::{self, MetaItemKind}; use syntax::attr; use syntax::attr::AttrMetaMethods; + use syntax::codemap::dummy_spanned; + use syntax::parse::token::InternedString; + use syntax::ptr::P; fn optgroups() -> Vec { super::rustc_optgroups().into_iter() @@ -1548,6 +1886,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() { @@ -1624,4 +1970,704 @@ mod tests { 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_crate_config_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(); + + // Reference value + v1.cfg = vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), + P(dummy_spanned(MetaItemKind::List(InternedString::new("b"), + vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), + dummy_spanned(ast::LitKind::Byte(1))))), + ]))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), + dummy_spanned(ast::LitKind::Byte(2))))), + ]; + + // Change a label + v2.cfg = vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), + P(dummy_spanned(MetaItemKind::List(InternedString::new("X"), + vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), + dummy_spanned(ast::LitKind::Byte(1))))), + ]))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), + dummy_spanned(ast::LitKind::Byte(2))))), + ]; + + // Change a literal + v3.cfg = vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), + P(dummy_spanned(MetaItemKind::List(InternedString::new("X"), + vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), + dummy_spanned(ast::LitKind::Byte(99))))), + ]))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), + dummy_spanned(ast::LitKind::Byte(2))))), + ]; + + // Remove something + v4.cfg = vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), + P(dummy_spanned(MetaItemKind::List(InternedString::new("X"), + vec![ + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), + dummy_spanned(ast::LitKind::Byte(99))))), + ]))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), + dummy_spanned(ast::LitKind::Byte(2))))), + ]; + + 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_crate_config_tracking_hash_different_order() { + let mut v1 = super::basic_options(); + let mut v2 = super::basic_options(); + let mut v3 = super::basic_options(); + + // Reference value + v1.cfg = vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), + P(dummy_spanned(MetaItemKind::List(InternedString::new("b"), + vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), + dummy_spanned(ast::LitKind::Byte(1))))), + ]))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), + dummy_spanned(ast::LitKind::Byte(2))))), + ]; + + v2.cfg = vec![ + P(dummy_spanned(MetaItemKind::List(InternedString::new("b"), + vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), + dummy_spanned(ast::LitKind::Byte(1))))), + ]))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), + dummy_spanned(ast::LitKind::Byte(2))))), + P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), + ]; + + v3.cfg = vec![ + P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), + P(dummy_spanned(MetaItemKind::List(InternedString::new("b"), + vec![ + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), + dummy_spanned(ast::LitKind::Byte(1))))), + P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), + ]))), + P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), + dummy_spanned(ast::LitKind::Byte(2))))), + ]; + + 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_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 7f50522b2032b..aa794829be2ca 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", || { @@ -1026,11 +1026,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..b2a6df8d345c9 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -506,12 +506,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; } diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 48c8bcff1ec56..543a9c88a586a 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_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 1077cb296c1ac..a79eca15a369a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2569,7 +2569,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..863b787c58d74 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) { 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..12749c857ab91 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 { @@ -172,7 +173,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 +183,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() @@ -396,7 +396,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 +405,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 29da0fb1a2735..d7a6c16ede0ce 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1171,7 +1171,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/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index d5220316a20ff..f501c06a823b5 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); From d3578ab742129a8aae8461f015d6cc36d85e65cc Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 4 Aug 2016 18:29:58 -0400 Subject: [PATCH 2/6] Save dep-tracking hash of commandline arguments in dep-graph file. .. and use it to purge the incremental compilation cache if necessary. --- src/librustc_incremental/persist/directory.rs | 4 +++ src/librustc_incremental/persist/load.rs | 19 ++++++++++-- src/librustc_incremental/persist/save.rs | 4 +++ src/test/incremental/commandline-args.rs | 30 +++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 src/test/incremental/commandline-args.rs 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/test/incremental/commandline-args.rs b/src/test/incremental/commandline-args.rs new file mode 100644 index 0000000000000..a79fcd4f6af57 --- /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() { + println!("hello world"); +} From 65eb024542835c0235c31ef0e2381d155c797b03 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 9 Aug 2016 08:44:11 -0400 Subject: [PATCH 3/6] Remove the 'cfg' field from session::config::Options. The 'cfg' in the Options struct is only the commandline-specified subset of the crate configuration and it's almost always wrong to read that instead of the CrateConfig in HIR crate node. --- src/librustc/session/config.rs | 226 ++----------------- src/librustc_driver/driver.rs | 5 +- src/librustc_driver/lib.rs | 38 ++-- src/librustc_metadata/creader.rs | 10 +- src/librustc_metadata/macro_import.rs | 8 +- src/librustc_plugin/load.rs | 10 +- src/librustdoc/core.rs | 3 +- src/librustdoc/test.rs | 6 +- src/test/run-make/issue-19371/foo.rs | 4 +- src/test/run-pass-fulldeps/compiler-calls.rs | 4 + 10 files changed, 74 insertions(+), 240 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index e337c1232aab8..a1e30cbaae91f 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -269,15 +269,6 @@ top_level_options!( target_triple: String [TRACKED], - // 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. - // FIXME(mw): If we could be entirely sure that the `cfg` only ever - // influenced which HIR nodes get filtered out, we wouldn't - // need to track this separately. However, we can't rely on - // this (see `debug_assertions` above). - cfg: ast::CrateConfig [TRACKED], test: bool [TRACKED], error_format: ErrorOutputType [UNTRACKED], mir_opt_level: usize [TRACKED], @@ -438,7 +429,6 @@ pub fn basic_options() -> Options { search_paths: SearchPaths::new(), maybe_sysroot: None, target_triple: host_triple().to_string(), - cfg: Vec::new(), test: false, mir_opt_level: 1, incremental: None, @@ -1007,11 +997,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")) @@ -1273,7 +1264,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, @@ -1534,7 +1526,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m)); - Options { + (Options { crate_types: crate_types, optimize: opt_level, debuginfo: debuginfo, @@ -1545,7 +1537,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { search_paths: search_paths, maybe_sysroot: sysroot_opt, target_triple: target, - cfg: cfg, test: test, mir_opt_level: mir_opt_level, incremental: incremental, @@ -1559,7 +1550,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { libs: libs, unstable_features: get_unstable_features_setting(), debug_assertions: debug_assertions, - } + }, + cfg) } pub fn get_unstable_features_setting() -> UnstableFeatures { @@ -1707,10 +1699,7 @@ mod dep_tracking { use std::path::PathBuf; use super::{Passes, PanicStrategy, CrateType, OptLevel, DebugInfoLevel, OutputTypes, Externs, ErrorOutputType}; - use syntax::ast; use syntax::feature_gate::UnstableFeatures; - use syntax::parse::token::InternedString; - use syntax::ptr::P; pub trait DepTrackingHash { fn hash(&self, &mut SipHasher, ErrorOutputType); @@ -1775,64 +1764,6 @@ mod dep_tracking { } } - fn sorted_meta_items(items: &[P]) -> Vec<&ast::MetaItem> { - // Sort subitems so the hash does not depend on their order - let mut items: Vec<&ast::MetaItem> = items.iter() - .map(|r| &**r) - .collect(); - items.sort_by_key(meta_item_sort_key); - return items; - - fn meta_item_sort_key(item: &&ast::MetaItem) -> InternedString { - match item.node { - ast::MetaItemKind::Word(ref s) | - ast::MetaItemKind::NameValue(ref s, _) | - ast::MetaItemKind::List(ref s, _) => s.clone() - } - } - } - - impl DepTrackingHash for ast::MetaItem { - fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) { - // ignoring span information, it doesn't matter here - match self.node { - ast::MetaItemKind::Word(ref s) => { - Hash::hash("Word", hasher); - Hash::hash(&s.len(), hasher); - Hash::hash(s, hasher); - } - ast::MetaItemKind::NameValue(ref s, ref lit) => { - Hash::hash("NameValue", hasher); - Hash::hash(&s.len(), hasher); - Hash::hash(s, hasher); - Hash::hash(&lit.node, hasher); - } - ast::MetaItemKind::List(ref s, ref items) => { - Hash::hash("List", hasher); - Hash::hash(&s.len(), hasher); - Hash::hash(s, hasher); - // Sort subitems so the hash does not depend on their order - let sorted = sorted_meta_items(&items[..]); - for (index, item) in sorted.iter().enumerate() { - Hash::hash(&index, hasher); - DepTrackingHash::hash(*item, hasher, error_format); - } - } - } - } - } - - impl DepTrackingHash for ast::CrateConfig { - fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) { - // Sort subitems so the hash does not depend on their order - let sorted = sorted_meta_items(&self[..]); - for (index, item) in sorted.iter().enumerate() { - Hash::hash(&index, hasher); - DepTrackingHash::hash(*item, hasher, error_format); - } - } - } - impl DepTrackingHash for (T1, T2) where T1: DepTrackingHash, T2: DepTrackingHash @@ -1866,19 +1797,15 @@ mod tests { use getopts::{getopts, OptGroup}; use lint; use middle::cstore::{self, DummyCrateStore}; - use session::config::{build_configuration, build_session_options}; + 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::ast::{self, MetaItemKind}; use syntax::attr; use syntax::attr::AttrMetaMethods; - use syntax::codemap::dummy_spanned; - use syntax::parse::token::InternedString; - use syntax::ptr::P; fn optgroups() -> Vec { super::rustc_optgroups().into_iter() @@ -1904,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"))); } @@ -1924,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()); @@ -1941,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); @@ -1953,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); @@ -1964,7 +1891,7 @@ 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); @@ -2141,127 +2068,6 @@ mod tests { assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash()); } - #[test] - fn test_crate_config_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(); - - // Reference value - v1.cfg = vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), - P(dummy_spanned(MetaItemKind::List(InternedString::new("b"), - vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), - dummy_spanned(ast::LitKind::Byte(1))))), - ]))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), - dummy_spanned(ast::LitKind::Byte(2))))), - ]; - - // Change a label - v2.cfg = vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), - P(dummy_spanned(MetaItemKind::List(InternedString::new("X"), - vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), - dummy_spanned(ast::LitKind::Byte(1))))), - ]))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), - dummy_spanned(ast::LitKind::Byte(2))))), - ]; - - // Change a literal - v3.cfg = vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), - P(dummy_spanned(MetaItemKind::List(InternedString::new("X"), - vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), - dummy_spanned(ast::LitKind::Byte(99))))), - ]))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), - dummy_spanned(ast::LitKind::Byte(2))))), - ]; - - // Remove something - v4.cfg = vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), - P(dummy_spanned(MetaItemKind::List(InternedString::new("X"), - vec![ - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), - dummy_spanned(ast::LitKind::Byte(99))))), - ]))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), - dummy_spanned(ast::LitKind::Byte(2))))), - ]; - - 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_crate_config_tracking_hash_different_order() { - let mut v1 = super::basic_options(); - let mut v2 = super::basic_options(); - let mut v3 = super::basic_options(); - - // Reference value - v1.cfg = vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), - P(dummy_spanned(MetaItemKind::List(InternedString::new("b"), - vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), - dummy_spanned(ast::LitKind::Byte(1))))), - ]))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), - dummy_spanned(ast::LitKind::Byte(2))))), - ]; - - v2.cfg = vec![ - P(dummy_spanned(MetaItemKind::List(InternedString::new("b"), - vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), - dummy_spanned(ast::LitKind::Byte(1))))), - ]))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), - dummy_spanned(ast::LitKind::Byte(2))))), - P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), - ]; - - v3.cfg = vec![ - P(dummy_spanned(MetaItemKind::Word(InternedString::new("a")))), - P(dummy_spanned(MetaItemKind::List(InternedString::new("b"), - vec![ - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("d"), - dummy_spanned(ast::LitKind::Byte(1))))), - P(dummy_spanned(MetaItemKind::Word(InternedString::new("c")))), - ]))), - P(dummy_spanned(MetaItemKind::NameValue(InternedString::new("e"), - dummy_spanned(ast::LitKind::Byte(2))))), - ]; - - 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_search_paths_tracking_hash_different_values() { let mut v1 = super::basic_options(); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index aa794829be2ca..568d98ac8d600 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -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, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b2a6df8d345c9..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)) } @@ -579,6 +593,7 @@ impl RustcDefaultCalls { fn print_crate_info(sess: &Session, + cfg: &ast::CrateConfig, input: Option<&Input>, odir: &Option, ofile: &Option) @@ -631,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_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/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/librustdoc/core.rs b/src/librustdoc/core.rs index 863b787c58d74..10736d2c827cd 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -119,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() @@ -138,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/test.rs b/src/librustdoc/test.rs index 12749c857ab91..7d1dbbe5dc07d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -90,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( @@ -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 { diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index f501c06a823b5..35043bdaddf21 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -52,7 +52,7 @@ fn main() { fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { let mut opts = basic_options(); - opts.output_types = OutputTypes::new([(OutputType::Exe, None)]); + opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); opts.maybe_sysroot = Some(sysroot); let descriptions = Registry::new(&rustc::DIAGNOSTICS); @@ -65,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) From a7de0bc4c6059d8455338d20444b38da85792500 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 9 Aug 2016 15:28:24 -0400 Subject: [PATCH 4/6] Address comments by reviewers. --- src/librustc/session/config.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a1e30cbaae91f..e988ddcd97b15 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -258,13 +258,11 @@ top_level_options!( lint_cap: Option [TRACKED], describe_lints: bool [UNTRACKED], output_types: OutputTypes [TRACKED], - // FIXME(mw): I'm not entirely sure if this can have any influence on - // incremental compilation apart from what is already handled - // by crate metadata hashes. Better track it. + // 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], - // FIXME(mw): Might not need to do dep-tracking for `libs`? libs: Vec<(String, cstore::NativeLibraryKind)> [TRACKED], - // FIXME(mw): Might not need to do dep-tracking for `maybe_sysroot`? maybe_sysroot: Option [TRACKED], target_triple: String [TRACKED], @@ -280,8 +278,9 @@ top_level_options!( debugging_opts: DebuggingOptions [TRACKED], prints: Vec [UNTRACKED], cg: CodegenOptions [TRACKED], - // FIXME(mw): `externs` might not need to be tracked but let's err on - // the side of caution for now. + // 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, @@ -1719,11 +1718,12 @@ mod dep_tracking { ($t:ty) => ( impl DepTrackingHash for Vec<$t> { fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) { - let mut elems = self.clone(); + let mut elems: Vec<&$t> = self.iter().collect(); elems.sort(); - for (i, e) in elems.iter().enumerate() { - Hash::hash(&i, hasher); - DepTrackingHash::hash(e, hasher, error_format); + Hash::hash(&elems.len(), hasher); + for (index, elem) in elems.iter().enumerate() { + Hash::hash(&index, hasher); + DepTrackingHash::hash(*elem, hasher, error_format); } } } From 3a70aa530fdce16a2f67ef20bd5e149174ae6e38 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 11 Aug 2016 10:59:05 -0400 Subject: [PATCH 5/6] Fix incremental/commandline-args test. --- src/test/incremental/commandline-args.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/incremental/commandline-args.rs b/src/test/incremental/commandline-args.rs index a79fcd4f6af57..95187b825be9f 100644 --- a/src/test/incremental/commandline-args.rs +++ b/src/test/incremental/commandline-args.rs @@ -26,5 +26,5 @@ //[rpass3] compile-flags: -C debuginfo=2 --verbose pub fn main() { - println!("hello world"); + // empty } From 67f19e5e28430773256ee55ab6b315e0130f228f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 11 Aug 2016 10:59:35 -0400 Subject: [PATCH 6/6] Always add `-Z incremental-info` to incremental compilation tests. --- src/tools/compiletest/src/runtest.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ae8e82e4e2f60..c5413e3722830 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2012,6 +2012,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,