diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 1056644b813a2..bbcd509c55869 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -28,6 +28,7 @@ use tracing::instrument;
 use crate::middle::region;
 use crate::mir::interpret::AllocId;
 use crate::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp};
+use crate::thir::visit::for_each_immediate_subpat;
 use crate::ty::adjustment::PointerCoercion;
 use crate::ty::layout::IntegerExt;
 use crate::ty::{
@@ -672,27 +673,7 @@ impl<'tcx> Pat<'tcx> {
             return;
         }
 
-        use PatKind::*;
-        match &self.kind {
-            Wild
-            | Never
-            | Range(..)
-            | Binding { subpattern: None, .. }
-            | Constant { .. }
-            | Error(_) => {}
-            AscribeUserType { subpattern, .. }
-            | Binding { subpattern: Some(subpattern), .. }
-            | Deref { subpattern }
-            | DerefPattern { subpattern, .. }
-            | ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
-            Leaf { subpatterns } | Variant { subpatterns, .. } => {
-                subpatterns.iter().for_each(|field| field.pattern.walk_(it))
-            }
-            Or { pats } => pats.iter().for_each(|p| p.walk_(it)),
-            Array { box prefix, slice, box suffix } | Slice { box prefix, slice, box suffix } => {
-                prefix.iter().chain(slice.as_deref()).chain(suffix.iter()).for_each(|p| p.walk_(it))
-            }
-        }
+        for_each_immediate_subpat(self, |p| p.walk_(it));
     }
 
     /// Whether the pattern has a `PatKind::Error` nested within.
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index d208692f4e711..7d62ab7970d01 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -240,36 +240,45 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
     visitor: &mut V,
     pat: &'thir Pat<'tcx>,
 ) {
-    use PatKind::*;
+    for_each_immediate_subpat(pat, |p| visitor.visit_pat(p));
+}
+
+/// Invokes `callback` on each immediate subpattern of `pat`, if any.
+/// A building block for assembling THIR pattern visitors.
+pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
+    pat: &'a Pat<'tcx>,
+    mut callback: impl FnMut(&'a Pat<'tcx>),
+) {
     match &pat.kind {
-        AscribeUserType { subpattern, ascription: _ }
-        | Deref { subpattern }
-        | DerefPattern { subpattern, .. }
-        | Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern),
-        Binding { .. } | Wild | Never | Error(_) => {}
-        Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
-            for subpattern in subpatterns {
-                visitor.visit_pat(&subpattern.pattern);
+        PatKind::Wild
+        | PatKind::Binding { subpattern: None, .. }
+        | PatKind::Constant { value: _ }
+        | PatKind::Range(_)
+        | PatKind::Never
+        | PatKind::Error(_) => {}
+
+        PatKind::AscribeUserType { subpattern, .. }
+        | PatKind::Binding { subpattern: Some(subpattern), .. }
+        | PatKind::Deref { subpattern }
+        | PatKind::DerefPattern { subpattern, .. }
+        | PatKind::ExpandedConstant { subpattern, .. } => callback(subpattern),
+
+        PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => {
+            for field_pat in subpatterns {
+                callback(&field_pat.pattern);
             }
         }
-        Constant { value: _ } => {}
-        ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern),
-        Range(_) => {}
-        Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
-            for subpattern in prefix.iter() {
-                visitor.visit_pat(subpattern);
-            }
-            if let Some(pat) = slice {
-                visitor.visit_pat(pat);
-            }
-            for subpattern in suffix.iter() {
-                visitor.visit_pat(subpattern);
+
+        PatKind::Slice { prefix, slice, suffix } | PatKind::Array { prefix, slice, suffix } => {
+            for pat in prefix.iter().chain(slice.as_deref()).chain(suffix) {
+                callback(pat);
             }
         }
-        Or { pats } => {
-            for pat in pats.iter() {
-                visitor.visit_pat(pat);
+
+        PatKind::Or { pats } => {
+            for pat in pats {
+                callback(pat);
             }
         }
-    };
+    }
 }
diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs
index a29baade42fb7..af568171f911c 100644
--- a/compiler/rustc_transmute/src/layout/dfa.rs
+++ b/compiler/rustc_transmute/src/layout/dfa.rs
@@ -55,6 +55,7 @@ where
 #[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
 pub(crate) struct State(u32);
 
+#[cfg(test)]
 #[derive(Hash, Eq, PartialEq, Clone, Copy)]
 pub(crate) enum Transition<R>
 where
@@ -70,6 +71,7 @@ impl fmt::Debug for State {
     }
 }
 
