Skip to content

Commit 3533204

Browse files
committed
clarify wrapping ptr arithmetic docs
1 parent 1f5beec commit 3533204

File tree

2 files changed

+102
-72
lines changed

2 files changed

+102
-72
lines changed

library/core/src/ptr/const_ptr.rs

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -232,23 +232,26 @@ impl<T: ?Sized> *const T {
232232
///
233233
/// # Safety
234234
///
235-
/// The resulting pointer does not need to be in bounds, but it is
236-
/// potentially hazardous to dereference (which requires `unsafe`).
235+
/// This operation itself is always safe, but using the resulting pointer is not.
237236
///
238-
/// In particular, the resulting pointer remains attached to the same allocated
239-
/// object that `self` points to. It may *not* be used to access a
240-
/// different allocated object. Note that in Rust,
241-
/// every (stack-allocated) variable is considered a separate allocated object.
237+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
238+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
239+
/// (stack-allocated) variable is considered a separate allocated object.
242240
///
243-
/// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
244-
/// is *not* the same as `y`, and dereferencing it is undefined behavior
245-
/// unless `x` and `y` point into the same allocated object.
241+
/// In other words, `let z = x.wrapping_add((y as usize).wrapping_sub(x as usize) /
242+
/// size_of::<T>())` does *not* make `z` the same as `y`: `z` is still attached to the object `x` is
243+
/// attached to, and dereferencing it is Undefined Behavior unless `x` and `y` point into the
244+
/// same allocated object.
246245
///
247-
/// Compared to [`offset`], this method basically delays the requirement of staying
248-
/// within the same allocated object: [`offset`] is immediate Undefined Behavior when
249-
/// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
250-
/// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
251-
/// better and is thus preferable in performance-sensitive code.
246+
/// Compared to [`offset`], this method basically delays the requirement of staying within the
247+
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
248+
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
249+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
250+
/// can be optimized better and is thus preferable in performance-sensitive code.
251+
///
252+
/// `x.wrapping_offset(o).wrapping_offset(-o)` is always the same as `x` (if `-o` does not
253+
/// overflow). In other words, leaving the allocated object and then re-entering it later is
254+
/// permitted.
252255
///
253256
/// If you need to cross object boundaries, cast the pointer to an integer and
254257
/// do the arithmetic there.
@@ -571,19 +574,25 @@ impl<T: ?Sized> *const T {
571574
///
572575
/// # Safety
573576
///
574-
/// The resulting pointer does not need to be in bounds, but it is
575-
/// potentially hazardous to dereference (which requires `unsafe`).
577+
/// This operation itself is always safe, but using the resulting pointer is not.
578+
///
579+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
580+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
581+
/// (stack-allocated) variable is considered a separate allocated object.
582+
///
583+
/// In other words, `let z = x.wrapping_add((y as usize).wrapping_sub(x as usize) /
584+
/// size_of::<T>())` does *not* make `z` the same as `y`: `z` is still attached to the object `x` is
585+
/// attached to, and dereferencing it is Undefined Behavior unless `x` and `y` point into the
586+
/// same allocated object.
576587
///
577-
/// In particular, the resulting pointer remains attached to the same allocated
578-
/// object that `self` points to. It may *not* be used to access a
579-
/// different allocated object. Note that in Rust,
580-
/// every (stack-allocated) variable is considered a separate allocated object.
588+
/// Compared to [`add`], this method basically delays the requirement of staying within the
589+
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
590+
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
591+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
592+
/// can be optimized better and is thus preferable in performance-sensitive code.
581593
///
582-
/// Compared to [`add`], this method basically delays the requirement of staying
583-
/// within the same allocated object: [`add`] is immediate Undefined Behavior when
584-
/// crossing object boundaries; `wrapping_add` produces a pointer but still leads
585-
/// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
586-
/// better and is thus preferable in performance-sensitive code.
594+
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
595+
/// allocated object and then re-entering it later is permitted.
587596
///
588597
/// If you need to cross object boundaries, cast the pointer to an integer and
589598
/// do the arithmetic there.
@@ -628,19 +637,25 @@ impl<T: ?Sized> *const T {
628637
///
629638
/// # Safety
630639
///
631-
/// The resulting pointer does not need to be in bounds, but it is
632-
/// potentially hazardous to dereference (which requires `unsafe`).
640+
/// This operation itself is always safe, but using the resulting pointer is not.
641+
///
642+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
643+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
644+
/// (stack-allocated) variable is considered a separate allocated object.
645+
///
646+
/// In other words, `let z = x.wrapping_add((y as usize).wrapping_sub(x as usize) /
647+
/// size_of::<T>())` does *not* make `z` the same as `y`: `z` is still attached to the object `x` is
648+
/// attached to, and dereferencing it is Undefined Behavior unless `x` and `y` point into the
649+
/// same allocated object.
633650
///
634-
/// In particular, the resulting pointer remains attached to the same allocated
635-
/// object that `self` points to. It may *not* be used to access a
636-
/// different allocated object. Note that in Rust,
637-
/// every (stack-allocated) variable is considered a separate allocated object.
651+
/// Compared to [`sub`], this method basically delays the requirement of staying within the
652+
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
653+
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
654+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
655+
/// can be optimized better and is thus preferable in performance-sensitive code.
638656
///
639-
/// Compared to [`sub`], this method basically delays the requirement of staying
640-
/// within the same allocated object: [`sub`] is immediate Undefined Behavior when
641-
/// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
642-
/// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
643-
/// better and is thus preferable in performance-sensitive code.
657+
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
658+
/// allocated object and then re-entering it later is permitted.
644659
///
645660
/// If you need to cross object boundaries, cast the pointer to an integer and
646661
/// do the arithmetic there.

library/core/src/ptr/mut_ptr.rs

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -238,23 +238,26 @@ impl<T: ?Sized> *mut T {
238238
///
239239
/// # Safety
240240
///
241-
/// The resulting pointer does not need to be in bounds, but it is
242-
/// potentially hazardous to dereference (which requires `unsafe`).
241+
/// This operation itself is always safe, but using the resulting pointer is not.
243242
///
244-
/// In particular, the resulting pointer remains attached to the same allocated
245-
/// object that `self` points to. It may *not* be used to access a
246-
/// different allocated object. Note that in Rust,
247-
/// every (stack-allocated) variable is considered a separate allocated object.
243+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
244+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
245+
/// (stack-allocated) variable is considered a separate allocated object.
248246
///
249-
/// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
250-
/// is *not* the same as `y`, and dereferencing it is undefined behavior
251-
/// unless `x` and `y` point into the same allocated object.
247+
/// In other words, `let z = x.wrapping_add((y as usize).wrapping_sub(x as usize) /
248+
/// size_of::<T>())` does *not* make `z` the same as `y`: `z` is still attached to the object `x` is
249+
/// attached to, and dereferencing it is Undefined Behavior unless `x` and `y` point into the
250+
/// same allocated object.
252251
///
253-
/// Compared to [`offset`], this method basically delays the requirement of staying
254-
/// within the same allocated object: [`offset`] is immediate Undefined Behavior when
255-
/// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
256-
/// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
257-
/// better and is thus preferable in performance-sensitive code.
252+
/// Compared to [`offset`], this method basically delays the requirement of staying within the
253+
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
254+
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
255+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
256+
/// can be optimized better and is thus preferable in performance-sensitive code.
257+
///
258+
/// `x.wrapping_offset(o).wrapping_offset(-o)` is always the same as `x` (if `-o` does not
259+
/// overflow). In other words, leaving the allocated object and then re-entering it later is
260+
/// permitted.
258261
///
259262
/// If you need to cross object boundaries, cast the pointer to an integer and
260263
/// do the arithmetic there.
@@ -678,19 +681,25 @@ impl<T: ?Sized> *mut T {
678681
///
679682
/// # Safety
680683
///
681-
/// The resulting pointer does not need to be in bounds, but it is
682-
/// potentially hazardous to dereference (which requires `unsafe`).
684+
/// This operation itself is always safe, but using the resulting pointer is not.
685+
///
686+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
687+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
688+
/// (stack-allocated) variable is considered a separate allocated object.
689+
///
690+
/// In other words, `let z = x.wrapping_add((y as usize).wrapping_sub(x as usize) /
691+
/// size_of::<T>())` does *not* make `z` the same as `y`: `z` is still attached to the object `x` is
692+
/// attached to, and dereferencing it is Undefined Behavior unless `x` and `y` point into the
693+
/// same allocated object.
683694
///
684-
/// In particular, the resulting pointer remains attached to the same allocated
685-
/// object that `self` points to. It may *not* be used to access a
686-
/// different allocated object. Note that in Rust,
687-
/// every (stack-allocated) variable is considered a separate allocated object.
695+
/// Compared to [`add`], this method basically delays the requirement of staying within the
696+
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
697+
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
698+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
699+
/// can be optimized better and is thus preferable in performance-sensitive code.
688700
///
689-
/// Compared to [`add`], this method basically delays the requirement of staying
690-
/// within the same allocated object: [`add`] is immediate Undefined Behavior when
691-
/// crossing object boundaries; `wrapping_add` produces a pointer but still leads
692-
/// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
693-
/// better and is thus preferable in performance-sensitive code.
701+
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
702+
/// allocated object and then re-entering it later is permitted.
694703
///
695704
/// If you need to cross object boundaries, cast the pointer to an integer and
696705
/// do the arithmetic there.
@@ -735,19 +744,25 @@ impl<T: ?Sized> *mut T {
735744
///
736745
/// # Safety
737746
///
738-
/// The resulting pointer does not need to be in bounds, but it is
739-
/// potentially hazardous to dereference (which requires `unsafe`).
747+
/// This operation itself is always safe, but using the resulting pointer is not.
748+
///
749+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
750+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
751+
/// (stack-allocated) variable is considered a separate allocated object.
752+
///
753+
/// In other words, `let z = x.wrapping_add((y as usize).wrapping_sub(x as usize) /
754+
/// size_of::<T>())` does *not* make `z` the same as `y`: `z` is still attached to the object `x` is
755+
/// attached to, and dereferencing it is Undefined Behavior unless `x` and `y` point into the
756+
/// same allocated object.
740757
///
741-
/// In particular, the resulting pointer remains attached to the same allocated
742-
/// object that `self` points to. It may *not* be used to access a
743-
/// different allocated object. Note that in Rust,
744-
/// every (stack-allocated) variable is considered a separate allocated object.
758+
/// Compared to [`sub`], this method basically delays the requirement of staying within the
759+
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
760+
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
761+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
762+
/// can be optimized better and is thus preferable in performance-sensitive code.
745763
///
746-
/// Compared to [`sub`], this method basically delays the requirement of staying
747-
/// within the same allocated object: [`sub`] is immediate Undefined Behavior when
748-
/// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
749-
/// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
750-
/// better and is thus preferable in performance-sensitive code.
764+
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
765+
/// allocated object and then re-entering it later is permitted.
751766
///
752767
/// If you need to cross object boundaries, cast the pointer to an integer and
753768
/// do the arithmetic there.

0 commit comments

Comments
 (0)