1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // FIXME (#14132): Even this SVH computation still has implementation
12 // artifacts: namely, the order of item declaration will affect the
13 // hash computation, but for many kinds of items the order of
14 // declaration should be irrelevant to the ABI.
16 pub use self::SawExprComponent
::*;
17 pub use self::SawStmtComponent
::*;
18 use self::SawAbiComponent
::*;
19 use syntax
::ast
::{self, Name, NodeId}
;
20 use syntax
::parse
::token
;
24 use rustc
::hir
::def
::{Def, PathResolution}
;
25 use rustc
::hir
::def_id
::DefId
;
26 use rustc
::hir
::intravisit
as visit
;
27 use rustc
::hir
::intravisit
::{Visitor, FnKind}
;
28 use rustc
::hir
::map
::DefPath
;
29 use rustc
::ty
::TyCtxt
;
31 use std
::hash
::{Hash, SipHasher}
;
33 pub struct StrictVersionHashVisitor
<'a
, 'tcx
: 'a
> {
34 pub tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
35 pub st
: &'a
mut SipHasher
,
38 impl<'a
, 'tcx
> StrictVersionHashVisitor
<'a
, 'tcx
> {
39 pub fn new(st
: &'a
mut SipHasher
,
40 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>)
42 StrictVersionHashVisitor { st: st, tcx: tcx }
45 fn hash_def_path(&mut self, path
: &DefPath
) {
46 path
.deterministic_hash_to(self.tcx
, self.st
);
50 // To off-load the bulk of the hash-computation on #[derive(Hash)],
51 // we define a set of enums corresponding to the content that our
52 // crate visitor will encounter as it traverses the ast.
54 // The important invariant is that all of the Saw*Component enums
55 // do not carry any Spans, Names, or Idents.
57 // Not carrying any Names/Idents is the important fix for problem
58 // noted on PR #13948: using the ident.name as the basis for a
59 // hash leads to unstable SVH, because ident.name is just an index
60 // into intern table (i.e. essentially a random address), not
61 // computed from the name content.
63 // With the below enums, the SVH computation is not sensitive to
64 // artifacts of how rustc was invoked nor of how the source code
65 // was laid out. (Or at least it is *less* sensitive.)
67 // This enum represents the different potential bits of code the
68 // visitor could encounter that could affect the ABI for the crate,
69 // and assigns each a distinct tag to feed into the hash computation.
71 enum SawAbiComponent
<'a
> {
73 // FIXME (#14132): should we include (some function of)
74 // ident.ctxt as well?
75 SawIdent(token
::InternedString
),
76 SawStructDef(token
::InternedString
),
78 SawLifetime(token
::InternedString
),
79 SawLifetimeDef(token
::InternedString
),
96 SawExpr(SawExprComponent
<'a
>),
97 SawStmt(SawStmtComponent
),
100 /// SawExprComponent carries all of the information that we want
101 /// to include in the hash that *won't* be covered by the
102 /// subsequent recursive traversal of the expression's
103 /// substructure by the visitor.
105 /// We know every Expr_ variant is covered by a variant because
106 /// `fn saw_expr` maps each to some case below. Ensuring that
107 /// each variant carries an appropriate payload has to be verified
110 /// (However, getting that *exactly* right is not so important
111 /// because the SVH is just a developer convenience; there is no
112 /// guarantee of collision-freedom, hash collisions are just
113 /// (hopefully) unlikely.)
115 pub enum SawExprComponent
<'a
> {
117 SawExprLoop(Option
<token
::InternedString
>),
118 SawExprField(token
::InternedString
),
119 SawExprTupField(usize),
120 SawExprBreak(Option
<token
::InternedString
>),
121 SawExprAgain(Option
<token
::InternedString
>),
128 SawExprBinary(hir
::BinOp_
),
129 SawExprUnary(hir
::UnOp
),
130 SawExprLit(ast
::LitKind
),
139 SawExprAssignOp(hir
::BinOp_
),
141 SawExprPath(Option
<usize>),
142 SawExprAddrOf(hir
::Mutability
),
144 SawExprInlineAsm(&'a hir
::InlineAsm
),
149 fn saw_expr
<'a
>(node
: &'a Expr_
) -> SawExprComponent
<'a
> {
151 ExprBox(..) => SawExprBox
,
152 ExprVec(..) => SawExprVec
,
153 ExprCall(..) => SawExprCall
,
154 ExprMethodCall(..) => SawExprMethodCall
,
155 ExprTup(..) => SawExprTup
,
156 ExprBinary(op
, _
, _
) => SawExprBinary(op
.node
),
157 ExprUnary(op
, _
) => SawExprUnary(op
),
158 ExprLit(ref lit
) => SawExprLit(lit
.node
.clone()),
159 ExprCast(..) => SawExprCast
,
160 ExprType(..) => SawExprType
,
161 ExprIf(..) => SawExprIf
,
162 ExprWhile(..) => SawExprWhile
,
163 ExprLoop(_
, id
) => SawExprLoop(id
.map(|id
| id
.node
.as_str())),
164 ExprMatch(..) => SawExprMatch
,
165 ExprClosure(..) => SawExprClosure
,
166 ExprBlock(..) => SawExprBlock
,
167 ExprAssign(..) => SawExprAssign
,
168 ExprAssignOp(op
, _
, _
) => SawExprAssignOp(op
.node
),
169 ExprField(_
, name
) => SawExprField(name
.node
.as_str()),
170 ExprTupField(_
, id
) => SawExprTupField(id
.node
),
171 ExprIndex(..) => SawExprIndex
,
172 ExprPath(ref qself
, _
) => SawExprPath(qself
.as_ref().map(|q
| q
.position
)),
173 ExprAddrOf(m
, _
) => SawExprAddrOf(m
),
174 ExprBreak(id
) => SawExprBreak(id
.map(|id
| id
.node
.as_str())),
175 ExprAgain(id
) => SawExprAgain(id
.map(|id
| id
.node
.as_str())),
176 ExprRet(..) => SawExprRet
,
177 ExprInlineAsm(ref a
,_
,_
) => SawExprInlineAsm(a
),
178 ExprStruct(..) => SawExprStruct
,
179 ExprRepeat(..) => SawExprRepeat
,
183 /// SawStmtComponent is analogous to SawExprComponent, but for statements.
185 pub enum SawStmtComponent
{
190 impl<'a
, 'tcx
> Visitor
<'a
> for StrictVersionHashVisitor
<'a
, 'tcx
> {
191 fn visit_nested_item(&mut self, _
: ItemId
) {
192 // Each item is hashed independently; ignore nested items.
195 fn visit_variant_data(&mut self, s
: &'a VariantData
, name
: Name
,
196 g
: &'a Generics
, _
: NodeId
, _
: Span
) {
197 debug
!("visit_variant_data: st={:?}", self.st
);
198 SawStructDef(name
.as_str()).hash(self.st
);
199 visit
::walk_generics(self, g
);
200 visit
::walk_struct_def(self, s
)
203 fn visit_variant(&mut self, v
: &'a Variant
, g
: &'a Generics
, item_id
: NodeId
) {
204 debug
!("visit_variant: st={:?}", self.st
);
205 SawVariant
.hash(self.st
);
206 // walk_variant does not call walk_generics, so do it here.
207 visit
::walk_generics(self, g
);
208 visit
::walk_variant(self, v
, g
, item_id
)
211 // All of the remaining methods just record (in the hash
212 // SipHasher) that the visitor saw that particular variant
213 // (with its payload), and continue walking as the default
216 // Some of the implementations have some notes as to how one
217 // might try to make their SVH computation less discerning
218 // (e.g. by incorporating reachability analysis). But
219 // currently all of their implementations are uniform and
222 // (If you edit a method such that it deviates from the
223 // pattern, please move that method up above this comment.)
225 fn visit_name(&mut self, _
: Span
, name
: Name
) {
226 debug
!("visit_name: st={:?}", self.st
);
227 SawIdent(name
.as_str()).hash(self.st
);
230 fn visit_lifetime(&mut self, l
: &'a Lifetime
) {
231 debug
!("visit_lifetime: st={:?}", self.st
);
232 SawLifetime(l
.name
.as_str()).hash(self.st
);
235 fn visit_lifetime_def(&mut self, l
: &'a LifetimeDef
) {
236 debug
!("visit_lifetime_def: st={:?}", self.st
);
237 SawLifetimeDef(l
.lifetime
.name
.as_str()).hash(self.st
);
240 // We do recursively walk the bodies of functions/methods
241 // (rather than omitting their bodies from the hash) since
242 // monomorphization and cross-crate inlining generally implies
243 // that a change to a crate body will require downstream
244 // crates to be recompiled.
245 fn visit_expr(&mut self, ex
: &'a Expr
) {
246 debug
!("visit_expr: st={:?}", self.st
);
247 SawExpr(saw_expr(&ex
.node
)).hash(self.st
); visit
::walk_expr(self, ex
)
250 fn visit_stmt(&mut self, s
: &'a Stmt
) {
251 debug
!("visit_stmt: st={:?}", self.st
);
253 // We don't want to modify the hash for decls, because
254 // they might be item decls (if they are local decls,
255 // we'll hash that fact in visit_local); but we do want to
256 // remember if this was a StmtExpr or StmtSemi (the later
257 // had an explicit semi-colon; this affects the typing
261 StmtExpr(..) => SawStmt(SawStmtExpr
).hash(self.st
),
262 StmtSemi(..) => SawStmt(SawStmtSemi
).hash(self.st
),
265 visit
::walk_stmt(self, s
)
268 fn visit_foreign_item(&mut self, i
: &'a ForeignItem
) {
269 debug
!("visit_foreign_item: st={:?}", self.st
);
271 // FIXME (#14132) ideally we would incorporate privacy (or
272 // perhaps reachability) somewhere here, so foreign items
273 // that do not leak into downstream crates would not be
275 SawForeignItem
.hash(self.st
); visit
::walk_foreign_item(self, i
)
278 fn visit_item(&mut self, i
: &'a Item
) {
279 debug
!("visit_item: {:?} st={:?}", i
, self.st
);
281 // FIXME (#14132) ideally would incorporate reachability
282 // analysis somewhere here, so items that never leak into
283 // downstream crates (e.g. via monomorphisation or
284 // inlining) would not be part of the ABI.
285 SawItem
.hash(self.st
); visit
::walk_item(self, i
)
288 fn visit_mod(&mut self, m
: &'a Mod
, _s
: Span
, n
: NodeId
) {
289 debug
!("visit_mod: st={:?}", self.st
);
290 SawMod
.hash(self.st
); visit
::walk_mod(self, m
, n
)
293 fn visit_ty(&mut self, t
: &'a Ty
) {
294 debug
!("visit_ty: st={:?}", self.st
);
295 SawTy
.hash(self.st
); visit
::walk_ty(self, t
)
298 fn visit_generics(&mut self, g
: &'a Generics
) {
299 debug
!("visit_generics: st={:?}", self.st
);
300 SawGenerics
.hash(self.st
); visit
::walk_generics(self, g
)
303 fn visit_fn(&mut self, fk
: FnKind
<'a
>, fd
: &'a FnDecl
,
304 b
: &'a Block
, s
: Span
, n
: NodeId
) {
305 debug
!("visit_fn: st={:?}", self.st
);
306 SawFn
.hash(self.st
); visit
::walk_fn(self, fk
, fd
, b
, s
, n
)
309 fn visit_trait_item(&mut self, ti
: &'a TraitItem
) {
310 debug
!("visit_trait_item: st={:?}", self.st
);
311 SawTraitItem
.hash(self.st
); visit
::walk_trait_item(self, ti
)
314 fn visit_impl_item(&mut self, ii
: &'a ImplItem
) {
315 debug
!("visit_impl_item: st={:?}", self.st
);
316 SawImplItem
.hash(self.st
); visit
::walk_impl_item(self, ii
)
319 fn visit_struct_field(&mut self, s
: &'a StructField
) {
320 debug
!("visit_struct_field: st={:?}", self.st
);
321 SawStructField
.hash(self.st
); visit
::walk_struct_field(self, s
)
324 fn visit_path(&mut self, path
: &'a Path
, _
: ast
::NodeId
) {
325 debug
!("visit_path: st={:?}", self.st
);
326 SawPath
.hash(self.st
); visit
::walk_path(self, path
)
329 fn visit_block(&mut self, b
: &'a Block
) {
330 debug
!("visit_block: st={:?}", self.st
);
331 SawBlock
.hash(self.st
); visit
::walk_block(self, b
)
334 fn visit_pat(&mut self, p
: &'a Pat
) {
335 debug
!("visit_pat: st={:?}", self.st
);
336 SawPat
.hash(self.st
); visit
::walk_pat(self, p
)
339 fn visit_local(&mut self, l
: &'a Local
) {
340 debug
!("visit_local: st={:?}", self.st
);
341 SawLocal
.hash(self.st
); visit
::walk_local(self, l
)
344 fn visit_arm(&mut self, a
: &'a Arm
) {
345 debug
!("visit_arm: st={:?}", self.st
);
346 SawArm
.hash(self.st
); visit
::walk_arm(self, a
)
349 fn visit_id(&mut self, id
: NodeId
) {
350 debug
!("visit_id: id={} st={:?}", id
, self.st
);
351 self.hash_resolve(id
);
364 impl<'a
, 'tcx
> StrictVersionHashVisitor
<'a
, 'tcx
> {
365 fn hash_resolve(&mut self, id
: ast
::NodeId
) {
366 // Because whether or not a given id has an entry is dependent
367 // solely on expr variant etc, we don't need to hash whether
368 // or not an entry was present (we are already hashing what
369 // variant it is above when we visit the HIR).
371 if let Some(def
) = self.tcx
.def_map
.borrow().get(&id
) {
372 self.hash_partial_def(def
);
375 if let Some(traits
) = self.tcx
.trait_map
.get(&id
) {
376 traits
.len().hash(self.st
);
377 for candidate
in traits
{
378 self.hash_def_id(candidate
.def_id
);
383 fn hash_def_id(&mut self, def_id
: DefId
) {
384 let def_path
= self.tcx
.def_path(def_id
);
385 self.hash_def_path(&def_path
);
388 fn hash_partial_def(&mut self, def
: &PathResolution
) {
389 self.hash_def(def
.base_def
);
390 def
.depth
.hash(self.st
);
393 fn hash_def(&mut self, def
: Def
) {
395 // Crucial point: for all of these variants, the variant +
396 // add'l data that is added is always the same if the
397 // def-id is the same, so it suffices to hash the def-id
400 Def
::ForeignMod(..) |
405 Def
::AssociatedTy(..) |
411 Def
::AssociatedConst(..) |
414 DefHash
::SawDefId
.hash(self.st
);
415 self.hash_def_id(def
.def_id());
419 DefHash
::SawLabel
.hash(self.st
);
420 // we don't encode the `id` because it always refers to something
421 // within this item, so if it changed, there would have to be other
424 Def
::PrimTy(ref prim_ty
) => {
425 DefHash
::SawPrimTy
.hash(self.st
);
426 prim_ty
.hash(self.st
);
429 DefHash
::SawSelfTy
.hash(self.st
);
430 // the meaning of Self is always the same within a
431 // given context, so we don't need to hash the other
435 DefHash
::SawErr
.hash(self.st
);