+#[cfg(test)]
 impl<R> fmt::Debug for Transition<R>
 where
     R: Ref,
@@ -166,6 +168,7 @@ impl State {
     }
 }
 
+#[cfg(test)]
 impl<R> From<nfa::Transition<R>> for Transition<R>
 where
     R: Ref,
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 6961fa8ea947f..05bd4345ea8dd 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -333,7 +333,7 @@ impl Error for VarError {
 ///
 /// Discussion of this unsafety on Unix may be found in:
 ///
-///  - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188)
+///  - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=188)
 ///  - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
 ///
 /// To pass an environment variable to a child process, you can instead use [`Command::env`].
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 07a56010255de..f81ce8e1a1a1e 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -2018,9 +2018,9 @@ impl ExitCode {
     ///
     /// Note that this has the same caveats as [`process::exit()`][exit], namely that this function
     /// terminates the process immediately, so no destructors on the current stack or any other
-    /// thread's stack will be run. If a clean shutdown is needed, it is recommended to simply
-    /// return this ExitCode from the `main` function, as demonstrated in the [type
-    /// documentation](#examples).
+    /// thread's stack will be run. Also see those docs for some important notes on interop with C
+    /// code. If a clean shutdown is needed, it is recommended to simply return this ExitCode from
+    /// the `main` function, as demonstrated in the [type documentation](#examples).
     ///
     /// # Differences from `process::exit()`
     ///
@@ -2326,6 +2326,33 @@ impl Child {
 ///
 /// process::exit(0x0100);
 /// ```
+///
+/// ### Safe interop with C code
+///
+/// On Unix, this function is currently implemented using the `exit` C function [`exit`][C-exit]. As
+/// of C23, the C standard does not permit multiple threads to call `exit` concurrently. Rust
+/// mitigates this with a lock, but if C code calls `exit`, that can still cause undefined behavior.
+/// Note that returning from `main` is equivalent to calling `exit`.
+///
+/// Therefore, it is undefined behavior to have two concurrent threads perform the following
+/// without synchronization:
+/// - One thread calls Rust's `exit` function or returns from Rust's `main` function
+/// - Another thread calls the C function `exit` or `quick_exit`, or returns from C's `main` function
+///
+/// Note that if a binary contains multiple copies of the Rust runtime (e.g., when combining
+/// multiple `cdylib` or `staticlib`), they each have their own separate lock, so from the
+/// perspective of code running in one of the Rust runtimes, the "outside" Rust code is basically C
+/// code, and concurrent `exit` again causes undefined behavior.
+///
+/// Individual C implementations might provide more guarantees than the standard and permit concurrent
+/// calls to `exit`; consult the documentation of your C implementation for details.
+///
+/// For some of the on-going discussion to make `exit` thread-safe in C, see:
+/// - [Rust issue #126600](https://github.com/rust-lang/rust/issues/126600)
+/// - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=1845)
+/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=31997)
+///
+/// [C-exit]: https://en.cppreference.com/w/c/program/exit
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "process_exit")]
 pub fn exit(code: i32) -> ! {
diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs
index 1191e335daadd..f83a2f90ed22a 100644
--- a/library/std/src/sys/fs/hermit.rs
+++ b/library/std/src/sys/fs/hermit.rs
@@ -396,7 +396,7 @@ impl File {
     }
 
     pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
-        crate::io::default_read_buf(|buf| self.read(buf), cursor)
+        self.0.read_buf(cursor)
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs
index 3d6b99cd77b54..edd984d920a1b 100644
--- a/library/std/src/sys/pal/hermit/fd.rs
+++ b/library/std/src/sys/pal/hermit/fd.rs
@@ -2,7 +2,7 @@
 
 use super::hermit_abi;
 use crate::cmp;
-use crate::io::{self, IoSlice, IoSliceMut, Read, SeekFrom};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, SeekFrom};
 use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::sys::{cvt, unsupported};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -23,6 +23,21 @@ impl FileDesc {
         Ok(result as usize)
     }
 
