Rollup merge of #80383 - RalfJung:wrapping-ptr-arithmetic, r=dtolnay

clarify wrapping ptr arithmetic docs

Fixes https://github.com/rust-lang/rust/issues/80306

`@steffahn` please let me know if this helps avoid the misunderstanding. :)
This commit is contained in:
Mara Bos 2020-12-28 19:09:18 +00:00 committed by GitHub
commit 9fdd95ff7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 112 additions and 72 deletions

View File

@ -232,23 +232,27 @@ pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
/// is *not* the same as `y`, and dereferencing it is undefined behavior
/// unless `x` and `y` point into the same allocated object.
/// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// Compared to [`offset`], this method basically delays the requirement of staying
/// within the same allocated object: [`offset`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// Compared to [`offset`], this method basically delays the requirement of staying within the
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
/// words, leaving the allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
@ -571,19 +575,27 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// Compared to [`add`], this method basically delays the requirement of staying
/// within the same allocated object: [`add`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_add` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// Compared to [`add`], this method basically delays the requirement of staying within the
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
@ -628,19 +640,27 @@ pub const fn wrapping_add(self, count: usize) -> Self
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// Compared to [`sub`], this method basically delays the requirement of staying
/// within the same allocated object: [`sub`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// Compared to [`sub`], this method basically delays the requirement of staying within the
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.

View File

@ -238,23 +238,27 @@ pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
/// is *not* the same as `y`, and dereferencing it is undefined behavior
/// unless `x` and `y` point into the same allocated object.
/// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// Compared to [`offset`], this method basically delays the requirement of staying
/// within the same allocated object: [`offset`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// Compared to [`offset`], this method basically delays the requirement of staying within the
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
/// words, leaving the allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
@ -678,19 +682,27 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// Compared to [`add`], this method basically delays the requirement of staying
/// within the same allocated object: [`add`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_add` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// Compared to [`add`], this method basically delays the requirement of staying within the
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
@ -735,19 +747,27 @@ pub const fn wrapping_add(self, count: usize) -> Self
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// Compared to [`sub`], this method basically delays the requirement of staying
/// within the same allocated object: [`sub`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// Compared to [`sub`], this method basically delays the requirement of staying within the
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.