From b1e68b9e2d75e66bc866a194b744ddf8502ca129 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 28 Mar 2016 17:36:56 -0400 Subject: [PATCH] make an incremental crate for now, this houses `svh` and the code to check `assert_dep_graph` is sane --- mk/crates.mk | 5 +- src/librustc/hir/svh.rs | 374 +--------------- src/librustc/lib.rs | 1 + src/librustc/middle/cstore.rs | 1 + src/librustc_driver/Cargo.toml | 1 + src/librustc_driver/driver.rs | 12 +- src/librustc_driver/lib.rs | 1 + src/librustc_incremental/Cargo.toml | 17 + .../assert_dep_graph.rs | 130 +++--- src/librustc_incremental/calculate_svh.rs | 420 ++++++++++++++++++ src/librustc_incremental/lib.rs | 41 ++ src/librustc_metadata/decoder.rs | 6 +- src/librustc_trans/Cargo.toml | 1 + src/librustc_trans/back/link.rs | 9 +- src/librustc_trans/base.rs | 5 +- src/librustc_trans/lib.rs | 2 +- 16 files changed, 584 insertions(+), 442 deletions(-) create mode 100644 src/librustc_incremental/Cargo.toml rename src/{librustc_trans => librustc_incremental}/assert_dep_graph.rs (78%) create mode 100644 src/librustc_incremental/calculate_svh.rs create mode 100644 src/librustc_incremental/lib.rs diff --git a/mk/crates.mk b/mk/crates.mk index 4c06afcae0c..84452945f27 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -58,7 +58,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ - rustc_const_eval rustc_const_math + rustc_const_eval rustc_const_math rustc_incremental HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros \ flate arena graphviz rbml log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator @@ -117,7 +117,8 @@ DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir DEPS_rustc_privacy := rustc log syntax DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \ log syntax serialize rustc_llvm rustc_platform_intrinsics \ - rustc_const_math rustc_const_eval + rustc_const_math rustc_const_eval rustc_incremental +DEPS_rustc_incremental := rbml rustc serialize rustc_data_structures DEPS_rustc_save_analysis := rustc log syntax DEPS_rustc_typeck := rustc syntax rustc_platform_intrinsics rustc_const_math \ rustc_const_eval diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs index 7ae20f68ad0..08c3d70034a 100644 --- a/src/librustc/hir/svh.rs +++ b/src/librustc/hir/svh.rs @@ -47,9 +47,6 @@ //! Original issue: https://github.com/rust-lang/rust/issues/10207 use std::fmt; -use std::hash::{Hash, SipHasher, Hasher}; -use hir; -use hir::intravisit as visit; #[derive(Clone, PartialEq, Debug)] pub struct Svh { @@ -57,53 +54,16 @@ pub struct Svh { } impl Svh { - pub fn new(hash: &str) -> Svh { + /// Create a new `Svh` given the hash. If you actually want to + /// compute the SVH from some HIR, you want the `calculate_svh` + /// function found in `librustc_trans`. + pub fn new(hash: String) -> Svh { assert!(hash.len() == 16); - Svh { hash: hash.to_string() } + Svh { hash: hash } } - pub fn as_str<'a>(&'a self) -> &'a str { - &self.hash - } - - pub fn calculate(crate_disambiguator: &str, krate: &hir::Crate) -> Svh { - // FIXME (#14132): This is better than it used to be, but it still not - // ideal. We now attempt to hash only the relevant portions of the - // Crate AST as well as the top-level crate attributes. (However, - // the hashing of the crate attributes should be double-checked - // to ensure it is not incorporating implementation artifacts into - // the hash that are not otherwise visible.) - - // FIXME: this should use SHA1, not SipHash. SipHash is not built to - // avoid collisions. - let mut state = SipHasher::new(); - - "crate_disambiguator".hash(&mut state); - crate_disambiguator.len().hash(&mut state); - crate_disambiguator.hash(&mut state); - - { - let mut visit = svh_visitor::make(&mut state, krate); - visit::walk_crate(&mut visit, krate); - } - - // FIXME (#14132): This hash is still sensitive to e.g. the - // spans of the crate Attributes and their underlying - // MetaItems; we should make ContentHashable impl for those - // types and then use hash_content. But, since all crate - // attributes should appear near beginning of the file, it is - // not such a big deal to be sensitive to their spans for now. - // - // We hash only the MetaItems instead of the entire Attribute - // to avoid hashing the AttrId - for attr in &krate.attrs { - attr.node.value.hash(&mut state); - } - - let hash = state.finish(); - return Svh { - hash: (0..64).step_by(4).map(|i| hex(hash >> i)).collect() - }; + pub fn from_hash(hash: u64) -> Svh { + return Svh::new((0..64).step_by(4).map(|i| hex(hash >> i)).collect()); fn hex(b: u64) -> char { let b = (b & 0xf) as u8; @@ -114,6 +74,10 @@ impl Svh { b as char } } + + pub fn as_str<'a>(&'a self) -> &'a str { + &self.hash + } } impl fmt::Display for Svh { @@ -121,319 +85,3 @@ impl fmt::Display for Svh { f.pad(self.as_str()) } } - -// FIXME (#14132): Even this SVH computation still has implementation -// artifacts: namely, the order of item declaration will affect the -// hash computation, but for many kinds of items the order of -// declaration should be irrelevant to the ABI. - -mod svh_visitor { - pub use self::SawExprComponent::*; - pub use self::SawStmtComponent::*; - use self::SawAbiComponent::*; - use syntax::ast::{self, Name, NodeId}; - use syntax::codemap::Span; - use syntax::parse::token; - use hir::intravisit as visit; - use hir::intravisit::{Visitor, FnKind}; - use hir::*; - use hir; - - use std::hash::{Hash, SipHasher}; - - pub struct StrictVersionHashVisitor<'a> { - pub krate: &'a Crate, - pub st: &'a mut SipHasher, - } - - pub fn make<'a>(st: &'a mut SipHasher, krate: &'a Crate) -> StrictVersionHashVisitor<'a> { - StrictVersionHashVisitor { st: st, krate: krate } - } - - // To off-load the bulk of the hash-computation on #[derive(Hash)], - // we define a set of enums corresponding to the content that our - // crate visitor will encounter as it traverses the ast. - // - // The important invariant is that all of the Saw*Component enums - // do not carry any Spans, Names, or Idents. - // - // Not carrying any Names/Idents is the important fix for problem - // noted on PR #13948: using the ident.name as the basis for a - // hash leads to unstable SVH, because ident.name is just an index - // into intern table (i.e. essentially a random address), not - // computed from the name content. - // - // With the below enums, the SVH computation is not sensitive to - // artifacts of how rustc was invoked nor of how the source code - // was laid out. (Or at least it is *less* sensitive.) - - // This enum represents the different potential bits of code the - // visitor could encounter that could affect the ABI for the crate, - // and assigns each a distinct tag to feed into the hash computation. - #[derive(Hash)] - enum SawAbiComponent<'a> { - - // FIXME (#14132): should we include (some function of) - // ident.ctxt as well? - SawIdent(token::InternedString), - SawStructDef(token::InternedString), - - SawLifetime(token::InternedString), - SawLifetimeDef(token::InternedString), - - SawMod, - SawForeignItem, - SawItem, - SawDecl, - SawTy, - SawGenerics, - SawFn, - SawTraitItem, - SawImplItem, - SawStructField, - SawVariant, - SawExplicitSelf, - SawPath, - SawBlock, - SawPat, - SawLocal, - SawArm, - SawExpr(SawExprComponent<'a>), - SawStmt(SawStmtComponent), - } - - /// SawExprComponent carries all of the information that we want - /// to include in the hash that *won't* be covered by the - /// subsequent recursive traversal of the expression's - /// substructure by the visitor. - /// - /// We know every Expr_ variant is covered by a variant because - /// `fn saw_expr` maps each to some case below. Ensuring that - /// each variant carries an appropriate payload has to be verified - /// by hand. - /// - /// (However, getting that *exactly* right is not so important - /// because the SVH is just a developer convenience; there is no - /// guarantee of collision-freedom, hash collisions are just - /// (hopefully) unlikely.) - #[derive(Hash)] - pub enum SawExprComponent<'a> { - - SawExprLoop(Option), - SawExprField(token::InternedString), - SawExprTupField(usize), - SawExprBreak(Option), - SawExprAgain(Option), - - SawExprBox, - SawExprVec, - SawExprCall, - SawExprMethodCall, - SawExprTup, - SawExprBinary(hir::BinOp_), - SawExprUnary(hir::UnOp), - SawExprLit(ast::LitKind), - SawExprCast, - SawExprType, - SawExprIf, - SawExprWhile, - SawExprMatch, - SawExprClosure, - SawExprBlock, - SawExprAssign, - SawExprAssignOp(hir::BinOp_), - SawExprIndex, - SawExprPath(Option), - SawExprAddrOf(hir::Mutability), - SawExprRet, - SawExprInlineAsm(&'a hir::InlineAsm), - SawExprStruct, - SawExprRepeat, - } - - fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { - match *node { - ExprBox(..) => SawExprBox, - ExprVec(..) => SawExprVec, - ExprCall(..) => SawExprCall, - ExprMethodCall(..) => SawExprMethodCall, - ExprTup(..) => SawExprTup, - ExprBinary(op, _, _) => SawExprBinary(op.node), - ExprUnary(op, _) => SawExprUnary(op), - ExprLit(ref lit) => SawExprLit(lit.node.clone()), - ExprCast(..) => SawExprCast, - ExprType(..) => SawExprType, - ExprIf(..) => SawExprIf, - ExprWhile(..) => SawExprWhile, - ExprLoop(_, id) => SawExprLoop(id.map(|id| id.name.as_str())), - ExprMatch(..) => SawExprMatch, - ExprClosure(..) => SawExprClosure, - ExprBlock(..) => SawExprBlock, - ExprAssign(..) => SawExprAssign, - ExprAssignOp(op, _, _) => SawExprAssignOp(op.node), - ExprField(_, name) => SawExprField(name.node.as_str()), - ExprTupField(_, id) => SawExprTupField(id.node), - ExprIndex(..) => SawExprIndex, - ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)), - ExprAddrOf(m, _) => SawExprAddrOf(m), - ExprBreak(id) => SawExprBreak(id.map(|id| id.node.name.as_str())), - ExprAgain(id) => SawExprAgain(id.map(|id| id.node.name.as_str())), - ExprRet(..) => SawExprRet, - ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a), - ExprStruct(..) => SawExprStruct, - ExprRepeat(..) => SawExprRepeat, - } - } - - /// SawStmtComponent is analogous to SawExprComponent, but for statements. - #[derive(Hash)] - pub enum SawStmtComponent { - SawStmtDecl, - SawStmtExpr, - SawStmtSemi, - } - - fn saw_stmt(node: &Stmt_) -> SawStmtComponent { - match *node { - StmtDecl(..) => SawStmtDecl, - StmtExpr(..) => SawStmtExpr, - StmtSemi(..) => SawStmtSemi, - } - } - - impl<'a> Visitor<'a> for StrictVersionHashVisitor<'a> { - fn visit_nested_item(&mut self, item: ItemId) { - self.visit_item(self.krate.item(item.id)) - } - - fn visit_variant_data(&mut self, s: &'a VariantData, name: Name, - g: &'a Generics, _: NodeId, _: Span) { - SawStructDef(name.as_str()).hash(self.st); - visit::walk_generics(self, g); - visit::walk_struct_def(self, s) - } - - fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { - SawVariant.hash(self.st); - // walk_variant does not call walk_generics, so do it here. - visit::walk_generics(self, g); - visit::walk_variant(self, v, g, item_id) - } - - // All of the remaining methods just record (in the hash - // SipHasher) that the visitor saw that particular variant - // (with its payload), and continue walking as the default - // visitor would. - // - // Some of the implementations have some notes as to how one - // might try to make their SVH computation less discerning - // (e.g. by incorporating reachability analysis). But - // currently all of their implementations are uniform and - // uninteresting. - // - // (If you edit a method such that it deviates from the - // pattern, please move that method up above this comment.) - - fn visit_name(&mut self, _: Span, name: Name) { - SawIdent(name.as_str()).hash(self.st); - } - - fn visit_lifetime(&mut self, l: &'a Lifetime) { - SawLifetime(l.name.as_str()).hash(self.st); - } - - fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) { - SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st); - } - - // We do recursively walk the bodies of functions/methods - // (rather than omitting their bodies from the hash) since - // monomorphization and cross-crate inlining generally implies - // that a change to a crate body will require downstream - // crates to be recompiled. - fn visit_expr(&mut self, ex: &'a Expr) { - SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex) - } - - fn visit_stmt(&mut self, s: &'a Stmt) { - SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s) - } - - fn visit_foreign_item(&mut self, i: &'a ForeignItem) { - // FIXME (#14132) ideally we would incorporate privacy (or - // perhaps reachability) somewhere here, so foreign items - // that do not leak into downstream crates would not be - // part of the ABI. - SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i) - } - - fn visit_item(&mut self, i: &'a Item) { - // FIXME (#14132) ideally would incorporate reachability - // analysis somewhere here, so items that never leak into - // downstream crates (e.g. via monomorphisation or - // inlining) would not be part of the ABI. - SawItem.hash(self.st); visit::walk_item(self, i) - } - - fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) { - SawMod.hash(self.st); visit::walk_mod(self, m) - } - - fn visit_decl(&mut self, d: &'a Decl) { - SawDecl.hash(self.st); visit::walk_decl(self, d) - } - - fn visit_ty(&mut self, t: &'a Ty) { - SawTy.hash(self.st); visit::walk_ty(self, t) - } - - fn visit_generics(&mut self, g: &'a Generics) { - SawGenerics.hash(self.st); visit::walk_generics(self, g) - } - - fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl, - b: &'a Block, s: Span, _: NodeId) { - SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s) - } - - fn visit_trait_item(&mut self, ti: &'a TraitItem) { - SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'a ImplItem) { - SawImplItem.hash(self.st); visit::walk_impl_item(self, ii) - } - - fn visit_struct_field(&mut self, s: &'a StructField) { - SawStructField.hash(self.st); visit::walk_struct_field(self, s) - } - - fn visit_explicit_self(&mut self, es: &'a ExplicitSelf) { - SawExplicitSelf.hash(self.st); visit::walk_explicit_self(self, es) - } - - fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) { - SawPath.hash(self.st); visit::walk_path(self, path) - } - - fn visit_path_list_item(&mut self, prefix: &'a Path, item: &'a PathListItem) { - SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item) - } - - fn visit_block(&mut self, b: &'a Block) { - SawBlock.hash(self.st); visit::walk_block(self, b) - } - - fn visit_pat(&mut self, p: &'a Pat) { - SawPat.hash(self.st); visit::walk_pat(self, p) - } - - fn visit_local(&mut self, l: &'a Local) { - SawLocal.hash(self.st); visit::walk_local(self, l) - } - - fn visit_arm(&mut self, a: &'a Arm) { - SawArm.hash(self.st); visit::walk_arm(self, a) - } - } -} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index deb20627772..342007d46c5 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -100,6 +100,7 @@ pub mod middle { pub mod recursion_limit; pub mod resolve_lifetime; pub mod stability; + pub mod svh; pub mod weak_lang_items; } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 1f6328187a5..0409451043d 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -28,6 +28,7 @@ use hir::def::{self, Def}; use middle::lang_items; use ty::{self, Ty, TyCtxt, VariantKind}; use hir::def_id::{DefId, DefIndex}; +use hir::svh::Svh; use mir::repr::Mir; use mir::mir_map::MirMap; use session::Session; diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index bac5900f3ed..4533946d26e 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -23,6 +23,7 @@ rustc_mir = { path = "../librustc_mir" } rustc_plugin = { path = "../librustc_plugin" } rustc_passes = { path = "../librustc_passes" } rustc_privacy = { path = "../librustc_privacy" } +rustc_incremental = { path = "../librustc_incremental" } rustc_resolve = { path = "../librustc_resolve" } rustc_save_analysis = { path = "../librustc_save_analysis" } rustc_trans = { path = "../librustc_trans" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index a4d34aaf652..f35d5f25962 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -24,6 +24,7 @@ use rustc::util::common::time; use rustc::util::nodemap::NodeSet; use rustc_back::sha2::{Sha256, Digest}; use rustc_borrowck as borrowck; +use rustc_incremental; use rustc_resolve as resolve; use rustc_metadata::macro_import; use rustc_metadata::creader::LocalCrateReader; @@ -952,9 +953,16 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>, passes.run_passes(tcx, &mut mir_map); }); + let translation = + time(time_passes, + "translation", + move || trans::trans_crate(tcx, &mir_map, analysis)); + time(time_passes, - "translation", - move || trans::trans_crate(tcx, &mir_map, analysis)) + "assert dep graph", + move || rustc_incremental::assert_dep_graph(tcx)); + + translation } /// Run LLVM itself, producing a bitcode file, assembly file or object file diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b4b53d30e3c..85807dec0ff 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -45,6 +45,7 @@ extern crate rustc_passes; extern crate rustc_lint; extern crate rustc_plugin; extern crate rustc_privacy; +extern crate rustc_incremental; extern crate rustc_metadata; extern crate rustc_mir; extern crate rustc_resolve; diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml new file mode 100644 index 00000000000..1a8b5a483e0 --- /dev/null +++ b/src/librustc_incremental/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_serialize" +version = "0.0.0" + +[lib] +name = "rustc_serialize" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +graphviz = { path = "../libgraphviz" } +rbml = { path = "../librbml" } +rustc = { path = "../librustc" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_front = { path = "../librustc_front" } +serialize = { path = "../libserialize" } diff --git a/src/librustc_trans/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs similarity index 78% rename from src/librustc_trans/assert_dep_graph.rs rename to src/librustc_incremental/assert_dep_graph.rs index 932f66f17cc..88d8ed8d581 100644 --- a/src/librustc_trans/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -13,12 +13,17 @@ //! will dump graphs in graphviz form to disk, and it searches for //! `#[rustc_if_this_changed]` and `#[rustc_then_this_would_need]` //! annotations. These annotations can be used to test whether paths -//! exist in the graph. We report errors on each -//! `rustc_if_this_changed` annotation. If a path exists in all -//! cases, then we would report "all path(s) exist". Otherwise, we -//! report: "no path to `foo`" for each case where no path exists. -//! `compile-fail` tests can then be used to check when paths exist or -//! do not. +//! exist in the graph. These checks run after trans, so they view the +//! the final state of the dependency graph. Note that there are +//! similar assertions found in `persist::dirty_clean` which check the +//! **initial** state of the dependency graph, just after it has been +//! loaded from disk. +//! +//! In this code, we report errors on each `rustc_if_this_changed` +//! annotation. If a path exists in all cases, then we would report +//! "all path(s) exist". Otherwise, we report: "no path to `foo`" for +//! each case where no path exists. `compile-fail` tests can then be +//! used to check when paths exist or do not. //! //! The full form of the `rustc_if_this_changed` annotation is //! `#[rustc_if_this_changed(id)]`. The `"id"` is optional and @@ -61,7 +66,7 @@ const ID: &'static str = "id"; pub fn assert_dep_graph(tcx: &TyCtxt) { let _ignore = tcx.dep_graph.in_ignore(); - if tcx.sess.opts.dump_dep_graph { + if tcx.sess.opts.debugging_opts.dump_dep_graph { dump_graph(tcx); } @@ -74,14 +79,23 @@ pub fn assert_dep_graph(tcx: &TyCtxt) { (visitor.if_this_changed, visitor.then_this_would_need) }; + if !if_this_changed.is_empty() || !then_this_would_need.is_empty() { + assert!(tcx.sess.opts.debugging_opts.query_dep_graph, + "cannot use the `#[{}]` or `#[{}]` annotations \ + without supplying `-Z query-dep-graph`", + IF_THIS_CHANGED, THEN_THIS_WOULD_NEED); + } + // Check paths. check_paths(tcx, &if_this_changed, &then_this_would_need); } -type SourceHashMap = FnvHashMap>; -type TargetHashMap = FnvHashMap>; +type SourceHashMap = + FnvHashMap)>>; +type TargetHashMap = + FnvHashMap)>>; struct IfThisChanged<'a, 'tcx:'a> { tcx: &'a TyCtxt<'tcx>, @@ -124,34 +138,21 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { } } } - let dep_node_str = dep_node_interned.as_ref().map(|s| &**s); - macro_rules! match_depnode_name { - ($input:expr, $def_id:expr, match { $($variant:ident,)* } else $y:expr) => { - match $input { - $(Some(stringify!($variant)) => DepNode::$variant($def_id),)* - _ => $y + let dep_node = match dep_node_interned { + Some(ref n) => { + match DepNode::from_label_string(&n[..], def_id) { + Ok(n) => n, + Err(()) => { + self.tcx.sess.span_fatal( + attr.span, + &format!("unrecognized DepNode variant {:?}", n)); + } } } - } - let dep_node = match_depnode_name! { - dep_node_str, def_id, match { - CollectItem, - BorrowCheck, - TransCrateItem, - TypeckItemType, - TypeckItemBody, - ImplOrTraitItems, - ItemSignature, - FieldTy, - TraitItemDefIds, - InherentImpls, - ImplItems, - TraitImpls, - ReprHints, - } else { + None => { self.tcx.sess.span_fatal( attr.span, - &format!("unrecognized DepNode variant {:?}", dep_node_str)); + &format!("missing DepNode variant")); } }; let id = id.unwrap_or(InternedString::new(ID)); @@ -194,7 +195,7 @@ fn check_paths(tcx: &TyCtxt, }; for &(_, source_def_id, source_dep_node) in sources { - let dependents = query.dependents(source_dep_node); + let dependents = query.transitive_dependents(source_dep_node); for &(target_span, ref target_pass, _, ref target_dep_node) in targets { if !dependents.contains(&target_dep_node) { tcx.sess.span_err( @@ -251,33 +252,34 @@ fn dump_graph(tcx: &TyCtxt) { } } -pub struct GraphvizDepGraph(FnvHashSet, Vec<(DepNode, DepNode)>); +pub struct GraphvizDepGraph(FnvHashSet>, + Vec<(DepNode, DepNode)>); impl<'a, 'tcx> dot::GraphWalk<'a> for GraphvizDepGraph { - type Node = DepNode; - type Edge = (DepNode, DepNode); - fn nodes(&self) -> dot::Nodes { + type Node = DepNode; + type Edge = (DepNode, DepNode); + fn nodes(&self) -> dot::Nodes> { let nodes: Vec<_> = self.0.iter().cloned().collect(); nodes.into_cow() } - fn edges(&self) -> dot::Edges<(DepNode, DepNode)> { + fn edges(&self) -> dot::Edges<(DepNode, DepNode)> { self.1[..].into_cow() } - fn source(&self, edge: &(DepNode, DepNode)) -> DepNode { + fn source(&self, edge: &(DepNode, DepNode)) -> DepNode { edge.0 } - fn target(&self, edge: &(DepNode, DepNode)) -> DepNode { + fn target(&self, edge: &(DepNode, DepNode)) -> DepNode { edge.1 } } impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph { - type Node = DepNode; - type Edge = (DepNode, DepNode); + type Node = DepNode; + type Edge = (DepNode, DepNode); fn graph_id(&self) -> dot::Id { dot::Id::new("DependencyGraph").unwrap() } - fn node_id(&self, n: &DepNode) -> dot::Id { + fn node_id(&self, n: &DepNode) -> dot::Id { let s: String = format!("{:?}", n).chars() .map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' }) @@ -285,7 +287,7 @@ impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph { debug!("n={:?} s={:?}", n, s); dot::Id::new(s).unwrap() } - fn node_label(&self, n: &DepNode) -> dot::LabelText { + fn node_label(&self, n: &DepNode) -> dot::LabelText { dot::LabelText::label(format!("{:?}", n)) } } @@ -293,7 +295,9 @@ impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph { // Given an optional filter like `"x,y,z"`, returns either `None` (no // filter) or the set of nodes whose labels contain all of those // substrings. -fn node_set(query: &DepGraphQuery, filter: &str) -> Option> { +fn node_set(query: &DepGraphQuery, filter: &str) + -> Option>> +{ debug!("node_set(filter={:?})", filter); if filter.trim().is_empty() { @@ -313,10 +317,10 @@ fn node_set(query: &DepGraphQuery, filter: &str) -> Option> .collect()) } -fn filter_nodes(query: &DepGraphQuery, - sources: &Option>, - targets: &Option>) - -> FnvHashSet +fn filter_nodes(query: &DepGraphQuery, + sources: &Option>>, + targets: &Option>>) + -> FnvHashSet> { if let &Some(ref sources) = sources { if let &Some(ref targets) = targets { @@ -331,10 +335,10 @@ fn filter_nodes(query: &DepGraphQuery, } } -fn walk_nodes(query: &DepGraphQuery, - starts: &FnvHashSet, +fn walk_nodes(query: &DepGraphQuery, + starts: &FnvHashSet>, direction: Direction) - -> FnvHashSet + -> FnvHashSet> { let mut set = FnvHashSet(); for start in starts { @@ -355,10 +359,10 @@ fn walk_nodes(query: &DepGraphQuery, set } -fn walk_between(query: &DepGraphQuery, - sources: &FnvHashSet, - targets: &FnvHashSet) - -> FnvHashSet +fn walk_between(query: &DepGraphQuery, + sources: &FnvHashSet>, + targets: &FnvHashSet>) + -> FnvHashSet> { // This is a bit tricky. We want to include a node only if it is: // (a) reachable from a source and (b) will reach a target. And we @@ -386,7 +390,7 @@ fn walk_between(query: &DepGraphQuery, }) .collect(); - fn recurse(query: &DepGraphQuery, + fn recurse(query: &DepGraphQuery, node_states: &mut [State], node: NodeIndex) -> bool @@ -423,9 +427,9 @@ fn walk_between(query: &DepGraphQuery, } } -fn filter_edges(query: &DepGraphQuery, - nodes: &FnvHashSet) - -> Vec<(DepNode, DepNode)> +fn filter_edges(query: &DepGraphQuery, + nodes: &FnvHashSet>) + -> Vec<(DepNode, DepNode)> { query.edges() .into_iter() diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs new file mode 100644 index 00000000000..158db34ee8a --- /dev/null +++ b/src/librustc_incremental/calculate_svh.rs @@ -0,0 +1,420 @@ +// Copyright 2012-2014 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. + +//! Calculation of a Strict Version Hash for crates. For a length +//! comment explaining the general idea, see `librustc/middle/svh.rs`. + +use std::hash::{Hash, SipHasher, Hasher}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::svh::Svh; +use rustc::ty; +use rustc_front::intravisit::{self, Visitor}; + +use self::svh_visitor::StrictVersionHashVisitor; + +pub trait SvhCalculate { + /// Calculate the SVH for an entire krate. + fn calculate_krate_hash(&self) -> Svh; + + /// Calculate the SVH for a particular item. + fn calculate_item_hash(&self, def_id: DefId) -> u64; +} + +impl<'tcx> SvhCalculate for ty::TyCtxt<'tcx> { + fn calculate_krate_hash(&self) -> Svh { + // FIXME (#14132): This is better than it used to be, but it still not + // ideal. We now attempt to hash only the relevant portions of the + // Crate AST as well as the top-level crate attributes. (However, + // the hashing of the crate attributes should be double-checked + // to ensure it is not incorporating implementation artifacts into + // the hash that are not otherwise visible.) + + let crate_disambiguator = self.sess.crate_disambiguator.get(); + let krate = self.map.krate(); + + // FIXME: this should use SHA1, not SipHash. SipHash is not built to + // avoid collisions. + let mut state = SipHasher::new(); + debug!("state: {:?}", state); + + "crate_disambiguator".hash(&mut state); + crate_disambiguator.as_str().len().hash(&mut state); + crate_disambiguator.as_str().hash(&mut state); + + debug!("crate_disambiguator: {:?}", crate_disambiguator.as_str()); + debug!("state: {:?}", state); + + { + let mut visit = StrictVersionHashVisitor::new(&mut state, self); + krate.visit_all_items(&mut visit); + } + + // FIXME (#14132): This hash is still sensitive to e.g. the + // spans of the crate Attributes and their underlying + // MetaItems; we should make ContentHashable impl for those + // types and then use hash_content. But, since all crate + // attributes should appear near beginning of the file, it is + // not such a big deal to be sensitive to their spans for now. + // + // We hash only the MetaItems instead of the entire Attribute + // to avoid hashing the AttrId + for attr in &krate.attrs { + debug!("krate attr {:?}", attr); + attr.node.value.hash(&mut state); + } + + Svh::from_hash(state.finish()) + } + + fn calculate_item_hash(&self, def_id: DefId) -> u64 { + assert!(def_id.is_local()); + + let mut state = SipHasher::new(); + + { + let mut visit = StrictVersionHashVisitor::new(&mut state, self); + if def_id.index == CRATE_DEF_INDEX { + // the crate root itself is not registered in the map + // as an item, so we have to fetch it this way + let krate = self.map.krate(); + intravisit::walk_crate(&mut visit, krate); + } else { + let node_id = self.map.as_local_node_id(def_id).unwrap(); + visit.visit_item(self.map.expect_item(node_id)); + } + } + + state.finish() + } +} + +// FIXME (#14132): Even this SVH computation still has implementation +// artifacts: namely, the order of item declaration will affect the +// hash computation, but for many kinds of items the order of +// declaration should be irrelevant to the ABI. + +mod svh_visitor { + pub use self::SawExprComponent::*; + pub use self::SawStmtComponent::*; + use self::SawAbiComponent::*; + use syntax::ast::{self, Name, NodeId}; + use syntax::codemap::Span; + use syntax::parse::token; + use rustc::ty; + use rustc_front::intravisit as visit; + use rustc_front::intravisit::{Visitor, FnKind}; + use rustc_front::hir::*; + use rustc_front::hir; + + use std::hash::{Hash, SipHasher}; + + pub struct StrictVersionHashVisitor<'a, 'tcx: 'a> { + pub tcx: &'a ty::TyCtxt<'tcx>, + pub st: &'a mut SipHasher, + } + + impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> { + pub fn new(st: &'a mut SipHasher, + tcx: &'a ty::TyCtxt<'tcx>) + -> Self { + StrictVersionHashVisitor { st: st, tcx: tcx } + } + } + + // To off-load the bulk of the hash-computation on #[derive(Hash)], + // we define a set of enums corresponding to the content that our + // crate visitor will encounter as it traverses the ast. + // + // The important invariant is that all of the Saw*Component enums + // do not carry any Spans, Names, or Idents. + // + // Not carrying any Names/Idents is the important fix for problem + // noted on PR #13948: using the ident.name as the basis for a + // hash leads to unstable SVH, because ident.name is just an index + // into intern table (i.e. essentially a random address), not + // computed from the name content. + // + // With the below enums, the SVH computation is not sensitive to + // artifacts of how rustc was invoked nor of how the source code + // was laid out. (Or at least it is *less* sensitive.) + + // This enum represents the different potential bits of code the + // visitor could encounter that could affect the ABI for the crate, + // and assigns each a distinct tag to feed into the hash computation. + #[derive(Hash)] + enum SawAbiComponent<'a> { + + // FIXME (#14132): should we include (some function of) + // ident.ctxt as well? + SawIdent(token::InternedString), + SawStructDef(token::InternedString), + + SawLifetime(token::InternedString), + SawLifetimeDef(token::InternedString), + + SawMod, + SawForeignItem, + SawItem, + SawDecl, + SawTy, + SawGenerics, + SawFn, + SawTraitItem, + SawImplItem, + SawStructField, + SawVariant, + SawExplicitSelf, + SawPath, + SawBlock, + SawPat, + SawLocal, + SawArm, + SawExpr(SawExprComponent<'a>), + SawStmt(SawStmtComponent), + } + + /// SawExprComponent carries all of the information that we want + /// to include in the hash that *won't* be covered by the + /// subsequent recursive traversal of the expression's + /// substructure by the visitor. + /// + /// We know every Expr_ variant is covered by a variant because + /// `fn saw_expr` maps each to some case below. Ensuring that + /// each variant carries an appropriate payload has to be verified + /// by hand. + /// + /// (However, getting that *exactly* right is not so important + /// because the SVH is just a developer convenience; there is no + /// guarantee of collision-freedom, hash collisions are just + /// (hopefully) unlikely.) + #[derive(Hash)] + pub enum SawExprComponent<'a> { + + SawExprLoop(Option), + SawExprField(token::InternedString), + SawExprTupField(usize), + SawExprBreak(Option), + SawExprAgain(Option), + + SawExprBox, + SawExprVec, + SawExprCall, + SawExprMethodCall, + SawExprTup, + SawExprBinary(hir::BinOp_), + SawExprUnary(hir::UnOp), + SawExprLit(ast::LitKind), + SawExprCast, + SawExprType, + SawExprIf, + SawExprWhile, + SawExprMatch, + SawExprClosure, + SawExprBlock, + SawExprAssign, + SawExprAssignOp(hir::BinOp_), + SawExprIndex, + SawExprPath(Option), + SawExprAddrOf(hir::Mutability), + SawExprRet, + SawExprInlineAsm(&'a hir::InlineAsm), + SawExprStruct, + SawExprRepeat, + } + + fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { + match *node { + ExprBox(..) => SawExprBox, + ExprVec(..) => SawExprVec, + ExprCall(..) => SawExprCall, + ExprMethodCall(..) => SawExprMethodCall, + ExprTup(..) => SawExprTup, + ExprBinary(op, _, _) => SawExprBinary(op.node), + ExprUnary(op, _) => SawExprUnary(op), + ExprLit(ref lit) => SawExprLit(lit.node.clone()), + ExprCast(..) => SawExprCast, + ExprType(..) => SawExprType, + ExprIf(..) => SawExprIf, + ExprWhile(..) => SawExprWhile, + ExprLoop(_, id) => SawExprLoop(id.map(|id| id.name.as_str())), + ExprMatch(..) => SawExprMatch, + ExprClosure(..) => SawExprClosure, + ExprBlock(..) => SawExprBlock, + ExprAssign(..) => SawExprAssign, + ExprAssignOp(op, _, _) => SawExprAssignOp(op.node), + ExprField(_, name) => SawExprField(name.node.as_str()), + ExprTupField(_, id) => SawExprTupField(id.node), + ExprIndex(..) => SawExprIndex, + ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)), + ExprAddrOf(m, _) => SawExprAddrOf(m), + ExprBreak(id) => SawExprBreak(id.map(|id| id.node.name.as_str())), + ExprAgain(id) => SawExprAgain(id.map(|id| id.node.name.as_str())), + ExprRet(..) => SawExprRet, + ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a), + ExprStruct(..) => SawExprStruct, + ExprRepeat(..) => SawExprRepeat, + } + } + + /// SawStmtComponent is analogous to SawExprComponent, but for statements. + #[derive(Hash)] + pub enum SawStmtComponent { + SawStmtDecl, + SawStmtExpr, + SawStmtSemi, + } + + fn saw_stmt(node: &Stmt_) -> SawStmtComponent { + match *node { + StmtDecl(..) => SawStmtDecl, + StmtExpr(..) => SawStmtExpr, + StmtSemi(..) => SawStmtSemi, + } + } + + impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> { + fn visit_nested_item(&mut self, item: ItemId) { + debug!("visit_nested_item: {:?} st={:?}", item, self.st); + let def_path = self.tcx.map.def_path_from_id(item.id); + def_path.hash(self.st); + } + + fn visit_variant_data(&mut self, s: &'a VariantData, name: Name, + g: &'a Generics, _: NodeId, _: Span) { + SawStructDef(name.as_str()).hash(self.st); + visit::walk_generics(self, g); + visit::walk_struct_def(self, s) + } + + fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { + SawVariant.hash(self.st); + // walk_variant does not call walk_generics, so do it here. + visit::walk_generics(self, g); + visit::walk_variant(self, v, g, item_id) + } + + // All of the remaining methods just record (in the hash + // SipHasher) that the visitor saw that particular variant + // (with its payload), and continue walking as the default + // visitor would. + // + // Some of the implementations have some notes as to how one + // might try to make their SVH computation less discerning + // (e.g. by incorporating reachability analysis). But + // currently all of their implementations are uniform and + // uninteresting. + // + // (If you edit a method such that it deviates from the + // pattern, please move that method up above this comment.) + + fn visit_name(&mut self, _: Span, name: Name) { + SawIdent(name.as_str()).hash(self.st); + } + + fn visit_lifetime(&mut self, l: &'a Lifetime) { + SawLifetime(l.name.as_str()).hash(self.st); + } + + fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) { + SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st); + } + + // We do recursively walk the bodies of functions/methods + // (rather than omitting their bodies from the hash) since + // monomorphization and cross-crate inlining generally implies + // that a change to a crate body will require downstream + // crates to be recompiled. + fn visit_expr(&mut self, ex: &'a Expr) { + SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex) + } + + fn visit_stmt(&mut self, s: &'a Stmt) { + SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s) + } + + fn visit_foreign_item(&mut self, i: &'a ForeignItem) { + // FIXME (#14132) ideally we would incorporate privacy (or + // perhaps reachability) somewhere here, so foreign items + // that do not leak into downstream crates would not be + // part of the ABI. + SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i) + } + + fn visit_item(&mut self, i: &'a Item) { + debug!("visit_item: {:?} st={:?}", i, self.st); + // FIXME (#14132) ideally would incorporate reachability + // analysis somewhere here, so items that never leak into + // downstream crates (e.g. via monomorphisation or + // inlining) would not be part of the ABI. + SawItem.hash(self.st); visit::walk_item(self, i) + } + + fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) { + SawMod.hash(self.st); visit::walk_mod(self, m) + } + + fn visit_decl(&mut self, d: &'a Decl) { + SawDecl.hash(self.st); visit::walk_decl(self, d) + } + + fn visit_ty(&mut self, t: &'a Ty) { + SawTy.hash(self.st); visit::walk_ty(self, t) + } + + fn visit_generics(&mut self, g: &'a Generics) { + SawGenerics.hash(self.st); visit::walk_generics(self, g) + } + + fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl, + b: &'a Block, s: Span, _: NodeId) { + SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s) + } + + fn visit_trait_item(&mut self, ti: &'a TraitItem) { + SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &'a ImplItem) { + SawImplItem.hash(self.st); visit::walk_impl_item(self, ii) + } + + fn visit_struct_field(&mut self, s: &'a StructField) { + SawStructField.hash(self.st); visit::walk_struct_field(self, s) + } + + fn visit_explicit_self(&mut self, es: &'a ExplicitSelf) { + SawExplicitSelf.hash(self.st); visit::walk_explicit_self(self, es) + } + + fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) { + SawPath.hash(self.st); visit::walk_path(self, path) + } + + fn visit_path_list_item(&mut self, prefix: &'a Path, item: &'a PathListItem) { + SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item) + } + + fn visit_block(&mut self, b: &'a Block) { + SawBlock.hash(self.st); visit::walk_block(self, b) + } + + fn visit_pat(&mut self, p: &'a Pat) { + SawPat.hash(self.st); visit::walk_pat(self, p) + } + + fn visit_local(&mut self, l: &'a Local) { + SawLocal.hash(self.st); visit::walk_local(self, l) + } + + fn visit_arm(&mut self, a: &'a Arm) { + SawArm.hash(self.st); visit::walk_arm(self, a) + } + } +} diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs new file mode 100644 index 00000000000..3af8fe5cc5f --- /dev/null +++ b/src/librustc_incremental/lib.rs @@ -0,0 +1,41 @@ +// Copyright 2012-2013 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. + +//! Support for serializing the dep-graph and reloading it. + +#![crate_name = "rustc_incremental"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] +#![cfg_attr(not(stage0), deny(warnings))] + +#![feature(rustc_private)] +#![feature(staged_api)] + +extern crate graphviz; +extern crate rbml; +extern crate rustc; +extern crate rustc_data_structures; +extern crate serialize as rustc_serialize; + +#[macro_use] extern crate log; +#[macro_use] extern crate syntax; + +mod assert_dep_graph; +mod calculate_svh; +mod persist; + +pub use assert_dep_graph::assert_dep_graph; +pub use calculate_svh::SvhCalculate; +pub use persist::load_dep_graph; +pub use persist::save_dep_graph; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 6b53edbbff1..bb95104ffea 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1242,7 +1242,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec { reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| { let name = docstr(depdoc, tag_crate_dep_crate_name); - let hash = Svh::new(&docstr(depdoc, tag_crate_dep_hash)); + let hash = Svh::new(docstr(depdoc, tag_crate_dep_hash)); let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked); let explicitly_linked = reader::doc_as_u8(doc) != 0; CrateDep { @@ -1266,14 +1266,14 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { pub fn maybe_get_crate_hash(data: &[u8]) -> Option { let cratedoc = rbml::Doc::new(data); reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| { - Svh::new(doc.as_str_slice()) + Svh::new(doc.as_str_slice().to_string()) }) } pub fn get_crate_hash(data: &[u8]) -> Svh { let cratedoc = rbml::Doc::new(data); let hashdoc = reader::get_doc(cratedoc, tag_crate_hash); - Svh::new(hashdoc.as_str_slice()) + Svh::new(hashdoc.as_str_slice().to_string()) } pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> { diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index ea4cef03b70..ccb430fbb78 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -18,6 +18,7 @@ rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_incremental = { path = "../librustc_incremental" } rustc_llvm = { path = "../librustc_llvm" } rustc_mir = { path = "../librustc_mir" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 130499603e7..1d15e67651a 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -13,7 +13,6 @@ use super::linker::{Linker, GnuLinker, MsvcLinker}; use super::rpath::RPathConfig; use super::rpath; use super::msvc; -use super::svh::Svh; use session::config; use session::config::NoDebugInfo; use session::config::{OutputFilenames, Input, OutputType}; @@ -26,8 +25,10 @@ use middle::dependency_format::Linkage; use CrateTranslation; use util::common::time; use util::fs::fix_windows_verbatim_for_gcc; +use rustc::ty::TyCtxt; use rustc_back::tempdir::TempDir; +use rustc_incremental::SvhCalculate; use std::ascii; use std::char; use std::env; @@ -122,15 +123,15 @@ pub fn find_crate_name(sess: Option<&Session>, } "rust_out".to_string() + } -pub fn build_link_meta(sess: &Session, - krate: &hir::Crate, +pub fn build_link_meta(tcx: &TyCtxt, name: &str) -> LinkMeta { let r = LinkMeta { crate_name: name.to_owned(), - crate_hash: Svh::calculate(&sess.crate_disambiguator.get().as_str(), krate), + crate_hash: tcx.calculate_krate_hash(), }; info!("{:?}", r); return r; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c8ed4e629e4..17230eff6e6 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -54,7 +54,6 @@ use session::Session; use _match; use abi::{self, Abi, FnType}; use adt; -use assert_dep_graph; use attributes; use build::*; use builder::{Builder, noname}; @@ -2730,7 +2729,7 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, } } - let link_meta = link::build_link_meta(&tcx.sess, krate, name); + let link_meta = link::build_link_meta(&tcx, name); let codegen_units = tcx.sess.opts.cg.codegen_units; let shared_ccx = SharedCrateContext::new(&link_meta.crate_name, @@ -2856,8 +2855,6 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, }; let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); - assert_dep_graph::assert_dep_graph(tcx); - CrateTranslation { modules: modules, metadata_module: metadata_module, diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 19a172e7f10..cb421b6be47 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -46,6 +46,7 @@ extern crate libc; #[macro_use] extern crate rustc; extern crate rustc_back; extern crate rustc_data_structures; +extern crate rustc_incremental; pub extern crate rustc_llvm as llvm; extern crate rustc_mir; extern crate rustc_platform_intrinsics as intrinsics; @@ -85,7 +86,6 @@ mod macros; mod abi; mod adt; mod asm; -mod assert_dep_graph; mod attributes; mod base; mod basic_block;