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
|
// N.B., if you change this, you'll probably want to change the corresponding
|
||||||
// type structure in middle/ty.rs as well.
|
// type structure in middle/ty.rs as well.
|
||||||
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||||
|
|
|
||||||
|
|
@ -1173,6 +1173,7 @@ fn resolve_local<'tcx>(
|
||||||
/// | VariantName(..., P&, ...)
|
/// | VariantName(..., P&, ...)
|
||||||
/// | [ ..., P&, ... ]
|
/// | [ ..., P&, ... ]
|
||||||
/// | ( ..., P&, ... )
|
/// | ( ..., P&, ... )
|
||||||
|
/// | ... "|" P& "|" ...
|
||||||
/// | box P&
|
/// | box P&
|
||||||
fn is_binding_pat(pat: &hir::Pat) -> bool {
|
fn is_binding_pat(pat: &hir::Pat) -> bool {
|
||||||
// Note that the code below looks for *explicit* refs only, that is, it won't
|
// 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))
|
pats3.iter().any(|p| is_binding_pat(&p))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatKind::Or(ref subpats) |
|
||||||
PatKind::TupleStruct(_, ref subpats, _) |
|
PatKind::TupleStruct(_, ref subpats, _) |
|
||||||
PatKind::Tuple(ref subpats, _) => {
|
PatKind::Tuple(ref subpats, _) => {
|
||||||
subpats.iter().any(|p| is_binding_pat(&p))
|
subpats.iter().any(|p| is_binding_pat(&p))
|
||||||
|
|
@ -1221,7 +1223,13 @@ fn resolve_local<'tcx>(
|
||||||
is_binding_pat(&subpat)
|
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.
|
//! Error reporting machinery for lifetime errors.
|
||||||
|
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
|
use rustc::infer::{
|
||||||
use rustc::infer::InferCtxt;
|
error_reporting::nice_region_error::NiceRegionError,
|
||||||
use rustc::infer::NLLRegionVariableOrigin;
|
InferCtxt, NLLRegionVariableOrigin,
|
||||||
use rustc::mir::{ConstraintCategory, Local, Location, Body};
|
};
|
||||||
|
use rustc::mir::{
|
||||||
|
ConstraintCategory, Local, Location, Body,
|
||||||
|
};
|
||||||
use rustc::ty::{self, RegionVid};
|
use rustc::ty::{self, RegionVid};
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_errors::DiagnosticBuilder;
|
use rustc_errors::DiagnosticBuilder;
|
||||||
|
|
@ -93,6 +96,32 @@ pub struct ErrorConstraintInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
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
|
/// Tries to find the best constraint to blame for the fact that
|
||||||
/// `R: from_region`, where `R` is some region that meets
|
/// `R: from_region`, where `R` is some region that meets
|
||||||
/// `target_test`. This works by following the constraint graph,
|
/// `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
|
/// 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
|
/// prove to be satisfied. If this is a closure, we will attempt to
|
||||||
/// "promote" this type-test into our `ClosureRegionRequirements` and
|
/// "promote" this type-test into our `ClosureRegionRequirements` and
|
||||||
|
|
@ -1164,7 +1138,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
/// include the CFG anyhow.
|
/// include the CFG anyhow.
|
||||||
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
|
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
|
||||||
/// a result `'y`.
|
/// 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));
|
debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
|
||||||
|
|
||||||
// Find the smallest universal region that contains all other
|
// 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={:?},\
|
debug!("check_polonius_subset_errors: subset_error longer_fr={:?},\
|
||||||
shorter_fr={:?}", longer_fr, shorter_fr);
|
shorter_fr={:?}", longer_fr, shorter_fr);
|
||||||
|
|
||||||
self.report_or_propagate_universal_region_error(
|
let propagated = self.try_propagate_universal_region_error(
|
||||||
*longer_fr,
|
*longer_fr,
|
||||||
*shorter_fr,
|
*shorter_fr,
|
||||||
infcx,
|
|
||||||
body,
|
body,
|
||||||
local_names,
|
|
||||||
upvars,
|
|
||||||
mir_def_id,
|
|
||||||
&mut propagated_outlives_requirements,
|
&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
|
// Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has
|
||||||
|
|
@ -1594,48 +1583,59 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.report_or_propagate_universal_region_error(
|
let propagated = self.try_propagate_universal_region_error(
|
||||||
longer_fr,
|
longer_fr,
|
||||||
shorter_fr,
|
shorter_fr,
|
||||||
infcx,
|
|
||||||
body,
|
body,
|
||||||
local_names,
|
|
||||||
upvars,
|
|
||||||
mir_def_id,
|
|
||||||
propagated_outlives_requirements,
|
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,
|
&self,
|
||||||
longer_fr: RegionVid,
|
longer_fr: RegionVid,
|
||||||
shorter_fr: RegionVid,
|
shorter_fr: RegionVid,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
|
||||||
body: &Body<'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>>>,
|
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||||
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
|
) -> bool {
|
||||||
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,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
|
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
|
||||||
// Shrink `longer_fr` until we find a non-local region (if we do).
|
// 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
|
// We'll call it `fr-` -- it's ever so slightly smaller than
|
||||||
// `longer_fr`.
|
// `longer_fr`.
|
||||||
|
|
||||||
if let Some(fr_minus) =
|
if let Some(fr_minus) =
|
||||||
self.universal_region_relations.non_local_lower_bound(longer_fr) {
|
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 =
|
let blame_span_category =
|
||||||
self.find_outlives_blame_span(body, longer_fr,
|
self.find_outlives_blame_span(body, longer_fr,
|
||||||
|
|
@ -1648,7 +1648,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
.universal_region_relations
|
.universal_region_relations
|
||||||
.non_local_upper_bounds(&shorter_fr);
|
.non_local_upper_bounds(&shorter_fr);
|
||||||
debug!(
|
debug!(
|
||||||
"report_or_propagate_universal_region_error: shorter_fr_plus={:?}",
|
"try_propagate_universal_region_error: shorter_fr_plus={:?}",
|
||||||
shorter_fr_plus
|
shorter_fr_plus
|
||||||
);
|
);
|
||||||
for &&fr in &shorter_fr_plus {
|
for &&fr in &shorter_fr_plus {
|
||||||
|
|
@ -1660,32 +1660,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
category: blame_span_category.0,
|
category: blame_span_category.0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return None;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are not in a context where we can't propagate errors, or we
|
false
|
||||||
// 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 check_bound_universal_region(
|
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() {
|
for (i, elem) in place.projection.iter().enumerate() {
|
||||||
let proj_base = &place.projection[..i];
|
let proj_base = &place.projection[..i];
|
||||||
let body = self.builder.body;
|
let body = self.builder.body;
|
||||||
|
|
@ -127,9 +134,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
InteriorOfTypeWithDestructor { container_ty: place_ty },
|
InteriorOfTypeWithDestructor { container_ty: place_ty },
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// move out of union - always move the entire union
|
|
||||||
ty::Adt(adt, _) if adt.is_union() => {
|
ty::Adt(adt, _) if adt.is_union() => {
|
||||||
return Err(MoveError::UnionMove { path: base });
|
union_path.get_or_insert(base);
|
||||||
}
|
}
|
||||||
ty::Slice(_) => {
|
ty::Slice(_) => {
|
||||||
return Err(MoveError::cannot_move_out_of(
|
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| {
|
if union_path.is_none() {
|
||||||
Place {
|
base = self.add_move_path(base, elem, |tcx| {
|
||||||
base: place.base.clone(),
|
Place {
|
||||||
projection: tcx.intern_place_elems(&place.projection[..i+1]),
|
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(
|
fn add_move_path(
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,7 @@ struct ConstPropagator<'mir, 'tcx> {
|
||||||
ecx: InterpCx<'mir, 'tcx, ConstPropMachine>,
|
ecx: InterpCx<'mir, 'tcx, ConstPropMachine>,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
source: MirSource<'tcx>,
|
source: MirSource<'tcx>,
|
||||||
can_const_prop: IndexVec<Local, bool>,
|
can_const_prop: IndexVec<Local, ConstPropMode>,
|
||||||
param_env: ParamEnv<'tcx>,
|
param_env: ParamEnv<'tcx>,
|
||||||
// FIXME(eddyb) avoid cloning these two fields more than once,
|
// FIXME(eddyb) avoid cloning these two fields more than once,
|
||||||
// by accessing them through `ecx` instead.
|
// 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 {
|
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
|
// false at the beginning, once set, there are not allowed to be any more assignments
|
||||||
found_assignment: IndexVec<Local, bool>,
|
found_assignment: IndexVec<Local, bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CanConstProp {
|
impl CanConstProp {
|
||||||
/// returns true if `local` can be propagated
|
/// 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 {
|
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),
|
found_assignment: IndexVec::from_elem(false, &body.local_decls),
|
||||||
};
|
};
|
||||||
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
|
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 variables until they are used in a condition
|
||||||
// FIXME(oli-obk): lint if return value is constant
|
// FIXME(oli-obk): lint if return value is constant
|
||||||
let local_kind = body.local_kind(local);
|
let local_kind = body.local_kind(local);
|
||||||
*val = local_kind == LocalKind::Temp || local_kind == LocalKind::ReturnPointer;
|
|
||||||
|
|
||||||
if !*val {
|
if local_kind == LocalKind::Arg || local_kind == LocalKind::Var {
|
||||||
trace!("local {:?} can't be propagated because it's not a temporary", local);
|
*val = ConstPropMode::OnlyPropagateInto;
|
||||||
|
trace!("local {:?} can't be const propagated because it's not a temporary", local);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cpv.visit_body(body);
|
cpv.visit_body(body);
|
||||||
|
|
@ -753,7 +764,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
|
||||||
// only occur in independent execution paths
|
// only occur in independent execution paths
|
||||||
MutatingUse(MutatingUseContext::Store) => if self.found_assignment[local] {
|
MutatingUse(MutatingUseContext::Store) => if self.found_assignment[local] {
|
||||||
trace!("local {:?} can't be propagated because of multiple assignments", 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 {
|
} else {
|
||||||
self.found_assignment[local] = true
|
self.found_assignment[local] = true
|
||||||
},
|
},
|
||||||
|
|
@ -766,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
|
||||||
NonUse(_) => {},
|
NonUse(_) => {},
|
||||||
_ => {
|
_ => {
|
||||||
trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
|
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 Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
|
||||||
if let Some(local) = place.as_local() {
|
if let Some(local) = place.as_local() {
|
||||||
let source = statement.source_info;
|
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 let Some(()) = self.const_prop(rval, place_layout, source, place) {
|
||||||
if self.can_const_prop[local] {
|
if can_const_prop == ConstPropMode::FullConstProp ||
|
||||||
trace!("propagated into {:?}", local);
|
can_const_prop == ConstPropMode::OnlyPropagateInto {
|
||||||
|
|
||||||
if let Some(value) = self.get_const(local) {
|
if let Some(value) = self.get_const(local) {
|
||||||
if self.should_const_prop(value) {
|
if self.should_const_prop(value) {
|
||||||
trace!("replacing {:?} with {:?}", rval, value);
|
trace!("replacing {:?} with {:?}", rval, value);
|
||||||
|
|
@ -812,13 +823,18 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
||||||
value,
|
value,
|
||||||
statement.source_info,
|
statement.source_info,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if can_const_prop == ConstPropMode::FullConstProp {
|
||||||
|
trace!("propagated into {:?}", local);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
trace!("can't propagate into {:?}", local);
|
}
|
||||||
if local != RETURN_PLACE {
|
if self.can_const_prop[local] != ConstPropMode::FullConstProp {
|
||||||
self.remove_const(local);
|
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 {
|
} else {
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::StorageLive(local) |
|
StatementKind::StorageLive(local) |
|
||||||
StatementKind::StorageDead(local) if self.can_const_prop[local] => {
|
StatementKind::StorageDead(local) => {
|
||||||
let frame = self.ecx.frame_mut();
|
let frame = self.ecx.frame_mut();
|
||||||
frame.locals[local].value =
|
frame.locals[local].value =
|
||||||
if let StatementKind::StorageLive(_) = statement.kind {
|
if let StatementKind::StorageLive(_) = statement.kind {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ struct InteriorVisitor<'a, 'tcx> {
|
||||||
region_scope_tree: &'tcx region::ScopeTree,
|
region_scope_tree: &'tcx region::ScopeTree,
|
||||||
expr_count: usize,
|
expr_count: usize,
|
||||||
kind: hir::GeneratorKind,
|
kind: hir::GeneratorKind,
|
||||||
|
prev_unresolved_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
||||||
|
|
@ -32,7 +33,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
||||||
debug!("generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
|
debug!("generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
|
||||||
ty, scope, expr, source_span);
|
ty, scope, expr, source_span);
|
||||||
|
|
||||||
|
|
||||||
let live_across_yield = scope.map(|s| {
|
let live_across_yield = scope.map(|s| {
|
||||||
self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| {
|
self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| {
|
||||||
// If we are recording an expression that is the last yield
|
// 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 {
|
}).unwrap_or_else(|| Some(YieldData {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
expr_and_pat_count: 0,
|
expr_and_pat_count: 0,
|
||||||
source: match self.kind { // Guess based on the kind of the current generator.
|
source: self.kind.into(),
|
||||||
hir::GeneratorKind::Gen => hir::YieldSource::Yield,
|
|
||||||
hir::GeneratorKind::Async(_) => hir::YieldSource::Await,
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if let Some(yield_data) = live_across_yield {
|
if let Some(yield_data) = live_across_yield {
|
||||||
let ty = self.fcx.resolve_vars_if_possible(&ty);
|
let ty = self.fcx.resolve_vars_if_possible(&ty);
|
||||||
|
|
||||||
debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
|
debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
|
||||||
expr, scope, ty, self.expr_count, yield_data.span);
|
expr, scope, ty, self.expr_count, yield_data.span);
|
||||||
|
|
||||||
|
|
@ -74,9 +70,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
||||||
yield_data.source);
|
yield_data.source);
|
||||||
|
|
||||||
// If unresolved type isn't a ty_var then unresolved_type_span is None
|
// 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.fcx.need_type_info_err_in_generator(
|
||||||
self.kind,
|
self.kind,
|
||||||
unresolved_type_span.unwrap_or(source_span),
|
span,
|
||||||
unresolved_type,
|
unresolved_type,
|
||||||
)
|
)
|
||||||
.span_note(yield_data.span, &*note)
|
.span_note(yield_data.span, &*note)
|
||||||
|
|
@ -94,6 +93,13 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
debug!("no type in expr = {:?}, count = {:?}, span = {:?}",
|
debug!("no type in expr = {:?}, count = {:?}, span = {:?}",
|
||||||
expr, self.expr_count, expr.map(|e| e.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),
|
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
|
||||||
expr_count: 0,
|
expr_count: 0,
|
||||||
kind,
|
kind,
|
||||||
|
prev_unresolved_span: None,
|
||||||
};
|
};
|
||||||
intravisit::walk_body(&mut visitor, body);
|
intravisit::walk_body(&mut visitor, body);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ fn main() {
|
||||||
// ...
|
// ...
|
||||||
// _3 = (const 0i32, const 1i32, const 2i32);
|
// _3 = (const 0i32, const 1i32, const 2i32);
|
||||||
// _2 = const 1i32;
|
// _2 = const 1i32;
|
||||||
// _1 = Add(move _2, const 0i32);
|
// _1 = const 1i32;
|
||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
// END rustc.main.ConstProp.after.mir
|
// 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;
|
// assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
|
||||||
// }
|
// }
|
||||||
// bb1: {
|
// bb1: {
|
||||||
// _1 = _2[_3];
|
// _1 = const 2u32;
|
||||||
// ...
|
// ...
|
||||||
// return;
|
// 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;
|
// _2 = const 2u8;
|
||||||
// ...
|
// ...
|
||||||
// _4 = const 2u8;
|
// _4 = const 2u8;
|
||||||
// _1 = Add(move _2, move _4);
|
// _1 = const 4u8;
|
||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
// END rustc.main.ConstProp.after.mir
|
// END rustc.main.ConstProp.after.mir
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ fn main() {
|
||||||
// }
|
// }
|
||||||
// bb1: {
|
// bb1: {
|
||||||
// _2 = const 42u32;
|
// _2 = const 42u32;
|
||||||
// _1 = Add(move _2, const 0u32);
|
// _1 = const 42u32;
|
||||||
// ...
|
// ...
|
||||||
// return;
|
// 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
|
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)
|
LL | intrinsics::ptr_offset_from(self, origin)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| ptr_offset_from cannot compute offset of pointers into different allocations.
|
| 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
|
::: $DIR/offset_from_ub.rs:13:1
|
||||||
|
|
|
|
||||||
|
|
@ -21,13 +21,13 @@ LL | | };
|
||||||
= note: `#[deny(const_err)]` on by default
|
= note: `#[deny(const_err)]` on by default
|
||||||
|
|
||||||
error: any use of this value will cause an error
|
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)
|
LL | intrinsics::ptr_offset_from(self, origin)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| a memory access tried to interpret some bytes as a pointer
|
| 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
|
::: $DIR/offset_from_ub.rs:23:1
|
||||||
|
|
|
|
||||||
|
|
@ -38,13 +38,13 @@ LL | | };
|
||||||
| |__-
|
| |__-
|
||||||
|
|
||||||
error: any use of this value will cause an error
|
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)
|
LL | intrinsics::ptr_offset_from(self, origin)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| exact_div: 1 cannot be divided by 2 without remainder
|
| 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
|
::: $DIR/offset_from_ub.rs:28:1
|
||||||
|
|
|
|
||||||
|
|
@ -58,13 +58,13 @@ LL | | };
|
||||||
| |__-
|
| |__-
|
||||||
|
|
||||||
error: any use of this value will cause an error
|
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)
|
LL | intrinsics::ptr_offset_from(self, origin)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| invalid use of NULL pointer
|
| 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
|
::: $DIR/offset_from_ub.rs:36:1
|
||||||
|
|
|
|
||||||
|
|
@ -76,13 +76,13 @@ LL | | };
|
||||||
| |__-
|
| |__-
|
||||||
|
|
||||||
error: any use of this value will cause an error
|
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)
|
LL | intrinsics::ptr_offset_from(self, origin)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| a memory access tried to interpret some bytes as a pointer
|
| 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
|
::: $DIR/offset_from_ub.rs:42:1
|
||||||
|
|
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue