about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/alloc/src/rc.rs5
-rw-r--r--library/alloc/src/sync.rs5
-rw-r--r--library/std/src/ffi/c_str.rs69
-rw-r--r--library/std/src/ffi/c_str/tests.rs37
-rw-r--r--library/std/src/io/cursor.rs53
-rw-r--r--library/std/src/io/cursor/tests.rs84
-rw-r--r--library/std/src/io/stdio.rs79
-rw-r--r--library/std/src/keyword_docs.rs14
-rw-r--r--library/std/src/os/l4re/fs.rs382
-rw-r--r--library/std/src/os/l4re/mod.rs7
-rw-r--r--library/std/src/os/l4re/raw.rs365
-rw-r--r--library/std/src/os/mod.rs4
-rw-r--r--library/std/src/os/unix/mod.rs4
-rw-r--r--library/std/src/os/unix/process.rs10
-rw-r--r--library/std/src/os/windows/io/handle.rs12
-rw-r--r--library/std/src/os/windows/io/raw.rs25
-rw-r--r--library/std/src/path/tests.rs14
-rw-r--r--library/std/src/sys/unix/l4re.rs58
-rw-r--r--library/std/src/sys/unix/mod.rs1
-rw-r--r--library/std/src/sys/unix/process/process_common.rs12
-rw-r--r--library/std/src/sys/unix/process/process_common/tests.rs55
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs20
-rw-r--r--library/std/src/sys/windows/process.rs67
-rw-r--r--library/std/src/sys/windows/process/tests.rs7
-rw-r--r--src/test/ui/check-cfg/mix.rs22
-rw-r--r--src/test/ui/check-cfg/mix.stderr96
-rw-r--r--src/tools/compiletest/src/main.rs5
27 files changed, 1379 insertions, 133 deletions
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 3065169e5e2..ea651c075d9 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -2112,9 +2112,10 @@ impl<T> Weak<T> {
     /// assert!(empty.upgrade().is_none());
     /// ```
     #[stable(feature = "downgraded_weak", since = "1.10.0")]
+    #[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")]
     #[must_use]
-    pub fn new() -> Weak<T> {
-        Weak { ptr: NonNull::new(usize::MAX as *mut RcBox<T>).expect("MAX is not 0") }
+    pub const fn new() -> Weak<T> {
+        Weak { ptr: unsafe { NonNull::new_unchecked(usize::MAX as *mut RcBox<T>) } }
     }
 }
 
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 2140c3f168d..ba3187294e6 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1742,9 +1742,10 @@ impl<T> Weak<T> {
     /// assert!(empty.upgrade().is_none());
     /// ```
     #[stable(feature = "downgraded_weak", since = "1.10.0")]
+    #[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")]
     #[must_use]
-    pub fn new() -> Weak<T> {
-        Weak { ptr: NonNull::new(usize::MAX as *mut ArcInner<T>).expect("MAX is not 0") }
+    pub const fn new() -> Weak<T> {
+        Weak { ptr: unsafe { NonNull::new_unchecked(usize::MAX as *mut ArcInner<T>) } }
     }
 }
 
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index b833d0e2ca5..a68def1e83d 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -328,6 +328,27 @@ impl FromVecWithNulError {
     }
 }
 
+/// An error indicating that no nul byte was present.
+///
+/// A slice used to create a [`CStr`] must contain a nul byte somewhere
+/// within the slice.
+///
+/// This error is created by the [`CStr::from_bytes_until_nul`] method.
+///
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+pub struct FromBytesUntilNulError(());
+
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+impl Error for FromBytesUntilNulError {}
+
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+impl fmt::Display for FromBytesUntilNulError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "data provided does not contain a nul")
+    }
+}
+
 /// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
 ///
 /// `CString` is just a wrapper over a buffer of bytes with a nul terminator;
@@ -1241,10 +1262,58 @@ impl CStr {
 
     /// Creates a C string wrapper from a byte slice.
     ///
+    /// This method will create a `CStr` from any byte slice that contains at
+    /// least one nul byte. The caller does not need to know or specify where
+    /// the nul byte is located.
+    ///
+    /// If the first byte is a nul character, this method will return an
+    /// empty `CStr`. If multiple nul characters are present, the `CStr` will
+    /// end at the first one.
+    ///
+    /// If the slice only has a single nul byte at the end, this method is
+    /// equivalent to [`CStr::from_bytes_with_nul`].
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(cstr_from_bytes_until_nul)]
+    ///
+    /// use std::ffi::CStr;
+    ///
+    /// let mut buffer = [0u8; 16];
+    /// unsafe {
+    ///     // Here we might call an unsafe C function that writes a string
+    ///     // into the buffer.
+    ///     let buf_ptr = buffer.as_mut_ptr();
+    ///     buf_ptr.write_bytes(b'A', 8);
+    /// }
+    /// // Attempt to extract a C nul-terminated string from the buffer.
+    /// let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap();
+    /// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
+    /// ```
+    ///
+    #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+    pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
+        let nul_pos = memchr::memchr(0, bytes);
+        match nul_pos {
+            Some(nul_pos) => {
+                // SAFETY: We know there is a nul byte at nul_pos, so this slice
+                // (ending at the nul byte) is a well-formed C string.
+                let subslice = &bytes[..nul_pos + 1];
+                Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) })
+            }
+            None => Err(FromBytesUntilNulError(())),
+        }
+    }
+
+    /// Creates a C string wrapper from a byte slice.
+    ///
     /// This function will cast the provided `bytes` to a `CStr`
     /// wrapper after ensuring that the byte slice is nul-terminated
     /// and does not contain any interior nul bytes.
     ///
+    /// If the nul byte may not be at the end,
+    /// [`CStr::from_bytes_until_nul`] can be used instead.
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs
index 8d603229315..c20da138a18 100644
--- a/library/std/src/ffi/c_str/tests.rs
+++ b/library/std/src/ffi/c_str/tests.rs
@@ -118,6 +118,43 @@ fn from_bytes_with_nul_interior() {
 }
 
 #[test]
