Skip to content

Commit f174099

Browse files
committed
array index accesses are stable places
1 parent b9a35dc commit f174099

File tree

3 files changed

+54
-6
lines changed

3 files changed

+54
-6
lines changed

src/librustc_mir/build/expr/as_place.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
8686
// region_scope=None so place indexes live forever. They are scalars so they
8787
// do not need storage annotations, and they are often copied between
8888
// places.
89+
// Making this a *fresh* temporary also means we do not have to worry about
90+
// the index changing later: Nothing will ever change this temporary.
91+
// The "retagging" transformation (for Stacked Borrows) relies on this.
8992
let idx = unpack!(block = this.as_temp(block, None, index, Mutability::Mut));
9093

9194
// bounds check:

src/librustc_mir/transform/add_retag.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,19 @@ fn is_stable<'tcx>(
3838
// Recurse for projections
3939
Projection(ref proj) => {
4040
match proj.elem {
41-
ProjectionElem::Deref |
42-
ProjectionElem::Index(_) =>
43-
// Which place these point to depends on external circumstances
44-
// (a local storing the array index, the current value of
45-
// the projection base), so we stop tracking here.
41+
// Which place this evaluates to can change with any memory write,
42+
// so cannot assume this to be stable.
43+
ProjectionElem::Deref =>
4644
false,
45+
// Array indices are intersting, but MIR building generates a *fresh*
46+
// temporary for every array access, so the index cannot be changed as
47+
// a side-effect.
48+
ProjectionElem::Index { .. } |
49+
// The rest is completely boring, they just offset by a constant.
4750
ProjectionElem::Field { .. } |
4851
ProjectionElem::ConstantIndex { .. } |
4952
ProjectionElem::Subslice { .. } |
5053
ProjectionElem::Downcast { .. } =>
51-
// These just offset by a constant, entirely independent of everything else.
5254
is_stable(&proj.base),
5355
}
5456
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Retagging (from Stacked Borrows) relies on the array index being a fresh
2+
// temporary, so that side-effects cannot change it.
3+
// Test that this is indeed the case.
4+
5+
unsafe fn foo(z: *mut usize) -> u32 {
6+
*z = 2;
7+
99
8+
}
9+
10+
fn main() {
11+
let mut x = [42, 43, 44];
12+
let mut y = 1;
13+
let z: *mut usize = &mut y;
14+
x[y] = unsafe { foo(z) };
15+
}
16+
17+
// END RUST SOURCE
18+
// START rustc.main.EraseRegions.after.mir
19+
// bb0: {
20+
// ...
21+
// _6 = &mut _2;
22+
// _5 = &mut (*_6);
23+
// _4 = move _5 as *mut usize (Misc);
24+
// _3 = move _4;
25+
// ...
26+
// _8 = _3;
27+
// _7 = const foo(move _8) -> bb1;
28+
// }
29+
//
30+
// bb1: {
31+
// ...
32+
// _9 = _2;
33+
// _10 = Len(_1);
34+
// _11 = Lt(_9, _10);
35+
// assert(move _11, "index out of bounds: the len is move _10 but the index is _9") -> bb2;
36+
// }
37+
//
38+
// bb2: {
39+
// _1[_9] = move _7;
40+
// ...
41+
// return;
42+
// }
43+
// END rustc.main.EraseRegions.after.mir

0 commit comments

Comments
 (0)