Skip to content

Commit 770b2fe

Browse files
committed
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
2 parents 2f79054 + 7a82d47 commit 770b2fe

File tree

1 file changed

+46
-2
lines changed

1 file changed

+46
-2
lines changed

src/libstd/vec.rs

+46-2
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,12 @@ impl<T> Vec<T> {
598598
/// ```
599599
#[inline]
600600
pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
601-
let slice = Slice { data: self.ptr as *T, len: self.len };
601+
// See the comment in as_slice() for what's going on here.
602+
let slice = if mem::size_of::<T>() == 0 {
603+
Slice { data: 1 as *T, len: self.len }
604+
} else {
605+
Slice { data: self.ptr as *T, len: self.len }
606+
};
602607
unsafe { transmute(slice) }
603608
}
604609

@@ -1335,7 +1340,15 @@ impl<T> Vector<T> for Vec<T> {
13351340
/// ```
13361341
#[inline]
13371342
fn as_slice<'a>(&'a self) -> &'a [T] {
1338-
let slice = Slice { data: self.ptr as *T, len: self.len };
1343+
// If we have a 0-sized vector, then the base pointer should not be NULL
1344+
// because an iterator over the slice will attempt to yield the base
1345+
// pointer as the first element in the vector, but this will end up
1346+
// being Some(NULL) which is optimized to None.
1347+
let slice = if mem::size_of::<T>() == 0 {
1348+
Slice { data: 1 as *T, len: self.len }
1349+
} else {
1350+
Slice { data: self.ptr as *T, len: self.len }
1351+
};
13391352
unsafe { transmute(slice) }
13401353
}
13411354
}
@@ -1588,4 +1601,35 @@ mod tests {
15881601
vec.retain(|x| x%2 == 0);
15891602
assert!(vec == Vec::from_slice([2u, 4]));
15901603
}
1604+
1605+
#[test]
1606+
fn zero_sized_values() {
1607+
let mut v = Vec::new();
1608+
assert_eq!(v.len(), 0);
1609+
v.push(());
1610+
assert_eq!(v.len(), 1);
1611+
v.push(());
1612+
assert_eq!(v.len(), 2);
1613+
assert_eq!(v.pop(), Some(()));
1614+
assert_eq!(v.pop(), Some(()));
1615+
assert_eq!(v.pop(), None);
1616+
1617+
assert_eq!(v.iter().len(), 0);
1618+
v.push(());
1619+
assert_eq!(v.iter().len(), 1);
1620+
v.push(());
1621+
assert_eq!(v.iter().len(), 2);
1622+
1623+
for &() in v.iter() {}
1624+
1625+
assert_eq!(v.mut_iter().len(), 2);
1626+
v.push(());
1627+
assert_eq!(v.mut_iter().len(), 3);
1628+
v.push(());
1629+
assert_eq!(v.mut_iter().len(), 4);
1630+
1631+
for &() in v.mut_iter() {}
1632+
unsafe { v.set_len(0); }
1633+
assert_eq!(v.mut_iter().len(), 0);
1634+
}
15911635
}

0 commit comments

Comments
 (0)