+fn cstr_from_bytes_until_nul() {
+    // Test an empty slice. This should fail because it
+    // does not contain a nul byte.
+    let b = b"";
+    assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));
+
+    // Test a non-empty slice, that does not contain a nul byte.
+    let b = b"hello";
+    assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));
+
+    // Test an empty nul-terminated string
+    let b = b"\0";
+    let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
+    assert_eq!(r.to_bytes(), b"");
+
+    // Test a slice with the nul byte in the middle
+    let b = b"hello\0world!";
+    let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
+    assert_eq!(r.to_bytes(), b"hello");
+
+    // Test a slice with the nul byte at the end
+    let b = b"hello\0";
+    let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
+    assert_eq!(r.to_bytes(), b"hello");
+
+    // Test a slice with two nul bytes at the end
+    let b = b"hello\0\0";
+    let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
+    assert_eq!(r.to_bytes(), b"hello");
+
+    // Test a slice containing lots of nul bytes
+    let b = b"\0\0\0\0";
+    let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
+    assert_eq!(r.to_bytes(), b"");
+}
+
+#[test]
 fn into_boxed() {
     let orig: &[u8] = b"Hello, world!\0";
     let cstr = CStr::from_bytes_with_nul(orig).unwrap();
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index fc19704bece..57f1d628f6a 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -3,6 +3,7 @@ mod tests;
 
 use crate::io::prelude::*;
 
+use crate::alloc::Allocator;
 use crate::cmp;
 use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 
@@ -398,7 +399,10 @@ fn slice_write_vectored(
 }
 
 // Resizing write implementation
-fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
+fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
+where
+    A: Allocator,
+{
     let pos: usize = (*pos_mut).try_into().map_err(|_| {
         io::const_io_error!(
             ErrorKind::InvalidInput,
@@ -426,11 +430,14 @@ fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usi
     Ok(buf.len())
 }
 
-fn vec_write_vectored(
+fn vec_write_vectored<A>(
     pos_mut: &mut u64,
-    vec: &mut Vec<u8>,
+    vec: &mut Vec<u8, A>,
     bufs: &[IoSlice<'_>],
-) -> io::Result<usize> {
+) -> io::Result<usize>
+where
+    A: Allocator,
+{
     let mut nwritten = 0;
     for buf in bufs {
         nwritten += vec_write(pos_mut, vec, buf)?;
@@ -462,7 +469,10 @@ impl Write for Cursor<&mut [u8]> {
 }
 
 #[stable(feature = "cursor_mut_vec", since = "1.25.0")]
-impl Write for Cursor<&mut Vec<u8>> {
+impl<A> Write for Cursor<&mut Vec<u8, A>>
+where
+    A: Allocator,
+{
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         vec_write(&mut self.pos, self.inner, buf)
     }
@@ -483,7 +493,10 @@ impl Write for Cursor<&mut Vec<u8>> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl Write for Cursor<Vec<u8>> {
+impl<A> Write for Cursor<Vec<u8, A>>
+where
+    A: Allocator,
+{
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         vec_write(&mut self.pos, &mut self.inner, buf)
     }
@@ -504,7 +517,33 @@ impl Write for Cursor<Vec<u8>> {
 }
 
 #[stable(feature = "cursor_box_slice", since = "1.5.0")]
-impl Write for Cursor<Box<[u8]>> {
+impl<A> Write for Cursor<Box<[u8], A>>
+where
+    A: Allocator,
+{
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        slice_write(&mut self.pos, &mut self.inner, buf)
+    }
+
+    #[inline]
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        slice_write_vectored(&mut self.pos, &mut self.inner, bufs)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+#[stable(feature = "cursor_array", since = "1.61.0")]
+impl<const N: usize> Write for Cursor<[u8; N]> {
     #[inline]
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         slice_write(&mut self.pos, &mut self.inner, buf)
diff --git a/library/std/src/io/cursor/tests.rs b/library/std/src/io/cursor/tests.rs
index 5da31ce0ba7..f1ee177b7f3 100644
--- a/library/std/src/io/cursor/tests.rs
+++ b/library/std/src/io/cursor/tests.rs
@@ -50,9 +50,11 @@ fn test_mem_mut_writer() {
     assert_eq!(&writer.get_ref()[..], b);
 }
 
-#[test]
-fn test_box_slice_writer() {
-    let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+fn test_slice_writer<T>(writer: &mut Cursor<T>)
+where
+    T: AsRef<[u8]>,
+    Cursor<T>: Write,
+{
     assert_eq!(writer.position(), 0);
     assert_eq!(writer.write(&[0]).unwrap(), 1);
     assert_eq!(writer.position(), 1);
@@ -65,12 +67,14 @@ fn test_box_slice_writer() {
     assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
     assert_eq!(writer.write(&[10]).unwrap(), 0);
     let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
-    assert_eq!(&**writer.get_ref(), b);
+    assert_eq!(writer.get_ref().as_ref(), b);
 }
 
-#[test]
-fn test_box_slice_writer_vectored() {
-    let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+fn test_slice_writer_vectored<T>(writer: &mut Cursor<T>)
+where
+    T: AsRef<[u8]>,
+    Cursor<T>: Write,
+{
     assert_eq!(writer.position(), 0);
     assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
     assert_eq!(writer.position(), 1);
@@ -85,53 +89,45 @@ fn test_box_slice_writer_vectored() {
     assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
     assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
     let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
-    assert_eq!(&**writer.get_ref(), b);
+    assert_eq!(writer.get_ref().as_ref(), b);
+}
+
+#[test]
+fn test_box_slice_writer() {
+    let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+    test_slice_writer(&mut writer);
+}
+
+#[test]
+fn test_box_slice_writer_vectored() {
+    let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+    test_slice_writer_vectored(&mut writer);
+}
+
+#[test]
+fn test_array_writer() {
+    let mut writer = Cursor::new([0u8; 9]);
+    test_slice_writer(&mut writer);
+}
+
+#[test]
+fn test_array_writer_vectored() {
+    let mut writer = Cursor::new([0u8; 9]);
+    test_slice_writer_vectored(&mut writer);
 }
 
 #[test]
 fn test_buf_writer() {
     let mut buf = [0 as u8; 9];
-    {
-        let mut writer = Cursor::new(&mut buf[..]);
-        assert_eq!(writer.position(), 0);
-        assert_eq!(writer.write(&[0]).unwrap(), 1);
-        assert_eq!(writer.position(), 1);
-        assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
-        assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
-        assert_eq!(writer.position(), 8);
-        assert_eq!(writer.write(&[]).unwrap(), 0);
-        assert_eq!(writer.position(), 8);
-
-        assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
-        assert_eq!(writer.write(&[10]).unwrap(), 0);
-    }
-    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
-    assert_eq!(buf, b);
+    let mut writer = Cursor::new(&mut buf[..]);
+    test_slice_writer(&mut writer);
 }
 
 #[test]
 fn test_buf_writer_vectored() {
     let mut buf = [0 as u8; 9];
-    {
-        let mut writer = Cursor::new(&mut buf[..]);
-        assert_eq!(writer.position(), 0);
-        assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
-        assert_eq!(writer.position(), 1);
-        assert_eq!(
-            writer
-                .write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],)
-                .unwrap(),
-            7,
-        );
-        assert_eq!(writer.position(), 8);
-        assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
-        assert_eq!(writer.position(), 8);
-
-        assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
-        assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
-    }
-    let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
-    assert_eq!(buf, b);
+    let mut writer = Cursor::new(&mut buf[..]);
+    test_slice_writer_vectored(&mut writer);
 }
 
 #[test]
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 50344e602a9..ac6d41e13b0 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -202,12 +202,18 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
 ///
 /// [`io::stdin`]: stdin
 ///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
 ///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
 /// an error.
 ///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
 /// # Examples
 ///
 /// ```no_run
@@ -230,12 +236,18 @@ pub struct Stdin {
 /// This handle implements both the [`Read`] and [`BufRead`] traits, and
 /// is constructed via the [`Stdin::lock`] method.
 ///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
 ///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
 /// an error.
 ///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
 /// # Examples
 ///
 /// ```no_run
@@ -263,11 +275,18 @@ pub struct StdinLock<'a> {
 /// is synchronized via a mutex. If you need more explicit control over
 /// locking, see the [`Stdin::lock`] method.
 ///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
 /// an error.
 ///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
 /// # Examples
 ///
 /// Using implicit synchronization:
@@ -490,11 +509,18 @@ impl fmt::Debug for StdinLock<'_> {
 ///
 /// Created by the [`io::stdout`] method.
 ///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
 /// an error.
 ///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
 /// [`lock`]: Stdout::lock
 /// [`io::stdout`]: stdout
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -510,10 +536,17 @@ pub struct Stdout {
 /// This handle implements the [`Write`] trait, and is constructed via
 /// the [`Stdout::lock`] method. See its documentation for more.
 ///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
 /// an error.
+///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
 #[must_use = "if unused stdout will immediately unlock"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StdoutLock<'a> {
@@ -528,11 +561,18 @@ static STDOUT: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = Sy
 /// is synchronized via a mutex. If you need more explicit control over
 /// locking, see the [`Stdout::lock`] method.
 ///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
 /// an error.
 ///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
 /// # Examples
 ///
 /// Using implicit synchronization:
@@ -710,10 +750,17 @@ impl fmt::Debug for StdoutLock<'_> {
 ///
 /// [`io::stderr`]: stderr
 ///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
 /// an error.
+///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Stderr {
     inner: Pin<&'static ReentrantMutex<RefCell<StderrRaw>>>,
@@ -724,10 +771,17 @@ pub struct Stderr {
 /// This handle implements the [`Write`] trait and is constructed via
 /// the [`Stderr::lock`] method. See its documentation for more.
 ///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
 /// an error.
+///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
 #[must_use = "if unused stderr will immediately unlock"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StderrLock<'a> {
@@ -738,11 +792,18 @@ pub struct StderrLock<'a> {
 ///
 /// This handle is not buffered.
 ///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
 /// an error.
 ///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
 /// # Examples
 ///
 /// Using implicit synchronization:
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 542b793f6da..bc2384c88d2 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -728,6 +728,20 @@ mod impl_keyword {}
 /// [`IntoIterator`]: ../book/ch13-04-performance.html
 /// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns
 /// [`for`]: keyword.for.html
+///
+/// The other use of `in` is with the keyword `pub`. It allows users to declare an item as visible
+/// only within a given scope.
+///
+/// ## Literal Example:
+///
+///    * `pub(in crate::outer_mod) fn outer_mod_visible_fn() {}` - fn is visible in `outer_mod`
+///
+/// Starting with the 2018 edition, paths for `pub(in path)` must start with `crate`, `self` or
+/// `super`. The 2015 edition may also use paths starting with `::` or modules from the crate root.
+///
+/// For more information, see the [Reference].
+///
+/// [Reference]: ../reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself
 mod in_keyword {}
 
 #[doc(keyword = "let")]
diff --git a/library/std/src/os/l4re/fs.rs b/library/std/src/os/l4re/fs.rs
new file mode 100644
index 00000000000..b9b6918292f
--- /dev/null
+++ b/library/std/src/os/l4re/fs.rs
@@ -0,0 +1,382 @@
+//! L4Re-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+#[allow(deprecated)]
+use crate::os::l4re::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    /// Gain a reference to the underlying `stat` structure which contains
+    /// the raw information returned by the OS.
+    ///
+    /// The contents of the returned [`stat`] are **not** consistent across
+    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+    /// cross-Unix abstractions contained within the raw stat.
+    ///
+    /// [`stat`]: struct@crate::os::linux::raw::stat
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let stat = meta.as_raw_stat();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    #[rustc_deprecated(since = "1.8.0", reason = "other methods of this trait are now preferred")]
+    #[allow(deprecated)]
+    fn as_raw_stat(&self) -> &raw::stat;
+
+    /// Returns the device ID on which this file resides.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_dev());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_dev(&self) -> u64;
+    /// Returns the inode number.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ino());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ino(&self) -> u64;
+    /// Returns the file type and mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mode());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mode(&self) -> u32;
+    /// Returns the number of hard links to file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_nlink());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_nlink(&self) -> u64;
+    /// Returns the user ID of the file owner.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_uid());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_uid(&self) -> u32;
+    /// Returns the group ID of the file owner.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_gid());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_gid(&self) -> u32;
+    /// Returns the device ID that this file represents. Only relevant for special file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_rdev());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_rdev(&self) -> u64;
+    /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+    ///
+    /// The size of a symbolic link is the length of the pathname it contains,
+    /// without a terminating null byte.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_size());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_size(&self) -> u64;
+    /// Returns the last access time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_atime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime(&self) -> i64;
+    /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+    ///
+    /// [`st_atime`]: Self::st_atime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_atime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime_nsec(&self) -> i64;
+    /// Returns the last modification time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mtime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime(&self) -> i64;
+    /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+    ///
+    /// [`st_mtime`]: Self::st_mtime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_mtime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime_nsec(&self) -> i64;
+    /// Returns the last status change time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ctime());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime(&self) -> i64;
+    /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+    ///
+    /// [`st_ctime`]: Self::st_ctime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_ctime_nsec());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime_nsec(&self) -> i64;
+    /// Returns the "preferred" block size for efficient filesystem I/O.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_blksize());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blksize(&self) -> u64;
+    /// Returns the number of blocks allocated to the file, 512-byte units.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::io;
+    /// use std::os::linux::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     println!("{}", meta.st_blocks());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+    #[allow(deprecated)]
+    fn as_raw_stat(&self) -> &raw::stat {
+        unsafe { &*(self.as_inner().as_inner() as *const libc::stat64 as *const raw::stat) }
+    }
+    fn st_dev(&self) -> u64 {
+        self.as_inner().as_inner().st_dev as u64
+    }
+    fn st_ino(&self) -> u64 {
+        self.as_inner().as_inner().st_ino as u64
+    }
+    fn st_mode(&self) -> u32 {
+        self.as_inner().as_inner().st_mode as u32
+    }
+    fn st_nlink(&self) -> u64 {
+        self.as_inner().as_inner().st_nlink as u64
+    }
+    fn st_uid(&self) -> u32 {
+        self.as_inner().as_inner().st_uid as u32
+    }
+    fn st_gid(&self) -> u32 {
+        self.as_inner().as_inner().st_gid as u32
+    }
+    fn st_rdev(&self) -> u64 {
+        self.as_inner().as_inner().st_rdev as u64
+    }
+    fn st_size(&self) -> u64 {
+        self.as_inner().as_inner().st_size as u64
+    }
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atime as i64
+    }
+    fn st_atime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_atime_nsec as i64
+    }
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime as i64
+    }
+    fn st_mtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime_nsec as i64
+    }
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime as i64
+    }
+    fn st_ctime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime_nsec as i64
+    }
+    fn st_blksize(&self) -> u64 {
+        self.as_inner().as_inner().st_blksize as u64
+    }
+    fn st_blocks(&self) -> u64 {
+        self.as_inner().as_inner().st_blocks as u64
+    }
+}
diff --git a/library/std/src/os/l4re/mod.rs b/library/std/src/os/l4re/mod.rs
new file mode 100644
index 00000000000..14c2425c165
--- /dev/null
+++ b/library/std/src/os/l4re/mod.rs
@@ -0,0 +1,7 @@
+//! L4Re-specific definitions.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![doc(cfg(target_os = "l4re"))]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/l4re/raw.rs b/library/std/src/os/l4re/raw.rs
new file mode 100644
index 00000000000..5efd6301fc9
--- /dev/null
+++ b/library/std/src/os/l4re/raw.rs
@@ -0,0 +1,365 @@
+//! L4Re-specific raw type definitions.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![rustc_deprecated(
+    since = "1.8.0",
+    reason = "these type aliases are no longer supported by \
+              the standard library, the `libc` crate on \
+              crates.io should be used instead for the correct \
+              definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = u32;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+
+#[cfg(any(
+    target_arch = "x86",
+    target_arch = "le32",
+    target_arch = "m68k",
+    target_arch = "powerpc",
+    target_arch = "sparc",
+    target_arch = "arm",
+    target_arch = "asmjs",
+    target_arch = "wasm32"
+))]
+mod arch {
+    use crate::os::raw::{c_long, c_short, c_uint};
+
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blkcnt_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blksize_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type ino_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type nlink_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type off_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type time_t = i64;
+
+    #[repr(C)]
+    #[derive(Clone)]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub struct stat {
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_dev: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __pad1: c_short,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __st_ino: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mode: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_nlink: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_uid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_gid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_rdev: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __pad2: c_uint,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_size: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blksize: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blocks: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ino: u64,
+    }
+}
+
+#[cfg(target_arch = "mips")]
+mod arch {
+    use crate::os::raw::{c_long, c_ulong};
+
+    #[cfg(target_env = "musl")]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blkcnt_t = i64;
+    #[cfg(not(target_env = "musl"))]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blkcnt_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blksize_t = u64;
+    #[cfg(target_env = "musl")]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type ino_t = u64;
+    #[cfg(not(target_env = "musl"))]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type ino_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type nlink_t = u64;
+    #[cfg(target_env = "musl")]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type off_t = u64;
+    #[cfg(not(target_env = "musl"))]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type off_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type time_t = i64;
+
+    #[repr(C)]
+    #[derive(Clone)]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub struct stat {
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_dev: c_ulong,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_pad1: [c_long; 3],
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ino: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mode: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_nlink: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_uid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_gid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_rdev: c_ulong,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_pad2: [c_long; 2],
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_size: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blksize: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blocks: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_pad5: [c_long; 14],
+    }
+}
+
+#[cfg(target_arch = "hexagon")]
+mod arch {
+    use crate::os::raw::{c_int, c_long, c_uint};
+
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blkcnt_t = i64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blksize_t = c_long;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type ino_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type nlink_t = c_uint;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type off_t = i64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type time_t = i64;
+
+    #[repr(C)]
+    #[derive(Clone)]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub struct stat {
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_dev: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ino: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mode: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_nlink: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_uid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_gid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_rdev: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __pad1: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_size: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blksize: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __pad2: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blocks: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __pad3: [c_int; 2],
+    }
+}
+
+#[cfg(any(
+    target_arch = "mips64",
+    target_arch = "s390x",
+    target_arch = "sparc64",
+    target_arch = "riscv64",
+    target_arch = "riscv32"
+))]
+mod arch {
+    pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
+}
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+    use crate::os::raw::{c_int, c_long};
+
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blkcnt_t = i64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blksize_t = i32;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type ino_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type nlink_t = u32;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type off_t = i64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type time_t = c_long;
+
+    #[repr(C)]
+    #[derive(Clone)]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub struct stat {
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_dev: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ino: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mode: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_nlink: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_uid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_gid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_rdev: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __pad1: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_size: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blksize: i32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __pad2: c_int,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blocks: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime: time_t,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime: time_t,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime: time_t,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __unused: [c_int; 2],
+    }
+}
+
+#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))]
+mod arch {
+    use crate::os::raw::{c_int, c_long};
+
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blkcnt_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type blksize_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type ino_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type nlink_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type off_t = u64;
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub type time_t = i64;
+
+    #[repr(C)]
+    #[derive(Clone)]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub struct stat {
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_dev: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ino: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_nlink: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mode: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_uid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_gid: u32,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __pad0: c_int,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_rdev: u64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_size: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blksize: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_blocks: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_atime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_mtime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime: i64,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub st_ctime_nsec: c_long,
+        #[stable(feature = "raw_ext", since = "1.1.0")]
+        pub __unused: [c_long; 3],
+    }
+}
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 90c30313dbb..029f131c40b 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -81,7 +81,7 @@ pub mod unix;
         all(target_vendor = "fortanix", target_env = "sgx")
     )
 )))]
