diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 38e66c5a3d6a2..d99ea607e5db3 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -631,8 +631,14 @@ fn size_from_ptr(_: *const T) -> usize { } -// Use macro to be generic over const/mut -macro_rules! slice_offset { +// Use macros to be generic over const/mut +// +// They require non-negative `$by` because otherwise the expression +// `(ptr as usize + $by)` would interpret `-1` as `usize::MAX` (and +// thus trigger a panic when overflow checks are on). + +// Use this to do `$ptr + $by`, where `$by` is non-negative. +macro_rules! slice_add_offset { ($ptr:expr, $by:expr) => {{ let ptr = $ptr; if size_from_ptr(ptr) == 0 { @@ -643,6 +649,18 @@ macro_rules! slice_offset { }}; } +// Use this to do `$ptr - $by`, where `$by` is non-negative. +macro_rules! slice_sub_offset { + ($ptr:expr, $by:expr) => {{ + let ptr = $ptr; + if size_from_ptr(ptr) == 0 { + transmute(ptr as usize - $by) + } else { + ptr.offset(-$by) + } + }}; +} + macro_rules! slice_ref { ($ptr:expr) => {{ let ptr = $ptr; @@ -672,7 +690,7 @@ macro_rules! iterator { None } else { let old = self.ptr; - self.ptr = slice_offset!(self.ptr, 1); + self.ptr = slice_add_offset!(self.ptr, 1); Some(slice_ref!(old)) } } @@ -714,7 +732,7 @@ macro_rules! iterator { if self.end == self.ptr { None } else { - self.end = slice_offset!(self.end, -1); + self.end = slice_sub_offset!(self.end, 1); Some(slice_ref!(self.end)) } } @@ -816,7 +834,7 @@ impl<'a, T> Iter<'a, T> { fn iter_nth(&mut self, n: usize) -> Option<&'a T> { match self.as_slice().get(n) { Some(elem_ref) => unsafe { - self.ptr = slice_offset!(elem_ref as *const _, 1); + self.ptr = slice_add_offset!(elem_ref as *const _, 1); Some(slice_ref!(elem_ref)) }, None => { @@ -959,7 +977,7 @@ impl<'a, T> IterMut<'a, T> { fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> { match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) { Some(elem_ref) => unsafe { - self.ptr = slice_offset!(elem_ref as *mut _, 1); + self.ptr = slice_add_offset!(elem_ref as *mut _, 1); Some(slice_ref!(elem_ref)) }, None => {