Merge pull request #564 from solson/rustup
Support two-phase borrows, and other rustup
This commit is contained in:
commit
bccadeb4f7
@ -47,7 +47,7 @@ pub fn run(filename: &str, bencher: &mut Bencher) {
|
||||
let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect(
|
||||
"no main or start function found",
|
||||
);
|
||||
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
|
||||
let entry_def_id = tcx.hir().local_def_id(entry_node_id);
|
||||
|
||||
bencher.borrow_mut().iter(|| {
|
||||
eval_main(tcx, entry_def_id, false);
|
||||
|
@ -1 +1 @@
|
||||
nightly-2018-12-03
|
||||
nightly-2018-12-08
|
||||
|
@ -93,7 +93,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
|
||||
fn visit_item(&mut self, i: &'hir hir::Item) {
|
||||
if let hir::ItemKind::Fn(.., body_id) = i.node {
|
||||
if i.attrs.iter().any(|attr| attr.name() == "test") {
|
||||
let did = self.0.hir.body_owner_def_id(body_id);
|
||||
let did = self.0.hir().body_owner_def_id(body_id);
|
||||
println!("running test: {}", self.0.def_path_debug_str(did));
|
||||
miri::eval_main(self.0, did, /*validate*/true);
|
||||
self.1.session.abort_if_errors();
|
||||
@ -105,7 +105,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
|
||||
}
|
||||
state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state));
|
||||
} else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
|
||||
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
|
||||
let entry_def_id = tcx.hir().local_def_id(entry_node_id);
|
||||
miri::eval_main(tcx, entry_def_id, /*validate*/true);
|
||||
|
||||
state.session.abort_if_errors();
|
||||
|
@ -128,7 +128,7 @@ fn after_analysis<'a, 'tcx>(
|
||||
attr.name() == "test"
|
||||
})
|
||||
{
|
||||
let did = self.tcx.hir.body_owner_def_id(body_id);
|
||||
let did = self.tcx.hir().body_owner_def_id(body_id);
|
||||
println!(
|
||||
"running test: {}",
|
||||
self.tcx.def_path_debug_str(did),
|
||||
@ -145,7 +145,7 @@ fn after_analysis<'a, 'tcx>(
|
||||
&mut Visitor { tcx, state, validate }
|
||||
);
|
||||
} else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
|
||||
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
|
||||
let entry_def_id = tcx.hir().local_def_id(entry_node_id);
|
||||
miri::eval_main(tcx, entry_def_id, validate);
|
||||
|
||||
state.session.abort_if_errors();
|
||||
|
@ -508,6 +508,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) {
|
||||
@ -518,7 +519,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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
@ -539,7 +539,7 @@ 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(
|
||||
@ -547,11 +547,13 @@ pub trait EvalContextExt<'tcx> {
|
||||
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>;
|
||||
|
||||
@ -649,9 +651,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);
|
||||
@ -671,7 +672,7 @@ 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(
|
||||
@ -679,6 +680,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
|
||||
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)?;
|
||||
@ -698,16 +700,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.
|
||||
@ -730,19 +741,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>>
|
||||
@ -763,7 +775,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(())
|
||||
|
@ -7,5 +7,5 @@ pub(crate) struct NonZero<T>(pub(crate) T);
|
||||
|
||||
fn main() {
|
||||
// Make sure that we detect this even when no function call is happening along the way
|
||||
let _x = Some(NonZero(0)); //~ ERROR encountered 0, but expected something greater or equal to 1
|
||||
let _x = Some(unsafe { NonZero(0) }); //~ ERROR encountered 0, but expected something greater or equal to 1
|
||||
}
|
||||
|
70
tests/run-pass/2phase.rs
Normal file
70
tests/run-pass/2phase.rs
Normal file
@ -0,0 +1,70 @@
|
||||
#![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();
|
||||
match_two_phase();
|
||||
with_interior_mutability();
|
||||
//FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved
|
||||
//two_phase_overlapping1();
|
||||
//two_phase_overlapping2();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user