Skip to content

Commit 8f0a824

Browse files
committed
Make EncodeUtf8::as_slice panic-less
We know for sure this method cannot slice out-of-bounds because: * 0 ≤ self.pos ≤ 3 * self.buf.len() = 4 This way the slicing will always succeed, but LLVM is incapable of figuring out both these conditions hold, resulting in suboptimal code, especially after inlining.
1 parent 34d14e7 commit 8f0a824

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

src/libcore/char.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const TAG_FOUR_B: u8 = 0b1111_0000;
2828
const MAX_ONE_B: u32 = 0x80;
2929
const MAX_TWO_B: u32 = 0x800;
3030
const MAX_THREE_B: u32 = 0x10000;
31+
const UTF8_BUF_SIZE: usize = 4;
3132

3233
/*
3334
Lu Uppercase_Letter an uppercase letter
@@ -644,15 +645,27 @@ impl ExactSizeIterator for EscapeDebug { }
644645
#[unstable(feature = "unicode", issue = "27784")]
645646
#[derive(Debug)]
646647
pub struct EncodeUtf8 {
647-
buf: [u8; 4],
648+
buf: [u8; UTF8_BUF_SIZE],
648649
pos: usize,
649650
}
650651

651652
impl EncodeUtf8 {
652653
/// Returns the remaining bytes of this iterator as a slice.
653654
#[unstable(feature = "unicode", issue = "27784")]
655+
#[inline(always)]
654656
pub fn as_slice(&self) -> &[u8] {
655-
&self.buf[self.pos..]
657+
// We know for sure this method cannot slice out-of-bounds because:
658+
// * 0 ≤ self.pos ≤ 3
659+
// * self.buf.len() = 4
660+
//
661+
// This way the slicing will always succeed, but LLVM is incapable of figuring out both
662+
// these conditions hold, resulting in suboptimal code, especially after inlining.
663+
// Ideally there would be a `slice_unchecked` method for slices, but there isn’t any,
664+
// therefore we construct the slice manually.
665+
unsafe {
666+
::slice::from_raw_parts(self.buf.as_ptr().offset(self.pos as isize),
667+
UTF8_BUF_SIZE.wrapping_sub(self.pos))
668+
}
656669
}
657670
}
658671

0 commit comments

Comments
 (0)