Use PrimVal instead of Pointer where applicable
This commit is contained in:
parent
a6734cd890
commit
ea6f6079ca
@ -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)?;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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(())
|
||||
|
@ -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)?,
|
||||
}
|
||||
|
58
tests/run-pass/slice-of-zero-size-elements.rs
Normal file
58
tests/run-pass/slice-of-zero-size-elements.rs
Normal 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())
|
||||
}
|
28
tests/run-pass/zero-sized-binary-heap-push.rs
Normal file
28
tests/run-pass/zero-sized-binary-heap-push.rs
Normal 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();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user