Skip to content

Commit

Permalink
Auto merge of #66279 - cjgillot:hashstable, r=Zoxc
Browse files Browse the repository at this point in the history
Use proc-macro to derive HashStable everywhere

Hello,

A second proc-macro is added to derive HashStable for crates librustc depends on.
This proc-macro `HashStable_Generic` (to bikeshed) allows to decouple code and strip much of librustc's boilerplate.

Still, two implementations `Span` and `TokenKind` require to be placed in librustc.
The latter only depends on the `bug` macro. Advise welcome on how to sever that link.
A trait `StableHasingContextLike` has been introduced at each crate root,
in order to handle those implementations which require librustc's very `StableHashingContext`.

This overall effort allowed to remove the `impl_stable_hash_for` macro.

Each commit passes the `x.py check`.
I still have to double check there was no change in the implementation.
  • Loading branch information
bors committed Nov 25, 2019
2 parents 4eee955 + 782cc9f commit 582a4ea
Show file tree
Hide file tree
Showing 18 changed files with 199 additions and 427 deletions.
101 changes: 10 additions & 91 deletions src/librustc/ich/hcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,23 @@ use crate::hir;
use crate::hir::def_id::{DefId, DefIndex};
use crate::hir::map::DefPathHash;
use crate::hir::map::definitions::Definitions;
use crate::ich::{self, CachingSourceMapView, Fingerprint};
use crate::ich::{self, CachingSourceMapView};
use crate::middle::cstore::CrateStore;
use crate::ty::{TyCtxt, fast_reject};
use crate::session::Session;

use std::cmp::Ord;
use std::hash as std_hash;
use std::cell::RefCell;

use syntax::ast;
use syntax::source_map::SourceMap;
use syntax::symbol::Symbol;
use syntax::tokenstream::DelimSpan;
use syntax_pos::{Span, DUMMY_SP};
use syntax_pos::hygiene::{self, SyntaxContext};
use syntax_pos::{SourceFile, BytePos};

use rustc_data_structures::stable_hasher::{
HashStable, StableHasher, ToStableHashKey,
};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use rustc_data_structures::sync::Lrc;
use smallvec::SmallVec;

fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
Expand Down Expand Up @@ -281,93 +278,15 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::NodeId {
}
}

impl<'a> HashStable<StableHashingContext<'a>> for Span {
/// Hashes 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 `SourceMap`). Instead, we hash the (file name, line, column)
/// triple, which stays the same even if the containing `SourceFile` has moved
/// within the `SourceMap`.
/// 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>, hasher: &mut StableHasher) {
const TAG_VALID_SPAN: u8 = 0;
const TAG_INVALID_SPAN: u8 = 1;
const TAG_EXPANSION: u8 = 0;
const TAG_NO_EXPANSION: u8 = 1;

if !hcx.hash_spans {
return
}

if *self == DUMMY_SP {
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
}

// 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 = self.data();
let (file_lo, line_lo, col_lo) = match hcx.source_map()
.byte_pos_to_line_and_col(span.lo) {
Some(pos) => pos,
None => {
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
}
};

if !file_lo.contains(span.hi) {
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
}

std_hash::Hash::hash(&TAG_VALID_SPAN, hasher);
// We truncate the stable ID hash and line and column numbers. The chances
// of causing a collision this way should be minimal.
std_hash::Hash::hash(&(file_lo.name_hash as u64), hasher);

let col = (col_lo.0 as u64) & 0xFF;
let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
let len = ((span.hi - span.lo).0 as u64) << 32;
let line_col_len = col | line | len;
std_hash::Hash::hash(&line_col_len, hasher);

if span.ctxt == SyntaxContext::root() {
TAG_NO_EXPANSION.hash_stable(hcx, hasher);
} else {
TAG_EXPANSION.hash_stable(hcx, hasher);

// Since the same expansion context is usually referenced many
// times, we cache a stable hash of it and hash that instead of
// recursing every time.
thread_local! {
static CACHE: RefCell<FxHashMap<hygiene::ExpnId, u64>> = Default::default();
}

let sub_hash: u64 = CACHE.with(|cache| {
let expn_id = span.ctxt.outer_expn();

if let Some(&sub_hash) = cache.borrow().get(&expn_id) {
return sub_hash;
}

let mut hasher = StableHasher::new();
expn_id.expn_data().hash_stable(hcx, &mut hasher);
let sub_hash: Fingerprint = hasher.finish();
let sub_hash = sub_hash.to_smaller_hash();
cache.borrow_mut().insert(expn_id, sub_hash);
sub_hash
});

sub_hash.hash_stable(hcx, hasher);
}
impl<'a> syntax_pos::HashStableContext for StableHashingContext<'a> {
fn hash_spans(&self) -> bool {
self.hash_spans
}
}

impl<'a> HashStable<StableHashingContext<'a>> for DelimSpan {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.open.hash_stable(hcx, hasher);
self.close.hash_stable(hcx, hasher);
fn byte_pos_to_line_and_col(&mut self, byte: BytePos)
-> Option<(Lrc<SourceFile>, usize, BytePos)>
{
self.source_map().byte_pos_to_line_and_col(byte)
}
}

Expand Down
21 changes: 0 additions & 21 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::ich::{StableHashingContext, NodeIdHashingMode, Fingerprint};
use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher};
use smallvec::SmallVec;
use std::mem;
use syntax::ast;
use syntax::attr;

impl<'a> HashStable<StableHashingContext<'a>> for DefId {
Expand Down Expand Up @@ -119,10 +118,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItemId {
}
}

