Auto merge of #130379 - Zalathar:rollup-wpmcnql, r=Zalathar
Rollup of 6 pull requests Successful merges: - #130042 (properly handle EOF in BufReader::peek) - #130061 (Add `NonNull` convenience methods to `Box` and `Vec`) - #130202 (set `download-ci-llvm = true` by default on "library" and "tools" profiles) - #130214 (MaybeUninit::zeroed: mention that padding is not zeroed) - #130353 (Make some lint doctests compatible with `--stage=0`) - #130370 (unstable-book: `trait_upcasting` example should not have `#![allow(incomplete_features)]`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
bc486f31a6
16 changed files with 561 additions and 28 deletions
|
@ -24,7 +24,7 @@ declare_lint! {
|
||||||
/// ### Example
|
/// ### Example
|
||||||
///
|
///
|
||||||
/// ```rust,edition2021
|
/// ```rust,edition2021
|
||||||
/// #![feature(if_let_rescope)]
|
/// #![cfg_attr(not(bootstrap), feature(if_let_rescope))] // Simplify this in bootstrap bump.
|
||||||
/// #![warn(if_let_rescope)]
|
/// #![warn(if_let_rescope)]
|
||||||
/// #![allow(unused_variables)]
|
/// #![allow(unused_variables)]
|
||||||
///
|
///
|
||||||
|
|
|
@ -1870,6 +1870,7 @@ declare_lint! {
|
||||||
/// ### Example
|
/// ### Example
|
||||||
///
|
///
|
||||||
/// ```rust,compile_fail
|
/// ```rust,compile_fail
|
||||||
|
/// # #[cfg_attr(bootstrap)] compile_error!(); // Remove this in bootstrap bump.
|
||||||
/// #![deny(elided_named_lifetimes)]
|
/// #![deny(elided_named_lifetimes)]
|
||||||
/// struct Foo;
|
/// struct Foo;
|
||||||
/// impl Foo {
|
/// impl Foo {
|
||||||
|
|
|
@ -1060,6 +1060,59 @@ impl<T: ?Sized> Box<T> {
|
||||||
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
||||||
unsafe { Self::from_raw_in(raw, Global) }
|
unsafe { Self::from_raw_in(raw, Global) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a box from a `NonNull` pointer.
|
||||||
|
///
|
||||||
|
/// After calling this function, the `NonNull` pointer is owned by
|
||||||
|
/// the resulting `Box`. Specifically, the `Box` destructor will call
|
||||||
|
/// the destructor of `T` and free the allocated memory. For this
|
||||||
|
/// to be safe, the memory must have been allocated in accordance
|
||||||
|
/// with the [memory layout] used by `Box` .
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is unsafe because improper use may lead to
|
||||||
|
/// memory problems. For example, a double-free may occur if the
|
||||||
|
/// function is called twice on the same `NonNull` pointer.
|
||||||
|
///
|
||||||
|
/// The safety conditions are described in the [memory layout] section.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Recreate a `Box` which was previously converted to a `NonNull`
|
||||||
|
/// pointer using [`Box::into_non_null`]:
|
||||||
|
/// ```
|
||||||
|
/// #![feature(box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// let x = Box::new(5);
|
||||||
|
/// let non_null = Box::into_non_null(x);
|
||||||
|
/// let x = unsafe { Box::from_non_null(non_null) };
|
||||||
|
/// ```
|
||||||
|
/// Manually create a `Box` from scratch by using the global allocator:
|
||||||
|
/// ```
|
||||||
|
/// #![feature(box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::{alloc, Layout};
|
||||||
|
/// use std::ptr::NonNull;
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// let non_null = NonNull::new(alloc(Layout::new::<i32>()).cast::<i32>())
|
||||||
|
/// .expect("allocation failed");
|
||||||
|
/// // In general .write is required to avoid attempting to destruct
|
||||||
|
/// // the (uninitialized) previous contents of `non_null`.
|
||||||
|
/// non_null.write(5);
|
||||||
|
/// let x = Box::from_non_null(non_null);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [memory layout]: self#memory-layout
|
||||||
|
/// [`Layout`]: crate::Layout
|
||||||
|
#[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
|
||||||
|
#[inline]
|
||||||
|
#[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"]
|
||||||
|
pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
|
||||||
|
unsafe { Self::from_raw(ptr.as_ptr()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized, A: Allocator> Box<T, A> {
|
impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||||
|
@ -1117,6 +1170,61 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||||
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
|
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a box from a `NonNull` pointer in the given allocator.
|
||||||
|
///
|
||||||
|
/// After calling this function, the `NonNull` pointer is owned by
|
||||||
|
/// the resulting `Box`. Specifically, the `Box` destructor will call
|
||||||
|
/// the destructor of `T` and free the allocated memory. For this
|
||||||
|
/// to be safe, the memory must have been allocated in accordance
|
||||||
|
/// with the [memory layout] used by `Box` .
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is unsafe because improper use may lead to
|
||||||
|
/// memory problems. For example, a double-free may occur if the
|
||||||
|
/// function is called twice on the same raw pointer.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Recreate a `Box` which was previously converted to a `NonNull` pointer
|
||||||
|
/// using [`Box::into_non_null_with_allocator`]:
|
||||||
|
/// ```
|
||||||
|
/// #![feature(allocator_api, box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::System;
|
||||||
|
///
|
||||||
|
/// let x = Box::new_in(5, System);
|
||||||
|
/// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
|
||||||
|
/// let x = unsafe { Box::from_non_null_in(non_null, alloc) };
|
||||||
|
/// ```
|
||||||
|
/// Manually create a `Box` from scratch by using the system allocator:
|
||||||
|
/// ```
|
||||||
|
/// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::{Allocator, Layout, System};
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// let non_null = System.allocate(Layout::new::<i32>())?.cast::<i32>();
|
||||||
|
/// // In general .write is required to avoid attempting to destruct
|
||||||
|
/// // the (uninitialized) previous contents of `non_null`.
|
||||||
|
/// non_null.write(5);
|
||||||
|
/// let x = Box::from_non_null_in(non_null, System);
|
||||||
|
/// }
|
||||||
|
/// # Ok::<(), std::alloc::AllocError>(())
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [memory layout]: self#memory-layout
|
||||||
|
/// [`Layout`]: crate::Layout
|
||||||
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
|
// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
|
||||||
|
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
|
||||||
|
#[inline]
|
||||||
|
pub const unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
|
||||||
|
// SAFETY: guaranteed by the caller.
|
||||||
|
unsafe { Box::from_raw_in(raw.as_ptr(), alloc) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes the `Box`, returning a wrapped raw pointer.
|
/// Consumes the `Box`, returning a wrapped raw pointer.
|
||||||
///
|
///
|
||||||
/// The pointer will be properly aligned and non-null.
|
/// The pointer will be properly aligned and non-null.
|
||||||
|
@ -1172,6 +1280,66 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||||
unsafe { addr_of_mut!(*&mut *Self::into_raw_with_allocator(b).0) }
|
unsafe { addr_of_mut!(*&mut *Self::into_raw_with_allocator(b).0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes the `Box`, returning a wrapped `NonNull` pointer.
|
||||||
|
///
|
||||||
|
/// The pointer will be properly aligned.
|
||||||
|
///
|
||||||
|
/// After calling this function, the caller is responsible for the
|
||||||
|
/// memory previously managed by the `Box`. In particular, the
|
||||||
|
/// caller should properly destroy `T` and release the memory, taking
|
||||||
|
/// into account the [memory layout] used by `Box`. The easiest way to
|
||||||
|
/// do this is to convert the `NonNull` pointer back into a `Box` with the
|
||||||
|
/// [`Box::from_non_null`] function, allowing the `Box` destructor to
|
||||||
|
/// perform the cleanup.
|
||||||
|
///
|
||||||
|
/// Note: this is an associated function, which means that you have
|
||||||
|
/// to call it as `Box::into_non_null(b)` instead of `b.into_non_null()`.
|
||||||
|
/// This is so that there is no conflict with a method on the inner type.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// Converting the `NonNull` pointer back into a `Box` with [`Box::from_non_null`]
|
||||||
|
/// for automatic cleanup:
|
||||||
|
/// ```
|
||||||
|
/// #![feature(box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// let x = Box::new(String::from("Hello"));
|
||||||
|
/// let non_null = Box::into_non_null(x);
|
||||||
|
/// let x = unsafe { Box::from_non_null(non_null) };
|
||||||
|
/// ```
|
||||||
|
/// Manual cleanup by explicitly running the destructor and deallocating
|
||||||
|
/// the memory:
|
||||||
|
/// ```
|
||||||
|
/// #![feature(box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::{dealloc, Layout};
|
||||||
|
///
|
||||||
|
/// let x = Box::new(String::from("Hello"));
|
||||||
|
/// let non_null = Box::into_non_null(x);
|
||||||
|
/// unsafe {
|
||||||
|
/// non_null.drop_in_place();
|
||||||
|
/// dealloc(non_null.as_ptr().cast::<u8>(), Layout::new::<String>());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// Note: This is equivalent to the following:
|
||||||
|
/// ```
|
||||||
|
/// #![feature(box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// let x = Box::new(String::from("Hello"));
|
||||||
|
/// let non_null = Box::into_non_null(x);
|
||||||
|
/// unsafe {
|
||||||
|
/// drop(Box::from_non_null(non_null));
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [memory layout]: self#memory-layout
|
||||||
|
#[must_use = "losing the pointer will leak memory"]
|
||||||
|
#[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
|
||||||
|
#[inline]
|
||||||
|
pub fn into_non_null(b: Self) -> NonNull<T> {
|
||||||
|
// SAFETY: `Box` is guaranteed to be non-null.
|
||||||
|
unsafe { NonNull::new_unchecked(Self::into_raw(b)) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes the `Box`, returning a wrapped raw pointer and the allocator.
|
/// Consumes the `Box`, returning a wrapped raw pointer and the allocator.
|
||||||
///
|
///
|
||||||
/// The pointer will be properly aligned and non-null.
|
/// The pointer will be properly aligned and non-null.
|
||||||
|
@ -1233,6 +1401,61 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||||
(ptr, alloc)
|
(ptr, alloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes the `Box`, returning a wrapped `NonNull` pointer and the allocator.
|
||||||
|
///
|
||||||
|
/// The pointer will be properly aligned.
|
||||||
|
///
|
||||||
|
/// After calling this function, the caller is responsible for the
|
||||||
|
/// memory previously managed by the `Box`. In particular, the
|
||||||
|
/// caller should properly destroy `T` and release the memory, taking
|
||||||
|
/// into account the [memory layout] used by `Box`. The easiest way to
|
||||||
|
/// do this is to convert the `NonNull` pointer back into a `Box` with the
|
||||||
|
/// [`Box::from_non_null_in`] function, allowing the `Box` destructor to
|
||||||
|
/// perform the cleanup.
|
||||||
|
///
|
||||||
|
/// Note: this is an associated function, which means that you have
|
||||||
|
/// to call it as `Box::into_non_null_with_allocator(b)` instead of
|
||||||
|
/// `b.into_non_null_with_allocator()`. This is so that there is no
|
||||||
|
/// conflict with a method on the inner type.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// Converting the `NonNull` pointer back into a `Box` with
|
||||||
|
/// [`Box::from_non_null_in`] for automatic cleanup:
|
||||||
|
/// ```
|
||||||
|
/// #![feature(allocator_api, box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::System;
|
||||||
|
///
|
||||||
|
/// let x = Box::new_in(String::from("Hello"), System);
|
||||||
|
/// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
|
||||||
|
/// let x = unsafe { Box::from_non_null_in(non_null, alloc) };
|
||||||
|
/// ```
|
||||||
|
/// Manual cleanup by explicitly running the destructor and deallocating
|
||||||
|
/// the memory:
|
||||||
|
/// ```
|
||||||
|
/// #![feature(allocator_api, box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::{Allocator, Layout, System};
|
||||||
|
///
|
||||||
|
/// let x = Box::new_in(String::from("Hello"), System);
|
||||||
|
/// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
|
||||||
|
/// unsafe {
|
||||||
|
/// non_null.drop_in_place();
|
||||||
|
/// alloc.deallocate(non_null.cast::<u8>(), Layout::new::<String>());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [memory layout]: self#memory-layout
|
||||||
|
#[must_use = "losing the pointer will leak memory"]
|
||||||
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
|
// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
|
||||||
|
#[inline]
|
||||||
|
pub fn into_non_null_with_allocator(b: Self) -> (NonNull<T>, A) {
|
||||||
|
let (ptr, alloc) = Box::into_raw_with_allocator(b);
|
||||||
|
// SAFETY: `Box` is guaranteed to be non-null.
|
||||||
|
unsafe { (NonNull::new_unchecked(ptr), alloc) }
|
||||||
|
}
|
||||||
|
|
||||||
#[unstable(
|
#[unstable(
|
||||||
feature = "ptr_internals",
|
feature = "ptr_internals",
|
||||||
issue = "none",
|
issue = "none",
|
||||||
|
|
|
@ -328,7 +328,7 @@ where
|
||||||
|
|
||||||
mem::forget(dst_guard);
|
mem::forget(dst_guard);
|
||||||
|
|
||||||
let vec = unsafe { Vec::from_nonnull(dst_buf, len, dst_cap) };
|
let vec = unsafe { Vec::from_parts(dst_buf, len, dst_cap) };
|
||||||
|
|
||||||
vec
|
vec
|
||||||
}
|
}
|
||||||
|
|
|
@ -603,15 +603,116 @@ impl<T> Vec<T> {
|
||||||
unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) }
|
unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience method for hoisting the non-null precondition out of [`Vec::from_raw_parts`].
|
#[doc(alias = "from_non_null_parts")]
|
||||||
|
/// Creates a `Vec<T>` directly from a `NonNull` pointer, a length, and a capacity.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// See [`Vec::from_raw_parts`].
|
/// This is highly unsafe, due to the number of invariants that aren't
|
||||||
|
/// checked:
|
||||||
|
///
|
||||||
|
/// * `ptr` must have been allocated using the global allocator, such as via
|
||||||
|
/// the [`alloc::alloc`] function.
|
||||||
|
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
|
||||||
|
/// (`T` having a less strict alignment is not sufficient, the alignment really
|
||||||
|
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
||||||
|
/// allocated and deallocated with the same layout.)
|
||||||
|
/// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
|
||||||
|
/// to be the same size as the pointer was allocated with. (Because similar to
|
||||||
|
/// alignment, [`dealloc`] must be called with the same layout `size`.)
|
||||||
|
/// * `length` needs to be less than or equal to `capacity`.
|
||||||
|
/// * The first `length` values must be properly initialized values of type `T`.
|
||||||
|
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||||
|
/// * The allocated size in bytes must be no larger than `isize::MAX`.
|
||||||
|
/// See the safety documentation of [`pointer::offset`].
|
||||||
|
///
|
||||||
|
/// These requirements are always upheld by any `ptr` that has been allocated
|
||||||
|
/// via `Vec<T>`. Other allocation sources are allowed if the invariants are
|
||||||
|
/// upheld.
|
||||||
|
///
|
||||||
|
/// Violating these may cause problems like corrupting the allocator's
|
||||||
|
/// internal data structures. For example it is normally **not** safe
|
||||||
|
/// to build a `Vec<u8>` from a pointer to a C `char` array with length
|
||||||
|
/// `size_t`, doing so is only safe if the array was initially allocated by
|
||||||
|
/// a `Vec` or `String`.
|
||||||
|
/// It's also not safe to build one from a `Vec<u16>` and its length, because
|
||||||
|
/// the allocator cares about the alignment, and these two types have different
|
||||||
|
/// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
|
||||||
|
/// turning it into a `Vec<u8>` it'll be deallocated with alignment 1. To avoid
|
||||||
|
/// these issues, it is often preferable to do casting/transmuting using
|
||||||
|
/// [`NonNull::slice_from_raw_parts`] instead.
|
||||||
|
///
|
||||||
|
/// The ownership of `ptr` is effectively transferred to the
|
||||||
|
/// `Vec<T>` which may then deallocate, reallocate or change the
|
||||||
|
/// contents of memory pointed to by the pointer at will. Ensure
|
||||||
|
/// that nothing else uses the pointer after calling this
|
||||||
|
/// function.
|
||||||
|
///
|
||||||
|
/// [`String`]: crate::string::String
|
||||||
|
/// [`alloc::alloc`]: crate::alloc::alloc
|
||||||
|
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::ptr::NonNull;
|
||||||
|
/// use std::mem;
|
||||||
|
///
|
||||||
|
/// let v = vec![1, 2, 3];
|
||||||
|
///
|
||||||
|
// FIXME Update this when vec_into_raw_parts is stabilized
|
||||||
|
/// // Prevent running `v`'s destructor so we are in complete control
|
||||||
|
/// // of the allocation.
|
||||||
|
/// let mut v = mem::ManuallyDrop::new(v);
|
||||||
|
///
|
||||||
|
/// // Pull out the various important pieces of information about `v`
|
||||||
|
/// let p = unsafe { NonNull::new_unchecked(v.as_mut_ptr()) };
|
||||||
|
/// let len = v.len();
|
||||||
|
/// let cap = v.capacity();
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// // Overwrite memory with 4, 5, 6
|
||||||
|
/// for i in 0..len {
|
||||||
|
/// p.add(i).write(4 + i);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Put everything back together into a Vec
|
||||||
|
/// let rebuilt = Vec::from_parts(p, len, cap);
|
||||||
|
/// assert_eq!(rebuilt, [4, 5, 6]);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using memory that was allocated elsewhere:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #![feature(box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::{alloc, Layout};
|
||||||
|
/// use std::ptr::NonNull;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
||||||
|
///
|
||||||
|
/// let vec = unsafe {
|
||||||
|
/// let Some(mem) = NonNull::new(alloc(layout).cast::<u32>()) else {
|
||||||
|
/// return;
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// mem.write(1_000_000);
|
||||||
|
///
|
||||||
|
/// Vec::from_parts(mem, 1, 16)
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(vec, &[1_000_000]);
|
||||||
|
/// assert_eq!(vec.capacity(), 16);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling
|
#[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
|
||||||
pub(crate) unsafe fn from_nonnull(ptr: NonNull<T>, length: usize, capacity: usize) -> Self {
|
pub unsafe fn from_parts(ptr: NonNull<T>, length: usize, capacity: usize) -> Self {
|
||||||
unsafe { Self::from_nonnull_in(ptr, length, capacity, Global) }
|
unsafe { Self::from_parts_in(ptr, length, capacity, Global) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,19 +931,119 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||||
unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
|
unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience method for hoisting the non-null precondition out of [`Vec::from_raw_parts_in`].
|
#[doc(alias = "from_non_null_parts_in")]
|
||||||
|
/// Creates a `Vec<T, A>` directly from a `NonNull` pointer, a length, a capacity,
|
||||||
|
/// and an allocator.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// See [`Vec::from_raw_parts_in`].
|
/// This is highly unsafe, due to the number of invariants that aren't
|
||||||
|
/// checked:
|
||||||
|
///
|
||||||
|
/// * `ptr` must be [*currently allocated*] via the given allocator `alloc`.
|
||||||
|
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
|
||||||
|
/// (`T` having a less strict alignment is not sufficient, the alignment really
|
||||||
|
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
||||||
|
/// allocated and deallocated with the same layout.)
|
||||||
|
/// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
|
||||||
|
/// to be the same size as the pointer was allocated with. (Because similar to
|
||||||
|
/// alignment, [`dealloc`] must be called with the same layout `size`.)
|
||||||
|
/// * `length` needs to be less than or equal to `capacity`.
|
||||||
|
/// * The first `length` values must be properly initialized values of type `T`.
|
||||||
|
/// * `capacity` needs to [*fit*] the layout size that the pointer was allocated with.
|
||||||
|
/// * The allocated size in bytes must be no larger than `isize::MAX`.
|
||||||
|
/// See the safety documentation of [`pointer::offset`].
|
||||||
|
///
|
||||||
|
/// These requirements are always upheld by any `ptr` that has been allocated
|
||||||
|
/// via `Vec<T, A>`. Other allocation sources are allowed if the invariants are
|
||||||
|
/// upheld.
|
||||||
|
///
|
||||||
|
/// Violating these may cause problems like corrupting the allocator's
|
||||||
|
/// internal data structures. For example it is **not** safe
|
||||||
|
/// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
|
||||||
|
/// It's also not safe to build one from a `Vec<u16>` and its length, because
|
||||||
|
/// the allocator cares about the alignment, and these two types have different
|
||||||
|
/// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
|
||||||
|
/// turning it into a `Vec<u8>` it'll be deallocated with alignment 1.
|
||||||
|
///
|
||||||
|
/// The ownership of `ptr` is effectively transferred to the
|
||||||
|
/// `Vec<T>` which may then deallocate, reallocate or change the
|
||||||
|
/// contents of memory pointed to by the pointer at will. Ensure
|
||||||
|
/// that nothing else uses the pointer after calling this
|
||||||
|
/// function.
|
||||||
|
///
|
||||||
|
/// [`String`]: crate::string::String
|
||||||
|
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
||||||
|
/// [*currently allocated*]: crate::alloc::Allocator#currently-allocated-memory
|
||||||
|
/// [*fit*]: crate::alloc::Allocator#memory-fitting
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(allocator_api, box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::System;
|
||||||
|
///
|
||||||
|
/// use std::ptr::NonNull;
|
||||||
|
/// use std::mem;
|
||||||
|
///
|
||||||
|
/// let mut v = Vec::with_capacity_in(3, System);
|
||||||
|
/// v.push(1);
|
||||||
|
/// v.push(2);
|
||||||
|
/// v.push(3);
|
||||||
|
///
|
||||||
|
// FIXME Update this when vec_into_raw_parts is stabilized
|
||||||
|
/// // Prevent running `v`'s destructor so we are in complete control
|
||||||
|
/// // of the allocation.
|
||||||
|
/// let mut v = mem::ManuallyDrop::new(v);
|
||||||
|
///
|
||||||
|
/// // Pull out the various important pieces of information about `v`
|
||||||
|
/// let p = unsafe { NonNull::new_unchecked(v.as_mut_ptr()) };
|
||||||
|
/// let len = v.len();
|
||||||
|
/// let cap = v.capacity();
|
||||||
|
/// let alloc = v.allocator();
|
||||||
|
///
|
||||||
|
/// unsafe {
|
||||||
|
/// // Overwrite memory with 4, 5, 6
|
||||||
|
/// for i in 0..len {
|
||||||
|
/// p.add(i).write(4 + i);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Put everything back together into a Vec
|
||||||
|
/// let rebuilt = Vec::from_parts_in(p, len, cap, alloc.clone());
|
||||||
|
/// assert_eq!(rebuilt, [4, 5, 6]);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using memory that was allocated elsewhere:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #![feature(allocator_api, box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::{AllocError, Allocator, Global, Layout};
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
||||||
|
///
|
||||||
|
/// let vec = unsafe {
|
||||||
|
/// let mem = match Global.allocate(layout) {
|
||||||
|
/// Ok(mem) => mem.cast::<u32>(),
|
||||||
|
/// Err(AllocError) => return,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// mem.write(1_000_000);
|
||||||
|
///
|
||||||
|
/// Vec::from_parts_in(mem, 1, 16, Global)
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(vec, &[1_000_000]);
|
||||||
|
/// assert_eq!(vec.capacity(), 16);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling
|
#[unstable(feature = "allocator_api", reason = "new API", issue = "32838")]
|
||||||
pub(crate) unsafe fn from_nonnull_in(
|
// #[unstable(feature = "box_vec_non_null", issue = "130364")]
|
||||||
ptr: NonNull<T>,
|
pub unsafe fn from_parts_in(ptr: NonNull<T>, length: usize, capacity: usize, alloc: A) -> Self {
|
||||||
length: usize,
|
|
||||||
capacity: usize,
|
|
||||||
alloc: A,
|
|
||||||
) -> Self {
|
|
||||||
unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } }
|
unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -885,6 +1086,49 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||||
(me.as_mut_ptr(), me.len(), me.capacity())
|
(me.as_mut_ptr(), me.len(), me.capacity())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(alias = "into_non_null_parts")]
|
||||||
|
/// Decomposes a `Vec<T>` into its raw components: `(NonNull pointer, length, capacity)`.
|
||||||
|
///
|
||||||
|
/// Returns the `NonNull` pointer to the underlying data, the length of
|
||||||
|
/// the vector (in elements), and the allocated capacity of the
|
||||||
|
/// data (in elements). These are the same arguments in the same
|
||||||
|
/// order as the arguments to [`from_parts`].
|
||||||
|
///
|
||||||
|
/// After calling this function, the caller is responsible for the
|
||||||
|
/// memory previously managed by the `Vec`. The only way to do
|
||||||
|
/// this is to convert the `NonNull` pointer, length, and capacity back
|
||||||
|
/// into a `Vec` with the [`from_parts`] function, allowing
|
||||||
|
/// the destructor to perform the cleanup.
|
||||||
|
///
|
||||||
|
/// [`from_parts`]: Vec::from_parts
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(vec_into_raw_parts, box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// let v: Vec<i32> = vec![-1, 0, 1];
|
||||||
|
///
|
||||||
|
/// let (ptr, len, cap) = v.into_parts();
|
||||||
|
///
|
||||||
|
/// let rebuilt = unsafe {
|
||||||
|
/// // We can now make changes to the components, such as
|
||||||
|
/// // transmuting the raw pointer to a compatible type.
|
||||||
|
/// let ptr = ptr.cast::<u32>();
|
||||||
|
///
|
||||||
|
/// Vec::from_parts(ptr, len, cap)
|
||||||
|
/// };
|
||||||
|
/// assert_eq!(rebuilt, [4294967295, 0, 1]);
|
||||||
|
/// ```
|
||||||
|
#[must_use = "losing the pointer will leak memory"]
|
||||||
|
#[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
|
||||||
|
// #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
|
||||||
|
pub fn into_parts(self) -> (NonNull<T>, usize, usize) {
|
||||||
|
let (ptr, len, capacity) = self.into_raw_parts();
|
||||||
|
// SAFETY: A `Vec` always has a non-null pointer.
|
||||||
|
(unsafe { NonNull::new_unchecked(ptr) }, len, capacity)
|
||||||
|
}
|
||||||
|
|
||||||
/// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity, allocator)`.
|
/// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity, allocator)`.
|
||||||
///
|
///
|
||||||
/// Returns the raw pointer to the underlying data, the length of the vector (in elements),
|
/// Returns the raw pointer to the underlying data, the length of the vector (in elements),
|
||||||
|
@ -934,6 +1178,54 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||||
(ptr, len, capacity, alloc)
|
(ptr, len, capacity, alloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(alias = "into_non_null_parts_with_alloc")]
|
||||||
|
/// Decomposes a `Vec<T>` into its raw components: `(NonNull pointer, length, capacity, allocator)`.
|
||||||
|
///
|
||||||
|
/// Returns the `NonNull` pointer to the underlying data, the length of the vector (in elements),
|
||||||
|
/// the allocated capacity of the data (in elements), and the allocator. These are the same
|
||||||
|
/// arguments in the same order as the arguments to [`from_parts_in`].
|
||||||
|
///
|
||||||
|
/// After calling this function, the caller is responsible for the
|
||||||
|
/// memory previously managed by the `Vec`. The only way to do
|
||||||
|
/// this is to convert the `NonNull` pointer, length, and capacity back
|
||||||
|
/// into a `Vec` with the [`from_parts_in`] function, allowing
|
||||||
|
/// the destructor to perform the cleanup.
|
||||||
|
///
|
||||||
|
/// [`from_parts_in`]: Vec::from_parts_in
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(allocator_api, vec_into_raw_parts, box_vec_non_null)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::System;
|
||||||
|
///
|
||||||
|
/// let mut v: Vec<i32, System> = Vec::new_in(System);
|
||||||
|
/// v.push(-1);
|
||||||
|
/// v.push(0);
|
||||||
|
/// v.push(1);
|
||||||
|
///
|
||||||
|
/// let (ptr, len, cap, alloc) = v.into_parts_with_alloc();
|
||||||
|
///
|
||||||
|
/// let rebuilt = unsafe {
|
||||||
|
/// // We can now make changes to the components, such as
|
||||||
|
/// // transmuting the raw pointer to a compatible type.
|
||||||
|
/// let ptr = ptr.cast::<u32>();
|
||||||
|
///
|
||||||
|
/// Vec::from_parts_in(ptr, len, cap, alloc)
|
||||||
|
/// };
|
||||||
|
/// assert_eq!(rebuilt, [4294967295, 0, 1]);
|
||||||
|
/// ```
|
||||||
|
#[must_use = "losing the pointer will leak memory"]
|
||||||
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
|
// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
|
||||||
|
// #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
|
||||||
|
pub fn into_parts_with_alloc(self) -> (NonNull<T>, usize, usize, A) {
|
||||||
|
let (ptr, len, capacity, alloc) = self.into_raw_parts_with_alloc();
|
||||||
|
// SAFETY: A `Vec` always has a non-null pointer.
|
||||||
|
(unsafe { NonNull::new_unchecked(ptr) }, len, capacity, alloc)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the total number of elements the vector can hold without
|
/// Returns the total number of elements the vector can hold without
|
||||||
/// reallocating.
|
/// reallocating.
|
||||||
///
|
///
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
|
||||||
if has_advanced {
|
if has_advanced {
|
||||||
ptr::copy(it.ptr.as_ptr(), it.buf.as_ptr(), it.len());
|
ptr::copy(it.ptr.as_ptr(), it.buf.as_ptr(), it.len());
|
||||||
}
|
}
|
||||||
return Vec::from_nonnull(it.buf, it.len(), it.cap);
|
return Vec::from_parts(it.buf, it.len(), it.cap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -351,6 +351,9 @@ impl<T> MaybeUninit<T> {
|
||||||
/// but `MaybeUninit<&'static i32>::zeroed()` is not because references must not
|
/// but `MaybeUninit<&'static i32>::zeroed()` is not because references must not
|
||||||
/// be null.
|
/// be null.
|
||||||
///
|
///
|
||||||
|
/// Note that if `T` has padding bytes, those bytes are *not* preserved when the
|
||||||
|
/// `MaybeUninit<T>` value is returned from this function, so those bytes will *not* be zeroed.
|
||||||
|
///
|
||||||
/// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
|
/// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
|
||||||
/// It is your responsibility to make sure `T` gets dropped if it got initialized.
|
/// It is your responsibility to make sure `T` gets dropped if it got initialized.
|
||||||
///
|
///
|
||||||
|
|
|
@ -99,7 +99,10 @@ impl<R: Read> BufReader<R> {
|
||||||
impl<R: Read + ?Sized> BufReader<R> {
|
impl<R: Read + ?Sized> BufReader<R> {
|
||||||
/// Attempt to look ahead `n` bytes.
|
/// Attempt to look ahead `n` bytes.
|
||||||
///
|
///
|
||||||
/// `n` must be less than `capacity`.
|
/// `n` must be less than or equal to `capacity`.
|
||||||
|
///
|
||||||
|
/// the returned slice may be less than `n` bytes long if
|
||||||
|
/// end of file is reached.
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
///
|
///
|
||||||
|
@ -117,6 +120,7 @@ impl<R: Read + ?Sized> BufReader<R> {
|
||||||
/// let mut s = String::new();
|
/// let mut s = String::new();
|
||||||
/// rdr.read_to_string(&mut s).unwrap();
|
/// rdr.read_to_string(&mut s).unwrap();
|
||||||
/// assert_eq!(&s, "hello");
|
/// assert_eq!(&s, "hello");
|
||||||
|
/// assert_eq!(rdr.peek(1).unwrap().len(), 0);
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "bufreader_peek", issue = "128405")]
|
#[unstable(feature = "bufreader_peek", issue = "128405")]
|
||||||
pub fn peek(&mut self, n: usize) -> io::Result<&[u8]> {
|
pub fn peek(&mut self, n: usize) -> io::Result<&[u8]> {
|
||||||
|
@ -125,7 +129,11 @@ impl<R: Read + ?Sized> BufReader<R> {
|
||||||
if self.buf.pos() > 0 {
|
if self.buf.pos() > 0 {
|
||||||
self.buf.backshift();
|
self.buf.backshift();
|
||||||
}
|
}
|
||||||
self.buf.read_more(&mut self.inner)?;
|
let new = self.buf.read_more(&mut self.inner)?;
|
||||||
|
if new == 0 {
|
||||||
|
// end of file, no more bytes to read
|
||||||
|
return Ok(&self.buf.buffer()[..]);
|
||||||
|
}
|
||||||
debug_assert_eq!(self.buf.pos(), 0);
|
debug_assert_eq!(self.buf.pos(), 0);
|
||||||
}
|
}
|
||||||
Ok(&self.buf.buffer()[..n])
|
Ok(&self.buf.buffer()[..n])
|
||||||
|
|
|
@ -98,7 +98,7 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read more bytes into the buffer without discarding any of its contents
|
/// Read more bytes into the buffer without discarding any of its contents
|
||||||
pub fn read_more(&mut self, mut reader: impl Read) -> io::Result<()> {
|
pub fn read_more(&mut self, mut reader: impl Read) -> io::Result<usize> {
|
||||||
let mut buf = BorrowedBuf::from(&mut self.buf[self.pos..]);
|
let mut buf = BorrowedBuf::from(&mut self.buf[self.pos..]);
|
||||||
let old_init = self.initialized - self.pos;
|
let old_init = self.initialized - self.pos;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -107,7 +107,7 @@ impl Buffer {
|
||||||
reader.read_buf(buf.unfilled())?;
|
reader.read_buf(buf.unfilled())?;
|
||||||
self.filled += buf.len();
|
self.filled += buf.len();
|
||||||
self.initialized += buf.init_len() - old_init;
|
self.initialized += buf.init_len() - old_init;
|
||||||
Ok(())
|
Ok(buf.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove bytes that have already been read from the buffer.
|
/// Remove bytes that have already been read from the buffer.
|
||||||
|
|
|
@ -13,4 +13,5 @@ lto = "off"
|
||||||
|
|
||||||
[llvm]
|
[llvm]
|
||||||
# Will download LLVM from CI if available on your platform.
|
# Will download LLVM from CI if available on your platform.
|
||||||
download-ci-llvm = "if-unchanged"
|
# If you intend to modify `src/llvm-project`, use `"if-unchanged"` or `false` instead.
|
||||||
|
download-ci-llvm = true
|
||||||
|
|
|
@ -17,4 +17,5 @@ compiler-docs = true
|
||||||
|
|
||||||
[llvm]
|
[llvm]
|
||||||
# Will download LLVM from CI if available on your platform.
|
# Will download LLVM from CI if available on your platform.
|
||||||
download-ci-llvm = "if-unchanged"
|
# If you intend to modify `src/llvm-project`, use `"if-unchanged"` or `false` instead.
|
||||||
|
download-ci-llvm = true
|
||||||
|
|
|
@ -255,4 +255,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
||||||
severity: ChangeSeverity::Warning,
|
severity: ChangeSeverity::Warning,
|
||||||
summary: "`download-ci-llvm = true` now checks if CI llvm is available and has become the default for the compiler profile",
|
summary: "`download-ci-llvm = true` now checks if CI llvm is available and has become the default for the compiler profile",
|
||||||
},
|
},
|
||||||
|
ChangeInfo {
|
||||||
|
change_id: 130202,
|
||||||
|
severity: ChangeSeverity::Info,
|
||||||
|
summary: "'tools' and 'library' profiles switched `download-ci-llvm` option from `if-unchanged` to `true`.",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -12,7 +12,6 @@ so long as `Bar: Foo`.
|
||||||
|
|
||||||
```rust,edition2018
|
```rust,edition2018
|
||||||
#![feature(trait_upcasting)]
|
#![feature(trait_upcasting)]
|
||||||
#![allow(incomplete_features)]
|
|
||||||
|
|
||||||
trait Foo {}
|
trait Foo {}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ LL | wtf: Some(Box::new_zeroed()),
|
||||||
| ~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~
|
||||||
LL | wtf: Some(Box::new_in(_, _)),
|
LL | wtf: Some(Box::new_in(_, _)),
|
||||||
| ~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~
|
||||||
and 10 other candidates
|
and 12 other candidates
|
||||||
help: consider using the `Default` trait
|
help: consider using the `Default` trait
|
||||||
|
|
|
|
||||||
LL | wtf: Some(<Box as std::default::Default>::default()),
|
LL | wtf: Some(<Box as std::default::Default>::default()),
|
||||||
|
@ -89,7 +89,7 @@ LL | let _ = Box::new_zeroed();
|
||||||
| ~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~
|
||||||
LL | let _ = Box::new_in(_, _);
|
LL | let _ = Box::new_in(_, _);
|
||||||
| ~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~
|
||||||
and 10 other candidates
|
and 12 other candidates
|
||||||
help: consider using the `Default` trait
|
help: consider using the `Default` trait
|
||||||
|
|
|
|
||||||
LL | let _ = <Box as std::default::Default>::default();
|
LL | let _ = <Box as std::default::Default>::default();
|
||||||
|
|
|
@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<_, _>` consider using one of the foll
|
||||||
Vec::<T>::with_capacity
|
Vec::<T>::with_capacity
|
||||||
Vec::<T>::try_with_capacity
|
Vec::<T>::try_with_capacity
|
||||||
Vec::<T>::from_raw_parts
|
Vec::<T>::from_raw_parts
|
||||||
and 4 others
|
and 6 others
|
||||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||||
help: the function `contains` is implemented on `[_]`
|
help: the function `contains` is implemented on `[_]`
|
||||||
|
|
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<Q>` consider using one of the followi
|
||||||
Vec::<T>::with_capacity
|
Vec::<T>::with_capacity
|
||||||
Vec::<T>::try_with_capacity
|
Vec::<T>::try_with_capacity
|
||||||
Vec::<T>::from_raw_parts
|
Vec::<T>::from_raw_parts
|
||||||
and 4 others
|
and 6 others
|
||||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||||
help: there is an associated function `new` with a similar name
|
help: there is an associated function `new` with a similar name
|
||||||
|
|
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue