Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve pointer offset method docs #63297

Merged
merged 2 commits into from
Aug 12, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 128 additions & 34 deletions src/libcore/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,8 @@ impl<T: ?Sized> *const T {
/// Behavior:
///
/// * Both the starting and resulting pointer must be either in bounds or one
/// byte past the end of the same allocated object.
/// byte past the end of the same allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
///
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
///
Expand All @@ -1140,10 +1141,12 @@ impl<T: ?Sized> *const T {
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
///
/// Consider using `wrapping_offset` instead if these constraints are
/// 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
///
/// # Examples
///
/// Basic usage:
Expand Down Expand Up @@ -1172,15 +1175,26 @@ impl<T: ?Sized> *const T {
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// In particular, the resulting pointer may *not* be used to access a
/// different allocated object than the one `self` points to. In other
/// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is
///
/// 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.
///
/// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is
/// *not* the same as `y`, and dereferencing it is undefined behavior
/// unless `x` and `y` point into the same allocated object.
///
/// Always use `.offset(count)` instead when possible, because `offset`
/// allows the compiler to optimize better. If you need to cross object
/// boundaries, cast the pointer to an integer and do the arithmetic there.
/// 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 preferrable in performance-sensitive code.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// [`offset`]: #method.offset
///
/// # Examples
///
Expand Down Expand Up @@ -1223,7 +1237,8 @@ impl<T: ?Sized> *const T {
/// Behavior:
///
/// * Both the starting and other pointer must be either in bounds or one
/// byte past the end of the same allocated object.
/// byte past the end of the same allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
///
/// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
///
Expand Down Expand Up @@ -1338,7 +1353,8 @@ impl<T: ?Sized> *const T {
/// Behavior:
///
/// * Both the starting and resulting pointer must be either in bounds or one
/// byte past the end of the same allocated object.
/// byte past the end of the same allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
///
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
///
Expand All @@ -1358,10 +1374,12 @@ impl<T: ?Sized> *const T {
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
///
/// Consider using `wrapping_offset` instead if these constraints are
/// 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
///
/// # Examples
///
/// Basic usage:
Expand Down Expand Up @@ -1395,7 +1413,8 @@ impl<T: ?Sized> *const T {
/// Behavior:
///
/// * Both the starting and resulting pointer must be either in bounds or one
/// byte past the end of the same allocated object.
/// byte past the end of the same allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
///
/// * The computed offset cannot exceed `isize::MAX` **bytes**.
///
Expand All @@ -1415,10 +1434,12 @@ impl<T: ?Sized> *const T {
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
///
/// Consider using `wrapping_offset` instead if these constraints are
/// 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
///
/// # Examples
///
/// Basic usage:
Expand Down Expand Up @@ -1451,8 +1472,21 @@ impl<T: ?Sized> *const T {
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
///
/// Always use `.add(count)` instead when possible, because `add`
/// allows the compiler to optimize better.
/// 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.
///
/// 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 preferrable in performance-sensitive code.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// [`add`]: #method.add
///
/// # Examples
///
Expand Down Expand Up @@ -1492,8 +1526,21 @@ impl<T: ?Sized> *const T {
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
///
/// Always use `.sub(count)` instead when possible, because `sub`
/// allows the compiler to optimize better.
/// 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.
///
/// 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 preferrable in performance-sensitive code.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// [`sub`]: #method.sub
///
/// # Examples
///
Expand Down Expand Up @@ -1755,7 +1802,8 @@ impl<T: ?Sized> *mut T {
/// Behavior:
///
/// * Both the starting and resulting pointer must be either in bounds or one
/// byte past the end of the same allocated object.
/// byte past the end of the same allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
///
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
///
Expand All @@ -1775,10 +1823,12 @@ impl<T: ?Sized> *mut T {
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
///
/// Consider using `wrapping_offset` instead if these constraints are
/// 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
///
/// # Examples
///
/// Basic usage:
Expand Down Expand Up @@ -1806,15 +1856,26 @@ impl<T: ?Sized> *mut T {
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// In particular, the resulting pointer may *not* be used to access a
/// different allocated object than the one `self` points to. In other
/// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is
///
/// 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.
///
/// In other words, `x.wrapping_offset(y.wrapping_offset_from(x))` is
/// *not* the same as `y`, and dereferencing it is undefined behavior
/// unless `x` and `y` point into the same allocated object.
///
/// Always use `.offset(count)` instead when possible, because `offset`
/// allows the compiler to optimize better. If you need to cross object
/// boundaries, cast the pointer to an integer and do the arithmetic there.
/// 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 preferrable in performance-sensitive code.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// [`offset`]: #method.offset
///
/// # Examples
///
Expand Down Expand Up @@ -1901,7 +1962,8 @@ impl<T: ?Sized> *mut T {
/// Behavior:
///
/// * Both the starting and other pointer must be either in bounds or one
/// byte past the end of the same allocated object.
/// byte past the end of the same allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
///
/// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
///
Expand Down Expand Up @@ -2005,7 +2067,8 @@ impl<T: ?Sized> *mut T {
/// Behavior:
///
/// * Both the starting and resulting pointer must be either in bounds or one
/// byte past the end of the same allocated object.
/// byte past the end of the same allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
///
/// * The computed offset, **in bytes**, cannot overflow an `isize`.
///
Expand All @@ -2025,10 +2088,12 @@ impl<T: ?Sized> *mut T {
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
///
/// Consider using `wrapping_offset` instead if these constraints are
/// 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
///
/// # Examples
///
/// Basic usage:
Expand Down Expand Up @@ -2062,7 +2127,8 @@ impl<T: ?Sized> *mut T {
/// Behavior:
///
/// * Both the starting and resulting pointer must be either in bounds or one
/// byte past the end of the same allocated object.
/// byte past the end of the same allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
///
/// * The computed offset cannot exceed `isize::MAX` **bytes**.
///
Expand All @@ -2082,10 +2148,12 @@ impl<T: ?Sized> *mut T {
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
///
/// Consider using `wrapping_offset` instead if these constraints are
/// 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
///
/// # Examples
///
/// Basic usage:
Expand Down Expand Up @@ -2118,8 +2186,21 @@ impl<T: ?Sized> *mut T {
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
///
/// Always use `.add(count)` instead when possible, because `add`
/// allows the compiler to optimize better.
/// 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.
///
/// 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 preferrable in performance-sensitive code.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// [`add`]: #method.add
///
/// # Examples
///
Expand Down Expand Up @@ -2159,8 +2240,21 @@ impl<T: ?Sized> *mut T {
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
///
/// Always use `.sub(count)` instead when possible, because `sub`
/// allows the compiler to optimize better.
/// 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.
///
/// 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 preferrable in performance-sensitive code.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
///
/// [`sub`]: #method.sub
///
/// # Examples
///
Expand Down