Skip to content

Commit e3025a0

Browse files
ICH: Hash expression spans if their source location is captured for panics
1 parent bf5b824 commit e3025a0

File tree

2 files changed

+276
-35
lines changed

2 files changed

+276
-35
lines changed

src/librustc_incremental/calculate_svh/svh_visitor.rs

+103-35
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use self::SawTyComponent::*;
2121
use self::SawTraitOrImplItemComponent::*;
2222
use syntax::abi::Abi;
2323
use syntax::ast::{self, Name, NodeId};
24+
use syntax::attr;
2425
use syntax::parse::token;
2526
use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
2627
use rustc::hir;
@@ -53,6 +54,7 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
5354
def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
5455
hash_spans: bool,
5556
codemap: &'a mut CachingCodemapView<'tcx>,
57+
overflow_checks_enabled: bool,
5658
}
5759

5860
impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
@@ -62,12 +64,16 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
6264
codemap: &'a mut CachingCodemapView<'tcx>,
6365
hash_spans: bool)
6466
-> Self {
67+
let check_overflow = tcx.sess.opts.debugging_opts.force_overflow_checks
68+
.unwrap_or(tcx.sess.opts.debug_assertions);
69+
6570
StrictVersionHashVisitor {
6671
st: st,
6772
tcx: tcx,
6873
def_path_hashes: def_path_hashes,
6974
hash_spans: hash_spans,
7075
codemap: codemap,
76+
overflow_checks_enabled: check_overflow,
7177
}
7278
}
7379

@@ -83,7 +89,6 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
8389
// Also note that we are hashing byte offsets for the column, not unicode
8490
// codepoint offsets. For the purpose of the hash that's sufficient.
8591
fn hash_span(&mut self, span: Span) {
86-
debug_assert!(self.hash_spans);
8792
debug!("hash_span: st={:?}", self.st);
8893

8994
// If this is not an empty or invalid span, we want to hash the last
@@ -241,37 +246,80 @@ enum SawExprComponent<'a> {
241246
SawExprRepeat,
242247
}
243248

