Skip to content

Commit 1ef95aa

Browse files
committed
Add tombstone checks to make sure incr-comp reads aren't dirty
1 parent b04ebef commit 1ef95aa

File tree

7 files changed

+93
-56
lines changed

7 files changed

+93
-56
lines changed

src/librustc/dep_graph/dep_tracking_map.rs

+59-9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
use hir::def_id::DefId;
1212
use rustc_data_structures::fx::FxHashMap;
13+
14+
#[cfg(debug_assertions)]
15+
use rustc_data_structures::fx::FxHashSet;
16+
1317
use std::cell::RefCell;
1418
use std::collections::hash_map::Entry;
1519
use std::ops::Index;
@@ -26,6 +30,8 @@ pub struct DepTrackingMap<M: DepTrackingMapConfig> {
2630
phantom: PhantomData<M>,
2731
graph: DepGraph,
2832
map: FxHashMap<M::Key, M::Value>,
33+
#[cfg(debug_assertions)]
34+
tombstones: RefCell<FxHashSet<M::Key>>,
2935
}
3036

3137
pub trait DepTrackingMapConfig {
@@ -35,11 +41,22 @@ pub trait DepTrackingMapConfig {
3541
}
3642

3743
impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
44+
#[cfg(debug_assertions)]
45+
pub fn new(graph: DepGraph) -> DepTrackingMap<M> {
46+
DepTrackingMap {
47+
phantom: PhantomData,
48+
graph: graph,
49+
map: FxHashMap(),
50+
tombstones: RefCell::new(FxHashSet()),
51+
}
52+
}
53+
54+
#[cfg(not(debug_assertions))]
3855
pub fn new(graph: DepGraph) -> DepTrackingMap<M> {
3956
DepTrackingMap {
4057
phantom: PhantomData,
4158
graph: graph,
42-
map: FxHashMap()
59+
map: FxHashMap(),
4360
}
4461
}
4562

@@ -59,13 +76,31 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
5976

6077
pub fn get(&self, k: &M::Key) -> Option<&M::Value> {
6178
self.read(k);
62-
self.map.get(k)
79+
let result = self.map.get(k);
80+
81+
#[cfg(debug_assertions)]
82+
{
83+
if result.is_none() {
84+
self.tombstones.borrow_mut().insert(k.clone());
85+
}
86+
}
87+
88+
result
6389
}
6490

6591
pub fn insert(&mut self, k: M::Key, v: M::Value) {
6692
self.write(&k);
93+
94+
// If we ever read a `None` value for this key, we do not want
95+
// to permit a later write to it. The only valid use case for
96+
// this is the memoization pattern: for that, use `memoize()`
97+
// below
98+
#[cfg(debug_assertions)]
99+
assert!(!self.tombstones.borrow().contains(&k),
100+
"inserting to `{0:?}` after reading from `{0:?}`",
101+
M::to_dep_node(&k));
67102
let old_value = self.map.insert(k, v);
68-
assert!(old_value.is_none());
103+
assert!(old_value.is_none(), "inserted value twice");
69104
}
70105

71106
pub fn entry(&mut self, k: M::Key) -> Entry<M::Key, M::Value> {
@@ -75,7 +110,13 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
75110

76111
pub fn contains_key(&self, k: &M::Key) -> bool {
77112
self.read(k);
78-
self.map.contains_key(k)
113+
if self.map.contains_key(k) {
114+
true
115+
} else {
116+
#[cfg(debug_assertions)]
117+
self.tombstones.borrow_mut().insert(k.clone());
118+
false
119+
}
79120
}
80121

81122
pub fn keys(&self) -> Vec<M::Key> {
@@ -125,7 +166,7 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
125166
/// let item_def_id = ccx.tcx.hir.local_def_id(it.id);
126167
/// ccx.tcx.item_types.memoized(item_def_id, || {
127168
/// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*)
128-
/// compute_type_of_item(ccx, item)
169+
/// Some(compute_type_of_item(ccx, item))
129170
/// });
130171
/// }
131172
/// ```
@@ -134,7 +175,7 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
134175
/// accesses the body of the item `item`, so we register a read
135176
/// from `Hir(item_def_id)`.
136177
fn memoize<OP>(&self, key: M::Key, op: OP) -> M::Value
137-
where OP: FnOnce() -> M::Value
178+
where OP: FnOnce() -> Option<M::Value>
138179
{
139180
let graph;
140181
{
@@ -147,9 +188,18 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
147188
}
148189

149190
let _task = graph.in_task(M::to_dep_node(&key));
150-
let result = op();
151-
self.borrow_mut().map.insert(key, result.clone());
152-
result
191+
if let Some(result) = op() {
192+
let old_value = self.borrow_mut().map.insert(key, result.clone());
193+
assert!(old_value.is_none());
194+
result
195+
} else {
196+
self.borrow().map
197+
.get(&key)
198+
.unwrap_or_else(|| bug!(
199+
"memoize closure failed to write to {:?}", M::to_dep_node(&key)
200+
))
201+
.clone()
202+
}
153203
}
154204
}
155205

src/librustc/ty/contents.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl fmt::Debug for TypeContents {
125125

126126
impl<'a, 'tcx> ty::TyS<'tcx> {
127127
pub fn type_contents(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> TypeContents {
128-
return tcx.tc_cache.memoize(self, || tc_ty(tcx, self, &mut FxHashMap()));
128+
return tcx.tc_cache.memoize(self, || Some(tc_ty(tcx, self, &mut FxHashMap())));
129129

130130
fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
131131
ty: Ty<'tcx>,

src/librustc/ty/mod.rs

+22-38
Original file line numberDiff line numberDiff line change
@@ -1633,65 +1633,51 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16331633
/// check should catch this case.
16341634
fn calculate_sized_constraint_inner(&self,
16351635
tcx: TyCtxt<'a, 'tcx, 'tcx>,
1636-
stack: &mut Vec<DefId>)
1636+
stack: &mut Vec<(DefId, bool)>)
16371637
-> Ty<'tcx>
16381638
{
1639-
if let Some(ty) = tcx.maps.adt_sized_constraint.borrow().get(&self.did) {
1640-
return ty;
1641-
}
1642-
1643-
// Follow the memoization pattern: push the computation of
1644-
// DepNode::SizedConstraint as our current task.
1645-
let _task = tcx.dep_graph.in_task(DepNode::SizedConstraint(self.did));
1639+
if let Some(index) = stack.iter().position(|pair| pair.0 == self.did) {
1640+
stack[index].1 = true;
16461641

1647-
if stack.contains(&self.did) {
16481642
debug!("calculate_sized_constraint: {:?} is recursive", self);
16491643
// This should be reported as an error by `check_representable`.
16501644
//
16511645
// Consider the type as Sized in the meanwhile to avoid
16521646
// further errors.
1653-
tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err);
16541647
return tcx.types.err;
16551648
}
16561649

1657-
stack.push(self.did);
1650+
tcx.maps.adt_sized_constraint.memoize(self.did, || {
1651+
stack.push((self.did, false));
16581652

1659-
let tys : Vec<_> =
1653+
let tys: Vec<_> =
16601654
self.variants.iter().flat_map(|v| {
16611655
v.fields.last()
16621656
}).flat_map(|f| {
16631657
let ty = tcx.item_type(f.did);
16641658
self.sized_constraint_for_ty(tcx, stack, ty)
16651659
}).collect();
16661660

1667-
let self_ = stack.pop().unwrap();
1668-
assert_eq!(self_, self.did);
1661+
let (self_, cycle) = stack.pop().unwrap();
1662+
assert_eq!(self_, self.did);
16691663

1670-
let ty = match tys.len() {
1671-
_ if tys.references_error() => tcx.types.err,
1672-
0 => tcx.types.bool,
1673-
1 => tys[0],
1674-
_ => tcx.intern_tup(&tys[..], false)
1675-
};
1664+
let ty = if cycle || tys.references_error() {
1665+
tcx.types.err
1666+
} else {
1667+
match tys.len() {
1668+
0 => tcx.types.bool,
1669+
1 => tys[0],
1670+
_ => tcx.intern_tup(&tys[..], false)
1671+
}
1672+
};
16761673

1677-
let old = tcx.maps.adt_sized_constraint.borrow().get(&self.did).cloned();
1678-
match old {
1679-
Some(old_ty) => {
1680-
debug!("calculate_sized_constraint: {:?} recurred", self);
1681-
assert_eq!(old_ty, tcx.types.err);
1682-
old_ty
1683-
}
1684-
None => {
1685-
debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
1686-
tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, ty);
1687-
ty
1688-
}
1689-
}
1674+
Some(ty)
1675+
})
16901676
}
16911677

16921678
fn sized_constraint_for_ty(&self,
16931679
tcx: TyCtxt<'a, 'tcx, 'tcx>,
1694-
stack: &mut Vec<DefId>,
1680+
stack: &mut Vec<(DefId, bool)>,
16951681
ty: Ty<'tcx>)
16961682
-> Vec<Ty<'tcx>> {
16971683
let result = match ty.sty {
@@ -2094,9 +2080,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
20942080
}
20952081
}
20962082

2097-
// memoize wants us to return something, so return
2098-
// the one we generated for this def-id
2099-
*self.maps.associated_item.borrow().get(&def_id).unwrap()
2083+
None
21002084
})
21012085
}
21022086

