diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-08-12 10:58:13 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-08-12 10:58:13 +0200 |
| commit | e9615f2487dc2acdad2d1dd7668808728f99e310 (patch) | |
| tree | 0eb16276ced8ea4daa946536040be667cb465792 /src | |
| parent | 0b4823de23ea6af70f49bd7fb8e811fc6dffe006 (diff) | |
| parent | 0dc9e2a56502c1138c6faf021888844905e64cf3 (diff) | |
| download | rust-e9615f2487dc2acdad2d1dd7668808728f99e310.tar.gz rust-e9615f2487dc2acdad2d1dd7668808728f99e310.zip | |
Rollup merge of #63297 - RalfJung:ptr_offset, r=dtolnay
Improve pointer offset method docs Cc @rkruppe @gnzlbg
Diffstat (limited to 'src')
| -rw-r--r-- | src/libcore/ptr/mod.rs | 162 |
1 files changed, 128 insertions, 34 deletions
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index fa55bbf9c16..f5fbd1a6b13 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -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`. /// @@ -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: @@ -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 /// @@ -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`. /// @@ -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`. /// @@ -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: @@ -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**. /// @@ -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: @@ -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 /// @@ -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 /// @@ -1757,7 +1804,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`. /// @@ -1777,10 +1825,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: @@ -1808,15 +1858,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 /// @@ -1903,7 +1964,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`. /// @@ -2007,7 +2069,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`. /// @@ -2027,10 +2090,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: @@ -2064,7 +2129,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**. /// @@ -2084,10 +2150,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: @@ -2120,8 +2188,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 /// @@ -2161,8 +2242,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 /// |