+    pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
+        // SAFETY: The `read` syscall does not read from the buffer, so it is
+        // safe to use `&mut [MaybeUninit<u8>]`.
+        let result = cvt(unsafe {
+            hermit_abi::read(
+                self.fd.as_raw_fd(),
+                buf.as_mut().as_mut_ptr() as *mut u8,
+                buf.capacity(),
+            )
+        })?;
+        // SAFETY: Exactly `result` bytes have been filled.
+        unsafe { buf.advance_unchecked(result as usize) };
+        Ok(())
+    }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             hermit_abi::readv(
diff --git a/library/std/src/sys/stdio/unix.rs b/library/std/src/sys/stdio/unix.rs
index 8d133857c596d..08a06e0da9f34 100644
--- a/library/std/src/sys/stdio/unix.rs
+++ b/library/std/src/sys/stdio/unix.rs
@@ -3,9 +3,7 @@ use hermit_abi::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
 #[cfg(target_family = "unix")]
 use libc::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
 
-#[cfg(target_family = "unix")]
-use crate::io::BorrowedCursor;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem::ManuallyDrop;
 #[cfg(target_os = "hermit")]
 use crate::os::hermit::io::FromRawFd;
@@ -28,7 +26,6 @@ impl io::Read for Stdin {
         unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read(buf) }
     }
 
