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:
bors 2024-03-09 20:51:26 +00:00
commit 2d24fe591f
48 changed files with 775 additions and 200 deletions

View file

@ -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",

View file

@ -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" }

View file

@ -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" }

View file

@ -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" }

View file

@ -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"] }

View file

@ -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"

View file

@ -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" }

View file

@ -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" }

View file

@ -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"

View file

@ -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" }

View file

@ -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" }

View file

@ -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" }

View file

@ -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" }

View file

@ -29,5 +29,5 @@ rustc = [
[dev-dependencies]
# tidy-alphabetical-start
itertools = "0.11"
itertools = "0.12"
# tidy-alphabetical-end

View file

@ -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" }

View file

@ -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> {

View file

@ -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)]

View file

@ -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");
}

View file

@ -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.

View file

@ -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

View file

@ -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.
///

View file

@ -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)]

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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));
}
}

View file

@ -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)]

View file

@ -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() };

View file

@ -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)
}
}

View file

@ -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

View file

@ -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();

View file

@ -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))]

View file

@ -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);

View file

@ -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,

View file

@ -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<'_> {

View file

@ -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());
}

View file

@ -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()

View file

@ -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())
}

View file

@ -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()

View file

@ -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 {

View file

@ -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,

View file

@ -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()
));
}

View file

@ -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"

View file

@ -209,7 +209,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"cc",
"cfg-if",
"compiler_builtins",
"convert_case", // dependency of derive_more
"cpufeatures",
"crc32fast",
"crossbeam-channel",

View 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)
}

View file

@ -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

View file

@ -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 `[_]`
|

View file

@ -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
|