More extensive slice and vec tests

Not all of them pass validation...
This commit is contained in:
Ralf Jung 2018-10-30 13:56:19 +01:00
parent 430e047a6f
commit 3302656247
3 changed files with 216 additions and 56 deletions

View file

@ -1,56 +0,0 @@
// 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.
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())
}

178
tests/run-pass/slices.rs Normal file
View file

@ -0,0 +1,178 @@
// FIXME: Still investigating whether there is UB here
// compile-flags: -Zmiri-disable-validation
use std::slice;
fn slice_of_zst() {
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())
}
// 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())
}
fn test_iter_ref_consistency() {
use std::fmt::Debug;
fn test<T : Copy + Debug + PartialEq>(x : T) {
let v : &[T] = &[x, x, x];
let v_ptrs : [*const T; 3] = match v {
[ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _],
_ => unreachable!()
};
let len = v.len();
// nth(i)
for i in 0..len {
assert_eq!(&v[i] as *const _, v_ptrs[i]); // check the v_ptrs array, just to be sure
let nth = v.iter().nth(i).unwrap();
assert_eq!(nth as *const _, v_ptrs[i]);
}
assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
// stepping through with nth(0)
{
let mut it = v.iter();
for i in 0..len {
let next = it.nth(0).unwrap();
assert_eq!(next as *const _, v_ptrs[i]);
}
assert_eq!(it.nth(0), None);
}
// next()
{
let mut it = v.iter();
for i in 0..len {
let remaining = len - i;
assert_eq!(it.size_hint(), (remaining, Some(remaining)));
let next = it.next().unwrap();
assert_eq!(next as *const _, v_ptrs[i]);
}
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next(), None, "The final call to next() should return None");
}
// next_back()
{
let mut it = v.iter();
for i in 0..len {
let remaining = len - i;
assert_eq!(it.size_hint(), (remaining, Some(remaining)));
let prev = it.next_back().unwrap();
assert_eq!(prev as *const _, v_ptrs[remaining-1]);
}
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
}
}
fn test_mut<T : Copy + Debug + PartialEq>(x : T) {
let v : &mut [T] = &mut [x, x, x];
let v_ptrs : [*mut T; 3] = match v {
[ref v1, ref v2, ref v3] =>
[v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _],
_ => unreachable!()
};
let len = v.len();
// nth(i)
for i in 0..len {
assert_eq!(&mut v[i] as *mut _, v_ptrs[i]); // check the v_ptrs array, just to be sure
let nth = v.iter_mut().nth(i).unwrap();
assert_eq!(nth as *mut _, v_ptrs[i]);
}
assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
// stepping through with nth(0)
{
let mut it = v.iter();
for i in 0..len {
let next = it.nth(0).unwrap();
assert_eq!(next as *const _, v_ptrs[i]);
}
assert_eq!(it.nth(0), None);
}
// next()
{
let mut it = v.iter_mut();
for i in 0..len {
let remaining = len - i;
assert_eq!(it.size_hint(), (remaining, Some(remaining)));
let next = it.next().unwrap();
assert_eq!(next as *mut _, v_ptrs[i]);
}
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next(), None, "The final call to next() should return None");
}
// next_back()
{
let mut it = v.iter_mut();
for i in 0..len {
let remaining = len - i;
assert_eq!(it.size_hint(), (remaining, Some(remaining)));
let prev = it.next_back().unwrap();
assert_eq!(prev as *mut _, v_ptrs[remaining-1]);
}
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
}
}
// Make sure iterators and slice patterns yield consistent addresses for various types,
// including ZSTs.
test(0u32);
test(());
test([0u32; 0]); // ZST with alignment > 0
test_mut(0u32);
test_mut(());
test_mut([0u32; 0]); // ZST with alignment > 0
}
fn main() {
slice_of_zst();
test_iter_ref_consistency();
}

View file

@ -24,13 +24,45 @@ fn vec_into_iter() -> u8 {
.fold(0, |x, y| x + y)
}
fn vec_into_iter_rev() -> u8 {
vec![1, 2, 3, 4]
.into_iter()
.map(|x| x * x)
.fold(0, |x, y| x + y)
}
fn vec_into_iter_zst() -> usize {
vec![[0u64; 0], [0u64; 0]]
.into_iter()
.rev()
.map(|x| x.len())
.sum()
}
fn vec_into_iter_rev_zst() -> usize {
vec![[0u64; 0], [0u64; 0]]
.into_iter()
.rev()
.map(|x| x.len())
.sum()
}
fn vec_iter_and_mut() {
let mut v = vec![1,2,3,4];
for i in v.iter_mut() {
*i += 1;
}
assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}
fn vec_iter_and_mut_rev() {
let mut v = vec![1,2,3,4];
for i in v.iter_mut().rev() {
*i += 1;
}
assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}
fn vec_reallocate() -> Vec<u8> {
let mut v = vec![1, 2];
v.push(3);
@ -41,8 +73,14 @@ fn vec_reallocate() -> Vec<u8> {
fn main() {
assert_eq!(vec_reallocate().len(), 5);
assert_eq!(vec_into_iter(), 30);
assert_eq!(vec_into_iter_rev(), 30);
vec_iter_and_mut();
assert_eq!(vec_into_iter_zst(), 0);
assert_eq!(vec_into_iter_rev_zst(), 0);
vec_iter_and_mut_rev();
assert_eq!(make_vec().capacity(), 4);
assert_eq!(make_vec_macro(), [1, 2]);
assert_eq!(make_vec_macro_repeat(), [42; 5]);