From 3f8352ee0dad0b056f766975696b0dbd59243aab Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Fri, 15 Feb 2019 15:24:06 -0500 Subject: [PATCH] avoid overflow case help eliminate bounds checks Currently `array_ref!` takes a slice this way: let slice = & $arr[offset..offset + $len]; If the length of `slice` is already known, the compiler should be able to skip bounds checks there. However, because of the possibility that `offset + $len` might overflow, the compiler sometimes has to be conservative. Switching to slightly different slicing arithmetic avoids this problem: let slice = & $arr[offset..][..$len]; Here's an example of the second version successfully eliding bounds checks, where the first version does not (https://godbolt.org/z/Je4lRl): fn get_array(input: &[u8], offset: usize) -> Option<&[u8; SIZE]> { if input.len() >= offset && input.len() - offset >= SIZE { Some(array_ref!(input, offset, SIZE)) } else { None } } --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b59b2fc..60abd40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ macro_rules! array_ref { &*(slice.as_ptr() as *const [_; $len]) } let offset = $offset; - let slice = & $arr[offset..offset + $len]; + let slice = & $arr[offset..][..$len]; #[allow(unused_unsafe)] unsafe { as_array(slice) @@ -287,7 +287,7 @@ macro_rules! array_mut_ref { &mut *(slice.as_mut_ptr() as *mut [_; $len]) } let offset = $offset; - let slice = &mut $arr[offset..offset + $len]; + let slice = &mut $arr[offset..][..$len]; #[allow(unused_unsafe)] unsafe { as_array(slice)