Skip to content

Commit c4c2716

Browse files
committed
make reborrow shallow, and fix tests for that
1 parent 5bbf673 commit c4c2716

6 files changed

+23
-54
lines changed

src/stacked_borrows.rs

+2-44
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc::hir::{MutMutable, MutImmutable};
1212
use rustc::mir::RetagKind;
1313

1414
use crate::{
15-
InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor,
15+
InterpResult, InterpError, HelpersEvalContextExt,
1616
MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy,
1717
};
1818

@@ -632,54 +632,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
632632
}
633633
}
634634

635-
// We need a visitor to visit all references. However, that requires
636-
// a `MemPlace`, so we have a fast path for reference types that
637-
// avoids allocating.
635+
// We only reborrow "bare" references/boxes.
638636
if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) {
639637
// Fast path.
640638
let val = this.read_immediate(this.place_to_op(place)?)?;
641639
let val = this.retag_reference(val, mutbl, protector)?;
642640
this.write_immediate(val, place)?;
643-
return Ok(());
644-
}
645-
let place = this.force_allocation(place)?;
646-
647-
let mut visitor = RetagVisitor { ecx: this, kind };
648-
visitor.visit_value(place)?;
649-
650-
// The actual visitor.
651-
struct RetagVisitor<'ecx, 'mir, 'tcx> {
652-
ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>,
653-
kind: RetagKind,
654-
}
655-
impl<'ecx, 'mir, 'tcx>
656-
MutValueVisitor<'mir, 'tcx, Evaluator<'tcx>>
657-
for
658-
RetagVisitor<'ecx, 'mir, 'tcx>
659-
{
660-
type V = MPlaceTy<'tcx, Tag>;
661-
662-
#[inline(always)]
663-
fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> {
664-
&mut self.ecx
665-
}
666-
667-
// Primitives of reference type, that is the one thing we are interested in.
668-
fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
669-
{
670-
// Cannot use `builtin_deref` because that reports *immutable* for `Box`,
671-
// making it useless.
672-
if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) {
673-
let val = self.ecx.read_immediate(place.into())?;
674-
let val = self.ecx.retag_reference(
675-
val,
676-
mutbl,
677-
protector
678-
)?;
679-
self.ecx.write_immediate(val, place.into())?;
680-
}
681-
Ok(())
682-
}
683641
}
684642

685643
Ok(())

tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ mod safe {
99
assert!(mid <= len);
1010

1111
(from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid"
12-
//~^ ERROR borrow stack
1312
from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
1413
}
1514
}
@@ -18,6 +17,7 @@ mod safe {
1817
fn main() {
1918
let mut array = [1,2,3,4];
2019
let (a, b) = safe::split_at_mut(&mut array, 0);
20+
//~^ ERROR borrow stack
2121
a[1] = 5;
2222
b[1] = 6;
2323
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
// Make sure that we cannot return a `&mut` that got already invalidated, not even in an `Option`.
2+
// Due to shallow reborrowing, the error only surfaces when we look into the `Option`.
23
fn foo(x: &mut (i32, i32)) -> Option<&mut i32> {
34
let xraw = x as *mut (i32, i32);
4-
let ret = Some(unsafe { &mut (*xraw).1 });
5+
let ret = unsafe { &mut (*xraw).1 }; // let-bind to avoid 2phase
6+
let ret = Some(ret);
57
let _val = unsafe { *xraw }; // invalidate xref
6-
ret //~ ERROR borrow stack
8+
ret
79
}
810

911
fn main() {
10-
foo(&mut (1, 2));
12+
match foo(&mut (1, 2)) {
13+
Some(_x) => {}, //~ ERROR borrow stack
14+
None => {},
15+
}
1116
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// Make sure that we cannot return a `&mut` that got already invalidated, not even in a tuple.
2+
// Due to shallow reborrowing, the error only surfaces when we look into the tuple.
23
fn foo(x: &mut (i32, i32)) -> (&mut i32,) {
34
let xraw = x as *mut (i32, i32);
45
let ret = (unsafe { &mut (*xraw).1 },);
56
let _val = unsafe { *xraw }; // invalidate xref
6-
ret //~ ERROR borrow stack
7+
ret
78
}
89

910
fn main() {
10-
foo(&mut (1, 2));
11+
foo(&mut (1, 2)).0; //~ ERROR: borrow stack
1112
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
// Make sure that we cannot return a `&` that got already invalidated, not even in an `Option`.
2+
// Due to shallow reborrowing, the error only surfaces when we look into the `Option`.
23
fn foo(x: &mut (i32, i32)) -> Option<&i32> {
34
let xraw = x as *mut (i32, i32);
45
let ret = Some(unsafe { &(*xraw).1 });
56
unsafe { *xraw = (42, 23) }; // unfreeze
6-
ret //~ ERROR borrow stack
7+
ret
78
}
89

910
fn main() {
10-
foo(&mut (1, 2));
11+
match foo(&mut (1, 2)) {
12+
Some(_x) => {}, //~ ERROR borrow stack
13+
None => {},
14+
}
1115
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// Make sure that we cannot return a `&` that got already invalidated, not even in a tuple.
2+
// Due to shallow reborrowing, the error only surfaces when we look into the tuple.
23
fn foo(x: &mut (i32, i32)) -> (&i32,) {
34
let xraw = x as *mut (i32, i32);
45
let ret = (unsafe { &(*xraw).1 },);
56
unsafe { *xraw = (42, 23) }; // unfreeze
6-
ret //~ ERROR borrow stack
7+
ret
78
}
89

910
fn main() {
10-
foo(&mut (1, 2));
11+
foo(&mut (1, 2)).0; //~ ERROR borrow stack
1112
}

0 commit comments

Comments
 (0)