Auto merge of #67464 - Centril:rollup-j3mkl1m, r=Centril
Rollup of 6 pull requests Successful merges: - #67130 (Const prop should finish propagation into user defined variables) - #67163 (Split up ptr/mod.rs in libcore...) - #67314 (Don't suppress move errors for union fields) - #67392 (Fix unresolved type span inside async object) - #67404 (Separate region inference logic from error handling better) - #67428 (`is_binding_pat`: use explicit match & include or-pats in grammar) Failed merges: r? @ghost
This commit is contained in:
commit
9ff30a7810
18 changed files with 2090 additions and 1828 deletions
755
src/libcore/ptr/const_ptr.rs
Normal file
755
src/libcore/ptr/const_ptr.rs
Normal file
|
|
@ -0,0 +1,755 @@
|
|||
use crate::cmp::Ordering::{self, Less, Equal, Greater};
|
||||
use crate::intrinsics;
|
||||
use crate::mem;
|
||||
use super::*;
|
||||
|
||||
// ignore-tidy-undocumented-unsafe
|
||||
|
||||
#[lang = "const_ptr"]
|
||||
impl<T: ?Sized> *const T {
|
||||
/// Returns `true` if the pointer is null.
|
||||
///
|
||||
/// Note that unsized types have many possible null pointers, as only the
|
||||
/// raw data pointer is considered, not their length, vtable, etc.
|
||||
/// Therefore, two pointers that are null may still not compare equal to
|
||||
/// each other.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "Follow the rabbit";
|
||||
/// let ptr: *const u8 = s.as_ptr();
|
||||
/// assert!(!ptr.is_null());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn is_null(self) -> bool {
|
||||
// Compare via a cast to a thin pointer, so fat pointers are only
|
||||
// considering their "data" part for null-ness.
|
||||
(self as *const u8) == null()
|
||||
}
|
||||
|
||||
/// Casts to a pointer of another type.
|
||||
#[stable(feature = "ptr_cast", since = "1.38.0")]
|
||||
#[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
|
||||
#[inline]
|
||||
pub const fn cast<U>(self) -> *const U {
|
||||
self as _
|
||||
}
|
||||
|
||||
/// Returns `None` if the pointer is null, or else returns a reference to
|
||||
/// the value wrapped in `Some`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// While this method and its mutable counterpart are useful for
|
||||
/// null-safety, it is important to note that this is still an unsafe
|
||||
/// operation because the returned value could be pointing to invalid
|
||||
/// memory.
|
||||
///
|
||||
/// When calling this method, you have to ensure that *either* the pointer is NULL *or*
|
||||
/// all of the following is true:
|
||||
/// - it is properly aligned
|
||||
/// - it must point to an initialized instance of T; in particular, the pointer must be
|
||||
/// "dereferencable" in the sense defined [here].
|
||||
///
|
||||
/// This applies even if the result of this method is unused!
|
||||
/// (The part about being initialized is not yet fully decided, but until
|
||||
/// it is, the only safe approach is to ensure that they are indeed initialized.)
|
||||
///
|
||||
/// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
|
||||
/// not necessarily reflect the actual lifetime of the data. *You* must enforce
|
||||
/// Rust's aliasing rules. In particular, for the duration of this lifetime,
|
||||
/// the memory the pointer points to must not get mutated (except inside `UnsafeCell`).
|
||||
///
|
||||
/// [here]: crate::ptr#safety
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *const u8 = &10u8 as *const u8;
|
||||
///
|
||||
/// unsafe {
|
||||
/// if let Some(val_back) = ptr.as_ref() {
|
||||
/// println!("We got back the value: {}!", val_back);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Null-unchecked version
|
||||
///
|
||||
/// If you are sure the pointer can never be null and are looking for some kind of
|
||||
/// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can
|
||||
/// dereference the pointer directly.
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *const u8 = &10u8 as *const u8;
|
||||
///
|
||||
/// unsafe {
|
||||
/// let val_back = &*ptr;
|
||||
/// println!("We got back the value: {}!", val_back);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||
#[inline]
|
||||
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
|
||||
if self.is_null() { None } else { Some(&*self) }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// 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`.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure 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
|
||||
/// `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
|
||||
/// 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:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
/// let ptr: *const u8 = s.as_ptr();
|
||||
///
|
||||
/// unsafe {
|
||||
/// println!("{}", *ptr.offset(1) as char);
|
||||
/// println!("{}", *ptr.offset(2) as char);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub unsafe fn offset(self, count: isize) -> *const T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
intrinsics::offset(self, count)
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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 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.
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
/// let mut ptr: *const u8 = data.as_ptr();
|
||||
/// let step = 2;
|
||||
/// let end_rounded_up = ptr.wrapping_offset(6);
|
||||
///
|
||||
/// // This loop prints "1, 3, 5, "
|
||||
/// while ptr != end_rounded_up {
|
||||
/// unsafe {
|
||||
/// print!("{}, ", *ptr);
|
||||
/// }
|
||||
/// ptr = ptr.wrapping_offset(step);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
|
||||
#[inline]
|
||||
pub fn wrapping_offset(self, count: isize) -> *const T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
unsafe { intrinsics::arith_offset(self, count) }
|
||||
}
|
||||
|
||||
/// Calculates the distance between two pointers. The returned value is in
|
||||
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||
///
|
||||
/// This function is the inverse of [`offset`].
|
||||
///
|
||||
/// [`offset`]: #method.offset
|
||||
/// [`wrapping_offset_from`]: #method.wrapping_offset_from
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and other pointer must be either in bounds or one
|
||||
/// 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`.
|
||||
///
|
||||
/// * The distance between the pointers, in bytes, must be an exact multiple
|
||||
/// of the size of `T`.
|
||||
///
|
||||
/// * The distance being in bounds cannot rely on "wrapping around" the address space.
|
||||
///
|
||||
/// The compiler and standard library generally try to ensure 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())` 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_from`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
/// enables more aggressive compiler optimizations.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if `T` is a Zero-Sized Type ("ZST").
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_offset_from)]
|
||||
///
|
||||
/// let a = [0; 5];
|
||||
/// let ptr1: *const i32 = &a[1];
|
||||
/// let ptr2: *const i32 = &a[3];
|
||||
/// unsafe {
|
||||
/// assert_eq!(ptr2.offset_from(ptr1), 2);
|
||||
/// assert_eq!(ptr1.offset_from(ptr2), -2);
|
||||
/// assert_eq!(ptr1.offset(2), ptr2);
|
||||
/// assert_eq!(ptr2.offset(-2), ptr1);
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "ptr_offset_from", issue = "41079")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
|
||||
#[inline]
|
||||
pub const unsafe fn offset_from(self, origin: *const T) -> isize
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
let pointee_size = mem::size_of::<T>();
|
||||
let ok = 0 < pointee_size && pointee_size <= isize::max_value() as usize;
|
||||
// assert that the pointee size is valid in a const eval compatible way
|
||||
// FIXME: do this with a real assert at some point
|
||||
[()][(!ok) as usize];
|
||||
intrinsics::ptr_offset_from(self, origin)
|
||||
}
|
||||
|
||||
/// Calculates the distance between two pointers. The returned value is in
|
||||
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||
///
|
||||
/// If the address different between the two pointers is not a multiple of
|
||||
/// `mem::size_of::<T>()` then the result of the division is rounded towards
|
||||
/// zero.
|
||||
///
|
||||
/// Though this method is safe for any two pointers, note that its result
|
||||
/// will be mostly useless if the two pointers aren't into the same allocated
|
||||
/// object, for example if they point to two different local variables.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if `T` is a zero-sized type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_wrapping_offset_from)]
|
||||
///
|
||||
/// let a = [0; 5];
|
||||
/// let ptr1: *const i32 = &a[1];
|
||||
/// let ptr2: *const i32 = &a[3];
|
||||
/// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
|
||||
/// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2);
|
||||
/// assert_eq!(ptr1.wrapping_offset(2), ptr2);
|
||||
/// assert_eq!(ptr2.wrapping_offset(-2), ptr1);
|
||||
///
|
||||
/// let ptr1: *const i32 = 3 as _;
|
||||
/// let ptr2: *const i32 = 13 as _;
|
||||
/// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
|
||||
/// ```
|
||||
#[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
|
||||
#[inline]
|
||||
pub fn wrapping_offset_from(self, origin: *const T) -> isize
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
let pointee_size = mem::size_of::<T>();
|
||||
assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize);
|
||||
|
||||
let d = isize::wrapping_sub(self as _, origin as _);
|
||||
d.wrapping_div(pointee_size as _)
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// 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`.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a `usize`.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure 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
|
||||
/// `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
|
||||
/// 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:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
/// let ptr: *const u8 = s.as_ptr();
|
||||
///
|
||||
/// unsafe {
|
||||
/// println!("{}", *ptr.add(1) as char);
|
||||
/// println!("{}", *ptr.add(2) as char);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.offset(count as isize)
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for
|
||||
/// `.offset((count as isize).wrapping_neg())`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// 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**.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure 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
|
||||
/// `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
|
||||
/// 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:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
///
|
||||
/// unsafe {
|
||||
/// let end: *const u8 = s.as_ptr().add(3);
|
||||
/// println!("{}", *end.sub(1) as char);
|
||||
/// println!("{}", *end.sub(2) as char);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.offset((count as isize).wrapping_neg())
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||
/// (convenience for `.wrapping_offset(count as isize)`)
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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 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
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
/// let mut ptr: *const u8 = data.as_ptr();
|
||||
/// let step = 2;
|
||||
/// let end_rounded_up = ptr.wrapping_add(6);
|
||||
///
|
||||
/// // This loop prints "1, 3, 5, "
|
||||
/// while ptr != end_rounded_up {
|
||||
/// unsafe {
|
||||
/// print!("{}, ", *ptr);
|
||||
/// }
|
||||
/// ptr = ptr.wrapping_add(step);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub fn wrapping_add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wrapping_offset(count as isize)
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||
/// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`)
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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 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
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements (backwards)
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
/// let mut ptr: *const u8 = data.as_ptr();
|
||||
/// let start_rounded_down = ptr.wrapping_sub(2);
|
||||
/// ptr = ptr.wrapping_add(4);
|
||||
/// let step = 2;
|
||||
/// // This loop prints "5, 3, 1, "
|
||||
/// while ptr != start_rounded_down {
|
||||
/// unsafe {
|
||||
/// print!("{}, ", *ptr);
|
||||
/// }
|
||||
/// ptr = ptr.wrapping_sub(step);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub fn wrapping_sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wrapping_offset((count as isize).wrapping_neg())
|
||||
}
|
||||
|
||||
/// Reads the value from `self` without moving it. This leaves the
|
||||
/// memory in `self` unchanged.
|
||||
///
|
||||
/// See [`ptr::read`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::read`]: ./ptr/fn.read.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn read(self) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
read(self)
|
||||
}
|
||||
|
||||
/// Performs a volatile read of the value from `self` without moving it. This
|
||||
/// leaves the memory in `self` unchanged.
|
||||
///
|
||||
/// Volatile operations are intended to act on I/O memory, and are guaranteed
|
||||
/// to not be elided or reordered by the compiler across other volatile
|
||||
/// operations.
|
||||
///
|
||||
/// See [`ptr::read_volatile`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn read_volatile(self) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
read_volatile(self)
|
||||
}
|
||||
|
||||
/// Reads the value from `self` without moving it. This leaves the
|
||||
/// memory in `self` unchanged.
|
||||
///
|
||||
/// Unlike `read`, the pointer may be unaligned.
|
||||
///
|
||||
/// See [`ptr::read_unaligned`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn read_unaligned(self) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
read_unaligned(self)
|
||||
}
|
||||
|
||||
/// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
|
||||
/// and destination may overlap.
|
||||
///
|
||||
/// NOTE: this has the *same* argument order as [`ptr::copy`].
|
||||
///
|
||||
/// See [`ptr::copy`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy`]: ./ptr/fn.copy.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_to(self, dest: *mut T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
copy(self, dest, count)
|
||||
}
|
||||
|
||||
/// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
|
||||
/// and destination may *not* overlap.
|
||||
///
|
||||
/// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`].
|
||||
///
|
||||
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
copy_nonoverlapping(self, dest, count)
|
||||
}
|
||||
|
||||
/// Computes the offset that needs to be applied to the pointer in order to make it aligned to
|
||||
/// `align`.
|
||||
///
|
||||
/// If it is not possible to align the pointer, the implementation returns
|
||||
/// `usize::max_value()`. It is permissible for the implementation to *always*
|
||||
/// return `usize::max_value()`. Only your algorithm's performance can depend
|
||||
/// on getting a usable offset here, not its correctness.
|
||||
///
|
||||
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
|
||||
/// used with the `wrapping_add` method.
|
||||
///
|
||||
/// There are no guarantees whatsoever that offsetting the pointer will not overflow or go
|
||||
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
|
||||
/// the returned offset is correct in all terms other than alignment.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// The function panics if `align` is not a power-of-two.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Accessing adjacent `u8` as `u16`
|
||||
///
|
||||
/// ```
|
||||
/// # fn foo(n: usize) {
|
||||
/// # use std::mem::align_of;
|
||||
/// # unsafe {
|
||||
/// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
|
||||
/// let ptr = &x[n] as *const u8;
|
||||
/// let offset = ptr.align_offset(align_of::<u16>());
|
||||
/// if offset < x.len() - n - 1 {
|
||||
/// let u16_ptr = ptr.add(offset) as *const u16;
|
||||
/// assert_ne!(*u16_ptr, 500);
|
||||
/// } else {
|
||||
/// // while the pointer can be aligned via `offset`, it would point
|
||||
/// // outside the allocation
|
||||
/// }
|
||||
/// # } }
|
||||
/// ```
|
||||
#[stable(feature = "align_offset", since = "1.36.0")]
|
||||
pub fn align_offset(self, align: usize) -> usize
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
if !align.is_power_of_two() {
|
||||
panic!("align_offset: align is not a power-of-two");
|
||||
}
|
||||
unsafe { align_offset(self, align) }
|
||||
}
|
||||
}
|
||||
|
||||
// Equality for pointers
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> PartialEq for *const T {
|
||||
#[inline]
|
||||
fn eq(&self, other: &*const T) -> bool { *self == *other }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Eq for *const T {}
|
||||
|
||||
// Comparison for pointers
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Ord for *const T {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &*const T) -> Ordering {
|
||||
if self < other {
|
||||
Less
|
||||
} else if self == other {
|
||||
Equal
|
||||
} else {
|
||||
Greater
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> PartialOrd for *const T {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &*const T) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn lt(&self, other: &*const T) -> bool { *self < *other }
|
||||
|
||||
#[inline]
|
||||
fn le(&self, other: &*const T) -> bool { *self <= *other }
|
||||
|
||||
#[inline]
|
||||
fn gt(&self, other: &*const T) -> bool { *self > *other }
|
||||
|
||||
#[inline]
|
||||
fn ge(&self, other: &*const T) -> bool { *self >= *other }
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
925
src/libcore/ptr/mut_ptr.rs
Normal file
925
src/libcore/ptr/mut_ptr.rs
Normal file
|
|
@ -0,0 +1,925 @@
|
|||
use crate::cmp::Ordering::{self, Less, Equal, Greater};
|
||||
use crate::intrinsics;
|
||||
use super::*;
|
||||
|
||||
// ignore-tidy-undocumented-unsafe
|
||||
|
||||
#[lang = "mut_ptr"]
|
||||
impl<T: ?Sized> *mut T {
|
||||
/// Returns `true` if the pointer is null.
|
||||
///
|
||||
/// Note that unsized types have many possible null pointers, as only the
|
||||
/// raw data pointer is considered, not their length, vtable, etc.
|
||||
/// Therefore, two pointers that are null may still not compare equal to
|
||||
/// each other.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let mut s = [1, 2, 3];
|
||||
/// let ptr: *mut u32 = s.as_mut_ptr();
|
||||
/// assert!(!ptr.is_null());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn is_null(self) -> bool {
|
||||
// Compare via a cast to a thin pointer, so fat pointers are only
|
||||
// considering their "data" part for null-ness.
|
||||
(self as *mut u8) == null_mut()
|
||||
}
|
||||
|
||||
/// Casts to a pointer of another type.
|
||||
#[stable(feature = "ptr_cast", since = "1.38.0")]
|
||||
#[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
|
||||
#[inline]
|
||||
pub const fn cast<U>(self) -> *mut U {
|
||||
self as _
|
||||
}
|
||||
|
||||
/// Returns `None` if the pointer is null, or else returns a reference to
|
||||
/// the value wrapped in `Some`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// While this method and its mutable counterpart are useful for
|
||||
/// null-safety, it is important to note that this is still an unsafe
|
||||
/// operation because the returned value could be pointing to invalid
|
||||
/// memory.
|
||||
///
|
||||
/// When calling this method, you have to ensure that if the pointer is
|
||||
/// non-NULL, then it is properly aligned, dereferencable (for the whole
|
||||
/// size of `T`) and points to an initialized instance of `T`. This applies
|
||||
/// even if the result of this method is unused!
|
||||
/// (The part about being initialized is not yet fully decided, but until
|
||||
/// it is, the only safe approach is to ensure that they are indeed initialized.)
|
||||
///
|
||||
/// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
|
||||
/// not necessarily reflect the actual lifetime of the data. It is up to the
|
||||
/// caller to ensure that for the duration of this lifetime, the memory this
|
||||
/// pointer points to does not get written to outside of `UnsafeCell<U>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *mut u8 = &mut 10u8 as *mut u8;
|
||||
///
|
||||
/// unsafe {
|
||||
/// if let Some(val_back) = ptr.as_ref() {
|
||||
/// println!("We got back the value: {}!", val_back);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Null-unchecked version
|
||||
///
|
||||
/// If you are sure the pointer can never be null and are looking for some kind of
|
||||
/// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can
|
||||
/// dereference the pointer directly.
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *mut u8 = &mut 10u8 as *mut u8;
|
||||
///
|
||||
/// unsafe {
|
||||
/// let val_back = &*ptr;
|
||||
/// println!("We got back the value: {}!", val_back);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||
#[inline]
|
||||
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
|
||||
if self.is_null() { None } else { Some(&*self) }
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer.
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// 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`.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure 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
|
||||
/// `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
|
||||
/// 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:
|
||||
///
|
||||
/// ```
|
||||
/// let mut s = [1, 2, 3];
|
||||
/// let ptr: *mut u32 = s.as_mut_ptr();
|
||||
///
|
||||
/// unsafe {
|
||||
/// println!("{}", *ptr.offset(1));
|
||||
/// println!("{}", *ptr.offset(2));
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub unsafe fn offset(self, count: isize) -> *mut T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
intrinsics::offset(self, count) as *mut T
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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 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.
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements
|
||||
/// let mut data = [1u8, 2, 3, 4, 5];
|
||||
/// let mut ptr: *mut u8 = data.as_mut_ptr();
|
||||
/// let step = 2;
|
||||
/// let end_rounded_up = ptr.wrapping_offset(6);
|
||||
///
|
||||
/// while ptr != end_rounded_up {
|
||||
/// unsafe {
|
||||
/// *ptr = 0;
|
||||
/// }
|
||||
/// ptr = ptr.wrapping_offset(step);
|
||||
/// }
|
||||
/// assert_eq!(&data, &[0, 2, 0, 4, 0]);
|
||||
/// ```
|
||||
#[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
|
||||
#[inline]
|
||||
pub fn wrapping_offset(self, count: isize) -> *mut T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
unsafe { intrinsics::arith_offset(self, count) as *mut T }
|
||||
}
|
||||
|
||||
/// Returns `None` if the pointer is null, or else returns a mutable
|
||||
/// reference to the value wrapped in `Some`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`as_ref`], this is unsafe because it cannot verify the validity
|
||||
/// of the returned pointer, nor can it ensure that the lifetime `'a`
|
||||
/// returned is indeed a valid lifetime for the contained data.
|
||||
///
|
||||
/// When calling this method, you have to ensure that *either* the pointer is NULL *or*
|
||||
/// all of the following is true:
|
||||
/// - it is properly aligned
|
||||
/// - it must point to an initialized instance of T; in particular, the pointer must be
|
||||
/// "dereferencable" in the sense defined [here].
|
||||
///
|
||||
/// This applies even if the result of this method is unused!
|
||||
/// (The part about being initialized is not yet fully decided, but until
|
||||
/// it is the only safe approach is to ensure that they are indeed initialized.)
|
||||
///
|
||||
/// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
|
||||
/// not necessarily reflect the actual lifetime of the data. *You* must enforce
|
||||
/// Rust's aliasing rules. In particular, for the duration of this lifetime,
|
||||
/// the memory this pointer points to must not get accessed (read or written)
|
||||
/// through any other pointer.
|
||||
///
|
||||
/// [here]: crate::ptr#safety
|
||||
/// [`as_ref`]: #method.as_ref
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let mut s = [1, 2, 3];
|
||||
/// let ptr: *mut u32 = s.as_mut_ptr();
|
||||
/// let first_value = unsafe { ptr.as_mut().unwrap() };
|
||||
/// *first_value = 4;
|
||||
/// println!("{:?}", s); // It'll print: "[4, 2, 3]".
|
||||
/// ```
|
||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||
#[inline]
|
||||
pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
|
||||
if self.is_null() { None } else { Some(&mut *self) }
|
||||
}
|
||||
|
||||
/// Calculates the distance between two pointers. The returned value is in
|
||||
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||
///
|
||||
/// This function is the inverse of [`offset`].
|
||||
///
|
||||
/// [`offset`]: #method.offset-1
|
||||
/// [`wrapping_offset_from`]: #method.wrapping_offset_from-1
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and other pointer must be either in bounds or one
|
||||
/// 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`.
|
||||
///
|
||||
/// * The distance between the pointers, in bytes, must be an exact multiple
|
||||
/// of the size of `T`.
|
||||
///
|
||||
/// * The distance being in bounds cannot rely on "wrapping around" the address space.
|
||||
///
|
||||
/// The compiler and standard library generally try to ensure 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())` 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_from`] instead if these constraints are
|
||||
/// difficult to satisfy. The only advantage of this method is that it
|
||||
/// enables more aggressive compiler optimizations.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if `T` is a Zero-Sized Type ("ZST").
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_offset_from)]
|
||||
///
|
||||
/// let mut a = [0; 5];
|
||||
/// let ptr1: *mut i32 = &mut a[1];
|
||||
/// let ptr2: *mut i32 = &mut a[3];
|
||||
/// unsafe {
|
||||
/// assert_eq!(ptr2.offset_from(ptr1), 2);
|
||||
/// assert_eq!(ptr1.offset_from(ptr2), -2);
|
||||
/// assert_eq!(ptr1.offset(2), ptr2);
|
||||
/// assert_eq!(ptr2.offset(-2), ptr1);
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "ptr_offset_from", issue = "41079")]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
|
||||
#[inline]
|
||||
pub const unsafe fn offset_from(self, origin: *const T) -> isize
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
(self as *const T).offset_from(origin)
|
||||
}
|
||||
|
||||
/// Calculates the distance between two pointers. The returned value is in
|
||||
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
|
||||
///
|
||||
/// If the address different between the two pointers is not a multiple of
|
||||
/// `mem::size_of::<T>()` then the result of the division is rounded towards
|
||||
/// zero.
|
||||
///
|
||||
/// Though this method is safe for any two pointers, note that its result
|
||||
/// will be mostly useless if the two pointers aren't into the same allocated
|
||||
/// object, for example if they point to two different local variables.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if `T` is a zero-sized type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_wrapping_offset_from)]
|
||||
///
|
||||
/// let mut a = [0; 5];
|
||||
/// let ptr1: *mut i32 = &mut a[1];
|
||||
/// let ptr2: *mut i32 = &mut a[3];
|
||||
/// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
|
||||
/// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2);
|
||||
/// assert_eq!(ptr1.wrapping_offset(2), ptr2);
|
||||
/// assert_eq!(ptr2.wrapping_offset(-2), ptr1);
|
||||
///
|
||||
/// let ptr1: *mut i32 = 3 as _;
|
||||
/// let ptr2: *mut i32 = 13 as _;
|
||||
/// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
|
||||
/// ```
|
||||
#[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
|
||||
#[inline]
|
||||
pub fn wrapping_offset_from(self, origin: *const T) -> isize
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
(self as *const T).wrapping_offset_from(origin)
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// 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`.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a `usize`.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure 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
|
||||
/// `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
|
||||
/// 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:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
/// let ptr: *const u8 = s.as_ptr();
|
||||
///
|
||||
/// unsafe {
|
||||
/// println!("{}", *ptr.add(1) as char);
|
||||
/// println!("{}", *ptr.add(2) as char);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.offset(count as isize)
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer (convenience for
|
||||
/// `.offset((count as isize).wrapping_neg())`).
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If any of the following conditions are violated, the result is Undefined
|
||||
/// Behavior:
|
||||
///
|
||||
/// * Both the starting and resulting pointer must be either in bounds or one
|
||||
/// 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**.
|
||||
///
|
||||
/// * The offset being in bounds cannot rely on "wrapping around" the address
|
||||
/// space. That is, the infinite-precision sum must fit in a usize.
|
||||
///
|
||||
/// The compiler and standard library generally tries to ensure 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
|
||||
/// `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
|
||||
/// 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:
|
||||
///
|
||||
/// ```
|
||||
/// let s: &str = "123";
|
||||
///
|
||||
/// unsafe {
|
||||
/// let end: *const u8 = s.as_ptr().add(3);
|
||||
/// println!("{}", *end.sub(1) as char);
|
||||
/// println!("{}", *end.sub(2) as char);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.offset((count as isize).wrapping_neg())
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||
/// (convenience for `.wrapping_offset(count as isize)`)
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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 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
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
/// let mut ptr: *const u8 = data.as_ptr();
|
||||
/// let step = 2;
|
||||
/// let end_rounded_up = ptr.wrapping_add(6);
|
||||
///
|
||||
/// // This loop prints "1, 3, 5, "
|
||||
/// while ptr != end_rounded_up {
|
||||
/// unsafe {
|
||||
/// print!("{}, ", *ptr);
|
||||
/// }
|
||||
/// ptr = ptr.wrapping_add(step);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub fn wrapping_add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wrapping_offset(count as isize)
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer using wrapping arithmetic.
|
||||
/// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`)
|
||||
///
|
||||
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
|
||||
/// offset of `3 * size_of::<T>()` bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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 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
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // Iterate using a raw pointer in increments of two elements (backwards)
|
||||
/// let data = [1u8, 2, 3, 4, 5];
|
||||
/// let mut ptr: *const u8 = data.as_ptr();
|
||||
/// let start_rounded_down = ptr.wrapping_sub(2);
|
||||
/// ptr = ptr.wrapping_add(4);
|
||||
/// let step = 2;
|
||||
/// // This loop prints "5, 3, 1, "
|
||||
/// while ptr != start_rounded_down {
|
||||
/// unsafe {
|
||||
/// print!("{}, ", *ptr);
|
||||
/// }
|
||||
/// ptr = ptr.wrapping_sub(step);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub fn wrapping_sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wrapping_offset((count as isize).wrapping_neg())
|
||||
}
|
||||
|
||||
/// Reads the value from `self` without moving it. This leaves the
|
||||
/// memory in `self` unchanged.
|
||||
///
|
||||
/// See [`ptr::read`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::read`]: ./ptr/fn.read.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn read(self) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
read(self)
|
||||
}
|
||||
|
||||
/// Performs a volatile read of the value from `self` without moving it. This
|
||||
/// leaves the memory in `self` unchanged.
|
||||
///
|
||||
/// Volatile operations are intended to act on I/O memory, and are guaranteed
|
||||
/// to not be elided or reordered by the compiler across other volatile
|
||||
/// operations.
|
||||
///
|
||||
/// See [`ptr::read_volatile`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn read_volatile(self) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
read_volatile(self)
|
||||
}
|
||||
|
||||
/// Reads the value from `self` without moving it. This leaves the
|
||||
/// memory in `self` unchanged.
|
||||
///
|
||||
/// Unlike `read`, the pointer may be unaligned.
|
||||
///
|
||||
/// See [`ptr::read_unaligned`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn read_unaligned(self) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
read_unaligned(self)
|
||||
}
|
||||
|
||||
/// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
|
||||
/// and destination may overlap.
|
||||
///
|
||||
/// NOTE: this has the *same* argument order as [`ptr::copy`].
|
||||
///
|
||||
/// See [`ptr::copy`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy`]: ./ptr/fn.copy.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_to(self, dest: *mut T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
copy(self, dest, count)
|
||||
}
|
||||
|
||||
/// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
|
||||
/// and destination may *not* overlap.
|
||||
///
|
||||
/// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`].
|
||||
///
|
||||
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
copy_nonoverlapping(self, dest, count)
|
||||
}
|
||||
|
||||
/// Copies `count * size_of<T>` bytes from `src` to `self`. The source
|
||||
/// and destination may overlap.
|
||||
///
|
||||
/// NOTE: this has the *opposite* argument order of [`ptr::copy`].
|
||||
///
|
||||
/// See [`ptr::copy`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy`]: ./ptr/fn.copy.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_from(self, src: *const T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
copy(src, self, count)
|
||||
}
|
||||
|
||||
/// Copies `count * size_of<T>` bytes from `src` to `self`. The source
|
||||
/// and destination may *not* overlap.
|
||||
///
|
||||
/// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`].
|
||||
///
|
||||
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
copy_nonoverlapping(src, self, count)
|
||||
}
|
||||
|
||||
/// Executes the destructor (if any) of the pointed-to value.
|
||||
///
|
||||
/// See [`ptr::drop_in_place`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::drop_in_place`]: ./ptr/fn.drop_in_place.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn drop_in_place(self) {
|
||||
drop_in_place(self)
|
||||
}
|
||||
|
||||
/// Overwrites a memory location with the given value without reading or
|
||||
/// dropping the old value.
|
||||
///
|
||||
/// See [`ptr::write`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::write`]: ./ptr/fn.write.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn write(self, val: T)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
write(self, val)
|
||||
}
|
||||
|
||||
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
|
||||
/// bytes of memory starting at `self` to `val`.
|
||||
///
|
||||
/// See [`ptr::write_bytes`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::write_bytes`]: ./ptr/fn.write_bytes.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn write_bytes(self, val: u8, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
write_bytes(self, val, count)
|
||||
}
|
||||
|
||||
/// Performs a volatile write of a memory location with the given value without
|
||||
/// reading or dropping the old value.
|
||||
///
|
||||
/// Volatile operations are intended to act on I/O memory, and are guaranteed
|
||||
/// to not be elided or reordered by the compiler across other volatile
|
||||
/// operations.
|
||||
///
|
||||
/// See [`ptr::write_volatile`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::write_volatile`]: ./ptr/fn.write_volatile.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn write_volatile(self, val: T)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
write_volatile(self, val)
|
||||
}
|
||||
|
||||
/// Overwrites a memory location with the given value without reading or
|
||||
/// dropping the old value.
|
||||
///
|
||||
/// Unlike `write`, the pointer may be unaligned.
|
||||
///
|
||||
/// See [`ptr::write_unaligned`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::write_unaligned`]: ./ptr/fn.write_unaligned.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn write_unaligned(self, val: T)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
write_unaligned(self, val)
|
||||
}
|
||||
|
||||
/// Replaces the value at `self` with `src`, returning the old
|
||||
/// value, without dropping either.
|
||||
///
|
||||
/// See [`ptr::replace`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::replace`]: ./ptr/fn.replace.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn replace(self, src: T) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
replace(self, src)
|
||||
}
|
||||
|
||||
/// Swaps the values at two mutable locations of the same type, without
|
||||
/// deinitializing either. They may overlap, unlike `mem::swap` which is
|
||||
/// otherwise equivalent.
|
||||
///
|
||||
/// See [`ptr::swap`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::swap`]: ./ptr/fn.swap.html
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn swap(self, with: *mut T)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
swap(self, with)
|
||||
}
|
||||
|
||||
/// Computes the offset that needs to be applied to the pointer in order to make it aligned to
|
||||
/// `align`.
|
||||
///
|
||||
/// If it is not possible to align the pointer, the implementation returns
|
||||
/// `usize::max_value()`. It is permissible for the implementation to *always*
|
||||
/// return `usize::max_value()`. Only your algorithm's performance can depend
|
||||
/// on getting a usable offset here, not its correctness.
|
||||
///
|
||||
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
|
||||
/// used with the `wrapping_add` method.
|
||||
///
|
||||
/// There are no guarantees whatsoever that offsetting the pointer will not overflow or go
|
||||
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
|
||||
/// the returned offset is correct in all terms other than alignment.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// The function panics if `align` is not a power-of-two.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Accessing adjacent `u8` as `u16`
|
||||
///
|
||||
/// ```
|
||||
/// # fn foo(n: usize) {
|
||||
/// # use std::mem::align_of;
|
||||
/// # unsafe {
|
||||
/// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
|
||||
/// let ptr = &x[n] as *const u8;
|
||||
/// let offset = ptr.align_offset(align_of::<u16>());
|
||||
/// if offset < x.len() - n - 1 {
|
||||
/// let u16_ptr = ptr.add(offset) as *const u16;
|
||||
/// assert_ne!(*u16_ptr, 500);
|
||||
/// } else {
|
||||
/// // while the pointer can be aligned via `offset`, it would point
|
||||
/// // outside the allocation
|
||||
/// }
|
||||
/// # } }
|
||||
/// ```
|
||||
#[stable(feature = "align_offset", since = "1.36.0")]
|
||||
pub fn align_offset(self, align: usize) -> usize
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
if !align.is_power_of_two() {
|
||||
panic!("align_offset: align is not a power-of-two");
|
||||
}
|
||||
unsafe { align_offset(self, align) }
|
||||
}
|
||||
}
|
||||
|
||||
// Equality for pointers
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> PartialEq for *mut T {
|
||||
#[inline]
|
||||
fn eq(&self, other: &*mut T) -> bool { *self == *other }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Eq for *mut T {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Ord for *mut T {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &*mut T) -> Ordering {
|
||||
if self < other {
|
||||
Less
|
||||
} else if self == other {
|
||||
Equal
|
||||
} else {
|
||||
Greater
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> PartialOrd for *mut T {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &*mut T) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn lt(&self, other: &*mut T) -> bool { *self < *other }
|
||||
|
||||
#[inline]
|
||||
fn le(&self, other: &*mut T) -> bool { *self <= *other }
|
||||
|
||||
#[inline]
|
||||
fn gt(&self, other: &*mut T) -> bool { *self > *other }
|
||||
|
||||
#[inline]
|
||||
fn ge(&self, other: &*mut T) -> bool { *self >= *other }
|
||||
}
|
||||
|
|
@ -1857,6 +1857,16 @@ impl fmt::Display for YieldSource {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<GeneratorKind> for YieldSource {
|
||||
fn from(kind: GeneratorKind) -> Self {
|
||||
match kind {
|
||||
// Guess based on the kind of the current generator.
|
||||
GeneratorKind::Gen => Self::Yield,
|
||||
GeneratorKind::Async(_) => Self::Await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// N.B., if you change this, you'll probably want to change the corresponding
|
||||
// type structure in middle/ty.rs as well.
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
|
|
|
|||
|
|
@ -1173,6 +1173,7 @@ fn resolve_local<'tcx>(
|
|||
/// | VariantName(..., P&, ...)
|
||||
/// | [ ..., P&, ... ]
|
||||
/// | ( ..., P&, ... )
|
||||
/// | ... "|" P& "|" ...
|
||||
/// | box P&
|
||||
fn is_binding_pat(pat: &hir::Pat) -> bool {
|
||||
// Note that the code below looks for *explicit* refs only, that is, it won't
|
||||
|
|
@ -1212,6 +1213,7 @@ fn resolve_local<'tcx>(
|
|||
pats3.iter().any(|p| is_binding_pat(&p))
|
||||
}
|
||||
|
||||
PatKind::Or(ref subpats) |
|
||||
PatKind::TupleStruct(_, ref subpats, _) |
|
||||
PatKind::Tuple(ref subpats, _) => {
|
||||
subpats.iter().any(|p| is_binding_pat(&p))
|
||||
|
|
@ -1221,7 +1223,13 @@ fn resolve_local<'tcx>(
|
|||
is_binding_pat(&subpat)
|
||||
}
|
||||
|
||||
_ => false,
|
||||
PatKind::Ref(_, _) |
|
||||
PatKind::Binding(hir::BindingAnnotation::Unannotated, ..) |
|
||||
PatKind::Binding(hir::BindingAnnotation::Mutable, ..) |
|
||||
PatKind::Wild |
|
||||
PatKind::Path(_) |
|
||||
PatKind::Lit(_) |
|
||||
PatKind::Range(_, _, _) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
//! Error reporting machinery for lifetime errors.
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::infer::NLLRegionVariableOrigin;
|
||||
use rustc::mir::{ConstraintCategory, Local, Location, Body};
|
||||
use rustc::infer::{
|
||||
error_reporting::nice_region_error::NiceRegionError,
|
||||
InferCtxt, NLLRegionVariableOrigin,
|
||||
};
|
||||
use rustc::mir::{
|
||||
ConstraintCategory, Local, Location, Body,
|
||||
};
|
||||
use rustc::ty::{self, RegionVid};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
|
|
@ -93,6 +96,32 @@ pub struct ErrorConstraintInfo {
|
|||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Converts a region inference variable into a `ty::Region` that
|
||||
/// we can use for error reporting. If `r` is universally bound,
|
||||
/// then we use the name that we have on record for it. If `r` is
|
||||
/// existentially bound, then we check its inferred value and try
|
||||
/// to find a good name from that. Returns `None` if we can't find
|
||||
/// one (e.g., this is just some random part of the CFG).
|
||||
pub fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
|
||||
self.to_error_region_vid(r).and_then(|r| self.definitions[r].external_name)
|
||||
}
|
||||
|
||||
/// Returns the [RegionVid] corresponding to the region returned by
|
||||
/// `to_error_region`.
|
||||
pub fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
|
||||
if self.universal_regions.is_universal_region(r) {
|
||||
Some(r)
|
||||
} else {
|
||||
let r_scc = self.constraint_sccs.scc(r);
|
||||
let upper_bound = self.universal_upper_bound(r);
|
||||
if self.scc_values.contains(r_scc, upper_bound) {
|
||||
self.to_error_region_vid(upper_bound)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to find the best constraint to blame for the fact that
|
||||
/// `R: from_region`, where `R` is some region that meets
|
||||
/// `target_test`. This works by following the constraint graph,
|
||||
|
|
|
|||
|
|
@ -928,32 +928,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a region inference variable into a `ty::Region` that
|
||||
/// we can use for error reporting. If `r` is universally bound,
|
||||
/// then we use the name that we have on record for it. If `r` is
|
||||
/// existentially bound, then we check its inferred value and try
|
||||
/// to find a good name from that. Returns `None` if we can't find
|
||||
/// one (e.g., this is just some random part of the CFG).
|
||||
pub fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
|
||||
self.to_error_region_vid(r).and_then(|r| self.definitions[r].external_name)
|
||||
}
|
||||
|
||||
/// Returns the [RegionVid] corresponding to the region returned by
|
||||
/// `to_error_region`.
|
||||
pub fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
|
||||
if self.universal_regions.is_universal_region(r) {
|
||||
Some(r)
|
||||
} else {
|
||||
let r_scc = self.constraint_sccs.scc(r);
|
||||
let upper_bound = self.universal_upper_bound(r);
|
||||
if self.scc_values.contains(r_scc, upper_bound) {
|
||||
self.to_error_region_vid(upper_bound)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Invoked when we have some type-test (e.g., `T: 'X`) that we cannot
|
||||
/// prove to be satisfied. If this is a closure, we will attempt to
|
||||
/// "promote" this type-test into our `ClosureRegionRequirements` and
|
||||
|
|
@ -1164,7 +1138,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// include the CFG anyhow.
|
||||
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
|
||||
/// a result `'y`.
|
||||
fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
|
||||
pub (in crate::borrow_check) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
|
||||
debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
|
||||
|
||||
// Find the smallest universal region that contains all other
|
||||
|
|
@ -1458,19 +1432,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
debug!("check_polonius_subset_errors: subset_error longer_fr={:?},\
|
||||
shorter_fr={:?}", longer_fr, shorter_fr);
|
||||
|
||||
self.report_or_propagate_universal_region_error(
|
||||
let propagated = self.try_propagate_universal_region_error(
|
||||
*longer_fr,
|
||||
*shorter_fr,
|
||||
infcx,
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
mir_def_id,
|
||||
&mut propagated_outlives_requirements,
|
||||
&mut outlives_suggestion,
|
||||
errors_buffer,
|
||||
region_naming,
|
||||
);
|
||||
if !propagated {
|
||||
// If we are not in a context where we can't propagate errors, or we
|
||||
// could not shrink `fr` to something smaller, then just report an
|
||||
// error.
|
||||
//
|
||||
// Note: in this case, we use the unapproximated regions to report the
|
||||
// error. This gives better error messages in some cases.
|
||||
let db = self.report_error(
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
infcx,
|
||||
mir_def_id,
|
||||
*longer_fr,
|
||||
NLLRegionVariableOrigin::FreeRegion,
|
||||
*shorter_fr,
|
||||
&mut outlives_suggestion,
|
||||
region_naming,
|
||||
);
|
||||
|
||||
db.buffer(errors_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has
|
||||
|
|
@ -1594,48 +1583,59 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
self.report_or_propagate_universal_region_error(
|
||||
let propagated = self.try_propagate_universal_region_error(
|
||||
longer_fr,
|
||||
shorter_fr,
|
||||
infcx,
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
mir_def_id,
|
||||
propagated_outlives_requirements,
|
||||
outlives_suggestion,
|
||||
errors_buffer,
|
||||
region_naming,
|
||||
)
|
||||
);
|
||||
|
||||
if propagated {
|
||||
None
|
||||
} else {
|
||||
// If we are not in a context where we can't propagate errors, or we
|
||||
// could not shrink `fr` to something smaller, then just report an
|
||||
// error.
|
||||
//
|
||||
// Note: in this case, we use the unapproximated regions to report the
|
||||
// error. This gives better error messages in some cases.
|
||||
let db = self.report_error(
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
infcx,
|
||||
mir_def_id,
|
||||
longer_fr,
|
||||
NLLRegionVariableOrigin::FreeRegion,
|
||||
shorter_fr,
|
||||
outlives_suggestion,
|
||||
region_naming,
|
||||
);
|
||||
|
||||
db.buffer(errors_buffer);
|
||||
|
||||
Some(ErrorReported)
|
||||
}
|
||||
}
|
||||
|
||||
fn report_or_propagate_universal_region_error(
|
||||
/// Attempt to propagate a region error (e.g. `'a: 'b`) that is not met to a closure's
|
||||
/// creator. If we cannot, then the caller should report an error to the user.
|
||||
///
|
||||
/// Returns `true` if the error was propagated, and `false` otherwise.
|
||||
fn try_propagate_universal_region_error(
|
||||
&self,
|
||||
longer_fr: RegionVid,
|
||||
shorter_fr: RegionVid,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexVec<Local, Option<Symbol>>,
|
||||
upvars: &[Upvar],
|
||||
mir_def_id: DefId,
|
||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
region_naming: &mut RegionErrorNamingCtx,
|
||||
) -> Option<ErrorReported> {
|
||||
debug!(
|
||||
"report_or_propagate_universal_region_error: fr={:?} does not outlive shorter_fr={:?}",
|
||||
longer_fr, shorter_fr,
|
||||
);
|
||||
|
||||
) -> bool {
|
||||
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
|
||||
// Shrink `longer_fr` until we find a non-local region (if we do).
|
||||
// We'll call it `fr-` -- it's ever so slightly smaller than
|
||||
// `longer_fr`.
|
||||
|
||||
if let Some(fr_minus) =
|
||||
self.universal_region_relations.non_local_lower_bound(longer_fr) {
|
||||
debug!("report_or_propagate_universal_region_error: fr_minus={:?}", fr_minus);
|
||||
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
|
||||
|
||||
let blame_span_category =
|
||||
self.find_outlives_blame_span(body, longer_fr,
|
||||
|
|
@ -1648,7 +1648,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
.universal_region_relations
|
||||
.non_local_upper_bounds(&shorter_fr);
|
||||
debug!(
|
||||
"report_or_propagate_universal_region_error: shorter_fr_plus={:?}",
|
||||
"try_propagate_universal_region_error: shorter_fr_plus={:?}",
|
||||
shorter_fr_plus
|
||||
);
|
||||
for &&fr in &shorter_fr_plus {
|
||||
|
|
@ -1660,32 +1660,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
category: blame_span_category.0,
|
||||
});
|
||||
}
|
||||
return None;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are not in a context where we can't propagate errors, or we
|
||||
// could not shrink `fr` to something smaller, then just report an
|
||||
// error.
|
||||
//
|
||||
// Note: in this case, we use the unapproximated regions to report the
|
||||
// error. This gives better error messages in some cases.
|
||||
let db = self.report_error(
|
||||
body,
|
||||
local_names,
|
||||
upvars,
|
||||
infcx,
|
||||
mir_def_id,
|
||||
longer_fr,
|
||||
NLLRegionVariableOrigin::FreeRegion,
|
||||
shorter_fr,
|
||||
outlives_suggestion,
|
||||
region_naming,
|
||||
);
|
||||
|
||||
db.buffer(errors_buffer);
|
||||
|
||||
Some(ErrorReported)
|
||||
false
|
||||
}
|
||||
|
||||
fn check_bound_universal_region(
|
||||
|
|
|
|||
|
|
@ -103,6 +103,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
// The move path index of the first union that we find. Once this is
|
||||
// some we stop creating child move paths, since moves from unions
|
||||
// move the whole thing.
|
||||
// We continue looking for other move errors though so that moving
|
||||
// from `*(u.f: &_)` isn't allowed.
|
||||
let mut union_path = None;
|
||||
|
||||
for (i, elem) in place.projection.iter().enumerate() {
|
||||
let proj_base = &place.projection[..i];
|
||||
let body = self.builder.body;
|
||||
|
|
@ -127,9 +134,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
InteriorOfTypeWithDestructor { container_ty: place_ty },
|
||||
));
|
||||
}
|
||||
// move out of union - always move the entire union
|
||||
ty::Adt(adt, _) if adt.is_union() => {
|
||||
return Err(MoveError::UnionMove { path: base });
|
||||
union_path.get_or_insert(base);
|
||||
}
|
||||
ty::Slice(_) => {
|
||||
return Err(MoveError::cannot_move_out_of(
|
||||
|
|
@ -155,15 +161,22 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
_ => {}
|
||||
};
|
||||
|
||||
base = self.add_move_path(base, elem, |tcx| {
|
||||
Place {
|
||||
base: place.base.clone(),
|
||||
projection: tcx.intern_place_elems(&place.projection[..i+1]),
|
||||
}
|
||||
});
|
||||
if union_path.is_none() {
|
||||
base = self.add_move_path(base, elem, |tcx| {
|
||||
Place {
|
||||
base: place.base.clone(),
|
||||
projection: tcx.intern_place_elems(&place.projection[..i+1]),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(base)
|
||||
if let Some(base) = union_path {
|
||||
// Move out of union - always move the entire union.
|
||||
Err(MoveError::UnionMove { path: base })
|
||||
} else {
|
||||
Ok(base)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_path(
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ struct ConstPropagator<'mir, 'tcx> {
|
|||
ecx: InterpCx<'mir, 'tcx, ConstPropMachine>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
source: MirSource<'tcx>,
|
||||
can_const_prop: IndexVec<Local, bool>,
|
||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
// FIXME(eddyb) avoid cloning these two fields more than once,
|
||||
// by accessing them through `ecx` instead.
|
||||
|
|
@ -708,17 +708,28 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum ConstPropMode {
|
||||
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
|
||||
FullConstProp,
|
||||
/// The `Local` can be propagated into but reads cannot be propagated.
|
||||
OnlyPropagateInto,
|
||||
/// No propagation is allowed at all.
|
||||
NoPropagation,
|
||||
}
|
||||
|
||||
struct CanConstProp {
|
||||
can_const_prop: IndexVec<Local, bool>,
|
||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
||||
// false at the beginning, once set, there are not allowed to be any more assignments
|
||||
found_assignment: IndexVec<Local, bool>,
|
||||
}
|
||||
|
||||
impl CanConstProp {
|
||||
/// returns true if `local` can be propagated
|
||||
fn check(body: ReadOnlyBodyAndCache<'_, '_>) -> IndexVec<Local, bool> {
|
||||
fn check(body: ReadOnlyBodyAndCache<'_, '_>) -> IndexVec<Local, ConstPropMode> {
|
||||
let mut cpv = CanConstProp {
|
||||
can_const_prop: IndexVec::from_elem(true, &body.local_decls),
|
||||
can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
|
||||
found_assignment: IndexVec::from_elem(false, &body.local_decls),
|
||||
};
|
||||
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
|
||||
|
|
@ -728,10 +739,10 @@ impl CanConstProp {
|
|||
// FIXME(oli-obk): lint variables until they are used in a condition
|
||||
// FIXME(oli-obk): lint if return value is constant
|
||||
let local_kind = body.local_kind(local);
|
||||
*val = local_kind == LocalKind::Temp || local_kind == LocalKind::ReturnPointer;
|
||||
|
||||
if !*val {
|
||||
trace!("local {:?} can't be propagated because it's not a temporary", local);
|
||||
if local_kind == LocalKind::Arg || local_kind == LocalKind::Var {
|
||||
*val = ConstPropMode::OnlyPropagateInto;
|
||||
trace!("local {:?} can't be const propagated because it's not a temporary", local);
|
||||
}
|
||||
}
|
||||
cpv.visit_body(body);
|
||||
|
|
@ -753,7 +764,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
|
|||
// only occur in independent execution paths
|
||||
MutatingUse(MutatingUseContext::Store) => if self.found_assignment[local] {
|
||||
trace!("local {:?} can't be propagated because of multiple assignments", local);
|
||||
self.can_const_prop[local] = false;
|
||||
self.can_const_prop[local] = ConstPropMode::NoPropagation;
|
||||
} else {
|
||||
self.found_assignment[local] = true
|
||||
},
|
||||
|
|
@ -766,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
|
|||
NonUse(_) => {},
|
||||
_ => {
|
||||
trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
|
||||
self.can_const_prop[local] = false;
|
||||
self.can_const_prop[local] = ConstPropMode::NoPropagation;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -800,10 +811,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
|
||||
if let Some(local) = place.as_local() {
|
||||
let source = statement.source_info;
|
||||
let can_const_prop = self.can_const_prop[local];
|
||||
if let Some(()) = self.const_prop(rval, place_layout, source, place) {
|
||||
if self.can_const_prop[local] {
|
||||
trace!("propagated into {:?}", local);
|
||||
|
||||
if can_const_prop == ConstPropMode::FullConstProp ||
|
||||
can_const_prop == ConstPropMode::OnlyPropagateInto {
|
||||
if let Some(value) = self.get_const(local) {
|
||||
if self.should_const_prop(value) {
|
||||
trace!("replacing {:?} with {:?}", rval, value);
|
||||
|
|
@ -812,13 +823,18 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
value,
|
||||
statement.source_info,
|
||||
);
|
||||
|
||||
if can_const_prop == ConstPropMode::FullConstProp {
|
||||
trace!("propagated into {:?}", local);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trace!("can't propagate into {:?}", local);
|
||||
if local != RETURN_PLACE {
|
||||
self.remove_const(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.can_const_prop[local] != ConstPropMode::FullConstProp {
|
||||
trace!("can't propagate into {:?}", local);
|
||||
if local != RETURN_PLACE {
|
||||
self.remove_const(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -826,7 +842,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
} else {
|
||||
match statement.kind {
|
||||
StatementKind::StorageLive(local) |
|
||||
StatementKind::StorageDead(local) if self.can_const_prop[local] => {
|
||||
StatementKind::StorageDead(local) => {
|
||||
let frame = self.ecx.frame_mut();
|
||||
frame.locals[local].value =
|
||||
if let StatementKind::StorageLive(_) = statement.kind {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ struct InteriorVisitor<'a, 'tcx> {
|
|||
region_scope_tree: &'tcx region::ScopeTree,
|
||||
expr_count: usize,
|
||||
kind: hir::GeneratorKind,
|
||||
prev_unresolved_span: Option<Span>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
||||
|
|
@ -32,7 +33,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
|||
debug!("generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
|
||||
ty, scope, expr, source_span);
|
||||
|
||||
|
||||
let live_across_yield = scope.map(|s| {
|
||||
self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| {
|
||||
// If we are recording an expression that is the last yield
|
||||
|
|
@ -54,15 +54,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
|||
}).unwrap_or_else(|| Some(YieldData {
|
||||
span: DUMMY_SP,
|
||||
expr_and_pat_count: 0,
|
||||
source: match self.kind { // Guess based on the kind of the current generator.
|
||||
hir::GeneratorKind::Gen => hir::YieldSource::Yield,
|
||||
hir::GeneratorKind::Async(_) => hir::YieldSource::Await,
|
||||
},
|
||||
source: self.kind.into(),
|
||||
}));
|
||||
|
||||
if let Some(yield_data) = live_across_yield {
|
||||
let ty = self.fcx.resolve_vars_if_possible(&ty);
|
||||
|
||||
debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
|
||||
expr, scope, ty, self.expr_count, yield_data.span);
|
||||
|
||||
|
|
@ -74,9 +70,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
|||
yield_data.source);
|
||||
|
||||
// If unresolved type isn't a ty_var then unresolved_type_span is None
|
||||
let span = self.prev_unresolved_span.unwrap_or_else(
|
||||
|| unresolved_type_span.unwrap_or(source_span)
|
||||
);
|
||||
self.fcx.need_type_info_err_in_generator(
|
||||
self.kind,
|
||||
unresolved_type_span.unwrap_or(source_span),
|
||||
span,
|
||||
unresolved_type,
|
||||
)
|
||||
.span_note(yield_data.span, &*note)
|
||||
|
|
@ -94,6 +93,13 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
|||
} else {
|
||||
debug!("no type in expr = {:?}, count = {:?}, span = {:?}",
|
||||
expr, self.expr_count, expr.map(|e| e.span));
|
||||
let ty = self.fcx.resolve_vars_if_possible(&ty);
|
||||
if let Some((unresolved_type, unresolved_type_span))
|
||||
= self.fcx.unresolved_type_vars(&ty) {
|
||||
debug!("remained unresolved_type = {:?}, unresolved_type_span: {:?}",
|
||||
unresolved_type, unresolved_type_span);
|
||||
self.prev_unresolved_span = unresolved_type_span;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -112,6 +118,7 @@ pub fn resolve_interior<'a, 'tcx>(
|
|||
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
|
||||
expr_count: 0,
|
||||
kind,
|
||||
prev_unresolved_span: None,
|
||||
};
|
||||
intravisit::walk_body(&mut visitor, body);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ fn main() {
|
|||
// ...
|
||||
// _3 = (const 0i32, const 1i32, const 2i32);
|
||||
// _2 = const 1i32;
|
||||
// _1 = Add(move _2, const 0i32);
|
||||
// _1 = const 1i32;
|
||||
// ...
|
||||
// }
|
||||
// END rustc.main.ConstProp.after.mir
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ fn main() {
|
|||
// assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
|
||||
// }
|
||||
// bb1: {
|
||||
// _1 = _2[_3];
|
||||
// _1 = const 2u32;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
|
|
|||
149
src/test/mir-opt/const_prop/optimizes_into_variable.rs
Normal file
149
src/test/mir-opt/const_prop/optimizes_into_variable.rs
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
// compile-flags: -C overflow-checks=on
|
||||
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 2 + 2;
|
||||
let y = [0, 1, 2, 3, 4, 5][3];
|
||||
let z = (Point { x: 12, y: 42}).y;
|
||||
}
|
||||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.ConstProp.before.mir
|
||||
// let mut _0: ();
|
||||
// let _1: i32;
|
||||
// let mut _2: (i32, bool);
|
||||
// let mut _4: [i32; 6];
|
||||
// let _5: usize;
|
||||
// let mut _6: usize;
|
||||
// let mut _7: bool;
|
||||
// let mut _9: Point;
|
||||
// scope 1 {
|
||||
// debug x => _1;
|
||||
// let _3: i32;
|
||||
// scope 2 {
|
||||
// debug y => _3;
|
||||
// let _8: u32;
|
||||
// scope 3 {
|
||||
// debug z => _8;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// bb0: {
|
||||
// StorageLive(_1);
|
||||
// _2 = CheckedAdd(const 2i32, const 2i32);
|
||||
// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
|
||||
// }
|
||||
// bb1: {
|
||||
// _1 = move (_2.0: i32);
|
||||
// StorageLive(_3);
|
||||
// StorageLive(_4);
|
||||
// _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32];
|
||||
// StorageLive(_5);
|
||||
// _5 = const 3usize;
|
||||
// _6 = const 6usize;
|
||||
// _7 = Lt(_5, _6);
|
||||
// assert(move _7, "index out of bounds: the len is move _6 but the index is _5") -> bb2;
|
||||
// }
|
||||
// bb2: {
|
||||
// _3 = _4[_5];
|
||||
// StorageDead(_5);
|
||||
// StorageDead(_4);
|
||||
// StorageLive(_8);
|
||||
// StorageLive(_9);
|
||||
// _9 = Point { x: const 12u32, y: const 42u32 };
|
||||
// _8 = (_9.1: u32);
|
||||
// StorageDead(_9);
|
||||
// _0 = ();
|
||||
// StorageDead(_8);
|
||||
// StorageDead(_3);
|
||||
// StorageDead(_1);
|
||||
// return;
|
||||
// }
|
||||
// END rustc.main.ConstProp.before.mir
|
||||
// START rustc.main.ConstProp.after.mir
|
||||
// let mut _0: ();
|
||||
// let _1: i32;
|
||||
// let mut _2: (i32, bool);
|
||||
// let mut _4: [i32; 6];
|
||||
// let _5: usize;
|
||||
// let mut _6: usize;
|
||||
// let mut _7: bool;
|
||||
// let mut _9: Point;
|
||||
// scope 1 {
|
||||
// debug x => _1;
|
||||
// let _3: i32;
|
||||
// scope 2 {
|
||||
// debug y => _3;
|
||||
// let _8: u32;
|
||||
// scope 3 {
|
||||
// debug z => _8;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// bb0: {
|
||||
// StorageLive(_1);
|
||||
// _2 = (const 4i32, const false);
|
||||
// assert(!const false, "attempt to add with overflow") -> bb1;
|
||||
// }
|
||||
// bb1: {
|
||||
// _1 = const 4i32;
|
||||
// StorageLive(_3);
|
||||
// StorageLive(_4);
|
||||
// _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32];
|
||||
// StorageLive(_5);
|
||||
// _5 = const 3usize;
|
||||
// _6 = const 6usize;
|
||||
// _7 = const true;
|
||||
// assert(const true, "index out of bounds: the len is move _6 but the index is _5") -> bb2;
|
||||
// }
|
||||
// bb2: {
|
||||
// _3 = const 3i32;
|
||||
// StorageDead(_5);
|
||||
// StorageDead(_4);
|
||||
// StorageLive(_8);
|
||||
// StorageLive(_9);
|
||||
// _9 = Point { x: const 12u32, y: const 42u32 };
|
||||
// _8 = const 42u32;
|
||||
// StorageDead(_9);
|
||||
// _0 = ();
|
||||
// StorageDead(_8);
|
||||
// StorageDead(_3);
|
||||
// StorageDead(_1);
|
||||
// return;
|
||||
// }
|
||||
// END rustc.main.ConstProp.after.mir
|
||||
// START rustc.main.SimplifyLocals.after.mir
|
||||
// let mut _0: ();
|
||||
// let _1: i32;
|
||||
// let mut _3: [i32; 6];
|
||||
// scope 1 {
|
||||
// debug x => _1;
|
||||
// let _2: i32;
|
||||
// scope 2 {
|
||||
// debug y => _2;
|
||||
// let _4: u32;
|
||||
// scope 3 {
|
||||
// debug z => _4;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// bb0: {
|
||||
// StorageLive(_1);
|
||||
// _1 = const 4i32;
|
||||
// StorageLive(_2);
|
||||
// StorageLive(_3);
|
||||
// _3 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32];
|
||||
// _2 = const 3i32;
|
||||
// StorageDead(_3);
|
||||
// StorageLive(_4);
|
||||
// _4 = const 42u32;
|
||||
// StorageDead(_4);
|
||||
// StorageDead(_2);
|
||||
// StorageDead(_1);
|
||||
// return;
|
||||
// }
|
||||
// END rustc.main.SimplifyLocals.after.mir
|
||||
|
|
@ -25,7 +25,7 @@ fn main() {
|
|||
// _2 = const 2u8;
|
||||
// ...
|
||||
// _4 = const 2u8;
|
||||
// _1 = Add(move _2, move _4);
|
||||
// _1 = const 4u8;
|
||||
// ...
|
||||
// }
|
||||
// END rustc.main.ConstProp.after.mir
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ fn main() {
|
|||
// }
|
||||
// bb1: {
|
||||
// _2 = const 42u32;
|
||||
// _1 = Add(move _2, const 0u32);
|
||||
// _1 = const 42u32;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
|
|
|||
30
src/test/ui/borrowck/move-from-union-field-issue-66500.rs
Normal file
30
src/test/ui/borrowck/move-from-union-field-issue-66500.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Moving from a reference/raw pointer should be an error, even when they're
|
||||
// the field of a union.
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
union Pointers {
|
||||
a: &'static String,
|
||||
b: &'static mut String,
|
||||
c: *const String,
|
||||
d: *mut String,
|
||||
}
|
||||
|
||||
unsafe fn move_ref(u: Pointers) -> String {
|
||||
*u.a
|
||||
//~^ ERROR cannot move out of `*u.a`
|
||||
}
|
||||
unsafe fn move_ref_mut(u: Pointers) -> String {
|
||||
*u.b
|
||||
//~^ ERROR cannot move out of `*u.b`
|
||||
}
|
||||
unsafe fn move_ptr(u: Pointers) -> String {
|
||||
*u.c
|
||||
//~^ ERROR cannot move out of `*u.c`
|
||||
}
|
||||
unsafe fn move_ptr_mut(u: Pointers) -> String {
|
||||
*u.d
|
||||
//~^ ERROR cannot move out of `*u.d`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
error[E0507]: cannot move out of `*u.a` which is behind a shared reference
|
||||
--> $DIR/move-from-union-field-issue-66500.rs:14:5
|
||||
|
|
||||
LL | *u.a
|
||||
| ^^^^ move occurs because `*u.a` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0507]: cannot move out of `*u.b` which is behind a mutable reference
|
||||
--> $DIR/move-from-union-field-issue-66500.rs:18:5
|
||||
|
|
||||
LL | *u.b
|
||||
| ^^^^ move occurs because `*u.b` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0507]: cannot move out of `*u.c` which is behind a raw pointer
|
||||
--> $DIR/move-from-union-field-issue-66500.rs:22:5
|
||||
|
|
||||
LL | *u.c
|
||||
| ^^^^ move occurs because `*u.c` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0507]: cannot move out of `*u.d` which is behind a raw pointer
|
||||
--> $DIR/move-from-union-field-issue-66500.rs:26:5
|
||||
|
|
||||
LL | *u.d
|
||||
| ^^^^ move occurs because `*u.d` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0507`.
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::ptr_offset_from(self, origin)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| ptr_offset_from cannot compute offset of pointers into different allocations.
|
||||
| inside call to `std::ptr::<impl *const Struct>::offset_from` at $DIR/offset_from_ub.rs:19:27
|
||||
| inside call to `std::ptr::const_ptr::<impl *const Struct>::offset_from` at $DIR/offset_from_ub.rs:19:27
|
||||
|
|
||||
::: $DIR/offset_from_ub.rs:13:1
|
||||
|
|
||||
|
|
@ -21,13 +21,13 @@ LL | | };
|
|||
= note: `#[deny(const_err)]` on by default
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::ptr_offset_from(self, origin)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| a memory access tried to interpret some bytes as a pointer
|
||||
| inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:25:14
|
||||
| inside call to `std::ptr::const_ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:25:14
|
||||
|
|
||||
::: $DIR/offset_from_ub.rs:23:1
|
||||
|
|
||||
|
|
@ -38,13 +38,13 @@ LL | | };
|
|||
| |__-
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::ptr_offset_from(self, origin)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| exact_div: 1 cannot be divided by 2 without remainder
|
||||
| inside call to `std::ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:33:14
|
||||
| inside call to `std::ptr::const_ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:33:14
|
||||
|
|
||||
::: $DIR/offset_from_ub.rs:28:1
|
||||
|
|
||||
|
|
@ -58,13 +58,13 @@ LL | | };
|
|||
| |__-
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::ptr_offset_from(self, origin)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| invalid use of NULL pointer
|
||||
| inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:39:14
|
||||
| inside call to `std::ptr::const_ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:39:14
|
||||
|
|
||||
::: $DIR/offset_from_ub.rs:36:1
|
||||
|
|
||||
|
|
@ -76,13 +76,13 @@ LL | | };
|
|||
| |__-
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
|
||||
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::ptr_offset_from(self, origin)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| a memory access tried to interpret some bytes as a pointer
|
||||
| inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:46:14
|
||||
| inside call to `std::ptr::const_ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:46:14
|
||||
|
|
||||
::: $DIR/offset_from_ub.rs:42:1
|
||||
|
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue