Skip to content

Commit 4242324

Browse files
committed
Auto merge of #110837 - scottmcm:offset-for-add, r=compiler-errors
Use MIR's `Offset` for pointer `add` too ~~Status: draft while waiting for #110822 to land, since this is built atop that.~~ ~~r? `@ghost~~` Canonical Rust code has mostly moved to `add`/`sub` on pointers, which take `usize`, instead of `offset` which takes `isize`. (And, relatedly, when `sub_ptr` was added it turned out it replaced every single in-tree use of `offset_from`, because `usize` is just so much more useful than `isize` in Rust.) Unfortunately, `intrinsics::offset` could only accept `*const` and `isize`, so there's a *huge* amount of type conversions back and forth being done. They're identity conversions in the backend, but still end up producing quite a lot of unhelpful MIR. This PR changes `intrinsics::offset` to accept `*const` *and* `*mut` along with `isize` *and* `usize`. Conveniently, the backends and CTFE already handle this, since MIR's `BinOp::Offset` [already supports all four combinations](https://github.com/rust-lang/rust/blob/adaac6b166df57ea5a20d56e4cce503b55aca927/compiler/rustc_const_eval/src/transform/validate.rs#L523-L528). To demonstrate the difference, I added some `mir-opt/pre-codegen/` tests around slice indexing. Here's the difference to `[T]::get_mut`, since it uses `<*mut _>::add` internally: ```diff `@@` -79,30 +70,21 `@@` fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { StorageLive(_12); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL _9 = _8 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageLive(_13); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - _13 = _2 as isize (IntToInt); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageLive(_14); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageLive(_15); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - _15 = _9 as *const u32 (Pointer(MutToConstPointer)); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - _14 = Offset(move _15, _13); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageDead(_15); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - _7 = move _14 as *mut u32 (PtrToPtr); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageDead(_14); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageDead(_13); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + _7 = Offset(_9, _2); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL StorageDead(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_12); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_11); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL ``` rust-lang/rust@1c1c8e4#diff-a841b6a4538657add3f39bc895744331453d0625e7aace128b1f604f0b63c8fdR80
2 parents dd6da6b + 89d0dc8 commit 4242324

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

core/src/intrinsics.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,6 +1413,10 @@ extern "rust-intrinsic" {
14131413
/// This is implemented as an intrinsic to avoid converting to and from an
14141414
/// integer, since the conversion would throw away aliasing information.
14151415
///
1416+
/// This can only be used with `Ptr` as a raw pointer type (`*mut` or `*const`)
1417+
/// to a `Sized` pointee and with `Delta` as `usize` or `isize`. Any other
1418+
/// instantiations may arbitrarily misbehave, and that's *not* a compiler bug.
1419+
///
14161420
/// # Safety
14171421
///
14181422
/// Both the starting and resulting pointer must be either in bounds or one
@@ -1421,6 +1425,14 @@ extern "rust-intrinsic" {
14211425
/// returned value will result in undefined behavior.
14221426
///
14231427
/// The stabilized version of this intrinsic is [`pointer::offset`].
1428+
#[cfg(not(bootstrap))]
1429+
#[must_use = "returns a new pointer rather than modifying its argument"]
1430+
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
1431+
#[rustc_nounwind]
1432+
pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
1433+
1434+
/// The bootstrap version of this is more restricted.
1435+
#[cfg(bootstrap)]
14241436
#[must_use = "returns a new pointer rather than modifying its argument"]
14251437
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
14261438
#[rustc_nounwind]

core/src/ptr/const_ptr.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,8 +916,16 @@ impl<T: ?Sized> *const T {
916916
where
917917
T: Sized,
918918
{
919+
#[cfg(bootstrap)]
919920
// SAFETY: the caller must uphold the safety contract for `offset`.
920-
unsafe { self.offset(count as isize) }
921+
unsafe {
922+
self.offset(count as isize)
923+
}
924+
#[cfg(not(bootstrap))]
925+
// SAFETY: the caller must uphold the safety contract for `offset`.
926+
unsafe {
927+
intrinsics::offset(self, count)
928+
}
921929
}
922930

923931
/// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).

core/src/ptr/mut_ptr.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,10 +473,20 @@ impl<T: ?Sized> *mut T {
473473
where
474474
T: Sized,
475475
{
476+
#[cfg(bootstrap)]
476477
// SAFETY: the caller must uphold the safety contract for `offset`.
477478
// The obtained pointer is valid for writes since the caller must
478479
// guarantee that it points to the same allocated object as `self`.
479-
unsafe { intrinsics::offset(self, count) as *mut T }
480+
unsafe {
481+
intrinsics::offset(self, count) as *mut T
482+
}
483+
#[cfg(not(bootstrap))]
484+
// SAFETY: the caller must uphold the safety contract for `offset`.
485+
// The obtained pointer is valid for writes since the caller must
486+
// guarantee that it points to the same allocated object as `self`.
487+
unsafe {
488+
intrinsics::offset(self, count)
489+
}
480490
}
481491

482492
/// Calculates the offset from a pointer in bytes.
@@ -1016,8 +1026,16 @@ impl<T: ?Sized> *mut T {
10161026
where
10171027
T: Sized,
10181028
{
1029+
#[cfg(bootstrap)]
1030+
// SAFETY: the caller must uphold the safety contract for `offset`.
1031+
unsafe {
1032+
self.offset(count as isize)
1033+
}
1034+
#[cfg(not(bootstrap))]
10191035
// SAFETY: the caller must uphold the safety contract for `offset`.
1020-
unsafe { self.offset(count as isize) }
1036+
unsafe {
1037+
intrinsics::offset(self, count)
1038+
}
10211039
}
10221040

10231041
/// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).

0 commit comments

Comments
 (0)