Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
fn retag(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
fn_entry: bool,
two_phase: bool,
place: PlaceTy<'tcx, Borrow>,
) -> EvalResult<'tcx> {
if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) {
Expand All @@ -535,7 +536,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
// uninitialized data.
Ok(())
} else {
ecx.retag(fn_entry, place)
ecx.retag(fn_entry, two_phase, place)
}
}

Expand Down
34 changes: 23 additions & 11 deletions src/stacked_borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable};
use crate::{
EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor,
MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra,
Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy,
Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy,
};

pub type Timestamp = u64;
Expand Down Expand Up @@ -534,19 +534,21 @@ pub trait EvalContextExt<'tcx> {
size: Size,
fn_barrier: bool,
new_bor: Borrow
) -> EvalResult<'tcx, Pointer<Borrow>>;
) -> EvalResult<'tcx>;

/// Retag an indidual pointer, returning the retagged version.
fn retag_reference(
&mut self,
ptr: ImmTy<'tcx, Borrow>,
mutbl: Mutability,
fn_barrier: bool,
two_phase: bool,
) -> EvalResult<'tcx, Immediate<Borrow>>;

fn retag(
&mut self,
fn_entry: bool,
two_phase: bool,
place: PlaceTy<'tcx, Borrow>
) -> EvalResult<'tcx>;

Expand Down Expand Up @@ -644,9 +646,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
size: Size,
fn_barrier: bool,
new_bor: Borrow
) -> EvalResult<'tcx, Pointer<Borrow>> {
) -> EvalResult<'tcx> {
let ptr = place.ptr.to_ptr()?;
let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor);
let barrier = if fn_barrier { Some(self.frame().extra) } else { None };
trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}",
ptr, place.layout.ty, new_bor);
Expand All @@ -666,14 +667,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw };
alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?;
}
Ok(new_ptr)
Ok(())
}

fn retag_reference(
&mut self,
val: ImmTy<'tcx, Borrow>,
mutbl: Mutability,
fn_barrier: bool,
two_phase: bool,
) -> EvalResult<'tcx, Immediate<Borrow>> {
// We want a place for where the ptr *points to*, so we get one.
let place = self.ref_to_mplace(val)?;
Expand All @@ -693,16 +695,25 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
};

// Reborrow.
let new_ptr = self.reborrow(place, size, fn_barrier, new_bor)?;
self.reborrow(place, size, fn_barrier, new_bor)?;
let new_place = place.with_tag(new_bor);
// Handle two-phase borrows.
if two_phase {
assert!(mutbl == MutMutable, "two-phase shared borrows make no sense");
// We immediately share it, to allow read accesses
let two_phase_time = self.machine.stacked_borrows.increment_clock();
let two_phase_bor = Borrow::Shr(Some(two_phase_time));
self.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?;
}

// Return new ptr
let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place };
// Return new ptr.
Ok(new_place.to_ref())
}

fn retag(
&mut self,
fn_entry: bool,
two_phase: bool,
place: PlaceTy<'tcx, Borrow>
) -> EvalResult<'tcx> {
// Determine mutability and whether to add a barrier.
Expand All @@ -725,19 +736,20 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) {
// fast path
let val = self.read_immediate(self.place_to_op(place)?)?;
let val = self.retag_reference(val, mutbl, barrier)?;
let val = self.retag_reference(val, mutbl, barrier, two_phase)?;
self.write_immediate(val, place)?;
return Ok(());
}
let place = self.force_allocation(place)?;

let mut visitor = RetagVisitor { ecx: self, fn_entry };
let mut visitor = RetagVisitor { ecx: self, fn_entry, two_phase };
visitor.visit_value(place)?;

// The actual visitor
struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> {
ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>,
fn_entry: bool,
two_phase: bool,
}
impl<'ecx, 'a, 'mir, 'tcx>
MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>>
Expand All @@ -758,7 +770,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
// making it useless.
if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.fn_entry) {
let val = self.ecx.read_immediate(place.into())?;
let val = self.ecx.retag_reference(val, mutbl, barrier)?;
let val = self.ecx.retag_reference(val, mutbl, barrier, self.two_phase)?;
self.ecx.write_immediate(val, place.into())?;
}
Ok(())
Expand Down
69 changes: 69 additions & 0 deletions tests/run-pass/2phase.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#![feature(nll)]

trait S: Sized {
fn tpb(&mut self, _s: Self) {}
}

impl S for i32 {}

fn two_phase1() {
let mut x = 3;
x.tpb(x);
}

fn two_phase2() {
let mut v = vec![];
v.push(v.len());
}

/*
fn two_phase_overlapping1() {
let mut x = vec![];
let p = &x;
x.push(p.len());
}

fn two_phase_overlapping2() {
use std::ops::AddAssign;
let mut x = 1;
let l = &x;
x.add_assign(x + *l);
}
*/

fn match_two_phase() {
let mut x = 3;
match x {
ref mut y if { let _val = x; let _val = *y; true } => {},
_ => (),
}
}

fn with_interior_mutability() {
use std::cell::Cell;

trait Thing: Sized {
fn do_the_thing(&mut self, _s: i32) {}
}

impl<T> Thing for Cell<T> {}

let mut x = Cell::new(1);
let l = &x;
x
.do_the_thing({
x.set(3);
l.set(4);
x.get() + l.get()
})
;
}

fn main() {
two_phase1();
two_phase2();
//two_phase_overlapping1();
//two_phase_overlapping2();
match_two_phase();
with_interior_mutability();
}