244-
fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
249+
// The boolean returned indicates whether the span of this expression is always
250+
// significant, regardless of debuginfo.
251+
fn saw_expr<'a>(node: &'a Expr_,
252+
overflow_checks_enabled: bool)
253+
-> (SawExprComponent<'a>, bool) {
254+
let binop_can_panic_at_runtime = |binop| {
255+
match binop {
256+
BiAdd |
257+
BiSub |
258+
BiMul => overflow_checks_enabled,
259+
260+
BiDiv |
261+
BiRem => true,
262+
263+
BiAnd |
264+
BiOr |
265+
BiBitXor |
266+
BiBitAnd |
267+
BiBitOr |
268+
BiShl |
269+
BiShr |
270+
BiEq |
271+
BiLt |
272+
BiLe |
273+
BiNe |
274+
BiGe |
275+
BiGt => false
276+
}
277+
};
278+
279+
let unop_can_panic_at_runtime = |unop| {
280+
match unop {
281+
UnDeref |
282+
UnNot => false,
283+
UnNeg => overflow_checks_enabled,
284+
}
285+
};
286+
245287
match *node {
246-
ExprBox(..) => SawExprBox,
247-
ExprArray(..) => SawExprArray,
248-
ExprCall(..) => SawExprCall,
249-
ExprMethodCall(..) => SawExprMethodCall,
250-
ExprTup(..) => SawExprTup,
251-
ExprBinary(op, ..) => SawExprBinary(op.node),
252-
ExprUnary(op, _) => SawExprUnary(op),
253-
ExprLit(ref lit) => SawExprLit(lit.node.clone()),
254-
ExprCast(..) => SawExprCast,
255-
ExprType(..) => SawExprType,
256-
ExprIf(..) => SawExprIf,
257-
ExprWhile(..) => SawExprWhile,
258-
ExprLoop(_, id) => SawExprLoop(id.map(|id| id.node.as_str())),
259-
ExprMatch(..) => SawExprMatch,
260-
ExprClosure(cc, _, _, _) => SawExprClosure(cc),
261-
ExprBlock(..) => SawExprBlock,
262-
ExprAssign(..) => SawExprAssign,
263-
ExprAssignOp(op, ..) => SawExprAssignOp(op.node),
264-
ExprField(_, name) => SawExprField(name.node.as_str()),
265-
ExprTupField(_, id) => SawExprTupField(id.node),
266-
ExprIndex(..) => SawExprIndex,
267-
ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)),
268-
ExprAddrOf(m, _) => SawExprAddrOf(m),
269-
ExprBreak(id) => SawExprBreak(id.map(|id| id.node.as_str())),
270-
ExprAgain(id) => SawExprAgain(id.map(|id| id.node.as_str())),
271-
ExprRet(..) => SawExprRet,
272-
ExprInlineAsm(ref a,..) => SawExprInlineAsm(a),
273-
ExprStruct(..) => SawExprStruct,
274-
ExprRepeat(..) => SawExprRepeat,
288+
ExprBox(..) => (SawExprBox, false),
289+
ExprArray(..) => (SawExprArray, false),
290+
ExprCall(..) => (SawExprCall, false),
291+
ExprMethodCall(..) => (SawExprMethodCall, false),
292+
ExprTup(..) => (SawExprTup, false),
293+
ExprBinary(op, ..) => {
294+
(SawExprBinary(op.node), binop_can_panic_at_runtime(op.node))
295+
}
296+
ExprUnary(op, _) => {
297+
(SawExprUnary(op), unop_can_panic_at_runtime(op))
298+
}
299+
ExprLit(ref lit) => (SawExprLit(lit.node.clone()), false),
300+
ExprCast(..) => (SawExprCast, false),
301+
ExprType(..) => (SawExprType, false),
302+
ExprIf(..) => (SawExprIf, false),
303+
ExprWhile(..) => (SawExprWhile, false),
304+
ExprLoop(_, id) => (SawExprLoop(id.map(|id| id.node.as_str())), false),
305+
ExprMatch(..) => (SawExprMatch, false),
306+
ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false),
307+
ExprBlock(..) => (SawExprBlock, false),
308+
ExprAssign(..) => (SawExprAssign, false),
309+
ExprAssignOp(op, ..) => {
310+
(SawExprAssignOp(op.node), binop_can_panic_at_runtime(op.node))
311+
}
312+
ExprField(_, name) => (SawExprField(name.node.as_str()), false),
313+
ExprTupField(_, id) => (SawExprTupField(id.node), false),
314+
ExprIndex(..) => (SawExprIndex, true),
315+
ExprPath(ref qself, _) => (SawExprPath(qself.as_ref().map(|q| q.position)), false),
316+
ExprAddrOf(m, _) => (SawExprAddrOf(m), false),
317+
ExprBreak(id) => (SawExprBreak(id.map(|id| id.node.as_str())), false),
318+
ExprAgain(id) => (SawExprAgain(id.map(|id| id.node.as_str())), false),
319+
ExprRet(..) => (SawExprRet, false),
320+
ExprInlineAsm(ref a,..) => (SawExprInlineAsm(a), false),
321+
ExprStruct(..) => (SawExprStruct, false),
322+
ExprRepeat(..) => (SawExprRepeat, false),
275323
}
276324
}
277325

@@ -421,10 +469,13 @@ macro_rules! hash_attrs {
421469

422470
macro_rules! hash_span {
423471
($visitor:expr, $span:expr) => ({
424-
if $visitor.hash_spans {
472+
hash_span!($visitor, $span, false)
473+
});
474+
($visitor:expr, $span:expr, $force:expr) => ({
475+
if $force || $visitor.hash_spans {
425476
$visitor.hash_span($span);
426477
}
427-
})
478+
});
428479
}
429480

430481
impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
@@ -474,10 +525,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
474525

475526
fn visit_expr(&mut self, ex: &'tcx Expr) {
476527
debug!("visit_expr: st={:?}", self.st);
477-
SawExpr(saw_expr(&ex.node)).hash(self.st);
528+
let (saw_expr, force_span) = saw_expr(&ex.node,
529+
self.overflow_checks_enabled);
530+
SawExpr(saw_expr).hash(self.st);
478531
// No need to explicitly hash the discriminant here, since we are
479532
// implicitly hashing the discriminant of SawExprComponent.
480-
hash_span!(self, ex.span);
533+
hash_span!(self, ex.span, force_span);
481534
hash_attrs!(self, &ex.attrs);
482535
visit::walk_expr(self, ex)
483536
}
@@ -519,6 +572,9 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
519572

