diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 809d5db3071d7..dca9ebb3397a6 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -394,6 +394,10 @@ impl Definitions { } } + pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { + self.node_to_hir_id[node_id] + } + /// Add a definition with a parent definition. pub fn create_def_with_parent(&mut self, parent: Option, diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs new file mode 100644 index 0000000000000..73d81212cd77e --- /dev/null +++ b/src/librustc/ich/hcx.rs @@ -0,0 +1,300 @@ +// Copyright 2017 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. + +use hir; +use hir::def_id::DefId; +use ich::{self, CachingCodemapView, DefPathHashes}; +use session::config::DebugInfoLevel::NoDebugInfo; +use ty; + +use std::hash as std_hash; + +use syntax::ast; +use syntax::attr; +use syntax::ext::hygiene::SyntaxContext; +use syntax::symbol::Symbol; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +/// This is the context state available during incr. comp. hashing. It contains +/// enough information to transform DefIds and HirIds into stable DefPaths (i.e. +/// a reference to the TyCtxt) and it holds a few caches for speeding up various +/// things (e.g. each DefId/DefPath is only hashed once). +pub struct StableHashingContext<'a, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + def_path_hashes: DefPathHashes<'a, 'tcx>, + codemap: CachingCodemapView<'tcx>, + hash_spans: bool, + hash_bodies: bool, + overflow_checks_enabled: bool, + node_id_hashing_mode: NodeIdHashingMode, + // A sorted array of symbol keys for fast lookup. + ignored_attr_names: Vec, +} + +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum NodeIdHashingMode { + Ignore, + HashDefPath, + HashTraitsInScope, +} + +impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { + + pub fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Self { + let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo; + let check_overflow_initial = tcx.sess.overflow_checks(); + + let mut ignored_attr_names: Vec<_> = ich::IGNORED_ATTRIBUTES + .iter() + .map(|&s| Symbol::intern(s)) + .collect(); + + ignored_attr_names.sort(); + + StableHashingContext { + tcx: tcx, + def_path_hashes: DefPathHashes::new(tcx), + codemap: CachingCodemapView::new(tcx), + hash_spans: hash_spans_initial, + hash_bodies: true, + overflow_checks_enabled: check_overflow_initial, + node_id_hashing_mode: NodeIdHashingMode::HashDefPath, + ignored_attr_names: ignored_attr_names, + } + } + + #[inline] + pub fn while_hashing_hir_bodies(&mut self, + hash_bodies: bool, + f: F) { + let prev_hash_bodies = self.hash_bodies; + self.hash_bodies = hash_bodies; + f(self); + self.hash_bodies = prev_hash_bodies; + } + + #[inline] + pub fn while_hashing_spans(&mut self, + hash_spans: bool, + f: F) { + let prev_hash_spans = self.hash_spans; + self.hash_spans = hash_spans; + f(self); + self.hash_spans = prev_hash_spans; + } + + #[inline] + pub fn with_node_id_hashing_mode(&mut self, + mode: NodeIdHashingMode, + f: F) { + let prev = self.node_id_hashing_mode; + self.node_id_hashing_mode = mode; + f(self); + self.node_id_hashing_mode = prev; + } + + #[inline] + pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + #[inline] + pub fn def_path_hash(&mut self, def_id: DefId) -> u64 { + self.def_path_hashes.hash(def_id) + } + + #[inline] + pub fn hash_spans(&self) -> bool { + self.hash_spans + } + + #[inline] + pub fn hash_bodies(&self) -> bool { + self.hash_bodies + } + + #[inline] + pub fn codemap(&mut self) -> &mut CachingCodemapView<'tcx> { + &mut self.codemap + } + + #[inline] + pub fn is_ignored_attr(&self, name: Symbol) -> bool { + self.ignored_attr_names.binary_search(&name).is_ok() + } + + pub fn hash_hir_item_like(&mut self, + item_attrs: &[ast::Attribute], + f: F) { + let prev_overflow_checks = self.overflow_checks_enabled; + if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { + self.overflow_checks_enabled = true; + } + let prev_hash_node_ids = self.node_id_hashing_mode; + self.node_id_hashing_mode = NodeIdHashingMode::Ignore; + + f(self); + + self.node_id_hashing_mode = prev_hash_node_ids; + self.overflow_checks_enabled = prev_overflow_checks; + } + + #[inline] + pub fn binop_can_panic_at_runtime(&self, binop: hir::BinOp_) -> bool + { + match binop { + hir::BiAdd | + hir::BiSub | + hir::BiMul => self.overflow_checks_enabled, + + hir::BiDiv | + hir::BiRem => true, + + hir::BiAnd | + hir::BiOr | + hir::BiBitXor | + hir::BiBitAnd | + hir::BiBitOr | + hir::BiShl | + hir::BiShr | + hir::BiEq | + hir::BiLt | + hir::BiLe | + hir::BiNe | + hir::BiGe | + hir::BiGt => false + } + } + + #[inline] + pub fn unop_can_panic_at_runtime(&self, unop: hir::UnOp) -> bool + { + match unop { + hir::UnDeref | + hir::UnNot => false, + hir::UnNeg => self.overflow_checks_enabled, + } + } +} + + +impl<'a, 'tcx> HashStable> for ast::NodeId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + match hcx.node_id_hashing_mode { + NodeIdHashingMode::Ignore => { + // Most NodeIds in the HIR can be ignored, but if there is a + // corresponding entry in the `trait_map` we need to hash that. + // Make sure we don't ignore too much by checking that there is + // no entry in a debug_assert!(). + debug_assert!(hcx.tcx.trait_map.get(self).is_none()); + } + NodeIdHashingMode::HashDefPath => { + hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher); + } + NodeIdHashingMode::HashTraitsInScope => { + if let Some(traits) = hcx.tcx.trait_map.get(self) { + // The ordering of the candidates is not fixed. So we hash + // the def-ids and then sort them and hash the collection. + let mut candidates: AccumulateVec<[_; 8]> = + traits.iter() + .map(|&hir::TraitCandidate { def_id, import_id: _ }| { + hcx.def_path_hash(def_id) + }) + .collect(); + if traits.len() > 1 { + candidates.sort(); + } + candidates.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable> for Span { + + // Hash a span in a stable way. We can't directly hash the span's BytePos + // fields (that would be similar to hashing pointers, since those are just + // offsets into the CodeMap). Instead, we hash the (file name, line, column) + // triple, which stays the same even if the containing FileMap has moved + // within the CodeMap. + // Also note that we are hashing byte offsets for the column, not unicode + // codepoint offsets. For the purpose of the hash that's sufficient. + // Also, hashing filenames is expensive so we avoid doing it twice when the + // span starts and ends in the same file, which is almost always the case. + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use syntax_pos::Pos; + + if !hcx.hash_spans { + return + } + + // If this is not an empty or invalid span, we want to hash the last + // position that belongs to it, as opposed to hashing the first + // position past it. + let span_hi = if self.hi > self.lo { + // We might end up in the middle of a multibyte character here, + // but that's OK, since we are not trying to decode anything at + // this position. + self.hi - ::syntax_pos::BytePos(1) + } else { + self.hi + }; + + { + let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo); + let loc1 = loc1.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi); + let loc2 = loc2.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + if loc1.0 == loc2.0 { + std_hash::Hash::hash(&0u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + // Do not hash the file name twice + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } else { + std_hash::Hash::hash(&1u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + std_hash::Hash::hash(loc2.0, hasher); + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } + } + + if self.ctxt == SyntaxContext::empty() { + 0u8.hash_stable(hcx, hasher); + } else { + 1u8.hash_stable(hcx, hasher); + self.source_callsite().hash_stable(hcx, hasher); + } + } +} diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs new file mode 100644 index 0000000000000..6d11f2a87a413 --- /dev/null +++ b/src/librustc/ich/impls_const_math.rs @@ -0,0 +1,71 @@ +// Copyright 2017 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. + +//! This module contains `HashStable` implementations for various data types +//! from `rustc_const_math` in no particular order. + +impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat { + F32(val), + F64(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstInt { + I8(val), + I16(val), + I32(val), + I64(val), + I128(val), + Isize(val), + U8(val), + U16(val), + U32(val), + U64(val), + U128(val), + Usize(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize { + Is16(i16), + Is32(i32), + Is64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize { + Us16(i16), + Us32(i32), + Us64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr { + NotInRange, + CmpBetweenUnequalTypes, + UnequalTypes(op), + Overflow(op), + ShiftNegative, + DivisionByZero, + RemainderByZero, + UnsignedNegation, + ULitOutOfRange(int_ty), + LitOutOfRange(int_ty) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::Op { + Add, + Sub, + Mul, + Div, + Rem, + Shr, + Shl, + Neg, + BitAnd, + BitOr, + BitXor +}); diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs new file mode 100644 index 0000000000000..9216fb41745c4 --- /dev/null +++ b/src/librustc/ich/impls_hir.rs @@ -0,0 +1,1107 @@ +// Copyright 2017 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. + +//! This module contains `HashStable` implementations for various HIR data +//! types in no particular order. + +use hir; +use hir::def_id::DefId; +use ich::{StableHashingContext, NodeIdHashingMode}; +use std::mem; + +use syntax::ast; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; + +impl<'a, 'tcx> HashStable> for DefId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.def_path_hash(*self).hash_stable(hcx, hasher); + } +} + + +impl<'a, 'tcx> HashStable> for hir::HirId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::HirId { + owner, + local_id, + } = *self; + + hcx.def_path_hash(DefId::local(owner)).hash_stable(hcx, hasher); + local_id.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); + +// The following implementations of HashStable for ItemId, TraitItemId, and +// ImplItemId deserve special attention. Normally we do not hash NodeIds within +// the HIR, since they just signify a HIR nodes own path. But ItemId et al +// are used when another item in the HIR is *referenced* and we certainly +// want to pick up on a reference changing its target, so we hash the NodeIds +// in "DefPath Mode". + +impl<'a, 'tcx> HashStable> for hir::ItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ItemId { + id + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable> for hir::TraitItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable> for hir::ImplItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ImplItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(struct hir::Lifetime { + id, + span, + name +}); + +impl_stable_hash_for!(struct hir::LifetimeDef { + lifetime, + bounds, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Path { + span, + def, + segments +}); + +impl_stable_hash_for!(struct hir::PathSegment { + name, + parameters +}); + +impl_stable_hash_for!(enum hir::PathParameters { + AngleBracketedParameters(data), + ParenthesizedParameters(data) +}); + +impl_stable_hash_for!(struct hir::AngleBracketedParameterData { + lifetimes, + types, + infer_types, + bindings +}); + +impl_stable_hash_for!(struct hir::ParenthesizedParameterData { + span, + inputs, + output +}); + +impl_stable_hash_for!(enum hir::TyParamBound { + TraitTyParamBound(poly_trait_ref, trait_bound_modifier), + RegionTyParamBound(lifetime) +}); + +impl_stable_hash_for!(enum hir::TraitBoundModifier { + None, + Maybe +}); + +impl_stable_hash_for!(struct hir::TyParam { + name, + id, + bounds, + default, + span, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Generics { + lifetimes, + ty_params, + where_clause, + span +}); + +impl_stable_hash_for!(struct hir::WhereClause { + id, + predicates +}); + +impl_stable_hash_for!(enum hir::WherePredicate { + BoundPredicate(pred), + RegionPredicate(pred), + EqPredicate(pred) +}); + +impl_stable_hash_for!(struct hir::WhereBoundPredicate { + span, + bound_lifetimes, + bounded_ty, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereRegionPredicate { + span, + lifetime, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereEqPredicate { + id, + span, + lhs_ty, + rhs_ty +}); + +impl_stable_hash_for!(struct hir::MutTy { + ty, + mutbl +}); + +impl_stable_hash_for!(struct hir::MethodSig { + unsafety, + constness, + abi, + decl, + generics +}); + +impl_stable_hash_for!(struct hir::TypeBinding { + id, + name, + ty, + span +}); + +impl<'a, 'tcx> HashStable> for hir::Ty { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::TySlice(..) | + hir::TyArray(..) | + hir::TyPtr(..) | + hir::TyRptr(..) | + hir::TyBareFn(..) | + hir::TyNever | + hir::TyTup(..) | + hir::TyTraitObject(..) | + hir::TyImplTrait(..) | + hir::TyTypeof(..) | + hir::TyInfer => { + NodeIdHashingMode::Ignore + } + hir::TyPath(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Ty { + id, + ref node, + ref span, + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(enum hir::PrimTy { + TyInt(int_ty), + TyUint(uint_ty), + TyFloat(float_ty), + TyStr, + TyBool, + TyChar +}); + +impl_stable_hash_for!(struct hir::BareFnTy { + unsafety, + abi, + lifetimes, + decl +}); + +impl_stable_hash_for!(enum hir::Ty_ { + TySlice(t), + TyArray(t, body_id), + TyPtr(t), + TyRptr(lifetime, t), + TyBareFn(t), + TyNever, + TyTup(ts), + TyPath(qpath), + TyTraitObject(trait_refs, lifetime), + TyImplTrait(bounds), + TyTypeof(body_id), + TyInfer +}); + +impl_stable_hash_for!(struct hir::FnDecl { + inputs, + output, + variadic, + has_implicit_self +}); + +impl_stable_hash_for!(enum hir::FunctionRetTy { + DefaultReturn(span), + Return(t) +}); + +impl<'a, 'tcx> HashStable> for hir::TraitRef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitRef { + ref path, + ref_id, + } = *self; + + path.hash_stable(hcx, hasher); + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + ref_id.hash_stable(hcx, hasher); + }); + } +} + + +impl_stable_hash_for!(struct hir::PolyTraitRef { + bound_lifetimes, + trait_ref, + span +}); + +impl_stable_hash_for!(enum hir::QPath { + Resolved(t, path), + TypeRelative(t, path_segment) +}); + +impl_stable_hash_for!(struct hir::MacroDef { + name, + attrs, + id, + span, + body +}); + + +impl<'a, 'tcx> HashStable> for hir::Block { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::Block { + ref stmts, + ref expr, + id, + rules, + span, + break_to_expr_id, + } = *self; + + let non_item_stmts = || stmts.iter().filter(|stmt| { + match stmt.node { + hir::StmtDecl(ref decl, _) => { + match decl.node { + // If this is a declaration of a nested item, we don't + // want to leave any trace of it in the hash value, not + // even that it exists. Otherwise changing the position + // of nested items would invalidate the containing item + // even though that does not constitute a semantic + // change. + hir::DeclItem(_) => false, + hir::DeclLocal(_) => true + } + } + hir::StmtExpr(..) | + hir::StmtSemi(..) => true + } + }); + + let count = non_item_stmts().count(); + + count.hash_stable(hcx, hasher); + + for stmt in non_item_stmts() { + stmt.hash_stable(hcx, hasher); + } + + expr.hash_stable(hcx, hasher); + id.hash_stable(hcx, hasher); + rules.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + break_to_expr_id.hash_stable(hcx, hasher); + }); + } +} + +impl<'a, 'tcx> HashStable> for hir::Pat { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::PatKind::Wild | + hir::PatKind::Binding(..) | + hir::PatKind::Tuple(..) | + hir::PatKind::Box(..) | + hir::PatKind::Ref(..) | + hir::PatKind::Lit(..) | + hir::PatKind::Range(..) | + hir::PatKind::Slice(..) => { + NodeIdHashingMode::Ignore + } + hir::PatKind::Path(..) | + hir::PatKind::Struct(..) | + hir::PatKind::TupleStruct(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Pat { + id, + ref node, + ref span + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for_spanned!(hir::FieldPat); +impl_stable_hash_for!(struct hir::FieldPat { + name, + pat, + is_shorthand +}); + +impl_stable_hash_for!(enum hir::BindingMode { + BindByRef(mutability), + BindByValue(mutability) +}); + +impl_stable_hash_for!(enum hir::RangeEnd { + Included, + Excluded +}); + +impl_stable_hash_for!(enum hir::PatKind { + Wild, + Binding(binding_mode, var, name, sub), + Struct(path, field_pats, dotdot), + TupleStruct(path, field_pats, dotdot), + Path(path), + Tuple(field_pats, dotdot), + Box(sub), + Ref(sub, mutability), + Lit(expr), + Range(start, end, end_kind), + Slice(one, two, three) +}); + +impl_stable_hash_for!(enum hir::BinOp_ { + BiAdd, + BiSub, + BiMul, + BiDiv, + BiRem, + BiAnd, + BiOr, + BiBitXor, + BiBitAnd, + BiBitOr, + BiShl, + BiShr, + BiEq, + BiLt, + BiLe, + BiNe, + BiGe, + BiGt +}); + +impl_stable_hash_for_spanned!(hir::BinOp_); + +impl_stable_hash_for!(enum hir::UnOp { + UnDeref, + UnNot, + UnNeg +}); + +impl_stable_hash_for_spanned!(hir::Stmt_); + +impl_stable_hash_for!(struct hir::Local { + pat, + ty, + init, + id, + span, + attrs +}); + +impl_stable_hash_for_spanned!(hir::Decl_); +impl_stable_hash_for!(enum hir::Decl_ { + DeclLocal(local), + DeclItem(item_id) +}); + +impl_stable_hash_for!(struct hir::Arm { + attrs, + pats, + guard, + body +}); + +impl_stable_hash_for!(struct hir::Field { + name, + expr, + span, + is_shorthand +}); + +impl_stable_hash_for_spanned!(ast::Name); + + +impl_stable_hash_for!(enum hir::BlockCheckMode { + DefaultBlock, + UnsafeBlock(src), + PushUnsafeBlock(src), + PopUnsafeBlock(src) +}); + +impl_stable_hash_for!(enum hir::UnsafeSource { + CompilerGenerated, + UserProvided +}); + +impl<'a, 'tcx> HashStable> for hir::Expr { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Expr { + id, + ref span, + ref node, + ref attrs + } = *self; + + let (spans_always_on, node_id_hashing_mode) = match *node { + hir::ExprBox(..) | + hir::ExprArray(..) | + hir::ExprCall(..) | + hir::ExprLit(..) | + hir::ExprCast(..) | + hir::ExprType(..) | + hir::ExprIf(..) | + hir::ExprWhile(..) | + hir::ExprLoop(..) | + hir::ExprMatch(..) | + hir::ExprClosure(..) | + hir::ExprBlock(..) | + hir::ExprAssign(..) | + hir::ExprTupField(..) | + hir::ExprAddrOf(..) | + hir::ExprBreak(..) | + hir::ExprAgain(..) | + hir::ExprRet(..) | + hir::ExprInlineAsm(..) | + hir::ExprRepeat(..) | + hir::ExprTup(..) => { + // For these we only hash the span when debuginfo is on. + (false, NodeIdHashingMode::Ignore) + } + // For the following, spans might be significant because of + // panic messages indicating the source location. + hir::ExprBinary(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprUnary(op, _) => { + (hcx.unop_can_panic_at_runtime(op), NodeIdHashingMode::Ignore) + } + hir::ExprAssignOp(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprIndex(..) => { + (true, NodeIdHashingMode::Ignore) + } + // For these we don't care about the span, but want to hash the + // trait in scope + hir::ExprMethodCall(..) | + hir::ExprPath(..) | + hir::ExprStruct(..) | + hir::ExprField(..) => { + (false, NodeIdHashingMode::HashTraitsInScope) + } + }; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + + if spans_always_on { + hcx.while_hashing_spans(true, |hcx| { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + }); + } else { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + } + }) + } +} + +impl_stable_hash_for!(enum hir::Expr_ { + ExprBox(sub), + ExprArray(subs), + ExprCall(callee, args), + ExprMethodCall(name, ts, args), + ExprTup(fields), + ExprBinary(op, lhs, rhs), + ExprUnary(op, operand), + ExprLit(value), + ExprCast(expr, t), + ExprType(expr, t), + ExprIf(cond, then, els), + ExprWhile(cond, body, label), + ExprLoop(body, label, loop_src), + ExprMatch(matchee, arms, match_src), + ExprClosure(capture_clause, decl, body_id, span), + ExprBlock(blk), + ExprAssign(lhs, rhs), + ExprAssignOp(op, lhs, rhs), + ExprField(owner, field_name), + ExprTupField(owner, idx), + ExprIndex(lhs, rhs), + ExprPath(path), + ExprAddrOf(mutability, sub), + ExprBreak(destination, sub), + ExprAgain(destination), + ExprRet(val), + ExprInlineAsm(asm, inputs, outputs), + ExprStruct(path, fields, base), + ExprRepeat(val, times) +}); + +impl_stable_hash_for!(enum hir::LoopSource { + Loop, + WhileLet, + ForLoop +}); + +impl<'a, 'tcx> HashStable> for hir::MatchSource { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use hir::MatchSource; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + MatchSource::Normal | + MatchSource::WhileLetDesugar | + MatchSource::ForLoopDesugar | + MatchSource::TryDesugar => { + // No fields to hash. + } + MatchSource::IfLetDesugar { contains_else_clause } => { + contains_else_clause.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::CaptureClause { + CaptureByValue, + CaptureByRef +}); + +impl_stable_hash_for_spanned!(usize); + +impl_stable_hash_for!(struct hir::Destination { + ident, + target_id +}); + +impl_stable_hash_for_spanned!(ast::Ident); + +impl_stable_hash_for!(enum hir::LoopIdResult { + Ok(node_id), + Err(loop_id_error) +}); + +impl_stable_hash_for!(enum hir::LoopIdError { + OutsideLoopScope, + UnlabeledCfInWhileCondition, + UnresolvedLabel +}); + +impl_stable_hash_for!(enum hir::ScopeTarget { + Block(node_id), + Loop(loop_id_result) +}); + +impl<'a, 'tcx> HashStable> for ast::Ident { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ast::Ident { + ref name, + ctxt: _ // Ignore this + } = *self; + + name.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for hir::TraitItem { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitItem { + id, + name, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::TraitMethod { + Required(name), + Provided(body) +}); + +impl_stable_hash_for!(enum hir::TraitItemKind { + Const(t, body), + Method(sig, method), + Type(bounds, rhs) +}); + +impl<'a, 'tcx> HashStable> for hir::ImplItem { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ImplItem { + id, + name, + ref vis, + defaultness, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + defaultness.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::ImplItemKind { + Const(t, body), + Method(sig, body), + Type(t) +}); + +impl<'a, 'tcx> HashStable> for hir::Visibility { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Visibility::Public | + hir::Visibility::Crate | + hir::Visibility::Inherited => { + // No fields to hash. + } + hir::Visibility::Restricted { ref path, id } => { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + id.hash_stable(hcx, hasher); + }); + path.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for hir::Defaultness { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Defaultness::Final => { + // No fields to hash. + } + hir::Defaultness::Default { has_value } => { + has_value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::ImplPolarity { + Positive, + Negative +}); + +impl<'a, 'tcx> HashStable> for hir::Mod { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::Mod { + inner, + // We are not hashing the IDs of the items contained in the module. + // This is harmless and matches the current behavior but it's not + // actually correct. See issue #40876. + item_ids: _, + } = *self; + + inner.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::ForeignMod { + abi, + items +}); + +impl_stable_hash_for!(struct hir::EnumDef { + variants +}); + +impl_stable_hash_for!(struct hir::Variant_ { + name, + attrs, + data, + disr_expr +}); + +impl_stable_hash_for_spanned!(hir::Variant_); + +impl_stable_hash_for!(enum hir::UseKind { + Single, + Glob, + ListStem +}); + +impl_stable_hash_for!(struct hir::StructField { + span, + name, + vis, + id, + ty, + attrs +}); + +impl_stable_hash_for!(enum hir::VariantData { + Struct(fields, id), + Tuple(fields, id), + Unit(id) +}); + +impl<'a, 'tcx> HashStable> for hir::Item { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::ItemExternCrate(..) | + hir::ItemStatic(..) | + hir::ItemConst(..) | + hir::ItemFn(..) | + hir::ItemMod(..) | + hir::ItemForeignMod(..) | + hir::ItemTy(..) | + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemTrait(..) | + hir::ItemDefaultImpl(..) | + hir::ItemImpl(..) => { + NodeIdHashingMode::Ignore + } + hir::ItemUse(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Item { + name, + ref attrs, + id, + ref node, + ref vis, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::Item_ { + ItemExternCrate(name), + ItemUse(path, use_kind), + ItemStatic(ty, mutability, body_id), + ItemConst(ty, body_id), + ItemFn(fn_decl, unsafety, constness, abi, generics, body_id), + ItemMod(module), + ItemForeignMod(foreign_mod), + ItemTy(ty, generics), + ItemEnum(enum_def, generics), + ItemStruct(variant_data, generics), + ItemUnion(variant_data, generics), + ItemTrait(unsafety, generics, bounds, item_refs), + ItemDefaultImpl(unsafety, trait_ref), + ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs) +}); + +impl_stable_hash_for!(struct hir::TraitItemRef { + id, + name, + kind, + span, + defaultness +}); + +impl_stable_hash_for!(struct hir::ImplItemRef { + id, + name, + kind, + span, + vis, + defaultness +}); + +impl<'a, 'tcx> HashStable> for hir::AssociatedItemKind { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::AssociatedItemKind::Const | + hir::AssociatedItemKind::Type => { + // No fields to hash. + } + hir::AssociatedItemKind::Method { has_self } => { + has_self.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct hir::ForeignItem { + name, + attrs, + node, + id, + span, + vis +}); + +impl_stable_hash_for!(enum hir::ForeignItem_ { + ForeignItemFn(fn_decl, arg_names, generics), + ForeignItemStatic(ty, is_mutbl) +}); + +impl_stable_hash_for!(enum hir::Stmt_ { + StmtDecl(decl, id), + StmtExpr(expr, id), + StmtSemi(expr, id) +}); + +impl_stable_hash_for!(struct hir::Arg { + pat, + id +}); + +impl_stable_hash_for!(struct hir::Body { + arguments, + value +}); + +impl<'a, 'tcx> HashStable> for hir::BodyId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + if hcx.hash_bodies() { + hcx.tcx().hir.body(*self).hash_stable(hcx, hasher); + } + } +} + +impl_stable_hash_for!(struct hir::InlineAsmOutput { + constraint, + is_rw, + is_indirect +}); + +impl<'a, 'tcx> HashStable> for hir::InlineAsm { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::InlineAsm { + asm, + asm_str_style, + ref outputs, + ref inputs, + ref clobbers, + volatile, + alignstack, + dialect, + ctxt: _, // This is used for error reporting + } = *self; + + asm.hash_stable(hcx, hasher); + asm_str_style.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + clobbers.hash_stable(hcx, hasher); + volatile.hash_stable(hcx, hasher); + alignstack.hash_stable(hcx, hasher); + dialect.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum hir::def::CtorKind { + Fn, + Const, + Fictive +}); + +impl_stable_hash_for!(enum hir::def::Def { + Mod(def_id), + Struct(def_id), + Union(def_id), + Enum(def_id), + Variant(def_id), + Trait(def_id), + TyAlias(def_id), + AssociatedTy(def_id), + PrimTy(prim_ty), + TyParam(def_id), + SelfTy(trait_def_id, impl_def_id), + Fn(def_id), + Const(def_id), + Static(def_id, is_mutbl), + StructCtor(def_id, ctor_kind), + VariantCtor(def_id, ctor_kind), + Method(def_id), + AssociatedConst(def_id), + Local(def_id), + Upvar(def_id, index, expr_id), + Label(node_id), + Macro(def_id, macro_kind), + Err +}); + +impl_stable_hash_for!(enum hir::Mutability { + MutMutable, + MutImmutable +}); + + +impl_stable_hash_for!(enum hir::Unsafety { + Unsafe, + Normal +}); + + +impl_stable_hash_for!(enum hir::Constness { + Const, + NotConst +}); + +impl<'a, 'tcx> HashStable> for hir::def_id::DefIndex { + + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + DefId::local(*self).hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::def::Export { + name, + def, + span +}); diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs new file mode 100644 index 0000000000000..401f7e1921ab4 --- /dev/null +++ b/src/librustc/ich/impls_mir.rs @@ -0,0 +1,407 @@ +// Copyright 2017 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. + +//! This module contains `HashStable` implementations for various MIR data +//! types in no particular order. + +use ich::StableHashingContext; +use mir; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::mem; + + +impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); +impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); +impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); +impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer }); +impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info }); +impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); +impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); +impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable> for mir::Local { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::BasicBlock { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::Field { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::VisibilityScope { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::Promoted { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::TerminatorKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::TerminatorKind::Goto { ref target } => { + target.hash_stable(hcx, hasher); + } + mir::TerminatorKind::SwitchInt { ref discr, + switch_ty, + ref values, + ref targets } => { + discr.hash_stable(hcx, hasher); + switch_ty.hash_stable(hcx, hasher); + values.hash_stable(hcx, hasher); + targets.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Resume | + mir::TerminatorKind::Return | + mir::TerminatorKind::Unreachable => {} + mir::TerminatorKind::Drop { ref location, target, unwind } => { + location.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::DropAndReplace { ref location, + ref value, + target, + unwind, } => { + location.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Call { ref func, + ref args, + ref destination, + cleanup } => { + func.hash_stable(hcx, hasher); + args.hash_stable(hcx, hasher); + destination.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Assert { ref cond, + expected, + ref msg, + target, + cleanup } => { + cond.hash_stable(hcx, hasher); + expected.hash_stable(hcx, hasher); + msg.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::AssertMessage<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::AssertMessage::BoundsCheck { ref len, ref index } => { + len.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + } + mir::AssertMessage::Math(ref const_math_err) => { + const_math_err.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable> for mir::StatementKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::StatementKind::Assign(ref lvalue, ref rvalue) => { + lvalue.hash_stable(hcx, hasher); + rvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::SetDiscriminant { ref lvalue, variant_index } => { + lvalue.hash_stable(hcx, hasher); + variant_index.hash_stable(hcx, hasher); + } + mir::StatementKind::StorageLive(ref lvalue) | + mir::StatementKind::StorageDead(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::Nop => {} + mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { + asm.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::Lvalue<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Lvalue::Local(ref local) => { + local.hash_stable(hcx, hasher); + } + mir::Lvalue::Static(ref statik) => { + statik.hash_stable(hcx, hasher); + } + mir::Lvalue::Projection(ref lvalue_projection) => { + lvalue_projection.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx, B, V> HashStable> for mir::Projection<'tcx, B, V> + where B: HashStable>, + V: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let mir::Projection { + ref base, + ref elem, + } = *self; + + base.hash_stable(hcx, hasher); + elem.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx, V> HashStable> for mir::ProjectionElem<'tcx, V> + where V: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::ProjectionElem::Deref => {} + mir::ProjectionElem::Field(field, ty) => { + field.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Index(ref value) => { + value.hash_stable(hcx, hasher); + } + mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + offset.hash_stable(hcx, hasher); + min_length.hash_stable(hcx, hasher); + from_end.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Subslice { from, to } => { + from.hash_stable(hcx, hasher); + to.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Downcast(adt_def, variant) => { + adt_def.hash_stable(hcx, hasher); + variant.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope }); + +impl<'a, 'tcx> HashStable> for mir::Operand<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Operand::Consume(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Operand::Constant(ref constant) => { + constant.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::Rvalue<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Rvalue::Use(ref operand) => { + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Repeat(ref operand, ref val) => { + operand.hash_stable(hcx, hasher); + val.hash_stable(hcx, hasher); + } + mir::Rvalue::Ref(region, borrow_kind, ref lvalue) => { + region.hash_stable(hcx, hasher); + borrow_kind.hash_stable(hcx, hasher); + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Len(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Cast(cast_kind, ref operand, ty) => { + cast_kind.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::BinaryOp(op, ref operand1, ref operand2) | + mir::Rvalue::CheckedBinaryOp(op, ref operand1, ref operand2) => { + op.hash_stable(hcx, hasher); + operand1.hash_stable(hcx, hasher); + operand2.hash_stable(hcx, hasher); + } + mir::Rvalue::UnaryOp(op, ref operand) => { + op.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Discriminant(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Box(ty) => { + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::Aggregate(ref kind, ref operands) => { + kind.hash_stable(hcx, hasher); + operands.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::CastKind { + Misc, + ReifyFnPointer, + ClosureFnPointer, + UnsafeFnPointer, + Unsize +}); + +impl<'a, 'tcx> HashStable> for mir::AggregateKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::AggregateKind::Tuple => {} + mir::AggregateKind::Array(t) => { + t.hash_stable(hcx, hasher); + } + mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => { + adt_def.hash_stable(hcx, hasher); + idx.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + active_field.hash_stable(hcx, hasher); + } + mir::AggregateKind::Closure(def_id, ref substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::BinOp { + Add, + Sub, + Mul, + Div, + Rem, + BitXor, + BitAnd, + BitOr, + Shl, + Shr, + Eq, + Lt, + Le, + Ne, + Ge, + Gt +}); + +impl_stable_hash_for!(enum mir::UnOp { + Not, + Neg +}); + + +impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); + +impl<'a, 'tcx> HashStable> for mir::Literal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Literal::Item { def_id, substs } => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + mir::Literal::Value { ref value } => { + value.hash_stable(hcx, hasher); + } + mir::Literal::Promoted { index } => { + index.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Location { block, statement_index }); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs new file mode 100644 index 0000000000000..26734500001f6 --- /dev/null +++ b/src/librustc/ich/impls_syntax.rs @@ -0,0 +1,301 @@ +// Copyright 2017 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. + +//! This module contains `HashStable` implementations for various data types +//! from libsyntax in no particular order. + +use ich::StableHashingContext; + +use std::hash as std_hash; +use std::mem; + +use syntax::ast; +use syntax::parse::token; +use syntax::tokenstream; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +impl<'a, 'tcx> HashStable> for ::syntax::symbol::InternedString { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let s: &str = &**self; + s.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ast::Name { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.as_str().hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ::syntax::ast::AsmDialect { + Att, + Intel +}); + +impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { + Bang, + Attr, + Derive +}); + + +impl_stable_hash_for!(enum ::syntax::abi::Abi { + Cdecl, + Stdcall, + Fastcall, + Vectorcall, + Aapcs, + Win64, + SysV64, + PtxKernel, + Msp430Interrupt, + X86Interrupt, + Rust, + C, + System, + RustIntrinsic, + RustCall, + PlatformIntrinsic, + Unadjusted +}); + +impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note }); +impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr }); + +impl<'a, 'tcx> HashStable> for ::syntax::attr::StabilityLevel { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => { + reason.hash_stable(hcx, hasher); + issue.hash_stable(hcx, hasher); + } + ::syntax::attr::StabilityLevel::Stable { ref since } => { + since.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason }); + + +impl_stable_hash_for!(enum ::syntax::attr::IntType { + SignedInt(int_ty), + UnsignedInt(uint_ty) +}); + +impl_stable_hash_for!(enum ::syntax::ast::LitIntType { + Signed(int_ty), + Unsigned(int_ty), + Unsuffixed +}); + +impl_stable_hash_for_spanned!(::syntax::ast::LitKind); +impl_stable_hash_for!(enum ::syntax::ast::LitKind { + Str(value, style), + ByteStr(value), + Byte(value), + Char(value), + Int(value, lit_int_type), + Float(value, float_ty), + FloatUnsuffixed(value), + Bool(value) +}); + +impl_stable_hash_for!(enum ::syntax::ast::IntTy { Is, I8, I16, I32, I64, I128 }); +impl_stable_hash_for!(enum ::syntax::ast::UintTy { Us, U8, U16, U32, U64, U128 }); +impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 }); +impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal }); +impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst }); +impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final }); +impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, name }); +impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); +impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); + +impl<'a, 'tcx> HashStable> for [ast::Attribute] { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + // Some attributes are always ignored during hashing. + let filtered: AccumulateVec<[&ast::Attribute; 8]> = self + .iter() + .filter(|attr| { + !attr.is_sugared_doc && + attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true) + }) + .collect(); + + filtered.len().hash_stable(hcx, hasher); + for attr in filtered { + attr.hash_stable(hcx, hasher); + } + } +} + +impl<'a, 'tcx> HashStable> for ast::Attribute { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + // Make sure that these have been filtered out. + debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)); + debug_assert!(!self.is_sugared_doc); + + let ast::Attribute { + id: _, + style, + ref path, + ref tokens, + is_sugared_doc: _, + span, + } = *self; + + style.hash_stable(hcx, hasher); + path.segments.len().hash_stable(hcx, hasher); + for segment in &path.segments { + segment.identifier.name.hash_stable(hcx, hasher); + } + for tt in tokens.trees() { + tt.hash_stable(hcx, hasher); + } + span.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for tokenstream::TokenTree { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + tokenstream::TokenTree::Token(span, ref token) => { + span.hash_stable(hcx, hasher); + hash_token(token, hcx, hasher, span); + } + tokenstream::TokenTree::Delimited(span, ref delimited) => { + span.hash_stable(hcx, hasher); + std_hash::Hash::hash(&delimited.delim, hasher); + for sub_tt in delimited.stream().trees() { + sub_tt.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable> for tokenstream::TokenStream { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + for sub_tt in self.trees() { + sub_tt.hash_stable(hcx, hasher); + } + } +} + +fn hash_token<'a, 'tcx, W: StableHasherResult>(token: &token::Token, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + error_reporting_span: Span) { + mem::discriminant(token).hash_stable(hcx, hasher); + match *token { + token::Token::Eq | + token::Token::Lt | + token::Token::Le | + token::Token::EqEq | + token::Token::Ne | + token::Token::Ge | + token::Token::Gt | + token::Token::AndAnd | + token::Token::OrOr | + token::Token::Not | + token::Token::Tilde | + token::Token::At | + token::Token::Dot | + token::Token::DotDot | + token::Token::DotDotDot | + token::Token::Comma | + token::Token::Semi | + token::Token::Colon | + token::Token::ModSep | + token::Token::RArrow | + token::Token::LArrow | + token::Token::FatArrow | + token::Token::Pound | + token::Token::Dollar | + token::Token::Question | + token::Token::Underscore | + token::Token::Whitespace | + token::Token::Comment | + token::Token::Eof => {} + + token::Token::BinOp(bin_op_token) | + token::Token::BinOpEq(bin_op_token) => { + std_hash::Hash::hash(&bin_op_token, hasher); + } + + token::Token::OpenDelim(delim_token) | + token::Token::CloseDelim(delim_token) => { + std_hash::Hash::hash(&delim_token, hasher); + } + token::Token::Literal(ref lit, ref opt_name) => { + mem::discriminant(lit).hash_stable(hcx, hasher); + match *lit { + token::Lit::Byte(val) | + token::Lit::Char(val) | + token::Lit::Integer(val) | + token::Lit::Float(val) | + token::Lit::Str_(val) | + token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher), + token::Lit::StrRaw(val, n) | + token::Lit::ByteStrRaw(val, n) => { + val.hash_stable(hcx, hasher); + n.hash_stable(hcx, hasher); + } + }; + opt_name.hash_stable(hcx, hasher); + } + + token::Token::Ident(ident) | + token::Token::Lifetime(ident) | + token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher), + + token::Token::Interpolated(ref non_terminal) => { + // FIXME(mw): This could be implemented properly. It's just a + // lot of work, since we would need to hash the AST + // in a stable way, in addition to the HIR. + // Since this is hardly used anywhere, just emit a + // warning for now. + if hcx.tcx().sess.opts.debugging_opts.incremental.is_some() { + let msg = format!("Quasi-quoting might make incremental \ + compilation very inefficient: {:?}", + non_terminal); + hcx.tcx().sess.span_warn(error_reporting_span, &msg[..]); + } + + std_hash::Hash::hash(non_terminal, hasher); + } + + token::Token::DocComment(val) | + token::Token::Shebang(val) => val.hash_stable(hcx, hasher), + } +} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs new file mode 100644 index 0000000000000..7b6f3af2a11ec --- /dev/null +++ b/src/librustc/ich/impls_ty.rs @@ -0,0 +1,415 @@ +// Copyright 2017 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. + +//! This module contains `HashStable` implementations for various data types +//! from rustc::ty in no particular order. + +use ich::StableHashingContext; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::hash as std_hash; +use std::mem; +use ty; + + +impl<'a, 'tcx> HashStable> for ty::Ty<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let type_hash = hcx.tcx().type_id_hash(*self); + type_hash.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); + +impl<'a, 'tcx, T> HashStable> for ty::Slice + where T: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + (&**self).hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::subst::Kind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.as_type().hash_stable(hcx, hasher); + self.as_region().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::Region { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ReErased | + ty::ReStatic | + ty::ReEmpty => { + // No variant fields to hash for these ... + } + ty::ReLateBound(db, ty::BrAnon(i)) => { + db.depth.hash_stable(hcx, hasher); + i.hash_stable(hcx, hasher); + } + ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => { + index.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + } + ty::ReLateBound(..) | + ty::ReFree(..) | + ty::ReScope(..) | + ty::ReVar(..) | + ty::ReSkolemized(..) => { + bug!("TypeIdHasher: unexpected region {:?}", *self) + } + } + } +} + +impl<'a, 'tcx> HashStable> for ty::adjustment::AutoBorrow<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::AutoBorrow::Ref(ref region, mutability) => { + region.hash_stable(hcx, hasher); + mutability.hash_stable(hcx, hasher); + } + ty::adjustment::AutoBorrow::RawPtr(mutability) => { + mutability.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for ty::adjustment::Adjust<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::Adjust::NeverToAny | + ty::adjustment::Adjust::ReifyFnPointer | + ty::adjustment::Adjust::UnsafeFnPointer | + ty::adjustment::Adjust::ClosureFnPointer | + ty::adjustment::Adjust::MutToConstPointer => {} + ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => { + autoderefs.hash_stable(hcx, hasher); + autoref.hash_stable(hcx, hasher); + unsize.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); +impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef }); +impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs }); +impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); +impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); + +impl_stable_hash_for!(enum ty::BorrowKind { + ImmBorrow, + UniqueImmBorrow, + MutBorrow +}); + + +impl<'a, 'tcx> HashStable> for ty::UpvarCapture<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByRef(ref up_var_borrow) => { + up_var_borrow.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::FnSig<'tcx> { + inputs_and_output, + variadic, + unsafety, + abi +}); + +impl<'a, 'tcx, T> HashStable> for ty::Binder + where T: HashStable> + ty::fold::TypeFoldable<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ty::ClosureKind { Fn, FnMut, FnOnce }); + +impl_stable_hash_for!(enum ty::Visibility { + Public, + Restricted(def_id), + Invisible +}); + +impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); +impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); +impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); + +impl<'a, 'tcx, A, B> HashStable> for ty::OutlivesPredicate + where A: HashStable>, + B: HashStable>, +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::OutlivesPredicate(ref a, ref b) = *self; + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty }); +impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_name }); + + +impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::Predicate::Trait(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Equate(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::RegionOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::TypeOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Projection(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::WellFormed(ty) => { + ty.hash_stable(hcx, hasher); + } + ty::Predicate::ObjectSafe(def_id) => { + def_id.hash_stable(hcx, hasher); + } + ty::Predicate::ClosureKind(def_id, closure_kind) => { + def_id.hash_stable(hcx, hasher); + closure_kind.hash_stable(hcx, hasher); + } + } + } +} + + +impl<'a, 'tcx> HashStable> for ty::AdtFlags { + fn hash_stable(&self, + _: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + std_hash::Hash::hash(self, hasher); + } +} + +impl_stable_hash_for!(struct ty::VariantDef { + did, + name, + discr, + fields, + ctor_kind +}); + +impl_stable_hash_for!(enum ty::VariantDiscr { + Explicit(def_id), + Relative(distance) +}); + +impl_stable_hash_for!(struct ty::FieldDef { + did, + name, + vis +}); + +impl<'a, 'tcx> HashStable> +for ::middle::const_val::ConstVal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::const_val::ConstVal; + + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + ConstVal::Float(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Integral(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Str(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::ByteStr(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Bool(value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Function(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + ConstVal::Struct(ref _name_value_map) => { + // BTreeMap>), + panic!("Ordering still unstable") + } + ConstVal::Tuple(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Array(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Repeat(ref value, times) => { + value.hash_stable(hcx, hasher); + times.hash_stable(hcx, hasher); + } + ConstVal::Char(value) => { + value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); + + +impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { + parent, + predicates +}); + +impl_stable_hash_for!(enum ty::Variance { + Covariant, + Invariant, + Contravariant, + Bivariant +}); + +impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized { + Struct(index) +}); + +impl<'a, 'tcx> HashStable> for ty::Generics { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::Generics { + parent, + parent_regions, + parent_types, + ref regions, + ref types, + + // Reverse map to each `TypeParameterDef`'s `index` field, from + // `def_id.index` (`def_id.krate` is the same as the item's). + type_param_to_index: _, // Don't hash this + has_self, + } = *self; + + parent.hash_stable(hcx, hasher); + parent_regions.hash_stable(hcx, hasher); + parent_types.hash_stable(hcx, hasher); + regions.hash_stable(hcx, hasher); + types.hash_stable(hcx, hasher); + has_self.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::RegionParameterDef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::RegionParameterDef { + name, + def_id, + index, + issue_32330: _, + pure_wrt_drop + } = *self; + + name.hash_stable(hcx, hasher); + def_id.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + pure_wrt_drop.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::TypeParameterDef { + name, + def_id, + index, + has_default, + object_lifetime_default, + pure_wrt_drop +}); + + +impl<'a, 'tcx, T> HashStable> +for ::middle::resolve_lifetime::Set1 + where T: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::resolve_lifetime::Set1; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + Set1::Empty | + Set1::Many => { + // Nothing to do. + } + Set1::One(ref value) => { + value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region { + Static, + EarlyBound(index, decl), + LateBound(db_index, decl), + LateBoundAnon(db_index, anon_index), + Free(call_site_scope_data, decl) +}); + +impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData { + fn_id, + body_id +}); + +impl_stable_hash_for!(struct ty::DebruijnIndex { + depth +}); diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index 209953f3c686b..f0601a0efabf8 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -8,13 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! ICH - Incremental Compilation Hash + pub use self::fingerprint::Fingerprint; pub use self::def_path_hash::DefPathHashes; pub use self::caching_codemap_view::CachingCodemapView; +pub use self::hcx::{StableHashingContext, NodeIdHashingMode}; mod fingerprint; mod def_path_hash; mod caching_codemap_view; +mod hcx; + +mod impls_const_math; +mod impls_hir; +mod impls_mir; +mod impls_ty; +mod impls_syntax; pub const ATTR_DIRTY: &'static str = "rustc_dirty"; pub const ATTR_CLEAN: &'static str = "rustc_clean"; @@ -22,6 +32,20 @@ pub const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty"; pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean"; pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; +pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused"; +pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; + + +pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[ + ATTR_IF_THIS_CHANGED, + ATTR_THEN_THIS_WOULD_NEED, + ATTR_DIRTY, + ATTR_CLEAN, + ATTR_DIRTY_METADATA, + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, +]; pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ "cfg", @@ -30,5 +54,7 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, - ATTR_CLEAN_METADATA + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, ]; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c1c945d4e6063..86476ddd813ba 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -42,6 +42,7 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(unboxed_closures)] +#![feature(discriminant_value)] extern crate arena; extern crate core; diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 76dca1bb5b649..c18e585f79553 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + macro_rules! enum_from_u32 { ($(#[$attr:meta])* pub enum $name:ident { $($variant:ident = $e:expr,)* @@ -59,3 +61,80 @@ macro_rules! span_bug { $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) }) } + +#[macro_export] +macro_rules! __impl_stable_hash_field { + (DECL IGNORED) => (_); + (DECL $name:ident) => (ref $name); + (USE IGNORED $ctx:expr, $hasher:expr) => ({}); + (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher)); +} + +#[macro_export] +macro_rules! impl_stable_hash_for { + (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + use $enum_name::*; + ::std::mem::discriminant(self).hash_stable(__ctx, __hasher); + + match *self { + $( + $variant $( ( $( __impl_stable_hash_field!(DECL $arg) ),* ) )* => { + $($( __impl_stable_hash_field!(USE $arg, __ctx, __hasher) );*)* + } + )* + } + } + } + }; + (struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name { + $(ref $field),* + } = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; + (tuple_struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name ( + $(ref $field),* + ) = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; +} + +#[macro_export] +macro_rules! impl_stable_hash_for_spanned { + ($T:path) => ( + + impl<'a, 'tcx> HashStable> for ::syntax::codemap::Spanned<$T> + { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.node.hash_stable(hcx, hasher); + self.span.hash_stable(hcx, hasher); + } + } + ); +} + diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index bc9bbebb1796a..799686ceca4a0 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -10,7 +10,9 @@ use std::cell::{Ref, RefCell}; use rustc_data_structures::indexed_vec::IndexVec; - +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use ich::StableHashingContext; use mir::{Mir, BasicBlock}; use rustc_serialize as serialize; @@ -33,6 +35,13 @@ impl serialize::Decodable for Cache { } } +impl<'a, 'tcx> HashStable> for Cache { + fn hash_stable(&self, + _: &mut StableHashingContext<'a, 'tcx>, + _: &mut StableHasher) { + // do nothing + } +} impl Cache { pub fn new() -> Self { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 01dc7f51e29d9..aea4684e526ce 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -243,6 +243,19 @@ impl<'tcx> Mir<'tcx> { } } +impl_stable_hash_for!(struct Mir<'tcx> { + basic_blocks, + visibility_scopes, + promoted, + return_ty, + local_decls, + arg_count, + upvar_decls, + spread_arg, + span, + cache +}); + impl<'tcx> Index for Mir<'tcx> { type Output = BasicBlockData<'tcx>; @@ -830,6 +843,11 @@ pub struct Static<'tcx> { pub ty: Ty<'tcx>, } +impl_stable_hash_for!(struct Static<'tcx> { + def_id, + ty +}); + /// The `Projection` data structure defines things of the form `B.x` /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Lvalue`. See the aliases diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6a4e7db21dd12..3c529a6982042 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -19,6 +19,7 @@ use dep_graph::{self, DepNode}; use hir::{map as hir_map, FreevarMap, TraitMap}; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; +use ich::StableHashingContext; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::privacy::AccessLevels; @@ -50,6 +51,8 @@ use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; use hir; use hir::itemlikevisit::ItemLikeVisitor; @@ -1379,6 +1382,25 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} + +impl<'a, 'tcx> HashStable> for AdtDef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::AdtDef { + did, + ref variants, + ref flags, + ref repr, + } = *self; + + did.hash_stable(hcx, hasher); + variants.hash_stable(hcx, hasher); + flags.hash_stable(hcx, hasher); + repr.hash_stable(hcx, hasher); + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } @@ -1391,6 +1413,13 @@ pub struct ReprOptions { pub int: Option, } +impl_stable_hash_for!(struct ReprOptions { + c, + packed, + simd, + int +}); + impl ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { let mut ret = ReprOptions::default(); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 8ecfd75dc95a9..0c37999b5359b 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -38,6 +38,8 @@ #![feature(unsize)] #![feature(i128_type)] #![feature(conservative_impl_trait)] +#![feature(discriminant_value)] +#![feature(specialization)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 231c01c9ab78d..dc412a0763ef7 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::hash::Hasher; +use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem; use blake2b::Blake2bHasher; @@ -174,3 +174,193 @@ impl Hasher for StableHasher { self.write_ileb128(i as i64); } } + + +/// Something that implements `HashStable` can be hashed in a way that is +/// stable across multiple compiliation sessions. +pub trait HashStable { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher); +} + +// Implement HashStable by just calling `Hash::hash()`. This works fine for +// self-contained values that don't depend on the hashing context `CTX`. +macro_rules! impl_stable_hash_via_hash { + ($t:ty) => ( + impl HashStable for $t { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + ::std::hash::Hash::hash(self, hasher); + } + } + ); +} + +impl_stable_hash_via_hash!(i8); +impl_stable_hash_via_hash!(i16); +impl_stable_hash_via_hash!(i32); +impl_stable_hash_via_hash!(i64); +impl_stable_hash_via_hash!(isize); + +impl_stable_hash_via_hash!(u8); +impl_stable_hash_via_hash!(u16); +impl_stable_hash_via_hash!(u32); +impl_stable_hash_via_hash!(u64); +impl_stable_hash_via_hash!(usize); + +impl_stable_hash_via_hash!(u128); +impl_stable_hash_via_hash!(i128); + +impl_stable_hash_via_hash!(char); +impl_stable_hash_via_hash!(()); + +impl HashStable for f32 { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + let val: u32 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl HashStable for f64 { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + let val: u64 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl, T2: HashStable, CTX> HashStable for (T1, T2) { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.0.hash_stable(ctx, hasher); + self.1.hash_stable(ctx, hasher); + } +} + +impl, CTX> HashStable for [T] { + default fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for item in self { + item.hash_stable(ctx, hasher); + } + } +} + +impl, CTX> HashStable for Vec { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (&self[..]).hash_stable(ctx, hasher); + } +} + +impl HashStable for str { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash(hasher); + self.as_bytes().hash(hasher); + } +} + +impl HashStable for bool { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher); + } +} + + +impl HashStable for Option + where T: HashStable +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + if let Some(ref value) = *self { + 1u8.hash_stable(ctx, hasher); + value.hash_stable(ctx, hasher); + } else { + 0u8.hash_stable(ctx, hasher); + } + } +} + +impl<'a, T, CTX> HashStable for &'a T + where T: HashStable +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(ctx, hasher); + } +} + +impl HashStable for ::std::mem::Discriminant { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + ::std::hash::Hash::hash(self, hasher); + } +} + +impl HashStable for ::std::collections::BTreeMap + where K: Ord + HashStable, + V: HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for (k, v) in self { + k.hash_stable(ctx, hasher); + v.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for ::std::collections::BTreeSet + where T: Ord + HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in self { + v.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for ::indexed_vec::IndexVec + where T: HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in &self.raw { + v.hash_stable(ctx, hasher); + } + } +} diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index c9496a4deb8eb..c80a5a1627797 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -27,24 +27,17 @@ //! at the end of compilation would be different from those computed //! at the beginning. -use syntax::ast; use std::cell::RefCell; use std::hash::Hash; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::hir::intravisit as visit; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use rustc::ich::{Fingerprint, DefPathHashes, CachingCodemapView}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::ich::{Fingerprint, StableHashingContext}; use rustc::ty::TyCtxt; -use rustc_data_structures::stable_hasher::StableHasher; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use rustc_data_structures::fx::FxHashMap; use rustc::util::common::record_time; -use rustc::session::config::DebugInfoLevel::NoDebugInfo; - -use self::svh_visitor::StrictVersionHashVisitor; - -mod svh_visitor; pub type IchHasher = StableHasher; @@ -94,91 +87,42 @@ impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { } } - -pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> IncrementalHashesMap { - let _ignore = tcx.dep_graph.in_ignore(); - let krate = tcx.hir.krate(); - let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo; - let mut visitor = HashItemsVisitor { - tcx: tcx, - hashes: IncrementalHashesMap::new(), - def_path_hashes: DefPathHashes::new(tcx), - codemap: CachingCodemapView::new(tcx), - hash_spans: hash_spans, - }; - record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { - visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| { - v.hash_crate_root_module(krate); - }); - krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); - - for macro_def in krate.exported_macros.iter() { - visitor.calculate_node_id(macro_def.id, - |v| v.visit_macro_def(macro_def)); - } - }); - - tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); - - record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); - visitor.hashes -} - -struct HashItemsVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_path_hashes: DefPathHashes<'a, 'tcx>, - codemap: CachingCodemapView<'tcx>, +struct ComputeItemHashesVisitor<'a, 'tcx: 'a> { + hcx: StableHashingContext<'a, 'tcx>, hashes: IncrementalHashesMap, - hash_spans: bool, } -impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { - fn calculate_node_id(&mut self, id: ast::NodeId, walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) - { - let def_id = self.tcx.hir.local_def_id(id); - self.calculate_def_id(def_id, walk_op) - } - - fn calculate_def_id(&mut self, def_id: DefId, mut walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) +impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { + fn compute_and_store_ich_for_item_like(&mut self, + dep_node: DepNode, + hash_bodies: bool, + item_like: T) + where T: HashStable> { - assert!(def_id.is_local()); - debug!("HashItemsVisitor::calculate(def_id={:?})", def_id); - self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op); - self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op); - } + let mut hasher = IchHasher::new(); + self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| { + item_like.hash_stable(hcx, &mut hasher); + }); - fn calculate_def_hash(&mut self, - dep_node: DepNode, - hash_bodies: bool, - walk_op: &mut W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) - { - let mut state = IchHasher::new(); - walk_op(&mut StrictVersionHashVisitor::new(&mut state, - self.tcx, - &mut self.def_path_hashes, - &mut self.codemap, - self.hash_spans, - hash_bodies)); - let bytes_hashed = state.bytes_hashed(); - let item_hash = state.finish(); + let bytes_hashed = hasher.bytes_hashed(); + let item_hash = hasher.finish(); debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash); self.hashes.insert(dep_node, item_hash); - let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + + let tcx = self.hcx.tcx(); + let bytes_hashed = + tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + bytes_hashed; - self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); + tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); } fn compute_crate_hash(&mut self) { - let krate = self.tcx.hir.krate(); + let tcx = self.hcx.tcx(); + let krate = tcx.hir.krate(); let mut crate_state = IchHasher::new(); - let crate_disambiguator = self.tcx.sess.local_crate_disambiguator(); + let crate_disambiguator = tcx.sess.local_crate_disambiguator(); "crate_disambiguator".hash(&mut crate_state); crate_disambiguator.as_str().len().hash(&mut crate_state); crate_disambiguator.as_str().hash(&mut crate_state); @@ -186,7 +130,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // add each item (in some deterministic order) to the overall // crate hash. { - let def_path_hashes = &mut self.def_path_hashes; + let hcx = &mut self.hcx; let mut item_hashes: Vec<_> = self.hashes.iter() .map(|(item_dep_node, &item_hash)| { @@ -194,7 +138,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // DepNode where the u64 is the // hash of the def-id's def-path: let item_dep_node = - item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did))) + item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did))) .unwrap(); (item_dep_node, item_hash) }) @@ -203,40 +147,85 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { item_hashes.hash(&mut crate_state); } - { - let mut visitor = StrictVersionHashVisitor::new(&mut crate_state, - self.tcx, - &mut self.def_path_hashes, - &mut self.codemap, - self.hash_spans, - false); - visitor.hash_attributes(&krate.attrs); - } + krate.attrs.hash_stable(&mut self.hcx, &mut crate_state); let crate_hash = crate_state.finish(); self.hashes.insert(DepNode::Krate, crate_hash); debug!("calculate_crate_hash: crate_hash={:?}", crate_hash); } -} - -impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None + fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) { + let hir::Crate { + ref module, + // Crate attributes are not copied over to the root `Mod`, so hash + // them explicitly here. + ref attrs, + span, + + // These fields are handled separately: + exported_macros: _, + items: _, + trait_items: _, + impl_items: _, + bodies: _, + trait_impls: _, + trait_default_impl: _, + body_ids: _, + } = *krate; + + let def_id = DefId::local(CRATE_DEF_INDEX); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), + false, + (module, (span, attrs))); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), + true, + (module, (span, attrs))); } +} +impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - self.calculate_node_id(item.id, |v| v.visit_item(item)); - visit::walk_item(self, item); + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item)); - visit::walk_trait_item(self, trait_item); + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) { + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item)); - visit::walk_impl_item(self, impl_item); + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) { + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } } + +pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> IncrementalHashesMap { + let _ignore = tcx.dep_graph.in_ignore(); + let krate = tcx.hir.krate(); + + let mut visitor = ComputeItemHashesVisitor { + hcx: StableHashingContext::new(tcx), + hashes: IncrementalHashesMap::new(), + }; + + record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { + visitor.hash_crate_root_module(krate); + krate.visit_all_item_likes(&mut visitor); + + for macro_def in krate.exported_macros.iter() { + let def_id = tcx.hir.local_def_id(macro_def.id); + visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def); + visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def); + } + }); + + tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); + + record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); + visitor.hashes +} diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs deleted file mode 100644 index 5401b371888e9..0000000000000 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ /dev/null @@ -1,1111 +0,0 @@ -// 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. - -use self::SawExprComponent::*; -use self::SawAbiComponent::*; -use self::SawItemComponent::*; -use self::SawPatComponent::*; -use self::SawTyComponent::*; -use self::SawTraitOrImplItemComponent::*; -use syntax::abi::Abi; -use syntax::ast::{self, Name, NodeId}; -use syntax::attr; -use syntax::ext::hygiene::SyntaxContext; -use syntax::parse::token; -use syntax::symbol::InternedString; -use syntax_pos::{Span, BytePos}; -use syntax::tokenstream; -use rustc::hir; -use rustc::hir::*; -use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::{self as visit, Visitor}; -use rustc::ich::{DefPathHashes, CachingCodemapView, IGNORED_ATTRIBUTES}; -use rustc::ty::TyCtxt; -use std::hash::{Hash, Hasher}; - -use super::IchHasher; - -pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { - pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, - pub st: &'a mut IchHasher, - // collect a deterministic hash of def-ids that we have seen - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, - hash_spans: bool, - codemap: &'a mut CachingCodemapView<'tcx>, - overflow_checks_enabled: bool, - hash_bodies: bool, -} - -impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { - pub fn new(st: &'a mut IchHasher, - tcx: TyCtxt<'hash, 'tcx, 'tcx>, - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, - codemap: &'a mut CachingCodemapView<'tcx>, - hash_spans: bool, - hash_bodies: bool) - -> Self { - let check_overflow = tcx.sess.overflow_checks(); - - StrictVersionHashVisitor { - st: st, - tcx: tcx, - def_path_hashes: def_path_hashes, - hash_spans: hash_spans, - codemap: codemap, - overflow_checks_enabled: check_overflow, - hash_bodies: hash_bodies, - } - } - - fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 { - self.def_path_hashes.hash(def_id) - } - - // Hash a span in a stable way. We can't directly hash the span's BytePos - // fields (that would be similar to hashing pointers, since those are just - // offsets into the CodeMap). Instead, we hash the (file name, line, column) - // triple, which stays the same even if the containing FileMap has moved - // within the CodeMap. - // Also note that we are hashing byte offsets for the column, not unicode - // codepoint offsets. For the purpose of the hash that's sufficient. - // Also, hashing filenames is expensive so we avoid doing it twice when the - // span starts and ends in the same file, which is almost always the case. - fn hash_span(&mut self, span: Span) { - debug!("hash_span: st={:?}", self.st); - - // If this is not an empty or invalid span, we want to hash the last - // position that belongs to it, as opposed to hashing the first - // position past it. - let span_hi = if span.hi > span.lo { - // We might end up in the middle of a multibyte character here, - // but that's OK, since we are not trying to decode anything at - // this position. - span.hi - BytePos(1) - } else { - span.hi - }; - - let expn_kind = if span.ctxt == SyntaxContext::empty() { - SawSpanExpnKind::NoExpansion - } else { - SawSpanExpnKind::SomeExpansion - }; - - let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); - let loc1 = loc1.as_ref() - .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) - .unwrap_or(("???", 0, BytePos(0))); - - let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi); - let loc2 = loc2.as_ref() - .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) - .unwrap_or(("???", 0, BytePos(0))); - - let saw = if loc1.0 == loc2.0 { - SawSpan(loc1.0, - loc1.1, loc1.2, - loc2.1, loc2.2, - expn_kind) - } else { - SawSpanTwoFiles(loc1.0, loc1.1, loc1.2, - loc2.0, loc2.1, loc2.2, - expn_kind) - }; - saw.hash(self.st); - - if expn_kind == SawSpanExpnKind::SomeExpansion { - self.hash_span(span.source_callsite()); - } - } - - fn hash_discriminant(&mut self, v: &T) { - unsafe { - let disr = ::std::intrinsics::discriminant_value(v); - debug!("hash_discriminant: disr={}, st={:?}", disr, self.st); - disr.hash(self.st); - } - } -} - -// 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(InternedString), - SawStructDef(InternedString), - - SawLifetime, - SawLifetimeDef(usize), - - SawMod, - SawForeignItem(SawForeignItemComponent), - SawItem(SawItemComponent), - SawTy(SawTyComponent), - SawFnDecl(bool), - SawGenerics, - SawTraitItem(SawTraitOrImplItemComponent), - SawImplItem(SawTraitOrImplItemComponent), - SawStructField, - SawVariant(bool), - SawQPath, - SawPathSegment, - SawPathParameters, - SawBlock, - SawPat(SawPatComponent), - SawLocal, - SawArm, - SawExpr(SawExprComponent<'a>), - SawStmt, - SawVis, - SawAssociatedItemKind(hir::AssociatedItemKind), - SawDefaultness(hir::Defaultness), - SawWherePredicate, - SawTyParamBound, - SawPolyTraitRef, - SawAssocTypeBinding, - SawAttribute(ast::AttrStyle), - SawMacroDef, - SawSpan(&'a str, - usize, BytePos, - usize, BytePos, - SawSpanExpnKind), - SawSpanTwoFiles(&'a str, usize, BytePos, - &'a str, usize, BytePos, - SawSpanExpnKind), -} - -/// 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.) -/// -/// The xxxComponent enums and saw_xxx functions for Item, Pat, -/// Ty, TraitItem and ImplItem follow the same methodology. -#[derive(Hash)] -enum SawExprComponent<'a> { - - SawExprLoop(Option), - SawExprField(InternedString), - SawExprTupField(usize), - SawExprBreak(Option), - SawExprAgain(Option), - - SawExprBox, - SawExprArray, - SawExprCall, - SawExprMethodCall, - SawExprTup, - SawExprBinary(hir::BinOp_), - SawExprUnary(hir::UnOp), - SawExprLit(ast::LitKind), - SawExprLitStr(InternedString, ast::StrStyle), - SawExprLitFloat(InternedString, Option), - SawExprCast, - SawExprType, - SawExprIf, - SawExprWhile, - SawExprMatch, - SawExprClosure(CaptureClause), - SawExprBlock, - SawExprAssign, - SawExprAssignOp(hir::BinOp_), - SawExprIndex, - SawExprPath, - SawExprAddrOf(hir::Mutability), - SawExprRet, - SawExprInlineAsm(StableInlineAsm<'a>), - SawExprStruct, - SawExprRepeat, -} - -// The boolean returned indicates whether the span of this expression is always -// significant, regardless of debuginfo. -fn saw_expr<'a>(node: &'a Expr_, - overflow_checks_enabled: bool) - -> (SawExprComponent<'a>, bool) { - let binop_can_panic_at_runtime = |binop| { - match binop { - BiAdd | - BiSub | - BiMul => overflow_checks_enabled, - - BiDiv | - BiRem => true, - - BiAnd | - BiOr | - BiBitXor | - BiBitAnd | - BiBitOr | - BiShl | - BiShr | - BiEq | - BiLt | - BiLe | - BiNe | - BiGe | - BiGt => false - } - }; - - let unop_can_panic_at_runtime = |unop| { - match unop { - UnDeref | - UnNot => false, - UnNeg => overflow_checks_enabled, - } - }; - - match *node { - ExprBox(..) => (SawExprBox, false), - ExprArray(..) => (SawExprArray, false), - ExprCall(..) => (SawExprCall, false), - ExprMethodCall(..) => (SawExprMethodCall, false), - ExprTup(..) => (SawExprTup, false), - ExprBinary(op, ..) => { - (SawExprBinary(op.node), binop_can_panic_at_runtime(op.node)) - } - ExprUnary(op, _) => { - (SawExprUnary(op), unop_can_panic_at_runtime(op)) - } - ExprLit(ref lit) => (saw_lit(lit), false), - ExprCast(..) => (SawExprCast, false), - ExprType(..) => (SawExprType, false), - ExprIf(..) => (SawExprIf, false), - ExprWhile(..) => (SawExprWhile, false), - ExprLoop(_, id, _) => (SawExprLoop(id.map(|id| id.node.as_str())), false), - ExprMatch(..) => (SawExprMatch, false), - ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false), - ExprBlock(..) => (SawExprBlock, false), - ExprAssign(..) => (SawExprAssign, false), - ExprAssignOp(op, ..) => { - (SawExprAssignOp(op.node), binop_can_panic_at_runtime(op.node)) - } - ExprField(_, name) => (SawExprField(name.node.as_str()), false), - ExprTupField(_, id) => (SawExprTupField(id.node), false), - ExprIndex(..) => (SawExprIndex, true), - ExprPath(_) => (SawExprPath, false), - ExprAddrOf(m, _) => (SawExprAddrOf(m), false), - ExprBreak(label, _) => (SawExprBreak(label.ident.map(|i| - i.node.name.as_str())), false), - ExprAgain(label) => (SawExprAgain(label.ident.map(|i| - i.node.name.as_str())), false), - ExprRet(..) => (SawExprRet, false), - ExprInlineAsm(ref a,..) => (SawExprInlineAsm(StableInlineAsm(a)), false), - ExprStruct(..) => (SawExprStruct, false), - ExprRepeat(..) => (SawExprRepeat, false), - } -} - -fn saw_lit(lit: &ast::Lit) -> SawExprComponent<'static> { - match lit.node { - ast::LitKind::Str(s, style) => SawExprLitStr(s.as_str(), style), - ast::LitKind::Float(s, ty) => SawExprLitFloat(s.as_str(), Some(ty)), - ast::LitKind::FloatUnsuffixed(s) => SawExprLitFloat(s.as_str(), None), - ref node @ _ => SawExprLit(node.clone()), - } -} - -#[derive(Hash)] -enum SawItemComponent { - SawItemExternCrate, - SawItemUse(UseKind), - SawItemStatic(Mutability), - SawItemConst, - SawItemFn(Unsafety, Constness, Abi), - SawItemMod, - SawItemForeignMod(Abi), - SawItemTy, - SawItemEnum, - SawItemStruct, - SawItemUnion, - SawItemTrait(Unsafety), - SawItemDefaultImpl(Unsafety), - SawItemImpl(Unsafety, ImplPolarity) -} - -fn saw_item(node: &Item_) -> SawItemComponent { - match *node { - ItemExternCrate(..) => SawItemExternCrate, - ItemUse(_, kind) => SawItemUse(kind), - ItemStatic(_, mutability, _) => SawItemStatic(mutability), - ItemConst(..) =>SawItemConst, - ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi), - ItemMod(..) => SawItemMod, - ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi), - ItemTy(..) => SawItemTy, - ItemEnum(..) => SawItemEnum, - ItemStruct(..) => SawItemStruct, - ItemUnion(..) => SawItemUnion, - ItemTrait(unsafety, ..) => SawItemTrait(unsafety), - ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety), - ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity) - } -} - -#[derive(Hash)] -enum SawForeignItemComponent { - Static { mutable: bool }, - Fn, -} - -#[derive(Hash)] -enum SawPatComponent { - SawPatWild, - SawPatBinding(BindingMode), - SawPatStruct, - SawPatTupleStruct, - SawPatPath, - SawPatTuple, - SawPatBox, - SawPatRef(Mutability), - SawPatLit, - SawPatRange, - SawPatSlice -} - -fn saw_pat(node: &PatKind) -> SawPatComponent { - match *node { - PatKind::Wild => SawPatWild, - PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode), - PatKind::Struct(..) => SawPatStruct, - PatKind::TupleStruct(..) => SawPatTupleStruct, - PatKind::Path(_) => SawPatPath, - PatKind::Tuple(..) => SawPatTuple, - PatKind::Box(..) => SawPatBox, - PatKind::Ref(_, mutability) => SawPatRef(mutability), - PatKind::Lit(..) => SawPatLit, - PatKind::Range(..) => SawPatRange, - PatKind::Slice(..) => SawPatSlice - } -} - -#[derive(Hash)] -enum SawTyComponent { - SawTySlice, - SawTyArray, - SawTyPtr(Mutability), - SawTyRptr(Mutability), - SawTyBareFn(Unsafety, Abi), - SawTyNever, - SawTyTup, - SawTyPath, - SawTyObjectSum, - SawTyImplTrait, - SawTyTypeof, - SawTyInfer -} - -fn saw_ty(node: &Ty_) -> SawTyComponent { - match *node { - TySlice(..) => SawTySlice, - TyArray(..) => SawTyArray, - TyPtr(ref mty) => SawTyPtr(mty.mutbl), - TyRptr(_, ref mty) => SawTyRptr(mty.mutbl), - TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi), - TyNever => SawTyNever, - TyTup(..) => SawTyTup, - TyPath(_) => SawTyPath, - TyTraitObject(..) => SawTyObjectSum, - TyImplTrait(..) => SawTyImplTrait, - TyTypeof(..) => SawTyTypeof, - TyInfer => SawTyInfer - } -} - -#[derive(Hash)] -enum SawTraitOrImplItemComponent { - SawTraitOrImplItemConst, - // The boolean signifies whether a body is present - SawTraitOrImplItemMethod(Unsafety, Constness, Abi, bool), - SawTraitOrImplItemType -} - -fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent { - match *ti { - TraitItemKind::Const(..) => SawTraitOrImplItemConst, - TraitItemKind::Method(ref sig, TraitMethod::Required(_)) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false), - TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true), - TraitItemKind::Type(..) => SawTraitOrImplItemType - } -} - -fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent { - match *ii { - ImplItemKind::Const(..) => SawTraitOrImplItemConst, - ImplItemKind::Method(ref sig, _) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true), - ImplItemKind::Type(..) => SawTraitOrImplItemType - } -} - -#[derive(Clone, Copy, Hash, Eq, PartialEq)] -enum SawSpanExpnKind { - NoExpansion, - SomeExpansion, -} - -/// A wrapper that provides a stable Hash implementation. -struct StableInlineAsm<'a>(&'a InlineAsm); - -impl<'a> Hash for StableInlineAsm<'a> { - fn hash(&self, state: &mut H) { - let InlineAsm { - asm, - asm_str_style, - ref outputs, - ref inputs, - ref clobbers, - volatile, - alignstack, - dialect, - ctxt: _, // This is used for error reporting - } = *self.0; - - asm.as_str().hash(state); - asm_str_style.hash(state); - outputs.len().hash(state); - for output in outputs { - let InlineAsmOutput { constraint, is_rw, is_indirect } = *output; - constraint.as_str().hash(state); - is_rw.hash(state); - is_indirect.hash(state); - } - inputs.len().hash(state); - for input in inputs { - input.as_str().hash(state); - } - clobbers.len().hash(state); - for clobber in clobbers { - clobber.as_str().hash(state); - } - volatile.hash(state); - alignstack.hash(state); - dialect.hash(state); - } -} - -macro_rules! hash_attrs { - ($visitor:expr, $attrs:expr) => ({ - let attrs = $attrs; - if attrs.len() > 0 { - $visitor.hash_attributes(attrs); - } - }) -} - -macro_rules! hash_span { - ($visitor:expr, $span:expr) => ({ - hash_span!($visitor, $span, false) - }); - ($visitor:expr, $span:expr, $force:expr) => ({ - if $force || $visitor.hash_spans { - $visitor.hash_span($span); - } - }); -} - -impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> { - if self.hash_bodies { - visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir) - } else { - visit::NestedVisitorMap::None - } - } - - fn visit_variant_data(&mut self, - s: &'tcx VariantData, - name: Name, - _: &'tcx Generics, - _: NodeId, - span: Span) { - debug!("visit_variant_data: st={:?}", self.st); - SawStructDef(name.as_str()).hash(self.st); - hash_span!(self, span); - visit::walk_struct_def(self, s); - } - - fn visit_variant(&mut self, - v: &'tcx Variant, - g: &'tcx Generics, - item_id: NodeId) { - debug!("visit_variant: st={:?}", self.st); - SawVariant(v.node.disr_expr.is_some()).hash(self.st); - hash_attrs!(self, &v.node.attrs); - visit::walk_variant(self, v, g, item_id) - } - - fn visit_name(&mut self, span: Span, name: Name) { - debug!("visit_name: st={:?}", self.st); - SawIdent(name.as_str()).hash(self.st); - hash_span!(self, span); - } - - fn visit_lifetime(&mut self, l: &'tcx Lifetime) { - debug!("visit_lifetime: st={:?}", self.st); - SawLifetime.hash(self.st); - visit::walk_lifetime(self, l); - } - - fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) { - debug!("visit_lifetime_def: st={:?}", self.st); - SawLifetimeDef(l.bounds.len()).hash(self.st); - visit::walk_lifetime_def(self, l); - } - - fn visit_expr(&mut self, ex: &'tcx Expr) { - debug!("visit_expr: st={:?}", self.st); - let (saw_expr, force_span) = saw_expr(&ex.node, - self.overflow_checks_enabled); - SawExpr(saw_expr).hash(self.st); - // No need to explicitly hash the discriminant here, since we are - // implicitly hashing the discriminant of SawExprComponent. - hash_span!(self, ex.span, force_span); - hash_attrs!(self, &ex.attrs); - - // Always hash nested constant bodies (e.g. n in `[x; n]`). - let hash_bodies = self.hash_bodies; - self.hash_bodies = true; - visit::walk_expr(self, ex); - self.hash_bodies = hash_bodies; - } - - fn visit_stmt(&mut self, s: &'tcx Stmt) { - debug!("visit_stmt: st={:?}", self.st); - - // We don't want to modify the hash for decls, because - // they might be item decls (if they are local decls, - // we'll hash that fact in visit_local); but we do want to - // remember if this was a StmtExpr or StmtSemi (the later - // had an explicit semi-colon; this affects the typing - // rules). - match s.node { - StmtDecl(..) => (), - StmtExpr(..) => { - SawStmt.hash(self.st); - self.hash_discriminant(&s.node); - hash_span!(self, s.span); - } - StmtSemi(..) => { - SawStmt.hash(self.st); - self.hash_discriminant(&s.node); - hash_span!(self, s.span); - } - } - - visit::walk_stmt(self, s) - } - - fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { - debug!("visit_foreign_item: st={:?}", self.st); - - match i.node { - ForeignItemFn(..) => { - SawForeignItem(SawForeignItemComponent::Fn) - } - ForeignItemStatic(_, mutable) => { - SawForeignItem(SawForeignItemComponent::Static { - mutable: mutable - }) - } - }.hash(self.st); - - hash_span!(self, i.span); - hash_attrs!(self, &i.attrs); - visit::walk_foreign_item(self, i) - } - - fn visit_item(&mut self, i: &'tcx Item) { - debug!("visit_item: {:?} st={:?}", i, self.st); - - self.maybe_enable_overflow_checks(&i.attrs); - - SawItem(saw_item(&i.node)).hash(self.st); - hash_span!(self, i.span); - hash_attrs!(self, &i.attrs); - visit::walk_item(self, i) - } - - fn visit_mod(&mut self, m: &'tcx Mod, span: Span, n: NodeId) { - debug!("visit_mod: st={:?}", self.st); - SawMod.hash(self.st); - hash_span!(self, span); - visit::walk_mod(self, m, n) - } - - fn visit_ty(&mut self, t: &'tcx Ty) { - debug!("visit_ty: st={:?}", self.st); - SawTy(saw_ty(&t.node)).hash(self.st); - hash_span!(self, t.span); - - // Always hash nested constant bodies (e.g. N in `[T; N]`). - let hash_bodies = self.hash_bodies; - self.hash_bodies = true; - visit::walk_ty(self, t); - self.hash_bodies = hash_bodies; - } - - fn visit_generics(&mut self, g: &'tcx Generics) { - debug!("visit_generics: st={:?}", self.st); - SawGenerics.hash(self.st); - visit::walk_generics(self, g) - } - - fn visit_fn_decl(&mut self, fd: &'tcx FnDecl) { - debug!("visit_fn_decl: st={:?}", self.st); - SawFnDecl(fd.variadic).hash(self.st); - visit::walk_fn_decl(self, fd) - } - - fn visit_trait_item(&mut self, ti: &'tcx TraitItem) { - debug!("visit_trait_item: st={:?}", self.st); - - self.maybe_enable_overflow_checks(&ti.attrs); - - SawTraitItem(saw_trait_item(&ti.node)).hash(self.st); - hash_span!(self, ti.span); - hash_attrs!(self, &ti.attrs); - visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'tcx ImplItem) { - debug!("visit_impl_item: st={:?}", self.st); - - self.maybe_enable_overflow_checks(&ii.attrs); - - SawImplItem(saw_impl_item(&ii.node)).hash(self.st); - hash_span!(self, ii.span); - hash_attrs!(self, &ii.attrs); - visit::walk_impl_item(self, ii) - } - - fn visit_struct_field(&mut self, s: &'tcx StructField) { - debug!("visit_struct_field: st={:?}", self.st); - SawStructField.hash(self.st); - hash_span!(self, s.span); - hash_attrs!(self, &s.attrs); - visit::walk_struct_field(self, s) - } - - fn visit_qpath(&mut self, qpath: &'tcx QPath, id: NodeId, span: Span) { - debug!("visit_qpath: st={:?}", self.st); - SawQPath.hash(self.st); - self.hash_discriminant(qpath); - visit::walk_qpath(self, qpath, id, span) - } - - fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { - debug!("visit_path: st={:?}", self.st); - hash_span!(self, path.span); - visit::walk_path(self, path) - } - - fn visit_def_mention(&mut self, def: Def) { - self.hash_def(def); - } - - fn visit_block(&mut self, b: &'tcx Block) { - debug!("visit_block: st={:?}", self.st); - SawBlock.hash(self.st); - hash_span!(self, b.span); - visit::walk_block(self, b) - } - - fn visit_pat(&mut self, p: &'tcx Pat) { - debug!("visit_pat: st={:?}", self.st); - SawPat(saw_pat(&p.node)).hash(self.st); - hash_span!(self, p.span); - visit::walk_pat(self, p) - } - - fn visit_local(&mut self, l: &'tcx Local) { - debug!("visit_local: st={:?}", self.st); - SawLocal.hash(self.st); - hash_attrs!(self, &l.attrs); - visit::walk_local(self, l) - // No need to hash span, we are hashing all component spans - } - - fn visit_arm(&mut self, a: &'tcx Arm) { - debug!("visit_arm: st={:?}", self.st); - SawArm.hash(self.st); - hash_attrs!(self, &a.attrs); - visit::walk_arm(self, a) - } - - fn visit_id(&mut self, id: NodeId) { - debug!("visit_id: id={} st={:?}", id, self.st); - self.hash_resolve(id) - } - - fn visit_vis(&mut self, v: &'tcx Visibility) { - debug!("visit_vis: st={:?}", self.st); - SawVis.hash(self.st); - self.hash_discriminant(v); - visit::walk_vis(self, v) - } - - fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) { - debug!("visit_associated_item_kind: st={:?}", self.st); - SawAssociatedItemKind(*kind).hash(self.st); - visit::walk_associated_item_kind(self, kind); - } - - fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) { - debug!("visit_associated_item_kind: st={:?}", self.st); - SawDefaultness(*defaultness).hash(self.st); - visit::walk_defaultness(self, defaultness); - } - - fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) { - debug!("visit_where_predicate: st={:?}", self.st); - SawWherePredicate.hash(self.st); - self.hash_discriminant(predicate); - // Ignoring span. Any important nested components should be visited. - visit::walk_where_predicate(self, predicate) - } - - fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) { - debug!("visit_ty_param_bound: st={:?}", self.st); - SawTyParamBound.hash(self.st); - self.hash_discriminant(bounds); - // The TraitBoundModifier in TraitTyParamBound will be hash in - // visit_poly_trait_ref() - visit::walk_ty_param_bound(self, bounds) - } - - fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) { - debug!("visit_poly_trait_ref: st={:?}", self.st); - SawPolyTraitRef.hash(self.st); - m.hash(self.st); - visit::walk_poly_trait_ref(self, t, m) - } - - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) { - debug!("visit_path_segment: st={:?}", self.st); - SawPathSegment.hash(self.st); - visit::walk_path_segment(self, path_span, path_segment) - } - - fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'tcx PathParameters) { - debug!("visit_path_parameters: st={:?}", self.st); - SawPathParameters.hash(self.st); - self.hash_discriminant(path_parameters); - visit::walk_path_parameters(self, path_span, path_parameters) - } - - fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) { - debug!("visit_assoc_type_binding: st={:?}", self.st); - SawAssocTypeBinding.hash(self.st); - hash_span!(self, type_binding.span); - visit::walk_assoc_type_binding(self, type_binding) - } - - fn visit_attribute(&mut self, _: &ast::Attribute) { - // We explicitly do not use this method, since doing that would - // implicitly impose an order on the attributes being hashed, while we - // explicitly don't want their order to matter - } - - fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) { - debug!("visit_macro_def: st={:?}", self.st); - SawMacroDef.hash(self.st); - hash_attrs!(self, ¯o_def.attrs); - for tt in macro_def.body.trees() { - self.hash_token_tree(&tt); - } - visit::walk_macro_def(self, macro_def) - } -} - -#[derive(Hash)] -pub enum DefHash { - SawDefId, - SawLabel, - SawPrimTy, - SawSelfTy, - SawErr, -} - -impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn hash_resolve(&mut self, id: ast::NodeId) { - // Because whether or not a given id has an entry is dependent - // solely on expr variant etc, we don't need to hash whether - // or not an entry was present (we are already hashing what - // variant it is above when we visit the HIR). - - if let Some(traits) = self.tcx.trait_map.get(&id) { - debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st); - traits.len().hash(self.st); - - // The ordering of the candidates is not fixed. So we hash - // the def-ids and then sort them and hash the collection. - let mut candidates: Vec<_> = - traits.iter() - .map(|&TraitCandidate { def_id, import_id: _ }| { - self.compute_def_id_hash(def_id) - }) - .collect(); - candidates.sort(); - candidates.hash(self.st); - } - } - - fn hash_def_id(&mut self, def_id: DefId) { - self.compute_def_id_hash(def_id).hash(self.st); - } - - fn hash_def(&mut self, def: Def) { - match def { - // Crucial point: for all of these variants, the variant + - // add'l data that is added is always the same if the - // def-id is the same, so it suffices to hash the def-id - Def::Fn(..) | - Def::Mod(..) | - Def::Static(..) | - Def::Variant(..) | - Def::VariantCtor(..) | - Def::Enum(..) | - Def::TyAlias(..) | - Def::AssociatedTy(..) | - Def::TyParam(..) | - Def::Struct(..) | - Def::StructCtor(..) | - Def::Union(..) | - Def::Trait(..) | - Def::Method(..) | - Def::Const(..) | - Def::AssociatedConst(..) | - Def::Local(..) | - Def::Upvar(..) | - Def::Macro(..) => { - DefHash::SawDefId.hash(self.st); - self.hash_def_id(def.def_id()); - } - - Def::Label(..) => { - DefHash::SawLabel.hash(self.st); - // we don't encode the `id` because it always refers to something - // within this item, so if it changed, there would have to be other - // changes too - } - Def::PrimTy(ref prim_ty) => { - DefHash::SawPrimTy.hash(self.st); - prim_ty.hash(self.st); - } - Def::SelfTy(..) => { - DefHash::SawSelfTy.hash(self.st); - // the meaning of Self is always the same within a - // given context, so we don't need to hash the other - // fields - } - Def::Err => { - DefHash::SawErr.hash(self.st); - } - } - } - - pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) { - debug!("hash_attributes: st={:?}", self.st); - let indices = self.indices_sorted_by(attributes, |attr| attr.name()); - - for i in indices { - let attr = &attributes[i]; - match attr.name() { - Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue, - _ => {} - }; - if !attr.is_sugared_doc { - SawAttribute(attr.style).hash(self.st); - for segment in &attr.path.segments { - SawIdent(segment.identifier.name.as_str()).hash(self.st); - } - for tt in attr.tokens.trees() { - self.hash_token_tree(&tt); - } - } - } - } - - fn indices_sorted_by(&mut self, items: &[T], get_key: F) -> Vec - where K: Ord, - F: Fn(&T) -> K - { - let mut indices = Vec::with_capacity(items.len()); - indices.extend(0 .. items.len()); - indices.sort_by_key(|index| get_key(&items[*index])); - indices - } - - fn maybe_enable_overflow_checks(&mut self, item_attrs: &[ast::Attribute]) { - if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { - self.overflow_checks_enabled = true; - } - } - - fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) { - self.hash_discriminant(tt); - match *tt { - tokenstream::TokenTree::Token(span, ref token) => { - hash_span!(self, span); - self.hash_token(token, span); - } - tokenstream::TokenTree::Delimited(span, ref delimited) => { - hash_span!(self, span); - delimited.delim.hash(self.st); - for sub_tt in delimited.stream().trees() { - self.hash_token_tree(&sub_tt); - } - } - } - } - - fn hash_token(&mut self, - token: &token::Token, - error_reporting_span: Span) { - self.hash_discriminant(token); - match *token { - token::Token::Eq | - token::Token::Lt | - token::Token::Le | - token::Token::EqEq | - token::Token::Ne | - token::Token::Ge | - token::Token::Gt | - token::Token::AndAnd | - token::Token::OrOr | - token::Token::Not | - token::Token::Tilde | - token::Token::At | - token::Token::Dot | - token::Token::DotDot | - token::Token::DotDotDot | - token::Token::Comma | - token::Token::Semi | - token::Token::Colon | - token::Token::ModSep | - token::Token::RArrow | - token::Token::LArrow | - token::Token::FatArrow | - token::Token::Pound | - token::Token::Dollar | - token::Token::Question | - token::Token::Underscore | - token::Token::Whitespace | - token::Token::Comment | - token::Token::Eof => {} - - token::Token::BinOp(bin_op_token) | - token::Token::BinOpEq(bin_op_token) => bin_op_token.hash(self.st), - - token::Token::OpenDelim(delim_token) | - token::Token::CloseDelim(delim_token) => delim_token.hash(self.st), - - token::Token::Literal(ref lit, ref opt_name) => { - self.hash_discriminant(lit); - match *lit { - token::Lit::Byte(val) | - token::Lit::Char(val) | - token::Lit::Integer(val) | - token::Lit::Float(val) | - token::Lit::Str_(val) | - token::Lit::ByteStr(val) => val.as_str().hash(self.st), - token::Lit::StrRaw(val, n) | - token::Lit::ByteStrRaw(val, n) => { - val.as_str().hash(self.st); - n.hash(self.st); - } - }; - opt_name.map(ast::Name::as_str).hash(self.st); - } - - token::Token::Ident(ident) | - token::Token::Lifetime(ident) | - token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st), - - token::Token::Interpolated(ref non_terminal) => { - // FIXME(mw): This could be implemented properly. It's just a - // lot of work, since we would need to hash the AST - // in a stable way, in addition to the HIR. - // Since this is hardly used anywhere, just emit a - // warning for now. - if self.tcx.sess.opts.debugging_opts.incremental.is_some() { - let msg = format!("Quasi-quoting might make incremental \ - compilation very inefficient: {:?}", - non_terminal); - self.tcx.sess.span_warn(error_reporting_span, &msg[..]); - } - - non_terminal.hash(self.st); - } - - token::Token::DocComment(val) | - token::Token::Shebang(val) => val.as_str().hash(self.st), - } - } - - pub fn hash_crate_root_module(&mut self, krate: &'tcx Crate) { - let hir::Crate { - ref module, - ref attrs, - span, - - // These fields are handled separately: - exported_macros: _, - items: _, - trait_items: _, - impl_items: _, - bodies: _, - trait_impls: _, - trait_default_impl: _, - body_ids: _, - } = *krate; - - visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); - // Crate attributes are not copied over to the root `Mod`, so hash them - // explicitly here. - hash_attrs!(self, attrs); - } -} diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 3b61cc1464a91..8cc53d9899727 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -22,7 +22,6 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(rand)] -#![feature(core_intrinsics)] #![feature(conservative_impl_trait)] #![cfg_attr(stage0,feature(field_init_shorthand))] #![cfg_attr(stage0, feature(pub_restricted))] diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index 8528482c7856c..63cfe591ce366 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -32,8 +32,7 @@ use syntax::ast; use {ModuleSource, ModuleTranslation}; -const PARTITION_REUSED: &'static str = "rustc_partition_reused"; -const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; +use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED}; const MODULE: &'static str = "module"; const CFG: &'static str = "cfg"; @@ -62,9 +61,9 @@ struct AssertModuleSource<'a, 'tcx: 'a> { impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { fn check_attr(&self, attr: &ast::Attribute) { - let disposition = if attr.check_name(PARTITION_REUSED) { + let disposition = if attr.check_name(ATTR_PARTITION_REUSED) { Disposition::Reused - } else if attr.check_name(PARTITION_TRANSLATED) { + } else if attr.check_name(ATTR_PARTITION_TRANSLATED) { Disposition::Translated } else { return; diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 5875015893144..15111bbba0a92 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -43,6 +43,8 @@ use std::{mem, ptr, slice, vec}; use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; /// An owned smart pointer. #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct P { @@ -215,3 +217,13 @@ impl Decodable for P<[T]> { })) } } + +impl HashStable for P + where T: ?Sized + HashStable +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(hcx, hasher); + } +} diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs index 195fb23f9d8c7..2d9fd7aa87553 100644 --- a/src/libsyntax/util/rc_slice.rs +++ b/src/libsyntax/util/rc_slice.rs @@ -12,6 +12,9 @@ use std::fmt; use std::ops::Deref; use std::rc::Rc; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; + #[derive(Clone)] pub struct RcSlice { data: Rc>, @@ -41,3 +44,13 @@ impl fmt::Debug for RcSlice { fmt::Debug::fmt(self.deref(), f) } } + +impl HashStable for RcSlice + where T: HashStable +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(hcx, hasher); + } +}