-#[cfg(any(target_os = "linux", target_os = "l4re", doc))]
+#[cfg(any(target_os = "linux", doc))]
 pub mod linux;
 
 // wasi
@@ -127,6 +127,8 @@ pub mod haiku;
 pub mod illumos;
 #[cfg(target_os = "ios")]
 pub mod ios;
+#[cfg(target_os = "l4re")]
+pub mod l4re;
 #[cfg(target_os = "macos")]
 pub mod macos;
 #[cfg(target_os = "netbsd")]
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 62f750fa607..7b8ca79eeb8 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -55,7 +55,9 @@ mod platform {
     pub use crate::os::illumos::*;
     #[cfg(target_os = "ios")]
     pub use crate::os::ios::*;
-    #[cfg(any(target_os = "linux", target_os = "l4re"))]
+    #[cfg(target_os = "l4re")]
+    pub use crate::os::l4re::*;
+    #[cfg(target_os = "linux")]
     pub use crate::os::linux::*;
     #[cfg(target_os = "macos")]
     pub use crate::os::macos::*;
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 855f900430c..d95bc9b15c9 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -149,6 +149,11 @@ pub trait CommandExt: Sealed {
     fn arg0<S>(&mut self, arg: S) -> &mut process::Command
     where
         S: AsRef<OsStr>;
+
+    /// Sets the process group ID of the child process. Translates to a `setpgid` call in the child
+    /// process.
+    #[unstable(feature = "process_set_process_group", issue = "93857")]
+    fn process_group(&mut self, pgroup: i32) -> &mut process::Command;
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -201,6 +206,11 @@ impl CommandExt for process::Command {
         self.as_inner_mut().set_arg_0(arg.as_ref());
         self
     }
+
+    fn process_group(&mut self, pgroup: i32) -> &mut process::Command {
+        self.as_inner_mut().pgroup(pgroup);
+        self
+    }
 }
 
 /// Unix-specific extensions to [`process::ExitStatus`] and
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 14b94d8dcdf..be2ccbd98e9 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -164,12 +164,22 @@ impl OwnedHandle {
         inherit: bool,
         options: c::DWORD,
     ) -> io::Result<Self> {
+        let handle = self.as_raw_handle();
+
+        // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as
+        // in a process with a detached console. `DuplicateHandle` would fail
+        // if we passed it a null handle, but we can treat null as a valid
+        // handle which doesn't do any I/O, and allow it to be duplicated.
+        if handle.is_null() {
+            return unsafe { Ok(Self::from_raw_handle(handle)) };
+        }
+
         let mut ret = 0 as c::HANDLE;
         cvt(unsafe {
             let cur_proc = c::GetCurrentProcess();
             c::DuplicateHandle(
                 cur_proc,
-                self.as_raw_handle(),
+                handle,
                 cur_proc,
                 &mut ret,
                 access,
diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs
index 48c5fd358d9..68fa8918a56 100644
--- a/library/std/src/os/windows/io/raw.rs
+++ b/library/std/src/os/windows/io/raw.rs
@@ -9,6 +9,7 @@ use crate::net;
 use crate::os::windows::io::{AsHandle, AsSocket};
 use crate::os::windows::io::{OwnedHandle, OwnedSocket};
 use crate::os::windows::raw;
+use crate::ptr;
 use crate::sys;
 use crate::sys::c;
 use crate::sys_common::{self, AsInner, FromInner, IntoInner};
@@ -96,45 +97,57 @@ impl AsRawHandle for fs::File {
 #[stable(feature = "asraw_stdio", since = "1.21.0")]
 impl AsRawHandle for io::Stdin {
     fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
+        stdio_handle(unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle })
     }
 }
 
 #[stable(feature = "asraw_stdio", since = "1.21.0")]
 impl AsRawHandle for io::Stdout {
     fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
+        stdio_handle(unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle })
     }
 }
 
 #[stable(feature = "asraw_stdio", since = "1.21.0")]
 impl AsRawHandle for io::Stderr {
     fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
+        stdio_handle(unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle })
     }
 }
 
 #[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
 impl<'a> AsRawHandle for io::StdinLock<'a> {
     fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
+        stdio_handle(unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle })
     }
 }
 
 #[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
 impl<'a> AsRawHandle for io::StdoutLock<'a> {
     fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
+        stdio_handle(unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle })
     }
 }
 
 #[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
 impl<'a> AsRawHandle for io::StderrLock<'a> {
     fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
+        stdio_handle(unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle })
     }
 }
 
