From 2cf09e17abfd46dfaa2c1768efd1ffaba642f62f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 May 2026 14:29:58 +0200 Subject: [PATCH 1/3] move ptr::sub docs into its own file (matching add, offset) --- library/core/src/ptr/const_ptr.rs | 33 +------------------------------ library/core/src/ptr/docs/sub.md | 32 ++++++++++++++++++++++++++++++ library/core/src/ptr/mut_ptr.rs | 33 +------------------------------ 3 files changed, 34 insertions(+), 64 deletions(-) create mode 100644 library/core/src/ptr/docs/sub.md diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 8b7b08bf82317..343b99cd4caff 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -883,38 +883,7 @@ impl *const T { unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Subtracts an unsigned offset from a pointer. - /// - /// This can only move the pointer backward (or not move it). If you need to move forward or - /// backward depending on the value, then you might want [`offset`](#method.offset) instead - /// which takes a signed offset. - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined Behavior: - /// - /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without - /// "wrapping around"), must fit in an `isize`. - /// - /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some - /// [allocation], and the entire memory range between `self` and the result must be in - /// bounds of that allocation. In particular, this range must not "wrap around" the edge - /// of the address space. - /// - /// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset - /// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. - /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always - /// safe. - /// - /// Consider using [`wrapping_sub`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// [`wrapping_sub`]: #method.wrapping_sub - /// [allocation]: crate::ptr#allocation + #[doc = include_str!("./docs/sub.md")] /// /// # Examples /// diff --git a/library/core/src/ptr/docs/sub.md b/library/core/src/ptr/docs/sub.md new file mode 100644 index 0000000000000..2a477c5665e9e --- /dev/null +++ b/library/core/src/ptr/docs/sub.md @@ -0,0 +1,32 @@ +Subtracts an unsigned offset from a pointer. + +This can only move the pointer backward (or not move it). If you need to move forward or +backward depending on the value, then you might want [`offset`](#method.offset) instead +which takes a signed offset. + +`count` is in units of T; e.g., a `count` of 3 represents a pointer +offset of `3 * size_of::()` bytes. + +# Safety + +If any of the following conditions are violated, the result is Undefined Behavior: + +* The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + "wrapping around"), must fit in an `isize`. + +* If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some + [allocation], and the entire memory range between `self` and the result must be in + bounds of that allocation. In particular, this range must not "wrap around" the edge + of the address space. + +Allocations can never be larger than `isize::MAX` bytes, so if the computed offset +stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. +This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always +safe. + +Consider using [`wrapping_sub`] instead if these constraints are +difficult to satisfy. The only advantage of this method is that it +enables more aggressive compiler optimizations. + +[`wrapping_sub`]: #method.wrapping_sub +[allocation]: crate::ptr#allocation diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 98b70a77fad7b..30b74b50664fd 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -981,38 +981,7 @@ impl *mut T { unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Subtracts an unsigned offset from a pointer. - /// - /// This can only move the pointer backward (or not move it). If you need to move forward or - /// backward depending on the value, then you might want [`offset`](#method.offset) instead - /// which takes a signed offset. - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined Behavior: - /// - /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without - /// "wrapping around"), must fit in an `isize`. - /// - /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some - /// [allocation], and the entire memory range between `self` and the result must be in - /// bounds of that allocation. In particular, this range must not "wrap around" the edge - /// of the address space. - /// - /// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset - /// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. - /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always - /// safe. - /// - /// Consider using [`wrapping_sub`] instead if these constraints are - /// difficult to satisfy. The only advantage of this method is that it - /// enables more aggressive compiler optimizations. - /// - /// [`wrapping_sub`]: #method.wrapping_sub - /// [allocation]: crate::ptr#allocation + #[doc = include_str!("./docs/sub.md")] /// /// # Examples /// From 9dc2496c1d2a797ad85a6077807bb070f3303d06 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 May 2026 14:35:54 +0200 Subject: [PATCH 2/3] offset, add, sub: make the range we are talking about more explicit --- library/core/src/ptr/docs/add.md | 17 +++++++++-------- library/core/src/ptr/docs/offset.md | 19 ++++++++++--------- library/core/src/ptr/docs/sub.md | 16 ++++++++-------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/library/core/src/ptr/docs/add.md b/library/core/src/ptr/docs/add.md index 6e2e87f5f811b..0cea5aca6f436 100644 --- a/library/core/src/ptr/docs/add.md +++ b/library/core/src/ptr/docs/add.md @@ -14,15 +14,16 @@ If any of the following conditions are violated, the result is Undefined Behavio * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without "wrapping around"), must fit in an `isize`. +* Let `result` be `self.addr() + count * size_of::()`, computed on mathematical integers. +This must fit in a `usize`. + * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some -[allocation], and the entire memory range between `self` and the result must be in -bounds of that allocation. In particular, this range must not "wrap around" the edge -of the address space. - -Allocations can never be larger than `isize::MAX` bytes, so if the computed offset -stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. -This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always -safe. +[allocation], and the entire memory range between `self` and `result` +(i.e., `self.addr()..result`) must be in bounds of that allocation. + +Allocations can never be larger than `isize::MAX` bytes and they can only contain addresses +representable by `usize`, so technically the last condition implies the first two. This implies, for +instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always safe. Consider using [`wrapping_add`] instead if these constraints are difficult to satisfy. The only advantage of this method is that it diff --git a/library/core/src/ptr/docs/offset.md b/library/core/src/ptr/docs/offset.md index f04f5606ab297..c7b66c0625e1b 100644 --- a/library/core/src/ptr/docs/offset.md +++ b/library/core/src/ptr/docs/offset.md @@ -10,16 +10,17 @@ If any of the following conditions are violated, the result is Undefined Behavio * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without "wrapping around"), must fit in an `isize`. +* Let `result` be `self.addr() + count * size_of::()`, computed on mathematical integers. +This must fit in a `usize`. + * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some -[allocation], and the entire memory range between `self` and the result must be in -bounds of that allocation. In particular, this range must not "wrap around" the edge -of the address space. Note that "range" here refers to a half-open range as usual in Rust, -i.e., `self..result` for non-negative offsets and `result..self` for negative offsets. - -Allocations can never be larger than `isize::MAX` bytes, so if the computed offset -stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. -This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always -safe. +[allocation], and the entire memory range between `self` and `result` +(i.e., `min(self.addr(), result)..max(self.addr(), result)`) +must be in bounds of that allocation. + +Allocations can never be larger than `isize::MAX` bytes and they can only contain addresses +representable by `usize`, so technically the last condition implies the first two. This implies, for +instance, that `vec.as_ptr().offset(vec.len() as isize)` (for `vec: Vec`) is always safe. Consider using [`wrapping_offset`] instead if these constraints are difficult to satisfy. The only advantage of this method is that it diff --git a/library/core/src/ptr/docs/sub.md b/library/core/src/ptr/docs/sub.md index 2a477c5665e9e..89733d71c4ad7 100644 --- a/library/core/src/ptr/docs/sub.md +++ b/library/core/src/ptr/docs/sub.md @@ -14,15 +14,15 @@ If any of the following conditions are violated, the result is Undefined Behavio * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without "wrapping around"), must fit in an `isize`. +* Let `result` be `self.addr() - count * size_of::()`, computed on mathematical integers. +This must fit in a `usize`. + * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some - [allocation], and the entire memory range between `self` and the result must be in - bounds of that allocation. In particular, this range must not "wrap around" the edge - of the address space. - -Allocations can never be larger than `isize::MAX` bytes, so if the computed offset -stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. -This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always -safe. +[allocation], and the entire memory range between `self` and `result` +(i.e., `result..self.addr()`) must be in bounds of that allocation. + +Allocations can never be larger than `isize::MAX` bytes and they can only contain addresses +representable by `usize`, so technically the last condition implies the first two. Consider using [`wrapping_sub`] instead if these constraints are difficult to satisfy. The only advantage of this method is that it From f0ef8a94b0855be0f85d6778b64df6b5ed6ea2fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 May 2026 14:54:22 +0200 Subject: [PATCH 3/3] also use shared pointer offset/add/sub docs for NonNull --- library/core/src/ptr/const_ptr.rs | 12 +++++ library/core/src/ptr/docs/add.md | 5 --- library/core/src/ptr/docs/offset.md | 5 --- library/core/src/ptr/docs/sub.md | 5 --- library/core/src/ptr/mut_ptr.rs | 12 +++++ library/core/src/ptr/non_null.rs | 70 ++--------------------------- 6 files changed, 27 insertions(+), 82 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 343b99cd4caff..6b8be00df6b3c 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -330,6 +330,10 @@ impl *const T { #[doc = include_str!("./docs/offset.md")] /// + /// Consider using [`wrapping_offset`](#method.wrapping_offset) instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// /// # Examples /// /// ``` @@ -810,6 +814,10 @@ impl *const T { #[doc = include_str!("./docs/add.md")] /// + /// Consider using [`wrapping_add`](#method.wrapping_add) instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// /// # Examples /// /// ``` @@ -885,6 +893,10 @@ impl *const T { #[doc = include_str!("./docs/sub.md")] /// + /// Consider using [`wrapping_sub`](#method.wrapping_sub) instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// /// # Examples /// /// ``` diff --git a/library/core/src/ptr/docs/add.md b/library/core/src/ptr/docs/add.md index 0cea5aca6f436..807ebee6db1c8 100644 --- a/library/core/src/ptr/docs/add.md +++ b/library/core/src/ptr/docs/add.md @@ -25,9 +25,4 @@ Allocations can never be larger than `isize::MAX` bytes and they can only contai representable by `usize`, so technically the last condition implies the first two. This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always safe. -Consider using [`wrapping_add`] instead if these constraints are -difficult to satisfy. The only advantage of this method is that it -enables more aggressive compiler optimizations. - -[`wrapping_add`]: #method.wrapping_add [allocation]: crate::ptr#allocation diff --git a/library/core/src/ptr/docs/offset.md b/library/core/src/ptr/docs/offset.md index c7b66c0625e1b..b1add36d37735 100644 --- a/library/core/src/ptr/docs/offset.md +++ b/library/core/src/ptr/docs/offset.md @@ -22,9 +22,4 @@ Allocations can never be larger than `isize::MAX` bytes and they can only contai representable by `usize`, so technically the last condition implies the first two. This implies, for instance, that `vec.as_ptr().offset(vec.len() as isize)` (for `vec: Vec`) is always safe. -Consider using [`wrapping_offset`] instead if these constraints are -difficult to satisfy. The only advantage of this method is that it -enables more aggressive compiler optimizations. - -[`wrapping_offset`]: #method.wrapping_offset [allocation]: crate::ptr#allocation diff --git a/library/core/src/ptr/docs/sub.md b/library/core/src/ptr/docs/sub.md index 89733d71c4ad7..b8873b0cf3631 100644 --- a/library/core/src/ptr/docs/sub.md +++ b/library/core/src/ptr/docs/sub.md @@ -24,9 +24,4 @@ This must fit in a `usize`. Allocations can never be larger than `isize::MAX` bytes and they can only contain addresses representable by `usize`, so technically the last condition implies the first two. -Consider using [`wrapping_sub`] instead if these constraints are -difficult to satisfy. The only advantage of this method is that it -enables more aggressive compiler optimizations. - -[`wrapping_sub`]: #method.wrapping_sub [allocation]: crate::ptr#allocation diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 30b74b50664fd..8d2e9746124b3 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -333,6 +333,10 @@ impl *mut T { #[doc = include_str!("./docs/offset.md")] /// + /// Consider using [`wrapping_offset`](#method.wrapping_offset) instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// /// # Examples /// /// ``` @@ -908,6 +912,10 @@ impl *mut T { #[doc = include_str!("./docs/add.md")] /// + /// Consider using [`wrapping_add`](#method.wrapping_add) instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// /// # Examples /// /// ``` @@ -983,6 +991,10 @@ impl *mut T { #[doc = include_str!("./docs/sub.md")] /// + /// Consider using [`wrapping_sub`](#method.wrapping_sub) instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// /// # Examples /// /// ``` diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index b9b42c1efe05a..66503d881bc40 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -528,28 +528,7 @@ impl NonNull { if self.is_aligned_to(align_of::()) { Some(self.cast()) } else { None } } - /// Adds an offset to a pointer. - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined Behavior: - /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. - /// - /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some - /// [allocation], and the entire memory range between `self` and the result must be in - /// bounds of that allocation. In particular, this range must not "wrap around" the edge - /// of the address space. - /// - /// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset - /// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. - /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always - /// safe. - /// - /// [allocation]: crate::ptr#allocation + #[doc = include_str!("./docs/offset.md")] /// /// # Examples /// @@ -604,28 +583,7 @@ impl NonNull { unsafe { transmute(self.as_ptr().byte_offset(count)) } } - /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined Behavior: - /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. - /// - /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some - /// [allocation], and the entire memory range between `self` and the result must be in - /// bounds of that allocation. In particular, this range must not "wrap around" the edge - /// of the address space. - /// - /// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset - /// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. - /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always - /// safe. - /// - /// [allocation]: crate::ptr#allocation + #[doc = include_str!("./docs/add.md")] /// /// # Examples /// @@ -680,29 +638,7 @@ impl NonNull { unsafe { transmute(self.as_ptr().byte_add(count)) } } - /// Subtracts an offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). - /// - /// `count` is in units of T; e.g., a `count` of 3 represents a pointer - /// offset of `3 * size_of::()` bytes. - /// - /// # Safety - /// - /// If any of the following conditions are violated, the result is Undefined Behavior: - /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. - /// - /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some - /// [allocation], and the entire memory range between `self` and the result must be in - /// bounds of that allocation. In particular, this range must not "wrap around" the edge - /// of the address space. - /// - /// Allocations can never be larger than `isize::MAX` bytes, so if the computed offset - /// stays in bounds of the allocation, it is guaranteed to satisfy the first requirement. - /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec`) is always - /// safe. - /// - /// [allocation]: crate::ptr#allocation + #[doc = include_str!("./docs/sub.md")] /// /// # Examples ///