diff --git a/Cargo.lock b/Cargo.lock index c4704fb0dd593..677c00b003662 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3810,6 +3810,8 @@ dependencies = [ "rustc_span", "rustc_symbol_mangling", "rustc_target", + "serde", + "serde_json", "smallvec", "tempfile", "tracing", diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 773c0ebbe59db..a7ba2f8b69533 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -36,3 +36,5 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } tempfile = "3.2.0" +serde = { version = "1", features = [ "derive" ]} +serde_json = "1" diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 40f0594b40db3..a4ae1b01e869d 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -761,6 +761,7 @@ pub(crate) unsafe fn codegen( EmitObj::None => {} } + record_llvm_cgu_instructions_stats(&cgcx.prof, llmod); drop(handlers); } @@ -974,3 +975,23 @@ fn record_artifact_size( self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size); } } + +fn record_llvm_cgu_instructions_stats(prof: &SelfProfilerRef, llmod: &llvm::Module) { + if !prof.enabled() { + return; + } + + let raw_stats = + llvm::build_string(|s| unsafe { llvm::LLVMRustModuleInstructionStats(&llmod, s) }) + .expect("cannot get module instruction stats"); + + #[derive(serde::Deserialize)] + struct InstructionsStats { + module: String, + total: u64, + } + + let InstructionsStats { module, total } = + serde_json::from_str(&raw_stats).expect("cannot parse llvm cgu instructions stats"); + prof.artifact_size("cgu_instructions", module, total); +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 7aab666fc5e8c..1b3ce2e83a979 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2410,6 +2410,8 @@ extern "C" { pub fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize; pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer); pub fn LLVMRustModuleCost(M: &Module) -> u64; + #[allow(improper_ctypes)] + pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString); pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer; pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer); diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index c694502e01680..7c20307ebd556 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -317,8 +317,6 @@ declare_features! ( (active, c_unwind, "1.52.0", Some(74990), None), /// Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), - /// Allows capturing disjoint fields in a closure/generator (RFC 2229). - (incomplete, capture_disjoint_fields, "1.49.0", Some(53488), None), /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 79a12801de29d..04d4f6cb14e4c 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -52,6 +52,8 @@ declare_features! ( (removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")), (removed, await_macro, "1.38.0", Some(50547), None, Some("subsumed by `.await` syntax")), + /// Allows capturing disjoint fields in a closure/generator (RFC 2229). + (removed, capture_disjoint_fields, "1.49.0", Some(53488), None, Some("stabilized in Rust 2021")), /// Allows comparing raw pointers during const eval. (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None, Some("cannot be allowed in const eval in any meaningful way")), diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index a15cf454df72f..25c467bfd2bd6 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -50,6 +50,7 @@ use rustc_trait_selection::traits::{self, astconv_object_safety_violations, Obli use smallvec::{smallvec, SmallVec}; use std::collections::BTreeSet; +use std::fmt::Display; use std::slice; #[derive(Debug)] @@ -1095,11 +1096,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // those that do. self.one_bound_for_assoc_type( || traits::supertraits(tcx, trait_ref), - || trait_ref.print_only_trait_path().to_string(), + trait_ref.print_only_trait_path(), binding.item_name, path_span, - || match binding.kind { - ConvertedBindingKind::Equality(ty) => Some(ty.to_string()), + match binding.kind { + ConvertedBindingKind::Equality(term) => Some(term), _ => None, }, )? @@ -1789,10 +1790,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_name, ) }, - || param_name.to_string(), + param_name, assoc_name, span, - || None, + None, ) } @@ -1802,10 +1803,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn one_bound_for_assoc_type( &self, all_candidates: impl Fn() -> I, - ty_param_name: impl Fn() -> String, + ty_param_name: impl Display, assoc_name: Ident, span: Span, - is_equality: impl Fn() -> Option, + is_equality: Option>, ) -> Result, ErrorGuaranteed> where I: Iterator>, @@ -1821,7 +1822,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (None, None) => { let reported = self.complain_about_assoc_type_not_found( all_candidates, - &ty_param_name(), + &ty_param_name.to_string(), assoc_name, span, ); @@ -1833,7 +1834,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some(bound2) = next_cand { debug!(?bound2); - let is_equality = is_equality(); let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates); let mut err = if is_equality.is_some() { // More specific Error Index entry. @@ -1843,7 +1843,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { E0222, "ambiguous associated type `{}` in bounds of `{}`", assoc_name, - ty_param_name() + ty_param_name ) } else { struct_span_err!( @@ -1852,7 +1852,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { E0221, "ambiguous associated type `{}` in bounds of `{}`", assoc_name, - ty_param_name() + ty_param_name ) }; err.span_label(span, format!("ambiguous associated type `{}`", assoc_name)); @@ -1886,18 +1886,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_suggestion_verbose( span.with_hi(assoc_name.span.lo()), "use fully qualified syntax to disambiguate", - format!( - "<{} as {}>::", - ty_param_name(), - bound.print_only_trait_path(), - ), + format!("<{} as {}>::", ty_param_name, bound.print_only_trait_path()), Applicability::MaybeIncorrect, ); } } else { err.note(&format!( "associated type `{}` could derive from `{}`", - ty_param_name(), + ty_param_name, bound.print_only_trait_path(), )); } @@ -1906,7 +1902,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.help(&format!( "consider introducing a new type parameter `T` and adding `where` constraints:\ \n where\n T: {},\n{}", - ty_param_name(), + ty_param_name, where_bounds.join(",\n"), )); } @@ -2070,10 +2066,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.one_bound_for_assoc_type( || traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())), - || "Self".to_string(), + kw::SelfUpper, assoc_ident, span, - || None, + None, )? } ( diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 3e27a78135e49..e8bc50440e234 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We now fake capture information for all variables that are mentioned within the closure // We do this after handling migrations so that min_captures computes before - if !enable_precise_capture(self.tcx, span) { + if !enable_precise_capture(span) { let mut capture_information: InferredCaptureInformation<'tcx> = Default::default(); if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { @@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we have an origin, store it. if let Some(origin) = origin { - let origin = if enable_precise_capture(self.tcx, span) { + let origin = if enable_precise_capture(span) { (origin.0, origin.1) } else { (origin.0, Place { projections: vec![], ..origin.1 }) @@ -1243,8 +1243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// This will make more sense with an example: /// - /// ```rust - /// #![feature(capture_disjoint_fields)] + /// ```rust,edition2021 /// /// struct FancyInteger(i32); // This implements Drop /// @@ -2250,12 +2249,10 @@ fn truncate_capture_for_optimization( (place, curr_mode) } -/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if -/// user is using Rust Edition 2021 or higher. -/// +/// Precise capture is enabled if user is using Rust Edition 2021 or higher. /// `span` is the span of the closure. -fn enable_precise_capture(tcx: TyCtxt<'_>, span: Span) -> bool { +fn enable_precise_capture(span: Span) -> bool { // We use span here to ensure that if the closure was generated by a macro with a different // edition. - tcx.features().capture_disjoint_fields || span.rust_2021() + span.rust_2021() } diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 9146a3739b2b1..0589062837866 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -14,6 +14,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/Host.h" #include "llvm/Support/Memory.h" #include "llvm/Support/SourceMgr.h" diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b1e6534944db3..e3493caaaf74e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1751,6 +1751,19 @@ LLVMRustModuleCost(LLVMModuleRef M) { return std::distance(std::begin(f), std::end(f)); } +extern "C" void +LLVMRustModuleInstructionStats(LLVMModuleRef M, RustStringRef Str) +{ + RawRustStringOstream OS(Str); + llvm::json::OStream JOS(OS); + auto Module = unwrap(M); + + JOS.object([&] { + JOS.attribute("module", Module->getName()); + JOS.attribute("total", Module->getInstructionCount()); + }); +} + // Vector reductions: extern "C" LLVMValueRef LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index eb20b2308c0bd..33200b80a572d 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::AdtDef; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, Variance}; use rustc_span::Span; use rustc_target::abi::VariantIdx; @@ -183,7 +183,7 @@ fn to_upvars_resolved_place_builder<'tcx>( &projection, ) else { let closure_span = cx.tcx.def_span(closure_def_id); - if !enable_precise_capture(cx.tcx, closure_span) { + if !enable_precise_capture(closure_span) { bug!( "No associated capture found for {:?}[{:#?}] even though \ capture_disjoint_fields isn't enabled", @@ -745,8 +745,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if -/// user is using Rust Edition 2021 or higher. -fn enable_precise_capture(tcx: TyCtxt<'_>, closure_span: Span) -> bool { - tcx.features().capture_disjoint_fields || closure_span.rust_2021() +/// Precise capture is enabled if user is using Rust Edition 2021 or higher. +fn enable_precise_capture(closure_span: Span) -> bool { + closure_span.rust_2021() } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 909d9bf4093b3..401def1845827 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -2,7 +2,8 @@ use crate::io::prelude::*; use crate::env; use crate::fs::{self, File, OpenOptions}; -use crate::io::{ErrorKind, SeekFrom}; +use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; +use crate::mem::MaybeUninit; use crate::path::Path; use crate::str; use crate::sync::Arc; @@ -401,6 +402,23 @@ fn file_test_io_seek_read_write() { check!(fs::remove_file(&filename)); } +#[test] +fn file_test_read_buf() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("test"); + check!(fs::write(filename, &[1, 2, 3, 4])); + + let mut buf: [MaybeUninit; 128] = MaybeUninit::uninit_array(); + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + let mut file = check!(File::open(filename)); + check!(file.read_buf(buf.unfilled())); + assert_eq!(buf.filled(), &[1, 2, 3, 4]); + // File::read_buf should omit buffer initialization. + assert_eq!(buf.init_len(), 4); + + check!(fs::remove_file(filename)); +} + #[test] fn file_test_stat_is_correct_on_is_file() { let tmpdir = tmpdir(); diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 14bfef4c7aad9..0455a00956e6f 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,7 +8,7 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::fs::File; -use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; +use crate::io::{self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard}; use crate::sys::stdio; @@ -97,6 +97,10 @@ impl Read for StdinRaw { handle_ebadf(self.0.read(buf), 0) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + handle_ebadf(self.0.read_buf(buf), ()) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { handle_ebadf(self.0.read_vectored(bufs), 0) } @@ -418,6 +422,9 @@ impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.lock().read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.lock().read_buf(buf) + } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.lock().read_vectored(bufs) } @@ -450,6 +457,10 @@ impl Read for StdinLock<'_> { self.inner.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index ac09a805975ef..3982d3636614e 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -6,7 +6,7 @@ mod tests; use crate::io::prelude::*; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::iter::FusedIterator; use crate::net::{Shutdown, SocketAddr, ToSocketAddrs}; use crate::sys_common::net as net_imp; @@ -619,6 +619,10 @@ impl Read for TcpStream { self.0.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } @@ -653,6 +657,10 @@ impl Read for &TcpStream { self.0.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 8c0adcfb0ebbb..b8cfead19d7ee 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -1,6 +1,7 @@ use crate::fmt; use crate::io::prelude::*; -use crate::io::{ErrorKind, IoSlice, IoSliceMut}; +use crate::io::{BorrowedBuf, ErrorKind, IoSlice, IoSliceMut}; +use crate::mem::MaybeUninit; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::net::*; use crate::sync::mpsc::channel; @@ -279,6 +280,27 @@ fn partial_read() { }) } +#[test] +fn read_buf() { + each_ip(&mut |addr| { + let srv = t!(TcpListener::bind(&addr)); + let t = thread::spawn(move || { + let mut s = t!(TcpStream::connect(&addr)); + s.write_all(&[1, 2, 3, 4]).unwrap(); + }); + + let mut s = t!(srv.accept()).0; + let mut buf: [MaybeUninit; 128] = MaybeUninit::uninit_array(); + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + t!(s.read_buf(buf.unfilled())); + assert_eq!(buf.filled(), &[1, 2, 3, 4]); + // TcpStream::read_buf should omit buffer initialization. + assert_eq!(buf.init_len(), 4); + + t.join().ok().expect("thread panicked"); + }) +} + #[test] fn read_vectored() { each_ip(&mut |addr| { diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 3fc6cc44ce4c8..edd77c824ad7c 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -54,6 +54,20 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; + /// Like `read_at`, except that it reads into a slice of buffers. + /// + /// Data is copied to fill each buffer in order, with the final buffer + /// written to possibly being only partially filled. This method must behave + /// equivalently to a single call to read with concatenated buffers. + #[unstable(feature = "unix_file_vectored_at", issue = "89517")] + fn read_vectored_at( + &mut self, + bufs: &mut [io::IoSliceMut<'_>], + offset: u64, + ) -> io::Result { + io::default_read_vectored(|b| self.read_at(b, offset), bufs) + } + /// Reads the exact number of byte required to fill `buf` from the given offset. /// /// The offset is relative to the start of the file and thus independent @@ -155,6 +169,16 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; + /// Like `write_at`, 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_at` with the buffers concatenated would. + #[unstable(feature = "unix_file_vectored_at", issue = "89517")] + fn write_vectored_at(&mut self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result { + io::default_write_vectored(|b| self.write_at(b, offset), bufs) + } + /// Attempts to write an entire buffer starting from a given offset. /// /// The offset is relative to the start of the file and thus independent @@ -218,9 +242,19 @@ impl FileExt for fs::File { fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { self.as_inner().read_at(buf, offset) } + fn read_vectored_at( + &mut self, + bufs: &mut [io::IoSliceMut<'_>], + offset: u64, + ) -> io::Result { + self.as_inner().read_vectored_at(bufs, offset) + } fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { self.as_inner().write_at(buf, offset) } + fn write_vectored_at(&mut self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result { + self.as_inner().write_vectored_at(bufs, offset) + } } /// Unix-specific extensions to [`fs::Permissions`]. diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 62ce2cb33dc55..27116f4b6139b 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -110,7 +110,7 @@ use crate::convert::Infallible; use crate::ffi::OsStr; use crate::fmt; use crate::fs; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::num::NonZeroI32; use crate::path::Path; use crate::str; @@ -354,6 +354,10 @@ impl Read for ChildStdout { self.inner.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } @@ -419,6 +423,10 @@ impl Read for ChildStderr { self.inner.read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index b4f6cc2dabae3..0e3494e53d24b 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -1,7 +1,8 @@ use crate::io::prelude::*; use super::{Command, Output, Stdio}; -use crate::io::ErrorKind; +use crate::io::{BorrowedBuf, ErrorKind}; +use crate::mem::MaybeUninit; use crate::str; fn known_command() -> Command { @@ -119,6 +120,34 @@ fn stdin_works() { assert_eq!(out, "foobar\n"); } +#[test] +#[cfg_attr(any(target_os = "vxworks"), ignore)] +fn child_stdout_read_buf() { + let mut cmd = shell_cmd(); + if cfg!(target_os = "windows") { + cmd.arg("/C").arg("echo abc"); + } else { + cmd.arg("-c").arg("echo abc"); + }; + cmd.stdin(Stdio::null()); + cmd.stdout(Stdio::piped()); + let child = cmd.spawn().unwrap(); + + let mut stdout = child.stdout.unwrap(); + let mut buf: [MaybeUninit; 128] = MaybeUninit::uninit_array(); + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + stdout.read_buf(buf.unfilled()).unwrap(); + + // ChildStdout::read_buf should omit buffer initialization. + if cfg!(target_os = "windows") { + assert_eq!(buf.filled(), b"abc\r\n"); + assert_eq!(buf.init_len(), 5); + } else { + assert_eq!(buf.filled(), b"abc\n"); + assert_eq!(buf.init_len(), 4); + }; +} + #[test] #[cfg_attr(any(target_os = "vxworks"), ignore)] fn test_process_status() { diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 66c33d58d6ca3..d3600c410cf08 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -92,7 +92,7 @@ impl FileDesc { let ret = cvt(unsafe { libc::readv( self.as_raw_fd(), - bufs.as_ptr() as *const libc::iovec, + bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, cmp::min(bufs.len(), max_iov()) as libc::c_int, ) })?; @@ -101,7 +101,7 @@ impl FileDesc { #[cfg(any(target_os = "espidf", target_os = "horizon"))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - return crate::io::default_read_vectored(|b| self.read(b), bufs); + io::default_read_vectored(|b| self.read(b), bufs) } #[inline] @@ -147,6 +147,44 @@ impl FileDesc { Ok(()) } + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { + let ret = cvt(unsafe { + libc::preadv( + self.as_raw_fd(), + bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + )))] + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { + io::default_read_vectored(|b| self.read_at(b, offset), bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result { let ret = cvt(unsafe { libc::write( @@ -172,7 +210,7 @@ impl FileDesc { #[cfg(any(target_os = "espidf", target_os = "horizon"))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - return crate::io::default_write_vectored(|b| self.write(b), bufs); + io::default_write_vectored(|b| self.write(b), bufs) } #[inline] @@ -197,6 +235,44 @@ impl FileDesc { } } + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { + let ret = cvt(unsafe { + libc::pwritev( + self.as_raw_fd(), + bufs.as_ptr() as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + )))] + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { + io::default_write_vectored(|b| self.write_at(b, offset), bufs) + } + #[cfg(not(any( target_env = "newlib", target_os = "solaris", @@ -283,6 +359,15 @@ impl<'a> Read for &'a FileDesc { fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { (**self).read_buf(cursor) } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + (**self).read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + (**self).is_read_vectored() + } } impl AsInner for FileDesc { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 8e1f35d6cc920..ec674801a8ff8 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1098,6 +1098,10 @@ impl File { self.0.read_buf(cursor) } + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { + self.0.read_vectored_at(bufs, offset) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } @@ -1115,6 +1119,10 @@ impl File { self.0.write_at(buf, offset) } + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { + self.0.write_vectored_at(bufs, offset) + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index c86f80972a69d..58431a479f045 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -1,6 +1,6 @@ use crate::cmp; use crate::ffi::CStr; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; @@ -240,19 +240,35 @@ impl Socket { self.0.duplicate().map(Socket) } - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { let ret = cvt(unsafe { - libc::recv(self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + libc::recv( + self.as_raw_fd(), + buf.as_mut().as_mut_ptr() as *mut c_void, + buf.capacity(), + flags, + ) })?; - Ok(ret as usize) + unsafe { + buf.advance(ret as usize); + } + Ok(()) } pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, 0) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), 0)?; + Ok(buf.len()) } pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, MSG_PEEK) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), MSG_PEEK)?; + Ok(buf.len()) + } + + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.recv_with_flags(buf, 0) } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index a744d0ab64043..dc17c9fac460a 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -1,4 +1,4 @@ -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; @@ -49,6 +49,10 @@ impl AnonPipe { self.0.read(buf) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index b3626c564e86a..a26f20795a191 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -1,4 +1,4 @@ -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::os::unix::io::FromRawFd; use crate::sys::fd::FileDesc; @@ -18,6 +18,10 @@ impl io::Read for Stdin { unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) } } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_buf(buf) } + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) } } diff --git a/library/std/src/sys/unsupported/net.rs b/library/std/src/sys/unsupported/net.rs index a5204a0845378..bbc52703f9632 100644 --- a/library/std/src/sys/unsupported/net.rs +++ b/library/std/src/sys/unsupported/net.rs @@ -1,5 +1,5 @@ use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::sys::unsupported; use crate::time::Duration; @@ -39,6 +39,10 @@ impl TcpStream { self.0 } + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { self.0 } diff --git a/library/std/src/sys/unsupported/pipe.rs b/library/std/src/sys/unsupported/pipe.rs index 0bba673b458cb..d7d8f297ae586 100644 --- a/library/std/src/sys/unsupported/pipe.rs +++ b/library/std/src/sys/unsupported/pipe.rs @@ -1,4 +1,4 @@ -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; pub struct AnonPipe(!); @@ -7,6 +7,10 @@ impl AnonPipe { self.0 } + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0 } diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index ae33d48c612ee..b290f4070e8fd 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -327,7 +327,16 @@ impl<'a> Read for &'a Handle { (**self).read(buf) } + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + (**self).read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { (**self).read_vectored(bufs) } + + #[inline] + fn is_read_vectored(&self) -> bool { + (**self).is_read_vectored() + } } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index e0701a498fad7..ee1f5482b47ee 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -1,7 +1,7 @@ #![unstable(issue = "none", feature = "windows_net")] use crate::cmp; -use crate::io::{self, IoSlice, IoSliceMut, Read}; +use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ @@ -214,28 +214,38 @@ impl Socket { Ok(Self(self.0.try_clone()?)) } - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - let length = cmp::min(buf.len(), i32::MAX as usize) as i32; - let result = - unsafe { c::recv(self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags) }; + let length = cmp::min(buf.capacity(), i32::MAX as usize) as i32; + let result = unsafe { + c::recv(self.as_raw_socket(), buf.as_mut().as_mut_ptr() as *mut _, length, flags) + }; match result { c::SOCKET_ERROR => { let error = unsafe { c::WSAGetLastError() }; if error == c::WSAESHUTDOWN { - Ok(0) + Ok(()) } else { Err(io::Error::from_raw_os_error(error)) } } - _ => Ok(result as usize), + _ => { + unsafe { buf.advance(result as usize) }; + Ok(()) + } } } pub fn read(&self, buf: &mut [u8]) -> io::Result { + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), 0)?; + Ok(buf.len()) + } + + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { self.recv_with_flags(buf, 0) } @@ -277,7 +287,9 @@ impl Socket { } pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.recv_with_flags(buf, c::MSG_PEEK) + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), c::MSG_PEEK)?; + Ok(buf.len()) } fn recv_from_with_flags( diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs index 7b25edaa556f0..0780b29584da4 100644 --- a/library/std/src/sys/windows/pipe.rs +++ b/library/std/src/sys/windows/pipe.rs @@ -1,7 +1,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsStr; -use crate::io::{self, IoSlice, IoSliceMut, Read}; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::path::Path; use crate::ptr; @@ -252,6 +252,28 @@ impl AnonPipe { } } + pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { + let result = unsafe { + let len = crate::cmp::min(buf.capacity(), c::DWORD::MAX as usize) as c::DWORD; + self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len) + }; + + match result { + // The special treatment of BrokenPipe is to deal with Windows + // pipe semantics, which yields this error when *reading* from + // a pipe after the other end has closed; we interpret that as + // EOF on the pipe. + Err(ref e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(()), + Err(e) => Err(e), + Ok(n) => { + unsafe { + buf.advance(n); + } + Ok(()) + } + } + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 2c38dfecf9734..ab988b97193c4 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -4,7 +4,7 @@ mod tests; use crate::cmp; use crate::convert::{TryFrom, TryInto}; use crate::fmt; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::ptr; @@ -271,6 +271,10 @@ impl TcpStream { self.inner.read(buf) } + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.inner.read_buf(buf) + } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.inner.read_vectored(bufs) } diff --git a/src/doc/book b/src/doc/book index d94e03a18a259..21a2ed14f4480 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit d94e03a18a2590ed3f1c67b859cb11528d2a2d5c +Subproject commit 21a2ed14f4480dab62438dcc1130291bebc65379 diff --git a/src/doc/reference b/src/doc/reference index e5adb99c04817..a9afb04b47a84 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit e5adb99c04817b7fbe08f4ffce5b36702667345f +Subproject commit a9afb04b47a84a6753e4dc657348c324c876102c diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index efe23c4fe12e0..af0998b747383 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit efe23c4fe12e06351b8dc8c3d18312c761455109 +Subproject commit af0998b7473839ca75563ba3d3e7fd0160bef235 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 41a96ab971cb4..b06dab8408339 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 41a96ab971cb45e2a184df20619ad1829765c990 +Subproject commit b06dab84083390e0ee1e998f466545a8a1a76a9f diff --git a/tests/debuginfo/captured-fields-1.rs b/tests/debuginfo/captured-fields-1.rs index afbf942d40471..b71734c2354df 100644 --- a/tests/debuginfo/captured-fields-1.rs +++ b/tests/debuginfo/captured-fields-1.rs @@ -1,5 +1,5 @@ // compile-flags:-g - +// edition:2021 // === GDB TESTS =================================================================================== // gdb-command:run @@ -44,7 +44,6 @@ // lldbg-check:(captured_fields_1::main::{closure_env#5}) $5 = { my_var = { my_field1 = 11 my_field2 = 22 } } // lldb-command:continue -#![feature(capture_disjoint_fields)] #![allow(unused)] struct MyStruct { diff --git a/tests/debuginfo/captured-fields-2.rs b/tests/debuginfo/captured-fields-2.rs index c872354a92489..8d463fb245162 100644 --- a/tests/debuginfo/captured-fields-2.rs +++ b/tests/debuginfo/captured-fields-2.rs @@ -1,5 +1,5 @@ // compile-flags:-g - +// edition:2021 // === GDB TESTS =================================================================================== // gdb-command:run @@ -20,7 +20,6 @@ // lldbg-check:(unsigned int) $1 = 22 // lldb-command:continue -#![feature(capture_disjoint_fields)] #![allow(unused)] struct MyStruct { @@ -29,10 +28,7 @@ struct MyStruct { } fn main() { - let mut my_var = MyStruct { - my_field1: 11, - my_field2: 22, - }; + let mut my_var = MyStruct { my_field1: 11, my_field2: 22 }; let my_ref = &mut my_var; let test = || { diff --git a/tests/ui/closures/2229_closure_analysis/issue_88118.rs b/tests/ui/closures/2229_closure_analysis/issue_88118.rs index 453b7e04a369b..bfb487649a3ce 100644 --- a/tests/ui/closures/2229_closure_analysis/issue_88118.rs +++ b/tests/ui/closures/2229_closure_analysis/issue_88118.rs @@ -1,10 +1,7 @@ // Regression test for #88118. Used to ICE. -// +// edition:2021 // check-pass -#![allow(incomplete_features)] -#![feature(capture_disjoint_fields)] - fn foo(handler: impl FnOnce() -> MsU + Clone + 'static) { Box::new(move |value| { (|_| handler.clone()())(value);