+// Translate a handle returned from `GetStdHandle` into a handle to return to
+// the user.
+fn stdio_handle(raw: RawHandle) -> RawHandle {
+    // `GetStdHandle` isn't expected to actually fail, so when it returns
+    // `INVALID_HANDLE_VALUE`, it means we were launched from a parent which
+    // didn't provide us with stdio handles, such as a parent with a detached
+    // console. In that case, return null to the user, which is consistent
+    // with what they'd get in the parent, and which avoids the problem that
+    // `INVALID_HANDLE_VALUE` aliases the current process handle.
+    if raw == c::INVALID_HANDLE_VALUE { ptr::null_mut() } else { raw }
+}
+
 #[stable(feature = "from_raw_os", since = "1.1.0")]
 impl FromRawHandle for fs::File {
     #[inline]
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index c8dc768d3fc..d1f59d2786e 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -1739,11 +1739,11 @@ fn test_windows_absolute() {
     let relative = r"a\b";
     let mut expected = crate::env::current_dir().unwrap();
     expected.push(relative);
-    assert_eq!(absolute(relative).unwrap(), expected);
+    assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str());
 
     macro_rules! unchanged(
         ($path:expr) => {
-            assert_eq!(absolute($path).unwrap(), Path::new($path));
+            assert_eq!(absolute($path).unwrap().as_os_str(), Path::new($path).as_os_str());
         }
     );
 
@@ -1759,11 +1759,11 @@ fn test_windows_absolute() {
     // Verbatim paths are always unchanged, no matter what.
     unchanged!(r"\\?\path.\to/file..");
 
-    assert_eq!(absolute(r"C:\path..\to.\file.").unwrap(), Path::new(r"C:\path..\to\file"));
-    assert_eq!(absolute(r"C:\path\to\COM1").unwrap(), Path::new(r"\\.\COM1"));
-    assert_eq!(absolute(r"C:\path\to\COM1.txt").unwrap(), Path::new(r"\\.\COM1"));
-    assert_eq!(absolute(r"C:\path\to\COM1  .txt").unwrap(), Path::new(r"\\.\COM1"));
-    assert_eq!(absolute(r"C:\path\to\cOnOuT$").unwrap(), Path::new(r"\\.\cOnOuT$"));
+    assert_eq!(
+        absolute(r"C:\path..\to.\file.").unwrap().as_os_str(),
+        Path::new(r"C:\path..\to\file").as_os_str()
+    );
+    assert_eq!(absolute(r"COM1").unwrap().as_os_str(), Path::new(r"\\.\COM1").as_os_str());
 }
 
 #[bench]
diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs
index d13e1ecbbfe..f052d8f7f05 100644
--- a/library/std/src/sys/unix/l4re.rs
+++ b/library/std/src/sys/unix/l4re.rs
@@ -13,6 +13,7 @@ pub mod net {
     use crate::fmt;
     use crate::io::{self, IoSlice, IoSliceMut};
     use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+    use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
     use crate::sys::fd::FileDesc;
     use crate::sys_common::{AsInner, FromInner, IntoInner};
     use crate::time::Duration;
@@ -59,7 +60,7 @@ pub mod net {
         }
 
         pub fn is_read_vectored(&self) -> bool {
-            unimpl!();
+            false
         }
 
         pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
@@ -83,7 +84,7 @@ pub mod net {
         }
 
         pub fn is_write_vectored(&self) -> bool {
-            unimpl!();
+            false
         }
 
         pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
@@ -121,23 +122,52 @@ pub mod net {
         pub fn take_error(&self) -> io::Result<Option<io::Error>> {
             unimpl!();
         }
+
+        // This is used by sys_common code to abstract over Windows and Unix.
+        pub fn as_raw(&self) -> RawFd {
+            self.as_raw_fd()
+        }
+    }
+
+    impl AsInner<FileDesc> for Socket {
+        fn as_inner(&self) -> &FileDesc {
+            &self.0
+        }
+    }
+
+    impl FromInner<FileDesc> for Socket {
+        fn from_inner(file_desc: FileDesc) -> Socket {
+            Socket(file_desc)
+        }
     }
 
-    impl AsInner<libc::c_int> for Socket {
-        fn as_inner(&self) -> &libc::c_int {
-            self.0.as_inner()
+    impl IntoInner<FileDesc> for Socket {
+        fn into_inner(self) -> FileDesc {
+            self.0
         }
     }
 
-    impl FromInner<libc::c_int> for Socket {
-        fn from_inner(fd: libc::c_int) -> Socket {
-            Socket(FileDesc::new(fd))
+    impl AsFd for Socket {
+        fn as_fd(&self) -> BorrowedFd<'_> {
+            self.0.as_fd()
         }
     }
 
-    impl IntoInner<libc::c_int> for Socket {
-        fn into_inner(self) -> libc::c_int {
-            self.0.into_raw()
+    impl AsRawFd for Socket {
+        fn as_raw_fd(&self) -> RawFd {
+            self.0.as_raw_fd()
+        }
+    }
+
+    impl IntoRawFd for Socket {
+        fn into_raw_fd(self) -> RawFd {
+            self.0.into_raw_fd()
+        }
+    }
+
+    impl FromRawFd for Socket {
+        unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+            Self(FromRawFd::from_raw_fd(raw_fd))
         }
     }
 
@@ -191,7 +221,7 @@ pub mod net {
         }
 
         pub fn is_read_vectored(&self) -> bool {
-            unimpl!();
+            false
         }
 
         pub fn write(&self, _: &[u8]) -> io::Result<usize> {
@@ -203,7 +233,7 @@ pub mod net {
         }
 
         pub fn is_write_vectored(&self) -> bool {
-            unimpl!();
+            false
         }
 
         pub fn peer_addr(&self) -> io::Result<SocketAddr> {
@@ -497,7 +527,7 @@ pub mod net {
 
     impl LookupHost {
         pub fn port(&self) -> u16 {
-            unimpl!();
+            0 // unimplemented
         }
     }
 
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 605cc499b3c..7423d90263d 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -80,6 +80,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
                 target_os = "macos",
                 target_os = "ios",
                 target_os = "redox",
+                target_os = "l4re",
             )))] {
                 use crate::sys::os::errno;
                 let pfds: &mut [_] = &mut [
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index 97985ddd331..27bee714f5b 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -18,7 +18,7 @@ use crate::sys_common::IntoInner;
 #[cfg(not(target_os = "fuchsia"))]
 use crate::sys::fs::OpenOptions;
 
-use libc::{c_char, c_int, gid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS};
+use libc::{c_char, c_int, gid_t, pid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS};
 
 cfg_if::cfg_if! {
     if #[cfg(target_os = "fuchsia")] {
@@ -82,6 +82,7 @@ pub struct Command {
     stderr: Option<Stdio>,
     #[cfg(target_os = "linux")]
     create_pidfd: bool,
+    pgroup: Option<pid_t>,
 }
 
 // Create a new type for argv, so that we can make it `Send` and `Sync`
@@ -145,6 +146,7 @@ impl Command {
             stdin: None,
             stdout: None,
             stderr: None,
+            pgroup: None,
         }
     }
 
@@ -167,6 +169,7 @@ impl Command {
             stdout: None,
             stderr: None,
             create_pidfd: false,
+            pgroup: None,
         }
     }
 
@@ -202,6 +205,9 @@ impl Command {
     pub fn groups(&mut self, groups: &[gid_t]) {
         self.groups = Some(Box::from(groups));
     }
+    pub fn pgroup(&mut self, pgroup: pid_t) {
+        self.pgroup = Some(pgroup);
+    }
 
     #[cfg(target_os = "linux")]
     pub fn create_pidfd(&mut self, val: bool) {
@@ -265,6 +271,10 @@ impl Command {
     pub fn get_groups(&self) -> Option<&[gid_t]> {
         self.groups.as_deref()
     }
+    #[allow(dead_code)]
+    pub fn get_pgroup(&self) -> Option<pid_t> {
+        self.pgroup
+    }
 
     pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
         &mut self.closures
diff --git a/library/std/src/sys/unix/process/process_common/tests.rs b/library/std/src/sys/unix/process/process_common/tests.rs
index 10aa34e9443..9f1a645372f 100644
--- a/library/std/src/sys/unix/process/process_common/tests.rs
+++ b/library/std/src/sys/unix/process/process_common/tests.rs
@@ -67,3 +67,58 @@ fn test_process_mask() {
         t!(cat.wait());
     }
 }
+
+#[test]
+#[cfg_attr(
+    any(
+        // See test_process_mask
+        target_os = "macos",
+        target_arch = "arm",
+        target_arch = "aarch64",
+        target_arch = "riscv64",
+    ),
+    ignore
+)]
+fn test_process_group_posix_spawn() {
+    unsafe {
+        // Spawn a cat subprocess that's just going to hang since there is no I/O.
+        let mut cmd = Command::new(OsStr::new("cat"));
+        cmd.pgroup(0);
+        cmd.stdin(Stdio::MakePipe);
+        cmd.stdout(Stdio::MakePipe);
+        let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true));
+
+        // Check that we can kill its process group, which means there *is* one.
+        t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT)));
+
+        t!(cat.wait());
+    }
+}
+
+#[test]
+#[cfg_attr(
+    any(
+        // See test_process_mask
+        target_os = "macos",
+        target_arch = "arm",
+        target_arch = "aarch64",
+        target_arch = "riscv64",
+    ),
+    ignore
+)]
+fn test_process_group_no_posix_spawn() {
+    unsafe {
+        // Same as above, create hang-y cat. This time, force using the non-posix_spawnp path.
+        let mut cmd = Command::new(OsStr::new("cat"));
+        cmd.pgroup(0);
+        cmd.pre_exec(Box::new(|| Ok(()))); // pre_exec forces fork + exec
+        cmd.stdin(Stdio::MakePipe);
+        cmd.stdout(Stdio::MakePipe);
+        let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true));
+
+        // Check that we can kill its process group, which means there *is* one.
+        t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT)));
+
+        t!(cat.wait());
+    }
+}
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 9d2803b40c4..3d305cd7310 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -27,7 +27,10 @@ use crate::sys::weak::weak;
 use libc::RTP_ID as pid_t;
 
 #[cfg(not(target_os = "vxworks"))]
