diff --git a/Cargo.lock b/Cargo.lock index 873182dde9102..9d5d0f2d403f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6213,9 +6213,9 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter-provider" -version = "44.0.2" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2211ca2d69a88055eefb06bad741dde3180c9d4020f7e42fea72caba83f9c10c" +checksum = "1b6c48003fe59c201c97a7786ff55feabe6b6f83b598aa9ff5bcc4f94d940bf3" [[package]] name = "wasip2" @@ -6282,9 +6282,9 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.25" +version = "0.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee72c06c556db23aca2d29e1e183d96efdffa7110b24915629a5091de600a894" +checksum = "51a12709376d4ce64f472699500db3b0e5902cc2bef16fb6ca3098bfdac032fa" dependencies = [ "anyhow", "clap", @@ -6293,12 +6293,12 @@ dependencies = [ "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.252.0", + "wasmparser 0.253.0", "wat", "windows-sys 0.61.2", "winsplit", - "wit-component 0.252.0", - "wit-parser 0.252.0", + "wit-component 0.253.0", + "wit-parser 0.253.0", ] [[package]] @@ -6330,12 +6330,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8185ae345fa5687c054626ff9a50e7089797a343d9904d1dc9820eb4c4d3196f" +checksum = "59972d6cd272259de647b7c1f1912e45e289c75ffd4be04e10695507cd7e1b59" dependencies = [ "leb128fmt", - "wasmparser 0.252.0", + "wasmparser 0.253.0", ] [[package]] @@ -6352,14 +6352,14 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b7e08e02a3cd55bf778009d4cd6faae50da011f293644daf78a531a32d6d142" +checksum = "b3f45816ef616806f48498bcd831377de578c4fa51db0c83ab8ceb78cc13523b" dependencies = [ "anyhow", "indexmap", - "wasm-encoder 0.252.0", - "wasmparser 0.252.0", + "wasm-encoder 0.253.0", + "wasmparser 0.253.0", ] [[package]] @@ -6396,9 +6396,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3eb099dcadcde5be9eef55e3a337128efd4e44b4c93122487e4d2e4e1c6627c" +checksum = "19db11f87d2486580e1e8b6f494c54df7e0566b87d0b599db843c24019667339" dependencies = [ "bitflags", "hashbrown 0.17.0", @@ -6409,22 +6409,22 @@ dependencies = [ [[package]] name = "wast" -version = "252.0.0" +version = "253.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942a3449d6a593fccc111a6241c8df52bda168af30e40bf9580d4394d7374c65" +checksum = "d3264542f8965c5d84fb1085d924bfba9a6314bb228eff13a2de14d7627664d0" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.2", - "wasm-encoder 0.252.0", + "wasm-encoder 0.253.0", ] [[package]] name = "wat" -version = "1.252.0" +version = "1.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c72a4ba7088f7bac94cf516e49882bdf97068904a563768cf249efc839ec42cb" +checksum = "4bfc5ce906144200c972ec617470aa35bd847472e170b26dde3e80541c674055" dependencies = [ "wast", ] @@ -6872,9 +6872,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76db0662b590f45d33d0e363fa13539a5a1eecd35d5a12fe208c335461c1053d" +checksum = "dbbd2500ac3488489ee8c6e59b79d7e47e6da5bfb019efd35d5dca57b78af624" dependencies = [ "anyhow", "bitflags", @@ -6883,10 +6883,10 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.252.0", - "wasm-metadata 0.252.0", - "wasmparser 0.252.0", - "wit-parser 0.252.0", + "wasm-encoder 0.253.0", + "wasm-metadata 0.253.0", + "wasmparser 0.253.0", + "wit-parser 0.253.0", ] [[package]] @@ -6909,9 +6909,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4266bea110371c620ccf3201c5023676046bc4556e5c7cfb5d500bda5ebc162d" +checksum = "4d997b8e5920fcbeec742b58e583325d6419a6aca617ae8075c406a61c65ba8a" dependencies = [ "anyhow", "hashbrown 0.17.0", @@ -6923,7 +6923,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-ident", - "wasmparser 0.252.0", + "wasmparser 0.253.0", ] [[package]] diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 4e979df471318..b9684eb52f3f4 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -877,12 +877,16 @@ pub fn codegen_crate< /// Returns whether a call from the current crate to the [`Instance`] would produce a call /// from `compiler_builtins` to a symbol the linker must resolve. /// -/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some +/// Such calls from `compiler_builtins` are effectively impossible for the linker to handle. Some /// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is -/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any +/// not guaranteed. So we use this function in codegen backends to ensure we do not generate any /// unlinkable calls. /// /// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker. +/// Note also that calls to foreign items that are actually exported by the local crate are also +/// okay. This situation arises because compiler-builtins calls functions in core that are +/// `#[inline]` wrappers for `extern "C"` declarations in core, which resolve to a symbol exported +/// by compiler-builtins. pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, @@ -895,11 +899,19 @@ pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>( } } + fn is_extern_call_to_local_crate<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool { + tcx.is_foreign_item(instance.def_id()) + && tcx.exported_non_generic_symbols(LOCAL_CRATE).iter().any(|(sym, _info)| { + sym.symbol_name_for_local_instance(tcx) == tcx.symbol_name(instance) + }) + } + let def_id = instance.def_id(); !def_id.is_local() && tcx.is_compiler_builtins(LOCAL_CRATE) && !is_llvm_intrinsic(tcx, def_id) && !tcx.should_codegen_locally(instance) + && !is_extern_call_to_local_crate(tcx, instance) } impl CrateInfo { diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 8b6a92071a7d7..5a4bf1a68dd5d 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -155,7 +155,6 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { match &stmt.kind { StatementKind::StorageDead(l) => state.kill(*l), - // If a place is assigned to in a statement, it needs storage for that statement. StatementKind::Assign((place, _)) => { state.gen_(place.local); } @@ -180,12 +179,35 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { fn apply_primary_statement_effect( &self, state: &mut Self::Domain, - _: &Statement<'tcx>, + stmt: &Statement<'tcx>, loc: Location, ) { // If we move from a place then it only stops needing storage *after* // that statement. self.check_for_move(state, loc); + + match &stmt.kind { + // If a place is assigned to in a statement, it needs storage after that statement. + // Even if the place was moved from in the rvalue (e.g. `x = x + 1` or `x = f(move x)`), + // the assignment restores a valid value into the place. + StatementKind::Assign((place, _)) => { + state.gen_(place.local); + } + StatementKind::SetDiscriminant { place, .. } => { + state.gen_(place.local); + } + + StatementKind::StorageDead(_) + | StatementKind::AscribeUserType(..) + | StatementKind::PlaceMention(..) + | StatementKind::Coverage(..) + | StatementKind::FakeRead(..) + | StatementKind::ConstEvalCounter + | StatementKind::Nop + | StatementKind::Intrinsic(..) + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::StorageLive(..) => {} + } } fn apply_early_terminator_effect( diff --git a/compiler/rustc_mir_transform/src/coroutine/mod.rs b/compiler/rustc_mir_transform/src/coroutine/mod.rs index 53283680c0966..a64d23b0b939f 100644 --- a/compiler/rustc_mir_transform/src/coroutine/mod.rs +++ b/compiler/rustc_mir_transform/src/coroutine/mod.rs @@ -79,6 +79,7 @@ use rustc_span::def_id::DefId; use tracing::{debug, instrument}; use crate::deref_separator::deref_finder; +use crate::patch::MirPatch; use crate::{abort_unwinding_calls, pass_manager as pm, simplify}; pub(super) struct StateTransform; @@ -199,6 +200,8 @@ struct TransformVisitor<'tcx> { old_yield_ty: Ty<'tcx>, old_ret_ty: Ty<'tcx>, + + patch: Option>, } impl<'tcx> TransformVisitor<'tcx> { @@ -408,11 +411,51 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { } #[tracing::instrument(level = "trace", skip(self), ret)] - fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, _location: Location) { + fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) { // Replace an Local in the remap with a coroutine struct access if let Some(&Some((ty, variant_index, idx))) = self.remap.get(place.local) { replace_base(place, self.make_field(variant_index, idx, ty), self.tcx); } + if let Some(new_projection) = self.process_projection(&place.projection, location) { + place.projection = self.tcx.mk_place_elems(&new_projection); + } + } + + fn process_projection_elem( + &mut self, + elem: PlaceElem<'tcx>, + location: Location, + ) -> Option> { + match elem { + PlaceElem::Index(local) => { + if let Some(&Some((ty, variant, idx))) = self.remap.get(local) { + // `PlaceElem::Index` only accepts a `Local`, not an arbitrary `Place`. + // If the local in indexing was saved across a yield point and remapped to a + // coroutine struct field, we cannot inline the struct field access into + // the index projection. + // For example, an local storing the counter to track which element to drop in + // an array is one such case. + // + // Instead, we inject an assignment before this location to restore the + // saved local from the coroutine struct (`local = copy $projection`), + // and leave the `PlaceElem::Index(local)` projection unchanged. + let field = self.make_field(variant, idx, ty); + self.patch.as_mut().unwrap().add_assign( + location, + Place::from(local), + Rvalue::Use(Operand::Copy(field), WithRetag::No), + ); + } + None + } + PlaceElem::Field(..) + | PlaceElem::OpaqueCast(..) + | PlaceElem::UnwrapUnsafeBinder(..) + | PlaceElem::Deref + | PlaceElem::ConstantIndex { .. } + | PlaceElem::Subslice { .. } + | PlaceElem::Downcast(..) => None, + } } #[tracing::instrument(level = "trace", skip(self, stmt), ret)] @@ -1096,6 +1139,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { new_ret_local, old_ret_ty, old_yield_ty, + patch: Some(MirPatch::new(body)), }; transform.visit_body(body); @@ -1116,6 +1160,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { Some(Statement::new(source_info, assign)) }), ); + transform.patch.take().unwrap().apply(body); // Remove the context argument within generator bodies. if matches!(coroutine_kind, CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) { diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 065cc128101ae..44211354f520e 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1430,6 +1430,7 @@ impl VecDeque { /// buf.truncate(1); /// assert_eq!(buf, [5]); /// ``` + #[doc(alias = "retain_front")] #[stable(feature = "deque_extras", since = "1.16.0")] pub fn truncate(&mut self, len: usize) { /// Runs the destructor for all items in the slice when it gets dropped (normally or @@ -1484,7 +1485,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// # #![feature(vec_deque_truncate_front)] /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -1493,11 +1493,12 @@ impl VecDeque { /// buf.push_front(15); /// assert_eq!(buf, [15, 10, 5]); /// assert_eq!(buf.as_slices(), (&[15, 10, 5][..], &[][..])); - /// buf.truncate_front(1); + /// buf.retain_back(1); /// assert_eq!(buf.as_slices(), (&[5][..], &[][..])); /// ``` - #[unstable(feature = "vec_deque_truncate_front", issue = "140667")] - pub fn truncate_front(&mut self, len: usize) { + #[doc(alias = "truncate_front")] + #[stable(feature = "vec_deque_truncate_front", since = "CURRENT_RUSTC_VERSION")] + pub fn retain_back(&mut self, len: usize) { /// Runs the destructor for all items in the slice when it gets dropped (normally or /// during unwinding). struct Dropper<'a, T>(&'a mut [T]); diff --git a/library/alloc/src/io/cursor.rs b/library/alloc/src/io/cursor.rs new file mode 100644 index 0000000000000..21f6b8b5b3ffd --- /dev/null +++ b/library/alloc/src/io/cursor.rs @@ -0,0 +1,260 @@ +use crate::alloc::Allocator; +use crate::boxed::Box; +use crate::io::{ + self, Cursor, ErrorKind, IoSlice, WriteThroughCursor, slice_write, slice_write_all, + slice_write_all_vectored, slice_write_vectored, +}; +use crate::vec::Vec; + +/// Reserves the required space, and pads the vec with 0s if necessary. +fn reserve_and_pad( + pos_mut: &mut u64, + vec: &mut Vec, + buf_len: usize, +) -> io::Result { + let pos: usize = (*pos_mut).try_into().map_err(|_| { + io::const_error!( + ErrorKind::InvalidInput, + "cursor position exceeds maximum possible vector length", + ) + })?; + + // For safety reasons, we don't want these numbers to overflow + // otherwise our allocation won't be enough + let desired_cap = pos.saturating_add(buf_len); + if desired_cap > vec.capacity() { + // We want our vec's total capacity + // to have room for (pos+buf_len) bytes. Reserve allocates + // based on additional elements from the length, so we need to + // reserve the difference + cfg_select! { + no_global_oom_handling => { + vec.try_reserve(desired_cap - vec.len())?; + } + _ => { + vec.reserve(desired_cap - vec.len()); + } + } + } + // Pad if pos is above the current len. + if pos > vec.len() { + let diff = pos - vec.len(); + // Unfortunately, `resize()` would suffice but the optimiser does not + // realise the `reserve` it does can be eliminated. So we do it manually + // to eliminate that extra branch + let spare = vec.spare_capacity_mut(); + debug_assert!(spare.len() >= diff); + // Safety: we have allocated enough capacity for this. + // And we are only writing, not reading + unsafe { + spare.get_unchecked_mut(..diff).fill(core::mem::MaybeUninit::new(0)); + vec.set_len(pos); + } + } + + Ok(pos) +} + +/// Writes the slice to the vec without allocating. +/// +/// # Safety +/// +/// `vec` must have `buf.len()` spare capacity. +unsafe fn vec_write_all_unchecked(pos: usize, vec: &mut Vec, buf: &[u8]) -> usize +where + A: Allocator, +{ + debug_assert!(vec.capacity() >= pos + buf.len()); + unsafe { vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()) }; + pos + buf.len() +} + +/// Resizing `write_all` implementation for [`Cursor`]. +/// +/// Cursor is allowed to have a pre-allocated and initialised +/// vector body, but with a position of 0. This means the [`Write`] +/// will overwrite the contents of the vec. +/// +/// This also allows for the vec body to be empty, but with a position of N. +/// This means that [`Write`] will pad the vec with 0 initially, +/// before writing anything from that point +/// +/// [`Write`]: crate::io::Write +fn vec_write_all(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result +where + A: Allocator, +{ + let buf_len = buf.len(); + let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?; + + // Write the buf then progress the vec forward if necessary + // Safety: we have ensured that the capacity is available + // and that all bytes get written up to pos + unsafe { + pos = vec_write_all_unchecked(pos, vec, buf); + if pos > vec.len() { + vec.set_len(pos); + } + }; + + // Bump us forward + *pos_mut += buf_len as u64; + Ok(buf_len) +} + +/// Resizing `write_all_vectored` implementation for [`Cursor`]. +/// +/// Cursor is allowed to have a pre-allocated and initialised +/// vector body, but with a position of 0. This means the [`Write`] +/// will overwrite the contents of the vec. +/// +/// This also allows for the vec body to be empty, but with a position of N. +/// This means that [`Write`] will pad the vec with 0 initially, +/// before writing anything from that point +/// +/// [`Write`]: crate::io::Write +fn vec_write_all_vectored( + pos_mut: &mut u64, + vec: &mut Vec, + bufs: &[IoSlice<'_>], +) -> io::Result +where + A: Allocator, +{ + // For safety reasons, we don't want this sum to overflow ever. + // If this saturates, the reserve should panic to avoid any unsound writing. + let buf_len = bufs.iter().fold(0usize, |a, b| a.saturating_add(b.len())); + let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?; + + // Write the buf then progress the vec forward if necessary + // Safety: we have ensured that the capacity is available + // and that all bytes get written up to the last pos + unsafe { + for buf in bufs { + pos = vec_write_all_unchecked(pos, vec, buf); + } + if pos > vec.len() { + vec.set_len(pos); + } + } + + // Bump us forward + *pos_mut += buf_len as u64; + Ok(buf_len) +} + +#[stable(feature = "cursor_mut_vec", since = "1.25.0")] +impl WriteThroughCursor for &mut Vec +where + A: Allocator, +{ + fn write(this: &mut Cursor, buf: &[u8]) -> io::Result { + let (pos, inner) = this.into_parts_mut(); + vec_write_all(pos, inner, buf) + } + + fn write_vectored(this: &mut Cursor, bufs: &[IoSlice<'_>]) -> io::Result { + let (pos, inner) = this.into_parts_mut(); + vec_write_all_vectored(pos, inner, bufs) + } + + #[inline] + fn is_write_vectored(_this: &Cursor) -> bool { + true + } + + fn write_all(this: &mut Cursor, buf: &[u8]) -> io::Result<()> { + let (pos, inner) = this.into_parts_mut(); + vec_write_all(pos, inner, buf)?; + Ok(()) + } + + fn write_all_vectored(this: &mut Cursor, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + let (pos, inner) = this.into_parts_mut(); + vec_write_all_vectored(pos, inner, bufs)?; + Ok(()) + } + + #[inline] + fn flush(_this: &mut Cursor) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl WriteThroughCursor for Vec +where + A: Allocator, +{ + fn write(this: &mut Cursor, buf: &[u8]) -> io::Result { + let (pos, inner) = this.into_parts_mut(); + vec_write_all(pos, inner, buf) + } + + fn write_vectored(this: &mut Cursor, bufs: &[IoSlice<'_>]) -> io::Result { + let (pos, inner) = this.into_parts_mut(); + vec_write_all_vectored(pos, inner, bufs) + } + + #[inline] + fn is_write_vectored(_this: &Cursor) -> bool { + true + } + + fn write_all(this: &mut Cursor, buf: &[u8]) -> io::Result<()> { + let (pos, inner) = this.into_parts_mut(); + vec_write_all(pos, inner, buf)?; + Ok(()) + } + + fn write_all_vectored(this: &mut Cursor, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + let (pos, inner) = this.into_parts_mut(); + vec_write_all_vectored(pos, inner, bufs)?; + Ok(()) + } + + #[inline] + fn flush(_this: &mut Cursor) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "cursor_box_slice", since = "1.5.0")] +impl WriteThroughCursor for Box<[u8], A> +where + A: Allocator, +{ + #[inline] + fn write(this: &mut Cursor, buf: &[u8]) -> io::Result { + let (pos, inner) = this.into_parts_mut(); + slice_write(pos, inner, buf) + } + + #[inline] + fn write_vectored(this: &mut Cursor, bufs: &[IoSlice<'_>]) -> io::Result { + let (pos, inner) = this.into_parts_mut(); + slice_write_vectored(pos, inner, bufs) + } + + #[inline] + fn is_write_vectored(_this: &Cursor) -> bool { + true + } + + #[inline] + fn write_all(this: &mut Cursor, buf: &[u8]) -> io::Result<()> { + let (pos, inner) = this.into_parts_mut(); + slice_write_all(pos, inner, buf) + } + + #[inline] + fn write_all_vectored(this: &mut Cursor, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + let (pos, inner) = this.into_parts_mut(); + slice_write_all_vectored(pos, inner, bufs) + } + + #[inline] + fn flush(_this: &mut Cursor) -> io::Result<()> { + Ok(()) + } +} diff --git a/library/alloc/src/io/impls.rs b/library/alloc/src/io/impls.rs index 732842bc65df7..1351d3e3ef3a1 100644 --- a/library/alloc/src/io/impls.rs +++ b/library/alloc/src/io/impls.rs @@ -1,7 +1,12 @@ +use crate::alloc::Allocator; use crate::boxed::Box; -use crate::io::{self, Seek, SeekFrom, SizeHint}; +#[cfg(not(no_global_oom_handling))] +use crate::collections::VecDeque; +use crate::fmt; +use crate::io::{self, IoSlice, Seek, SeekFrom, SizeHint, Write}; #[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] use crate::sync::Arc; +use crate::vec::Vec; // ============================================================================= // Forwarding implementations @@ -20,6 +25,43 @@ impl SizeHint for Box { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for Box { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + (**self).write(buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (**self).write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + (**self).is_write_vectored() + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + (**self).flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (**self).write_all(buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + (**self).write_all_vectored(bufs) + } + + #[inline] + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + (**self).write_fmt(fmt) + } +} #[stable(feature = "rust1", since = "1.0.0")] impl Seek for Box { #[inline] @@ -51,6 +93,148 @@ impl Seek for Box { // ============================================================================= // In-memory buffer implementations +/// Write is implemented for `Vec` by appending to the vector. +/// The vector will grow as needed. +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for Vec { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + ::write_all(self, buf)?; + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let len = bufs.iter().map(|b| b.len()).sum(); + cfg_select! { + no_global_oom_handling => { + self.try_reserve(len)?; + } + _ => { + self.reserve(len); + } + } + for buf in bufs { + ::write_all(self, buf)?; + } + Ok(len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + cfg_select! { + no_global_oom_handling => { + self.try_extend_from_slice_of_bytes(buf)?; + } + _ => { + self.extend_from_slice(buf); + } + } + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.write_vectored(bufs)?; + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +/// Write is implemented for `VecDeque` by appending to the `VecDeque`, growing it as needed. +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "vecdeque_read_write", since = "1.63.0")] +impl Write for VecDeque { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.extend(buf); + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let len = bufs.iter().map(|b| b.len()).sum(); + self.reserve(len); + for buf in bufs { + self.extend(&**buf); + } + Ok(len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend(buf); + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.write_vectored(bufs)?; + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] +#[stable(feature = "io_traits_arc", since = "1.73.0")] +impl Write for Arc +where + for<'a> &'a W: Write, + W: crate::io::IoHandle, +{ + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + (&**self).write(buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (&**self).write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + (&**self).is_write_vectored() + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + (&**self).flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (&**self).write_all(buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + (&**self).write_all_vectored(bufs) + } + + #[inline] + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + (&**self).write_fmt(fmt) + } +} #[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] #[stable(feature = "io_traits_arc", since = "1.73.0")] impl Seek for Arc diff --git a/library/alloc/src/io/mod.rs b/library/alloc/src/io/mod.rs index 44a1d1b71d164..ef7e95ed5bd7c 100644 --- a/library/alloc/src/io/mod.rs +++ b/library/alloc/src/io/mod.rs @@ -1,5 +1,6 @@ //! Traits, helpers, and type definitions for core I/O functionality. +mod cursor; mod error; mod impls; @@ -14,8 +15,12 @@ pub use core::io::{BorrowedBuf, BorrowedCursor}; #[unstable(feature = "alloc_io", issue = "154046")] pub use core::io::{ Chain, Cursor, Empty, Error, ErrorKind, IoSlice, IoSliceMut, Repeat, Result, Seek, SeekFrom, - Sink, Take, empty, repeat, sink, + Sink, Take, Write, empty, repeat, sink, }; #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] -pub use core::io::{IoHandle, OsFunctions, SizeHint, chain, stream_len_default, take}; +pub use core::io::{ + IoHandle, OsFunctions, SizeHint, WriteThroughCursor, chain, default_write_vectored, + slice_write, slice_write_all, slice_write_all_vectored, slice_write_vectored, + stream_len_default, take, +}; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 01b4e6f938616..9f82f5be82a68 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -96,6 +96,7 @@ #![feature(async_iterator)] #![feature(bstr)] #![feature(bstr_internals)] +#![feature(can_vector)] #![feature(case_ignorable)] #![feature(cast_maybe_uninit)] #![feature(cell_get_cloned)] @@ -180,6 +181,7 @@ #![feature(unicode_internals)] #![feature(unsize)] #![feature(unwrap_infallible)] +#![feature(write_all_vectored)] #![feature(wtf8_internals)] // tidy-alphabetical-end // diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index c3b86a635bd0f..a5d03ef76ade6 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2938,8 +2938,26 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[inline] unsafe fn append_elements(&mut self, other: *const [T]) { + self.reserve(other.len()); + unsafe { + self.append_elements_unreserved(other); + } + } + + /// Appends elements to `self` from other buffer, returning [`TryReserveError`] on OOM. + #[inline] + unsafe fn try_append_elements(&mut self, other: *const [T]) -> Result<(), TryReserveError> { + self.try_reserve(other.len())?; + unsafe { + self.append_elements_unreserved(other); + } + Ok(()) + } + + /// Appends elements to `self` from other buffer without reserving additional capacity. + #[inline] + unsafe fn append_elements_unreserved(&mut self, other: *const [T]) { let count = other.len(); - self.reserve(count); let len = self.len(); if count > 0 { unsafe { @@ -3609,6 +3627,22 @@ impl Vec { } } +impl Vec { + #[cfg_attr( + not(no_global_oom_handling), + expect( + dead_code, + reason = "currently only used in IO module when global OOM handling is disabled" + ) + )] + pub(crate) fn try_extend_from_slice_of_bytes( + &mut self, + other: &[u8], + ) -> Result<(), TryReserveError> { + unsafe { self.try_append_elements(other) } + } +} + impl Vec<[T; N], A> { /// Takes a `Vec<[T; N]>` and flattens it into a `Vec`. /// diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index f89b974cd290c..2ede9730d12dc 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -36,7 +36,6 @@ #![feature(str_as_str)] #![feature(strict_provenance_lints)] #![feature(string_replace_in_place)] -#![feature(vec_deque_truncate_front)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] #![feature(vec_peek_mut)] diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 91843dfd00585..2e75b7b07e63f 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -1635,7 +1635,7 @@ fn truncate_leak() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn truncate_front_leak() { +fn retain_back_leak() { struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } ); let mut q = VecDeque::new(); @@ -1648,7 +1648,7 @@ fn truncate_front_leak() { q.push_front(D(false)); q.push_front(D(false)); - catch_unwind(AssertUnwindSafe(|| q.truncate_front(1))).ok(); + catch_unwind(AssertUnwindSafe(|| q.retain_back(1))).ok(); assert_eq!(DROPS.get(), 7); } @@ -1817,20 +1817,20 @@ fn test_collect_from_into_iter_keeps_allocation() { } #[test] -fn test_truncate_front() { +fn test_retain_back() { let mut v = VecDeque::with_capacity(13); v.extend(0..7); assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); - v.truncate_front(10); + v.retain_back(10); assert_eq!(v.len(), 7); assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); - v.truncate_front(7); + v.retain_back(7); assert_eq!(v.len(), 7); assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); - v.truncate_front(3); + v.retain_back(3); assert_eq!(v.as_slices(), ([4, 5, 6].as_slice(), [].as_slice())); assert_eq!(v.len(), 3); - v.truncate_front(0); + v.retain_back(0); assert_eq!(v.as_slices(), ([].as_slice(), [].as_slice())); assert_eq!(v.len(), 0); @@ -1841,13 +1841,13 @@ fn test_truncate_front() { v.push_front(8); v.push_front(7); assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); - v.truncate_front(12); + v.retain_back(12); assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); - v.truncate_front(10); + v.retain_back(10); assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); - v.truncate_front(8); + v.retain_back(8); assert_eq!(v.as_slices(), ([9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); - v.truncate_front(5); + v.retain_back(5); assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice())); } @@ -1855,7 +1855,7 @@ fn test_truncate_front() { fn test_extend_from_within() { let mut v = VecDeque::with_capacity(8); v.extend(0..6); - v.truncate_front(4); + v.retain_back(4); assert_eq!(v, [2, 3, 4, 5]); v.extend_from_within(1..4); assert_eq!(v, [2, 3, 4, 5, 3, 4, 5]); @@ -1915,7 +1915,7 @@ fn test_extend_from_within_clone() { panic: false, })); // remove the dummy elements - v.truncate_front(4); + v.retain_back(4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1, 2, 3]); v.extend_from_within(2..); @@ -1947,7 +1947,7 @@ fn test_extend_from_within_clone_panic() { panic: false, })); // remove the dummy elements - v.truncate_front(4); + v.retain_back(4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1, 2, 3]); // panic after wrapping @@ -1963,7 +1963,7 @@ fn test_extend_from_within_clone_panic() { // nothing should have been dropped assert_eq!(drop_count.get(), 0); - v.truncate_front(2); + v.retain_back(2); assert_eq!(drop_count.get(), 4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1]); @@ -1985,7 +1985,7 @@ fn test_extend_from_within_clone_panic() { fn test_prepend_from_within() { let mut v = VecDeque::with_capacity(8); v.extend(0..6); - v.truncate_front(4); + v.retain_back(4); v.prepend_from_within(..=0); assert_eq!(v.as_slices(), ([2, 2, 3, 4, 5].as_slice(), [].as_slice())); v.prepend_from_within(2..); @@ -2007,7 +2007,7 @@ fn test_prepend_from_within_clone() { panic: false, })); // remove the dummy elements - v.truncate_front(4); + v.retain_back(4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1, 2, 3]); v.prepend_from_within(..2); @@ -2034,7 +2034,7 @@ fn test_prepend_from_within_clone_panic() { panic: false, })); // remove the dummy elements - v.truncate_front(4); + v.retain_back(4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1, 2, 3]); // panic after wrapping @@ -2050,7 +2050,7 @@ fn test_prepend_from_within_clone_panic() { // nothing should have been dropped assert_eq!(drop_count.get(), 0); - v.truncate_front(2); + v.retain_back(2); assert_eq!(drop_count.get(), 4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [2, 3]); @@ -2071,7 +2071,7 @@ fn test_prepend_from_within_clone_panic() { #[test] fn test_extend_and_prepend_from_within() { let mut v = ('0'..='9').map(String::from).collect::>(); - v.truncate_front(5); + v.retain_back(5); v.extend_from_within(4..); v.prepend_from_within(..2); assert_eq!(v.iter().map(|s| &**s).collect::(), "56567899"); @@ -2095,7 +2095,7 @@ fn test_extend_front() { let mut v = VecDeque::with_capacity(8); let cap = v.capacity(); v.extend(0..4); - v.truncate_front(2); + v.retain_back(2); v.extend_front(4..8); assert_eq!(v.as_slices(), ([7, 6].as_slice(), [5, 4, 2, 3].as_slice())); assert_eq!(v.capacity(), cap); diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index bc96c768c0c94..84e8aa9569fec 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -55,6 +55,7 @@ use crate::ffi::{VaArgSafe, VaList}; use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple}; +use crate::num::imp::libm; use crate::{mem, ptr}; mod bounds; @@ -1083,233 +1084,329 @@ pub fn powif128(a: f128, x: i32) -> f128; /// /// The stabilized version of this intrinsic is /// [`f16::sin`](../../std/primitive.f16.html#method.sin) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn sinf16(x: f16) -> f16; +pub fn sinf16(x: f16) -> f16 { + libm::likely_available::sinf(x as f32) as f16 +} /// Returns the sine of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::sin`](../../std/primitive.f32.html#method.sin) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn sinf32(x: f32) -> f32; +pub fn sinf32(x: f32) -> f32 { + libm::likely_available::sinf(x) +} /// Returns the sine of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::sin`](../../std/primitive.f64.html#method.sin) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn sinf64(x: f64) -> f64; +pub fn sinf64(x: f64) -> f64 { + libm::likely_available::sin(x) +} /// Returns the sine of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::sin`](../../std/primitive.f128.html#method.sin) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn sinf128(x: f128) -> f128; +pub fn sinf128(x: f128) -> f128 { + libm::maybe_available::sinf128(x) +} /// Returns the cosine of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::cos`](../../std/primitive.f16.html#method.cos) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn cosf16(x: f16) -> f16; +pub fn cosf16(x: f16) -> f16 { + libm::likely_available::cosf(x as f32) as f16 +} /// Returns the cosine of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::cos`](../../std/primitive.f32.html#method.cos) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn cosf32(x: f32) -> f32; +pub fn cosf32(x: f32) -> f32 { + libm::likely_available::cosf(x) +} /// Returns the cosine of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::cos`](../../std/primitive.f64.html#method.cos) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn cosf64(x: f64) -> f64; +pub fn cosf64(x: f64) -> f64 { + libm::likely_available::cos(x) +} /// Returns the cosine of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::cos`](../../std/primitive.f128.html#method.cos) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn cosf128(x: f128) -> f128; +pub fn cosf128(x: f128) -> f128 { + libm::maybe_available::cosf128(x) +} /// Raises an `f16` to an `f16` power. /// /// The stabilized version of this intrinsic is /// [`f16::powf`](../../std/primitive.f16.html#method.powf) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn powf16(a: f16, x: f16) -> f16; +pub fn powf16(a: f16, x: f16) -> f16 { + libm::likely_available::powf(a as f32, x as f32) as f16 +} /// Raises an `f32` to an `f32` power. /// /// The stabilized version of this intrinsic is /// [`f32::powf`](../../std/primitive.f32.html#method.powf) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn powf32(a: f32, x: f32) -> f32; +pub fn powf32(a: f32, x: f32) -> f32 { + libm::likely_available::powf(a, x) +} /// Raises an `f64` to an `f64` power. /// /// The stabilized version of this intrinsic is /// [`f64::powf`](../../std/primitive.f64.html#method.powf) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn powf64(a: f64, x: f64) -> f64; +pub fn powf64(a: f64, x: f64) -> f64 { + libm::likely_available::pow(a, x) +} /// Raises an `f128` to an `f128` power. /// /// The stabilized version of this intrinsic is /// [`f128::powf`](../../std/primitive.f128.html#method.powf) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn powf128(a: f128, x: f128) -> f128; +pub fn powf128(a: f128, x: f128) -> f128 { + libm::maybe_available::powf128(a, x) +} /// Returns the exponential of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::exp`](../../std/primitive.f16.html#method.exp) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn expf16(x: f16) -> f16; +pub fn expf16(x: f16) -> f16 { + libm::likely_available::expf(x as f32) as f16 +} /// Returns the exponential of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::exp`](../../std/primitive.f32.html#method.exp) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn expf32(x: f32) -> f32; +pub fn expf32(x: f32) -> f32 { + libm::likely_available::expf(x) +} /// Returns the exponential of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::exp`](../../std/primitive.f64.html#method.exp) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn expf64(x: f64) -> f64; +pub fn expf64(x: f64) -> f64 { + libm::likely_available::exp(x) +} /// Returns the exponential of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::exp`](../../std/primitive.f128.html#method.exp) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn expf128(x: f128) -> f128; +pub fn expf128(x: f128) -> f128 { + libm::maybe_available::expf128(x) +} /// Returns 2 raised to the power of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn exp2f16(x: f16) -> f16; +pub fn exp2f16(x: f16) -> f16 { + libm::likely_available::exp2f(x as f32) as f16 +} /// Returns 2 raised to the power of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn exp2f32(x: f32) -> f32; +pub fn exp2f32(x: f32) -> f32 { + libm::likely_available::exp2f(x) +} /// Returns 2 raised to the power of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn exp2f64(x: f64) -> f64; +pub fn exp2f64(x: f64) -> f64 { + libm::likely_available::exp2(x) +} /// Returns 2 raised to the power of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn exp2f128(x: f128) -> f128; +pub fn exp2f128(x: f128) -> f128 { + libm::maybe_available::exp2f128(x) +} /// Returns the natural logarithm of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::ln`](../../std/primitive.f16.html#method.ln) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn logf16(x: f16) -> f16; +pub fn logf16(x: f16) -> f16 { + libm::likely_available::logf(x as f32) as f16 +} /// Returns the natural logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::ln`](../../std/primitive.f32.html#method.ln) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn logf32(x: f32) -> f32; +pub fn logf32(x: f32) -> f32 { + libm::likely_available::logf(x) +} /// Returns the natural logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::ln`](../../std/primitive.f64.html#method.ln) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn logf64(x: f64) -> f64; +pub fn logf64(x: f64) -> f64 { + libm::likely_available::log(x) +} /// Returns the natural logarithm of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::ln`](../../std/primitive.f128.html#method.ln) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn logf128(x: f128) -> f128; +pub fn logf128(x: f128) -> f128 { + libm::maybe_available::logf128(x) +} /// Returns the base 10 logarithm of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::log10`](../../std/primitive.f16.html#method.log10) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn log10f16(x: f16) -> f16; +pub fn log10f16(x: f16) -> f16 { + libm::likely_available::log10f(x as f32) as f16 +} /// Returns the base 10 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::log10`](../../std/primitive.f32.html#method.log10) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn log10f32(x: f32) -> f32; +pub fn log10f32(x: f32) -> f32 { + libm::likely_available::log10f(x) +} /// Returns the base 10 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::log10`](../../std/primitive.f64.html#method.log10) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn log10f64(x: f64) -> f64; +pub fn log10f64(x: f64) -> f64 { + libm::likely_available::log10(x) +} /// Returns the base 10 logarithm of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::log10`](../../std/primitive.f128.html#method.log10) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn log10f128(x: f128) -> f128; +pub fn log10f128(x: f128) -> f128 { + libm::maybe_available::log10f128(x) +} /// Returns the base 2 logarithm of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::log2`](../../std/primitive.f16.html#method.log2) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn log2f16(x: f16) -> f16; +pub fn log2f16(x: f16) -> f16 { + libm::likely_available::log2f(x as f32) as f16 +} /// Returns the base 2 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::log2`](../../std/primitive.f32.html#method.log2) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn log2f32(x: f32) -> f32; +pub fn log2f32(x: f32) -> f32 { + libm::likely_available::log2f(x) +} /// Returns the base 2 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::log2`](../../std/primitive.f64.html#method.log2) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn log2f64(x: f64) -> f64; +pub fn log2f64(x: f64) -> f64 { + libm::likely_available::log2(x) +} /// Returns the base 2 logarithm of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::log2`](../../std/primitive.f128.html#method.log2) +#[inline] #[rustc_intrinsic] #[rustc_nounwind] -pub fn log2f128(x: f128) -> f128; +pub fn log2f128(x: f128) -> f128 { + libm::maybe_available::log2f128(x) +} /// Returns `a * b + c` for `f16` values. /// diff --git a/library/core/src/io/cursor.rs b/library/core/src/io/cursor.rs index c104b426f48df..fe4def531a84a 100644 --- a/library/core/src/io/cursor.rs +++ b/library/core/src/io/cursor.rs @@ -1,4 +1,5 @@ -use crate::io::{self, ErrorKind, SeekFrom}; +use crate::cmp; +use crate::io::{self, ErrorKind, IoSlice, SeekFrom, Write}; /// A `Cursor` wraps an in-memory buffer and provides it with a /// [`Seek`] implementation. @@ -22,7 +23,7 @@ use crate::io::{self, ErrorKind, SeekFrom}; /// [bytes]: crate::slice "slice" /// [`File`]: ../../std/fs/struct.File.html /// [`Read`]: ../../std/io/trait.Read.html -/// [`Write`]: ../../std/io/trait.Write.html +/// [`Write`]: crate::io::Write /// [`Seek`]: crate::io::Seek /// [Vec]: ../../alloc/vec/struct.Vec.html /// @@ -294,6 +295,144 @@ where } } +/// Non-resizing [`Write::write`] implementation for slices. +/// Exported for `Cursor>`'s implementation of [`Write`]. +#[inline] +#[doc(hidden)] +#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] +pub fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result { + let pos = cmp::min(*pos_mut, slice.len() as u64); + let dst = &mut slice[(pos as usize)..]; + let amt = cmp::min(buf.len(), dst.len()); + dst[..amt].copy_from_slice(&buf[..amt]); + *pos_mut += amt as u64; + Ok(amt) +} + +/// Non-resizing [`Write::write_vectored`] implementation for slices. +/// Exported for `Cursor>`'s implementation of [`Write`]. +#[inline] +#[doc(hidden)] +#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] +pub fn slice_write_vectored( + pos_mut: &mut u64, + slice: &mut [u8], + bufs: &[IoSlice<'_>], +) -> io::Result { + let mut nwritten = 0; + for buf in bufs { + let n = slice_write(pos_mut, slice, buf)?; + nwritten += n; + if n < buf.len() { + break; + } + } + Ok(nwritten) +} + +/// Non-resizing [`Write::write_all`] implementation for slices. +/// Exported for `Cursor>`'s implementation of [`Write`]. +#[inline] +#[doc(hidden)] +#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] +pub fn slice_write_all(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<()> { + let n = slice_write(pos_mut, slice, buf)?; + if n < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } +} + +/// Non-resizing [`Write::write_all_vectored`] implementation for slices. +/// Exported for `Cursor>`'s implementation of [`Write`]. +#[inline] +#[doc(hidden)] +#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] +pub fn slice_write_all_vectored( + pos_mut: &mut u64, + slice: &mut [u8], + bufs: &[IoSlice<'_>], +) -> io::Result<()> { + for buf in bufs { + let n = slice_write(pos_mut, slice, buf)?; + if n < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for Cursor<&mut [u8]> { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + let (pos, inner) = self.into_parts_mut(); + slice_write(pos, inner, buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let (pos, inner) = self.into_parts_mut(); + slice_write_vectored(pos, inner, bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + let (pos, inner) = self.into_parts_mut(); + slice_write_all(pos, inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + let (pos, inner) = self.into_parts_mut(); + slice_write_all_vectored(pos, inner, bufs) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "cursor_array", since = "1.61.0")] +impl Write for Cursor<[u8; N]> { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + let (pos, inner) = self.into_parts_mut(); + slice_write(pos, inner, buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let (pos, inner) = self.into_parts_mut(); + slice_write_vectored(pos, inner, bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + let (pos, inner) = self.into_parts_mut(); + slice_write_all(pos, inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + let (pos, inner) = self.into_parts_mut(); + slice_write_all_vectored(pos, inner, bufs) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl io::Seek for Cursor where @@ -328,3 +467,53 @@ where Ok(self.position()) } } + +/// Trait used to allow indirect implementation of `Write` for `Cursor`. +/// Since [`Cursor`] is not a foundational type, it is not possible to implement +/// `Write` for `Cursor` if `Write` is defined in `libcore` and `T` is in a +/// downstream crate (e.g., `liballoc` or `libstd`). +/// +/// Methods are identical in purpose and meaning to their `Write` namesakes. +#[doc(hidden)] +#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] +pub trait WriteThroughCursor: Sized { + fn write(this: &mut Cursor, buf: &[u8]) -> io::Result; + fn write_vectored(this: &mut Cursor, bufs: &[IoSlice<'_>]) -> io::Result; + fn is_write_vectored(this: &Cursor) -> bool; + fn write_all(this: &mut Cursor, buf: &[u8]) -> io::Result<()>; + fn write_all_vectored(this: &mut Cursor, bufs: &mut [IoSlice<'_>]) -> io::Result<()>; + fn flush(this: &mut Cursor) -> io::Result<()>; +} + +#[doc(hidden)] +impl Write for Cursor { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + WriteThroughCursor::write(self, buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + WriteThroughCursor::write_vectored(self, bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + WriteThroughCursor::is_write_vectored(self) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + WriteThroughCursor::write_all(self, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + WriteThroughCursor::write_all_vectored(self, bufs) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + WriteThroughCursor::flush(self) + } +} diff --git a/library/core/src/io/error.rs b/library/core/src/io/error.rs index 4214a5f87e3ef..eac7396bcfd83 100644 --- a/library/core/src/io/error.rs +++ b/library/core/src/io/error.rs @@ -79,7 +79,7 @@ pub type Result = result::Result; /// // FIXME(#74481): Hard-links required to link from `core` to `std` /// [Read]: ../../std/io/trait.Read.html -/// [Write]: ../../std/io/trait.Write.html +/// [Write]: crate::io::Write /// [Seek]: crate::io::Seek #[stable(feature = "rust1", since = "1.0.0")] #[rustc_has_incoherent_inherent_impls] @@ -853,7 +853,7 @@ pub enum ErrorKind { /// particular number of bytes but only a smaller number of bytes could be /// written. /// - /// [write]: ../../std/io/trait.Write.html#tymethod.write + /// [write]: crate::io::Write::write /// [`Ok(0)`]: Ok #[stable(feature = "rust1", since = "1.0.0")] WriteZero, diff --git a/library/core/src/io/impls.rs b/library/core/src/io/impls.rs index e8c716f060119..218bd7adc2a55 100644 --- a/library/core/src/io/impls.rs +++ b/library/core/src/io/impls.rs @@ -1,4 +1,5 @@ -use crate::io::{self, Seek, SeekFrom, SizeHint}; +use crate::io::{self, IoSlice, Seek, SeekFrom, SizeHint, Write}; +use crate::{cmp, fmt, mem}; // ============================================================================= // Forwarding implementations @@ -17,6 +18,43 @@ impl SizeHint for &mut T { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for &mut W { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + (**self).write(buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (**self).write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + (**self).is_write_vectored() + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + (**self).flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (**self).write_all(buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + (**self).write_all_vectored(bufs) + } + + #[inline] + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + (**self).write_fmt(fmt) + } +} #[stable(feature = "rust1", since = "1.0.0")] impl Seek for &mut S { #[inline] @@ -61,3 +99,110 @@ impl SizeHint for &[u8] { Some(self.len()) } } + +/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting +/// its data. +/// +/// Note that writing updates the slice to point to the yet unwritten part. +/// The slice will be empty when it has been completely overwritten. +/// +/// If the number of bytes to be written exceeds the size of the slice, write operations will +/// return short writes: ultimately, `Ok(0)`; in this situation, `write_all` returns an error of +/// kind `ErrorKind::WriteZero`. +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for &mut [u8] { + #[inline] + fn write(&mut self, data: &[u8]) -> io::Result { + let amt = cmp::min(data.len(), self.len()); + let (a, b) = mem::take(self).split_at_mut(amt); + a.copy_from_slice(&data[..amt]); + *self = b; + Ok(amt) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let mut nwritten = 0; + for buf in bufs { + nwritten += self.write(buf)?; + if self.is_empty() { + break; + } + } + + Ok(nwritten) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, data: &[u8]) -> io::Result<()> { + if self.write(data)? < data.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + for buf in bufs { + if self.write(buf)? < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[unstable(feature = "read_buf", issue = "78485")] +impl<'a> io::Write for core::io::BorrowedCursor<'a, u8> { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + let amt = cmp::min(buf.len(), self.capacity()); + self.append(&buf[..amt]); + Ok(amt) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let mut nwritten = 0; + for buf in bufs { + let n = self.write(buf)?; + nwritten += n; + if n < buf.len() { + break; + } + } + Ok(nwritten) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + if self.write(buf)? < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + for buf in bufs { + if self.write(buf)? < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} diff --git a/library/core/src/io/mod.rs b/library/core/src/io/mod.rs index 1c27e42229bb7..0134540ae86c8 100644 --- a/library/core/src/io/mod.rs +++ b/library/core/src/io/mod.rs @@ -8,6 +8,7 @@ mod io_slice; mod seek; mod size_hint; mod util; +mod write; #[unstable(feature = "core_io_borrowed_buf", issue = "117693")] pub use self::borrowed_buf::{BorrowedBuf, BorrowedCursor}; @@ -24,14 +25,20 @@ pub use self::{ io_slice::{IoSlice, IoSliceMut}, seek::{Seek, SeekFrom}, util::{Chain, Empty, Repeat, Sink, Take, empty, repeat, sink}, + write::Write, }; #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub use self::{ + cursor::{ + WriteThroughCursor, slice_write, slice_write_all, slice_write_all_vectored, + slice_write_vectored, + }, error::{Custom, CustomOwner, OsFunctions}, seek::stream_len_default, size_hint::SizeHint, util::{chain, take}, + write::default_write_vectored, }; /// Marks that a type `T` can have IO traits such as [`Seek`], [`Write`], etc. automatically @@ -48,7 +55,7 @@ pub use self::{ // FIXME(#74481): Hard-links required to link from `core` to `std` /// [file]: ../../std/fs/struct.File.html /// [arc]: ../../alloc/sync/struct.Arc.html -/// [`Write`]: ../../std/io/trait.Write.html +/// [`Write`]: crate::io::Write /// [`Seek`]: crate::io::Seek #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] diff --git a/library/core/src/io/util.rs b/library/core/src/io/util.rs index de37690436c80..b022d876eb8f5 100644 --- a/library/core/src/io/util.rs +++ b/library/core/src/io/util.rs @@ -1,10 +1,10 @@ -use crate::io::{ErrorKind, Result, Seek, SeekFrom, SizeHint}; +use crate::io::{self, ErrorKind, IoSlice, Result, Seek, SeekFrom, SizeHint, Write}; use crate::{cmp, fmt}; /// `Empty` ignores any data written via [`Write`], and will always be empty /// (returning zero bytes) when read via [`Read`]. /// -/// [`Write`]: ../../std/io/trait.Write.html +/// [`Write`]: crate::io::Write /// [`Read`]: ../../std/io/trait.Read.html /// /// This struct is generally created by calling [`empty()`]. Please @@ -23,6 +23,84 @@ impl SizeHint for Empty { } } +#[stable(feature = "empty_write", since = "1.73.0")] +impl Write for Empty { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "empty_write", since = "1.73.0")] +impl Write for &Empty { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + #[stable(feature = "empty_seek", since = "1.51.0")] impl Seek for Empty { #[inline] @@ -51,7 +129,7 @@ impl Seek for Empty { /// [`Ok(buf.len())`]: Ok /// [`Ok(0)`]: Ok /// -/// [`write`]: ../../std/io/trait.Write.html#tymethod.write +/// [`write`]: crate::io::Write::write /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// /// # Examples @@ -142,12 +220,90 @@ impl fmt::Debug for Repeat { #[derive(Copy, Clone, Debug, Default)] pub struct Sink; +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for Sink { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "write_mt", since = "1.48.0")] +impl Write for &Sink { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + /// Creates an instance of a writer which will successfully consume all data. /// /// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`] /// and the contents of the buffer will not be inspected. /// -/// [`write`]: ../../std/io/trait.Write.html#tymethod.write +/// [`write`]: crate::io::Write::write /// [`Ok(buf.len())`]: Ok /// /// # Examples diff --git a/library/core/src/io/write.rs b/library/core/src/io/write.rs new file mode 100644 index 0000000000000..cdddd380885f4 --- /dev/null +++ b/library/core/src/io/write.rs @@ -0,0 +1,417 @@ +use crate::fmt; +use crate::io::{Error, IoSlice, Result}; + +/// A trait for objects which are byte-oriented sinks. +/// +/// Implementors of the `Write` trait are sometimes called 'writers'. +/// +/// Writers are defined by two required methods, [`write`] and [`flush`]: +/// +/// * The [`write`] method will attempt to write some data into the object, +/// returning how many bytes were successfully written. +/// +/// * The [`flush`] method is useful for adapters and explicit buffers +/// themselves for ensuring that all buffered data has been pushed out to the +/// 'true sink'. +/// +/// Writers are intended to be composable with one another. Many implementors +/// throughout [`std::io`] take and provide types which implement the `Write` +/// trait. +/// +/// [`write`]: Write::write +/// [`flush`]: Write::flush +/// [`std::io`]: crate::io +/// +/// # Examples +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// fn main() -> std::io::Result<()> { +/// let data = b"some bytes"; +/// +/// let mut pos = 0; +/// let mut buffer = File::create("foo.txt")?; +/// +/// while pos < data.len() { +/// let bytes_written = buffer.write(&data[pos..])?; +/// pos += bytes_written; +/// } +/// Ok(()) +/// } +/// ``` +/// +/// The trait also provides convenience methods like [`write_all`], which calls +/// `write` in a loop until its entire input has been written. +/// +/// [`write_all`]: Write::write_all +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(notable_trait)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoWrite")] +pub trait Write { + /// Writes a buffer into this writer, returning how many bytes were written. + /// + /// This function will attempt to write the entire contents of `buf`, but + /// the entire write might not succeed, or the write may also generate an + /// error. Typically, a call to `write` represents one attempt to write to + /// any wrapped object. + /// + /// Calls to `write` are not guaranteed to block waiting for data to be + /// written, and a write which would otherwise block can be indicated through + /// an [`Err`] variant. + /// + /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. + /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`. + /// A return value of `Ok(0)` typically means that the underlying object is + /// no longer able to accept bytes and will likely not be able to in the + /// future as well, or that the buffer provided is empty. + /// + /// # Errors + /// + /// Each call to `write` may generate an I/O error indicating that the + /// operation could not be completed. If an error is returned then no bytes + /// in the buffer were written to this writer. + /// + /// It is **not** considered an error if the entire buffer could not be + /// written to this writer. + /// + /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the + /// write operation should be retried if there is nothing else to do. + /// + /// [`ErrorKind::Interrupted`]: crate::io::ErrorKind::Interrupted + /// + /// # Examples + /// + /// ```no_run + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// // Writes some prefix of the byte string, not necessarily all of it. + /// buffer.write(b"some bytes")?; + /// Ok(()) + /// } + /// ``` + /// + /// [`Ok(n)`]: Ok + #[stable(feature = "rust1", since = "1.0.0")] + fn write(&mut self, buf: &[u8]) -> Result; + + /// Like [`write`], except that it writes from a slice of buffers. + /// + /// Data is copied from each buffer in order, with the final buffer + /// read from possibly being only partially consumed. This method must + /// behave as a call to [`write`] with the buffers concatenated would. + /// + /// The default implementation calls [`write`] with either the first nonempty + /// buffer provided, or an empty one if none exists. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::IoSlice; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let data1 = [1; 8]; + /// let data2 = [15; 8]; + /// let io_slice1 = IoSlice::new(&data1); + /// let io_slice2 = IoSlice::new(&data2); + /// + /// let mut buffer = File::create("foo.txt")?; + /// + /// // Writes some prefix of the byte string, not necessarily all of it. + /// buffer.write_vectored(&[io_slice1, io_slice2])?; + /// Ok(()) + /// } + /// ``` + /// + /// [`write`]: Write::write + #[stable(feature = "iovec", since = "1.36.0")] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { + default_write_vectored(|b| self.write(b), bufs) + } + + /// Determines if this `Write`r has an efficient [`write_vectored`] + /// implementation. + /// + /// If a `Write`r does not override the default [`write_vectored`] + /// implementation, code using it may want to avoid the method all together + /// and coalesce writes into a single buffer for higher performance. + /// + /// The default implementation returns `false`. + /// + /// [`write_vectored`]: Write::write_vectored + #[unstable(feature = "can_vector", issue = "69941")] + fn is_write_vectored(&self) -> bool { + false + } + + /// Flushes this output stream, ensuring that all intermediately buffered + /// contents reach their destination. + /// + /// # Errors + /// + /// It is considered an error if not all bytes could be written due to + /// I/O errors or EOF being reached. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::prelude::*; + /// use std::io::BufWriter; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = BufWriter::new(File::create("foo.txt")?); + /// + /// buffer.write_all(b"some bytes")?; + /// buffer.flush()?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn flush(&mut self) -> Result<()>; + + /// Attempts to write an entire buffer into this writer. + /// + /// This method will continuously call [`write`] until there is no more data + /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of [`ErrorKind::Interrupted`] kind generated from this method will be + /// returned. + /// + /// [`ErrorKind::Interrupted`]: crate::io::ErrorKind::Interrupted + /// + /// If the buffer contains no data, this will never call [`write`]. + /// + /// # Errors + /// + /// This function will return the first error of + /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns. + /// + /// [`write`]: Write::write + /// + /// # Examples + /// + /// ```no_run + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// buffer.write_all(b"some bytes")?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { + while !buf.is_empty() { + match self.write(buf) { + Ok(0) => { + return Err(Error::WRITE_ALL_EOF); + } + Ok(n) => buf = &buf[n..], + Err(ref e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Attempts to write multiple buffers into this writer. + /// + /// This method will continuously call [`write_vectored`] until there is no + /// more data to be written or an error of non-[`ErrorKind::Interrupted`] + /// kind is returned. This method will not return until all buffers have + /// been successfully written or such an error occurs. The first error that + /// is not of [`ErrorKind::Interrupted`] kind generated from this method + /// will be returned. + /// + /// [`ErrorKind::Interrupted`]: crate::io::ErrorKind::Interrupted + /// + /// If the buffer contains no data, this will never call [`write_vectored`]. + /// + /// # Notes + /// + /// Unlike [`write_vectored`], this takes a *mutable* reference to + /// a slice of [`IoSlice`]s, not an immutable one. That's because we need to + /// modify the slice to keep track of the bytes already written. + /// + /// Once this function returns, the contents of `bufs` are unspecified, as + /// this depends on how many calls to [`write_vectored`] were necessary. It is + /// best to understand this function as taking ownership of `bufs` and to + /// not use `bufs` afterwards. The underlying buffers, to which the + /// [`IoSlice`]s point (but not the [`IoSlice`]s themselves), are unchanged and + /// can be reused. + /// + /// [`write_vectored`]: Write::write_vectored + /// + /// # Examples + /// + /// ``` + /// #![feature(write_all_vectored)] + /// # fn main() -> std::io::Result<()> { + /// + /// use std::io::{Write, IoSlice}; + /// + /// let mut writer = Vec::new(); + /// let bufs = &mut [ + /// IoSlice::new(&[1]), + /// IoSlice::new(&[2, 3]), + /// IoSlice::new(&[4, 5, 6]), + /// ]; + /// + /// writer.write_all_vectored(bufs)?; + /// // Note: the contents of `bufs` is now undefined, see the Notes section. + /// + /// assert_eq!(writer, &[1, 2, 3, 4, 5, 6]); + /// # Ok(()) } + /// ``` + #[unstable(feature = "write_all_vectored", issue = "70436")] + fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> { + // Guarantee that bufs is empty if it contains no data, + // to avoid calling write_vectored if there is no data to be written. + IoSlice::advance_slices(&mut bufs, 0); + while !bufs.is_empty() { + match self.write_vectored(bufs) { + Ok(0) => { + return Err(Error::WRITE_ALL_EOF); + } + Ok(n) => IoSlice::advance_slices(&mut bufs, n), + Err(ref e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Writes a formatted string into this writer, returning any error + /// encountered. + /// + /// This method is primarily used to interface with the + /// [`format_args!()`] macro, and it is rare that this should + /// explicitly be called. The [`write!()`] macro should be favored to + /// invoke this method instead. + /// + /// This function internally uses the [`write_all`] method on + /// this trait and hence will continuously write data so long as no errors + /// are received. This also means that partial writes are not indicated in + /// this signature. + /// + /// [`write_all`]: Write::write_all + /// + /// # Errors + /// + /// This function will return any I/O error reported while formatting. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// // this call + /// write!(buffer, "{:.*}", 2, 1.234567)?; + /// // turns into this: + /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> { + if let Some(s) = args.as_statically_known_str() { + self.write_all(s.as_bytes()) + } else { + default_write_fmt(self, args) + } + } + + /// Creates a "by reference" adapter for this instance of `Write`. + /// + /// The returned adapter also implements `Write` and will simply borrow this + /// current writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::Write; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// let reference = buffer.by_ref(); + /// + /// // we can use reference just like our original buffer + /// reference.write_all(b"some bytes")?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn by_ref(&mut self) -> &mut Self + where + Self: Sized, + { + self + } +} + +/// Default implementation of [`Write::write_vectored`], which is currently used +/// in `libstd` for file system implementations of similar methods. +#[doc(hidden)] +#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] +pub fn default_write_vectored(write: F, bufs: &[IoSlice<'_>]) -> Result +where + F: FnOnce(&[u8]) -> Result, +{ + let buf = bufs.iter().find(|b| !b.is_empty()).map_or(&[][..], |b| &**b); + write(buf) +} + +fn default_write_fmt(this: &mut W, args: fmt::Arguments<'_>) -> Result<()> { + // Create a shim which translates a `Write` to a `fmt::Write` and saves off + // I/O errors, instead of discarding them. + struct Adapter<'a, T: ?Sized + 'a> { + inner: &'a mut T, + error: Result<()>, + } + + impl fmt::Write for Adapter<'_, T> { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.inner.write_all(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(fmt::Error) + } + } + } + } + + let mut output = Adapter { inner: this, error: Ok(()) }; + match fmt::write(&mut output, args) { + Ok(()) => Ok(()), + Err(..) => { + // Check whether the error came from the underlying `Write`. + if output.error.is_err() { + output.error + } else { + // This shouldn't happen: the underlying stream did not error, + // but somehow the formatter still errored? + panic!( + "a formatting trait implementation returned an error when the underlying stream did not" + ); + } + } + } +} diff --git a/library/core/src/num/imp/libm.rs b/library/core/src/num/imp/libm.rs index aeabb08723095..c67adc337c1cb 100644 --- a/library/core/src/num/imp/libm.rs +++ b/library/core/src/num/imp/libm.rs @@ -1,11 +1,157 @@ //! Bindings to math functions provided by the system `libm` or by the `libm` crate, exposed //! via `compiler-builtins`. +//! +//! The functions in the root of this module are "guaranteed" to be available; see the +//! `full_availability` module in compiler-builtins for details. // SAFETY: These symbols have standard interfaces in C and are defined by `libm`, or are // provided by `compiler-builtins` on unsupported platforms. +#[allow(dead_code)] // This list reflects what is available rather than what is consumed. unsafe extern "C" { - pub(crate) safe fn cbrt(n: f64) -> f64; + pub(crate) safe fn cbrt(x: f64) -> f64; pub(crate) safe fn cbrtf(n: f32) -> f32; + pub(crate) safe fn ceil(x: f64) -> f64; + pub(crate) safe fn ceilf(x: f32) -> f32; + pub(crate) safe fn ceilf128(x: f128) -> f128; + pub(crate) safe fn ceilf16(x: f16) -> f16; + pub(crate) safe fn copysign(x: f64, y: f64) -> f64; + pub(crate) safe fn copysignf(x: f32, y: f32) -> f32; + pub(crate) safe fn copysignf128(x: f128, y: f128) -> f128; + pub(crate) safe fn copysignf16(x: f16, y: f16) -> f16; + pub(crate) safe fn fabs(x: f64) -> f64; + pub(crate) safe fn fabsf(x: f32) -> f32; + pub(crate) safe fn fabsf128(x: f128) -> f128; + pub(crate) safe fn fabsf16(x: f16) -> f16; pub(crate) safe fn fdim(a: f64, b: f64) -> f64; pub(crate) safe fn fdimf(a: f32, b: f32) -> f32; + pub(crate) safe fn fdimf128(x: f128, y: f128) -> f128; + pub(crate) safe fn fdimf16(x: f16, y: f16) -> f16; + pub(crate) safe fn floor(x: f64) -> f64; + pub(crate) safe fn floorf(x: f32) -> f32; + pub(crate) safe fn floorf128(x: f128) -> f128; + pub(crate) safe fn floorf16(x: f16) -> f16; + pub(crate) safe fn fma(x: f64, y: f64, z: f64) -> f64; + pub(crate) safe fn fmaf(x: f32, y: f32, z: f32) -> f32; + pub(crate) safe fn fmaf128(x: f128, y: f128, z: f128) -> f128; + pub(crate) safe fn fmax(x: f64, y: f64) -> f64; + pub(crate) safe fn fmaxf(x: f32, y: f32) -> f32; + pub(crate) safe fn fmaxf128(x: f128, y: f128) -> f128; + pub(crate) safe fn fmaxf16(x: f16, y: f16) -> f16; + pub(crate) safe fn fmaximum(x: f64, y: f64) -> f64; + pub(crate) safe fn fmaximumf(x: f32, y: f32) -> f32; + pub(crate) safe fn fmaximumf128(x: f128, y: f128) -> f128; + pub(crate) safe fn fmaximumf16(x: f16, y: f16) -> f16; + pub(crate) safe fn fmin(x: f64, y: f64) -> f64; + pub(crate) safe fn fminf(x: f32, y: f32) -> f32; + pub(crate) safe fn fminf128(x: f128, y: f128) -> f128; + pub(crate) safe fn fminf16(x: f16, y: f16) -> f16; + pub(crate) safe fn fminimum(x: f64, y: f64) -> f64; + pub(crate) safe fn fminimumf(x: f32, y: f32) -> f32; + pub(crate) safe fn fminimumf128(x: f128, y: f128) -> f128; + pub(crate) safe fn fminimumf16(x: f16, y: f16) -> f16; + pub(crate) safe fn fmod(x: f64, y: f64) -> f64; + pub(crate) safe fn fmodf(x: f32, y: f32) -> f32; + pub(crate) safe fn fmodf128(x: f128, y: f128) -> f128; + pub(crate) safe fn fmodf16(x: f16, y: f16) -> f16; + pub(crate) safe fn rint(x: f64) -> f64; + pub(crate) safe fn rintf(x: f32) -> f32; + pub(crate) safe fn rintf128(x: f128) -> f128; + pub(crate) safe fn rintf16(x: f16) -> f16; + pub(crate) safe fn round(x: f64) -> f64; + pub(crate) safe fn roundeven(x: f64) -> f64; + pub(crate) safe fn roundevenf(x: f32) -> f32; + pub(crate) safe fn roundevenf128(x: f128) -> f128; + pub(crate) safe fn roundevenf16(x: f16) -> f16; + pub(crate) safe fn roundf(x: f32) -> f32; + pub(crate) safe fn roundf128(x: f128) -> f128; + pub(crate) safe fn roundf16(x: f16) -> f16; + pub(crate) safe fn sqrt(x: f64) -> f64; + pub(crate) safe fn sqrtf(x: f32) -> f32; + pub(crate) safe fn sqrtf128(x: f128) -> f128; + pub(crate) safe fn sqrtf16(x: f16) -> f16; + pub(crate) safe fn trunc(x: f64) -> f64; + pub(crate) safe fn truncf(x: f32) -> f32; + pub(crate) safe fn truncf128(x: f128) -> f128; + pub(crate) safe fn truncf16(x: f16) -> f16; +} + +/// These symbols will be available when `std` is available, and on many no-std platforms. However, +/// since this isn't a guarantee, we cannot rely on them for stable implementations. +pub(crate) mod likely_available { + #[allow(dead_code)] + unsafe extern "C" { + pub(crate) safe fn acos(x: f64) -> f64; + pub(crate) safe fn acosf(n: f32) -> f32; + pub(crate) safe fn asin(x: f64) -> f64; + pub(crate) safe fn asinf(n: f32) -> f32; + pub(crate) safe fn atan(x: f64) -> f64; + pub(crate) safe fn atan2(x: f64, y: f64) -> f64; + pub(crate) safe fn atan2f(a: f32, b: f32) -> f32; + pub(crate) safe fn atanf(n: f32) -> f32; + pub(crate) safe fn cos(x: f64) -> f64; + pub(crate) safe fn cosf(x: f32) -> f32; + pub(crate) safe fn cosh(x: f64) -> f64; + pub(crate) safe fn coshf(n: f32) -> f32; + pub(crate) safe fn erf(x: f64) -> f64; + pub(crate) safe fn erfc(x: f64) -> f64; + pub(crate) safe fn erfcf(x: f32) -> f32; + pub(crate) safe fn erff(x: f32) -> f32; + pub(crate) safe fn exp(x: f64) -> f64; + pub(crate) safe fn exp2(x: f64) -> f64; + pub(crate) safe fn exp2f(x: f32) -> f32; + pub(crate) safe fn expf(x: f32) -> f32; + pub(crate) safe fn expm1(x: f64) -> f64; + pub(crate) safe fn expm1f(n: f32) -> f32; + pub(crate) safe fn hypot(x: f64, y: f64) -> f64; + pub(crate) safe fn hypotf(x: f32, y: f32) -> f32; + pub(crate) safe fn ldexp(f: f64, n: i32) -> f64; + pub(crate) safe fn ldexpf(f: f32, n: i32) -> f32; + pub(crate) safe fn log(x: f64) -> f64; + pub(crate) safe fn log10(x: f64) -> f64; + pub(crate) safe fn log10f(x: f32) -> f32; + pub(crate) safe fn log1p(x: f64) -> f64; + pub(crate) safe fn log1pf(n: f32) -> f32; + pub(crate) safe fn log2(x: f64) -> f64; + pub(crate) safe fn log2f(x: f32) -> f32; + pub(crate) safe fn logf(x: f32) -> f32; + pub(crate) safe fn pow(x: f64, y: f64) -> f64; + pub(crate) safe fn powf(x: f32, y: f32) -> f32; + pub(crate) safe fn sin(x: f64) -> f64; + pub(crate) safe fn sinf(x: f32) -> f32; + pub(crate) safe fn sinh(x: f64) -> f64; + pub(crate) safe fn sinhf(n: f32) -> f32; + pub(crate) safe fn tan(x: f64) -> f64; + pub(crate) safe fn tanf(n: f32) -> f32; + pub(crate) safe fn tanh(x: f64) -> f64; + pub(crate) safe fn tanhf(n: f32) -> f32; + pub(crate) safe fn tgamma(x: f64) -> f64; + pub(crate) safe fn tgammaf(x: f32) -> f32; + } +} + +/// These symbols exist on some platforms but do not have a compiler-builtins fallback. +pub(crate) mod maybe_available { + #[allow(dead_code)] + unsafe extern "C" { + pub(crate) safe fn acosf128(x: f128) -> f128; + pub(crate) safe fn asinf128(x: f128) -> f128; + pub(crate) safe fn atanf128(x: f128) -> f128; + pub(crate) safe fn cbrtf128(x: f128) -> f128; + pub(crate) safe fn cosf128(x: f128) -> f128; + pub(crate) safe fn erff128(x: f128) -> f128; + pub(crate) safe fn expf128(x: f128) -> f128; + pub(crate) safe fn exp2f128(x: f128) -> f128; + pub(crate) safe fn expm1f128(x: f128) -> f128; + pub(crate) safe fn hypotf128(x: f128, y: f128) -> f128; + pub(crate) safe fn ldexpf128(f: f128, n: i32) -> f128; + pub(crate) safe fn log10f128(x: f128) -> f128; + pub(crate) safe fn log1pf128(x: f128) -> f128; + pub(crate) safe fn log2f128(x: f128) -> f128; + pub(crate) safe fn logf128(x: f128) -> f128; + pub(crate) safe fn powf128(x: f128, y: f128) -> f128; + pub(crate) safe fn sinf128(x: f128) -> f128; + pub(crate) safe fn tanf128(x: f128) -> f128; + pub(crate) safe fn tanhf128(x: f128) -> f128; + pub(crate) safe fn tgammaf128(x: f128) -> f128; + } } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 8a374f015a958..a2d367931ea9b 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2392,7 +2392,7 @@ macro_rules! int_impl { /// /// Beware that, unlike most other `wrapping_*` methods on integers, this /// does *not* give the same result as doing the shift in infinite precision - /// then truncating as needed. The behaviour matches what shift instructions + /// then truncating as needed. Instead, the behaviour of this method matches what shift instructions /// do on many processors, and is what the `<<` operator does when overflow /// checks are disabled, but numerically it's weird. Consider, instead, /// using [`Self::unbounded_shl`] which has nicer behaviour. @@ -2429,7 +2429,7 @@ macro_rules! int_impl { /// /// Beware that, unlike most other `wrapping_*` methods on integers, this /// does *not* give the same result as doing the shift in infinite precision - /// then truncating as needed. The behaviour matches what shift instructions + /// then truncating as needed. Instead, the behaviour of this method matches what shift instructions /// do on many processors, and is what the `>>` operator does when overflow /// checks are disabled, but numerically it's weird. Consider, instead, /// using [`Self::unbounded_shr`] which has nicer behaviour. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index cfb5eb54fb6bc..b33b2b5db1a32 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2827,7 +2827,7 @@ macro_rules! uint_impl { /// /// Beware that, unlike most other `wrapping_*` methods on integers, this /// does *not* give the same result as doing the shift in infinite precision - /// then truncating as needed. The behaviour matches what shift instructions + /// then truncating as needed. Instead, the behaviour of this method matches what shift instructions /// do on many processors, and is what the `<<` operator does when overflow /// checks are disabled, but numerically it's weird. Consider, instead, /// using [`Self::unbounded_shl`] which has nicer behaviour. @@ -2871,7 +2871,7 @@ macro_rules! uint_impl { /// /// Beware that, unlike most other `wrapping_*` methods on integers, this /// does *not* give the same result as doing the shift in infinite precision - /// then truncating as needed. The behaviour matches what shift instructions + /// then truncating as needed. Instead, the behaviour of this method matches what shift instructions /// do on many processors, and is what the `>>` operator does when overflow /// checks are disabled, but numerically it's weird. Consider, instead, /// using [`Self::unbounded_shr`] which has nicer behaviour. diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 5399789b4242f..e0b127bef8e2b 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -4,10 +4,8 @@ mod tests; #[stable(feature = "rust1", since = "1.0.0")] pub use core::io::Cursor; -use crate::alloc::Allocator; -use crate::cmp; use crate::io::prelude::*; -use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSliceMut}; #[stable(feature = "rust1", since = "1.0.0")] impl Read for Cursor @@ -101,414 +99,3 @@ where self.set_position(self.position() + amt as u64); } } - -/// Trait used to allow indirect implementation of `Write` for `Cursor`. -/// Since [`Cursor`] is not a foundational type, it is not possible to implement -/// `Write` for `Cursor` if `Write` is defined in `libcore` and `T` is in a -/// downstream crate (e.g., `liballoc` or `libstd`). -/// -/// Methods are identical in purpose and meaning to their `Write` namesakes. -trait WriteThroughCursor: Sized { - fn write(this: &mut Cursor, buf: &[u8]) -> io::Result; - fn write_vectored(this: &mut Cursor, bufs: &[IoSlice<'_>]) -> io::Result; - fn is_write_vectored(this: &Cursor) -> bool; - fn write_all(this: &mut Cursor, buf: &[u8]) -> io::Result<()>; - fn write_all_vectored(this: &mut Cursor, bufs: &mut [IoSlice<'_>]) -> io::Result<()>; - fn flush(this: &mut Cursor) -> io::Result<()>; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Cursor { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - WriteThroughCursor::write(self, buf) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - WriteThroughCursor::write_vectored(self, bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - WriteThroughCursor::is_write_vectored(self) - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - WriteThroughCursor::write_all(self, buf) - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - WriteThroughCursor::write_all_vectored(self, bufs) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - WriteThroughCursor::flush(self) - } -} - -// Non-resizing write implementation -#[inline] -fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result { - let pos = cmp::min(*pos_mut, slice.len() as u64); - let amt = (&mut slice[(pos as usize)..]).write(buf)?; - *pos_mut += amt as u64; - Ok(amt) -} - -#[inline] -fn slice_write_vectored( - pos_mut: &mut u64, - slice: &mut [u8], - bufs: &[IoSlice<'_>], -) -> io::Result { - let mut nwritten = 0; - for buf in bufs { - let n = slice_write(pos_mut, slice, buf)?; - nwritten += n; - if n < buf.len() { - break; - } - } - Ok(nwritten) -} - -#[inline] -fn slice_write_all(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<()> { - let n = slice_write(pos_mut, slice, buf)?; - if n < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } -} - -#[inline] -fn slice_write_all_vectored( - pos_mut: &mut u64, - slice: &mut [u8], - bufs: &[IoSlice<'_>], -) -> io::Result<()> { - for buf in bufs { - let n = slice_write(pos_mut, slice, buf)?; - if n < buf.len() { - return Err(io::Error::WRITE_ALL_EOF); - } - } - Ok(()) -} - -/// Reserves the required space, and pads the vec with 0s if necessary. -fn reserve_and_pad( - pos_mut: &mut u64, - vec: &mut Vec, - buf_len: usize, -) -> io::Result { - let pos: usize = (*pos_mut).try_into().map_err(|_| { - io::const_error!( - ErrorKind::InvalidInput, - "cursor position exceeds maximum possible vector length", - ) - })?; - - // For safety reasons, we don't want these numbers to overflow - // otherwise our allocation won't be enough - let desired_cap = pos.saturating_add(buf_len); - if desired_cap > vec.capacity() { - // We want our vec's total capacity - // to have room for (pos+buf_len) bytes. Reserve allocates - // based on additional elements from the length, so we need to - // reserve the difference - vec.reserve(desired_cap - vec.len()); - } - // Pad if pos is above the current len. - if pos > vec.len() { - let diff = pos - vec.len(); - // Unfortunately, `resize()` would suffice but the optimiser does not - // realise the `reserve` it does can be eliminated. So we do it manually - // to eliminate that extra branch - let spare = vec.spare_capacity_mut(); - debug_assert!(spare.len() >= diff); - // Safety: we have allocated enough capacity for this. - // And we are only writing, not reading - unsafe { - spare.get_unchecked_mut(..diff).fill(core::mem::MaybeUninit::new(0)); - vec.set_len(pos); - } - } - - Ok(pos) -} - -/// Writes the slice to the vec without allocating. -/// -/// # Safety -/// -/// `vec` must have `buf.len()` spare capacity. -unsafe fn vec_write_all_unchecked(pos: usize, vec: &mut Vec, buf: &[u8]) -> usize -where - A: Allocator, -{ - debug_assert!(vec.capacity() >= pos + buf.len()); - unsafe { vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()) }; - pos + buf.len() -} - -/// Resizing `write_all` implementation for [`Cursor`]. -/// -/// Cursor is allowed to have a pre-allocated and initialised -/// vector body, but with a position of 0. This means the [`Write`] -/// will overwrite the contents of the vec. -/// -/// This also allows for the vec body to be empty, but with a position of N. -/// This means that [`Write`] will pad the vec with 0 initially, -/// before writing anything from that point -fn vec_write_all(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result -where - A: Allocator, -{ - let buf_len = buf.len(); - let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?; - - // Write the buf then progress the vec forward if necessary - // Safety: we have ensured that the capacity is available - // and that all bytes get written up to pos - unsafe { - pos = vec_write_all_unchecked(pos, vec, buf); - if pos > vec.len() { - vec.set_len(pos); - } - }; - - // Bump us forward - *pos_mut += buf_len as u64; - Ok(buf_len) -} - -/// Resizing `write_all_vectored` implementation for [`Cursor`]. -/// -/// Cursor is allowed to have a pre-allocated and initialised -/// vector body, but with a position of 0. This means the [`Write`] -/// will overwrite the contents of the vec. -/// -/// This also allows for the vec body to be empty, but with a position of N. -/// This means that [`Write`] will pad the vec with 0 initially, -/// before writing anything from that point -fn vec_write_all_vectored( - pos_mut: &mut u64, - vec: &mut Vec, - bufs: &[IoSlice<'_>], -) -> io::Result -where - A: Allocator, -{ - // For safety reasons, we don't want this sum to overflow ever. - // If this saturates, the reserve should panic to avoid any unsound writing. - let buf_len = bufs.iter().fold(0usize, |a, b| a.saturating_add(b.len())); - let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?; - - // Write the buf then progress the vec forward if necessary - // Safety: we have ensured that the capacity is available - // and that all bytes get written up to the last pos - unsafe { - for buf in bufs { - pos = vec_write_all_unchecked(pos, vec, buf); - } - if pos > vec.len() { - vec.set_len(pos); - } - } - - // Bump us forward - *pos_mut += buf_len as u64; - Ok(buf_len) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Cursor<&mut [u8]> { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - let (pos, inner) = self.into_parts_mut(); - slice_write(pos, inner, buf) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let (pos, inner) = self.into_parts_mut(); - slice_write_vectored(pos, inner, bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - let (pos, inner) = self.into_parts_mut(); - slice_write_all(pos, inner, buf) - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - let (pos, inner) = self.into_parts_mut(); - slice_write_all_vectored(pos, inner, bufs) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "cursor_mut_vec", since = "1.25.0")] -impl WriteThroughCursor for &mut Vec -where - A: Allocator, -{ - fn write(this: &mut Cursor, buf: &[u8]) -> io::Result { - let (pos, inner) = this.into_parts_mut(); - vec_write_all(pos, inner, buf) - } - - fn write_vectored(this: &mut Cursor, bufs: &[IoSlice<'_>]) -> io::Result { - let (pos, inner) = this.into_parts_mut(); - vec_write_all_vectored(pos, inner, bufs) - } - - #[inline] - fn is_write_vectored(_this: &Cursor) -> bool { - true - } - - fn write_all(this: &mut Cursor, buf: &[u8]) -> io::Result<()> { - let (pos, inner) = this.into_parts_mut(); - vec_write_all(pos, inner, buf)?; - Ok(()) - } - - fn write_all_vectored(this: &mut Cursor, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - let (pos, inner) = this.into_parts_mut(); - vec_write_all_vectored(pos, inner, bufs)?; - Ok(()) - } - - #[inline] - fn flush(_this: &mut Cursor) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl WriteThroughCursor for Vec -where - A: Allocator, -{ - fn write(this: &mut Cursor, buf: &[u8]) -> io::Result { - let (pos, inner) = this.into_parts_mut(); - vec_write_all(pos, inner, buf) - } - - fn write_vectored(this: &mut Cursor, bufs: &[IoSlice<'_>]) -> io::Result { - let (pos, inner) = this.into_parts_mut(); - vec_write_all_vectored(pos, inner, bufs) - } - - #[inline] - fn is_write_vectored(_this: &Cursor) -> bool { - true - } - - fn write_all(this: &mut Cursor, buf: &[u8]) -> io::Result<()> { - let (pos, inner) = this.into_parts_mut(); - vec_write_all(pos, inner, buf)?; - Ok(()) - } - - fn write_all_vectored(this: &mut Cursor, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - let (pos, inner) = this.into_parts_mut(); - vec_write_all_vectored(pos, inner, bufs)?; - Ok(()) - } - - #[inline] - fn flush(_this: &mut Cursor) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "cursor_box_slice", since = "1.5.0")] -impl WriteThroughCursor for Box<[u8], A> -where - A: Allocator, -{ - #[inline] - fn write(this: &mut Cursor, buf: &[u8]) -> io::Result { - let (pos, inner) = this.into_parts_mut(); - slice_write(pos, inner, buf) - } - - #[inline] - fn write_vectored(this: &mut Cursor, bufs: &[IoSlice<'_>]) -> io::Result { - let (pos, inner) = this.into_parts_mut(); - slice_write_vectored(pos, inner, bufs) - } - - #[inline] - fn is_write_vectored(_this: &Cursor) -> bool { - true - } - - #[inline] - fn write_all(this: &mut Cursor, buf: &[u8]) -> io::Result<()> { - let (pos, inner) = this.into_parts_mut(); - slice_write_all(pos, inner, buf) - } - - #[inline] - fn write_all_vectored(this: &mut Cursor, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - let (pos, inner) = this.into_parts_mut(); - slice_write_all_vectored(pos, inner, bufs) - } - - #[inline] - fn flush(_this: &mut Cursor) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "cursor_array", since = "1.61.0")] -impl Write for Cursor<[u8; N]> { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - let (pos, inner) = self.into_parts_mut(); - slice_write(pos, inner, buf) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let (pos, inner) = self.into_parts_mut(); - slice_write_vectored(pos, inner, bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - let (pos, inner) = self.into_parts_mut(); - slice_write_all(pos, inner, buf) - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - let (pos, inner) = self.into_parts_mut(); - slice_write_all_vectored(pos, inner, bufs) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 08bb34376b075..61f82828149aa 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -3,9 +3,9 @@ mod tests; use crate::alloc::Allocator; use crate::collections::VecDeque; -use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Write}; +use crate::io::{self, BorrowedCursor, BufRead, IoSliceMut, Read}; use crate::sync::Arc; -use crate::{cmp, fmt, mem, str}; +use crate::{cmp, str}; // ============================================================================= // Forwarding implementations @@ -53,43 +53,6 @@ impl Read for &mut R { } } #[stable(feature = "rust1", since = "1.0.0")] -impl Write for &mut W { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - (**self).write(buf) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (**self).write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - (**self).is_write_vectored() - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - (**self).flush() - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - (**self).write_all(buf) - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - (**self).write_all_vectored(bufs) - } - - #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - (**self).write_fmt(fmt) - } -} -#[stable(feature = "rust1", since = "1.0.0")] impl BufRead for &mut B { #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { @@ -165,43 +128,6 @@ impl Read for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl Write for Box { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - (**self).write(buf) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (**self).write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - (**self).is_write_vectored() - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - (**self).flush() - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - (**self).write_all(buf) - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - (**self).write_all_vectored(bufs) - } - - #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - (**self).write_fmt(fmt) - } -} -#[stable(feature = "rust1", since = "1.0.0")] impl BufRead for Box { #[inline] fn fill_buf(&mut self) -> io::Result<&[u8]> { @@ -362,108 +288,6 @@ impl BufRead for &[u8] { } } -/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting -/// its data. -/// -/// Note that writing updates the slice to point to the yet unwritten part. -/// The slice will be empty when it has been completely overwritten. -/// -/// If the number of bytes to be written exceeds the size of the slice, write operations will -/// return short writes: ultimately, `Ok(0)`; in this situation, `write_all` returns an error of -/// kind `ErrorKind::WriteZero`. -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for &mut [u8] { - #[inline] - fn write(&mut self, data: &[u8]) -> io::Result { - let amt = cmp::min(data.len(), self.len()); - let (a, b) = mem::take(self).split_at_mut(amt); - a.copy_from_slice(&data[..amt]); - *self = b; - Ok(amt) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let mut nwritten = 0; - for buf in bufs { - nwritten += self.write(buf)?; - if self.is_empty() { - break; - } - } - - Ok(nwritten) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, data: &[u8]) -> io::Result<()> { - if self.write(data)? < data.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - for buf in bufs { - if self.write(buf)? < buf.len() { - return Err(io::Error::WRITE_ALL_EOF); - } - } - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -/// Write is implemented for `Vec` by appending to the vector. -/// The vector will grow as needed. -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Vec { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.extend_from_slice(buf); - Ok(buf.len()) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let len = bufs.iter().map(|b| b.len()).sum(); - self.reserve(len); - for buf in bufs { - self.extend_from_slice(buf); - } - Ok(len) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.extend_from_slice(buf); - Ok(()) - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.write_vectored(bufs)?; - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - /// Read is implemented for `VecDeque` by consuming bytes from the front of the `VecDeque`. #[stable(feature = "vecdeque_read_write", since = "1.63.0")] impl Read for VecDeque { @@ -573,96 +397,6 @@ impl BufRead for VecDeque { } } -/// Write is implemented for `VecDeque` by appending to the `VecDeque`, growing it as needed. -#[stable(feature = "vecdeque_read_write", since = "1.63.0")] -impl Write for VecDeque { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.extend(buf); - Ok(buf.len()) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let len = bufs.iter().map(|b| b.len()).sum(); - self.reserve(len); - for buf in bufs { - self.extend(&**buf); - } - Ok(len) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.extend(buf); - Ok(()) - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.write_vectored(bufs)?; - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[unstable(feature = "read_buf", issue = "78485")] -impl<'a> io::Write for core::io::BorrowedCursor<'a, u8> { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - let amt = cmp::min(buf.len(), self.capacity()); - self.append(&buf[..amt]); - Ok(amt) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let mut nwritten = 0; - for buf in bufs { - let n = self.write(buf)?; - nwritten += n; - if n < buf.len() { - break; - } - } - Ok(nwritten) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - if self.write(buf)? < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - for buf in bufs { - if self.write(buf)? < buf.len() { - return Err(io::Error::WRITE_ALL_EOF); - } - } - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - #[stable(feature = "io_traits_arc", since = "1.73.0")] impl Read for Arc where @@ -709,44 +443,3 @@ where (&**self).read_buf_exact(cursor) } } -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Write for Arc -where - for<'a> &'a W: Write, - W: crate::io::IoHandle, -{ - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - (&**self).write(buf) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (&**self).write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - (&**self).is_write_vectored() - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - (&**self).flush() - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - (&**self).write_all(buf) - } - - #[inline] - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - (&**self).write_all_vectored(bufs) - } - - #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - (&**self).write_fmt(fmt) - } -} diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 38c8120d66fc6..798997b2f7e72 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -310,9 +310,10 @@ pub use alloc_crate::io::const_error; pub use alloc_crate::io::{BorrowedBuf, BorrowedCursor}; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::io::{ - Chain, Empty, Error, ErrorKind, Repeat, Result, Seek, SeekFrom, Sink, Take, empty, repeat, sink, + Chain, Empty, Error, ErrorKind, Repeat, Result, Seek, SeekFrom, Sink, Take, Write, empty, + repeat, sink, }; -pub(crate) use alloc_crate::io::{IoHandle, stream_len_default}; +pub(crate) use alloc_crate::io::{IoHandle, default_write_vectored, stream_len_default}; #[stable(feature = "iovec", since = "1.36.0")] pub use alloc_crate::io::{IoSlice, IoSliceMut}; use alloc_crate::io::{OsFunctions, SizeHint}; @@ -338,7 +339,7 @@ pub use self::{ stdio::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout}, }; use crate::mem::MaybeUninit; -use crate::{cmp, fmt, slice, str}; +use crate::{cmp, slice, str}; mod buffered; pub(crate) mod copy; @@ -549,14 +550,6 @@ where read(buf) } -pub(crate) fn default_write_vectored(write: F, bufs: &[IoSlice<'_>]) -> Result -where - F: FnOnce(&[u8]) -> Result, -{ - let buf = bufs.iter().find(|b| !b.is_empty()).map_or(&[][..], |b| &**b); - write(buf) -} - pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [u8]) -> Result<()> { while !buf.is_empty() { match this.read(buf) { @@ -600,47 +593,6 @@ pub(crate) fn default_read_buf_exact( Ok(()) } -pub(crate) fn default_write_fmt( - this: &mut W, - args: fmt::Arguments<'_>, -) -> Result<()> { - // Create a shim which translates a `Write` to a `fmt::Write` and saves off - // I/O errors, instead of discarding them. - struct Adapter<'a, T: ?Sized + 'a> { - inner: &'a mut T, - error: Result<()>, - } - - impl fmt::Write for Adapter<'_, T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.inner.write_all(s.as_bytes()) { - Ok(()) => Ok(()), - Err(e) => { - self.error = Err(e); - Err(fmt::Error) - } - } - } - } - - let mut output = Adapter { inner: this, error: Ok(()) }; - match fmt::write(&mut output, args) { - Ok(()) => Ok(()), - Err(..) => { - // Check whether the error came from the underlying `Write`. - if output.error.is_err() { - output.error - } else { - // This shouldn't happen: the underlying stream did not error, - // but somehow the formatter still errored? - panic!( - "a formatting trait implementation returned an error when the underlying stream did not" - ); - } - } - } -} - /// The `Read` trait allows for reading bytes from a source. /// /// Implementors of the `Read` trait are called 'readers'. @@ -1403,365 +1355,6 @@ pub fn read_to_string(mut reader: R) -> Result { Ok(buf) } -/// A trait for objects which are byte-oriented sinks. -/// -/// Implementors of the `Write` trait are sometimes called 'writers'. -/// -/// Writers are defined by two required methods, [`write`] and [`flush`]: -/// -/// * The [`write`] method will attempt to write some data into the object, -/// returning how many bytes were successfully written. -/// -/// * The [`flush`] method is useful for adapters and explicit buffers -/// themselves for ensuring that all buffered data has been pushed out to the -/// 'true sink'. -/// -/// Writers are intended to be composable with one another. Many implementors -/// throughout [`std::io`] take and provide types which implement the `Write` -/// trait. -/// -/// [`write`]: Write::write -/// [`flush`]: Write::flush -/// [`std::io`]: self -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// fn main() -> std::io::Result<()> { -/// let data = b"some bytes"; -/// -/// let mut pos = 0; -/// let mut buffer = File::create("foo.txt")?; -/// -/// while pos < data.len() { -/// let bytes_written = buffer.write(&data[pos..])?; -/// pos += bytes_written; -/// } -/// Ok(()) -/// } -/// ``` -/// -/// The trait also provides convenience methods like [`write_all`], which calls -/// `write` in a loop until its entire input has been written. -/// -/// [`write_all`]: Write::write_all -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(notable_trait)] -#[cfg_attr(not(test), rustc_diagnostic_item = "IoWrite")] -pub trait Write { - /// Writes a buffer into this writer, returning how many bytes were written. - /// - /// This function will attempt to write the entire contents of `buf`, but - /// the entire write might not succeed, or the write may also generate an - /// error. Typically, a call to `write` represents one attempt to write to - /// any wrapped object. - /// - /// Calls to `write` are not guaranteed to block waiting for data to be - /// written, and a write which would otherwise block can be indicated through - /// an [`Err`] variant. - /// - /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. - /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`. - /// A return value of `Ok(0)` typically means that the underlying object is - /// no longer able to accept bytes and will likely not be able to in the - /// future as well, or that the buffer provided is empty. - /// - /// # Errors - /// - /// Each call to `write` may generate an I/O error indicating that the - /// operation could not be completed. If an error is returned then no bytes - /// in the buffer were written to this writer. - /// - /// It is **not** considered an error if the entire buffer could not be - /// written to this writer. - /// - /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the - /// write operation should be retried if there is nothing else to do. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// // Writes some prefix of the byte string, not necessarily all of it. - /// buffer.write(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - /// - /// [`Ok(n)`]: Ok - #[stable(feature = "rust1", since = "1.0.0")] - fn write(&mut self, buf: &[u8]) -> Result; - - /// Like [`write`], except that it writes from a slice of buffers. - /// - /// Data is copied from each buffer in order, with the final buffer - /// read from possibly being only partially consumed. This method must - /// behave as a call to [`write`] with the buffers concatenated would. - /// - /// The default implementation calls [`write`] with either the first nonempty - /// buffer provided, or an empty one if none exists. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::IoSlice; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let data1 = [1; 8]; - /// let data2 = [15; 8]; - /// let io_slice1 = IoSlice::new(&data1); - /// let io_slice2 = IoSlice::new(&data2); - /// - /// let mut buffer = File::create("foo.txt")?; - /// - /// // Writes some prefix of the byte string, not necessarily all of it. - /// buffer.write_vectored(&[io_slice1, io_slice2])?; - /// Ok(()) - /// } - /// ``` - /// - /// [`write`]: Write::write - #[stable(feature = "iovec", since = "1.36.0")] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - default_write_vectored(|b| self.write(b), bufs) - } - - /// Determines if this `Write`r has an efficient [`write_vectored`] - /// implementation. - /// - /// If a `Write`r does not override the default [`write_vectored`] - /// implementation, code using it may want to avoid the method all together - /// and coalesce writes into a single buffer for higher performance. - /// - /// The default implementation returns `false`. - /// - /// [`write_vectored`]: Write::write_vectored - #[unstable(feature = "can_vector", issue = "69941")] - fn is_write_vectored(&self) -> bool { - false - } - - /// Flushes this output stream, ensuring that all intermediately buffered - /// contents reach their destination. - /// - /// # Errors - /// - /// It is considered an error if not all bytes could be written due to - /// I/O errors or EOF being reached. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::io::BufWriter; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = BufWriter::new(File::create("foo.txt")?); - /// - /// buffer.write_all(b"some bytes")?; - /// buffer.flush()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn flush(&mut self) -> Result<()>; - - /// Attempts to write an entire buffer into this writer. - /// - /// This method will continuously call [`write`] until there is no more data - /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is - /// returned. This method will not return until the entire buffer has been - /// successfully written or such an error occurs. The first error that is - /// not of [`ErrorKind::Interrupted`] kind generated from this method will be - /// returned. - /// - /// If the buffer contains no data, this will never call [`write`]. - /// - /// # Errors - /// - /// This function will return the first error of - /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns. - /// - /// [`write`]: Write::write - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// buffer.write_all(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { - while !buf.is_empty() { - match self.write(buf) { - Ok(0) => { - return Err(Error::WRITE_ALL_EOF); - } - Ok(n) => buf = &buf[n..], - Err(ref e) if e.is_interrupted() => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - - /// Attempts to write multiple buffers into this writer. - /// - /// This method will continuously call [`write_vectored`] until there is no - /// more data to be written or an error of non-[`ErrorKind::Interrupted`] - /// kind is returned. This method will not return until all buffers have - /// been successfully written or such an error occurs. The first error that - /// is not of [`ErrorKind::Interrupted`] kind generated from this method - /// will be returned. - /// - /// If the buffer contains no data, this will never call [`write_vectored`]. - /// - /// # Notes - /// - /// Unlike [`write_vectored`], this takes a *mutable* reference to - /// a slice of [`IoSlice`]s, not an immutable one. That's because we need to - /// modify the slice to keep track of the bytes already written. - /// - /// Once this function returns, the contents of `bufs` are unspecified, as - /// this depends on how many calls to [`write_vectored`] were necessary. It is - /// best to understand this function as taking ownership of `bufs` and to - /// not use `bufs` afterwards. The underlying buffers, to which the - /// [`IoSlice`]s point (but not the [`IoSlice`]s themselves), are unchanged and - /// can be reused. - /// - /// [`write_vectored`]: Write::write_vectored - /// - /// # Examples - /// - /// ``` - /// #![feature(write_all_vectored)] - /// # fn main() -> std::io::Result<()> { - /// - /// use std::io::{Write, IoSlice}; - /// - /// let mut writer = Vec::new(); - /// let bufs = &mut [ - /// IoSlice::new(&[1]), - /// IoSlice::new(&[2, 3]), - /// IoSlice::new(&[4, 5, 6]), - /// ]; - /// - /// writer.write_all_vectored(bufs)?; - /// // Note: the contents of `bufs` is now undefined, see the Notes section. - /// - /// assert_eq!(writer, &[1, 2, 3, 4, 5, 6]); - /// # Ok(()) } - /// ``` - #[unstable(feature = "write_all_vectored", issue = "70436")] - fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> { - // Guarantee that bufs is empty if it contains no data, - // to avoid calling write_vectored if there is no data to be written. - IoSlice::advance_slices(&mut bufs, 0); - while !bufs.is_empty() { - match self.write_vectored(bufs) { - Ok(0) => { - return Err(Error::WRITE_ALL_EOF); - } - Ok(n) => IoSlice::advance_slices(&mut bufs, n), - Err(ref e) if e.is_interrupted() => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - - /// Writes a formatted string into this writer, returning any error - /// encountered. - /// - /// This method is primarily used to interface with the - /// [`format_args!()`] macro, and it is rare that this should - /// explicitly be called. The [`write!()`] macro should be favored to - /// invoke this method instead. - /// - /// This function internally uses the [`write_all`] method on - /// this trait and hence will continuously write data so long as no errors - /// are received. This also means that partial writes are not indicated in - /// this signature. - /// - /// [`write_all`]: Write::write_all - /// - /// # Errors - /// - /// This function will return any I/O error reported while formatting. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// // this call - /// write!(buffer, "{:.*}", 2, 1.234567)?; - /// // turns into this: - /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> { - if let Some(s) = args.as_statically_known_str() { - self.write_all(s.as_bytes()) - } else { - default_write_fmt(self, args) - } - } - - /// Creates a "by reference" adapter for this instance of `Write`. - /// - /// The returned adapter also implements `Write` and will simply borrow this - /// current writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::Write; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; - /// - /// let reference = buffer.by_ref(); - /// - /// // we can use reference just like our original buffer - /// reference.write_all(b"some bytes")?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn by_ref(&mut self) -> &mut Self - where - Self: Sized, - { - self - } -} - fn read_until(r: &mut R, delim: u8, buf: &mut Vec) -> Result { let mut read = 0; loop { diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index ce2137f9567c7..ac3e0f84d1e80 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -3,10 +3,7 @@ #[cfg(test)] mod tests; -use crate::fmt; -use crate::io::{ - self, BorrowedCursor, BufRead, Empty, IoSlice, IoSliceMut, Read, Repeat, Sink, Write, -}; +use crate::io::{self, BorrowedCursor, BufRead, Empty, IoSliceMut, Read, Repeat}; #[stable(feature = "rust1", since = "1.0.0")] impl Read for Empty { @@ -83,84 +80,6 @@ impl BufRead for Empty { } } -#[stable(feature = "empty_write", since = "1.73.0")] -impl Write for Empty { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total_len = bufs.iter().map(|b| b.len()).sum(); - Ok(total_len) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "empty_write", since = "1.73.0")] -impl Write for &Empty { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total_len = bufs.iter().map(|b| b.len()).sum(); - Ok(total_len) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Read for Repeat { #[inline] @@ -213,81 +132,3 @@ impl Read for Repeat { true } } - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Sink { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total_len = bufs.iter().map(|b| b.len()).sum(); - Ok(total_len) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "write_mt", since = "1.48.0")] -impl Write for &Sink { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total_len = bufs.iter().map(|b| b.len()).sum(); - Ok(total_len) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index db37df63c5763..7cf576ecd8803 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -322,6 +322,7 @@ #![feature(borrowed_buf_init)] #![feature(bstr)] #![feature(bstr_internals)] +#![feature(can_vector)] #![feature(cast_maybe_uninit)] #![feature(char_internals)] #![feature(clone_to_uninit)] @@ -389,6 +390,7 @@ #![feature(ub_checks)] #![feature(uint_carryless_mul)] #![feature(used_with_arg)] +#![feature(write_all_vectored)] // tidy-alphabetical-end // // Library features (alloc): diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index c226a0dc2403f..4ed5c43616a29 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -12,7 +12,7 @@ use crate::fs; use crate::marker::PhantomData; use crate::mem::ManuallyDrop; #[cfg(not(any( - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "emscripten")), target_env = "sgx", target_os = "hermit", target_os = "trusty", @@ -104,7 +104,7 @@ impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. #[cfg(not(any( - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "emscripten")), target_os = "hermit", target_os = "trusty", target_os = "motor" @@ -131,7 +131,11 @@ impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. - #[cfg(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty"))] + #[cfg(any( + all(target_arch = "wasm32", not(target_os = "emscripten")), + target_os = "hermit", + target_os = "trusty" + ))] #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> io::Result { Err(io::Error::UNSUPPORTED_PLATFORM) diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 0385e5513ea08..19fdf8ba2fb03 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -214,7 +214,7 @@ fn replace_stdio_fd(this: BorrowedFd<'_>, other: OwnedFd) -> io::Result<()> { cvt(unsafe { libc::__wasilibc_fd_renumber(other.as_raw_fd(), this.as_raw_fd()) }).map(|_| ()) } not(any( - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "emscripten")), target_os = "hermit", target_os = "trusty", target_os = "motor" diff --git a/package.json b/package.json index a4f6e18bcf422..6bd8a5be6a105 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "browser-ui-test": "^0.24.0", + "browser-ui-test": "^0.24.1", "es-check": "^9.4.4", "eslint": "^8.57.1", "typescript": "^5.8.3" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/check-miri.sh b/src/ci/docker/host-x86_64/x86_64-gnu-miri/check-miri.sh index c2a5b308b3284..0ccd364be21bb 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-miri/check-miri.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/check-miri.sh @@ -15,14 +15,6 @@ if [ -z "${PR_CI_JOB:-}" ]; then else python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri fi -# We re-run the test suite for a chance to find bugs in the intrinsic fallback bodies and in MIR -# optimizations. This can miss UB, so we only run the "pass" tests. We need to enable debug -# assertions as `-O` disables them but some tests rely on them. We also set a cfg flag so tests can -# adjust their expectations if needed. This can change the output of the tests so we ignore that, -# we only ensure that all assertions still pass. -MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zmir-opt-level=4 -Cdebug-assertions=yes" \ - MIRI_SKIP_UI_CHECKS=1 \ - python3 "$X_PY" test --stage 2 src/tools/miri -- tests/pass tests/panic # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. case $HOST_TARGET in diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index ef6c6f0f586ae..a07c2029f4b38 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.25" +wasm-component-ld = "0.5.26" diff --git a/tests/mir-opt/coroutine/async_drop.array-{closure#0}.ElaborateDrops.diff b/tests/mir-opt/coroutine/async_drop.array-{closure#0}.ElaborateDrops.diff new file mode 100644 index 0000000000000..bad684407ae57 --- /dev/null +++ b/tests/mir-opt/coroutine/async_drop.array-{closure#0}.ElaborateDrops.diff @@ -0,0 +1,220 @@ +- // MIR for `array::{closure#0}` before ElaborateDrops ++ // MIR for `array::{closure#0}` after ElaborateDrops + + fn array::{closure#0}(_1: {async fn body of array()}, _2: std::future::ResumeTy) -> () + yields () + { + debug _task_context => _2; + let mut _0: (); + let _3: [AsyncInt; 2]; + let mut _4: AsyncInt; + let mut _5: AsyncInt; ++ let mut _6: impl std::future::Future; ++ let mut _7: std::future::ResumeTy; ++ let mut _8: std::task::Poll<()>; ++ let mut _9: isize; ++ let mut _10: std::pin::Pin<&mut impl std::future::Future>; ++ let mut _11: &mut std::task::Context<'_>; ++ let mut _12: std::future::ResumeTy; ++ let mut _13: &mut impl std::future::Future; ++ let mut _14: std::future::ResumeTy; ++ let mut _15: std::task::Poll<()>; ++ let mut _16: isize; ++ let mut _17: std::pin::Pin<&mut impl std::future::Future>; ++ let mut _18: &mut std::task::Context<'_>; ++ let mut _19: std::future::ResumeTy; ++ let mut _20: &mut impl std::future::Future; ++ let mut _21: std::pin::Pin<&mut [AsyncInt; 2]>; ++ let mut _22: &mut [AsyncInt; 2]; + scope 1 { + debug array => _3; + } + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = AsyncInt(const 1_i32); + StorageLive(_5); + _5 = AsyncInt(const 2_i32); + _3 = [move _4, move _5]; +- drop(_5) -> [return: bb1, unwind: bb9, drop: bb5]; ++ goto -> bb1; + } + + bb1: { + StorageDead(_5); +- drop(_4) -> [return: bb2, unwind: bb10, drop: bb6]; ++ goto -> bb2; + } + + bb2: { + StorageDead(_4); + _0 = const (); +- drop(_3) -> [return: bb3, unwind: bb11, drop: bb7]; ++ goto -> bb34; + } + + bb3: { + StorageDead(_3); +- drop(_1) -> [return: bb4, drop: bb8, unwind continue]; ++ drop(_1) -> [return: bb4, unwind: bb12]; + } + + bb4: { + return; + } + + bb5: { + StorageDead(_5); +- drop(_4) -> [return: bb6, unwind: bb13]; ++ goto -> bb6; + } + + bb6: { + StorageDead(_4); + goto -> bb7; + } + + bb7: { + StorageDead(_3); +- drop(_1) -> [return: bb8, unwind continue]; ++ goto -> bb8; + } + + bb8: { + coroutine_drop; + } + + bb9 (cleanup): { + StorageDead(_5); +- drop(_4) -> [return: bb10, unwind terminate(cleanup)]; ++ goto -> bb10; + } + + bb10 (cleanup): { + StorageDead(_4); + goto -> bb11; + } + + bb11 (cleanup): { + StorageDead(_3); + drop(_1) -> [return: bb12, unwind terminate(cleanup)]; + } + + bb12 (cleanup): { + resume; + } + + bb13 (cleanup): { + StorageDead(_4); + StorageDead(_3); +- drop(_1) -> [return: bb12, unwind terminate(cleanup)]; ++ goto -> bb12; ++ } ++ ++ bb14: { ++ StorageDead(_6); ++ goto -> bb3; ++ } ++ ++ bb15: { ++ StorageDead(_6); ++ goto -> bb7; ++ } ++ ++ bb16 (cleanup): { ++ StorageDead(_6); ++ goto -> bb11; ++ } ++ ++ bb17: { ++ assert(const false, "`async fn` resumed after async drop") -> [success: bb17, unwind: bb16]; ++ } ++ ++ bb18: { ++ _2 = move _7; ++ StorageDead(_7); ++ goto -> bb17; ++ } ++ ++ bb19: { ++ _2 = move _7; ++ StorageDead(_7); ++ goto -> bb25; ++ } ++ ++ bb20: { ++ StorageLive(_7); ++ _7 = yield(const ()) -> [resume: bb18, drop: bb19]; ++ } ++ ++ bb21: { ++ unreachable; ++ } ++ ++ bb22: { ++ _9 = discriminant(_8); ++ switchInt(move _9) -> [0: bb15, 1: bb20, otherwise: bb21]; ++ } ++ ++ bb23: { ++ _8 = as Future>::poll(move _10, move _11) -> [return: bb22, unwind: bb16]; ++ } ++ ++ bb24: { ++ _12 = move _2; ++ _11 = std::future::get_context::<'_, '_>(move _12) -> [return: bb23, unwind: bb16]; ++ } ++ ++ bb25: { ++ _13 = &mut _6; ++ _10 = Pin::<&mut impl Future>::new_unchecked(move _13) -> [return: bb24, unwind: bb16]; ++ } ++ ++ bb26: { ++ _2 = move _14; ++ StorageDead(_14); ++ goto -> bb32; ++ } ++ ++ bb27: { ++ _2 = move _14; ++ StorageDead(_14); ++ goto -> bb25; ++ } ++ ++ bb28: { ++ StorageLive(_14); ++ _14 = yield(const ()) -> [resume: bb26, drop: bb27]; ++ } ++ ++ bb29: { ++ _16 = discriminant(_15); ++ switchInt(move _16) -> [0: bb14, 1: bb28, otherwise: bb21]; ++ } ++ ++ bb30: { ++ _15 = as Future>::poll(move _17, move _18) -> [return: bb29, unwind: bb16]; ++ } ++ ++ bb31: { ++ _19 = move _2; ++ _18 = std::future::get_context::<'_, '_>(move _19) -> [return: bb30, unwind: bb16]; ++ } ++ ++ bb32: { ++ _20 = &mut _6; ++ _17 = Pin::<&mut impl Future>::new_unchecked(move _20) -> [return: bb31, unwind: bb16]; ++ } ++ ++ bb33: { ++ StorageLive(_6); ++ _6 = async_drop_in_place::<[AsyncInt; 2]>(copy (_21.0: &mut [AsyncInt; 2])) -> [return: bb32, unwind: bb16]; ++ } ++ ++ bb34: { ++ _22 = &mut _3; ++ _21 = Pin::<&mut [AsyncInt; 2]>::new_unchecked(move _22) -> [return: bb33, unwind: bb11]; + } + } + diff --git a/tests/mir-opt/coroutine/async_drop.array-{closure#0}.StateTransform.diff b/tests/mir-opt/coroutine/async_drop.array-{closure#0}.StateTransform.diff new file mode 100644 index 0000000000000..5b4e617251396 --- /dev/null +++ b/tests/mir-opt/coroutine/async_drop.array-{closure#0}.StateTransform.diff @@ -0,0 +1,273 @@ +- // MIR for `array::{closure#0}` before StateTransform ++ // MIR for `array::{closure#0}` after StateTransform + +- fn array::{closure#0}(_1: {async fn body of array()}, _2: std::future::ResumeTy) -> () +- yields () +- { +- debug _task_context => _2; +- let mut _0: (); ++ fn array::{closure#0}(_1: Pin<&mut {async fn body of array()}>, _2: &mut Context<'_>) -> Poll<()> { ++ coroutine layout { ++ field _s0: (); ++ field _s1: [AsyncInt; 2]; ++ field _s2: impl Future; ++ variant_fields = { ++ Unresumed(0): [], ++ Returned (1): [], ++ Panicked (2): [], ++ Suspend0 (3): [_s1, _s2], ++ Suspend1 (4): [_s0, _s1, _s2], ++ } ++ storage_conflicts = BitMatrix(3x3) {(_s0, _s0), (_s0, _s1), (_s0, _s2), (_s1, _s0), (_s1, _s1), (_s1, _s2), (_s2, _s0), (_s2, _s1), (_s2, _s2)} ++ } ++ debug _task_context => _26; ++ coroutine debug array => _s1; ++ let mut _0: std::task::Poll<()>; + let _3: [AsyncInt; 2]; + let mut _4: AsyncInt; + let mut _5: AsyncInt; + let mut _6: impl std::future::Future; + let mut _7: std::future::ResumeTy; + let mut _8: std::task::Poll<()>; + let mut _9: isize; + let mut _10: std::pin::Pin<&mut impl std::future::Future>; + let mut _11: &mut std::task::Context<'_>; + let mut _12: std::future::ResumeTy; + let mut _13: &mut impl std::future::Future; + let mut _14: std::future::ResumeTy; + let mut _15: std::task::Poll<()>; + let mut _16: isize; + let mut _17: std::pin::Pin<&mut impl std::future::Future>; + let mut _18: &mut std::task::Context<'_>; + let mut _19: std::future::ResumeTy; + let mut _20: &mut impl std::future::Future; + let mut _21: std::pin::Pin<&mut [AsyncInt; 2]>; + let mut _22: &mut [AsyncInt; 2]; ++ let mut _23: (); ++ let mut _24: u32; ++ let mut _25: &mut {async fn body of array()}; ++ let mut _26: std::future::ResumeTy; ++ let mut _27: std::ptr::NonNull>; + scope 1 { +- debug array => _3; ++ debug array => (((*_25) as variant#4).1: [AsyncInt; 2]); + } + + bb0: { +- StorageLive(_3); +- StorageLive(_4); +- _4 = AsyncInt(const 1_i32); +- StorageLive(_5); +- _5 = AsyncInt(const 2_i32); +- _3 = [move _4, move _5]; +- goto -> bb1; ++ _27 = move _2 as std::ptr::NonNull> (Transmute); ++ _26 = std::future::ResumeTy(move _27); ++ _25 = copy (_1.0: &mut {async fn body of array()}); ++ _24 = discriminant((*_25)); ++ switchInt(move _24) -> [0: bb26, 1: bb25, 2: bb24, 3: bb22, 4: bb23, otherwise: bb11]; + } + + bb1: { + StorageDead(_5); + goto -> bb2; + } + + bb2: { + StorageDead(_4); +- _0 = const (); +- goto -> bb29; ++ (((*_25) as variant#4).0: ()) = const (); ++ goto -> bb19; + } + + bb3: { +- StorageDead(_3); +- drop(_1) -> [return: bb4, unwind: bb8]; ++ nop; ++ goto -> bb20; + } + + bb4: { ++ _0 = Poll::<()>::Ready(move (((*_25) as variant#4).0: ())); ++ discriminant((*_25)) = 1; + return; + } + +- bb5: { +- StorageDead(_3); ++ bb5 (cleanup): { ++ nop; + goto -> bb6; + } + +- bb6: { +- coroutine_drop; ++ bb6 (cleanup): { ++ goto -> bb21; + } + +- bb7 (cleanup): { +- StorageDead(_3); +- drop(_1) -> [return: bb8, unwind terminate(cleanup)]; ++ bb7: { ++ nop; ++ goto -> bb3; + } + + bb8 (cleanup): { +- resume; ++ nop; ++ goto -> bb5; + } + + bb9: { +- StorageDead(_6); +- goto -> bb3; ++ assert(const false, "`async fn` resumed after async drop") -> [success: bb9, unwind: bb8]; + } + + bb10: { +- StorageDead(_6); +- goto -> bb5; ++ _26 = move _7; ++ StorageDead(_7); ++ goto -> bb9; + } + +- bb11 (cleanup): { +- StorageDead(_6); +- goto -> bb7; ++ bb11: { ++ unreachable; + } + + bb12: { +- assert(const false, "`async fn` resumed after async drop") -> [success: bb12, unwind: bb11]; ++ _26 = move _14; ++ StorageDead(_14); ++ goto -> bb17; + } + + bb13: { +- _2 = move _7; +- StorageDead(_7); +- goto -> bb12; ++ StorageLive(_14); ++ _0 = Poll::<()>::Pending; ++ StorageDead(_14); ++ discriminant((*_25)) = 4; ++ return; + } + + bb14: { +- _2 = move _7; +- StorageDead(_7); +- goto -> bb20; ++ _16 = discriminant(_15); ++ switchInt(move _16) -> [0: bb7, 1: bb13, otherwise: bb11]; + } + + bb15: { +- StorageLive(_7); +- _7 = yield(const ()) -> [resume: bb13, drop: bb14]; ++ _15 = as Future>::poll(move _17, move _18) -> [return: bb14, unwind: bb8]; + } + + bb16: { +- unreachable; ++ _19 = move _26; ++ _18 = copy (_19.0: std::ptr::NonNull>) as &mut std::task::Context<'_> (Transmute); ++ goto -> bb15; + } + + bb17: { +- _9 = discriminant(_8); +- switchInt(move _9) -> [0: bb10, 1: bb15, otherwise: bb16]; ++ _20 = &mut (((*_25) as variant#4).2: impl std::future::Future); ++ _17 = Pin::<&mut impl Future>::new_unchecked(move _20) -> [return: bb16, unwind: bb8]; + } + + bb18: { +- _8 = as Future>::poll(move _10, move _11) -> [return: bb17, unwind: bb11]; ++ nop; ++ (((*_25) as variant#4).2: impl std::future::Future) = async_drop_in_place::<[AsyncInt; 2]>(copy (_21.0: &mut [AsyncInt; 2])) -> [return: bb17, unwind: bb8]; + } + + bb19: { +- _12 = move _2; +- _11 = std::future::get_context::<'_, '_>(move _12) -> [return: bb18, unwind: bb11]; ++ _22 = &mut (((*_25) as variant#4).1: [AsyncInt; 2]); ++ _21 = Pin::<&mut [AsyncInt; 2]>::new_unchecked(move _22) -> [return: bb18, unwind: bb5]; + } + + bb20: { +- _13 = &mut _6; +- _10 = Pin::<&mut impl Future>::new_unchecked(move _13) -> [return: bb19, unwind: bb11]; ++ goto -> bb4; + } + +- bb21: { +- _2 = move _14; +- StorageDead(_14); +- goto -> bb27; ++ bb21 (cleanup): { ++ discriminant((*_25)) = 2; ++ resume; + } + + bb22: { +- _2 = move _14; +- StorageDead(_14); +- goto -> bb20; ++ StorageLive(_7); ++ _7 = move _26; ++ goto -> bb10; + } + + bb23: { + StorageLive(_14); +- _14 = yield(const ()) -> [resume: bb21, drop: bb22]; ++ _14 = move _26; ++ goto -> bb12; + } + + bb24: { +- _16 = discriminant(_15); +- switchInt(move _16) -> [0: bb9, 1: bb23, otherwise: bb16]; ++ assert(const false, "`async fn` resumed after panicking") -> [success: bb24, unwind continue]; + } + + bb25: { +- _15 = as Future>::poll(move _17, move _18) -> [return: bb24, unwind: bb11]; ++ assert(const false, "`async fn` resumed after completion") -> [success: bb25, unwind continue]; + } + + bb26: { +- _19 = move _2; +- _18 = std::future::get_context::<'_, '_>(move _19) -> [return: bb25, unwind: bb11]; +- } +- +- bb27: { +- _20 = &mut _6; +- _17 = Pin::<&mut impl Future>::new_unchecked(move _20) -> [return: bb26, unwind: bb11]; +- } +- +- bb28: { +- StorageLive(_6); +- _6 = async_drop_in_place::<[AsyncInt; 2]>(copy (_21.0: &mut [AsyncInt; 2])) -> [return: bb27, unwind: bb11]; +- } +- +- bb29: { +- _22 = &mut _3; +- _21 = Pin::<&mut [AsyncInt; 2]>::new_unchecked(move _22) -> [return: bb28, unwind: bb7]; ++ nop; ++ StorageLive(_4); ++ _4 = AsyncInt(const 1_i32); ++ StorageLive(_5); ++ _5 = AsyncInt(const 2_i32); ++ (((*_25) as variant#4).1: [AsyncInt; 2]) = [move _4, move _5]; ++ goto -> bb1; + } + } + diff --git a/tests/mir-opt/coroutine/async_drop.array-{closure#0}.coroutine_drop_async.0.mir b/tests/mir-opt/coroutine/async_drop.array-{closure#0}.coroutine_drop_async.0.mir new file mode 100644 index 0000000000000..9fc1ebbe39d14 --- /dev/null +++ b/tests/mir-opt/coroutine/async_drop.array-{closure#0}.coroutine_drop_async.0.mir @@ -0,0 +1,154 @@ +// MIR for `array::{closure#0}` 0 coroutine_drop_async + +fn array::{closure#0}(_1: Pin<&mut {async fn body of array()}>, _2: &mut Context<'_>) -> Poll<()> { + debug _task_context => _26; + let mut _0: std::task::Poll<()>; + let _3: [AsyncInt; 2]; + let mut _4: AsyncInt; + let mut _5: AsyncInt; + let mut _6: impl std::future::Future; + let mut _7: std::future::ResumeTy; + let mut _8: std::task::Poll<()>; + let mut _9: isize; + let mut _10: std::pin::Pin<&mut impl std::future::Future>; + let mut _11: &mut std::task::Context<'_>; + let mut _12: std::future::ResumeTy; + let mut _13: &mut impl std::future::Future; + let mut _14: std::future::ResumeTy; + let mut _15: std::task::Poll<()>; + let mut _16: isize; + let mut _17: std::pin::Pin<&mut impl std::future::Future>; + let mut _18: &mut std::task::Context<'_>; + let mut _19: std::future::ResumeTy; + let mut _20: &mut impl std::future::Future; + let mut _21: std::pin::Pin<&mut [AsyncInt; 2]>; + let mut _22: &mut [AsyncInt; 2]; + let mut _23: (); + let mut _24: u32; + let mut _25: &mut {async fn body of array()}; + let mut _26: std::future::ResumeTy; + let mut _27: std::ptr::NonNull>; + scope 1 { + debug array => (((*_25) as variant#4).1: [AsyncInt; 2]); + } + + bb0: { + _27 = move _2 as std::ptr::NonNull> (Transmute); + _26 = std::future::ResumeTy(move _27); + _25 = copy (_1.0: &mut {async fn body of array()}); + _24 = discriminant((*_25)); + switchInt(move _24) -> [0: bb16, 2: bb21, 3: bb19, 4: bb20, otherwise: bb22]; + } + + bb1: { + nop; + goto -> bb2; + } + + bb2: { + _0 = Poll::<()>::Ready(const ()); + return; + } + + bb3 (cleanup): { + nop; + goto -> bb4; + } + + bb4 (cleanup): { + goto -> bb18; + } + + bb5: { + nop; + goto -> bb1; + } + + bb6 (cleanup): { + nop; + goto -> bb3; + } + + bb7: { + _26 = move _7; + StorageDead(_7); + goto -> bb13; + } + + bb8: { + StorageLive(_7); + _0 = Poll::<()>::Pending; + StorageDead(_7); + discriminant((*_25)) = 3; + return; + } + + bb9: { + unreachable; + } + + bb10: { + _9 = discriminant(_8); + switchInt(move _9) -> [0: bb5, 1: bb8, otherwise: bb9]; + } + + bb11: { + _8 = as Future>::poll(move _10, move _11) -> [return: bb10, unwind: bb6]; + } + + bb12: { + _12 = move _26; + _11 = copy (_12.0: std::ptr::NonNull>) as &mut std::task::Context<'_> (Transmute); + goto -> bb11; + } + + bb13: { + _13 = &mut (((*_25) as variant#4).2: impl std::future::Future); + _10 = Pin::<&mut impl Future>::new_unchecked(move _13) -> [return: bb12, unwind: bb6]; + } + + bb14: { + _26 = move _14; + StorageDead(_14); + goto -> bb13; + } + + bb15: { + _0 = Poll::<()>::Ready(const ()); + return; + } + + bb16: { + goto -> bb17; + } + + bb17: { + goto -> bb15; + } + + bb18 (cleanup): { + discriminant((*_25)) = 2; + resume; + } + + bb19: { + StorageLive(_7); + _7 = move _26; + goto -> bb7; + } + + bb20: { + StorageLive(_14); + _14 = move _26; + goto -> bb14; + } + + bb21: { + assert(const false, "`async fn` resumed after panicking") -> [success: bb21, unwind continue]; + } + + bb22: { + _0 = Poll::<()>::Ready(const ()); + return; + } +} diff --git a/tests/mir-opt/coroutine/async_drop.core.future-async_drop-async_drop_in_place-{closure#0}.[AsyncInt;2].StateTransform.diff b/tests/mir-opt/coroutine/async_drop.core.future-async_drop-async_drop_in_place-{closure#0}.[AsyncInt;2].StateTransform.diff new file mode 100644 index 0000000000000..7718554895afd --- /dev/null +++ b/tests/mir-opt/coroutine/async_drop.core.future-async_drop-async_drop_in_place-{closure#0}.[AsyncInt;2].StateTransform.diff @@ -0,0 +1,357 @@ +- // MIR for `std::future::async_drop_in_place::{closure#0}` before StateTransform ++ // MIR for `std::future::async_drop_in_place::{closure#0}` after StateTransform + +- fn async_drop_in_place::{closure#0}(_1: {async fn body of async_drop_in_place<[AsyncInt; 2]>()}, _2: std::future::ResumeTy) -> () +- yields () +- { +- let mut _0: (); ++ fn async_drop_in_place::{closure#0}(_1: Pin<&mut {async fn body of async_drop_in_place<[AsyncInt; 2]>()}>, _2: &mut Context<'_>) -> Poll<()> { ++ coroutine layout { ++ field _s0: *mut [AsyncInt]; ++ field _s1: usize; ++ field _s2: usize; ++ field _s3: impl Future; ++ field _s4: impl Future; ++ variant_fields = { ++ Unresumed(0): [], ++ Returned (1): [], ++ Panicked (2): [], ++ Suspend0 (3): [_s0, _s1, _s2, _s3], ++ Suspend1 (4): [_s0, _s1, _s2, _s4], ++ Suspend2 (5): [_s0, _s1, _s2, _s4], ++ } ++ storage_conflicts = BitMatrix(5x5) {(_s0, _s0), (_s0, _s1), (_s0, _s2), (_s0, _s3), (_s0, _s4), (_s1, _s0), (_s1, _s1), (_s1, _s2), (_s1, _s3), (_s1, _s4), (_s2, _s0), (_s2, _s1), (_s2, _s2), (_s2, _s3), (_s2, _s4), (_s3, _s0), (_s3, _s1), (_s3, _s2), (_s3, _s3), (_s4, _s0), (_s4, _s1), (_s4, _s2), (_s4, _s4)} ++ } ++ let mut _0: std::task::Poll<()>; + let mut _3: &mut [AsyncInt; 2]; + let mut _4: *mut [AsyncInt; 2]; + let mut _5: *mut [AsyncInt]; + let mut _6: usize; + let mut _7: usize; + let mut _8: *mut AsyncInt; + let mut _9: bool; + let mut _10: *mut AsyncInt; + let mut _11: bool; + let mut _12: impl std::future::Future; + let mut _13: std::future::ResumeTy; + let mut _14: std::task::Poll<()>; + let mut _15: isize; + let mut _16: std::pin::Pin<&mut impl std::future::Future>; + let mut _17: &mut std::task::Context<'_>; + let mut _18: std::future::ResumeTy; + let mut _19: &mut impl std::future::Future; + let mut _20: std::pin::Pin<&mut AsyncInt>; + let mut _21: &mut AsyncInt; + let mut _22: *mut AsyncInt; + let mut _23: bool; + let mut _24: impl std::future::Future; + let mut _25: std::future::ResumeTy; + let mut _26: std::task::Poll<()>; + let mut _27: isize; + let mut _28: std::pin::Pin<&mut impl std::future::Future>; + let mut _29: &mut std::task::Context<'_>; + let mut _30: std::future::ResumeTy; + let mut _31: &mut impl std::future::Future; + let mut _32: std::future::ResumeTy; + let mut _33: std::task::Poll<()>; + let mut _34: isize; + let mut _35: std::pin::Pin<&mut impl std::future::Future>; + let mut _36: &mut std::task::Context<'_>; + let mut _37: std::future::ResumeTy; + let mut _38: &mut impl std::future::Future; + let mut _39: std::pin::Pin<&mut AsyncInt>; + let mut _40: &mut AsyncInt; ++ let mut _41: (); ++ let mut _42: u32; ++ let mut _43: &mut {async fn body of std::future::async_drop_in_place<[AsyncInt; 2]>()}; ++ let mut _44: *mut [AsyncInt]; ++ let mut _45: *mut [AsyncInt]; ++ let _46: std::future::ResumeTy; ++ let mut _47: std::ptr::NonNull>; + + bb0: { +- _3 = move (_1.0: &mut [AsyncInt; 2]); +- _4 = &raw mut (*_3); +- _5 = move _4 as *mut [AsyncInt] (PointerCoercion(Unsize, Implicit)); +- _6 = PtrMetadata(copy _5); +- _7 = const 0_usize; +- goto -> bb20; ++ _47 = move _2 as std::ptr::NonNull> (Transmute); ++ _46 = std::future::ResumeTy(move _47); ++ _43 = copy (_1.0: &mut {async fn body of std::future::async_drop_in_place<[AsyncInt; 2]>()}); ++ _42 = discriminant((*_43)); ++ switchInt(move _42) -> [0: bb28, 1: bb27, 2: bb26, 3: bb23, 4: bb24, 5: bb25, otherwise: bb8]; + } + + bb1: { ++ _0 = Poll::<()>::Ready(move _41); ++ discriminant((*_43)) = 1; + return; + } + + bb2 (cleanup): { +- resume; ++ goto -> bb22; + } + + bb3 (cleanup): { +- _8 = &raw mut (*_5)[_7]; +- _7 = Add(move _7, const 1_usize); ++ _7 = no_retag copy (((*_43) as variant#5).2: usize); ++ _44 = no_retag copy (((*_43) as variant#5).0: *mut [AsyncInt]); ++ _8 = &raw mut (*_44)[_7]; ++ (((*_43) as variant#5).2: usize) = Add(move (((*_43) as variant#5).2: usize), const 1_usize); + drop((*_8)) -> [return: bb4, unwind terminate(cleanup)]; + } + + bb4 (cleanup): { +- _9 = Eq(copy _7, copy _6); ++ _9 = Eq(copy (((*_43) as variant#5).2: usize), copy (((*_43) as variant#5).1: usize)); + switchInt(move _9) -> [0: bb3, otherwise: bb2]; + } + +- bb5: { +- _10 = &raw mut (*_5)[_7]; +- _7 = Add(move _7, const 1_usize); +- _21 = &mut (*_10); +- _20 = Pin::<&mut AsyncInt>::new_unchecked(move _21) -> [return: bb18, unwind: bb4]; ++ bb5 (cleanup): { ++ nop; ++ goto -> bb4; + } + + bb6: { +- _11 = Eq(copy _7, copy _6); +- switchInt(move _11) -> [0: bb5, otherwise: bb1]; ++ assert(const false, "`async fn` resumed after async drop") -> [success: bb6, unwind: bb5]; + } + + bb7: { +- StorageDead(_12); ++ _46 = move _13; ++ StorageDead(_13); + goto -> bb6; + } + +- bb8 (cleanup): { +- StorageDead(_12); +- goto -> bb4; ++ bb8: { ++ unreachable; + } + + bb9: { +- assert(const false, "`async fn` resumed after async drop") -> [success: bb9, unwind: bb8]; ++ _7 = no_retag copy (((*_43) as variant#5).2: usize); ++ _45 = no_retag copy (((*_43) as variant#5).0: *mut [AsyncInt]); ++ _22 = &raw mut (*_45)[_7]; ++ (((*_43) as variant#5).2: usize) = Add(move (((*_43) as variant#5).2: usize), const 1_usize); ++ _40 = &mut (*_22); ++ _39 = Pin::<&mut AsyncInt>::new_unchecked(move _40) -> [return: bb21, unwind: bb4]; + } + + bb10: { +- _2 = move _13; +- StorageDead(_13); +- goto -> bb9; ++ _23 = Eq(copy (((*_43) as variant#5).2: usize), copy (((*_43) as variant#5).1: usize)); ++ switchInt(move _23) -> [0: bb9, otherwise: bb1]; + } + + bb11: { +- _2 = move _13; +- StorageDead(_13); +- goto -> bb17; ++ nop; ++ goto -> bb10; + } + +- bb12: { +- StorageLive(_13); +- _13 = yield(const ()) -> [resume: bb10, drop: bb11]; ++ bb12 (cleanup): { ++ nop; ++ goto -> bb4; + } + + bb13: { +- unreachable; ++ assert(const false, "`async fn` resumed after async drop") -> [success: bb13, unwind: bb12]; + } + + bb14: { +- _15 = discriminant(_14); +- switchInt(move _15) -> [0: bb7, 1: bb12, otherwise: bb13]; ++ _46 = move _25; ++ StorageDead(_25); ++ goto -> bb13; + } + + bb15: { +- _14 = as Future>::poll(move _16, move _17) -> [return: bb14, unwind: bb8]; ++ _46 = move _32; ++ StorageDead(_32); ++ goto -> bb20; + } + + bb16: { +- _18 = move _2; +- _17 = std::future::get_context::<'_, '_>(move _18) -> [return: bb15, unwind: bb8]; ++ StorageLive(_32); ++ _0 = Poll::<()>::Pending; ++ StorageDead(_32); ++ discriminant((*_43)) = 5; ++ return; + } + + bb17: { +- _19 = &mut _12; +- _16 = Pin::<&mut impl Future>::new_unchecked(move _19) -> [return: bb16, unwind: bb8]; ++ _34 = discriminant(_33); ++ switchInt(move _34) -> [0: bb11, 1: bb16, otherwise: bb8]; + } + + bb18: { +- StorageLive(_12); +- _12 = async_drop_in_place::(copy (_20.0: &mut AsyncInt)) -> [return: bb17, unwind: bb8]; ++ _33 = as Future>::poll(move _35, move _36) -> [return: bb17, unwind: bb12]; + } + + bb19: { +- _22 = &raw mut (*_5)[_7]; +- _7 = Add(move _7, const 1_usize); +- _40 = &mut (*_22); +- _39 = Pin::<&mut AsyncInt>::new_unchecked(move _40) -> [return: bb39, unwind: bb4]; ++ _37 = move _46; ++ _36 = copy (_37.0: std::ptr::NonNull>) as &mut std::task::Context<'_> (Transmute); ++ goto -> bb18; + } + + bb20: { +- _23 = Eq(copy _7, copy _6); +- switchInt(move _23) -> [0: bb19, otherwise: bb1]; ++ _38 = &mut (((*_43) as variant#5).3: impl std::future::Future); ++ _35 = Pin::<&mut impl Future>::new_unchecked(move _38) -> [return: bb19, unwind: bb12]; + } + + bb21: { +- StorageDead(_24); +- goto -> bb20; ++ nop; ++ (((*_43) as variant#5).3: impl std::future::Future) = async_drop_in_place::(copy (_39.0: &mut AsyncInt)) -> [return: bb20, unwind: bb12]; + } + +- bb22: { +- StorageDead(_24); +- goto -> bb6; ++ bb22 (cleanup): { ++ discriminant((*_43)) = 2; ++ resume; + } + +- bb23 (cleanup): { +- StorageDead(_24); +- goto -> bb4; ++ bb23: { ++ StorageLive(_13); ++ _13 = move _46; ++ goto -> bb7; + } + + bb24: { +- assert(const false, "`async fn` resumed after async drop") -> [success: bb24, unwind: bb23]; ++ StorageLive(_25); ++ _25 = move _46; ++ goto -> bb14; + } + + bb25: { +- _2 = move _25; +- StorageDead(_25); +- goto -> bb24; ++ StorageLive(_32); ++ _32 = move _46; ++ goto -> bb15; + } + + bb26: { +- _2 = move _25; +- StorageDead(_25); +- goto -> bb31; ++ assert(const false, "`async fn` resumed after panicking") -> [success: bb26, unwind continue]; + } + + bb27: { +- StorageLive(_25); +- _25 = yield(const ()) -> [resume: bb25, drop: bb26]; ++ _0 = Poll::<()>::Ready(const ()); ++ return; + } + + bb28: { +- _27 = discriminant(_26); +- switchInt(move _27) -> [0: bb22, 1: bb27, otherwise: bb13]; +- } +- +- bb29: { +- _26 = as Future>::poll(move _28, move _29) -> [return: bb28, unwind: bb23]; +- } +- +- bb30: { +- _30 = move _2; +- _29 = std::future::get_context::<'_, '_>(move _30) -> [return: bb29, unwind: bb23]; +- } +- +- bb31: { +- _31 = &mut _24; +- _28 = Pin::<&mut impl Future>::new_unchecked(move _31) -> [return: bb30, unwind: bb23]; +- } +- +- bb32: { +- _2 = move _32; +- StorageDead(_32); +- goto -> bb38; +- } +- +- bb33: { +- _2 = move _32; +- StorageDead(_32); +- goto -> bb31; +- } +- +- bb34: { +- StorageLive(_32); +- _32 = yield(const ()) -> [resume: bb32, drop: bb33]; +- } +- +- bb35: { +- _34 = discriminant(_33); +- switchInt(move _34) -> [0: bb21, 1: bb34, otherwise: bb13]; +- } +- +- bb36: { +- _33 = as Future>::poll(move _35, move _36) -> [return: bb35, unwind: bb23]; +- } +- +- bb37: { +- _37 = move _2; +- _36 = std::future::get_context::<'_, '_>(move _37) -> [return: bb36, unwind: bb23]; +- } +- +- bb38: { +- _38 = &mut _24; +- _35 = Pin::<&mut impl Future>::new_unchecked(move _38) -> [return: bb37, unwind: bb23]; +- } +- +- bb39: { +- StorageLive(_24); +- _24 = async_drop_in_place::(copy (_39.0: &mut AsyncInt)) -> [return: bb38, unwind: bb23]; ++ _3 = move ((*_43).0: &mut [AsyncInt; 2]); ++ _4 = &raw mut (*_3); ++ (((*_43) as variant#5).0: *mut [AsyncInt]) = move _4 as *mut [AsyncInt] (PointerCoercion(Unsize, Implicit)); ++ (((*_43) as variant#5).1: usize) = PtrMetadata(copy (((*_43) as variant#5).0: *mut [AsyncInt])); ++ (((*_43) as variant#5).2: usize) = const 0_usize; ++ goto -> bb10; + } + } + diff --git a/tests/mir-opt/coroutine/async_drop.elaborate_drops-{closure#0}.ElaborateDrops.diff b/tests/mir-opt/coroutine/async_drop.elaborate_drops-{closure#0}.ElaborateDrops.diff index dd65409f0db13..4e0cbbfc4357c 100644 --- a/tests/mir-opt/coroutine/async_drop.elaborate_drops-{closure#0}.ElaborateDrops.diff +++ b/tests/mir-opt/coroutine/async_drop.elaborate_drops-{closure#0}.ElaborateDrops.diff @@ -33,8 +33,8 @@ + let mut _39: &mut std::task::Context<'_>; + let mut _40: std::future::ResumeTy; + let mut _41: &mut impl std::future::Future; -+ let mut _42: std::pin::Pin<&mut {async closure@$DIR/async_drop.rs:78:27: 78:35}>; -+ let mut _43: &mut {async closure@$DIR/async_drop.rs:78:27: 78:35}; ++ let mut _42: std::pin::Pin<&mut {async closure@$DIR/async_drop.rs:86:27: 86:35}>; ++ let mut _43: &mut {async closure@$DIR/async_drop.rs:86:27: 86:35}; + let mut _44: impl std::future::Future; + let mut _45: std::future::ResumeTy; + let mut _46: std::task::Poll<()>; @@ -50,8 +50,8 @@ + let mut _56: &mut std::task::Context<'_>; + let mut _57: std::future::ResumeTy; + let mut _58: &mut impl std::future::Future; -+ let mut _59: std::pin::Pin<&mut {closure@$DIR/async_drop.rs:70:25: 70:27}>; -+ let mut _60: &mut {closure@$DIR/async_drop.rs:70:25: 70:27}; ++ let mut _59: std::pin::Pin<&mut {closure@$DIR/async_drop.rs:78:25: 78:27}>; ++ let mut _60: &mut {closure@$DIR/async_drop.rs:78:25: 78:27}; + let mut _61: impl std::future::Future; + let mut _62: std::future::ResumeTy; + let mut _63: std::task::Poll<()>; @@ -200,13 +200,13 @@ let _23: AsyncInt; scope 10 { debug foo => _23; - let _24: {closure@$DIR/async_drop.rs:70:25: 70:27}; + let _24: {closure@$DIR/async_drop.rs:78:25: 78:27}; scope 11 { debug async_closure => _24; let _25: AsyncInt; scope 12 { debug foo => _25; - let _26: {async closure@$DIR/async_drop.rs:78:27: 78:35}; + let _26: {async closure@$DIR/async_drop.rs:86:27: 86:35}; scope 13 { debug async_coroutine => _26; } @@ -321,11 +321,11 @@ StorageLive(_23); _23 = AsyncInt(const 14_i32); StorageLive(_24); - _24 = {closure@$DIR/async_drop.rs:70:25: 70:27} { foo: move _23 }; + _24 = {closure@$DIR/async_drop.rs:78:25: 78:27} { foo: move _23 }; StorageLive(_25); _25 = AsyncInt(const 15_i32); StorageLive(_26); - _26 = {closure@$DIR/async_drop.rs:78:27: 78:35} { foo: move _25 }; + _26 = {closure@$DIR/async_drop.rs:86:27: 86:35} { foo: move _25 }; _0 = const (); - drop(_26) -> [return: bb10, unwind: bb44, drop: bb23]; + goto -> bb103; @@ -838,12 +838,12 @@ + + bb102: { + StorageLive(_27); -+ _27 = async_drop_in_place::<{async closure@$DIR/async_drop.rs:78:27: 78:35}>(copy (_42.0: &mut {async closure@$DIR/async_drop.rs:78:27: 78:35})) -> [return: bb101, unwind: bb85]; ++ _27 = async_drop_in_place::<{async closure@$DIR/async_drop.rs:86:27: 86:35}>(copy (_42.0: &mut {async closure@$DIR/async_drop.rs:86:27: 86:35})) -> [return: bb101, unwind: bb85]; + } + + bb103: { + _43 = &mut _26; -+ _42 = Pin::<&mut {async closure@$DIR/async_drop.rs:78:27: 78:35}>::new_unchecked(move _43) -> [return: bb102, unwind: bb44]; ++ _42 = Pin::<&mut {async closure@$DIR/async_drop.rs:86:27: 86:35}>::new_unchecked(move _43) -> [return: bb102, unwind: bb44]; + } + + bb104: { @@ -939,12 +939,12 @@ + + bb122: { + StorageLive(_44); -+ _44 = async_drop_in_place::<{closure@$DIR/async_drop.rs:70:25: 70:27}>(copy (_59.0: &mut {closure@$DIR/async_drop.rs:70:25: 70:27})) -> [return: bb121, unwind: bb106]; ++ _44 = async_drop_in_place::<{closure@$DIR/async_drop.rs:78:25: 78:27}>(copy (_59.0: &mut {closure@$DIR/async_drop.rs:78:25: 78:27})) -> [return: bb121, unwind: bb106]; + } + + bb123: { + _60 = &mut _24; -+ _59 = Pin::<&mut {closure@$DIR/async_drop.rs:70:25: 70:27}>::new_unchecked(move _60) -> [return: bb122, unwind: bb46]; ++ _59 = Pin::<&mut {closure@$DIR/async_drop.rs:78:25: 78:27}>::new_unchecked(move _60) -> [return: bb122, unwind: bb46]; + } + + bb124: { diff --git a/tests/mir-opt/coroutine/async_drop.elaborate_drops-{closure#0}.StateTransform.diff b/tests/mir-opt/coroutine/async_drop.elaborate_drops-{closure#0}.StateTransform.diff index 5fb3dba08ad87..34ea0eeaa07a2 100644 --- a/tests/mir-opt/coroutine/async_drop.elaborate_drops-{closure#0}.StateTransform.diff +++ b/tests/mir-opt/coroutine/async_drop.elaborate_drops-{closure#0}.StateTransform.diff @@ -17,8 +17,8 @@ + field _s6: AsyncEnum; + field _s7: AsyncInt; + field _s8: AsyncReference<'_>; -+ field _s9: {closure@$DIR/async_drop.rs:70:25: 70:27}; -+ field _s10: {async closure@$DIR/async_drop.rs:78:27: 78:35}; ++ field _s9: {closure@$DIR/async_drop.rs:78:25: 78:27}; ++ field _s10: {async closure@$DIR/async_drop.rs:86:27: 86:35}; + field _s11: impl Future; + field _s12: impl Future; + field _s13: impl Future; @@ -83,8 +83,8 @@ let mut _39: &mut std::task::Context<'_>; let mut _40: std::future::ResumeTy; let mut _41: &mut impl std::future::Future; - let mut _42: std::pin::Pin<&mut {async closure@$DIR/async_drop.rs:78:27: 78:35}>; - let mut _43: &mut {async closure@$DIR/async_drop.rs:78:27: 78:35}; + let mut _42: std::pin::Pin<&mut {async closure@$DIR/async_drop.rs:86:27: 86:35}>; + let mut _43: &mut {async closure@$DIR/async_drop.rs:86:27: 86:35}; let mut _44: impl std::future::Future; let mut _45: std::future::ResumeTy; let mut _46: std::task::Poll<()>; @@ -100,8 +100,8 @@ let mut _56: &mut std::task::Context<'_>; let mut _57: std::future::ResumeTy; let mut _58: &mut impl std::future::Future; - let mut _59: std::pin::Pin<&mut {closure@$DIR/async_drop.rs:70:25: 70:27}>; - let mut _60: &mut {closure@$DIR/async_drop.rs:70:25: 70:27}; + let mut _59: std::pin::Pin<&mut {closure@$DIR/async_drop.rs:78:25: 78:27}>; + let mut _60: &mut {closure@$DIR/async_drop.rs:78:25: 78:27}; let mut _61: impl std::future::Future; let mut _62: std::future::ResumeTy; let mut _63: std::task::Poll<()>; @@ -271,18 +271,18 @@ scope 10 { debug foo => _23; + coroutine debug async_closure => _s9; - let _24: {closure@$DIR/async_drop.rs:70:25: 70:27}; + let _24: {closure@$DIR/async_drop.rs:78:25: 78:27}; scope 11 { - debug async_closure => _24; -+ debug async_closure => (((*_182) as variant#6).9: {closure@$DIR/async_drop.rs:70:25: 70:27}); ++ debug async_closure => (((*_182) as variant#6).9: {closure@$DIR/async_drop.rs:78:25: 78:27}); let _25: AsyncInt; scope 12 { debug foo => _25; + coroutine debug async_coroutine => _s10; - let _26: {async closure@$DIR/async_drop.rs:78:27: 78:35}; + let _26: {async closure@$DIR/async_drop.rs:86:27: 86:35}; scope 13 { - debug async_coroutine => _26; -+ debug async_coroutine => (((*_182) as variant#4).10: {async closure@$DIR/async_drop.rs:78:27: 78:35}); ++ debug async_coroutine => (((*_182) as variant#4).10: {async closure@$DIR/async_drop.rs:86:27: 86:35}); } } } @@ -404,17 +404,17 @@ StorageLive(_23); _23 = AsyncInt(const 14_i32); - StorageLive(_24); -- _24 = {closure@$DIR/async_drop.rs:70:25: 70:27} { foo: move _23 }; +- _24 = {closure@$DIR/async_drop.rs:78:25: 78:27} { foo: move _23 }; + nop; -+ (((*_182) as variant#6).9: {closure@$DIR/async_drop.rs:70:25: 70:27}) = {closure@$DIR/async_drop.rs:70:25: 70:27} { foo: move _23 }; ++ (((*_182) as variant#6).9: {closure@$DIR/async_drop.rs:78:25: 78:27}) = {closure@$DIR/async_drop.rs:78:25: 78:27} { foo: move _23 }; StorageLive(_25); _25 = AsyncInt(const 15_i32); - StorageLive(_26); -- _26 = {closure@$DIR/async_drop.rs:78:27: 78:35} { foo: move _25 }; +- _26 = {closure@$DIR/async_drop.rs:86:27: 86:35} { foo: move _25 }; - _0 = const (); - goto -> bb72; + nop; -+ (((*_182) as variant#4).10: {async closure@$DIR/async_drop.rs:78:27: 78:35}) = {closure@$DIR/async_drop.rs:78:27: 78:35} { foo: move _25 }; ++ (((*_182) as variant#4).10: {async closure@$DIR/async_drop.rs:86:27: 86:35}) = {closure@$DIR/async_drop.rs:86:27: 86:35} { foo: move _25 }; + (((*_182) as variant#20).0: ()) = const (); + goto -> bb51; } @@ -517,7 +517,7 @@ + bb24 (cleanup): { StorageDead(_25); - goto -> bb25; -+ drop((((*_182) as variant#6).9: {closure@$DIR/async_drop.rs:70:25: 70:27})) -> [return: bb25, unwind terminate(cleanup)]; ++ drop((((*_182) as variant#6).9: {closure@$DIR/async_drop.rs:78:25: 78:27})) -> [return: bb25, unwind terminate(cleanup)]; } - bb25: { @@ -720,14 +720,14 @@ - drop(_1) -> [return: bb51, unwind terminate(cleanup)]; + bb50: { + nop; -+ (((*_182) as variant#4).11: impl std::future::Future) = async_drop_in_place::<{async closure@$DIR/async_drop.rs:78:27: 78:35}>(copy (_42.0: &mut {async closure@$DIR/async_drop.rs:78:27: 78:35})) -> [return: bb49, unwind: bb40]; ++ (((*_182) as variant#4).11: impl std::future::Future) = async_drop_in_place::<{async closure@$DIR/async_drop.rs:86:27: 86:35}>(copy (_42.0: &mut {async closure@$DIR/async_drop.rs:86:27: 86:35})) -> [return: bb49, unwind: bb40]; } - bb51 (cleanup): { - resume; + bb51: { -+ _43 = &mut (((*_182) as variant#4).10: {async closure@$DIR/async_drop.rs:78:27: 78:35}); -+ _42 = Pin::<&mut {async closure@$DIR/async_drop.rs:78:27: 78:35}>::new_unchecked(move _43) -> [return: bb50, unwind: bb23]; ++ _43 = &mut (((*_182) as variant#4).10: {async closure@$DIR/async_drop.rs:86:27: 86:35}); ++ _42 = Pin::<&mut {async closure@$DIR/async_drop.rs:86:27: 86:35}>::new_unchecked(move _43) -> [return: bb50, unwind: bb23]; } bb52: { @@ -811,14 +811,14 @@ - _33 = move _2; - _32 = std::future::get_context::<'_, '_>(move _33) -> [return: bb61, unwind: bb54]; + nop; -+ (((*_182) as variant#6).10: impl std::future::Future) = async_drop_in_place::<{closure@$DIR/async_drop.rs:70:25: 70:27}>(copy (_59.0: &mut {closure@$DIR/async_drop.rs:70:25: 70:27})) -> [return: bb61, unwind: bb53]; ++ (((*_182) as variant#6).10: impl std::future::Future) = async_drop_in_place::<{closure@$DIR/async_drop.rs:78:25: 78:27}>(copy (_59.0: &mut {closure@$DIR/async_drop.rs:78:25: 78:27})) -> [return: bb61, unwind: bb53]; } bb63: { - _34 = &mut _27; - _31 = Pin::<&mut impl Future>::new_unchecked(move _34) -> [return: bb62, unwind: bb54]; -+ _60 = &mut (((*_182) as variant#6).9: {closure@$DIR/async_drop.rs:70:25: 70:27}); -+ _59 = Pin::<&mut {closure@$DIR/async_drop.rs:70:25: 70:27}>::new_unchecked(move _60) -> [return: bb62, unwind: bb25]; ++ _60 = &mut (((*_182) as variant#6).9: {closure@$DIR/async_drop.rs:78:25: 78:27}); ++ _59 = Pin::<&mut {closure@$DIR/async_drop.rs:78:25: 78:27}>::new_unchecked(move _60) -> [return: bb62, unwind: bb25]; } bb64: { @@ -879,13 +879,13 @@ bb71: { - StorageLive(_27); -- _27 = async_drop_in_place::<{async closure@$DIR/async_drop.rs:78:27: 78:35}>(copy (_42.0: &mut {async closure@$DIR/async_drop.rs:78:27: 78:35})) -> [return: bb70, unwind: bb54]; +- _27 = async_drop_in_place::<{async closure@$DIR/async_drop.rs:86:27: 86:35}>(copy (_42.0: &mut {async closure@$DIR/async_drop.rs:86:27: 86:35})) -> [return: bb70, unwind: bb54]; + _70 = as Future>::poll(move _72, move _73) -> [return: bb70, unwind: bb65]; } bb72: { - _43 = &mut _26; -- _42 = Pin::<&mut {async closure@$DIR/async_drop.rs:78:27: 78:35}>::new_unchecked(move _43) -> [return: bb71, unwind: bb36]; +- _42 = Pin::<&mut {async closure@$DIR/async_drop.rs:86:27: 86:35}>::new_unchecked(move _43) -> [return: bb71, unwind: bb36]; + _74 = move _183; + _73 = copy (_74.0: std::ptr::NonNull>) as &mut std::task::Context<'_> (Transmute); + goto -> bb71; @@ -1027,7 +1027,7 @@ bb91: { - StorageLive(_44); -- _44 = async_drop_in_place::<{closure@$DIR/async_drop.rs:70:25: 70:27}>(copy (_59.0: &mut {closure@$DIR/async_drop.rs:70:25: 70:27})) -> [return: bb90, unwind: bb75]; +- _44 = async_drop_in_place::<{closure@$DIR/async_drop.rs:78:25: 78:27}>(copy (_59.0: &mut {closure@$DIR/async_drop.rs:78:25: 78:27})) -> [return: bb90, unwind: bb75]; + _183 = move _96; + StorageDead(_96); + goto -> bb90; @@ -1035,7 +1035,7 @@ bb92: { - _60 = &mut _24; -- _59 = Pin::<&mut {closure@$DIR/async_drop.rs:70:25: 70:27}>::new_unchecked(move _60) -> [return: bb91, unwind: bb38]; +- _59 = Pin::<&mut {closure@$DIR/async_drop.rs:78:25: 78:27}>::new_unchecked(move _60) -> [return: bb91, unwind: bb38]; + _183 = move _103; + StorageDead(_103); + goto -> bb97; diff --git a/tests/mir-opt/coroutine/async_drop.rs b/tests/mir-opt/coroutine/async_drop.rs index 506baac1dabd8..dfba9e14708db 100644 --- a/tests/mir-opt/coroutine/async_drop.rs +++ b/tests/mir-opt/coroutine/async_drop.rs @@ -51,6 +51,14 @@ async fn double() { let async_int_again = AsyncInt(0); } +// EMIT_MIR async_drop.array-{closure#0}.ElaborateDrops.diff +// EMIT_MIR async_drop.array-{closure#0}.StateTransform.diff +// EMIT_MIR async_drop.array-{closure#0}.coroutine_drop_async.0.mir +// EMIT_MIR core.future-async_drop-async_drop_in_place-{closure#0}.[AsyncInt;2].StateTransform.diff +async fn array() { + let array = [AsyncInt(1), AsyncInt(2)]; +} + // EMIT_MIR async_drop.elaborate_drops-{closure#0}.ElaborateDrops.diff // EMIT_MIR async_drop.elaborate_drops-{closure#0}.StateTransform.diff async fn elaborate_drops() { @@ -90,6 +98,7 @@ fn main() { let i = 13; let fut = pin!(async { + array().await; elaborate_drops().await; test_async_drop(Int(0)).await; diff --git a/tests/ui/async-await/async-drop/async-drop-array-step.rs b/tests/ui/async-await/async-drop/async-drop-array-step.rs new file mode 100644 index 0000000000000..9bb26ccde6c10 --- /dev/null +++ b/tests/ui/async-await/async-drop/async-drop-array-step.rs @@ -0,0 +1,94 @@ +//@ run-pass +//@ check-run-results +//@ edition: 2021 + +#![feature(async_drop)] +#![allow(incomplete_features)] + +use std::future::{async_drop_in_place, AsyncDrop, Future}; +use std::mem::ManuallyDrop; +use std::pin::{pin, Pin}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{mpsc, Arc}; +use std::task::{Context, Poll, Wake, Waker}; + +static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); + +struct YieldOnce(bool); + +impl Future for YieldOnce { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if !self.0 { + self.0 = true; + cx.waker().wake_by_ref(); + Poll::Pending + } else { + Poll::Ready(()) + } + } +} + +struct Item(usize); + +impl Drop for Item { + fn drop(&mut self) {} +} + +impl AsyncDrop for Item { + async fn drop(self: Pin<&mut Self>) { + let count = DROP_COUNT.fetch_add(1, Ordering::Relaxed); + if count >= 8 { + panic!("Infinite loop detected: array drop index reset across yield points!"); + } + YieldOnce(false).await; + println!("Dropping {}", self.0); + } +} + +fn block_on(fut_unpin: F) -> F::Output { + let mut fut_pin = pin!(ManuallyDrop::new(fut_unpin)); + let mut fut: Pin<&mut F> = unsafe { + Pin::map_unchecked_mut(fut_pin.as_mut(), |x| &mut **x) + }; + let (waker, rx) = simple_waker(); + let mut context = Context::from_waker(&waker); + let rv = loop { + match fut.as_mut().poll(&mut context) { + Poll::Ready(out) => break out, + Poll::Pending => rx.try_recv().unwrap(), + } + }; + let drop_fut_unpin = unsafe { async_drop_in_place(fut.get_unchecked_mut()) }; + let mut drop_fut = pin!(drop_fut_unpin); + loop { + match drop_fut.as_mut().poll(&mut context) { + Poll::Ready(()) => break, + Poll::Pending => rx.try_recv().unwrap(), + } + } + rv +} + +fn simple_waker() -> (Waker, mpsc::Receiver<()>) { + struct SimpleWaker { + tx: mpsc::Sender<()>, + } + + impl Wake for SimpleWaker { + fn wake(self: Arc) { + self.tx.send(()).unwrap(); + } + } + + let (tx, rx) = mpsc::channel(); + (Waker::from(Arc::new(SimpleWaker { tx })), rx) +} + +async fn run() { + let _arr: [Item; 4] = [Item(0), Item(1), Item(2), Item(3)]; +} + +fn main() { + block_on(run()); +} diff --git a/tests/ui/async-await/async-drop/async-drop-array-step.run.stdout b/tests/ui/async-await/async-drop/async-drop-array-step.run.stdout new file mode 100644 index 0000000000000..50423d4dc19d4 --- /dev/null +++ b/tests/ui/async-await/async-drop/async-drop-array-step.run.stdout @@ -0,0 +1,4 @@ +Dropping 0 +Dropping 1 +Dropping 2 +Dropping 3 diff --git a/tests/ui/async-await/async-drop/async-drop-initial.rs b/tests/ui/async-await/async-drop/async-drop-initial.rs index 7da87a78701b5..873256890f6a7 100644 --- a/tests/ui/async-await/async-drop/async-drop-initial.rs +++ b/tests/ui/async-await/async-drop/async-drop-initial.rs @@ -54,7 +54,7 @@ fn main() { let fut = pin!(async { test_async_drop(Int(0), 16).await; test_async_drop(AsyncInt(0), 32).await; - test_async_drop([AsyncInt(1), AsyncInt(2)], 104).await; + test_async_drop([AsyncInt(1), AsyncInt(2)], 112).await; test_async_drop((AsyncInt(3), AsyncInt(4)), 120).await; test_async_drop(5, 16).await; let j = 42; diff --git a/tests/ui/suggestions/issue-105645.stderr b/tests/ui/suggestions/issue-105645.stderr index 2b9a94d8e0ab2..2342c22cfa80a 100644 --- a/tests/ui/suggestions/issue-105645.stderr +++ b/tests/ui/suggestions/issue-105645.stderr @@ -7,7 +7,7 @@ LL | foo(&mut bref); | required by a bound introduced by this call | help: the trait `std::io::Write` is implemented for `&mut [u8]` - --> $SRC_DIR/std/src/io/impls.rs:LL:COL + --> $SRC_DIR/core/src/io/impls.rs:LL:COL note: required by a bound in `foo` --> $DIR/issue-105645.rs:8:21 | diff --git a/yarn.lock b/yarn.lock index cd35ba9089e46..3d5855dec80cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -74,18 +74,18 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@puppeteer/browsers@3.0.4": - version "3.0.4" - resolved "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.0.4.tgz" - integrity sha512-HGM8iAmGTf+Y7t0373szVbTmt3d7vPkYL/1bpOkOFO0YUYLgSeuYBCzESklogNPvOBnZ/MRD5f07OkpqH1trtA== +"@puppeteer/browsers@3.0.6": + version "3.0.6" + resolved "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.0.6.tgz" + integrity sha512-B/gKoqlFkzhvzsI6jo9K1cZz9o5ypviVv/xu8CwA4grZzyVwN+XfkT+tu8T1zrauuEXv6VhS2oGX+6NL95WcKA== dependencies: modern-tar "^0.7.6" - yargs "^17.7.2" + yargs "^18.0.0" "@ungap/structured-clone@^1.2.0": - version "1.3.1" - resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz" - integrity sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ== + version "1.3.0" + resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== acorn-jsx@^5.3.2: version "5.3.2" @@ -112,13 +112,23 @@ ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-regex@^6.2.2: + version "6.2.2" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz" + integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== + +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +ansi-styles@^6.2.1: + version "6.2.3" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz" + integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== + argparse@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" @@ -130,9 +140,9 @@ balanced-match@^1.0.0: integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== brace-expansion@^1.1.7: - version "1.1.15" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz" - integrity sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg== + version "1.1.14" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz" + integrity sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -144,10 +154,10 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" -browser-ui-test@^0.24.0: - version "0.24.0" - resolved "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.24.0.tgz" - integrity sha512-jVpAdq/M1cCHG/2K6pAS8NUYJ6BcNSHune72JOheeoASk+oLuGcWcY1SalYAdkWet3dlyfUSyKKtq+DDjYgdVg== +browser-ui-test@^0.24.1: + version "0.24.1" + resolved "https://registry.yarnpkg.com/browser-ui-test/-/browser-ui-test-0.24.1.tgz#1b186b652e2c6593ae1d698408d0e6ba0f32bff5" + integrity sha512-+S+gDOxc7GGfDUmZeRUcCAUzBVbD6qS7TzZSg1CFN/lgJyXf2MCG8CUbvHTsEi/oG5Iuuza1XzKDPpAAvfSUNw== dependencies: css-unit-converter "^1.1.2" pngjs "^3.4.0" @@ -175,14 +185,14 @@ chromium-bidi@16.0.1: mitt "^3.0.1" zod "^3.24.1" -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== +cliui@^9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz" + integrity sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w== dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" + string-width "^7.2.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" color-convert@^2.0.1: version "2.0.1" @@ -227,10 +237,10 @@ deep-is@^0.1.3: resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -devtools-protocol@0.0.1624250: - version "0.0.1624250" - resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1624250.tgz" - integrity sha512-YFAat/lOiIk0ARmBweG+ygrEcbZrq5B9urRyUoeQKp53MlidHXE2TmTbxKcaXoQj7u/aX+jebDO4BW55rs0WwA== +devtools-protocol@0.0.1638949: + version "0.0.1638949" + resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1638949.tgz" + integrity sha512-mXwg4Fqnv0WR4iuAT/gYUmctNkjILwXFHyZ+m7Ty1dfr0ezZt2U3gnrrJTfRobJTHoXf+IbuFvFITzLrLFjwJA== doctrine@^3.0.0: version "3.0.0" @@ -239,10 +249,10 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^10.3.0: + version "10.6.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz" + integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A== es-check@^9.4.4: version "9.6.4" @@ -431,6 +441,11 @@ get-caller-file@^2.0.5: resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-east-asian-width@^1.0.0: + version "1.6.0" + resolved "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz" + integrity sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA== + glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -510,11 +525,6 @@ is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -538,9 +548,9 @@ isexe@^2.0.0: integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== js-yaml@^4.1.0: - version "4.2.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz" - integrity sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw== + version "4.1.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -706,28 +716,28 @@ punycode@^2.1.0: resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -puppeteer-core@25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.1.0.tgz" - integrity sha512-jKzy5y4WG6uNuFbTWgW1D7mqoT9o0nllc/6a1DGF775T1mPmgw3scdFEtEq67yVFikavQmbYq6NLfbTfxHSlqQ== +puppeteer-core@25.3.0: + version "25.3.0" + resolved "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.3.0.tgz" + integrity sha512-fm+wpUr2oigH1PXZvwgATrM2tYWHMDG8ASzTEe9uukCye4X5Ldx1K5BTHPFKITrIWvQQAQ256d1NpbEveBcKjA== dependencies: - "@puppeteer/browsers" "3.0.4" + "@puppeteer/browsers" "3.0.6" chromium-bidi "16.0.1" - devtools-protocol "0.0.1624250" + devtools-protocol "0.0.1638949" typed-query-selector "^2.12.2" webdriver-bidi-protocol "0.4.2" ws "^8.21.0" puppeteer@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-25.1.0.tgz" - integrity sha512-7L6/0JM7XStK99lIL4xQySyNEXNfII6pk0BxkI5kKBTOhR7AsoQiv067YTsE/rIXxQiq9ajlO4WcqBjS/FWK1A== + version "25.3.0" + resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-25.3.0.tgz" + integrity sha512-O1tx8S315aw8eI99HZ5ZNcVEzJ9+jKF//eO5UvfZ3cXJ6okZ5sX3Y50u7DJaM+ewEK4LqXP068tBhfRaWikj+g== dependencies: - "@puppeteer/browsers" "3.0.4" + "@puppeteer/browsers" "3.0.6" chromium-bidi "16.0.1" - devtools-protocol "0.0.1624250" + devtools-protocol "0.0.1638949" lilconfig "^3.1.3" - puppeteer-core "25.1.0" + puppeteer-core "25.3.0" typed-query-selector "^2.12.2" queue-microtask@^1.2.2: @@ -740,11 +750,6 @@ readline-sync@^1.4.10: resolved "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz" integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" @@ -781,22 +786,29 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== +string-width@^7.0.0, string-width@^7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz" + integrity sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w== + dependencies: + ansi-regex "^6.2.2" + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" @@ -867,14 +879,14 @@ word-wrap@^1.2.5: resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== +wrap-ansi@^9.0.0: + version "9.0.2" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz" + integrity sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww== dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" wrappy@1: version "1.0.2" @@ -891,23 +903,22 @@ y18n@^5.0.5: resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== +yargs-parser@^22.0.0: + version "22.0.0" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz" + integrity sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw== -yargs@^17.7.2: - version "17.7.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== +yargs@^18.0.0: + version "18.0.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz" + integrity sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg== dependencies: - cliui "^8.0.1" + cliui "^9.0.1" escalade "^3.1.1" get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" + string-width "^7.2.0" y18n "^5.0.5" - yargs-parser "^21.1.1" + yargs-parser "^22.0.0" yocto-queue@^0.1.0: version "0.1.0"