Skip to content

Commit e9e5ea2

Browse files
committed
libcore: Fix Items iterator for zero sized types.
1 parent f48cc74 commit e9e5ea2

File tree

2 files changed

+28
-18
lines changed

2 files changed

+28
-18
lines changed

src/libcollections/vec.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,10 @@ impl<T> Vec<T> {
7575
/// ```
7676
#[inline]
7777
pub fn new() -> Vec<T> {
78-
// If we have a 0-sized vector, then the base pointer should not be NULL
79-
// because an iterator over the slice will attempt to yield the base
80-
// pointer as the first element in the vector, but this will end up
81-
// being Some(NULL) which is optimized to None. So instead we set ptr
82-
// to some arbitrary non-null value which is fine since we never call
83-
// deallocate on the ptr if cap is 0.
78+
// We want ptr to never be NULL so instead we set it to some arbitrary
79+
// non-null value which is fine since we never call deallocate on the ptr
80+
// if cap is 0. The reason for this is because the pointer of a slice
81+
// being NULL would break the null pointer optimization for enums.
8482
Vec { len: 0, cap: 0, ptr: &PTR_MARKER as *const _ as *mut T }
8583
}
8684

src/libcore/slice.rs

+24-12
Original file line numberDiff line numberDiff line change
@@ -884,17 +884,20 @@ macro_rules! iterator {
884884
if self.ptr == self.end {
885885
None
886886
} else {
887-
let old = self.ptr;
888-
self.ptr = if mem::size_of::<T>() == 0 {
887+
if mem::size_of::<T>() == 0 {
889888
// purposefully don't use 'ptr.offset' because for
890889
// vectors with 0-size elements this would return the
891890
// same pointer.
892-
transmute(self.ptr as uint + 1)
891+
self.ptr = transmute(self.ptr as uint + 1);
892+
893+
// Use a non-null pointer value
894+
Some(transmute(1u))
893895
} else {
894-
self.ptr.offset(1)
895-
};
896+
let old = self.ptr;
897+
self.ptr = self.ptr.offset(1);
896898

897-
Some(transmute(old))
899+
Some(transmute(old))
900+
}
898901
}
899902
}
900903
}
@@ -916,13 +919,17 @@ macro_rules! iterator {
916919
if self.end == self.ptr {
917920
None
918921
} else {
919-
self.end = if mem::size_of::<T>() == 0 {
922+
if mem::size_of::<T>() == 0 {
920923
// See above for why 'ptr.offset' isn't used
921-
transmute(self.end as uint - 1)
924+
self.end = transmute(self.end as uint - 1);
925+
926+
// Use a non-null pointer value
927+
Some(transmute(1u))
922928
} else {
923-
self.end.offset(-1)
924-
};
925-
Some(transmute(self.end))
929+
self.end = self.end.offset(-1);
930+
931+
Some(transmute(self.end))
932+
}
926933
}
927934
}
928935
}
@@ -956,7 +963,12 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
956963
fn idx(&mut self, index: uint) -> Option<&'a T> {
957964
unsafe {
958965
if index < self.indexable() {
959-
transmute(self.ptr.offset(index as int))
966+
if mem::size_of::<T>() == 0 {
967+
// Use a non-null pointer value
968+
Some(transmute(1u))
969+
} else {
970+
Some(transmute(self.ptr.offset(index as int)))
971+
}
960972
} else {
961973
None
962974
}

0 commit comments

Comments
 (0)