520573
fn visit_item(&mut self, i: &'tcx Item) {
521574
debug!("visit_item: {:?} st={:?}", i, self.st);
575+
576+
self.maybe_enable_overflow_checks(&i.attrs);
577+
522578
SawItem(saw_item(&i.node)).hash(self.st);
523579
hash_span!(self, i.span);
524580
hash_attrs!(self, &i.attrs);
@@ -545,6 +601,9 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
545601

546602
fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
547603
debug!("visit_trait_item: st={:?}", self.st);
604+
605+
self.maybe_enable_overflow_checks(&ti.attrs);
606+
548607
SawTraitItem(saw_trait_item(&ti.node)).hash(self.st);
549608
hash_span!(self, ti.span);
550609
hash_attrs!(self, &ti.attrs);
@@ -553,6 +612,9 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
553612

554613
fn visit_impl_item(&mut self, ii: &'tcx ImplItem) {
555614
debug!("visit_impl_item: st={:?}", self.st);
615+
616+
self.maybe_enable_overflow_checks(&ii.attrs);
617+
556618
SawImplItem(saw_impl_item(&ii.node)).hash(self.st);
557619
hash_span!(self, ii.span);
558620
hash_attrs!(self, &ii.attrs);
@@ -842,4 +904,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
842904
indices.sort_by_key(|index| get_key(&items[*index]));
843905
indices
844906
}
907+
908+
fn maybe_enable_overflow_checks(&mut self, item_attrs: &[ast::Attribute]) {
909+
if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") {
910+
self.overflow_checks_enabled = true;
911+
}
912+
}
845913
}
+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
// Copyright 2016 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+
11+
// This test case tests the incremental compilation hash (ICH) implementation
12+
// for exprs that can panic at runtime (e.g. because of bounds checking). For
13+
// these expressions an error message containing their source location is
14+
// generated, so their hash must always depend on their location in the source
15+
// code, not just when debuginfo is enabled.
16+
17+
// The general pattern followed here is: Change one thing between rev1 and rev2
18+
// and make sure that the hash has changed, then change nothing between rev2 and
19+
// rev3 and make sure that the hash has not changed.
20+
21+
// must-compile-successfully
22+
// revisions: cfail1 cfail2 cfail3
23+
// compile-flags: -Z query-dep-graph -C debug-assertions
24+
25+
#![allow(warnings)]
26+
#![feature(rustc_attrs)]
27+
#![crate_type="rlib"]
28+
29+
30+
// Indexing expression ---------------------------------------------------------
31+
#[cfg(cfail1)]
32+
pub fn indexing(slice: &[u8]) -> u8 {
33+
slice[100]
34+
}
35+
36+
#[cfg(not(cfail1))]
37+
#[rustc_dirty(label="Hir", cfg="cfail2")]
38+
#[rustc_clean(label="Hir", cfg="cfail3")]
39+
#[rustc_metadata_dirty(cfg="cfail2")]
40+
#[rustc_metadata_clean(cfg="cfail3")]
41+
pub fn indexing(slice: &[u8]) -> u8 {
42+
slice[100]
43+
}
44+
45+
46+
// Arithmetic overflow plus ----------------------------------------------------
47+
#[cfg(cfail1)]
48+
pub fn arithmetic_overflow_plus(val: i32) -> i32 {
49+
val + 1
50+
}
51+
52+
#[cfg(not(cfail1))]
53+
#[rustc_dirty(label="Hir", cfg="cfail2")]
54+
#[rustc_clean(label="Hir", cfg="cfail3")]
55+
#[rustc_metadata_dirty(cfg="cfail2")]
56+
#[rustc_metadata_clean(cfg="cfail3")]
57+
pub fn arithmetic_overflow_plus(val: i32) -> i32 {
58+
val + 1
59+
}
60+
61+
62+
// Arithmetic overflow minus ----------------------------------------------------
63+
#[cfg(cfail1)]
64+
pub fn arithmetic_overflow_minus(val: i32) -> i32 {
65+
val - 1
66+
}
67+
68+
#[cfg(not(cfail1))]
69+
#[rustc_dirty(label="Hir", cfg="cfail2")]
70+
#[rustc_clean(label="Hir", cfg="cfail3")]
71+
#[rustc_metadata_dirty(cfg="cfail2")]
72+
#[rustc_metadata_clean(cfg="cfail3")]
73+
pub fn arithmetic_overflow_minus(val: i32) -> i32 {
74+
val - 1
75+
}
76+
77+
78+
// Arithmetic overflow mult ----------------------------------------------------
79+
#[cfg(cfail1)]
80+
pub fn arithmetic_overflow_mult(val: i32) -> i32 {
81+
val * 2
82+
}
83+
84+
#[cfg(not(cfail1))]
85+
#[rustc_dirty(label="Hir", cfg="cfail2")]
86+
#[rustc_clean(label="Hir", cfg="cfail3")]
87+
#[rustc_metadata_dirty(cfg="cfail2")]
88+
#[rustc_metadata_clean(cfg="cfail3")]
89+
pub fn arithmetic_overflow_mult(val: i32) -> i32 {
90+
val * 2
91+
}
92+
93+
94+
// Arithmetic overflow negation ------------------------------------------------
95+
#[cfg(cfail1)]
96+
pub fn arithmetic_overflow_negation(val: i32) -> i32 {
97+
-val
98+
}
99+
100+
#[cfg(not(cfail1))]
101+
#[rustc_dirty(label="Hir", cfg="cfail2")]
102+
#[rustc_clean(label="Hir", cfg="cfail3")]
103+
#[rustc_metadata_dirty(cfg="cfail2")]
104+
#[rustc_metadata_clean(cfg="cfail3")]
105+
pub fn arithmetic_overflow_negation(val: i32) -> i32 {
106+
-val
107+
}
108+
109+
110+
// Division by zero ------------------------------------------------------------
111+
#[cfg(cfail1)]
112+
pub fn division_by_zero(val: i32) -> i32 {
113+
2 / val
114+
}
115+
116+
#[cfg(not(cfail1))]
117+
#[rustc_dirty(label="Hir", cfg="cfail2")]
118+
#[rustc_clean(label="Hir", cfg="cfail3")]
119+
#[rustc_metadata_dirty(cfg="cfail2")]
120+
#[rustc_metadata_clean(cfg="cfail3")]
121+
pub fn division_by_zero(val: i32) -> i32 {
122+
2 / val
123+
}
124+
125+
// Division by zero ------------------------------------------------------------
126+
#[cfg(cfail1)]
127+
pub fn mod_by_zero(val: i32) -> i32 {
128+
2 % val
129+
}
130+
131+
#[cfg(not(cfail1))]
132+
#[rustc_dirty(label="Hir", cfg="cfail2")]
133+
#[rustc_clean(label="Hir", cfg="cfail3")]
134+
#[rustc_metadata_dirty(cfg="cfail2")]
135+
#[rustc_metadata_clean(cfg="cfail3")]
136+
pub fn mod_by_zero(val: i32) -> i32 {
137+
2 % val
138+
}
139+
140+
141+
142+
// THE FOLLOWING ITEMS SHOULD NOT BE INFLUENCED BY THEIR SOURCE LOCATION
143+
144+
// bitwise ---------------------------------------------------------------------
145+
#[cfg(cfail1)]
146+
pub fn bitwise(val: i32) -> i32 {
147+
!val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1
148+
}
149+
150+
#[cfg(not(cfail1))]
151+
#[rustc_clean(label="Hir", cfg="cfail2")]
152+
#[rustc_clean(label="Hir", cfg="cfail3")]
153+
#[rustc_metadata_clean(cfg="cfail2")]
154+
#[rustc_metadata_clean(cfg="cfail3")]
155+
pub fn bitwise(val: i32) -> i32 {
156+
!val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1
157+
}
158+
159+
160+
// logical ---------------------------------------------------------------------
161+
#[cfg(cfail1)]
162+
pub fn logical(val1: bool, val2: bool, val3: bool) -> bool {
163+
val1 && val2 || val3
164+
}
165+
166+
#[cfg(not(cfail1))]
167+
#[rustc_clean(label="Hir", cfg="cfail2")]
168+
#[rustc_clean(label="Hir", cfg="cfail3")]
169+
#[rustc_metadata_clean(cfg="cfail2")]
170+
#[rustc_metadata_clean(cfg="cfail3")]
171+
pub fn logical(val1: bool, val2: bool, val3: bool) -> bool {
172+
val1 && val2 || val3
173+
}

0 commit comments

Comments
 (0)