]> git.proxmox.com Git - rustc.git/blame - src/librustc_incremental/calculate_svh.rs
Imported Upstream version 1.11.0+dfsg1
[rustc.git] / src / librustc_incremental / calculate_svh.rs
CommitLineData
1a4d82fc
JJ
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.
4//
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.
10
54a0048b
SL
11//! Calculation of a Strict Version Hash for crates. For a length
12//! comment explaining the general idea, see `librustc/middle/svh.rs`.
13
1a4d82fc 14use std::hash::{Hash, SipHasher, Hasher};
54a0048b
SL
15use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
16use rustc::hir::svh::Svh;
a7813a04 17use rustc::ty::TyCtxt;
54a0048b 18use rustc::hir::intravisit::{self, Visitor};
1a4d82fc 19
54a0048b 20use self::svh_visitor::StrictVersionHashVisitor;
1a4d82fc 21
54a0048b
SL
22pub trait SvhCalculate {
23 /// Calculate the SVH for an entire krate.
a7813a04 24 fn calculate_krate_hash(self) -> Svh;
1a4d82fc 25
54a0048b 26 /// Calculate the SVH for a particular item.
a7813a04 27 fn calculate_item_hash(self, def_id: DefId) -> u64;
54a0048b 28}
1a4d82fc 29
a7813a04
XL
30impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
31 fn calculate_krate_hash(self) -> Svh {
1a4d82fc
JJ
32 // FIXME (#14132): This is better than it used to be, but it still not
33 // ideal. We now attempt to hash only the relevant portions of the
34 // Crate AST as well as the top-level crate attributes. (However,
35 // the hashing of the crate attributes should be double-checked
36 // to ensure it is not incorporating implementation artifacts into
37 // the hash that are not otherwise visible.)
38
54a0048b
SL
39 let crate_disambiguator = self.sess.crate_disambiguator.get();
40 let krate = self.map.krate();
41
1a4d82fc
JJ
42 // FIXME: this should use SHA1, not SipHash. SipHash is not built to
43 // avoid collisions.
44 let mut state = SipHasher::new();
54a0048b 45 debug!("state: {:?}", state);
1a4d82fc 46
54a0048b
SL
47 // FIXME(#32753) -- at (*) we `to_le` for endianness, but is
48 // this enough, and does it matter anyway?
49 "crate_disambiguator".hash(&mut state);
50 crate_disambiguator.as_str().len().to_le().hash(&mut state); // (*)
51 crate_disambiguator.as_str().hash(&mut state);
52
53 debug!("crate_disambiguator: {:?}", crate_disambiguator.as_str());
54 debug!("state: {:?}", state);
1a4d82fc
JJ
55
56 {
54a0048b
SL
57 let mut visit = StrictVersionHashVisitor::new(&mut state, self);
58 krate.visit_all_items(&mut visit);
1a4d82fc
JJ
59 }
60
61 // FIXME (#14132): This hash is still sensitive to e.g. the
62 // spans of the crate Attributes and their underlying
63 // MetaItems; we should make ContentHashable impl for those
64 // types and then use hash_content. But, since all crate
65 // attributes should appear near beginning of the file, it is
66 // not such a big deal to be sensitive to their spans for now.
67 //
68 // We hash only the MetaItems instead of the entire Attribute
69 // to avoid hashing the AttrId
85aaf69f 70 for attr in &krate.attrs {
54a0048b 71 debug!("krate attr {:?}", attr);
1a4d82fc
JJ
72 attr.node.value.hash(&mut state);
73 }
74
a7813a04 75 Svh::new(state.finish())
1a4d82fc 76 }
1a4d82fc 77
a7813a04 78 fn calculate_item_hash(self, def_id: DefId) -> u64 {
54a0048b
SL
79 assert!(def_id.is_local());
80
a7813a04
XL
81 debug!("calculate_item_hash(def_id={:?})", def_id);
82
54a0048b
SL
83 let mut state = SipHasher::new();
84
85 {
86 let mut visit = StrictVersionHashVisitor::new(&mut state, self);
87 if def_id.index == CRATE_DEF_INDEX {
88 // the crate root itself is not registered in the map
89 // as an item, so we have to fetch it this way
90 let krate = self.map.krate();
91 intravisit::walk_crate(&mut visit, krate);
92 } else {
93 let node_id = self.map.as_local_node_id(def_id).unwrap();
a7813a04
XL
94 let item = self.map.expect_item(node_id);
95 visit.visit_item(item);
54a0048b
SL
96 }
97 }
98
a7813a04
XL
99 let hash = state.finish();
100
101 debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, hash);
102
103 hash
1a4d82fc
JJ
104 }
105}
106
107// FIXME (#14132): Even this SVH computation still has implementation
108// artifacts: namely, the order of item declaration will affect the
109// hash computation, but for many kinds of items the order of
110// declaration should be irrelevant to the ABI.
111
112mod svh_visitor {
113 pub use self::SawExprComponent::*;
114 pub use self::SawStmtComponent::*;
115 use self::SawAbiComponent::*;
b039eaaf 116 use syntax::ast::{self, Name, NodeId};
1a4d82fc 117 use syntax::parse::token;
3157f602 118 use syntax_pos::Span;
a7813a04 119 use rustc::ty::TyCtxt;
54a0048b
SL
120 use rustc::hir;
121 use rustc::hir::*;
122 use rustc::hir::intravisit as visit;
123 use rustc::hir::intravisit::{Visitor, FnKind};
1a4d82fc
JJ
124
125 use std::hash::{Hash, SipHasher};
126
54a0048b 127 pub struct StrictVersionHashVisitor<'a, 'tcx: 'a> {
a7813a04 128 pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
1a4d82fc
JJ
129 pub st: &'a mut SipHasher,
130 }
131
54a0048b
SL
132 impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> {
133 pub fn new(st: &'a mut SipHasher,
a7813a04 134 tcx: TyCtxt<'a, 'tcx, 'tcx>)
54a0048b
SL
135 -> Self {
136 StrictVersionHashVisitor { st: st, tcx: tcx }
137 }
1a4d82fc
JJ
138 }
139
85aaf69f 140 // To off-load the bulk of the hash-computation on #[derive(Hash)],
1a4d82fc
JJ
141 // we define a set of enums corresponding to the content that our
142 // crate visitor will encounter as it traverses the ast.
143 //
144 // The important invariant is that all of the Saw*Component enums
145 // do not carry any Spans, Names, or Idents.
146 //
147 // Not carrying any Names/Idents is the important fix for problem
148 // noted on PR #13948: using the ident.name as the basis for a
149 // hash leads to unstable SVH, because ident.name is just an index
150 // into intern table (i.e. essentially a random address), not
151 // computed from the name content.
152 //
153 // With the below enums, the SVH computation is not sensitive to
154 // artifacts of how rustc was invoked nor of how the source code
155 // was laid out. (Or at least it is *less* sensitive.)
156
157 // This enum represents the different potential bits of code the
158 // visitor could encounter that could affect the ABI for the crate,
159 // and assigns each a distinct tag to feed into the hash computation.
160 #[derive(Hash)]
161 enum SawAbiComponent<'a> {
162
163 // FIXME (#14132): should we include (some function of)
164 // ident.ctxt as well?
165 SawIdent(token::InternedString),
166 SawStructDef(token::InternedString),
167
b039eaaf 168 SawLifetime(token::InternedString),
1a4d82fc
JJ
169 SawLifetimeDef(token::InternedString),
170
171 SawMod,
1a4d82fc
JJ
172 SawForeignItem,
173 SawItem,
174 SawDecl,
175 SawTy,
176 SawGenerics,
177 SawFn,
c34b1796
AL
178 SawTraitItem,
179 SawImplItem,
1a4d82fc
JJ
180 SawStructField,
181 SawVariant,
1a4d82fc 182 SawPath,
1a4d82fc
JJ
183 SawBlock,
184 SawPat,
185 SawLocal,
186 SawArm,
187 SawExpr(SawExprComponent<'a>),
188 SawStmt(SawStmtComponent),
189 }
190
191 /// SawExprComponent carries all of the information that we want
192 /// to include in the hash that *won't* be covered by the
193 /// subsequent recursive traversal of the expression's
194 /// substructure by the visitor.
195 ///
196 /// We know every Expr_ variant is covered by a variant because
197 /// `fn saw_expr` maps each to some case below. Ensuring that
198 /// each variant carries an appropriate payload has to be verified
199 /// by hand.
200 ///
201 /// (However, getting that *exactly* right is not so important
202 /// because the SVH is just a developer convenience; there is no
203 /// guarantee of collision-freedom, hash collisions are just
204 /// (hopefully) unlikely.)
205 #[derive(Hash)]
206 pub enum SawExprComponent<'a> {
207
208 SawExprLoop(Option<token::InternedString>),
209 SawExprField(token::InternedString),
c34b1796 210 SawExprTupField(usize),
1a4d82fc
JJ
211 SawExprBreak(Option<token::InternedString>),
212 SawExprAgain(Option<token::InternedString>),
213
214 SawExprBox,
215 SawExprVec,
216 SawExprCall,
217 SawExprMethodCall,
218 SawExprTup,
e9174d1e
SL
219 SawExprBinary(hir::BinOp_),
220 SawExprUnary(hir::UnOp),
7453a54e 221 SawExprLit(ast::LitKind),
1a4d82fc 222 SawExprCast,
9cc50fc6 223 SawExprType,
1a4d82fc
JJ
224 SawExprIf,
225 SawExprWhile,
226 SawExprMatch,
227 SawExprClosure,
228 SawExprBlock,
229 SawExprAssign,
e9174d1e 230 SawExprAssignOp(hir::BinOp_),
1a4d82fc 231 SawExprIndex,
c34b1796 232 SawExprPath(Option<usize>),
e9174d1e 233 SawExprAddrOf(hir::Mutability),
1a4d82fc 234 SawExprRet,
e9174d1e 235 SawExprInlineAsm(&'a hir::InlineAsm),
1a4d82fc
JJ
236 SawExprStruct,
237 SawExprRepeat,
1a4d82fc
JJ
238 }
239
240 fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
241 match *node {
242 ExprBox(..) => SawExprBox,
243 ExprVec(..) => SawExprVec,
244 ExprCall(..) => SawExprCall,
245 ExprMethodCall(..) => SawExprMethodCall,
246 ExprTup(..) => SawExprTup,
85aaf69f 247 ExprBinary(op, _, _) => SawExprBinary(op.node),
1a4d82fc
JJ
248 ExprUnary(op, _) => SawExprUnary(op),
249 ExprLit(ref lit) => SawExprLit(lit.node.clone()),
250 ExprCast(..) => SawExprCast,
9cc50fc6 251 ExprType(..) => SawExprType,
1a4d82fc
JJ
252 ExprIf(..) => SawExprIf,
253 ExprWhile(..) => SawExprWhile,
3157f602 254 ExprLoop(_, id) => SawExprLoop(id.map(|id| id.node.as_str())),
1a4d82fc
JJ
255 ExprMatch(..) => SawExprMatch,
256 ExprClosure(..) => SawExprClosure,
257 ExprBlock(..) => SawExprBlock,
258 ExprAssign(..) => SawExprAssign,
85aaf69f 259 ExprAssignOp(op, _, _) => SawExprAssignOp(op.node),
b039eaaf 260 ExprField(_, name) => SawExprField(name.node.as_str()),
1a4d82fc
JJ
261 ExprTupField(_, id) => SawExprTupField(id.node),
262 ExprIndex(..) => SawExprIndex,
c34b1796 263 ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)),
1a4d82fc 264 ExprAddrOf(m, _) => SawExprAddrOf(m),
a7813a04
XL
265 ExprBreak(id) => SawExprBreak(id.map(|id| id.node.as_str())),
266 ExprAgain(id) => SawExprAgain(id.map(|id| id.node.as_str())),
1a4d82fc 267 ExprRet(..) => SawExprRet,
54a0048b 268 ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a),
1a4d82fc
JJ
269 ExprStruct(..) => SawExprStruct,
270 ExprRepeat(..) => SawExprRepeat,
1a4d82fc
JJ
271 }
272 }
273
274 /// SawStmtComponent is analogous to SawExprComponent, but for statements.
275 #[derive(Hash)]
276 pub enum SawStmtComponent {
277 SawStmtDecl,
278 SawStmtExpr,
279 SawStmtSemi,
280 }
281
282 fn saw_stmt(node: &Stmt_) -> SawStmtComponent {
283 match *node {
284 StmtDecl(..) => SawStmtDecl,
285 StmtExpr(..) => SawStmtExpr,
286 StmtSemi(..) => SawStmtSemi,
1a4d82fc
JJ
287 }
288 }
289
54a0048b 290 impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> {
92a42be0 291 fn visit_nested_item(&mut self, item: ItemId) {
54a0048b
SL
292 debug!("visit_nested_item: {:?} st={:?}", item, self.st);
293 let def_path = self.tcx.map.def_path_from_id(item.id);
294 def_path.hash(self.st);
92a42be0
SL
295 }
296
297 fn visit_variant_data(&mut self, s: &'a VariantData, name: Name,
298 g: &'a Generics, _: NodeId, _: Span) {
b039eaaf 299 SawStructDef(name.as_str()).hash(self.st);
1a4d82fc
JJ
300 visit::walk_generics(self, g);
301 visit::walk_struct_def(self, s)
302 }
303
92a42be0 304 fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
1a4d82fc
JJ
305 SawVariant.hash(self.st);
306 // walk_variant does not call walk_generics, so do it here.
307 visit::walk_generics(self, g);
b039eaaf 308 visit::walk_variant(self, v, g, item_id)
1a4d82fc
JJ
309 }
310
311 // All of the remaining methods just record (in the hash
312 // SipHasher) that the visitor saw that particular variant
313 // (with its payload), and continue walking as the default
314 // visitor would.
315 //
316 // Some of the implementations have some notes as to how one
317 // might try to make their SVH computation less discerning
318 // (e.g. by incorporating reachability analysis). But
319 // currently all of their implementations are uniform and
320 // uninteresting.
321 //
322 // (If you edit a method such that it deviates from the
323 // pattern, please move that method up above this comment.)
324
b039eaaf
SL
325 fn visit_name(&mut self, _: Span, name: Name) {
326 SawIdent(name.as_str()).hash(self.st);
1a4d82fc
JJ
327 }
328
92a42be0 329 fn visit_lifetime(&mut self, l: &'a Lifetime) {
b039eaaf 330 SawLifetime(l.name.as_str()).hash(self.st);
1a4d82fc
JJ
331 }
332
92a42be0 333 fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) {
c1a9b12d 334 SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st);
1a4d82fc
JJ
335 }
336
337 // We do recursively walk the bodies of functions/methods
338 // (rather than omitting their bodies from the hash) since
339 // monomorphization and cross-crate inlining generally implies
340 // that a change to a crate body will require downstream
341 // crates to be recompiled.
92a42be0 342 fn visit_expr(&mut self, ex: &'a Expr) {
1a4d82fc
JJ
343 SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex)
344 }
345
92a42be0 346 fn visit_stmt(&mut self, s: &'a Stmt) {
1a4d82fc
JJ
347 SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s)
348 }
349
92a42be0 350 fn visit_foreign_item(&mut self, i: &'a ForeignItem) {
1a4d82fc
JJ
351 // FIXME (#14132) ideally we would incorporate privacy (or
352 // perhaps reachability) somewhere here, so foreign items
353 // that do not leak into downstream crates would not be
354 // part of the ABI.
355 SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i)
356 }
357
92a42be0 358 fn visit_item(&mut self, i: &'a Item) {
54a0048b 359 debug!("visit_item: {:?} st={:?}", i, self.st);
1a4d82fc
JJ
360 // FIXME (#14132) ideally would incorporate reachability
361 // analysis somewhere here, so items that never leak into
362 // downstream crates (e.g. via monomorphisation or
363 // inlining) would not be part of the ABI.
364 SawItem.hash(self.st); visit::walk_item(self, i)
365 }
366
92a42be0 367 fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) {
1a4d82fc
JJ
368 SawMod.hash(self.st); visit::walk_mod(self, m)
369 }
370
92a42be0 371 fn visit_decl(&mut self, d: &'a Decl) {
1a4d82fc
JJ
372 SawDecl.hash(self.st); visit::walk_decl(self, d)
373 }
374
92a42be0 375 fn visit_ty(&mut self, t: &'a Ty) {
1a4d82fc
JJ
376 SawTy.hash(self.st); visit::walk_ty(self, t)
377 }
378
92a42be0 379 fn visit_generics(&mut self, g: &'a Generics) {
1a4d82fc
JJ
380 SawGenerics.hash(self.st); visit::walk_generics(self, g)
381 }
382
92a42be0
SL
383 fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl,
384 b: &'a Block, s: Span, _: NodeId) {
1a4d82fc
JJ
385 SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s)
386 }
387
92a42be0 388 fn visit_trait_item(&mut self, ti: &'a TraitItem) {
c34b1796 389 SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti)
1a4d82fc
JJ
390 }
391
92a42be0 392 fn visit_impl_item(&mut self, ii: &'a ImplItem) {
c34b1796 393 SawImplItem.hash(self.st); visit::walk_impl_item(self, ii)
1a4d82fc
JJ
394 }
395
92a42be0 396 fn visit_struct_field(&mut self, s: &'a StructField) {
1a4d82fc
JJ
397 SawStructField.hash(self.st); visit::walk_struct_field(self, s)
398 }
399
92a42be0 400 fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) {
1a4d82fc
JJ
401 SawPath.hash(self.st); visit::walk_path(self, path)
402 }
403
92a42be0 404 fn visit_block(&mut self, b: &'a Block) {
1a4d82fc
JJ
405 SawBlock.hash(self.st); visit::walk_block(self, b)
406 }
407
92a42be0 408 fn visit_pat(&mut self, p: &'a Pat) {
1a4d82fc
JJ
409 SawPat.hash(self.st); visit::walk_pat(self, p)
410 }
411
92a42be0 412 fn visit_local(&mut self, l: &'a Local) {
1a4d82fc
JJ
413 SawLocal.hash(self.st); visit::walk_local(self, l)
414 }
415
92a42be0 416 fn visit_arm(&mut self, a: &'a Arm) {
1a4d82fc
JJ
417 SawArm.hash(self.st); visit::walk_arm(self, a)
418 }
419 }
420}