about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-07 12:49:15 +0000
committerbors <bors@rust-lang.org>2024-04-07 12:49:15 +0000
commit4e431fad67b46c480f1833119cd368fa33df95f7 (patch)
tree9d793a570f5ce2b0c6aedd34c2d5aeaac4df2a16
parentfc1a4c5cc9308c4b5980c64a73fd344a59c10601 (diff)
parent712aab72df2a9c511e49a51974294d3d2712056e (diff)
downloadrust-4e431fad67b46c480f1833119cd368fa33df95f7.tar.gz
rust-4e431fad67b46c480f1833119cd368fa33df95f7.zip
Auto merge of #123561 - saethlin:str-unchecked-sub-index, r=scottmcm
Use unchecked_sub in str indexing

https://github.com/rust-lang/rust/pull/108763 applied this logic to indexing for slices, but of course `str` has its own separate impl.

Found this by skimming over the codegen for https://github.com/oxidecomputer/hubris/; their dist builds enable overflow checks so the lack of `unchecked_sub` was producing an impossible-to-hit overflow check and also inhibiting some inlining.

r? scottmcm
-rw-r--r--library/core/src/str/traits.rs15
-rw-r--r--tests/codegen/slice-indexing.rs28
2 files changed, 37 insertions, 6 deletions
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 672af752149..ba2d6f64496 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -1,6 +1,7 @@
 //! Trait implementations for `str`.
 
 use crate::cmp::Ordering;
+use crate::intrinsics::unchecked_sub;
 use crate::ops;
 use crate::ptr;
 use crate::slice::SliceIndex;
@@ -210,9 +211,10 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
 
         // SAFETY: the caller guarantees that `self` is in bounds of `slice`
         // which satisfies all the conditions for `add`.
-        let ptr = unsafe { slice.as_ptr().add(self.start) };
-        let len = self.end - self.start;
-        ptr::slice_from_raw_parts(ptr, len) as *const str
+        unsafe {
+            let new_len = unchecked_sub(self.end, self.start);
+            ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) as *const str
+        }
     }
     #[inline]
     unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
@@ -229,9 +231,10 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
         );
 
         // SAFETY: see comments for `get_unchecked`.
-        let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
-        let len = self.end - self.start;
-        ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
+        unsafe {
+            let new_len = unchecked_sub(self.end, self.start);
+            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) as *mut str
+        }
     }
     #[inline]
     fn index(self, slice: &str) -> &Self::Output {
diff --git a/tests/codegen/slice-indexing.rs b/tests/codegen/slice-indexing.rs
index ecce9201071..3d284148db2 100644
--- a/tests/codegen/slice-indexing.rs
+++ b/tests/codegen/slice-indexing.rs
@@ -32,3 +32,31 @@ pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut
     // CHECK: sub nuw i64
     x.get_unchecked_mut(r)
 }
+
+// CHECK-LABEL: @str_index_by_range(
+#[no_mangle]
+pub fn str_index_by_range(x: &str, r: Range<usize>) -> &str {
+    // CHECK: sub nuw i64
+    &x[r]
+}
+
+// CHECK-LABEL: @str_get_unchecked_by_range(
+#[no_mangle]
+pub unsafe fn str_get_unchecked_by_range(x: &str, r: Range<usize>) -> &str {
+    // CHECK: sub nuw i64
+    x.get_unchecked(r)
+}
+
+// CHECK-LABEL: @str_index_mut_by_range(
+#[no_mangle]
+pub fn str_index_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str {
+    // CHECK: sub nuw i64
+    &mut x[r]
+}
+
+// CHECK-LABEL: @str_get_unchecked_mut_by_range(
+#[no_mangle]
+pub unsafe fn str_get_unchecked_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str {
+    // CHECK: sub nuw i64
+    x.get_unchecked_mut(r)
+}