diff options
Diffstat (limited to 'library/std')
47 files changed, 687 insertions, 192 deletions
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index ddcd35b1ac7..33c9c6e63c1 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,21 +18,19 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true } -compiler_builtins = { version = "0.1.98" } +compiler_builtins = { version = "0.1.100" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate -addr2line = { version = "0.20.0", optional = true, default-features = false } rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] } -miniz_oxide = { version = "0.7.0", optional = true, default-features = false, public = false } -[dependencies.object] -version = "0.31.1" -optional = true -default-features = false -features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] + +[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] +miniz_oxide = { version = "0.7.0", optional = true, default-features = false } +addr2line = { version = "0.21.0", optional = true, default-features = false } +object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/std/src/env.rs b/library/std/src/env.rs index d372fa64065..f67f6034d34 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -178,7 +178,8 @@ impl Iterator for Vars { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Vars { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Vars").finish_non_exhaustive() + let Self { inner: VarsOs { inner } } = self; + f.debug_struct("Vars").field("inner", &inner.str_debug()).finish() } } @@ -196,7 +197,8 @@ impl Iterator for VarsOs { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for VarsOs { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("VarOs").finish_non_exhaustive() + let Self { inner } = self; + f.debug_struct("VarsOs").field("inner", inner).finish() } } @@ -829,7 +831,8 @@ impl DoubleEndedIterator for Args { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Args { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Args").field("inner", &self.inner.inner).finish() + let Self { inner: ArgsOs { inner } } = self; + f.debug_struct("Args").field("inner", inner).finish() } } @@ -870,7 +873,8 @@ impl DoubleEndedIterator for ArgsOs { #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for ArgsOs { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ArgsOs").field("inner", &self.inner).finish() + let Self { inner } = self; + f.debug_struct("ArgsOs").field("inner", inner).finish() } } @@ -890,6 +894,7 @@ pub mod consts { /// - aarch64 /// - loongarch64 /// - m68k + /// - csky /// - mips /// - mips64 /// - powerpc diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs index 94cace03af6..55869229581 100644 --- a/library/std/src/env/tests.rs +++ b/library/std/src/env/tests.rs @@ -95,8 +95,28 @@ fn args_debug() { format!("Args {{ inner: {:?} }}", args().collect::<Vec<_>>()), format!("{:?}", args()) ); +} + +#[test] +fn args_os_debug() { assert_eq!( format!("ArgsOs {{ inner: {:?} }}", args_os().collect::<Vec<_>>()), format!("{:?}", args_os()) ); } + +#[test] +fn vars_debug() { + assert_eq!( + format!("Vars {{ inner: {:?} }}", vars().collect::<Vec<_>>()), + format!("{:?}", vars()) + ); +} + +#[test] +fn vars_os_debug() { + assert_eq!( + format!("VarsOs {{ inner: {:?} }}", vars_os().collect::<Vec<_>>()), + format!("{:?}", vars_os()) + ); +} diff --git a/library/std/src/error.rs b/library/std/src/error.rs index ee5eddebfaf..7bc3af1793e 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -9,6 +9,8 @@ use crate::fmt::{self, Write}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::error::Error; +#[unstable(feature = "error_generic_member_access", issue = "99301")] +pub use core::error::{request_ref, Request}; mod private { // This is a hack to prevent `type_id` from being overridden by `Error` @@ -371,11 +373,10 @@ impl<E> Report<E> { /// /// ```rust /// #![feature(error_reporter)] - /// #![feature(provide_any)] /// #![feature(error_generic_member_access)] /// # use std::error::Error; /// # use std::fmt; - /// use std::any::Demand; + /// use std::error::Request; /// use std::error::Report; /// use std::backtrace::Backtrace; /// @@ -405,8 +406,8 @@ impl<E> Report<E> { /// } /// /// impl Error for SuperErrorSideKick { - /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { - /// demand.provide_ref::<Backtrace>(&self.backtrace); + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// request.provide_ref::<Backtrace>(&self.backtrace); /// } /// } /// @@ -459,11 +460,11 @@ where fn backtrace(&self) -> Option<&Backtrace> { // have to grab the backtrace on the first error directly since that error may not be // 'static - let backtrace = (&self.error as &dyn Error).request_ref(); + let backtrace = request_ref(&self.error); let backtrace = backtrace.or_else(|| { self.error .source() - .map(|source| source.sources().find_map(|source| source.request_ref())) + .map(|source| source.sources().find_map(|source| request_ref(source))) .flatten() }); backtrace diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs index ee999bd65c3..ed070a26b0c 100644 --- a/library/std/src/error/tests.rs +++ b/library/std/src/error/tests.rs @@ -1,6 +1,6 @@ use super::Error; use crate::fmt; -use core::any::Demand; +use core::error::Request; #[derive(Debug, PartialEq)] struct A; @@ -199,7 +199,7 @@ where self.source.as_deref() } - fn provide<'a>(&'a self, req: &mut Demand<'a>) { + fn provide<'a>(&'a self, req: &mut Request<'a>) { self.backtrace.as_ref().map(|bt| req.provide_ref::<Backtrace>(bt)); } } diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index bc532990e94..a53b8535213 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -957,4 +957,46 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + + /// Gamma function. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_gamma)] + /// let x = 5.0f32; + /// + /// let abs_difference = (x.gamma() - 24.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_gamma", issue = "99842")] + #[inline] + pub fn gamma(self) -> f32 { + unsafe { cmath::tgammaf(self) } + } + + /// Returns the natural logarithm of the gamma function. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_gamma)] + /// let x = 2.0f32; + /// + /// let abs_difference = (x.ln_gamma().0 - 0.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_gamma", issue = "99842")] + #[inline] + pub fn ln_gamma(self) -> (f32, i32) { + let mut signgamp: i32 = 0; + let x = unsafe { cmath::lgammaf_r(self, &mut signgamp) }; + (x, signgamp) + } } diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index e949def00bb..9ca4e8f2f45 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -653,6 +653,38 @@ fn test_atanh() { } #[test] +fn test_gamma() { + // precision can differ between platforms + assert_approx_eq!(1.0f32.gamma(), 1.0f32); + assert_approx_eq!(2.0f32.gamma(), 1.0f32); + assert_approx_eq!(3.0f32.gamma(), 2.0f32); + assert_approx_eq!(4.0f32.gamma(), 6.0f32); + assert_approx_eq!(5.0f32.gamma(), 24.0f32); + assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt()); + assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt()); + assert_eq!(0.0f32.gamma(), f32::INFINITY); + assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY); + assert!((-1.0f32).gamma().is_nan()); + assert!((-2.0f32).gamma().is_nan()); + assert!(f32::NAN.gamma().is_nan()); + assert!(f32::NEG_INFINITY.gamma().is_nan()); + assert_eq!(f32::INFINITY.gamma(), f32::INFINITY); + assert_eq!(171.71f32.gamma(), f32::INFINITY); +} + +#[test] +fn test_ln_gamma() { + assert_approx_eq!(1.0f32.ln_gamma().0, 0.0f32); + assert_eq!(1.0f32.ln_gamma().1, 1); + assert_approx_eq!(2.0f32.ln_gamma().0, 0.0f32); + assert_eq!(2.0f32.ln_gamma().1, 1); + assert_approx_eq!(3.0f32.ln_gamma().0, 2.0f32.ln()); + assert_eq!(3.0f32.ln_gamma().1, 1); + assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln()); + assert_eq!((-0.5f32).ln_gamma().1, -1); +} + +#[test] fn test_real_consts() { use super::consts; diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 5af9f8bcb23..a1cec22c97a 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -957,4 +957,46 @@ impl f64 { pub fn atanh(self) -> f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + + /// Gamma function. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_gamma)] + /// let x = 5.0f64; + /// + /// let abs_difference = (x.gamma() - 24.0).abs(); + /// + /// assert!(abs_difference <= f64::EPSILON); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_gamma", issue = "99842")] + #[inline] + pub fn gamma(self) -> f64 { + unsafe { cmath::tgamma(self) } + } + + /// Returns the natural logarithm of the gamma function. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_gamma)] + /// let x = 2.0f64; + /// + /// let abs_difference = (x.ln_gamma().0 - 0.0).abs(); + /// + /// assert!(abs_difference <= f64::EPSILON); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_gamma", issue = "99842")] + #[inline] + pub fn ln_gamma(self) -> (f64, i32) { + let mut signgamp: i32 = 0; + let x = unsafe { cmath::lgamma_r(self, &mut signgamp) }; + (x, signgamp) + } } diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index 53d351cceef..f88d01593b5 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -636,6 +636,38 @@ fn test_atanh() { } #[test] +fn test_gamma() { + // precision can differ between platforms + assert_approx_eq!(1.0f64.gamma(), 1.0f64); + assert_approx_eq!(2.0f64.gamma(), 1.0f64); + assert_approx_eq!(3.0f64.gamma(), 2.0f64); + assert_approx_eq!(4.0f64.gamma(), 6.0f64); + assert_approx_eq!(5.0f64.gamma(), 24.0f64); + assert_approx_eq!(0.5f64.gamma(), consts::PI.sqrt()); + assert_approx_eq!((-0.5f64).gamma(), -2.0 * consts::PI.sqrt()); + assert_eq!(0.0f64.gamma(), f64::INFINITY); + assert_eq!((-0.0f64).gamma(), f64::NEG_INFINITY); + assert!((-1.0f64).gamma().is_nan()); + assert!((-2.0f64).gamma().is_nan()); + assert!(f64::NAN.gamma().is_nan()); + assert!(f64::NEG_INFINITY.gamma().is_nan()); + assert_eq!(f64::INFINITY.gamma(), f64::INFINITY); + assert_eq!(171.71f64.gamma(), f64::INFINITY); +} + +#[test] +fn test_ln_gamma() { + assert_approx_eq!(1.0f64.ln_gamma().0, 0.0f64); + assert_eq!(1.0f64.ln_gamma().1, 1); + assert_approx_eq!(2.0f64.ln_gamma().0, 0.0f64); + assert_eq!(2.0f64.ln_gamma().1, 1); + assert_approx_eq!(3.0f64.ln_gamma().0, 2.0f64.ln()); + assert_eq!(3.0f64.ln_gamma().1, 1); + assert_approx_eq!((-0.5f64).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln()); + assert_eq!((-0.5f64).ln_gamma().1, -1); +} + +#[test] fn test_real_consts() { use super::consts; let pi: f64 = consts::PI; diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 67e58fd1b86..43cecb19b14 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -110,12 +110,12 @@ impl crate::sealed::Sealed for OsString {} /// [conversions]: super#conversions #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] -// FIXME: // `OsStr::from_inner` current implementation relies // on `OsStr` being layout-compatible with `Slice`. -// When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`. -// Anyway, `OsStr` representation and layout are considered implementation details, are -// not documented and must not be relied upon. +// However, `OsStr` layout is considered an implementation detail and must not be relied upon. We +// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under +// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. +#[cfg_attr(not(doc), repr(transparent))] pub struct OsStr { inner: Slice, } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 0f79e74f555..a7e65305386 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -791,6 +791,7 @@ impl Write for &File { self.inner.is_write_vectored() } + #[inline] fn flush(&mut self) -> io::Result<()> { self.inner.flush() } @@ -836,6 +837,7 @@ impl Write for File { fn is_write_vectored(&self) -> bool { (&&*self).is_write_vectored() } + #[inline] fn flush(&mut self) -> io::Result<()> { (&*self).flush() } @@ -881,6 +883,7 @@ impl Write for Arc<File> { fn is_write_vectored(&self) -> bool { (&**self).is_write_vectored() } + #[inline] fn flush(&mut self) -> io::Result<()> { (&**self).flush() } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 5c1d2d8f46c..71d91f21362 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1425,9 +1425,9 @@ pub trait Write { /// /// 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()`. - /// Unless `buf` is empty, this function shouldn’t return `Ok(0)` since the - /// caller may interpret that as an error. To indicate lack of space, - /// implementors should return [`ErrorKind::StorageFull`] error instead. + /// 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 /// diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs index 1f3f80b9618..034ddd8df9a 100644 --- a/library/std/src/io/readbuf.rs +++ b/library/std/src/io/readbuf.rs @@ -310,6 +310,7 @@ impl<'a> Write for BorrowedCursor<'a> { Ok(buf.len()) } + #[inline] fn flush(&mut self) -> Result<()> { Ok(()) } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 31481de8495..ac4ce222fba 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -190,7 +190,7 @@ // To run std tests without x.py without ending up with two copies of std, Miri needs to be // able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. -// rustc itself never sets the feature, so this line has no affect there. +// rustc itself never sets the feature, so this line has no effect there. #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] // miri-test-libstd also prefers to make std use the sysroot versions of the dependencies. #![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))] @@ -288,11 +288,11 @@ #![feature(exact_size_is_empty)] #![feature(exclusive_wrapper)] #![feature(extend_one)] +#![feature(float_gamma)] #![feature(float_minimum_maximum)] #![feature(float_next_up_down)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] -#![feature(int_roundings)] #![feature(ip)] #![feature(ip_in_core)] #![feature(maybe_uninit_slice)] @@ -306,7 +306,6 @@ #![feature(pointer_is_aligned)] #![feature(portable_simd)] #![feature(prelude_2024)] -#![feature(provide_any)] #![feature(ptr_as_uninit)] #![feature(raw_os_nonzero)] #![feature(round_ties_even)] @@ -396,9 +395,15 @@ extern crate libc; #[allow(unused_extern_crates)] extern crate unwind; +// FIXME: #94122 this extern crate definition only exist here to stop +// miniz_oxide docs leaking into std docs. Find better way to do it. +// Remove exclusion from tidy platform check when this removed. #[doc(masked)] #[allow(unused_extern_crates)] -#[cfg(feature = "miniz_oxide")] +#[cfg(all( + not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))), + feature = "miniz_oxide" +))] extern crate miniz_oxide; // During testing, this crate is not actually the "real" std library, but rather diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 141a18a42dd..32fd54c8e75 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -647,6 +647,7 @@ impl Write for TcpStream { self.0.is_write_vectored() } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -685,6 +686,7 @@ impl Write for &TcpStream { self.0.is_write_vectored() } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } diff --git a/library/std/src/os/l4re/raw.rs b/library/std/src/os/l4re/raw.rs index b3f7439f8cd..12c0293285a 100644 --- a/library/std/src/os/l4re/raw.rs +++ b/library/std/src/os/l4re/raw.rs @@ -27,6 +27,7 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; #[cfg(any( target_arch = "x86", target_arch = "m68k", + target_arch = "csky", target_arch = "powerpc", target_arch = "sparc", target_arch = "arm", diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index 7c55e92502f..a568f9b26ba 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -27,6 +27,7 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; #[cfg(any( target_arch = "x86", target_arch = "m68k", + target_arch = "csky", target_arch = "powerpc", target_arch = "sparc", target_arch = "arm", diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index e20170873bb..41290e0017a 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -712,6 +712,7 @@ impl<'a> io::Write for &'a UnixStream { self.0.is_write_vectored() } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 99f7a60f8ab..5842c096f1a 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1158,12 +1158,12 @@ impl FusedIterator for Ancestors<'_> {} /// Which method works best depends on what kind of situation you're in. #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] -// FIXME: // `PathBuf::as_mut_vec` current implementation relies // on `PathBuf` being layout-compatible with `Vec<u8>`. -// When attribute privacy is implemented, `PathBuf` should be annotated as `#[repr(transparent)]`. -// Anyway, `PathBuf` representation and layout are considered implementation detail, are -// not documented and must not be relied upon. +// However, `PathBuf` layout is considered an implementation detail and must not be relied upon. We +// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under +// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. +#[cfg_attr(not(doc), repr(transparent))] pub struct PathBuf { inner: OsString, } @@ -1983,12 +1983,12 @@ impl AsRef<OsStr> for PathBuf { /// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "Path")] #[stable(feature = "rust1", since = "1.0.0")] -// FIXME: // `Path::new` current implementation relies // on `Path` being layout-compatible with `OsStr`. -// When attribute privacy is implemented, `Path` should be annotated as `#[repr(transparent)]`. -// Anyway, `Path` representation and layout are considered implementation detail, are -// not documented and must not be relied upon. +// However, `Path` layout is considered an implementation detail and must not be relied upon. We +// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under +// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. +#[cfg_attr(not(doc), repr(transparent))] pub struct Path { inner: OsStr, } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index f9cb755b01a..f54d5934175 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -280,6 +280,7 @@ impl Write for ChildStdin { io::Write::is_write_vectored(&&*self) } + #[inline] fn flush(&mut self) -> io::Result<()> { (&*self).flush() } @@ -299,6 +300,7 @@ impl Write for &ChildStdin { self.inner.is_write_vectored() } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -1532,6 +1534,15 @@ impl From<fs::File> for Stdio { #[stable(feature = "process", since = "1.0.0")] pub struct ExitStatus(imp::ExitStatus); +/// The default value is one which indicates successful completion. +#[stable(feature = "process-exitcode-default", since = "CURRENT_RUSTC_VERSION")] +impl Default for ExitStatus { + fn default() -> Self { + // Ideally this would be done by ExitCode::default().into() but that is complicated. + ExitStatus::from_inner(imp::ExitStatus::default()) + } +} + /// Allows extension traits within `std`. #[unstable(feature = "sealed", issue = "none")] impl crate::sealed::Sealed for ExitStatus {} diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index e39254aa434..ed3c5512084 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -130,11 +130,8 @@ impl Barrier { let local_gen = lock.generation_id; lock.count += 1; if lock.count < self.num_threads { - // We need a while loop to guard against spurious wakeups. - // https://en.wikipedia.org/wiki/Spurious_wakeup - while local_gen == lock.generation_id { - lock = self.cvar.wait(lock).unwrap(); - } + let _guard = + self.cvar.wait_while(lock, |state| local_gen == state.generation_id).unwrap(); BarrierWaitResult(false) } else { lock.count = 0; diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index c00134c8b95..f92bb1a4b1f 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -303,12 +303,11 @@ pub struct IntoIter<T> { rx: Receiver<T>, } -/// The sending-half of Rust's asynchronous [`channel`] type. This half can only be -/// owned by one thread, but it can be cloned to send to other threads. +/// The sending-half of Rust's asynchronous [`channel`] type. /// /// Messages can be sent through this channel with [`send`]. /// -/// Note: all senders (the original and the clones) need to be dropped for the receiver +/// Note: all senders (the original and its clones) need to be dropped for the receiver /// to stop blocking to receive messages with [`Receiver::recv`]. /// /// [`send`]: Sender::send diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs index 3ccea3ce0e3..d58aa6c27b8 100644 --- a/library/std/src/sys/common/alloc.rs +++ b/library/std/src/sys/common/alloc.rs @@ -8,6 +8,7 @@ use crate::ptr; target_arch = "x86", target_arch = "arm", target_arch = "m68k", + target_arch = "csky", target_arch = "mips", target_arch = "mips32r6", target_arch = "powerpc", diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index 4bb735668d2..6aa4ea7f5b4 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -335,6 +335,7 @@ impl File { false } + #[inline] pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/library/std/src/sys/hermit/os.rs b/library/std/src/sys/hermit/os.rs index e53dbae6119..c79197a9ad1 100644 --- a/library/std/src/sys/hermit/os.rs +++ b/library/std/src/sys/hermit/os.rs @@ -112,6 +112,34 @@ pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, } +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + impl !Send for Env {} impl !Sync for Env {} diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs index dc9636ac8c9..e477a0cd7ab 100644 --- a/library/std/src/sys/personality/gcc.rs +++ b/library/std/src/sys/personality/gcc.rs @@ -67,6 +67,9 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // D0, D1 ))] const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 +#[cfg(target_arch = "csky")] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 diff --git a/library/std/src/sys/sgx/os.rs b/library/std/src/sys/sgx/os.rs index 5da0257f35d..86f4c7d3d56 100644 --- a/library/std/src/sys/sgx/os.rs +++ b/library/std/src/sys/sgx/os.rs @@ -96,14 +96,61 @@ fn create_env_store() -> &'static EnvStore { unsafe { &*(ENV.load(Ordering::Relaxed) as *const EnvStore) } } -pub type Env = vec::IntoIter<(OsString, OsString)>; +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} pub fn env() -> Env { let clone_to_vec = |map: &HashMap<OsString, OsString>| -> Vec<_> { map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() }; - get_env_store().map(|env| clone_to_vec(&env.lock().unwrap())).unwrap_or_default().into_iter() + let iter = get_env_store() + .map(|env| clone_to_vec(&env.lock().unwrap())) + .unwrap_or_default() + .into_iter(); + Env { iter } } pub fn getenv(k: &OsStr) -> Option<OsString> { diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs index 6135921f0b5..717c08434a8 100644 --- a/library/std/src/sys/solid/os.rs +++ b/library/std/src/sys/solid/os.rs @@ -85,6 +85,34 @@ pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, } +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + impl !Send for Env {} impl !Sync for Env {} diff --git a/library/std/src/sys/unix/cmath.rs b/library/std/src/sys/unix/cmath.rs index 2bf80d7a4cb..5346d229116 100644 --- a/library/std/src/sys/unix/cmath.rs +++ b/library/std/src/sys/unix/cmath.rs @@ -30,4 +30,8 @@ extern "C" { pub fn tanf(n: f32) -> f32; pub fn tanh(n: f64) -> f64; pub fn tanhf(n: f32) -> f32; + pub fn tgamma(n: f64) -> f64; + pub fn tgammaf(n: f32) -> f32; + pub fn lgamma_r(n: f64, s: &mut i32) -> f64; + pub fn lgammaf_r(n: f32, s: &mut i32) -> f32; } diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 7dc809a038b..a5604c92a80 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1204,6 +1204,7 @@ impl File { self.0.write_vectored_at(bufs, offset) } + #[inline] pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index a68c14758ff..215f63d04f7 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -495,6 +495,34 @@ pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, } +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + impl !Send for Env {} impl !Sync for Env {} diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index e45c380a0bb..9931c2af2f1 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -235,7 +235,7 @@ impl Process { } } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] pub struct ExitStatus(i64); impl ExitStatus { diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 0ce93af66ac..3963e7f52d5 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -10,9 +10,6 @@ use core::ffi::NonZero_c_int; #[cfg(target_os = "linux")] use crate::os::linux::process::PidFd; -#[cfg(target_os = "linux")] -use crate::sys::weak::raw_syscall; - #[cfg(any( target_os = "macos", target_os = "watchos", @@ -91,6 +88,11 @@ impl Command { if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? { return Ok((ret, ours)); } + + #[cfg(target_os = "linux")] + let (input, output) = sys::net::Socket::new_pair(libc::AF_UNIX, libc::SOCK_SEQPACKET)?; + + #[cfg(not(target_os = "linux"))] let (input, output) = sys::pipe::anon_pipe()?; // Whatever happens after the fork is almost for sure going to touch or @@ -104,12 +106,16 @@ impl Command { // The child calls `mem::forget` to leak the lock, which is crucial because // releasing a lock is not async-signal-safe. let env_lock = sys::os::env_read_lock(); - let (pid, pidfd) = unsafe { self.do_fork()? }; + let pid = unsafe { self.do_fork()? }; if pid == 0 { crate::panic::always_abort(); mem::forget(env_lock); // avoid non-async-signal-safe unlocking drop(input); + #[cfg(target_os = "linux")] + if self.get_create_pidfd() { + self.send_pidfd(&output); + } let Err(err) = unsafe { self.do_exec(theirs, envp.as_ref()) }; let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32; let errno = errno.to_be_bytes(); @@ -133,6 +139,12 @@ impl Command { drop(env_lock); drop(output); + #[cfg(target_os = "linux")] + let pidfd = if self.get_create_pidfd() { self.recv_pidfd(&input) } else { -1 }; + + #[cfg(not(target_os = "linux"))] + let pidfd = -1; + // Safety: We obtained the pidfd from calling `clone3` with // `CLONE_PIDFD` so it's valid an otherwise unowned. let mut p = unsafe { Process::new(pid, pidfd) }; @@ -160,6 +172,7 @@ impl Command { } Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic + // similarly SOCK_SEQPACKET messages should arrive whole assert!(p.wait().is_ok(), "wait() should either return Ok or panic"); panic!("short read on the CLOEXEC pipe") } @@ -185,20 +198,19 @@ impl Command { ); #[cfg(any(target_os = "tvos", target_os = "watchos"))] - unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { + unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> { return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC); } // Attempts to fork the process. If successful, returns Ok((0, -1)) // in the child, and Ok((child_pid, -1)) in the parent. #[cfg(not(any( - target_os = "linux", target_os = "watchos", target_os = "tvos", all(target_os = "nto", target_env = "nto71"), )))] - unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { - cvt(libc::fork()).map(|res| (res, -1)) + unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> { + cvt(libc::fork()) } // On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened @@ -206,7 +218,7 @@ impl Command { // Documentation says "... or try calling fork() again". This is what we do here. // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html #[cfg(all(target_os = "nto", target_env = "nto71"))] - unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { + unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> { use crate::sys::os::errno; let mut delay = MIN_FORKSPAWN_SLEEP; @@ -229,91 +241,11 @@ impl Command { delay *= 2; continue; } else { - return cvt(r).map(|res| (res, -1)); + return cvt(r); } } } - // Attempts to fork the process. If successful, returns Ok((0, -1)) - // in the child, and Ok((child_pid, child_pidfd)) in the parent. - #[cfg(target_os = "linux")] - unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { - use crate::sync::atomic::{AtomicBool, Ordering}; - - static HAS_CLONE3: AtomicBool = AtomicBool::new(true); - const CLONE_PIDFD: u64 = 0x00001000; - - #[repr(C)] - struct clone_args { - flags: u64, - pidfd: u64, - child_tid: u64, - parent_tid: u64, - exit_signal: u64, - stack: u64, - stack_size: u64, - tls: u64, - set_tid: u64, - set_tid_size: u64, - cgroup: u64, - } - - raw_syscall! { - fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long - } - - // Bypassing libc for `clone3` can make further libc calls unsafe, - // so we use it sparingly for now. See #89522 for details. - // Some tools (e.g. sandboxing tools) may also expect `fork` - // rather than `clone3`. - let want_clone3_pidfd = self.get_create_pidfd(); - - // If we fail to create a pidfd for any reason, this will - // stay as -1, which indicates an error. - let mut pidfd: pid_t = -1; - - // Attempt to use the `clone3` syscall, which supports more arguments - // (in particular, the ability to create a pidfd). If this fails, - // we will fall through this block to a call to `fork()` - if want_clone3_pidfd && HAS_CLONE3.load(Ordering::Relaxed) { - let mut args = clone_args { - flags: CLONE_PIDFD, - pidfd: &mut pidfd as *mut pid_t as u64, - child_tid: 0, - parent_tid: 0, - exit_signal: libc::SIGCHLD as u64, - stack: 0, - stack_size: 0, - tls: 0, - set_tid: 0, - set_tid_size: 0, - cgroup: 0, - }; - - let args_ptr = &mut args as *mut clone_args; - let args_size = crate::mem::size_of::<clone_args>(); - - let res = cvt(clone3(args_ptr, args_size)); - match res { - Ok(n) => return Ok((n as pid_t, pidfd)), - Err(e) => match e.raw_os_error() { - // Multiple threads can race to execute this store, - // but that's fine - that just means that multiple threads - // will have tried and failed to execute the same syscall, - // with no other side effects. - Some(libc::ENOSYS) => HAS_CLONE3.store(false, Ordering::Relaxed), - // Fallback to fork if `EPERM` is returned. (e.g. blocked by seccomp) - Some(libc::EPERM) => {} - _ => return Err(e), - }, - } - } - - // Generally, we just call `fork`. If we get here after wanting `clone3`, - // then the syscall does not exist or we do not have permission to call it. - cvt(libc::fork()).map(|res| (res, pidfd)) - } - pub fn exec(&mut self, default: Stdio) -> io::Error { let envp = self.capture_env(); @@ -722,6 +654,115 @@ impl Command { Ok(Some(p)) } } + + #[cfg(target_os = "linux")] + fn send_pidfd(&self, sock: &crate::sys::net::Socket) { + use crate::io::IoSlice; + use crate::os::fd::RawFd; + use crate::sys::cvt_r; + use libc::{CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_SPACE, SCM_RIGHTS, SOL_SOCKET}; + + unsafe { + let child_pid = libc::getpid(); + // pidfd_open sets CLOEXEC by default + let pidfd = libc::syscall(libc::SYS_pidfd_open, child_pid, 0); + + let fds: [c_int; 1] = [pidfd as RawFd]; + + const SCM_MSG_LEN: usize = mem::size_of::<[c_int; 1]>(); + + #[repr(C)] + union Cmsg { + buf: [u8; unsafe { CMSG_SPACE(SCM_MSG_LEN as u32) as usize }], + _align: libc::cmsghdr, + } + + let mut cmsg: Cmsg = mem::zeroed(); + + // 0-length message to send through the socket so we can pass along the fd + let mut iov = [IoSlice::new(b"")]; + let mut msg: libc::msghdr = mem::zeroed(); + + msg.msg_iov = &mut iov as *mut _ as *mut _; + msg.msg_iovlen = 1; + msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _; + msg.msg_control = &mut cmsg.buf as *mut _ as *mut _; + + // only attach cmsg if we successfully acquired the pidfd + if pidfd >= 0 { + let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _); + (*hdr).cmsg_level = SOL_SOCKET; + (*hdr).cmsg_type = SCM_RIGHTS; + (*hdr).cmsg_len = CMSG_LEN(SCM_MSG_LEN as _) as _; + let data = CMSG_DATA(hdr); + crate::ptr::copy_nonoverlapping( + fds.as_ptr().cast::<u8>(), + data as *mut _, + SCM_MSG_LEN, + ); + } + + // we send the 0-length message even if we failed to acquire the pidfd + // so we get a consistent SEQPACKET order + match cvt_r(|| libc::sendmsg(sock.as_raw(), &msg, 0)) { + Ok(0) => {} + _ => rtabort!("failed to communicate with parent process"), + } + } + } + + #[cfg(target_os = "linux")] + fn recv_pidfd(&self, sock: &crate::sys::net::Socket) -> pid_t { + use crate::io::IoSliceMut; + use crate::sys::cvt_r; + + use libc::{CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_SPACE, SCM_RIGHTS, SOL_SOCKET}; + + unsafe { + const SCM_MSG_LEN: usize = mem::size_of::<[c_int; 1]>(); + + #[repr(C)] + union Cmsg { + _buf: [u8; unsafe { CMSG_SPACE(SCM_MSG_LEN as u32) as usize }], + _align: libc::cmsghdr, + } + let mut cmsg: Cmsg = mem::zeroed(); + // 0-length read to get the fd + let mut iov = [IoSliceMut::new(&mut [])]; + + let mut msg: libc::msghdr = mem::zeroed(); + + msg.msg_iov = &mut iov as *mut _ as *mut _; + msg.msg_iovlen = 1; + msg.msg_controllen = mem::size_of::<Cmsg>() as _; + msg.msg_control = &mut cmsg as *mut _ as *mut _; + + match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, 0)) { + Err(_) => return -1, + Ok(_) => {} + } + + let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _); + if hdr.is_null() + || (*hdr).cmsg_level != SOL_SOCKET + || (*hdr).cmsg_type != SCM_RIGHTS + || (*hdr).cmsg_len != CMSG_LEN(SCM_MSG_LEN as _) as _ + { + return -1; + } + let data = CMSG_DATA(hdr); + + let mut fds = [-1 as c_int]; + + crate::ptr::copy_nonoverlapping( + data as *const _, + fds.as_mut_ptr().cast::<u8>(), + SCM_MSG_LEN, + ); + + fds[0] + } + } } //////////////////////////////////////////////////////////////////////////////// @@ -800,7 +841,7 @@ impl Process { // // This is not actually an "exit status" in Unix terminology. Rather, it is a "wait status". // See the discussion in comments and doc comments for `std::process::ExitStatus`. -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(PartialEq, Eq, Clone, Copy, Default)] pub struct ExitStatus(c_int); impl fmt::Debug for ExitStatus { diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs index e5e1f956bc3..6aa79e7f9e7 100644 --- a/library/std/src/sys/unix/process/process_unix/tests.rs +++ b/library/std/src/sys/unix/process/process_unix/tests.rs @@ -60,3 +60,28 @@ fn test_command_fork_no_unwind() { || signal == libc::SIGSEGV ); } + +#[test] +#[cfg(target_os = "linux")] +fn test_command_pidfd() { + use crate::os::fd::RawFd; + use crate::os::linux::process::{ChildExt, CommandExt}; + use crate::process::Command; + + let our_pid = crate::process::id(); + let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) }; + let pidfd_open_available = if pidfd >= 0 { + unsafe { libc::close(pidfd as RawFd) }; + true + } else { + false + }; + + // always exercise creation attempts + let child = Command::new("echo").create_pidfd(true).spawn().unwrap(); + + // but only check if we know that the kernel supports pidfds + if pidfd_open_available { + assert!(child.pidfd().is_ok()) + } +} diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs index f28ca58d020..8e0b971af73 100644 --- a/library/std/src/sys/unix/process/process_unsupported.rs +++ b/library/std/src/sys/unix/process/process_unsupported.rs @@ -55,7 +55,7 @@ impl Process { } } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] pub struct ExitStatus(c_int); impl ExitStatus { diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs index f70d3cb396b..1ff2b2fb383 100644 --- a/library/std/src/sys/unix/process/process_vxworks.rs +++ b/library/std/src/sys/unix/process/process_vxworks.rs @@ -179,7 +179,7 @@ impl Process { } /// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] pub struct ExitStatus(c_int); impl ExitStatus { diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index a26f20795a1..97e75f1b5b6 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -54,6 +54,7 @@ impl io::Write for Stdout { true } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -81,6 +82,7 @@ impl io::Write for Stderr { true } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } diff --git a/library/std/src/sys/unsupported/os.rs b/library/std/src/sys/unsupported/os.rs index e150ae143ad..248b34829f2 100644 --- a/library/std/src/sys/unsupported/os.rs +++ b/library/std/src/sys/unsupported/os.rs @@ -65,10 +65,26 @@ pub fn current_exe() -> io::Result<PathBuf> { pub struct Env(!); +impl Env { + // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self(inner) = self; + match *inner {} + } +} + +impl fmt::Debug for Env { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(inner) = self; + match *inner {} + } +} + impl Iterator for Env { type Item = (OsString, OsString); fn next(&mut self) -> Option<(OsString, OsString)> { - self.0 + let Self(inner) = self; + match *inner {} } } diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index a494f2d6b4c..77b675aaa4e 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -99,58 +99,59 @@ impl fmt::Debug for Command { } } -pub struct ExitStatus(!); +#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] +#[non_exhaustive] +pub struct ExitStatus(); impl ExitStatus { pub fn exit_ok(&self) -> Result<(), ExitStatusError> { - self.0 + Ok(()) } pub fn code(&self) -> Option<i32> { - self.0 + Some(0) } } -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - self.0 +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "<dummy exit status>") } } -impl Copy for ExitStatus {} +pub struct ExitStatusError(!); -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { +impl Clone for ExitStatusError { + fn clone(&self) -> ExitStatusError { self.0 } } -impl Eq for ExitStatus {} +impl Copy for ExitStatusError {} -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl PartialEq for ExitStatusError { + fn eq(&self, _other: &ExitStatusError) -> bool { self.0 } } -impl fmt::Display for ExitStatus { +impl Eq for ExitStatusError {} + +impl fmt::Debug for ExitStatusError { fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0 } } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatusError(ExitStatus); - impl Into<ExitStatus> for ExitStatusError { fn into(self) -> ExitStatus { - self.0.0 + self.0 } } impl ExitStatusError { pub fn code(self) -> Option<NonZeroI32> { - self.0.0 + self.0 } } diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index 1b50c2ea6dd..d7295a799da 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -16,14 +16,20 @@ pub struct WasiFd { fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { assert_eq!(mem::size_of::<IoSliceMut<'_>>(), mem::size_of::<wasi::Iovec>()); assert_eq!(mem::align_of::<IoSliceMut<'_>>(), mem::align_of::<wasi::Iovec>()); - // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout + // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout. + // We decorate our `IoSliceMut` with `repr(transparent)` (see `io.rs`), and + // `crate::io::IoSliceMut` is a `repr(transparent)` wrapper around our type, so this is + // guaranteed. unsafe { mem::transmute(a) } } fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { assert_eq!(mem::size_of::<IoSlice<'_>>(), mem::size_of::<wasi::Ciovec>()); assert_eq!(mem::align_of::<IoSlice<'_>>(), mem::align_of::<wasi::Ciovec>()); - // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout + // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout. + // We decorate our `IoSlice` with `repr(transparent)` (see `io.rs`), and + // `crate::io::IoSlice` is a `repr(transparent)` wrapper around our type, so this is + // guaranteed. unsafe { mem::transmute(a) } } diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs index 197bdeda4fb..e0de284c5e2 100644 --- a/library/std/src/sys/wasi/os.rs +++ b/library/std/src/sys/wasi/os.rs @@ -142,10 +142,39 @@ impl StdError for JoinPathsError { pub fn current_exe() -> io::Result<PathBuf> { unsupported() } + pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, } +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + impl !Send for Env {} impl !Sync for Env {} diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index d27b7a2e0f5..dbad425976a 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -20,9 +20,9 @@ cfg_if::cfg_if! { // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108 #[repr(C)] union pthread_attr_union { - __i: [ffi::c_int; if mem::size_of::<ffi::c_int>() == 8 { 14 } else { 9 }], - __vi: [ffi::c_int; if mem::size_of::<ffi::c_int>() == 8 { 14 } else { 9 }], - __s: [ffi::c_ulong; if mem::size_of::<ffi::c_int>() == 8 { 7 } else { 9 }], + __i: [ffi::c_int; if mem::size_of::<ffi::c_long>() == 8 { 14 } else { 9 }], + __vi: [ffi::c_int; if mem::size_of::<ffi::c_long>() == 8 { 14 } else { 9 }], + __s: [ffi::c_ulong; if mem::size_of::<ffi::c_long>() == 8 { 7 } else { 9 }], } #[repr(C)] diff --git a/library/std/src/sys/windows/cmath.rs b/library/std/src/sys/windows/cmath.rs index 43ab8c7ee65..1b2a86f3c0e 100644 --- a/library/std/src/sys/windows/cmath.rs +++ b/library/std/src/sys/windows/cmath.rs @@ -1,6 +1,6 @@ #![cfg(not(test))] -use libc::{c_double, c_float}; +use libc::{c_double, c_float, c_int}; extern "C" { pub fn acos(n: c_double) -> c_double; @@ -23,6 +23,10 @@ extern "C" { pub fn sinh(n: c_double) -> c_double; pub fn tan(n: c_double) -> c_double; pub fn tanh(n: c_double) -> c_double; + pub fn tgamma(n: c_double) -> c_double; + pub fn tgammaf(n: c_float) -> c_float; + pub fn lgamma_r(n: c_double, s: &mut c_int) -> c_double; + pub fn lgammaf_r(n: c_float, s: &mut c_int) -> c_float; } pub use self::shims::*; diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index d7adeb266ed..2329426ad1d 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -85,25 +85,69 @@ pub fn error_string(mut errnum: i32) -> String { pub struct Env { base: c::LPWCH, - cur: c::LPWCH, + iter: EnvIterator, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. +pub struct EnvStrDebug<'a> { + iter: &'a EnvIterator, +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + let iter: EnvIterator = (*iter).clone(); + let mut list = f.debug_list(); + for (a, b) in iter { + list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); + } + list.finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { base: _, iter } = self; + EnvStrDebug { iter } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { base: _, iter } = self; + f.debug_list().entries(iter.clone()).finish() + } } impl Iterator for Env { type Item = (OsString, OsString); fn next(&mut self) -> Option<(OsString, OsString)> { + let Self { base: _, iter } = self; + iter.next() + } +} + +#[derive(Clone)] +struct EnvIterator(c::LPWCH); + +impl Iterator for EnvIterator { + type Item = (OsString, OsString); + + fn next(&mut self) -> Option<(OsString, OsString)> { + let Self(cur) = self; loop { unsafe { - if *self.cur == 0 { + if **cur == 0 { return None; } - let p = self.cur as *const u16; + let p = *cur as *const u16; let mut len = 0; while *p.add(len) != 0 { len += 1; } let s = slice::from_raw_parts(p, len); - self.cur = self.cur.add(len + 1); + *cur = cur.add(len + 1); // Windows allows environment variables to start with an equals // symbol (in any other position, this is the separator between @@ -137,7 +181,7 @@ pub fn env() -> Env { if ch.is_null() { panic!("failure getting env string from OS: {}", io::Error::last_os_error()); } - Env { base: ch, cur: ch } + Env { base: ch, iter: EnvIterator(ch) } } } diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index e3493cbb850..2dd0c67acdb 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -652,7 +652,7 @@ impl Process { } } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] pub struct ExitStatus(c::DWORD); impl ExitStatus { diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 195d175cc9b..67db5ebd89c 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -459,6 +459,7 @@ impl Wtf8Buf { /// Converts this `Wtf8Buf` into a boxed `Wtf8`. #[inline] pub fn into_box(self) -> Box<Wtf8> { + // SAFETY: relies on `Wtf8` being `repr(transparent)`. unsafe { mem::transmute(self.bytes.into_boxed_slice()) } } @@ -511,6 +512,7 @@ impl Extend<CodePoint> for Wtf8Buf { /// Similar to `&str`, but can additionally contain surrogate code points /// if they’re not in a surrogate pair. #[derive(Eq, Ord, PartialEq, PartialOrd)] +#[repr(transparent)] pub struct Wtf8 { bytes: [u8], } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 1b86d898cc7..21515adc6c4 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -313,7 +313,6 @@ impl<T: 'static> LocalKey<Cell<T>> { /// # Examples /// /// ``` - /// #![feature(local_key_cell_methods)] /// use std::cell::Cell; /// /// thread_local! { @@ -326,7 +325,7 @@ impl<T: 'static> LocalKey<Cell<T>> { /// /// assert_eq!(X.get(), 123); /// ``` - #[unstable(feature = "local_key_cell_methods", issue = "92122")] + #[stable(feature = "local_key_cell_methods", since = "CURRENT_RUSTC_VERSION")] pub fn set(&'static self, value: T) { self.initialize_with(Cell::new(value), |value, cell| { if let Some(value) = value { @@ -351,7 +350,6 @@ impl<T: 'static> LocalKey<Cell<T>> { /// # Examples /// /// ``` - /// #![feature(local_key_cell_methods)] /// use std::cell::Cell; /// /// thread_local! { @@ -360,7 +358,7 @@ impl<T: 'static> LocalKey<Cell<T>> { /// /// assert_eq!(X.get(), 1); /// ``` - #[unstable(feature = "local_key_cell_methods", issue = "92122")] + #[stable(feature = "local_key_cell_methods", since = "CURRENT_RUSTC_VERSION")] pub fn get(&'static self) -> T where T: Copy, @@ -381,7 +379,6 @@ impl<T: 'static> LocalKey<Cell<T>> { /// # Examples /// /// ``` - /// #![feature(local_key_cell_methods)] /// use std::cell::Cell; /// /// thread_local! { @@ -391,7 +388,7 @@ impl<T: 'static> LocalKey<Cell<T>> { /// assert_eq!(X.take(), Some(1)); /// assert_eq!(X.take(), None); /// ``` - #[unstable(feature = "local_key_cell_methods", issue = "92122")] + #[stable(feature = "local_key_cell_methods", since = "CURRENT_RUSTC_VERSION")] pub fn take(&'static self) -> T where T: Default, @@ -412,7 +409,6 @@ impl<T: 'static> LocalKey<Cell<T>> { /// # Examples /// /// ``` - /// #![feature(local_key_cell_methods)] /// use std::cell::Cell; /// /// thread_local! { @@ -422,7 +418,7 @@ impl<T: 'static> LocalKey<Cell<T>> { /// assert_eq!(X.replace(2), 1); /// assert_eq!(X.replace(3), 2); /// ``` - #[unstable(feature = "local_key_cell_methods", issue = "92122")] + #[stable(feature = "local_key_cell_methods", since = "CURRENT_RUSTC_VERSION")] pub fn replace(&'static self, value: T) -> T { self.with(|cell| cell.replace(value)) } @@ -444,7 +440,6 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// # Example /// /// ``` - /// #![feature(local_key_cell_methods)] /// use std::cell::RefCell; /// /// thread_local! { @@ -453,7 +448,7 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// /// X.with_borrow(|v| assert!(v.is_empty())); /// ``` - #[unstable(feature = "local_key_cell_methods", issue = "92122")] + #[stable(feature = "local_key_cell_methods", since = "CURRENT_RUSTC_VERSION")] pub fn with_borrow<F, R>(&'static self, f: F) -> R where F: FnOnce(&T) -> R, @@ -476,7 +471,6 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// # Example /// /// ``` - /// #![feature(local_key_cell_methods)] /// use std::cell::RefCell; /// /// thread_local! { @@ -487,7 +481,7 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// /// X.with_borrow(|v| assert_eq!(*v, vec![1])); /// ``` - #[unstable(feature = "local_key_cell_methods", issue = "92122")] + #[stable(feature = "local_key_cell_methods", since = "CURRENT_RUSTC_VERSION")] pub fn with_borrow_mut<F, R>(&'static self, f: F) -> R where F: FnOnce(&mut T) -> R, @@ -511,7 +505,6 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// # Examples /// /// ``` - /// #![feature(local_key_cell_methods)] /// use std::cell::RefCell; /// /// thread_local! { @@ -524,7 +517,7 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3])); /// ``` - #[unstable(feature = "local_key_cell_methods", issue = "92122")] + #[stable(feature = "local_key_cell_methods", since = "CURRENT_RUSTC_VERSION")] pub fn set(&'static self, value: T) { self.initialize_with(RefCell::new(value), |value, cell| { if let Some(value) = value { @@ -551,7 +544,6 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// # Examples /// /// ``` - /// #![feature(local_key_cell_methods)] /// use std::cell::RefCell; /// /// thread_local! { @@ -566,7 +558,7 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// /// X.with_borrow(|v| assert!(v.is_empty())); /// ``` - #[unstable(feature = "local_key_cell_methods", issue = "92122")] + #[stable(feature = "local_key_cell_methods", since = "CURRENT_RUSTC_VERSION")] pub fn take(&'static self) -> T where T: Default, @@ -586,7 +578,6 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// # Examples /// /// ``` - /// #![feature(local_key_cell_methods)] /// use std::cell::RefCell; /// /// thread_local! { @@ -598,7 +589,7 @@ impl<T: 'static> LocalKey<RefCell<T>> { /// /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3])); /// ``` - #[unstable(feature = "local_key_cell_methods", issue = "92122")] + #[stable(feature = "local_key_cell_methods", since = "CURRENT_RUSTC_VERSION")] pub fn replace(&'static self, value: T) -> T { self.with(|cell| cell.replace(value)) } |