-use libc::{c_int, gid_t, pid_t, uid_t};
+use libc::{c_int, pid_t};
+
+#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))]
+use libc::{gid_t, uid_t};
 
 ////////////////////////////////////////////////////////////////////////////////
 // Command
@@ -317,6 +320,10 @@ impl Command {
             cvt(libc::chdir(cwd.as_ptr()))?;
         }
 
+        if let Some(pgroup) = self.get_pgroup() {
+            cvt(libc::setpgid(0, pgroup))?;
+        }
+
         // emscripten has no signal support.
         #[cfg(not(target_os = "emscripten"))]
         {
@@ -456,6 +463,8 @@ impl Command {
             None => None,
         };
 
+        let pgroup = self.get_pgroup();
+
         // Safety: -1 indicates we don't have a pidfd.
         let mut p = unsafe { Process::new(0, -1) };
 
@@ -484,6 +493,8 @@ impl Command {
             cvt_nz(libc::posix_spawnattr_init(attrs.as_mut_ptr()))?;
             let attrs = PosixSpawnattr(&mut attrs);
 
+            let mut flags = 0;
+
             let mut file_actions = MaybeUninit::uninit();
             cvt_nz(libc::posix_spawn_file_actions_init(file_actions.as_mut_ptr()))?;
             let file_actions = PosixSpawnFileActions(&mut file_actions);
@@ -513,13 +524,18 @@ impl Command {
                 cvt_nz(f(file_actions.0.as_mut_ptr(), cwd.as_ptr()))?;
             }
 
+            if let Some(pgroup) = pgroup {
+                flags |= libc::POSIX_SPAWN_SETPGROUP;
+                cvt_nz(libc::posix_spawnattr_setpgroup(attrs.0.as_mut_ptr(), pgroup))?;
+            }
+
             let mut set = MaybeUninit::<libc::sigset_t>::uninit();
             cvt(sigemptyset(set.as_mut_ptr()))?;
             cvt_nz(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), set.as_ptr()))?;
             cvt(sigaddset(set.as_mut_ptr(), libc::SIGPIPE))?;
             cvt_nz(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), set.as_ptr()))?;
 
