Use PrimVal instead of Pointer where applicable

This commit is contained in:
Oliver Schneider 2017-06-20 14:26:50 +02:00
parent a6734cd890
commit ea6f6079ca
No known key found for this signature in database
GPG Key ID: A69F8D225B3AD7D9
6 changed files with 125 additions and 31 deletions

View File

@ -637,7 +637,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let value = self.eval_operand(operand)?;
// FIXME(solson)
let dest = self.force_allocation(dest)?.to_ptr()?;
let dest = PrimVal::Ptr(self.force_allocation(dest)?.to_ptr()?);
for i in 0..length {
let elem_dest = dest.offset(i * elem_size, self.memory.layout)?;
@ -893,6 +893,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
if pointee_size == 0 {
// rustc relies on offsetting pointers to zsts to be a nop
return Ok(ptr);
}
return if let Some(offset) = offset.checked_mul(pointee_size) {
let ptr = ptr.signed_offset(offset, self.memory.layout)?;
self.memory.check_bounds(ptr.to_ptr()?, false)?;
@ -943,7 +947,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.monomorphize(operand.ty(self.mir(), self.tcx), self.substs())
}
fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> {
fn copy(&mut self, src: PrimVal, dest: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> {
let size = self.type_size(ty)?.expect("cannot copy from an unsized type");
let align = self.type_align(ty)?;
self.memory.copy(src, dest, size, align)?;
@ -969,7 +973,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let substs = self.stack[frame].instance.substs;
let ptr = self.alloc_ptr_with_substs(ty, substs)?;
self.stack[frame].locals[local.index() - 1] = Some(Value::ByRef(ptr)); // it stays live
self.write_value_to_ptr(val, ptr, ty)?;
self.write_value_to_ptr(val, PrimVal::Ptr(ptr), ty)?;
let lval = Lvalue::from_ptr(ptr);
if let Some((field, field_ty)) = field {
self.lvalue_field(lval, field, ty, field_ty)?
@ -987,7 +991,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
_ => {
let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.instance.substs)?;
self.memory.mark_static(ptr.alloc_id);
self.write_value_to_ptr(global_val.value, ptr, global_val.ty)?;
self.write_value_to_ptr(global_val.value, PrimVal::Ptr(ptr), global_val.ty)?;
// see comment on `initialized` field
if global_val.initialized {
self.memory.mark_static_initalized(ptr.alloc_id, global_val.mutable)?;
@ -1059,7 +1063,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Lvalue::Ptr { ptr, extra } => {
assert_eq!(extra, LvalueExtra::None);
self.write_value_to_ptr(src_val, ptr.to_ptr()?, dest_ty)
self.write_value_to_ptr(src_val, ptr, dest_ty)
}
Lvalue::Local { frame, local, field } => {
@ -1090,7 +1094,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
//
// Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
// knew for certain that there were no outstanding pointers to this allocation.
self.write_value_to_ptr(src_val, dest_ptr, dest_ty)?;
self.write_value_to_ptr(src_val, PrimVal::Ptr(dest_ptr), dest_ty)?;
} else if let Value::ByRef(src_ptr) = src_val {
// If the value is not `ByRef`, then we know there are no pointers to it
@ -1108,7 +1112,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
write_dest(self, src_val)?;
} else {
let dest_ptr = self.alloc_ptr(dest_ty)?;
self.copy(src_ptr, dest_ptr, dest_ty)?;
self.copy(PrimVal::Ptr(src_ptr), PrimVal::Ptr(dest_ptr), dest_ty)?;
write_dest(self, Value::ByRef(dest_ptr))?;
}
@ -1123,16 +1127,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
pub(super) fn write_value_to_ptr(
&mut self,
value: Value,
dest: Pointer,
dest: PrimVal,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx> {
match value {
Value::ByRef(ptr) => self.copy(ptr, dest, dest_ty),
Value::ByRef(ptr) => self.copy(PrimVal::Ptr(ptr), dest, dest_ty),
Value::ByVal(primval) => {
let size = self.type_size(dest_ty)?.expect("dest type must be sized");
self.memory.write_primval(dest, primval, size)
}
Value::ByValPair(a, b) => self.write_pair_to_ptr(a, b, dest, dest_ty),
Value::ByValPair(a, b) => self.write_pair_to_ptr(a, b, dest.to_ptr()?, dest_ty),
}
}
@ -1153,8 +1157,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let field_1_ty = self.get_field_ty(ty, 1)?;
let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized");
let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized");
self.memory.write_primval(ptr.offset(field_0, self.memory.layout)?, a, field_0_size)?;
self.memory.write_primval(ptr.offset(field_1, self.memory.layout)?, b, field_1_size)?;
self.memory.write_primval(PrimVal::Ptr(ptr.offset(field_0, self.memory.layout)?), a, field_0_size)?;
self.memory.write_primval(PrimVal::Ptr(ptr.offset(field_1, self.memory.layout)?), b, field_1_size)?;
Ok(())
}
@ -1457,7 +1461,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let src_f_ptr = src_ptr.offset(src_field_offset, self.memory.layout)?;
let dst_f_ptr = dest.offset(dst_field_offset, self.memory.layout)?;
if src_fty == dst_fty {
self.copy(src_f_ptr, dst_f_ptr, src_fty)?;
self.copy(PrimVal::Ptr(src_f_ptr), PrimVal::Ptr(dst_f_ptr), src_fty)?;
} else {
self.unsize_into(Value::ByRef(src_f_ptr), src_fty, Lvalue::from_ptr(dst_f_ptr), dst_fty)?;
}

View File

@ -66,10 +66,11 @@ pub struct Global<'tcx> {
impl<'tcx> Lvalue<'tcx> {
/// Produces an Lvalue that will error if attempted to be read from
pub fn undef() -> Self {
Lvalue::Ptr {
ptr: PrimVal::Undef,
extra: LvalueExtra::None,
}
Self::from_primval_ptr(PrimVal::Undef)
}
fn from_primval_ptr(ptr: PrimVal) -> Self {
Lvalue::Ptr { ptr, extra: LvalueExtra::None }
}
pub fn zst() -> Self {
@ -77,7 +78,7 @@ impl<'tcx> Lvalue<'tcx> {
}
pub fn from_ptr(ptr: Pointer) -> Self {
Lvalue::Ptr { ptr: PrimVal::Ptr(ptr), extra: LvalueExtra::None }
Self::from_primval_ptr(PrimVal::Ptr(ptr))
}
pub(super) fn to_ptr_and_extra(self) -> (PrimVal, LvalueExtra) {

View File

@ -618,7 +618,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
return Ok(&mut []);
}
self.clear_relocations(ptr, size)?;
self.mark_definedness(ptr, size, true)?;
self.mark_definedness(PrimVal::Ptr(ptr), size, true)?;
self.get_bytes_unchecked_mut(ptr, size, align)
}
}
@ -671,10 +671,12 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
Ok(())
}
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: u64, align: u64) -> EvalResult<'tcx> {
pub fn copy(&mut self, src: PrimVal, dest: PrimVal, size: u64, align: u64) -> EvalResult<'tcx> {
if size == 0 {
return Ok(());
}
let src = src.to_ptr()?;
let dest = dest.to_ptr()?;
self.check_relocation_edges(src, size)?;
let src_bytes = self.get_bytes_unchecked(src, size, align)?.as_ptr();
@ -755,14 +757,14 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn write_primval(
&mut self,
dest: Pointer,
dest: PrimVal,
val: PrimVal,
size: u64,
) -> EvalResult<'tcx> {
match val {
PrimVal::Ptr(ptr) => {
assert_eq!(size, self.pointer_size());
self.write_ptr(dest, ptr)
self.write_ptr(dest.to_ptr()?, ptr)
}
PrimVal::Bytes(bytes) => {
@ -776,7 +778,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
16 => !0,
_ => bug!("unexpected PrimVal::Bytes size"),
};
self.write_uint(dest, bytes & mask, size)
self.write_uint(dest.to_ptr()?, bytes & mask, size)
}
PrimVal::Undef => self.mark_definedness(dest, size, false),
@ -962,13 +964,14 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn mark_definedness(
&mut self,
ptr: Pointer,
ptr: PrimVal,
size: u64,
new_state: bool
) -> EvalResult<'tcx> {
if size == 0 {
return Ok(())
}
let ptr = ptr.to_ptr()?;
let mut alloc = self.get_mut(ptr.alloc_id)?;
alloc.undef_mask.set_range(ptr.offset, ptr.offset + size, new_state);
Ok(())

View File

@ -69,7 +69,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
"atomic_store_rel" |
"volatile_store" => {
let ty = substs.type_at(0);
let dest = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
let dest = arg_vals[0].read_ptr(&self.memory)?;
self.write_value_to_ptr(arg_vals[1], dest, ty)?;
}
@ -145,8 +145,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value");
if elem_size != 0 {
let elem_align = self.type_align(elem_ty)?;
let src = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
let dest = arg_vals[1].read_ptr(&self.memory)?.to_ptr()?;
let src = arg_vals[0].read_ptr(&self.memory)?;
let dest = arg_vals[1].read_ptr(&self.memory)?;
let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
self.memory.copy(src, dest, count * elem_size, elem_align)?;
}
@ -284,7 +284,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
"move_val_init" => {
let ty = substs.type_at(0);
let ptr = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
let ptr = arg_vals[0].read_ptr(&self.memory)?;
self.write_value_to_ptr(arg_vals[1], ptr, ty)?;
}
@ -392,7 +392,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
if dest_align < src_align {
let ptr = self.force_allocation(dest)?.to_ptr()?;
self.memory.mark_packed(ptr, size);
self.write_value_to_ptr(arg_vals[0], ptr, dest_ty)?;
self.write_value_to_ptr(arg_vals[0], PrimVal::Ptr(ptr), dest_ty)?;
} else {
self.write_value(arg_vals[0], dest, dest_ty)?;
}
@ -403,7 +403,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let uninit = |this: &mut Self, val: Value| {
match val {
Value::ByRef(ptr) => {
this.memory.mark_definedness(ptr, size, false)?;
this.memory.mark_definedness(PrimVal::Ptr(ptr), size, false)?;
Ok(Value::ByRef(ptr))
},
_ => Ok(Value::ByVal(PrimVal::Undef)),
@ -412,7 +412,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
match dest {
Lvalue::Local { frame, local, field } => self.modify_local(frame, local, field.map(|(i, _)| i), uninit)?,
Lvalue::Ptr { ptr, extra: LvalueExtra::None } =>
self.memory.mark_definedness(ptr.to_ptr()?, size, false)?,
self.memory.mark_definedness(ptr, size, false)?,
Lvalue::Ptr { .. } => bug!("uninit intrinsic tried to write to fat ptr target"),
Lvalue::Global(cid) => self.modify_global(cid, uninit)?,
}

View File

@ -0,0 +1,58 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -C debug-assertions
use std::slice;
fn foo<T>(v: &[T]) -> Option<&[T]> {
let mut it = v.iter();
for _ in 0..5 {
let _ = it.next();
}
Some(it.as_slice())
}
fn foo_mut<T>(v: &mut [T]) -> Option<&mut [T]> {
let mut it = v.iter_mut();
for _ in 0..5 {
let _ = it.next();
}
Some(it.into_slice())
}
pub fn main() {
// In a slice of zero-size elements the pointer is meaningless.
// Ensure iteration still works even if the pointer is at the end of the address space.
let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) };
assert_eq!(slice.len(), 10);
assert_eq!(slice.iter().count(), 10);
// .nth() on the iterator should also behave correctly
let mut it = slice.iter();
assert!(it.nth(5).is_some());
assert_eq!(it.count(), 4);
// Converting Iter to a slice should never have a null pointer
assert!(foo(slice).is_some());
// Test mutable iterators as well
let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) };
assert_eq!(slice.len(), 10);
assert_eq!(slice.iter_mut().count(), 10);
{
let mut it = slice.iter_mut();
assert!(it.nth(5).is_some());
assert_eq!(it.count(), 4);
}
assert!(foo_mut(slice).is_some())
}

View File

@ -0,0 +1,28 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::collections::BinaryHeap;
use std::iter::Iterator;
fn main() {
const N: usize = 8;
for len in 0..N {
let mut tester = BinaryHeap::with_capacity(len);
assert_eq!(tester.len(), 0);
assert!(tester.capacity() >= len);
for _ in 0..len {
tester.push(());
}
assert_eq!(tester.len(), len);
assert_eq!(tester.iter().count(), len);
tester.clear();
}
}