Auto merge of #122256 - Nadrieril:rollup-rc232xh, r=Nadrieril
Rollup of 8 pull requests Successful merges: - #99153 (Add Read Impl for &Stdin) - #114655 (Make `impl<Fd: AsFd>` impl take `?Sized`) - #120504 (Vec::try_with_capacity) - #121280 (Implement MaybeUninit::fill{,_with,_from}) - #121403 (impl From<TryReserveError> for io::Error) - #121526 (on the fly type casting for `build.rustc` and `build.cargo`) - #121584 (bump itertools to 0.12) - #121711 (Implement junction_point) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
2d24fe591f
48 changed files with 775 additions and 200 deletions
36
Cargo.lock
36
Cargo.lock
|
@ -784,12 +784,6 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "core"
|
||||
version = "0.0.0"
|
||||
|
@ -1035,10 +1029,8 @@ version = "0.99.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
|
@ -3497,7 +3489,7 @@ dependencies = [
|
|||
name = "rustc_ast_passes"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr",
|
||||
|
@ -3517,7 +3509,7 @@ dependencies = [
|
|||
name = "rustc_ast_pretty"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"rustc_ast",
|
||||
"rustc_lexer",
|
||||
"rustc_span",
|
||||
|
@ -3558,7 +3550,7 @@ name = "rustc_borrowck"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"polonius-engine",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
@ -3611,7 +3603,7 @@ name = "rustc_codegen_llvm"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"libc",
|
||||
"measureme",
|
||||
"object",
|
||||
|
@ -3647,7 +3639,7 @@ dependencies = [
|
|||
"ar_archive_writer",
|
||||
"bitflags 2.4.2",
|
||||
"cc",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"object",
|
||||
|
@ -3929,7 +3921,7 @@ dependencies = [
|
|||
name = "rustc_hir_analysis"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
@ -3968,7 +3960,7 @@ dependencies = [
|
|||
name = "rustc_hir_typeck"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"rustc_ast",
|
||||
"rustc_ast_ir",
|
||||
"rustc_attr",
|
||||
|
@ -4216,7 +4208,6 @@ name = "rustc_middle"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"derive_more",
|
||||
"either",
|
||||
"field-offset",
|
||||
"gsgdt",
|
||||
|
@ -4254,7 +4245,7 @@ name = "rustc_mir_build"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
|
@ -4301,7 +4292,7 @@ name = "rustc_mir_transform"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
@ -4381,7 +4372,6 @@ dependencies = [
|
|||
name = "rustc_passes"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr",
|
||||
|
@ -4632,7 +4622,7 @@ name = "rustc_trait_selection"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"rustc_ast",
|
||||
"rustc_ast_ir",
|
||||
"rustc_attr",
|
||||
|
@ -4672,7 +4662,7 @@ dependencies = [
|
|||
name = "rustc_transmute"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"rustc_ast_ir",
|
||||
"rustc_data_structures",
|
||||
"rustc_hir",
|
||||
|
@ -4688,7 +4678,7 @@ dependencies = [
|
|||
name = "rustc_ty_utils"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"rustc_ast_ir",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
@ -4738,7 +4728,7 @@ dependencies = [
|
|||
"askama",
|
||||
"expect-test",
|
||||
"indexmap",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.1",
|
||||
"minifier",
|
||||
"once_cell",
|
||||
"regex",
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
either = "1.5.0"
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
polonius-engine = "0.13.0"
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
|
|
@ -9,7 +9,7 @@ test = false
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
libc = "0.2"
|
||||
measureme = "11"
|
||||
object = { version = "0.32.0", default-features = false, features = ["std", "read"] }
|
||||
|
|
|
@ -8,7 +8,7 @@ edition = "2021"
|
|||
ar_archive_writer = "0.1.5"
|
||||
bitflags = "2.4.1"
|
||||
cc = "1.0.90"
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
jobserver = "0.1.28"
|
||||
pathdiff = "0.2.0"
|
||||
regex = "1.4"
|
||||
|
|
|
@ -9,7 +9,7 @@ doctest = false
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -6,7 +6,6 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
derive_more = "0.99.17"
|
||||
either = "1.5.0"
|
||||
field-offset = "0.3.5"
|
||||
gsgdt = "0.1.2"
|
||||
|
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
either = "1"
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
rustc_apfloat = "0.2.0"
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
|
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
either = "1"
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -5,7 +5,6 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
itertools = "0.11"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
itertools = "0.11.0"
|
||||
itertools = "0.12"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -29,5 +29,5 @@ rustc = [
|
|||
|
||||
[dev-dependencies]
|
||||
# tidy-alphabetical-start
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
|
|
@ -559,6 +559,30 @@ impl<T> VecDeque<T> {
|
|||
pub fn with_capacity(capacity: usize) -> VecDeque<T> {
|
||||
Self::with_capacity_in(capacity, Global)
|
||||
}
|
||||
|
||||
/// Creates an empty deque with space for at least `capacity` elements.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the capacity exceeds `isize::MAX` _bytes_,
|
||||
/// or if the allocator reports allocation failure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(try_with_capacity)]
|
||||
/// # #[allow(unused)]
|
||||
/// # fn example() -> Result<(), std::collections::TryReserveError> {
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let deque: VecDeque<u32> = VecDeque::try_with_capacity(10)?;
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "try_with_capacity", issue = "91913")]
|
||||
pub fn try_with_capacity(capacity: usize) -> Result<VecDeque<T>, TryReserveError> {
|
||||
Ok(VecDeque { head: 0, len: 0, buf: RawVec::try_with_capacity_in(capacity, Global)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> VecDeque<T, A> {
|
||||
|
|
|
@ -163,6 +163,7 @@
|
|||
#![feature(trusted_len)]
|
||||
#![feature(trusted_random_access)]
|
||||
#![feature(try_trait_v2)]
|
||||
#![feature(try_with_capacity)]
|
||||
#![feature(tuple_trait)]
|
||||
#![feature(unchecked_math)]
|
||||
#![feature(unicode_internals)]
|
||||
|
|
|
@ -17,10 +17,19 @@ use crate::collections::TryReserveErrorKind::*;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// One central function responsible for reporting capacity overflows. This'll
|
||||
// ensure that the code generation related to these panics is minimal as there's
|
||||
// only one location which panics rather than a bunch throughout the module.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
fn capacity_overflow() -> ! {
|
||||
panic!("capacity overflow");
|
||||
}
|
||||
|
||||
enum AllocInit {
|
||||
/// The contents of the new memory are uninitialized.
|
||||
Uninitialized,
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
/// The new memory is guaranteed to be zeroed.
|
||||
Zeroed,
|
||||
}
|
||||
|
@ -93,6 +102,8 @@ impl<T> RawVec<T, Global> {
|
|||
/// zero-sized. Note that if `T` is zero-sized this means you will
|
||||
/// *not* get a `RawVec` with the requested capacity.
|
||||
///
|
||||
/// Non-fallible version of `try_with_capacity`
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the requested capacity exceeds `isize::MAX` bytes.
|
||||
|
@ -104,7 +115,7 @@ impl<T> RawVec<T, Global> {
|
|||
#[must_use]
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self::with_capacity_in(capacity, Global)
|
||||
handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global))
|
||||
}
|
||||
|
||||
/// Like `with_capacity`, but guarantees the buffer is zeroed.
|
||||
|
@ -142,7 +153,14 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
#[inline]
|
||||
pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
|
||||
Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
|
||||
handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc))
|
||||
}
|
||||
|
||||
/// Like `try_with_capacity`, but parameterized over the choice of
|
||||
/// allocator for the returned `RawVec`.
|
||||
#[inline]
|
||||
pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
|
||||
Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)
|
||||
}
|
||||
|
||||
/// Like `with_capacity_zeroed`, but parameterized over the choice
|
||||
|
@ -150,7 +168,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
#[cfg(not(no_global_oom_handling))]
|
||||
#[inline]
|
||||
pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
|
||||
Self::allocate_in(capacity, AllocInit::Zeroed, alloc)
|
||||
handle_reserve(Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc))
|
||||
}
|
||||
|
||||
/// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
|
||||
|
@ -179,35 +197,41 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
|
||||
fn try_allocate_in(
|
||||
capacity: usize,
|
||||
init: AllocInit,
|
||||
alloc: A,
|
||||
) -> Result<Self, TryReserveError> {
|
||||
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
|
||||
|
||||
if T::IS_ZST || capacity == 0 {
|
||||
Self::new_in(alloc)
|
||||
Ok(Self::new_in(alloc))
|
||||
} else {
|
||||
// We avoid `unwrap_or_else` here because it bloats the amount of
|
||||
// LLVM IR generated.
|
||||
let layout = match Layout::array::<T>(capacity) {
|
||||
Ok(layout) => layout,
|
||||
Err(_) => capacity_overflow(),
|
||||
Err(_) => return Err(CapacityOverflow.into()),
|
||||
};
|
||||
match alloc_guard(layout.size()) {
|
||||
Ok(_) => {}
|
||||
Err(_) => capacity_overflow(),
|
||||
|
||||
if let Err(err) = alloc_guard(layout.size()) {
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
let result = match init {
|
||||
AllocInit::Uninitialized => alloc.allocate(layout),
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
AllocInit::Zeroed => alloc.allocate_zeroed(layout),
|
||||
};
|
||||
let ptr = match result {
|
||||
Ok(ptr) => ptr,
|
||||
Err(_) => handle_alloc_error(layout),
|
||||
Err(_) => return Err(AllocError { layout, non_exhaustive: () }.into()),
|
||||
};
|
||||
|
||||
// Allocators currently return a `NonNull<[u8]>` whose length
|
||||
// matches the size requested. If that ever changes, the capacity
|
||||
// here should change to `ptr.len() / mem::size_of::<T>()`.
|
||||
Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc }
|
||||
Ok(Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,11 +561,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
|
|||
// Central function for reserve error handling.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[inline]
|
||||
fn handle_reserve(result: Result<(), TryReserveError>) {
|
||||
fn handle_reserve<T>(result: Result<T, TryReserveError>) -> T {
|
||||
match result.map_err(|e| e.kind()) {
|
||||
Ok(res) => res,
|
||||
Err(CapacityOverflow) => capacity_overflow(),
|
||||
Err(AllocError { layout, .. }) => handle_alloc_error(layout),
|
||||
Ok(()) => { /* yay */ }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,12 +585,3 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// One central function responsible for reporting capacity overflows. This'll
|
||||
// ensure that the code generation related to these panics is minimal as there's
|
||||
// only one location which panics rather than a bunch throughout the module.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
fn capacity_overflow() -> ! {
|
||||
panic!("capacity overflow");
|
||||
}
|
||||
|
|
|
@ -105,13 +105,14 @@ fn zst() {
|
|||
let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
|
||||
zst_sanity(&v);
|
||||
|
||||
let v: RawVec<ZST> = RawVec::allocate_in(0, AllocInit::Uninitialized, Global);
|
||||
let v: RawVec<ZST> = RawVec::try_allocate_in(0, AllocInit::Uninitialized, Global).unwrap();
|
||||
zst_sanity(&v);
|
||||
|
||||
let v: RawVec<ZST> = RawVec::allocate_in(100, AllocInit::Uninitialized, Global);
|
||||
let v: RawVec<ZST> = RawVec::try_allocate_in(100, AllocInit::Uninitialized, Global).unwrap();
|
||||
zst_sanity(&v);
|
||||
|
||||
let mut v: RawVec<ZST> = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global);
|
||||
let mut v: RawVec<ZST> =
|
||||
RawVec::try_allocate_in(usize::MAX, AllocInit::Uninitialized, Global).unwrap();
|
||||
zst_sanity(&v);
|
||||
|
||||
// Check all these operations work as expected with zero-sized elements.
|
||||
|
|
|
@ -492,6 +492,19 @@ impl String {
|
|||
String { vec: Vec::with_capacity(capacity) }
|
||||
}
|
||||
|
||||
/// Creates a new empty `String` with at least the specified capacity.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`Err`] if the capacity exceeds `isize::MAX` bytes,
|
||||
/// or if the memory allocator reports failure.
|
||||
///
|
||||
#[inline]
|
||||
#[unstable(feature = "try_with_capacity", issue = "91913")]
|
||||
pub fn try_with_capacity(capacity: usize) -> Result<String, TryReserveError> {
|
||||
Ok(String { vec: Vec::try_with_capacity(capacity)? })
|
||||
}
|
||||
|
||||
// HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
|
||||
// required for this method definition, is not available. Since we don't
|
||||
// require this method for testing purposes, I'll just stub it
|
||||
|
|
|
@ -481,6 +481,22 @@ impl<T> Vec<T> {
|
|||
Self::with_capacity_in(capacity, Global)
|
||||
}
|
||||
|
||||
/// Constructs a new, empty `Vec<T>` with at least the specified capacity.
|
||||
///
|
||||
/// The vector will be able to hold at least `capacity` elements without
|
||||
/// reallocating. This method is allowed to allocate for more elements than
|
||||
/// `capacity`. If `capacity` is 0, the vector will not allocate.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the capacity exceeds `isize::MAX` _bytes_,
|
||||
/// or if the allocator reports allocation failure.
|
||||
#[inline]
|
||||
#[unstable(feature = "try_with_capacity", issue = "91913")]
|
||||
pub fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
|
||||
Self::try_with_capacity_in(capacity, Global)
|
||||
}
|
||||
|
||||
/// Creates a `Vec<T>` directly from a pointer, a length, and a capacity.
|
||||
///
|
||||
/// # Safety
|
||||
|
@ -672,6 +688,24 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
|
||||
}
|
||||
|
||||
/// Constructs a new, empty `Vec<T, A>` with at least the specified capacity
|
||||
/// with the provided allocator.
|
||||
///
|
||||
/// The vector will be able to hold at least `capacity` elements without
|
||||
/// reallocating. This method is allowed to allocate for more elements than
|
||||
/// `capacity`. If `capacity` is 0, the vector will not allocate.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the capacity exceeds `isize::MAX` _bytes_,
|
||||
/// or if the allocator reports allocation failure.
|
||||
#[inline]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
// #[unstable(feature = "try_with_capacity", issue = "91913")]
|
||||
pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
|
||||
Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 })
|
||||
}
|
||||
|
||||
/// Creates a `Vec<T, A>` directly from a pointer, a length, a capacity,
|
||||
/// and an allocator.
|
||||
///
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#![feature(pattern)]
|
||||
#![feature(trusted_len)]
|
||||
#![feature(try_reserve_kind)]
|
||||
#![feature(try_with_capacity)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(binary_heap_into_iter_sorted)]
|
||||
|
|
|
@ -723,6 +723,17 @@ fn test_reserve_exact() {
|
|||
assert!(s.capacity() >= 33)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
|
||||
#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
|
||||
fn test_try_with_capacity() {
|
||||
let string = String::try_with_capacity(1000).unwrap();
|
||||
assert_eq!(0, string.len());
|
||||
assert!(string.capacity() >= 1000 && string.capacity() <= isize::MAX as usize);
|
||||
|
||||
assert!(String::try_with_capacity(usize::MAX).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
|
||||
#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
|
||||
|
|
|
@ -1694,6 +1694,18 @@ fn test_reserve_exact() {
|
|||
assert!(v.capacity() >= 33)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
|
||||
#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
|
||||
fn test_try_with_capacity() {
|
||||
let mut vec: Vec<u32> = Vec::try_with_capacity(5).unwrap();
|
||||
assert_eq!(0, vec.len());
|
||||
assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4);
|
||||
assert!(vec.spare_capacity_mut().len() >= 5);
|
||||
|
||||
assert!(Vec::<u16>::try_with_capacity(isize::MAX as usize + 1).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
|
||||
#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
|
||||
|
|
|
@ -1182,6 +1182,17 @@ fn test_reserve_exact_2() {
|
|||
assert!(v.capacity() >= 33)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
|
||||
#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
|
||||
fn test_try_with_capacity() {
|
||||
let vec: VecDeque<u32> = VecDeque::try_with_capacity(5).unwrap();
|
||||
assert_eq!(0, vec.len());
|
||||
assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4);
|
||||
|
||||
assert!(VecDeque::<u16>::try_with_capacity(isize::MAX as usize + 1).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
|
||||
#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
|
||||
|
|
|
@ -1125,22 +1125,6 @@ impl<T> MaybeUninit<T> {
|
|||
// unlike copy_from_slice this does not call clone_from_slice on the slice
|
||||
// this is because `MaybeUninit<T: Clone>` does not implement Clone.
|
||||
|
||||
struct Guard<'a, T> {
|
||||
slice: &'a mut [MaybeUninit<T>],
|
||||
initialized: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for Guard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
let initialized_part = &mut self.slice[..self.initialized];
|
||||
// SAFETY: this raw slice will contain only initialized objects
|
||||
// that's why, it is allowed to drop it.
|
||||
unsafe {
|
||||
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(this.len(), src.len(), "destination and source slices have different lengths");
|
||||
// NOTE: We need to explicitly slice them to the same length
|
||||
// for bounds checking to be elided, and the optimizer will
|
||||
|
@ -1162,6 +1146,151 @@ impl<T> MaybeUninit<T> {
|
|||
unsafe { MaybeUninit::slice_assume_init_mut(this) }
|
||||
}
|
||||
|
||||
/// Fills `this` with elements by cloning `value`, returning a mutable reference to the now
|
||||
/// initialized contents of `this`.
|
||||
/// Any previously initialized elements will not be dropped.
|
||||
///
|
||||
/// This is similar to [`slice::fill`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if any call to `Clone` panics.
|
||||
///
|
||||
/// If such a panic occurs, any elements previously initialized during this operation will be
|
||||
/// dropped.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Fill an uninit vec with 1.
|
||||
/// ```
|
||||
/// #![feature(maybe_uninit_fill)]
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut buf = vec![MaybeUninit::uninit(); 10];
|
||||
/// let initialized = MaybeUninit::fill(buf.as_mut_slice(), 1);
|
||||
/// assert_eq!(initialized, &mut [1; 10]);
|
||||
/// ```
|
||||
#[doc(alias = "memset")]
|
||||
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
|
||||
pub fn fill<'a>(this: &'a mut [MaybeUninit<T>], value: T) -> &'a mut [T]
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
SpecFill::spec_fill(this, value);
|
||||
// SAFETY: Valid elements have just been filled into `this` so it is initialized
|
||||
unsafe { MaybeUninit::slice_assume_init_mut(this) }
|
||||
}
|
||||
|
||||
/// Fills `this` with elements returned by calling a closure repeatedly.
|
||||
///
|
||||
/// This method uses a closure to create new values. If you'd rather `Clone` a given value, use
|
||||
/// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can
|
||||
/// pass [`Default::default`] as the argument.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if any call to the provided closure panics.
|
||||
///
|
||||
/// If such a panic occurs, any elements previously initialized during this operation will be
|
||||
/// dropped.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Fill an uninit vec with the default value.
|
||||
/// ```
|
||||
/// #![feature(maybe_uninit_fill)]
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut buf = vec![MaybeUninit::<i32>::uninit(); 10];
|
||||
/// let initialized = MaybeUninit::fill_with(buf.as_mut_slice(), Default::default);
|
||||
/// assert_eq!(initialized, &mut [0; 10]);
|
||||
/// ```
|
||||
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
|
||||
pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit<T>], mut f: F) -> &'a mut [T]
|
||||
where
|
||||
F: FnMut() -> T,
|
||||
{
|
||||
let mut guard = Guard { slice: this, initialized: 0 };
|
||||
|
||||
for element in guard.slice.iter_mut() {
|
||||
element.write(f());
|
||||
guard.initialized += 1;
|
||||
}
|
||||
|
||||
super::forget(guard);
|
||||
|
||||
// SAFETY: Valid elements have just been written into `this` so it is initialized
|
||||
unsafe { MaybeUninit::slice_assume_init_mut(this) }
|
||||
}
|
||||
|
||||
/// Fills `this` with elements yielded by an iterator until either all elements have been
|
||||
/// initialized or the iterator is empty.
|
||||
///
|
||||
/// Returns two slices. The first slice contains the initialized portion of the original slice.
|
||||
/// The second slice is the still-uninitialized remainder of the original slice.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if the iterator's `next` function panics.
|
||||
///
|
||||
/// If such a panic occurs, any elements previously initialized during this operation will be
|
||||
/// dropped.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Fill an uninit vec with a cycling iterator.
|
||||
/// ```
|
||||
/// #![feature(maybe_uninit_fill)]
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut buf = vec![MaybeUninit::uninit(); 5];
|
||||
///
|
||||
/// let iter = [1, 2, 3].into_iter().cycle();
|
||||
/// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter);
|
||||
///
|
||||
/// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]);
|
||||
/// assert_eq!(0, remainder.len());
|
||||
/// ```
|
||||
///
|
||||
/// Fill an uninit vec, but not completely.
|
||||
/// ```
|
||||
/// #![feature(maybe_uninit_fill)]
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut buf = vec![MaybeUninit::uninit(); 5];
|
||||
/// let iter = [1, 2];
|
||||
/// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter);
|
||||
///
|
||||
/// assert_eq!(initialized, &mut [1, 2]);
|
||||
/// assert_eq!(remainder.len(), 3);
|
||||
/// ```
|
||||
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
|
||||
pub fn fill_from<'a, I>(
|
||||
this: &'a mut [MaybeUninit<T>],
|
||||
it: I,
|
||||
) -> (&'a mut [T], &'a mut [MaybeUninit<T>])
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
let iter = it.into_iter();
|
||||
let mut guard = Guard { slice: this, initialized: 0 };
|
||||
|
||||
for (element, val) in guard.slice.iter_mut().zip(iter) {
|
||||
element.write(val);
|
||||
guard.initialized += 1;
|
||||
}
|
||||
|
||||
let initialized_len = guard.initialized;
|
||||
super::forget(guard);
|
||||
|
||||
// SAFETY: guard.initialized <= this.len()
|
||||
let (initted, remainder) = unsafe { this.split_at_mut_unchecked(initialized_len) };
|
||||
|
||||
// SAFETY: Valid elements have just been written into `init`, so that portion
|
||||
// of `this` is initialized.
|
||||
(unsafe { MaybeUninit::slice_assume_init_mut(initted) }, remainder)
|
||||
}
|
||||
|
||||
/// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
|
||||
///
|
||||
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
|
||||
|
@ -1315,3 +1444,44 @@ impl<T, const N: usize> [MaybeUninit<T>; N] {
|
|||
unsafe { intrinsics::transmute_unchecked(self) }
|
||||
}
|
||||
}
|
||||
|
||||
struct Guard<'a, T> {
|
||||
slice: &'a mut [MaybeUninit<T>],
|
||||
initialized: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for Guard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
let initialized_part = &mut self.slice[..self.initialized];
|
||||
// SAFETY: this raw sub-slice will contain only initialized objects.
|
||||
unsafe {
|
||||
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait SpecFill<T> {
|
||||
fn spec_fill(&mut self, value: T);
|
||||
}
|
||||
|
||||
impl<T: Clone> SpecFill<T> for [MaybeUninit<T>] {
|
||||
default fn spec_fill(&mut self, value: T) {
|
||||
let mut guard = Guard { slice: self, initialized: 0 };
|
||||
|
||||
if let Some((last, elems)) = guard.slice.split_last_mut() {
|
||||
for el in elems {
|
||||
el.write(value.clone());
|
||||
guard.initialized += 1;
|
||||
}
|
||||
|
||||
last.write(value);
|
||||
}
|
||||
super::forget(guard);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> SpecFill<T> for [MaybeUninit<T>] {
|
||||
fn spec_fill(&mut self, value: T) {
|
||||
self.fill(MaybeUninit::new(value));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#![feature(slice_from_ptr_range)]
|
||||
#![feature(slice_split_once)]
|
||||
#![feature(split_as_slice)]
|
||||
#![feature(maybe_uninit_fill)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(maybe_uninit_write_slice)]
|
||||
#![feature(maybe_uninit_uninit_array_transpose)]
|
||||
|
|
|
@ -308,17 +308,17 @@ fn uninit_write_slice_cloned_mid_panic() {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Bomb;
|
||||
|
||||
impl Drop for Bomb {
|
||||
fn drop(&mut self) {
|
||||
panic!("dropped a bomb! kaboom!")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_write_slice_cloned_no_drop() {
|
||||
#[derive(Clone)]
|
||||
struct Bomb;
|
||||
|
||||
impl Drop for Bomb {
|
||||
fn drop(&mut self) {
|
||||
panic!("dropped a bomb! kaboom")
|
||||
}
|
||||
}
|
||||
|
||||
let mut dst = [MaybeUninit::uninit()];
|
||||
let src = [Bomb];
|
||||
|
||||
|
@ -327,6 +327,211 @@ fn uninit_write_slice_cloned_no_drop() {
|
|||
forget(src);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_fill() {
|
||||
let mut dst = [MaybeUninit::new(255); 64];
|
||||
let expect = [0; 64];
|
||||
|
||||
assert_eq!(MaybeUninit::fill(&mut dst, 0), &expect);
|
||||
}
|
||||
|
||||
#[cfg(panic = "unwind")]
|
||||
struct CloneUntilPanic {
|
||||
limit: usize,
|
||||
rc: Rc<()>,
|
||||
}
|
||||
|
||||
#[cfg(panic = "unwind")]
|
||||
impl Clone for CloneUntilPanic {
|
||||
fn clone(&self) -> Self {
|
||||
if Rc::strong_count(&self.rc) >= self.limit {
|
||||
panic!("expected panic on clone");
|
||||
}
|
||||
Self { limit: self.limit, rc: self.rc.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(panic = "unwind")]
|
||||
fn uninit_fill_clone_panic_drop() {
|
||||
use std::panic;
|
||||
|
||||
let rc = Rc::new(());
|
||||
|
||||
let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
|
||||
|
||||
let src = CloneUntilPanic { limit: 3, rc: rc.clone() };
|
||||
let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
MaybeUninit::fill(&mut dst, src);
|
||||
}));
|
||||
|
||||
match err {
|
||||
Ok(_) => unreachable!(),
|
||||
Err(payload) => {
|
||||
payload
|
||||
.downcast::<&'static str>()
|
||||
.and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) })
|
||||
.unwrap_or_else(|p| panic::resume_unwind(p));
|
||||
assert_eq!(Rc::strong_count(&rc), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(panic = "unwind")]
|
||||
fn uninit_fill_clone_no_drop_clones() {
|
||||
let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
|
||||
|
||||
MaybeUninit::fill(&mut dst, Bomb);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_fill_with() {
|
||||
let mut dst = [MaybeUninit::new(255); 64];
|
||||
let expect = [0; 64];
|
||||
|
||||
assert_eq!(MaybeUninit::fill_with(&mut dst, || 0), &expect);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(panic = "unwind")]
|
||||
fn uninit_fill_with_mid_panic() {
|
||||
use std::panic;
|
||||
|
||||
let rc = Rc::new(());
|
||||
|
||||
let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
|
||||
|
||||
let src = CloneUntilPanic { limit: 3, rc: rc.clone() };
|
||||
let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
MaybeUninit::fill_with(&mut dst, || src.clone());
|
||||
}));
|
||||
|
||||
drop(src);
|
||||
|
||||
match err {
|
||||
Ok(_) => unreachable!(),
|
||||
Err(payload) => {
|
||||
payload
|
||||
.downcast::<&'static str>()
|
||||
.and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) })
|
||||
.unwrap_or_else(|p| panic::resume_unwind(p));
|
||||
|
||||
assert_eq!(Rc::strong_count(&rc), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(panic = "unwind")]
|
||||
fn uninit_fill_with_no_drop() {
|
||||
let mut dst = [MaybeUninit::uninit()];
|
||||
let src = Bomb;
|
||||
|
||||
MaybeUninit::fill_with(&mut dst, || src.clone());
|
||||
|
||||
forget(src);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_fill_from() {
|
||||
let mut dst = [MaybeUninit::new(255); 64];
|
||||
let src = [0; 64];
|
||||
|
||||
let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
|
||||
assert_eq!(initted, &src);
|
||||
assert_eq!(remainder.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_fill_from_partial() {
|
||||
let mut dst = [MaybeUninit::new(255); 64];
|
||||
let src = [0; 48];
|
||||
|
||||
let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
|
||||
assert_eq!(initted, &src);
|
||||
assert_eq!(remainder.len(), 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_over_fill() {
|
||||
let mut dst = [MaybeUninit::new(255); 64];
|
||||
let src = [0; 72];
|
||||
|
||||
let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
|
||||
assert_eq!(initted, &src[0..64]);
|
||||
assert_eq!(remainder.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_empty_fill() {
|
||||
let mut dst = [MaybeUninit::new(255); 64];
|
||||
let src = [0; 0];
|
||||
|
||||
let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
|
||||
assert_eq!(initted, &src[0..0]);
|
||||
assert_eq!(remainder.len(), 64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(panic = "unwind")]
|
||||
fn uninit_fill_from_mid_panic() {
|
||||
use std::panic;
|
||||
|
||||
struct IterUntilPanic {
|
||||
limit: usize,
|
||||
rc: Rc<()>,
|
||||
}
|
||||
|
||||
impl Iterator for IterUntilPanic {
|
||||
type Item = Rc<()>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if Rc::strong_count(&self.rc) >= self.limit {
|
||||
panic!("expected panic on next");
|
||||
}
|
||||
Some(self.rc.clone())
|
||||
}
|
||||
}
|
||||
|
||||
let rc = Rc::new(());
|
||||
|
||||
let mut dst = [
|
||||
MaybeUninit::uninit(),
|
||||
MaybeUninit::uninit(),
|
||||
MaybeUninit::uninit(),
|
||||
MaybeUninit::uninit(),
|
||||
];
|
||||
|
||||
let src = IterUntilPanic { limit: 3, rc: rc.clone() };
|
||||
|
||||
let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
MaybeUninit::fill_from(&mut dst, src);
|
||||
}));
|
||||
|
||||
match err {
|
||||
Ok(_) => unreachable!(),
|
||||
Err(payload) => {
|
||||
payload
|
||||
.downcast::<&'static str>()
|
||||
.and_then(|s| if *s == "expected panic on next" { Ok(s) } else { Err(s) })
|
||||
.unwrap_or_else(|p| panic::resume_unwind(p));
|
||||
|
||||
assert_eq!(Rc::strong_count(&rc), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(panic = "unwind")]
|
||||
fn uninit_fill_from_no_drop() {
|
||||
let mut dst = [MaybeUninit::uninit()];
|
||||
let src = [Bomb];
|
||||
|
||||
MaybeUninit::fill_from(&mut dst, src.iter());
|
||||
|
||||
forget(src);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_const_assume_init_read() {
|
||||
const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() };
|
||||
|
|
|
@ -261,7 +261,7 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
|||
let mut file = File::open(path)?;
|
||||
let size = file.metadata().map(|m| m.len() as usize).ok();
|
||||
let mut bytes = Vec::new();
|
||||
bytes.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
|
||||
bytes.try_reserve_exact(size.unwrap_or(0))?;
|
||||
io::default_read_to_end(&mut file, &mut bytes, size)?;
|
||||
Ok(bytes)
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
|
|||
let mut file = File::open(path)?;
|
||||
let size = file.metadata().map(|m| m.len() as usize).ok();
|
||||
let mut string = String::new();
|
||||
string.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
|
||||
string.try_reserve_exact(size.unwrap_or(0))?;
|
||||
io::default_read_to_string(&mut file, &mut string, size)?;
|
||||
Ok(string)
|
||||
}
|
||||
|
@ -777,14 +777,14 @@ impl Read for &File {
|
|||
// Reserves space in the buffer based on the file size when available.
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
let size = buffer_capacity_required(self);
|
||||
buf.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
|
||||
buf.try_reserve(size.unwrap_or(0))?;
|
||||
io::default_read_to_end(self, buf, size)
|
||||
}
|
||||
|
||||
// Reserves space in the buffer based on the file size when available.
|
||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
let size = buffer_capacity_required(self);
|
||||
buf.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
|
||||
buf.try_reserve(size.unwrap_or(0))?;
|
||||
io::default_read_to_string(self, buf, size)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,9 @@ use crate::os::unix::fs::symlink as symlink_dir;
|
|||
#[cfg(unix)]
|
||||
use crate::os::unix::fs::symlink as symlink_file;
|
||||
#[cfg(unix)]
|
||||
use crate::os::unix::fs::symlink as symlink_junction;
|
||||
use crate::os::unix::fs::symlink as junction_point;
|
||||
#[cfg(windows)]
|
||||
use crate::os::windows::fs::{symlink_dir, symlink_file, OpenOptionsExt};
|
||||
#[cfg(windows)]
|
||||
use crate::sys::fs::symlink_junction;
|
||||
use crate::os::windows::fs::{junction_point, symlink_dir, symlink_file, OpenOptionsExt};
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::sys::weak::weak;
|
||||
|
||||
|
@ -598,7 +596,7 @@ fn recursive_rmdir() {
|
|||
check!(fs::create_dir_all(&dtt));
|
||||
check!(fs::create_dir_all(&d2));
|
||||
check!(check!(File::create(&canary)).write(b"foo"));
|
||||
check!(symlink_junction(&d2, &dt.join("d2")));
|
||||
check!(junction_point(&d2, &dt.join("d2")));
|
||||
let _ = symlink_file(&canary, &d1.join("canary"));
|
||||
check!(fs::remove_dir_all(&d1));
|
||||
|
||||
|
@ -615,7 +613,7 @@ fn recursive_rmdir_of_symlink() {
|
|||
let canary = dir.join("do_not_delete");
|
||||
check!(fs::create_dir_all(&dir));
|
||||
check!(check!(File::create(&canary)).write(b"foo"));
|
||||
check!(symlink_junction(&dir, &link));
|
||||
check!(junction_point(&dir, &link));
|
||||
check!(fs::remove_dir_all(&link));
|
||||
|
||||
assert!(!link.is_dir());
|
||||
|
@ -1403,7 +1401,7 @@ fn create_dir_all_with_junctions() {
|
|||
|
||||
fs::create_dir(&target).unwrap();
|
||||
|
||||
check!(symlink_junction(&target, &junction));
|
||||
check!(junction_point(&target, &junction));
|
||||
check!(fs::create_dir_all(&b));
|
||||
// the junction itself is not a directory, but `is_dir()` on a Path
|
||||
// follows links
|
||||
|
|
|
@ -344,7 +344,7 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
|
|||
// delegate to the inner implementation.
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
let inner_buf = self.buffer();
|
||||
buf.try_reserve(inner_buf.len()).map_err(|_| io::ErrorKind::OutOfMemory)?;
|
||||
buf.try_reserve(inner_buf.len())?;
|
||||
buf.extend_from_slice(inner_buf);
|
||||
let nread = inner_buf.len();
|
||||
self.discard_buffer();
|
||||
|
|
|
@ -83,6 +83,18 @@ impl From<alloc::ffi::NulError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_error_from_try_reserve", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl From<alloc::collections::TryReserveError> for Error {
|
||||
/// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
|
||||
///
|
||||
/// `TryReserveError` won't be available as the error `source()`,
|
||||
/// but this may change in the future.
|
||||
fn from(_: alloc::collections::TryReserveError) -> Error {
|
||||
// ErrorData::Custom allocates, which isn't great for handling OOM errors.
|
||||
ErrorKind::OutOfMemory.into()
|
||||
}
|
||||
}
|
||||
|
||||
// Only derive debug in tests, to make sure it
|
||||
// doesn't accidentally get printed.
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
|
|
|
@ -304,7 +304,7 @@ impl Read for &[u8] {
|
|||
#[inline]
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
let len = self.len();
|
||||
buf.try_reserve(len).map_err(|_| ErrorKind::OutOfMemory)?;
|
||||
buf.try_reserve(len)?;
|
||||
buf.extend_from_slice(*self);
|
||||
*self = &self[len..];
|
||||
Ok(len)
|
||||
|
@ -452,7 +452,7 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
|
|||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
// The total len is known upfront so we can reserve it in a single call.
|
||||
let len = self.len();
|
||||
buf.try_reserve(len).map_err(|_| ErrorKind::OutOfMemory)?;
|
||||
buf.try_reserve(len)?;
|
||||
|
||||
let (front, back) = self.as_slices();
|
||||
buf.extend_from_slice(front);
|
||||
|
|
|
@ -465,7 +465,7 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
|
|||
|
||||
if buf.len() == buf.capacity() {
|
||||
// buf is full, need more space
|
||||
buf.try_reserve(PROBE_SIZE).map_err(|_| ErrorKind::OutOfMemory)?;
|
||||
buf.try_reserve(PROBE_SIZE)?;
|
||||
}
|
||||
|
||||
let mut spare = buf.spare_capacity_mut();
|
||||
|
@ -834,7 +834,7 @@ pub trait Read {
|
|||
/// if src_buf.is_empty() {
|
||||
/// break;
|
||||
/// }
|
||||
/// dest_vec.try_reserve(src_buf.len()).map_err(|_| io::ErrorKind::OutOfMemory)?;
|
||||
/// dest_vec.try_reserve(src_buf.len())?;
|
||||
/// dest_vec.extend_from_slice(src_buf);
|
||||
///
|
||||
/// // Any irreversible side effects should happen after `try_reserve` succeeds,
|
||||
|
|
|
@ -453,6 +453,32 @@ impl Read for Stdin {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "read_shared_stdin", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl Read for &Stdin {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.lock().read(buf)
|
||||
}
|
||||
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
self.lock().read_buf(buf)
|
||||
}
|
||||
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.lock().read_vectored(bufs)
|
||||
}
|
||||
#[inline]
|
||||
fn is_read_vectored(&self) -> bool {
|
||||
self.lock().is_read_vectored()
|
||||
}
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.lock().read_to_end(buf)
|
||||
}
|
||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
self.lock().read_to_string(buf)
|
||||
}
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
self.lock().read_exact(buf)
|
||||
}
|
||||
}
|
||||
|
||||
// only used by platform-dependent io::copy specializations, i.e. unused on some platforms
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
impl StdinLock<'_> {
|
||||
|
|
|
@ -692,3 +692,13 @@ fn read_buf_full_read() {
|
|||
|
||||
assert_eq!(BufReader::new(FullRead).fill_buf().unwrap().len(), DEFAULT_BUF_SIZE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// 64-bit only to be sure the allocator will fail fast on an impossible to satsify size
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
fn try_oom_error() {
|
||||
let mut v = Vec::<u8>::new();
|
||||
let reserve_err = v.try_reserve(isize::MAX as usize - 1).unwrap_err();
|
||||
let io_err = io::Error::from(reserve_err);
|
||||
assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind());
|
||||
}
|
||||
|
|
|
@ -244,7 +244,7 @@ pub trait AsFd {
|
|||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl<T: AsFd> AsFd for &T {
|
||||
impl<T: AsFd + ?Sized> AsFd for &T {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
T::as_fd(self)
|
||||
|
@ -252,7 +252,7 @@ impl<T: AsFd> AsFd for &T {
|
|||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl<T: AsFd> AsFd for &mut T {
|
||||
impl<T: AsFd + ?Sized> AsFd for &mut T {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
T::as_fd(self)
|
||||
|
@ -402,7 +402,7 @@ impl From<OwnedFd> for crate::net::UdpSocket {
|
|||
/// impl MyTrait for Box<UdpSocket> {}
|
||||
/// # }
|
||||
/// ```
|
||||
impl<T: AsFd> AsFd for crate::sync::Arc<T> {
|
||||
impl<T: AsFd + ?Sized> AsFd for crate::sync::Arc<T> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
(**self).as_fd()
|
||||
|
@ -410,7 +410,7 @@ impl<T: AsFd> AsFd for crate::sync::Arc<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "asfd_rc", since = "1.69.0")]
|
||||
impl<T: AsFd> AsFd for crate::rc::Rc<T> {
|
||||
impl<T: AsFd + ?Sized> AsFd for crate::rc::Rc<T> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
(**self).as_fd()
|
||||
|
@ -418,7 +418,7 @@ impl<T: AsFd> AsFd for crate::rc::Rc<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "asfd_ptrs", since = "1.64.0")]
|
||||
impl<T: AsFd> AsFd for Box<T> {
|
||||
impl<T: AsFd + ?Sized> AsFd for Box<T> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
(**self).as_fd()
|
||||
|
|
|
@ -620,3 +620,15 @@ pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io:
|
|||
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
|
||||
sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
|
||||
}
|
||||
|
||||
/// Create a junction point.
|
||||
///
|
||||
/// The `link` path will be a directory junction pointing to the original path.
|
||||
/// If `link` is a relative path then it will be made absolute prior to creating the junction point.
|
||||
/// The `original` path must be a directory or a link to a directory, otherwise the junction point will be broken.
|
||||
///
|
||||
/// If either path is not a local file path then this will fail.
|
||||
#[unstable(feature = "junction_point", issue = "121709")]
|
||||
pub fn junction_point<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
|
||||
sys::fs::junction_point(original.as_ref(), link.as_ref())
|
||||
}
|
||||
|
|
|
@ -422,7 +422,7 @@ pub trait AsHandle {
|
|||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl<T: AsHandle> AsHandle for &T {
|
||||
impl<T: AsHandle + ?Sized> AsHandle for &T {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
T::as_handle(self)
|
||||
|
@ -430,7 +430,7 @@ impl<T: AsHandle> AsHandle for &T {
|
|||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl<T: AsHandle> AsHandle for &mut T {
|
||||
impl<T: AsHandle + ?Sized> AsHandle for &mut T {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
T::as_handle(self)
|
||||
|
@ -450,7 +450,7 @@ impl<T: AsHandle> AsHandle for &mut T {
|
|||
/// impl MyTrait for Box<File> {}
|
||||
/// # }
|
||||
/// ```
|
||||
impl<T: AsHandle> AsHandle for crate::sync::Arc<T> {
|
||||
impl<T: AsHandle + ?Sized> AsHandle for crate::sync::Arc<T> {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
(**self).as_handle()
|
||||
|
@ -458,7 +458,7 @@ impl<T: AsHandle> AsHandle for crate::sync::Arc<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "as_windows_ptrs", since = "1.71.0")]
|
||||
impl<T: AsHandle> AsHandle for crate::rc::Rc<T> {
|
||||
impl<T: AsHandle + ?Sized> AsHandle for crate::rc::Rc<T> {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
(**self).as_handle()
|
||||
|
@ -466,7 +466,7 @@ impl<T: AsHandle> AsHandle for crate::rc::Rc<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "as_windows_ptrs", since = "1.71.0")]
|
||||
impl<T: AsHandle> AsHandle for Box<T> {
|
||||
impl<T: AsHandle + ?Sized> AsHandle for Box<T> {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
(**self).as_handle()
|
||||
|
|
|
@ -25,7 +25,6 @@ pub type UINT = c_uint;
|
|||
pub type WCHAR = u16;
|
||||
pub type USHORT = c_ushort;
|
||||
pub type SIZE_T = usize;
|
||||
pub type WORD = u16;
|
||||
pub type CHAR = c_char;
|
||||
pub type ULONG = c_ulong;
|
||||
|
||||
|
@ -145,16 +144,6 @@ pub struct MOUNT_POINT_REPARSE_BUFFER {
|
|||
pub PrintNameLength: c_ushort,
|
||||
pub PathBuffer: WCHAR,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
|
||||
pub ReparseTag: DWORD,
|
||||
pub ReparseDataLength: DWORD,
|
||||
pub Reserved: WORD,
|
||||
pub ReparseTargetLength: WORD,
|
||||
pub ReparseTargetMaximumLength: WORD,
|
||||
pub Reserved1: WORD,
|
||||
pub ReparseTarget: WCHAR,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SOCKADDR_STORAGE_LH {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use core::ptr::addr_of;
|
||||
|
||||
use crate::os::windows::prelude::*;
|
||||
|
||||
use crate::borrow::Cow;
|
||||
use crate::ffi::{c_void, OsString};
|
||||
use crate::ffi::{c_void, OsStr, OsString};
|
||||
use crate::fmt;
|
||||
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::mem::{self, MaybeUninit};
|
||||
|
@ -1446,75 +1448,79 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
|
|||
Ok(size as u64)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn symlink_junction<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||
original: P,
|
||||
junction: Q,
|
||||
) -> io::Result<()> {
|
||||
symlink_junction_inner(original.as_ref(), junction.as_ref())
|
||||
}
|
||||
|
||||
// Creating a directory junction on windows involves dealing with reparse
|
||||
// points and the DeviceIoControl function, and this code is a skeleton of
|
||||
// what can be found here:
|
||||
//
|
||||
// http://www.flexhex.com/docs/articles/hard-links.phtml
|
||||
#[allow(dead_code)]
|
||||
fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
|
||||
let d = DirBuilder::new();
|
||||
d.mkdir(junction)?;
|
||||
|
||||
pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> {
|
||||
// Create and open a new directory in one go.
|
||||
let mut opts = OpenOptions::new();
|
||||
opts.create_new(true);
|
||||
opts.write(true);
|
||||
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
|
||||
let f = File::open(junction, &opts)?;
|
||||
let h = f.as_inner().as_raw_handle();
|
||||
unsafe {
|
||||
let mut data =
|
||||
Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]);
|
||||
let data_ptr = data.0.as_mut_ptr();
|
||||
let data_end = data_ptr.add(c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize);
|
||||
let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
|
||||
// Zero the header to ensure it's fully initialized, including reserved parameters.
|
||||
*db = mem::zeroed();
|
||||
let reparse_target_slice = {
|
||||
let buf_start = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
|
||||
// Compute offset in bytes and then divide so that we round down
|
||||
// rather than hit any UB (admittedly this arithmetic should work
|
||||
// out so that this isn't necessary)
|
||||
let buf_len_bytes = usize::try_from(data_end.byte_offset_from(buf_start)).unwrap();
|
||||
let buf_len_wchars = buf_len_bytes / core::mem::size_of::<c::WCHAR>();
|
||||
core::slice::from_raw_parts_mut(buf_start, buf_len_wchars)
|
||||
};
|
||||
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_POSIX_SEMANTICS);
|
||||
opts.attributes(c::FILE_ATTRIBUTE_DIRECTORY);
|
||||
|
||||
// FIXME: this conversion is very hacky
|
||||
let iter = br"\??\"
|
||||
.iter()
|
||||
.map(|x| *x as u16)
|
||||
.chain(original.as_os_str().encode_wide())
|
||||
.chain(core::iter::once(0));
|
||||
let mut i = 0;
|
||||
for c in iter {
|
||||
if i >= reparse_target_slice.len() {
|
||||
return Err(crate::io::const_io_error!(
|
||||
crate::io::ErrorKind::InvalidFilename,
|
||||
"Input filename is too long"
|
||||
));
|
||||
}
|
||||
reparse_target_slice[i] = c;
|
||||
i += 1;
|
||||
let d = File::open(link, &opts)?;
|
||||
|
||||
// We need to get an absolute, NT-style path.
|
||||
let path_bytes = original.as_os_str().as_encoded_bytes();
|
||||
let abs_path: Vec<u16> = if path_bytes.starts_with(br"\\?\") || path_bytes.starts_with(br"\??\")
|
||||
{
|
||||
// It's already an absolute path, we just need to convert the prefix to `\??\`
|
||||
let bytes = unsafe { OsStr::from_encoded_bytes_unchecked(&path_bytes[4..]) };
|
||||
r"\??\".encode_utf16().chain(bytes.encode_wide()).collect()
|
||||
} else {
|
||||
// Get an absolute path and then convert the prefix to `\??\`
|
||||
let abs_path = crate::path::absolute(original)?.into_os_string().into_encoded_bytes();
|
||||
if abs_path.len() > 0 && abs_path[1..].starts_with(br":\") {
|
||||
let bytes = unsafe { OsStr::from_encoded_bytes_unchecked(&abs_path) };
|
||||
r"\??\".encode_utf16().chain(bytes.encode_wide()).collect()
|
||||
} else if abs_path.starts_with(br"\\.\") {
|
||||
let bytes = unsafe { OsStr::from_encoded_bytes_unchecked(&abs_path[4..]) };
|
||||
r"\??\".encode_utf16().chain(bytes.encode_wide()).collect()
|
||||
} else if abs_path.starts_with(br"\\") {
|
||||
let bytes = unsafe { OsStr::from_encoded_bytes_unchecked(&abs_path[2..]) };
|
||||
r"\??\UNC\".encode_utf16().chain(bytes.encode_wide()).collect()
|
||||
} else {
|
||||
return Err(io::const_io_error!(io::ErrorKind::InvalidInput, "path is not valid"));
|
||||
}
|
||||
(*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT;
|
||||
(*db).ReparseTargetMaximumLength = (i * 2) as c::WORD;
|
||||
(*db).ReparseTargetLength = ((i - 1) * 2) as c::WORD;
|
||||
(*db).ReparseDataLength = (*db).ReparseTargetLength as c::DWORD + 12;
|
||||
};
|
||||
// Defined inline so we don't have to mess about with variable length buffer.
|
||||
#[repr(C)]
|
||||
pub struct MountPointBuffer {
|
||||
ReparseTag: u32,
|
||||
ReparseDataLength: u16,
|
||||
Reserved: u16,
|
||||
SubstituteNameOffset: u16,
|
||||
SubstituteNameLength: u16,
|
||||
PrintNameOffset: u16,
|
||||
PrintNameLength: u16,
|
||||
PathBuffer: [MaybeUninit<u16>; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
|
||||
}
|
||||
let data_len = 12 + (abs_path.len() * 2);
|
||||
if data_len > u16::MAX as usize {
|
||||
return Err(io::const_io_error!(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"`original` path is too long"
|
||||
));
|
||||
}
|
||||
let data_len = data_len as u16;
|
||||
let mut header = MountPointBuffer {
|
||||
ReparseTag: c::IO_REPARSE_TAG_MOUNT_POINT,
|
||||
ReparseDataLength: data_len,
|
||||
Reserved: 0,
|
||||
SubstituteNameOffset: 0,
|
||||
SubstituteNameLength: (abs_path.len() * 2) as u16,
|
||||
PrintNameOffset: ((abs_path.len() + 1) * 2) as u16,
|
||||
PrintNameLength: 0,
|
||||
PathBuffer: [MaybeUninit::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize],
|
||||
};
|
||||
unsafe {
|
||||
let ptr = header.PathBuffer.as_mut_ptr();
|
||||
ptr.copy_from(abs_path.as_ptr().cast::<MaybeUninit<u16>>(), abs_path.len());
|
||||
|
||||
let mut ret = 0;
|
||||
cvt(c::DeviceIoControl(
|
||||
h as *mut _,
|
||||
d.as_raw_handle(),
|
||||
c::FSCTL_SET_REPARSE_POINT,
|
||||
data_ptr.cast(),
|
||||
(*db).ReparseDataLength + 8,
|
||||
addr_of!(header).cast::<c_void>(),
|
||||
data_len as u32 + 8,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
&mut ret,
|
||||
|
|
|
@ -812,8 +812,8 @@ define_config! {
|
|||
host: Option<Vec<String>> = "host",
|
||||
target: Option<Vec<String>> = "target",
|
||||
build_dir: Option<String> = "build-dir",
|
||||
cargo: Option<String> = "cargo",
|
||||
rustc: Option<String> = "rustc",
|
||||
cargo: Option<PathBuf> = "cargo",
|
||||
rustc: Option<PathBuf> = "rustc",
|
||||
rustfmt: Option<PathBuf> = "rustfmt",
|
||||
docs: Option<bool> = "docs",
|
||||
compiler_docs: Option<bool> = "compiler-docs",
|
||||
|
@ -1433,7 +1433,7 @@ impl Config {
|
|||
if !flags.skip_stage0_validation {
|
||||
config.check_stage0_version(&rustc, "rustc");
|
||||
}
|
||||
PathBuf::from(rustc)
|
||||
rustc
|
||||
} else {
|
||||
config.download_beta_toolchain();
|
||||
config.out.join(config.build.triple).join("stage0/bin/rustc")
|
||||
|
@ -1443,7 +1443,7 @@ impl Config {
|
|||
if !flags.skip_stage0_validation {
|
||||
config.check_stage0_version(&cargo, "cargo");
|
||||
}
|
||||
PathBuf::from(cargo)
|
||||
cargo
|
||||
} else {
|
||||
config.download_beta_toolchain();
|
||||
config.out.join(config.build.triple).join("stage0/bin/cargo")
|
||||
|
@ -2305,7 +2305,7 @@ impl Config {
|
|||
}
|
||||
|
||||
// check rustc/cargo version is same or lower with 1 apart from the building one
|
||||
pub fn check_stage0_version(&self, program_path: &str, component_name: &'static str) {
|
||||
pub fn check_stage0_version(&self, program_path: &Path, component_name: &'static str) {
|
||||
if self.dry_run() {
|
||||
return;
|
||||
}
|
||||
|
@ -2316,7 +2316,8 @@ impl Config {
|
|||
let stage0_name = stage0_output.next().unwrap();
|
||||
if stage0_name != component_name {
|
||||
fail(&format!(
|
||||
"Expected to find {component_name} at {program_path} but it claims to be {stage0_name}"
|
||||
"Expected to find {component_name} at {} but it claims to be {stage0_name}",
|
||||
program_path.display()
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
arrayvec = { version = "0.7", default-features = false }
|
||||
askama = { version = "0.12", default-features = false, features = ["config"] }
|
||||
itertools = "0.11"
|
||||
itertools = "0.12"
|
||||
indexmap = "2"
|
||||
minifier = "0.3.0"
|
||||
once_cell = "1.10.0"
|
||||
|
|
|
@ -209,7 +209,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"cc",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"convert_case", // dependency of derive_more
|
||||
"cpufeatures",
|
||||
"crc32fast",
|
||||
"crossbeam-channel",
|
||||
|
|
35
tests/codegen/vec-with-capacity.rs
Normal file
35
tests/codegen/vec-with-capacity.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
//@ compile-flags: -O
|
||||
//@ ignore-debug
|
||||
// (with debug assertions turned on, `assert_unchecked` generates a real assertion)
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(try_with_capacity)]
|
||||
|
||||
// CHECK-LABEL: @with_capacity_does_not_grow1
|
||||
#[no_mangle]
|
||||
pub fn with_capacity_does_not_grow1() -> Vec<u32> {
|
||||
let v = Vec::with_capacity(1234);
|
||||
// CHECK: call {{.*}}__rust_alloc(
|
||||
// CHECK-NOT: call {{.*}}__rust_realloc
|
||||
// CHECK-NOT: call {{.*}}capacity_overflow
|
||||
// CHECK-NOT: call {{.*}}finish_grow
|
||||
// CHECK-NOT: call {{.*}}reserve
|
||||
// CHECK-NOT: memcpy
|
||||
// CHECK-NOT: memset
|
||||
v
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @try_with_capacity_does_not_grow2
|
||||
#[no_mangle]
|
||||
pub fn try_with_capacity_does_not_grow2() -> Option<Vec<Vec<u8>>> {
|
||||
let v = Vec::try_with_capacity(1234).ok()?;
|
||||
// CHECK: call {{.*}}__rust_alloc(
|
||||
// CHECK-NOT: call {{.*}}__rust_realloc
|
||||
// CHECK-NOT: call {{.*}}capacity_overflow
|
||||
// CHECK-NOT: call {{.*}}finish_grow
|
||||
// CHECK-NOT: call {{.*}}handle_alloc_error
|
||||
// CHECK-NOT: call {{.*}}reserve
|
||||
// CHECK-NOT: memcpy
|
||||
// CHECK-NOT: memset
|
||||
Some(v)
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
thread 'main' panicked at library/alloc/src/raw_vec.rs:571:5:
|
||||
thread 'main' panicked at library/alloc/src/raw_vec.rs:26:5:
|
||||
capacity overflow
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
|
|
|
@ -7,9 +7,9 @@ LL | Vec::contains(&vec, &0);
|
|||
note: if you're trying to build a new `Vec<_, _>` consider using one of the following associated functions:
|
||||
Vec::<T>::new
|
||||
Vec::<T>::with_capacity
|
||||
Vec::<T>::try_with_capacity
|
||||
Vec::<T>::from_raw_parts
|
||||
Vec::<T, A>::new_in
|
||||
and 2 others
|
||||
and 4 others
|
||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||
help: the function `contains` is implemented on `[_]`
|
||||
|
|
||||
|
|
|
@ -7,9 +7,9 @@ LL | Vec::<Q>::mew()
|
|||
note: if you're trying to build a new `Vec<Q>` consider using one of the following associated functions:
|
||||
Vec::<T>::new
|
||||
Vec::<T>::with_capacity
|
||||
Vec::<T>::try_with_capacity
|
||||
Vec::<T>::from_raw_parts
|
||||
Vec::<T, A>::new_in
|
||||
and 2 others
|
||||
and 4 others
|
||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||
help: there is an associated function `new` with a similar name
|
||||
|
|
||||
|
|
Loading…
Add table
Reference in a new issue