-            let flags = libc::POSIX_SPAWN_SETSIGDEF | libc::POSIX_SPAWN_SETSIGMASK;
+            flags |= libc::POSIX_SPAWN_SETSIGDEF | libc::POSIX_SPAWN_SETSIGMASK;
             cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
 
             // Make sure we synchronize access to the global `environ` resource
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index fafd1412d4c..a13585a0222 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -19,12 +19,12 @@ use crate::path::{Path, PathBuf};
 use crate::ptr;
 use crate::sys::c;
 use crate::sys::c::NonZeroDWORD;
+use crate::sys::cvt;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
 use crate::sys::path;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::stdio;
-use crate::sys::{cvt, to_u16s};
 use crate::sys_common::mutex::StaticMutex;
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::sys_common::{AsInner, IntoInner};
@@ -269,8 +269,13 @@ impl Command {
             None
         };
         let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
+        // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd"
+        let is_batch_file = matches!(
+            program.len().checked_sub(5).and_then(|i| program.get(i..)),
+            Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0])
+        );
         let mut cmd_str =
-            make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?;
+            make_command_line(&program, &self.args, self.force_quotes_enabled, is_batch_file)?;
         cmd_str.push(0); // add null terminator
 
         // stolen from the libuv code.
@@ -309,7 +314,6 @@ impl Command {
         si.hStdOutput = stdout.as_raw_handle();
         si.hStdError = stderr.as_raw_handle();
 
-        let program = to_u16s(&program)?;
         unsafe {
             cvt(c::CreateProcessW(
                 program.as_ptr(),
@@ -366,7 +370,7 @@ fn resolve_exe<'a>(
     exe_path: &'a OsStr,
     parent_paths: impl FnOnce() -> Option<OsString>,
     child_paths: Option<&OsStr>,
-) -> io::Result<PathBuf> {
+) -> io::Result<Vec<u16>> {
     // Early return if there is no filename.
     if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
         return Err(io::const_io_error!(
@@ -388,19 +392,19 @@ fn resolve_exe<'a>(
         if has_exe_suffix {
             // The application name is a path to a `.exe` file.
             // Let `CreateProcessW` figure out if it exists or not.
-            return Ok(exe_path.into());
+            return path::maybe_verbatim(Path::new(exe_path));
         }
         let mut path = PathBuf::from(exe_path);
 
         // Append `.exe` if not already there.
         path = path::append_suffix(path, EXE_SUFFIX.as_ref());
-        if program_exists(&path) {
+        if let Some(path) = program_exists(&path) {
             return Ok(path);
         } else {
             // It's ok to use `set_extension` here because the intent is to
             // remove the extension that was just added.
             path.set_extension("");
-            return Ok(path);
+            return path::maybe_verbatim(&path);
         }
     } else {
         ensure_no_nuls(exe_path)?;
@@ -415,7 +419,7 @@ fn resolve_exe<'a>(
             if !has_extension {
                 path.set_extension(EXE_EXTENSION);
             }
-            if program_exists(&path) { Some(path) } else { None }
+            program_exists(&path)
         });
         if let Some(path) = result {
             return Ok(path);
@@ -431,10 +435,10 @@ fn search_paths<Paths, Exists>(
     parent_paths: Paths,
     child_paths: Option<&OsStr>,
     mut exists: Exists,
-) -> Option<PathBuf>
+) -> Option<Vec<u16>>
 where
     Paths: FnOnce() -> Option<OsString>,
-    Exists: FnMut(PathBuf) -> Option<PathBuf>,
+    Exists: FnMut(PathBuf) -> Option<Vec<u16>>,
 {
     // 1. Child paths
     // This is for consistency with Rust's historic behaviour.
@@ -486,17 +490,18 @@ where
 }
 
 /// Check if a file exists without following symlinks.
-fn program_exists(path: &Path) -> bool {
+fn program_exists(path: &Path) -> Option<Vec<u16>> {
     unsafe {
-        to_u16s(path)
-            .map(|path| {
-                // Getting attributes using `GetFileAttributesW` does not follow symlinks
-                // and it will almost always be successful if the link exists.
-                // There are some exceptions for special system files (e.g. the pagefile)
-                // but these are not executable.
-                c::GetFileAttributesW(path.as_ptr()) != c::INVALID_FILE_ATTRIBUTES
-            })
-            .unwrap_or(false)
+        let path = path::maybe_verbatim(path).ok()?;
+        // Getting attributes using `GetFileAttributesW` does not follow symlinks
+        // and it will almost always be successful if the link exists.
+        // There are some exceptions for special system files (e.g. the pagefile)
+        // but these are not executable.
+        if c::GetFileAttributesW(path.as_ptr()) == c::INVALID_FILE_ATTRIBUTES {
+            None
+        } else {
+            Some(path)
+        }
     }
 }
 
@@ -730,7 +735,12 @@ enum Quote {
 
 // Produces a wide string *without terminating null*; returns an error if
 // `prog` or any of the `args` contain a nul.
-fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> {
+fn make_command_line(
+    prog: &[u16],
+    args: &[Arg],
+    force_quotes: bool,
+    is_batch_file: bool,
+) -> io::Result<Vec<u16>> {
     // Encode the command and arguments in a command line string such
     // that the spawned process may recover them using CommandLineToArgvW.
     let mut cmd: Vec<u16> = Vec::new();
@@ -739,17 +749,18 @@ fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Resu
     // need to add an extra pair of quotes surrounding the whole command line
     // so they are properly passed on to the script.
     // See issue #91991.
-    let is_batch_file = Path::new(prog)
-        .extension()
-        .map(|ext| ext.eq_ignore_ascii_case("cmd") || ext.eq_ignore_ascii_case("bat"))
-        .unwrap_or(false);
     if is_batch_file {
         cmd.push(b'"' as u16);
     }
 
-    // Always quote the program name so CreateProcess doesn't interpret args as
-    // part of the name if the binary wasn't found first time.
-    append_arg(&mut cmd, prog, Quote::Always)?;
+    // Always quote the program name so CreateProcess to avoid ambiguity when
+    // the child process parses its arguments.
+    // Note that quotes aren't escaped here because they can't be used in arg0.
+    // But that's ok because file paths can't contain quotes.
+    cmd.push(b'"' as u16);
+    cmd.extend_from_slice(prog.strip_suffix(&[0]).unwrap_or(prog));
+    cmd.push(b'"' as u16);
+
     for arg in args {
         cmd.push(' ' as u16);
         let (arg, quote) = match arg {
diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs
index d8c9beb0c19..96477fb19da 100644
--- a/library/std/src/sys/windows/process/tests.rs
+++ b/library/std/src/sys/windows/process/tests.rs
@@ -3,11 +3,12 @@ use super::Arg;
 use crate::env;
 use crate::ffi::{OsStr, OsString};
 use crate::process::Command;
+use crate::sys::to_u16s;
 
 #[test]
 fn test_raw_args() {
     let command_line = &make_command_line(
-        OsStr::new("quoted exe"),
+        &to_u16s("quoted exe").unwrap(),
         &[
             Arg::Regular(OsString::from("quote me")),
             Arg::Raw(OsString::from("quote me *not*")),
@@ -16,6 +17,7 @@ fn test_raw_args() {
             Arg::Regular(OsString::from("optional-quotes")),
         ],
         false,
+        false,
     )
     .unwrap();
     assert_eq!(
@@ -28,9 +30,10 @@ fn test_raw_args() {
 fn test_make_command_line() {
     fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
         let command_line = &make_command_line(
-            OsStr::new(prog),
+            &to_u16s(prog).unwrap(),
             &args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
             force_quotes,
+            false,
         )
         .unwrap();
         String::from_utf16(command_line).unwrap()
diff --git a/src/test/ui/check-cfg/mix.rs b/src/test/ui/check-cfg/mix.rs
index 26c735c4a10..b51d356f61f 100644
--- a/src/test/ui/check-cfg/mix.rs
+++ b/src/test/ui/check-cfg/mix.rs
@@ -45,6 +45,28 @@ fn test_cfg_macro() {
     //~^ WARNING unexpected `cfg` condition name
     cfg!(any(feature = "bad", windows));
     //~^ WARNING unexpected `cfg` condition value
+    cfg!(any(windows, xxx));
+    //~^ WARNING unexpected `cfg` condition name
+    cfg!(all(unix, xxx));
+    //~^ WARNING unexpected `cfg` condition name
+    cfg!(all(aa, bb));
+    //~^ WARNING unexpected `cfg` condition name
+    //~| WARNING unexpected `cfg` condition name
+    cfg!(any(aa, bb));
+    //~^ WARNING unexpected `cfg` condition name
+    //~| WARNING unexpected `cfg` condition name
+    cfg!(any(unix, feature = "zebra"));
+    //~^ WARNING unexpected `cfg` condition value
+    cfg!(any(xxx, feature = "zebra"));
+    //~^ WARNING unexpected `cfg` condition name
+    //~| WARNING unexpected `cfg` condition value
+    cfg!(any(xxx, unix, xxx));
+    //~^ WARNING unexpected `cfg` condition name
+    //~| WARNING unexpected `cfg` condition name
+    cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+    //~^ WARNING unexpected `cfg` condition value
+    //~| WARNING unexpected `cfg` condition value
+    //~| WARNING unexpected `cfg` condition value
 }
 
 fn main() {}
diff --git a/src/test/ui/check-cfg/mix.stderr b/src/test/ui/check-cfg/mix.stderr
index b273be77422..08a338da104 100644
--- a/src/test/ui/check-cfg/mix.stderr
+++ b/src/test/ui/check-cfg/mix.stderr
@@ -62,5 +62,99 @@ LL |     cfg!(any(feature = "bad", windows));
    |
    = note: expected values for `feature` are: bar, foo
 
-warning: 9 warnings emitted
+warning: unexpected `cfg` condition name
+  --> $DIR/mix.rs:48:23
+   |
+LL |     cfg!(any(windows, xxx));
+   |                       ^^^
+
+warning: unexpected `cfg` condition name
+  --> $DIR/mix.rs:50:20
+   |
+LL |     cfg!(all(unix, xxx));
+   |                    ^^^
+
+warning: unexpected `cfg` condition name
+  --> $DIR/mix.rs:52:14
+   |
+LL |     cfg!(all(aa, bb));
+   |              ^^
+
+warning: unexpected `cfg` condition name
+  --> $DIR/mix.rs:52:18
+   |
+LL |     cfg!(all(aa, bb));
+   |                  ^^
+
+warning: unexpected `cfg` condition name
+  --> $DIR/mix.rs:55:14
+   |
+LL |     cfg!(any(aa, bb));
+   |              ^^
+
+warning: unexpected `cfg` condition name
+  --> $DIR/mix.rs:55:18
+   |
+LL |     cfg!(any(aa, bb));
+   |                  ^^
+
+warning: unexpected `cfg` condition value
+  --> $DIR/mix.rs:58:20
+   |
+LL |     cfg!(any(unix, feature = "zebra"));
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: bar, foo
+
+warning: unexpected `cfg` condition name
+  --> $DIR/mix.rs:60:14
+   |
+LL |     cfg!(any(xxx, feature = "zebra"));
+   |              ^^^
+
+warning: unexpected `cfg` condition value
+  --> $DIR/mix.rs:60:19
+   |
+LL |     cfg!(any(xxx, feature = "zebra"));
+   |                   ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: bar, foo
+
+warning: unexpected `cfg` condition name
+  --> $DIR/mix.rs:63:14
+   |
+LL |     cfg!(any(xxx, unix, xxx));
+   |              ^^^
+
+warning: unexpected `cfg` condition name
+  --> $DIR/mix.rs:63:25
+   |
+LL |     cfg!(any(xxx, unix, xxx));
+   |                         ^^^
+
+warning: unexpected `cfg` condition value
+  --> $DIR/mix.rs:66:14
+   |
+LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+   |              ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: bar, foo
+
+warning: unexpected `cfg` condition value
+  --> $DIR/mix.rs:66:33
+   |
+LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+   |                                 ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: bar, foo
+
+warning: unexpected `cfg` condition value
+  --> $DIR/mix.rs:66:52
+   |
+LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
+   |                                                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: bar, foo
+
+warning: 23 warnings emitted
 
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 3f2cd3ae232..503b624114a 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -487,11 +487,6 @@ fn configure_lldb(config: &Config) -> Option<Config> {
         return None;
     }
 
-    // Some older versions of LLDB seem to have problems with multiple
-    // instances running in parallel, so only run one test thread at a
-    // time.
-    env::set_var("RUST_TEST_THREADS", "1");
-
     Some(Config { debugger: Some(Debugger::Lldb), ..config.clone() })
 }