impl_stable_hash_for!(struct ast::Label {
ident
});

impl<'a> HashStable<StableHashingContext<'a>> for hir::Ty {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
hcx.while_hashing_hir_bodies(true, |hcx| {
Expand All @@ -138,10 +133,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Ty {
}
}

impl_stable_hash_for_spanned!(hir::BinOpKind);

impl_stable_hash_for_spanned!(ast::Name);

impl<'a> HashStable<StableHashingContext<'a>> for hir::Expr {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
hcx.while_hashing_hir_bodies(true, |hcx| {
Expand All @@ -159,13 +150,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Expr {
}
}

impl_stable_hash_for_spanned!(usize);

impl_stable_hash_for!(struct ast::Ident {
name,
span,
});

impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitItem {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let hir::TraitItem {
Expand Down Expand Up @@ -234,8 +218,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::VisibilityKind {
}
}

impl_stable_hash_for_spanned!(hir::VisibilityKind);

impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let hir::Mod {
Expand Down Expand Up @@ -263,9 +245,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
}
}

impl_stable_hash_for_spanned!(hir::Variant);


impl<'a> HashStable<StableHashingContext<'a>> for hir::Item {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let hir::Item {
Expand Down
158 changes: 8 additions & 150 deletions src/librustc/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,23 @@

use crate::ich::StableHashingContext;

use std::hash as std_hash;
use std::mem;

use syntax::ast;
use syntax::feature_gate;
use syntax::token;
use syntax::tokenstream;
use syntax_pos::SourceFile;

use crate::hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX};

use smallvec::SmallVec;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};

impl_stable_hash_for!(struct ::syntax::ast::Lit {
kind,
token,
span
});

impl_stable_hash_for_spanned!(::syntax::ast::LitKind);
impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {}

impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, ident });
impl<'a> HashStable<StableHashingContext<'a>> for ast::Lifetime {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.id.hash_stable(hcx, hasher);
self.ident.hash_stable(hcx, hasher);
}
}

impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
Expand All @@ -50,20 +44,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
}
}

impl<'a> HashStable<StableHashingContext<'a>> for ast::Path {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.segments.len().hash_stable(hcx, hasher);
for segment in &self.segments {
segment.ident.name.hash_stable(hcx, hasher);
}
}
}

impl_stable_hash_for!(struct ::syntax::ast::AttrItem {
path,
tokens,
});

impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
// Make sure that these have been filtered out.
Expand All @@ -81,129 +61,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
}
}

impl<'a> HashStable<StableHashingContext<'a>>
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(ref token) => {
token.hash_stable(hcx, hasher);
}
tokenstream::TokenTree::Delimited(span, delim, ref tts) => {
span.hash_stable(hcx, hasher);
std_hash::Hash::hash(&delim, hasher);
for sub_tt in tts.trees() {
sub_tt.hash_stable(hcx, hasher);
}
}
}
}
}

impl<'a> HashStable<StableHashingContext<'a>>
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);
}
}
}

impl<'a> HashStable<StableHashingContext<'a>> for token::TokenKind {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
token::Eq |
token::Lt |
token::Le |
token::EqEq |
token::Ne |
token::Ge |
token::Gt |
token::AndAnd |
token::OrOr |
token::Not |
token::Tilde |
token::At |
token::Dot |
token::DotDot |
token::DotDotDot |
token::DotDotEq |
token::Comma |
token::Semi |
token::Colon |
token::ModSep |
token::RArrow |
token::LArrow |
token::FatArrow |
token::Pound |
token::Dollar |
token::Question |
token::SingleQuote |
token::Whitespace |
token::Comment |
token::Eof => {}

token::BinOp(bin_op_token) |
token::BinOpEq(bin_op_token) => {
std_hash::Hash::hash(&bin_op_token, hasher);
}

token::OpenDelim(delim_token) |
token::CloseDelim(delim_token) => {
std_hash::Hash::hash(&delim_token, hasher);
}
token::Literal(lit) => lit.hash_stable(hcx, hasher),

token::Ident(name, is_raw) => {
name.hash_stable(hcx, hasher);
is_raw.hash_stable(hcx, hasher);
}
token::Lifetime(name) => name.hash_stable(hcx, hasher),

token::Interpolated(_) => {
bug!("interpolated tokens should not be present in the HIR")
}

token::DocComment(val) |
token::Shebang(val) |
token::Unknown(val) => val.hash_stable(hcx, hasher),
}
}
}

impl_stable_hash_for!(struct token::Token {
kind,
span
});

impl_stable_hash_for!(enum ::syntax::ast::NestedMetaItem {
MetaItem(meta_item),
Literal(lit)
});

impl_stable_hash_for!(struct ::syntax::ast::MetaItem {
path,
kind,
span
});

impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind {
Word,
List(nested_items),
NameValue(lit)
});

impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnData {
kind,
parent -> _,
call_site,
def_site,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
edition
});
impl<'ctx> syntax::HashStableContext for StableHashingContext<'ctx> {}

impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/ich/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
//! ICH - Incremental Compilation Hash

crate use rustc_data_structures::fingerprint::Fingerprint;
pub use self::caching_source_map_view::CachingSourceMapView;
pub use syntax_pos::CachingSourceMapView;
pub use self::hcx::{StableHashingContextProvider, StableHashingContext, NodeIdHashingMode,
hash_stable_trait_impls};
use syntax::symbol::{Symbol, sym};

mod caching_source_map_view;
mod hcx;

mod impls_hir;
Expand Down
Loading

0 comments on commit 582a4ea

Please sign in to comment.