// 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::feature_gate; use syntax::parse::token; use syntax::symbol::InternedString; use syntax::tokenstream; use syntax_pos::FileMap; use hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX}; use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; use rustc_data_structures::accumulate_vec::AccumulateVec; impl<'a> HashStable> for InternedString { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let s: &str = &**self; s.hash_stable(hcx, hasher); } } impl<'a> ToStableHashKey> for InternedString { type KeyType = InternedString; #[inline] fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> InternedString { self.clone() } } impl<'a> HashStable> for ast::Name { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.as_str().hash_stable(hcx, hasher); } } impl<'a> ToStableHashKey> for ast::Name { type KeyType = InternedString; #[inline] fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> InternedString { self.as_str() } } 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 ::rustc_target::spec::abi::Abi { Cdecl, Stdcall, Fastcall, Vectorcall, Thiscall, 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, rustc_const_unstable }); impl<'a> HashStable> for ::syntax::attr::StabilityLevel { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, 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!(struct ::syntax::attr::RustcConstUnstable { feature }); 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 { Isize, I8, I16, I32, I64, I128 }); impl_stable_hash_for!(enum ::syntax::ast::UintTy { Usize, 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, ident }); impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); impl<'a> HashStable> for [ast::Attribute] { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { if self.len() == 0 { self.len().hash_stable(hcx, hasher); return } // 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> HashStable> for ast::Attribute { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, 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.ident.name.hash_stable(hcx, hasher); } for tt in tokens.trees() { tt.hash_stable(hcx, hasher); } span.hash_stable(hcx, hasher); } } impl<'a> HashStable> for tokenstream::TokenTree { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, 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); } 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> HashStable> for tokenstream::TokenStream { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { for sub_tt in self.trees() { sub_tt.hash_stable(hcx, hasher); } } } fn hash_token<'a, 'gcx, W: StableHasherResult>( token: &token::Token, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher, ) { 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::DotDotEq | token::Token::DotEq | 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::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, is_raw) => { ident.name.hash_stable(hcx, hasher); is_raw.hash_stable(hcx, hasher); } token::Token::Lifetime(ident) => ident.name.hash_stable(hcx, hasher), token::Token::Interpolated(_) => { bug!("interpolated tokens should not be present in the HIR") } token::Token::DocComment(val) | token::Token::Shebang(val) => val.hash_stable(hcx, hasher), } } impl_stable_hash_for_spanned!(::syntax::ast::NestedMetaItemKind); impl_stable_hash_for!(enum ::syntax::ast::NestedMetaItemKind { MetaItem(meta_item), Literal(lit) }); impl_stable_hash_for!(struct ::syntax::ast::MetaItem { ident, node, span }); impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind { Word, List(nested_items), NameValue(lit) }); impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { call_site, callee }); impl_stable_hash_for!(struct ::syntax_pos::hygiene::NameAndSpan { format, allow_internal_unstable, allow_internal_unsafe, span }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { MacroAttribute(sym), MacroBang(sym), CompilerDesugaring(kind) }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { DotFill, QuestionMark, Catch }); impl_stable_hash_for!(enum ::syntax_pos::FileName { Real(pb), Macros(s), QuoteExpansion, Anon, MacroExpansion, ProcMacroSourceCode, CfgSpec, Custom(s) }); impl<'a> HashStable> for FileMap { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let FileMap { name: _, // We hash the smaller name_hash instead of this name_hash, name_was_remapped, unmapped_path: _, crate_of_origin, // Do not hash the source as it is not encoded src: _, src_hash, external_src: _, start_pos, end_pos: _, ref lines, ref multibyte_chars, ref non_narrow_chars, } = *self; (name_hash as u64).hash_stable(hcx, hasher); name_was_remapped.hash_stable(hcx, hasher); DefId { krate: CrateNum::from_u32(crate_of_origin), index: CRATE_DEF_INDEX, }.hash_stable(hcx, hasher); src_hash.hash_stable(hcx, hasher); // We only hash the relative position within this filemap lines.with_lock(|lines| { lines.len().hash_stable(hcx, hasher); for &line in lines.iter() { stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); } }); // We only hash the relative position within this filemap multibyte_chars.with_lock(|multibyte_chars| { multibyte_chars.len().hash_stable(hcx, hasher); for &char_pos in multibyte_chars.iter() { stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); } }); non_narrow_chars.with_lock(|non_narrow_chars| { non_narrow_chars.len().hash_stable(hcx, hasher); for &char_pos in non_narrow_chars.iter() { stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); } }); } } fn stable_byte_pos(pos: ::syntax_pos::BytePos, filemap_start: ::syntax_pos::BytePos) -> u32 { pos.0 - filemap_start.0 } fn stable_multibyte_char(mbc: ::syntax_pos::MultiByteChar, filemap_start: ::syntax_pos::BytePos) -> (u32, u32) { let ::syntax_pos::MultiByteChar { pos, bytes, } = mbc; (pos.0 - filemap_start.0, bytes as u32) } fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar, filemap_start: ::syntax_pos::BytePos) -> (u32, u32) { let pos = swc.pos(); let width = swc.width(); (pos.0 - filemap_start.0, width as u32) } impl<'gcx> HashStable> for feature_gate::Features { fn hash_stable(&self, hcx: &mut StableHashingContext<'gcx>, hasher: &mut StableHasher) { // Unfortunately we cannot exhaustively list fields here, since the // struct is macro generated. self.declared_stable_lang_features.hash_stable(hcx, hasher); self.declared_lib_features.hash_stable(hcx, hasher); self.walk_feature_fields(|feature_name, value| { feature_name.hash_stable(hcx, hasher); value.hash_stable(hcx, hasher); }); } }