auto merge of #13468 : alexcrichton/rust/issue-13467, r=thestinger
Previously, all slices derived from a vector whose values were of size 0 had a null pointer as the 'data' pointer on the slice. This caused first pointer to be yielded during iteration to always be the null pointer. Due to the null pointer optimization, this meant that the first return value was None, instead of Some(&T). This commit changes slice construction from a Vec instance to use a base pointer of 1 if the values have zero size. This means that the iterator will never return null, and the iteration will proceed appropriately. Closes #13467
This commit is contained in:
commit
770b2fea06
@ -598,7 +598,12 @@ impl<T> Vec<T> {
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
|
||||
let slice = Slice { data: self.ptr as *T, len: self.len };
|
||||
// See the comment in as_slice() for what's going on here.
|
||||
let slice = if mem::size_of::<T>() == 0 {
|
||||
Slice { data: 1 as *T, len: self.len }
|
||||
} else {
|
||||
Slice { data: self.ptr as *T, len: self.len }
|
||||
};
|
||||
unsafe { transmute(slice) }
|
||||
}
|
||||
|
||||
@ -1335,7 +1340,15 @@ impl<T> Vector<T> for Vec<T> {
|
||||
/// ```
|
||||
#[inline]
|
||||
fn as_slice<'a>(&'a self) -> &'a [T] {
|
||||
let slice = Slice { data: self.ptr as *T, len: self.len };
|
||||
// If we have a 0-sized vector, then the base pointer should not be NULL
|
||||
// because an iterator over the slice will attempt to yield the base
|
||||
// pointer as the first element in the vector, but this will end up
|
||||
// being Some(NULL) which is optimized to None.
|
||||
let slice = if mem::size_of::<T>() == 0 {
|
||||
Slice { data: 1 as *T, len: self.len }
|
||||
} else {
|
||||
Slice { data: self.ptr as *T, len: self.len }
|
||||
};
|
||||
unsafe { transmute(slice) }
|
||||
}
|
||||
}
|
||||
@ -1588,4 +1601,35 @@ mod tests {
|
||||
vec.retain(|x| x%2 == 0);
|
||||
assert!(vec == Vec::from_slice([2u, 4]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_sized_values() {
|
||||
let mut v = Vec::new();
|
||||
assert_eq!(v.len(), 0);
|
||||
v.push(());
|
||||
assert_eq!(v.len(), 1);
|
||||
v.push(());
|
||||
assert_eq!(v.len(), 2);
|
||||
assert_eq!(v.pop(), Some(()));
|
||||
assert_eq!(v.pop(), Some(()));
|
||||
assert_eq!(v.pop(), None);
|
||||
|
||||
assert_eq!(v.iter().len(), 0);
|
||||
v.push(());
|
||||
assert_eq!(v.iter().len(), 1);
|
||||
v.push(());
|
||||
assert_eq!(v.iter().len(), 2);
|
||||
|
||||
for &() in v.iter() {}
|
||||
|
||||
assert_eq!(v.mut_iter().len(), 2);
|
||||
v.push(());
|
||||
assert_eq!(v.mut_iter().len(), 3);
|
||||
v.push(());
|
||||
assert_eq!(v.mut_iter().len(), 4);
|
||||
|
||||
for &() in v.mut_iter() {}
|
||||
unsafe { v.set_len(0); }
|
||||
assert_eq!(v.mut_iter().len(), 0);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user