diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index daf1ff8ad2b..bd3a3583676 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -202,6 +202,40 @@ impl<'a, 'gcx, 'lcx> StableHashingContextProvider for ty::TyCtxt<'a, 'gcx, 'lcx> } } +impl<'a, 'gcx, 'tcx> HashStable> for hir::HirId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, + hasher: &mut StableHasher) { + match hcx.node_id_hashing_mode { + NodeIdHashingMode::Ignore => { + // Don't do anything. + } + NodeIdHashingMode::HashDefPath => { + let hir::HirId { + owner, + local_id, + } = *self; + + hcx.tcx.hir.definitions().def_path_hash(owner).hash_stable(hcx, hasher); + local_id.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'gcx, 'tcx> ToStableHashKey> for hir::HirId { + type KeyType = (DefPathHash, hir::ItemLocalId); + + #[inline] + fn to_stable_hash_key(&self, + hcx: &StableHashingContext<'a, 'gcx, 'tcx>) + -> (DefPathHash, hir::ItemLocalId) { + let def_path_hash = hcx.tcx().hir.definitions().def_path_hash(self.owner); + (def_path_hash, self.local_id) + } +} + impl<'a, 'gcx, 'tcx> HashStable> for ast::NodeId { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, diff --git a/src/librustc/ich/impls_cstore.rs b/src/librustc/ich/impls_cstore.rs index 057a83ebbe3..18a02ff5c58 100644 --- a/src/librustc/ich/impls_cstore.rs +++ b/src/librustc/ich/impls_cstore.rs @@ -11,6 +11,8 @@ //! This module contains `HashStable` implementations for various data types //! from rustc::middle::cstore in no particular order. +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; + use middle; impl_stable_hash_for!(enum middle::cstore::DepKind { @@ -51,3 +53,29 @@ impl_stable_hash_for!(struct middle::cstore::CrateSource { rlib, rmeta }); + +impl HashStable for middle::cstore::ExternBodyNestedBodies { + fn hash_stable(&self, + hcx: &mut HCX, + hasher: &mut StableHasher) { + let middle::cstore::ExternBodyNestedBodies { + nested_bodies: _, + fingerprint, + } = *self; + + fingerprint.hash_stable(hcx, hasher); + } +} + +impl<'a, HCX> HashStable for middle::cstore::ExternConstBody<'a> { + fn hash_stable(&self, + hcx: &mut HCX, + hasher: &mut StableHasher) { + let middle::cstore::ExternConstBody { + body: _, + fingerprint, + } = *self; + + fingerprint.hash_stable(hcx, hasher); + } +} diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 9da147472ce..3c89e10a0d2 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -38,33 +38,6 @@ impl<'a, 'gcx, 'tcx> ToStableHashKey> for D } } -impl<'a, 'gcx, 'tcx> HashStable> for hir::HirId { - #[inline] - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, - hasher: &mut StableHasher) { - let hir::HirId { - owner, - local_id, - } = *self; - - hcx.tcx().hir.definitions().def_path_hash(owner).hash_stable(hcx, hasher); - local_id.hash_stable(hcx, hasher); - } -} - -impl<'a, 'gcx, 'tcx> ToStableHashKey> for hir::HirId { - type KeyType = (DefPathHash, hir::ItemLocalId); - - #[inline] - fn to_stable_hash_key(&self, - hcx: &StableHashingContext<'a, 'gcx, 'tcx>) - -> (DefPathHash, hir::ItemLocalId) { - let def_path_hash = hcx.tcx().hir.definitions().def_path_hash(self.owner); - (def_path_hash, self.local_id) - } -} - impl<'a, 'gcx, 'tcx> HashStable> for CrateNum { #[inline] fn hash_stable(&self, @@ -415,6 +388,7 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::P ref span } = *self; + node.hash_stable(hcx, hasher); span.hash_stable(hcx, hasher); } @@ -1003,11 +977,23 @@ impl_stable_hash_for!(struct hir::Arg { hir_id }); -impl_stable_hash_for!(struct hir::Body { - arguments, - value, - is_generator -}); +impl<'a, 'gcx, 'tcx> HashStable> for hir::Body { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, + hasher: &mut StableHasher) { + let hir::Body { + ref arguments, + ref value, + is_generator, + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| { + arguments.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + is_generator.hash_stable(hcx, hasher); + }); + } +} impl<'a, 'gcx, 'tcx> HashStable> for hir::BodyId { fn hash_stable(&self, diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 7c60c6d6430..de647913f0f 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -22,6 +22,7 @@ //! are *mostly* used as a part of that interface, but these should //! probably get a better home if someone can find one. +use hir; use hir::def; use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use hir::map as hir_map; @@ -34,6 +35,7 @@ use session::search_paths::PathKind; use util::nodemap::NodeSet; use std::any::Any; +use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::rc::Rc; use owning_ref::ErasedBoxRef; @@ -218,6 +220,26 @@ pub trait MetadataLoader { -> Result, String>; } +#[derive(Clone)] +pub struct ExternConstBody<'tcx> { + pub body: &'tcx hir::Body, + + // It would require a lot of infrastructure to enable stable-hashing Bodies + // from other crates, so we hash on export and just store the fingerprint + // with them. + pub fingerprint: ich::Fingerprint, +} + +#[derive(Clone)] +pub struct ExternBodyNestedBodies { + pub nested_bodies: Rc>, + + // It would require a lot of infrastructure to enable stable-hashing Bodies + // from other crates, so we hash on export and just store the fingerprint + // with them. + pub fingerprint: ich::Fingerprint, +} + /// A store of Rust crates, through with their metadata /// can be accessed. /// diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index fc803d1c849..5207aaa0c5b 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -16,8 +16,9 @@ use hir::{self, TraitCandidate, ItemLocalId}; use hir::svh::Svh; use lint; use middle::const_val; -use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary}; -use middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; +use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, + ExternBodyNestedBodies}; +use middle::cstore::{NativeLibraryKind, DepKind, CrateSource, ExternConstBody}; use middle::privacy::AccessLevels; use middle::reachable::ReachableSet; use middle::region; @@ -50,7 +51,6 @@ use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; use std::mem; -use std::collections::BTreeMap; use std::ops::Deref; use std::rc::Rc; use std::sync::Arc; @@ -1321,8 +1321,7 @@ define_maps! { <'tcx> [] fn impl_parent: ImplParent(DefId) -> Option, [] fn trait_of_item: TraitOfItem(DefId) -> Option, [] fn is_exported_symbol: IsExportedSymbol(DefId) -> bool, - [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) - -> Rc>, + [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies, [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, [] fn is_mir_available: IsMirAvailable(DefId) -> bool, @@ -1402,7 +1401,7 @@ define_maps! { <'tcx> [] fn get_lang_items: get_lang_items_node(CrateNum) -> Rc, [] fn defined_lang_items: DefinedLangItems(CrateNum) -> Rc>, [] fn missing_lang_items: MissingLangItems(CrateNum) -> Rc>, - [] fn extern_const_body: ExternConstBody(DefId) -> &'tcx hir::Body, + [] fn extern_const_body: ExternConstBody(DefId) -> ExternConstBody<'tcx>, [] fn visible_parent_map: visible_parent_map_node(CrateNum) -> Rc>, [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 61eb5dfd18b..7520c6ac652 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -34,7 +34,6 @@ use syntax_pos::Span; use std::cmp::Ordering; use rustc_const_math::*; - macro_rules! signal { ($e:expr, $exn:expr) => { return Err(ConstEvalErr { span: $e.span, kind: $exn }) @@ -366,7 +365,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } else { if tcx.is_const_fn(def_id) { - tcx.extern_const_body(def_id) + tcx.extern_const_body(def_id).body } else { signal!(e, TypeckError) } @@ -790,7 +789,7 @@ fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.mir_const_qualif(def_id); tcx.hir.body(tcx.hir.body_owned_by(id)) } else { - tcx.extern_const_body(def_id) + tcx.extern_const_body(def_id).body }; ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value) } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index a87fa0c2746..7586ad5a75f 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -607,7 +607,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { self.tcx.hir.body(self.tcx.hir.body_owned_by(id)) } else { - self.tcx.extern_const_body(def_id) + self.tcx.extern_const_body(def_id).body }; let pat = self.lower_const_expr(&body.value, pat_id, span); self.tables = old_tables; diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index ade2612855e..3bc281e5486 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -16,26 +16,46 @@ use schema::*; use rustc::hir; use rustc::ty::{self, TyCtxt}; +use rustc::ich::{StableHashingContext, Fingerprint}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; + #[derive(RustcEncodable, RustcDecodable)] pub struct Ast<'tcx> { pub body: Lazy, pub tables: Lazy>, pub nested_bodies: LazySeq, pub rvalue_promotable_to_static: bool, + pub stable_bodies_hash: Fingerprint, } impl_stable_hash_for!(struct Ast<'tcx> { body, tables, nested_bodies, - rvalue_promotable_to_static + rvalue_promotable_to_static, + stable_bodies_hash }); impl<'a, 'b, 'tcx> IsolatedEncoder<'a, 'b, 'tcx> { pub fn encode_body(&mut self, body_id: hir::BodyId) -> Lazy> { let body = self.tcx.hir.body(body_id); - let lazy_body = self.lazy(body); + // In order to avoid having to hash hir::Bodies from extern crates, we + // hash them here, during export, and store the hash with metadata. + let stable_bodies_hash = { + let mut hcx = StableHashingContext::new(self.tcx); + let mut hasher = StableHasher::new(); + + hcx.while_hashing_hir_bodies(true, |hcx| { + hcx.while_hashing_spans(false, |hcx| { + body.hash_stable(hcx, &mut hasher); + }); + }); + + hasher.finish() + }; + + let lazy_body = self.lazy(body); let tables = self.tcx.body_tables(body_id); let lazy_tables = self.lazy(tables); @@ -54,6 +74,7 @@ impl<'a, 'b, 'tcx> IsolatedEncoder<'a, 'b, 'tcx> { tables: lazy_tables, nested_bodies: lazy_nested_bodies, rvalue_promotable_to_static, + stable_bodies_hash, }) } } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index e4de27ee15e..78c44c7e45c 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -159,7 +159,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, is_exported_symbol => { cdata.exported_symbols.contains(&def_id.index) } - item_body_nested_bodies => { Rc::new(cdata.item_body_nested_bodies(def_id.index)) } + item_body_nested_bodies => { cdata.item_body_nested_bodies(def_id.index) } const_is_rvalue_promotable_to_static => { cdata.const_is_rvalue_promotable_to_static(def_id.index) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 4696759817f..65cf15e5a0e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -17,9 +17,11 @@ use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc::hir; use rustc::middle::const_val::ByteArray; -use rustc::middle::cstore::LinkagePreference; +use rustc::middle::cstore::{LinkagePreference, ExternConstBody, + ExternBodyNestedBodies}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc::ich::Fingerprint; use rustc::middle::lang_items; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; @@ -775,12 +777,16 @@ impl<'a, 'tcx> CrateMetadata { pub fn extern_const_body(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) - -> &'tcx hir::Body { + -> ExternConstBody<'tcx> { assert!(!self.is_proc_macro(id)); let ast = self.entry(id).ast.unwrap(); let def_id = self.local_def_id(id); - let body = ast.decode((self, tcx)).body.decode((self, tcx)); - tcx.hir.intern_inlined_body(def_id, body) + let ast = ast.decode((self, tcx)); + let body = ast.body.decode((self, tcx)); + ExternConstBody { + body: tcx.hir.intern_inlined_body(def_id, body), + fingerprint: ast.stable_bodies_hash, + } } pub fn item_body_tables(&self, @@ -791,10 +797,23 @@ impl<'a, 'tcx> CrateMetadata { tcx.alloc_tables(ast.tables.decode((self, tcx))) } - pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap { - self.entry(id).ast.into_iter().flat_map(|ast| { - ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body)) - }).collect() + pub fn item_body_nested_bodies(&self, id: DefIndex) -> ExternBodyNestedBodies { + if let Some(ref ast) = self.entry(id).ast { + let ast = ast.decode(self); + let nested_bodies: BTreeMap<_, _> = ast.nested_bodies + .decode(self) + .map(|body| (body.id(), body)) + .collect(); + ExternBodyNestedBodies { + nested_bodies: Rc::new(nested_bodies), + fingerprint: ast.stable_bodies_hash, + } + } else { + ExternBodyNestedBodies { + nested_bodies: Rc::new(BTreeMap::new()), + fingerprint: Fingerprint::zero(), + } + } } pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 7f5d11ba5de..3a4dcc32173 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -474,9 +474,9 @@ impl hir::print::PpAnn for InlinedConst { } pub fn print_inlined_const(cx: &DocContext, did: DefId) -> String { - let body = cx.tcx.extern_const_body(did); + let body = cx.tcx.extern_const_body(did).body; let inlined = InlinedConst { - nested_bodies: cx.tcx.item_body_nested_bodies(did) + nested_bodies: cx.tcx.item_body_nested_bodies(did).nested_bodies }; hir::print::to_string(&inlined, |s| s.print_expr(&body.value)) }