1
Fork 0

Auto merge of #127420 - matthiaskrgr:rollup-vpitwow, r=matthiaskrgr

Rollup of 3 pull requests

Successful merges:

 - #127275 (offset_from, offset: clearly separate safety requirements the user needs to prove from corollaries that automatically follow)
 - #127379 (rustdoc-search: stop constructing pointless arrays in decode)
 - #127391 (Use verbose suggestion for `ptr::null_mut()`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-07-06 12:07:55 +00:00
commit 3bec61736a
9 changed files with 153 additions and 287 deletions

View file

@ -301,9 +301,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
} }
// The signed form of the intrinsic allows this. If we interpret the // The signed form of the intrinsic allows this. If we interpret the
// difference as isize, we'll get the proper signed difference. If that // difference as isize, we'll get the proper signed difference. If that
// seems *positive*, they were more than isize::MAX apart. // seems *positive* or equal to isize::MIN, they were more than isize::MAX apart.
let dist = val.to_target_isize(self)?; let dist = val.to_target_isize(self)?;
if dist >= 0 { if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() {
throw_ub_custom!( throw_ub_custom!(
fluent::const_eval_offset_from_underflow, fluent::const_eval_offset_from_underflow,
name = intrinsic_name, name = intrinsic_name,

View file

@ -501,6 +501,7 @@ pub enum SuggestBoxing {
#[suggestion( #[suggestion(
hir_typeck_suggest_ptr_null_mut, hir_typeck_suggest_ptr_null_mut,
applicability = "maybe-incorrect", applicability = "maybe-incorrect",
style = "verbose",
code = "core::ptr::null_mut()" code = "core::ptr::null_mut()"
)] )]
pub struct SuggestPtrNullMut { pub struct SuggestPtrNullMut {

View file

@ -390,37 +390,26 @@ impl<T: ?Sized> *const T {
if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) } if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
} }
/// Calculates the offset from a pointer. /// Adds an offset to a pointer.
/// ///
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
/// offset of `3 * size_of::<T>()` bytes. /// offset of `3 * size_of::<T>()` bytes.
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
/// pointer must be either in bounds or at the end of the same [allocated object].
/// (If it is zero, then the function is always well-defined.)
/// ///
/// * The computed offset, **in bytes**, cannot overflow an `isize`. /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
/// ///
/// * The offset being in bounds cannot rely on "wrapping around" the address /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// The compiler and standard library generally tries to ensure allocations /// safe.
/// never reach a size where an offset is a concern. For instance, `Vec`
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
/// `vec.as_ptr().add(vec.len())` is always safe.
///
/// Most platforms fundamentally can't even construct such an allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// 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 /// difficult to satisfy. The only advantage of this method is that it
@ -611,8 +600,7 @@ impl<T: ?Sized> *const T {
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * `self` and `origin` must either /// * `self` and `origin` must either
/// ///
@ -623,26 +611,10 @@ impl<T: ?Sized> *const T {
/// * The distance between the pointers, in bytes, must be an exact multiple /// * The distance between the pointers, in bytes, must be an exact multiple
/// of the size of `T`. /// of the size of `T`.
/// ///
/// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. /// As a consequence, the absolute distance between the pointers, in bytes, computed on
/// /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
/// * The distance being in bounds cannot rely on "wrapping around" the address space. /// implied by the in-bounds requirement, and the fact that no allocated object can be larger
/// /// than `isize::MAX` bytes.
/// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
/// address space, so two pointers within some value of any Rust type `T` will always satisfy
/// the last two conditions. The standard library also generally ensures that allocations
/// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
/// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
/// always satisfies the last two conditions.
///
/// Most platforms fundamentally can't even construct such a large allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
/// such large allocations either.)
/// ///
/// The requirement for pointers to be derived from the same allocated object is primarily /// The requirement for pointers to be derived from the same allocated object is primarily
/// needed for `const`-compatibility: the distance between pointers into *different* allocated /// needed for `const`-compatibility: the distance between pointers into *different* allocated
@ -879,37 +851,26 @@ impl<T: ?Sized> *const T {
} }
} }
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// 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 /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
/// offset of `3 * size_of::<T>()` bytes. /// offset of `3 * size_of::<T>()` bytes.
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
/// pointer must be either in bounds or at the end of the same [allocated object].
/// (If it is zero, then the function is always well-defined.)
/// ///
/// * The computed offset, **in bytes**, cannot overflow an `isize`. /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
/// ///
/// * The offset being in bounds cannot rely on "wrapping around" the address /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// space. That is, the infinite-precision sum must fit in a `usize`. /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// The compiler and standard library generally tries to ensure allocations /// safe.
/// never reach a size where an offset is a concern. For instance, `Vec`
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
/// `vec.as_ptr().add(vec.len())` is always safe.
///
/// Most platforms fundamentally can't even construct such an allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// ///
/// Consider using [`wrapping_add`] 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 /// difficult to satisfy. The only advantage of this method is that it
@ -963,7 +924,7 @@ impl<T: ?Sized> *const T {
unsafe { self.cast::<u8>().add(count).with_metadata_of(self) } unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
} }
/// Calculates the offset from a pointer (convenience for /// Subtracts an offset from a pointer (convenience for
/// `.offset((count as isize).wrapping_neg())`). /// `.offset((count as isize).wrapping_neg())`).
/// ///
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
@ -971,30 +932,19 @@ impl<T: ?Sized> *const T {
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
/// pointer must be either in bounds or at the end of the same [allocated object].
/// (If it is zero, then the function is always well-defined.)
/// ///
/// * The computed offset cannot exceed `isize::MAX` **bytes**. /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
/// ///
/// * The offset being in bounds cannot rely on "wrapping around" the address /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// space. That is, the infinite-precision sum must fit in a usize. /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// The compiler and standard library generally tries to ensure allocations /// safe.
/// never reach a size where an offset is a concern. For instance, `Vec`
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
/// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
///
/// Most platforms fundamentally can't even construct such an allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// ///
/// Consider using [`wrapping_sub`] 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 /// difficult to satisfy. The only advantage of this method is that it

View file

@ -404,37 +404,26 @@ impl<T: ?Sized> *mut T {
if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) } if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
} }
/// Calculates the offset from a pointer. /// Adds an offset to a pointer.
/// ///
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
/// offset of `3 * size_of::<T>()` bytes. /// offset of `3 * size_of::<T>()` bytes.
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
/// pointer must be either in bounds or at the end of the same [allocated object].
/// (If it is zero, then the function is always well-defined.)
/// ///
/// * The computed offset, **in bytes**, cannot overflow an `isize`. /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
/// ///
/// * The offset being in bounds cannot rely on "wrapping around" the address /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// The compiler and standard library generally tries to ensure allocations /// safe.
/// never reach a size where an offset is a concern. For instance, `Vec`
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
/// `vec.as_ptr().add(vec.len())` is always safe.
///
/// Most platforms fundamentally can't even construct such an allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// 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 /// difficult to satisfy. The only advantage of this method is that it
@ -836,8 +825,7 @@ impl<T: ?Sized> *mut T {
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * `self` and `origin` must either /// * `self` and `origin` must either
/// ///
@ -848,26 +836,10 @@ impl<T: ?Sized> *mut T {
/// * The distance between the pointers, in bytes, must be an exact multiple /// * The distance between the pointers, in bytes, must be an exact multiple
/// of the size of `T`. /// of the size of `T`.
/// ///
/// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. /// As a consequence, the absolute distance between the pointers, in bytes, computed on
/// /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
/// * The distance being in bounds cannot rely on "wrapping around" the address space. /// implied by the in-bounds requirement, and the fact that no allocated object can be larger
/// /// than `isize::MAX` bytes.
/// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
/// address space, so two pointers within some value of any Rust type `T` will always satisfy
/// the last two conditions. The standard library also generally ensures that allocations
/// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
/// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
/// always satisfies the last two conditions.
///
/// Most platforms fundamentally can't even construct such a large allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
/// such large allocations either.)
/// ///
/// The requirement for pointers to be derived from the same allocated object is primarily /// The requirement for pointers to be derived from the same allocated object is primarily
/// needed for `const`-compatibility: the distance between pointers into *different* allocated /// needed for `const`-compatibility: the distance between pointers into *different* allocated
@ -1020,37 +992,26 @@ impl<T: ?Sized> *mut T {
unsafe { (self as *const T).sub_ptr(origin) } unsafe { (self as *const T).sub_ptr(origin) }
} }
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// 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 /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
/// offset of `3 * size_of::<T>()` bytes. /// offset of `3 * size_of::<T>()` bytes.
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
/// pointer must be either in bounds or at the end of the same [allocated object].
/// (If it is zero, then the function is always well-defined.)
/// ///
/// * The computed offset, **in bytes**, cannot overflow an `isize`. /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
/// ///
/// * The offset being in bounds cannot rely on "wrapping around" the address /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// space. That is, the infinite-precision sum must fit in a `usize`. /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// The compiler and standard library generally tries to ensure allocations /// safe.
/// never reach a size where an offset is a concern. For instance, `Vec`
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
/// `vec.as_ptr().add(vec.len())` is always safe.
///
/// Most platforms fundamentally can't even construct such an allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// ///
/// Consider using [`wrapping_add`] 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 /// difficult to satisfy. The only advantage of this method is that it
@ -1104,7 +1065,7 @@ impl<T: ?Sized> *mut T {
unsafe { self.cast::<u8>().add(count).with_metadata_of(self) } unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
} }
/// Calculates the offset from a pointer (convenience for /// Subtracts an offset from a pointer (convenience for
/// `.offset((count as isize).wrapping_neg())`). /// `.offset((count as isize).wrapping_neg())`).
/// ///
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
@ -1112,30 +1073,19 @@ impl<T: ?Sized> *mut T {
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
/// pointer must be either in bounds or at the end of the same [allocated object].
/// (If it is zero, then the function is always well-defined.)
/// ///
/// * The computed offset cannot exceed `isize::MAX` **bytes**. /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
/// ///
/// * The offset being in bounds cannot rely on "wrapping around" the address /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// space. That is, the infinite-precision sum must fit in a usize. /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// The compiler and standard library generally tries to ensure allocations /// safe.
/// never reach a size where an offset is a concern. For instance, `Vec`
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
/// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
///
/// Most platforms fundamentally can't even construct such an allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// ///
/// Consider using [`wrapping_sub`] 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 /// difficult to satisfy. The only advantage of this method is that it

View file

@ -476,36 +476,26 @@ impl<T: ?Sized> NonNull<T> {
unsafe { NonNull { pointer: self.as_ptr() as *mut U } } unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
} }
/// Calculates the offset from a pointer. /// Adds an offset to a pointer.
/// ///
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
/// offset of `3 * size_of::<T>()` bytes. /// offset of `3 * size_of::<T>()` bytes.
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * Both the starting and resulting pointer must be either in bounds or one /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
/// byte past the end of the same [allocated object].
/// ///
/// * The computed offset, **in bytes**, cannot overflow an `isize`. /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
/// ///
/// * The offset being in bounds cannot rely on "wrapping around" the address /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// The compiler and standard library generally tries to ensure allocations /// safe.
/// never reach a size where an offset is a concern. For instance, `Vec`
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
/// `vec.as_ptr().add(vec.len())` is always safe.
///
/// Most platforms fundamentally can't even construct such an allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// ///
/// [allocated object]: crate::ptr#allocated-object /// [allocated object]: crate::ptr#allocated-object
/// ///
@ -562,36 +552,26 @@ impl<T: ?Sized> NonNull<T> {
unsafe { NonNull { pointer: self.pointer.byte_offset(count) } } unsafe { NonNull { pointer: self.pointer.byte_offset(count) } }
} }
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// 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 /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
/// offset of `3 * size_of::<T>()` bytes. /// offset of `3 * size_of::<T>()` bytes.
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * Both the starting and resulting pointer must be either in bounds or one /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
/// byte past the end of the same [allocated object].
/// ///
/// * The computed offset, **in bytes**, cannot overflow an `isize`. /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
/// ///
/// * The offset being in bounds cannot rely on "wrapping around" the address /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// space. That is, the infinite-precision sum must fit in a `usize`. /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// The compiler and standard library generally tries to ensure allocations /// safe.
/// never reach a size where an offset is a concern. For instance, `Vec`
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
/// `vec.as_ptr().add(vec.len())` is always safe.
///
/// Most platforms fundamentally can't even construct such an allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// ///
/// [allocated object]: crate::ptr#allocated-object /// [allocated object]: crate::ptr#allocated-object
/// ///
@ -649,7 +629,7 @@ impl<T: ?Sized> NonNull<T> {
unsafe { NonNull { pointer: self.pointer.byte_add(count) } } unsafe { NonNull { pointer: self.pointer.byte_add(count) } }
} }
/// Calculates the offset from a pointer (convenience for /// Subtracts an offset from a pointer (convenience for
/// `.offset((count as isize).wrapping_neg())`). /// `.offset((count as isize).wrapping_neg())`).
/// ///
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
@ -657,29 +637,19 @@ impl<T: ?Sized> NonNull<T> {
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * Both the starting and resulting pointer must be either in bounds or one /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
/// byte past the end of the same [allocated object].
/// ///
/// * The computed offset cannot exceed `isize::MAX` **bytes**. /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
/// [allocated object], and the entire memory range between `self` and the result must be in
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
/// of the address space.
/// ///
/// * The offset being in bounds cannot rely on "wrapping around" the address /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
/// space. That is, the infinite-precision sum must fit in a usize. /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
/// /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
/// The compiler and standard library generally tries to ensure allocations /// safe.
/// never reach a size where an offset is a concern. For instance, `Vec`
/// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
/// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
///
/// Most platforms fundamentally can't even construct such an allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// ///
/// [allocated object]: crate::ptr#allocated-object /// [allocated object]: crate::ptr#allocated-object
/// ///
@ -761,38 +731,21 @@ impl<T: ?Sized> NonNull<T> {
/// ///
/// # Safety /// # Safety
/// ///
/// If any of the following conditions are violated, the result is Undefined /// If any of the following conditions are violated, the result is Undefined Behavior:
/// Behavior:
/// ///
/// * Both `self` and `origin` must be either in bounds or one /// * `self` and `origin` must either
/// byte past the end of the same [allocated object].
/// ///
/// * Both pointers must be *derived from* a pointer to the same object. /// * both be *derived from* a pointer to the same [allocated object], and the memory range between
/// (See below for an example.) /// the two pointers must be either empty or in bounds of that object. (See below for an example.)
/// * or both be derived from an integer literal/constant, and point to the same address.
/// ///
/// * The distance between the pointers, in bytes, must be an exact multiple /// * The distance between the pointers, in bytes, must be an exact multiple
/// of the size of `T`. /// of the size of `T`.
/// ///
/// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. /// As a consequence, the absolute distance between the pointers, in bytes, computed on
/// /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
/// * The distance being in bounds cannot rely on "wrapping around" the address space. /// implied by the in-bounds requirement, and the fact that no allocated object can be larger
/// /// than `isize::MAX` bytes.
/// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
/// address space, so two pointers within some value of any Rust type `T` will always satisfy
/// the last two conditions. The standard library also generally ensures that allocations
/// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
/// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
/// always satisfies the last two conditions.
///
/// Most platforms fundamentally can't even construct such a large allocation.
/// For instance, no known 64-bit platform can ever serve a request
/// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
/// However, some 32-bit and 16-bit platforms may successfully serve a request for
/// more than `isize::MAX` bytes with things like Physical Address
/// Extension. As such, memory acquired directly from allocators or memory
/// mapped files *may* be too large to handle with this function.
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
/// such large allocations either.)
/// ///
/// The requirement for pointers to be derived from the same allocated object is primarily /// The requirement for pointers to be derived from the same allocated object is primarily
/// needed for `const`-compatibility: the distance between pointers into *different* allocated /// needed for `const`-compatibility: the distance between pointers into *different* allocated

View file

@ -3293,10 +3293,9 @@ ${item.displayPath}<span class="${type}">${name}</span>\
} }
// call after consuming `{` // call after consuming `{`
decodeList() { decodeList() {
const cb = "}".charCodeAt(0);
let c = this.string.charCodeAt(this.offset); let c = this.string.charCodeAt(this.offset);
const ret = []; const ret = [];
while (c !== cb) { while (c !== 125) { // 125 = "}"
ret.push(this.decode()); ret.push(this.decode());
c = this.string.charCodeAt(this.offset); c = this.string.charCodeAt(this.offset);
} }
@ -3305,14 +3304,13 @@ ${item.displayPath}<span class="${type}">${name}</span>\
} }
// consumes and returns a list or integer // consumes and returns a list or integer
decode() { decode() {
const [ob, la] = ["{", "`"].map(c => c.charCodeAt(0));
let n = 0; let n = 0;
let c = this.string.charCodeAt(this.offset); let c = this.string.charCodeAt(this.offset);
if (c === ob) { if (c === 123) { // 123 = "{"
this.offset += 1; this.offset += 1;
return this.decodeList(); return this.decodeList();
} }
while (c < la) { while (c < 96) { // 96 = "`"
n = (n << 4) | (c & 0xF); n = (n << 4) | (c & 0xF);
this.offset += 1; this.offset += 1;
c = this.string.charCodeAt(this.offset); c = this.string.charCodeAt(this.offset);
@ -3325,15 +3323,14 @@ ${item.displayPath}<span class="${type}">${name}</span>\
} }
next() { next() {
const c = this.string.charCodeAt(this.offset); const c = this.string.charCodeAt(this.offset);
const [zero, ua, la] = ["0", "@", "`"].map(c => c.charCodeAt(0));
// sixteen characters after "0" are backref // sixteen characters after "0" are backref
if (c >= zero && c < ua) { if (c >= 48 && c < 64) { // 48 = "0", 64 = "@"
this.offset += 1; this.offset += 1;
return this.backrefQueue[c - zero]; return this.backrefQueue[c - 48];
} }
// special exception: 0 doesn't use backref encoding // special exception: 0 doesn't use backref encoding
// it's already one character, and it's always nullish // it's already one character, and it's always nullish
if (c === la) { if (c === 96) { // 96 = "`"
this.offset += 1; this.offset += 1;
return this.cons(0); return this.cons(0);
} }
@ -3472,7 +3469,6 @@ ${item.displayPath}<span class="${type}">${name}</span>\
searchIndex = []; searchIndex = [];
searchIndexDeprecated = new Map(); searchIndexDeprecated = new Map();
searchIndexEmptyDesc = new Map(); searchIndexEmptyDesc = new Map();
const charA = "A".charCodeAt(0);
let currentIndex = 0; let currentIndex = 0;
let id = 0; let id = 0;
@ -3639,7 +3635,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
// object defined above. // object defined above.
const row = { const row = {
crate, crate,
ty: itemTypes.charCodeAt(i) - charA, ty: itemTypes.charCodeAt(i) - 65, // 65 = "A"
name: itemNames[i], name: itemNames[i],
path, path,
descShard, descShard,

View file

@ -92,6 +92,14 @@ pub const TOO_FAR_APART2: isize = {
unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed
//~| too far before //~| too far before
}; };
pub const TOO_FAR_APART3: isize = {
let ptr1 = &0u8 as *const u8;
let ptr2 = ptr1.wrapping_offset(isize::MIN);
// The result of this would be `isize::MIN`, which *does* fit in an `isize`, but its
// absolute value does not. (Also anyway there cannot be an allocation of that size.)
unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed
//~| too far before
};
const WRONG_ORDER_UNSIGNED: usize = { const WRONG_ORDER_UNSIGNED: usize = {
let a = ['a', 'b', 'c']; let a = ['a', 'b', 'c'];

View file

@ -60,13 +60,19 @@ LL | unsafe { ptr_offset_from(ptr1, ptr2) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:99:14 --> $DIR/offset_from_ub.rs:100:14
|
LL | unsafe { ptr_offset_from(ptr1, ptr2) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:107:14
| |
LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:106:14 --> $DIR/offset_from_ub.rs:114:14
| |
LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second
@ -79,7 +85,7 @@ error[E0080]: evaluation of constant value failed
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from` note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `OFFSET_VERY_FAR1` note: inside `OFFSET_VERY_FAR1`
--> $DIR/offset_from_ub.rs:115:14 --> $DIR/offset_from_ub.rs:123:14
| |
LL | unsafe { ptr2.offset_from(ptr1) } LL | unsafe { ptr2.offset_from(ptr1) }
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
@ -92,11 +98,11 @@ error[E0080]: evaluation of constant value failed
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from` note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `OFFSET_VERY_FAR2` note: inside `OFFSET_VERY_FAR2`
--> $DIR/offset_from_ub.rs:121:14 --> $DIR/offset_from_ub.rs:129:14
| |
LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 13 previous errors error: aborting due to 14 previous errors
For more information about this error, try `rustc --explain E0080`. For more information about this error, try `rustc --explain E0080`.

View file

@ -2,10 +2,8 @@ error[E0308]: mismatched types
--> $DIR/ptr-null-mutability-suggestions.rs:9:24 --> $DIR/ptr-null-mutability-suggestions.rs:9:24
| |
LL | expecting_null_mut(ptr::null()); LL | expecting_null_mut(ptr::null());
| ------------------ ^^^^^^^^^^^ | ------------------ ^^^^^^^^^^^ types differ in mutability
| | | | |
| | types differ in mutability
| | help: consider using `core::ptr::null_mut` instead: `core::ptr::null_mut()`
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= note: expected raw pointer `*mut u8` = note: expected raw pointer `*mut u8`
@ -15,6 +13,10 @@ note: function defined here
| |
LL | fn expecting_null_mut(_: *mut u8) {} LL | fn expecting_null_mut(_: *mut u8) {}
| ^^^^^^^^^^^^^^^^^^ ---------- | ^^^^^^^^^^^^^^^^^^ ----------
help: consider using `core::ptr::null_mut` instead
|
LL | expecting_null_mut(core::ptr::null_mut());
| ~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 1 previous error error: aborting due to 1 previous error