@@ -2176,7 +2160,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
21762160
}
21772161
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait")
21782162
};
2179-
Rc::new(vec)
2163+
Some(Rc::new(vec))
21802164
})
21812165
}
21822166

src/librustc/util/common.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ pub trait MemoizationMap {
208208
/// added into the dep graph. See the `DepTrackingMap` impl for
209209
/// more details!
210210
fn memoize<OP>(&self, key: Self::Key, op: OP) -> Self::Value
211-
where OP: FnOnce() -> Self::Value;
211+
where OP: FnOnce() -> Option<Self::Value>;
212212
}
213213

214214
impl<K, V, S> MemoizationMap for RefCell<HashMap<K,V,S>>
@@ -218,15 +218,18 @@ impl<K, V, S> MemoizationMap for RefCell<HashMap<K,V,S>>
218218
type Value = V;
219219

220220
fn memoize<OP>(&self, key: K, op: OP) -> V
221-
where OP: FnOnce() -> V
221+
where OP: FnOnce() -> Option<V>
222222
{
223223
let result = self.borrow().get(&key).cloned();
224224
match result {
225225
Some(result) => result,
226226
None => {
227-
let result = op();
228-
self.borrow_mut().insert(key, result.clone());
229-
result
227+
if let Some(result) = op() {
228+
self.borrow_mut().insert(key, result.clone());
229+
result
230+
} else {
231+
self.borrow().get(&key).unwrap().clone()
232+
}
230233
}
231234
}
232235
}

src/librustc_trans/common.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
488488
let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
489489

490490
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
491-
vtable
491+
Some(vtable)
492492
})
493493
})
494494
}

src/librustc_trans/monomorphize.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, '
121121
} else {
122122
self.shared.project_cache().memoize(ty, || {
123123
debug!("AssociatedTypeNormalizer: ty={:?}", ty);
124-
self.shared.tcx().normalize_associated_type(&ty)
124+
Some(self.shared.tcx().normalize_associated_type(&ty))
125125
})
126126
}
127127
}

src/librustc_typeck/collect.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
617617
prev_discr = Some(if let Some(e) = variant.node.disr_expr {
618618
let expr_did = tcx.hir.local_def_id(e.node_id);
619619
let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || {
620-
evaluate_disr_expr(tcx, e)
620+
Some(evaluate_disr_expr(tcx, e))
621621
});
622622

623623
match result {

0 commit comments

Comments
 (0)