-    #[cfg(not(target_os = "hermit"))]
     fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
         unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read_buf(buf) }
     }
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 636d51e0e9022..80d92135dd378 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -214,8 +214,9 @@ fn setup_config_toml(path: &Path, profile: Profile, config: &Config) {
 
     let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap().change_id;
     let settings = format!(
-        "# Includes one of the default files in {PROFILE_DIR}\n\
-    profile = \"{profile}\"\n\
+        "# See bootstrap.example.toml for documentation of available options\n\
+    #\n\
+    profile = \"{profile}\"  # Includes one of the default files in {PROFILE_DIR}\n\
     change-id = {latest_change_id}\n"
     );
 
diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs
new file mode 100644
index 0000000000000..bebbe1fea349d
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_align.rs
@@ -0,0 +1,8 @@
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='Aligned')].attrs" '["#[attr = Repr([ReprAlign(Align(4 bytes))])]\n"]'
+#[repr(align(4))]
+pub struct Aligned {
+    a: i8,
+    b: i64,
+}
diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs
new file mode 100644
index 0000000000000..609d33d94de76
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_c.rs
@@ -0,0 +1,18 @@
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='ReprCStruct')].attrs" '["#[attr = Repr([ReprC])]\n"]'
+#[repr(C)]
+pub struct ReprCStruct(pub i64);
+
+//@ is "$.index[*][?(@.name=='ReprCEnum')].attrs" '["#[attr = Repr([ReprC])]\n"]'
+#[repr(C)]
+pub enum ReprCEnum {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='ReprCUnion')].attrs" '["#[attr = Repr([ReprC])]\n"]'
+#[repr(C)]
+pub union ReprCUnion {
+    pub left: i64,
+    pub right: u64,
+}
diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs
new file mode 100644
index 0000000000000..662bfef67cb87
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_combination.rs
@@ -0,0 +1,78 @@
+#![no_std]
+
+// Combinations of `#[repr(..)]` attributes.
+
+//@ is "$.index[*][?(@.name=='ReprCI8')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I8))])]\n"]'
+#[repr(C, i8)]
+pub enum ReprCI8 {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='SeparateReprCI16')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I16))])]\n"]'
+#[repr(C)]
+#[repr(i16)]
+pub enum SeparateReprCI16 {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='ReversedReprCUsize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize)), ReprC])]\n"]'
+#[repr(usize, C)]
+pub enum ReversedReprCUsize {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='ReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(1 bytes))])]\n"]'
+#[repr(C, packed)]
+pub struct ReprCPacked {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='SeparateReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(2 bytes))])]\n"]'
+#[repr(C)]
+#[repr(packed(2))]
+pub struct SeparateReprCPacked {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='ReversedReprCPacked')].attrs" '["#[attr = Repr([ReprPacked(Align(2 bytes)), ReprC])]\n"]'
+#[repr(packed(2), C)]
+pub struct ReversedReprCPacked {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='ReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes))])]\n"]'
+#[repr(C, align(16))]
+pub struct ReprCAlign {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='SeparateReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(2 bytes))])]\n"]'
+#[repr(C)]
+#[repr(align(2))]
+pub struct SeparateReprCAlign {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='ReversedReprCAlign')].attrs" '["#[attr = Repr([ReprAlign(Align(2 bytes)), ReprC])]\n"]'
+#[repr(align(2), C)]
+pub struct ReversedReprCAlign {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='AlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes)), ReprInt(SignedInt(Isize))])]\n"]'
+#[repr(C, align(16), isize)]
+pub enum AlignedExplicitRepr {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprInt(SignedInt(Isize)), ReprC, ReprAlign(Align(16 bytes))])]\n"]'
+#[repr(isize, C, align(16))]
+pub enum ReorderedAlignedExplicitRepr {
+    First,
+}
diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs
new file mode 100644
index 0000000000000..2ad57de279887
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_int_enum.rs
@@ -0,0 +1,19 @@
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='I8')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I8))])]\n"]'
+#[repr(i8)]
+pub enum I8 {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='I32')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]'
+#[repr(i32)]
+pub enum I32 {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='Usize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize))])]\n"]'
+#[repr(usize)]
+pub enum Usize {
+    First,
+}
diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs
new file mode 100644
index 0000000000000..33acc23b7c894
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_packed.rs
@@ -0,0 +1,18 @@
+#![no_std]
+
+// Note the normalization:
+// `#[repr(packed)]` in has the implict "1" in rustdoc JSON.
+
+//@ is "$.index[*][?(@.name=='Packed')].attrs" '["#[attr = Repr([ReprPacked(Align(1 bytes))])]\n"]'
+#[repr(packed)]
+pub struct Packed {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='PackedAligned')].attrs" '["#[attr = Repr([ReprPacked(Align(4 bytes))])]\n"]'
+#[repr(packed(4))]
+pub struct PackedAligned {
+    a: i8,
+    b: i64,
+}
diff --git a/tests/rustdoc-json/attrs/repr_transparent.rs b/tests/rustdoc-json/attrs/repr_transparent.rs
new file mode 100644
index 0000000000000..ef6e69f8703b1
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_transparent.rs
@@ -0,0 +1,22 @@
+#![no_std]
+
+// Rustdoc JSON currently includes `#[repr(transparent)]`
+// even if the transparency is not part of the public API
+//
+// https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
+
+//@ is "$.index[*][?(@.name=='Transparent')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
+#[repr(transparent)]
+pub struct Transparent(pub i64);
+
+//@ is "$.index[*][?(@.name=='TransparentNonPub')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
+#[repr(transparent)]
+pub struct TransparentNonPub(i64);
+
+//@ is "$.index[*][?(@.name=='AllZst')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
+#[repr(transparent)]
+pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ());
+
+//@ is "$.index[*][?(@.name=='AllZstNotPublic')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
+#[repr(transparent)]
+pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ());
diff --git a/triagebot.toml b/triagebot.toml
index 745f9dfaee813..cd488a7cdf65c 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1082,7 +1082,6 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
 users_on_vacation = [
     "jyn514",
     "ChrisDenton",
-    "jieyouxu",
 ]
 
 [[assign.warn_non_default_branch.exceptions]]