diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 08f7434a4a9c8..67804998a3293 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -19,11 +19,12 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp};
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarArgs};
-use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation};
+use rustc_middle::ty::{
+    self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty,
+    UpvarArgs,
+};
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{sym, Span, Symbol, DUMMY_SP};
+use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::asm::InlineAsmRegOrRegClass;
 use std::fmt;
@@ -632,7 +633,7 @@ impl<'tcx> Pat<'tcx> {
 
         use PatKind::*;
         match &self.kind {
-            Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } => {}
+            Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {}
             AscribeUserType { subpattern, .. }
             | Binding { subpattern: Some(subpattern), .. }
             | Deref { subpattern } => subpattern.walk_(it),
@@ -647,6 +648,21 @@ impl<'tcx> Pat<'tcx> {
         }
     }
 
+    /// Whether the pattern has a `PatKind::Error` nested within.
+    pub fn pat_error_reported(&self) -> Result<(), ErrorGuaranteed> {
+        let mut error = None;
+        self.walk(|pat| {
+            if let PatKind::Error(e) = pat.kind && error.is_none() {
+                error = Some(e);
+            }
+            error.is_none()
+        });
+        match error {
+            None => Ok(()),
+            Some(e) => Err(e),
+        }
+    }
+
     /// Walk the pattern in left-to-right order.
     ///
     /// If you always want to recurse, prefer this method over `walk`.
@@ -771,6 +787,10 @@ pub enum PatKind<'tcx> {
     Or {
         pats: Box<[Box<Pat<'tcx>>]>,
     },
+
+    /// An error has been encountered during lowering. We probably shouldn't report more lints
+    /// related to this pattern.
+    Error(ErrorGuaranteed),
 }
 
 #[derive(Clone, Debug, PartialEq, HashStable, TypeVisitable)]
@@ -934,6 +954,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 }
                 Ok(())
             }
+            PatKind::Error(_) => write!(f, "<error>"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index b84e15688848b..afb58438519cc 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -226,7 +226,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
             is_primary: _,
             name: _,
         } => visitor.visit_pat(&subpattern),
-        Binding { .. } | Wild => {}
+        Binding { .. } | Wild | Error(_) => {}
         Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
             for subpattern in subpatterns {
                 visitor.visit_pat(&subpattern.pattern);
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index eb1c6a9824a47..ab3ffabe29790 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -814,7 +814,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
 
-            PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild => {}
+            PatKind::Constant { .. }
+            | PatKind::Range { .. }
+            | PatKind::Wild
+            | PatKind::Error(_) => {}
 
             PatKind::Deref { ref subpattern } => {
                 self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 17ac1f4e0cea6..f340feb40d4a7 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -168,7 +168,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 Ok(())
             }
 
-            PatKind::Wild => {
+            PatKind::Wild | PatKind::Error(_) => {
                 // nothing left to do
                 Ok(())
             }
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 795d1db8eecda..dde3702ca634c 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -77,7 +77,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | PatKind::Wild
             | PatKind::Binding { .. }
             | PatKind::Leaf { .. }
-            | PatKind::Deref { .. } => self.error_simplifiable(match_pair),
+            | PatKind::Deref { .. }
+            | PatKind::Error(_) => self.error_simplifiable(match_pair),
         }
     }
 
@@ -111,7 +112,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | PatKind::Binding { .. }
             | PatKind::AscribeUserType { .. }
             | PatKind::Leaf { .. }
-            | PatKind::Deref { .. } => {
+            | PatKind::Deref { .. }
+            | PatKind::Error(_) => {
                 // don't know how to add these patterns to a switch
                 false
             }
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 192bd4a83e3ed..6cf2ecc51e9e0 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -224,7 +224,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 PatKind::Wild |
                 // these just wrap other patterns
                 PatKind::Or { .. } |
-                PatKind::AscribeUserType { .. } => {}
+                PatKind::AscribeUserType { .. } |
+                PatKind::Error(_) => {}
             }
         };
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 93434dd3cc290..bcecd0ff9db2f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -19,7 +19,7 @@ use rustc_hir::HirId;
 use rustc_middle::thir::visit::{self, Visitor};
 use rustc_middle::thir::*;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
@@ -231,6 +231,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         if let LetSource::None = source {
             return;
         }
+        if let Err(err) = pat.pat_error_reported() {
+            self.error = Err(err);
+            return;
+        }
         self.check_patterns(pat, Refutable);
         let mut cx = self.new_cx(self.lint_level, true);
         let tpat = self.lower_pattern(&mut cx, pat);
@@ -252,6 +256,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
             self.with_lint_level(arm.lint_level, |this| {
                 this.check_patterns(&arm.pattern, Refutable);
             });
+            if let Err(err) = arm.pattern.pat_error_reported() {
+                self.error = Err(err);
+                return;
+            }
         }
 
         let tarms: Vec<_> = arms
@@ -334,7 +342,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         // and record chain members that aren't let exprs.
         let mut chain_refutabilities = Vec::new();
 
-        let add = |expr: ExprId, mut local_lint_level| {
+        let mut error = Ok(());
+        let mut add = |expr: ExprId, mut local_lint_level| {
             // `local_lint_level` is the lint level enclosing the pattern inside `expr`.
             let mut expr = &self.thir[expr];
             debug!(?expr, ?local_lint_level, "add");
@@ -348,6 +357,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
             debug!(?expr, ?local_lint_level, "after scopes");
             match expr.kind {
                 ExprKind::Let { box ref pat, expr: _ } => {
+                    if let Err(err) = pat.pat_error_reported() {
+                        error = Err(err);
+                        return None;
+                    }
                     let mut ncx = self.new_cx(local_lint_level, true);
                     let tpat = self.lower_pattern(&mut ncx, pat);
                     let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat);
@@ -380,6 +393,11 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         debug!(?chain_refutabilities);
         chain_refutabilities.reverse();
 
+        if error.is_err() {
+            self.error = error;
+            return;
+        }
+
         // Third, emit the actual warnings.
         if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) {
             // The entire chain is made up of irrefutable `let` statements
@@ -426,6 +444,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
 
     #[instrument(level = "trace", skip(self))]
     fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
+        // If we got errors while lowering, don't emit anything more.
+        if let Err(err) = pat.pat_error_reported() {
+            self.error = Err(err);
+            return;
+        }
+
         let mut cx = self.new_cx(self.lint_level, false);
 
         let pattern = self.lower_pattern(&mut cx, pat);
@@ -682,12 +706,6 @@ fn non_exhaustive_match<'p, 'tcx>(
     arms: &[ArmId],
     expr_span: Span,
 ) -> ErrorGuaranteed {
-    for &arm in arms {
-        if let Err(err) = thir[arm].pattern.error_reported() {
-            return err;
-        }
-    }
-
     let is_empty_match = arms.is_empty();
     let non_empty_enum = match scrut_ty.kind() {
         ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(),
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index fde6defd87f1b..32d389c4354c7 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -196,9 +196,7 @@ impl<'tcx> ConstToPat<'tcx> {
                     };
                     // All branches above emitted an error. Don't print any more lints.
                     // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                    let kind = PatKind::Constant {
-                        value: mir::Const::Ty(ty::Const::new_error(self.tcx(), e, cv.ty())),
-                    };
+                    let kind = PatKind::Error(e);
                     return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
                 } else if !self.saw_const_match_lint.get() {
                     if let Some(mir_structural_match_violation) = mir_structural_match_violation {
@@ -351,7 +349,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 let e = tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty });
                 self.saw_const_match_error.set(Some(e));
                 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) }
+                PatKind::Error(e)
             }
             ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
                 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
@@ -359,7 +357,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 let e = tcx.sess.emit_err(err);
                 self.saw_const_match_error.set(Some(e));
                 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) }
+                PatKind::Error(e)
             }
             ty::Adt(adt_def, args) if adt_def.is_enum() => {
                 let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
@@ -434,17 +432,13 @@ impl<'tcx> ConstToPat<'tcx> {
                     } else {
                         if let Some(e) = self.saw_const_match_error.get() {
                             // We already errored. Signal that in the pattern, so that follow up errors can be silenced.
-                            PatKind::Constant {
-                                value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)),
-                            }
+                            PatKind::Error(e)
                         } else {
                             let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
                             let e = tcx.sess.emit_err(err);
                             self.saw_const_match_error.set(Some(e));
                             // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                            PatKind::Constant {
-                                value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)),
-                            }
+                            PatKind::Error(e)
                         }
                     }
                 }
@@ -456,9 +450,7 @@ impl<'tcx> ConstToPat<'tcx> {
                         let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
                         let e = tcx.sess.emit_err(err);
                         // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                        PatKind::Constant {
-                            value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)),
-                        }
+                        PatKind::Error(e)
                     } else {
                         let old = self.behind_reference.replace(true);
                         // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
@@ -489,7 +481,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 let e = tcx.sess.emit_err(err);
                 self.saw_const_match_error.set(Some(e));
                 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) }
+                PatKind::Error(e)
             }
         };
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index a7a000ba31c6f..bbc0aeb66cfda 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -1525,6 +1525,10 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
                 let pats = expand_or_pat(pat);
                 fields = Fields::from_iter(cx, pats.into_iter().map(mkpat));
             }
+            PatKind::Error(_) => {
+                ctor = Opaque;
+                fields = Fields::empty();
+            }
         }
         DeconstructedPat::new(ctor, fields, pat.ty, pat.span)
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 25726c5a8725e..76ed6d2b6d73d 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -252,10 +252,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
             hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
                 let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
-                // FIXME?: returning `_` can cause inaccurate "unreachable" warnings. This can be
-                // fixed by returning `PatKind::Const(ConstKind::Error(...))` if #115937 gets
-                // merged.
-                self.lower_pattern_range(lo_expr, hi_expr, end, ty, span).unwrap_or(PatKind::Wild)
+                self.lower_pattern_range(lo_expr, hi_expr, end, ty, span)
+                    .unwrap_or_else(PatKind::Error)
             }
 
             hir::PatKind::Path(ref qpath) => {
@@ -423,9 +421,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 if adt_def.is_enum() {
                     let args = match ty.kind() {
                         ty::Adt(_, args) | ty::FnDef(_, args) => args,
-                        ty::Error(_) => {
+                        ty::Error(e) => {
                             // Avoid ICE (#50585)
-                            return PatKind::Wild;
+                            return PatKind::Error(*e);
                         }
                         _ => bug!("inappropriate type for def: {:?}", ty),
                     };
@@ -452,7 +450,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             | Res::SelfTyAlias { .. }
             | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
             _ => {
-                match res {
+                let e = match res {
                     Res::Def(DefKind::ConstParam, _) => {
                         self.tcx.sess.emit_err(ConstParamInPattern { span })
                     }
@@ -461,7 +459,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     }
                     _ => self.tcx.sess.emit_err(NonConstPath { span }),
                 };
-                PatKind::Wild
+                PatKind::Error(e)
             }
         };
 
@@ -513,14 +511,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 // It should be assoc consts if there's no error but we cannot resolve it.
                 debug_assert!(is_associated_const);
 
-                self.tcx.sess.emit_err(AssocConstInPattern { span });
-
-                return pat_from_kind(PatKind::Wild);
+                let e = self.tcx.sess.emit_err(AssocConstInPattern { span });
+                return pat_from_kind(PatKind::Error(e));
             }
 
             Err(_) => {
-                self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
-                return pat_from_kind(PatKind::Wild);
+                let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
+                return pat_from_kind(PatKind::Error(e));
             }
         };
 
@@ -574,12 +571,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             Err(ErrorHandled::TooGeneric(_)) => {
                 // While `Reported | Linted` cases will have diagnostics emitted already
                 // it is not true for TooGeneric case, so we need to give user more information.
-                self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
-                pat_from_kind(PatKind::Wild)
+                let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
+                pat_from_kind(PatKind::Error(e))
             }
             Err(_) => {
-                self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
-                pat_from_kind(PatKind::Wild)
+                let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
+                pat_from_kind(PatKind::Error(e))
             }
         }
     }
@@ -629,7 +626,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), args, promoted: None };
         debug_assert!(!args.has_free_regions());
 
-        let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args: args };
+        let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
         // First try using a valtree in order to destructure the constant into a pattern.
         // FIXME: replace "try to do a thing, then fall back to another thing"
         // but something more principled, like a trait query checking whether this can be turned into a valtree.
@@ -649,10 +646,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind,
                 Err(ErrorHandled::TooGeneric(_)) => {
                     // If we land here it means the const can't be evaluated because it's `TooGeneric`.
-                    self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
-                    PatKind::Wild
+                    let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
+                    PatKind::Error(e)
                 }
-                Err(ErrorHandled::Reported(..)) => PatKind::Wild,
+                Err(ErrorHandled::Reported(err, ..)) => PatKind::Error(err.into()),
             }
         }
     }
@@ -685,7 +682,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             Ok(constant) => {
                 self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind
             }
-            Err(LitToConstError::Reported(_)) => PatKind::Wild,
+            Err(LitToConstError::Reported(e)) => PatKind::Error(e),
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
         }
     }
@@ -791,6 +788,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
             PatKind::Wild => PatKind::Wild,
+            PatKind::Error(e) => PatKind::Error(e),
             PatKind::AscribeUserType {
                 ref subpattern,
                 ascription: Ascription { ref annotation, variance },
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 3b6276cfeb0e6..c957611b975c7 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -757,6 +757,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 print_indented!(self, "]", depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
+            PatKind::Error(_) => {
+                print_indented!(self, "Error", depth_lvl + 1);
+            }
         }
 
         print_indented!(self, "}", depth_lvl);
diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs
index 0cf163d9fb8e9..947ef4c8aeff5 100644
--- a/library/std/src/sys/unix/process/mod.rs
+++ b/library/std/src/sys/unix/process/mod.rs
@@ -6,6 +6,9 @@ pub use crate::sys_common::process::CommandEnvs;
 #[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused))]
 mod process_common;
 
+#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
+mod process_unsupported;
+
 cfg_if::cfg_if! {
     if #[cfg(target_os = "fuchsia")] {
         #[path = "process_fuchsia.rs"]
@@ -15,8 +18,9 @@ cfg_if::cfg_if! {
         #[path = "process_vxworks.rs"]
         mod process_inner;
     } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
-        #[path = "process_unsupported.rs"]
-        mod process_inner;
+        mod process_inner {
+            pub use super::process_unsupported::*;
+        }
     } else {
         #[path = "process_unix.rs"]
         mod process_inner;
diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs
index 325d3f23be7c2..2fbb31922653c 100644
--- a/library/std/src/sys/unix/process/process_unsupported.rs
+++ b/library/std/src/sys/unix/process/process_unsupported.rs
@@ -63,12 +63,12 @@ pub struct ExitStatusError(NonZero_c_int);
 
 impl Into<ExitStatus> for ExitStatusError {
     fn into(self) -> ExitStatus {
-        ExitStatus(self.0.into())
+        ExitStatus::from(c_int::from(self.0))
     }
 }
 
 impl ExitStatusError {
     pub fn code(self) -> Option<NonZeroI32> {
-        ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
+        ExitStatus::from(c_int::from(self.0)).code().map(|st| st.try_into().unwrap())
     }
 }
diff --git a/library/std/src/sys/unix/process/process_unsupported/wait_status.rs b/library/std/src/sys/unix/process/process_unsupported/wait_status.rs
index 3c649db1a35e5..72b7ae18cff27 100644
--- a/library/std/src/sys/unix/process/process_unsupported/wait_status.rs
+++ b/library/std/src/sys/unix/process/process_unsupported/wait_status.rs
@@ -1,10 +1,13 @@
 //! Emulated wait status for non-Unix #[cfg(unix) platforms
 //!
 //! Separate module to facilitate testing against a real Unix implementation.
+use core::ffi::NonZero_c_int;
 
 use crate::ffi::c_int;
 use crate::fmt;
 
+use super::ExitStatusError;
+
 /// Emulated wait status for use by `process_unsupported.rs`
 ///
 /// Uses the "traditional unix" encoding.  For use on platfors which are `#[cfg(unix)]`
@@ -40,6 +43,19 @@ impl ExitStatus {
         if (w & 0x7f) == 0 { Some((w & 0xff00) >> 8) } else { None }
     }
 
+    #[allow(unused)]
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
+        // true on all actual versions of Unix, is widely assumed, and is specified in SuS
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
+        // true for a platform pretending to be Unix, the tests (our doctests, and also
+        // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
+        match NonZero_c_int::try_from(self.wait_status) {
+            /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
+            /* was zero, couldn't convert */ Err(_) => Ok(()),
+        }
+    }
+
     pub fn signal(&self) -> Option<i32> {
         let signal = self.wait_status & 0x007f;
         if signal > 0 && signal < 0x7f { Some(signal) } else { None }
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 9bf26948af3aa..7e72e87710486 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -5,6 +5,9 @@ edition = "2021"
 build = "build.rs"
 default-run = "bootstrap"
 
+[features]
+build-metrics = ["sysinfo"]
+
 [lib]
 path = "lib.rs"
 doctest = false
@@ -31,12 +34,18 @@ test = false
 
 [dependencies]
 build_helper = { path = "../tools/build_helper" }
+cc = "1.0.69"
+clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
+clap_complete = "4.2.2"
 cmake = "0.1.38"
 filetime = "0.2"
-cc = "1.0.69"
-libc = "0.2"
 hex = "0.4"
+ignore = "0.4.10"
+libc = "0.2"
 object = { version = "0.32.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
+once_cell = "1.7.2"
+opener = "0.5"
+semver = "1.0.17"
 serde = "1.0.137"
 # Directly use serde_derive rather than through the derive feature of serde to allow building both
 # in parallel and to allow serde_json and toml to start building as soon as serde has been built.
@@ -46,17 +55,11 @@ sha2 = "0.10"
 tar = "0.4"
 termcolor = "1.2.0"
 toml = "0.5"
-ignore = "0.4.10"
-opener = "0.5"
-once_cell = "1.7.2"
-xz2 = "0.1"
 walkdir = "2"
+xz2 = "0.1"
 
 # Dependencies needed by the build-metrics feature
 sysinfo = { version = "0.26.0", optional = true }
-clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
-clap_complete = "4.2.2"
-semver = "1.0.17"
 
 # Solaris doesn't support flock() and thus fd-lock is not option now
 [target.'cfg(not(target_os = "solaris"))'.dependencies]
@@ -80,9 +83,6 @@ features = [
 [dev-dependencies]
 pretty_assertions = "1.4"
 
-[features]
-build-metrics = ["sysinfo"]
-
 # We care a lot about bootstrap's compile times, so don't include debuginfo for
 # dependencies, only bootstrap itself.
 [profile.dev]
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index dbf0baec04c03..1733c8fc9a246 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -110,3 +110,23 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
 
 This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
 to automatically go to the first result.
+
+## `#[repr(transparent)]`: Documenting the transparent representation
+
+You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and
+in the [Rustonomicon][repr-trans-nomicon].
+
+Since this representation is only considered part of the public ABI if the single field with non-trivial
+size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays
+the attribute if and only if the non-1-ZST field is public or at least one field is public in case all
+fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized.
+
+It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]`
+if one wishes to declare the representation as private even if the non-1-ZST field is public.
+However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work.
+Therefore, if you would like to do so, you should always write it down in prose independently of whether
+you use `cfg_attr` or not.
+
+[repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation
+[repr-trans-nomicon]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
+[cross-crate-cfg-doc]: https://github.com/rust-lang/rust/issues/114952
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 517a51867cfff..2a54266676d0c 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -713,12 +713,16 @@ impl Item {
         Some(tcx.visibility(def_id))
     }
 
-    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec<String> {
+    pub(crate) fn attributes(
+        &self,
+        tcx: TyCtxt<'_>,
+        cache: &Cache,
+        keep_as_is: bool,
+    ) -> Vec<String> {
         const ALLOWED_ATTRIBUTES: &[Symbol] =
-            &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
+            &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
 
         use rustc_abi::IntegerType;
-        use rustc_middle::ty::ReprFlags;
 
         let mut attrs: Vec<String> = self
             .attrs
@@ -739,20 +743,38 @@ impl Item {
                 }
             })
             .collect();
-        if let Some(def_id) = self.def_id() &&
-            !def_id.is_local() &&
-            // This check is needed because `adt_def` will panic if not a compatible type otherwise...
-            matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union)
+        if !keep_as_is
+            && let Some(def_id) = self.def_id()
+            && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
         {
-            let repr = tcx.adt_def(def_id).repr();
+            let adt = tcx.adt_def(def_id);
+            let repr = adt.repr();
             let mut out = Vec::new();
-            if repr.flags.contains(ReprFlags::IS_C) {
+            if repr.c() {
                 out.push("C");
             }
-            if repr.flags.contains(ReprFlags::IS_TRANSPARENT) {
-                out.push("transparent");
+            if repr.transparent() {
+                // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
+                // field is public in case all fields are 1-ZST fields.
+                let render_transparent = cache.document_private
+                    || adt
+                        .all_fields()
+                        .find(|field| {
+                            let ty =
+                                field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
+                            tcx.layout_of(tcx.param_env(field.did).and(ty))
+                                .is_ok_and(|layout| !layout.is_1zst())
+                        })
+                        .map_or_else(
+                            || adt.all_fields().any(|field| field.vis.is_public()),
+                            |field| field.vis.is_public(),
+                        );
+
+                if render_transparent {
+                    out.push("transparent");
+                }
             }
-            if repr.flags.contains(ReprFlags::IS_SIMD) {
+            if repr.simd() {
                 out.push("simd");
             }
             let pack_s;
@@ -777,10 +799,9 @@ impl Item {
                 };
                 out.push(&int_s);
             }
-            if out.is_empty() {
-                return Vec::new();
+            if !out.is_empty() {
+                attrs.push(format!("#[repr({})]", out.join(", ")));
             }
-            attrs.push(format!("#[repr({})]", out.join(", ")));
         }
         attrs
     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 49817f5eb6457..89e29d8b59b2f 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -868,10 +868,10 @@ fn assoc_method(
     let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
         header_len += 4;
         let indent_str = "    ";
-        write!(w, "{}", render_attributes_in_pre(meth, indent_str, tcx));
+        write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx));
         (4, indent_str, Ending::NoNewline)
     } else {
-        render_attributes_in_code(w, meth, tcx);
+        render_attributes_in_code(w, meth, cx);
         (0, "", Ending::Newline)
     };
     w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
@@ -1047,13 +1047,13 @@ fn render_assoc_item(
 
 // When an attribute is rendered inside a `<pre>` tag, it is formatted using
 // a whitespace prefix and newline.
-fn render_attributes_in_pre<'a, 'b: 'a>(
+fn render_attributes_in_pre<'a, 'tcx: 'a>(
     it: &'a clean::Item,
     prefix: &'a str,
-    tcx: TyCtxt<'b>,
-) -> impl fmt::Display + Captures<'a> + Captures<'b> {
+    cx: &'a Context<'tcx>,
+) -> impl fmt::Display + Captures<'a> + Captures<'tcx> {
     crate::html::format::display_fn(move |f| {
-        for a in it.attributes(tcx, false) {
+        for a in it.attributes(cx.tcx(), cx.cache(), false) {
             writeln!(f, "{prefix}{a}")?;
         }
         Ok(())
@@ -1062,8 +1062,8 @@ fn render_attributes_in_pre<'a, 'b: 'a>(
 
 // When an attribute is rendered inside a <code> tag, it is formatted using
 // a div to produce a newline after it.
-fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, tcx: TyCtxt<'_>) {
-    for attr in it.attributes(tcx, false) {
+fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
+    for attr in it.attributes(cx.tcx(), cx.cache(), false) {
         write!(w, "<div class=\"code-attribute\">{attr}</div>").unwrap();
     }
 }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index cd31493bf3ff8..f6432dc61ae06 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -120,8 +120,7 @@ macro_rules! item_template_methods {
         fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
             display_fn(move |f| {
                 let (item, cx) = self.item_and_mut_cx();
-                let tcx = cx.tcx();
-                let v = render_attributes_in_pre(item, "", tcx);
+                let v = render_attributes_in_pre(item, "", &cx);
                 write!(f, "{v}")
             })
         }
@@ -659,7 +658,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
             w,
             "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \
                 {name}{generics}{decl}{notable_traits}{where_clause}",
-            attrs = render_attributes_in_pre(it, "", tcx),
+            attrs = render_attributes_in_pre(it, "", cx),
             vis = visibility,
             constness = constness,
             asyncness = asyncness,
@@ -694,7 +693,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
         write!(
             w,
             "{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}",
-            attrs = render_attributes_in_pre(it, "", tcx),
+            attrs = render_attributes_in_pre(it, "", cx),
             vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
             unsafety = t.unsafety(tcx).print_with_space(),
             is_auto = if t.is_auto(tcx) { "auto " } else { "" },
@@ -1173,7 +1172,7 @@ fn item_trait_alias(
         write!(
             w,
             "{attrs}trait {name}{generics}{where_b} = {bounds};",
-            attrs = render_attributes_in_pre(it, "", cx.tcx()),
+            attrs = render_attributes_in_pre(it, "", cx),
             name = it.name.unwrap(),
             generics = t.generics.print(cx),
             where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline),
@@ -1201,7 +1200,7 @@ fn item_opaque_ty(
         write!(
             w,
             "{attrs}type {name}{generics}{where_clause} = impl {bounds};",
-            attrs = render_attributes_in_pre(it, "", cx.tcx()),
+            attrs = render_attributes_in_pre(it, "", cx),
             name = it.name.unwrap(),
             generics = t.generics.print(cx),
             where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
@@ -1226,7 +1225,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c
             write!(
                 w,
                 "{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
-                attrs = render_attributes_in_pre(it, "", cx.tcx()),
+                attrs = render_attributes_in_pre(it, "", cx),
                 vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
                 name = it.name.unwrap(),
                 generics = t.generics.print(cx),
@@ -1415,7 +1414,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
     let tcx = cx.tcx();
     let count_variants = e.variants().count();
     wrap_item(w, |w| {
-        render_attributes_in_code(w, it, tcx);
+        render_attributes_in_code(w, it, cx);
         write!(
             w,
             "{}enum {}{}",
@@ -1734,7 +1733,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Ite
 fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
     wrap_item(w, |w| {
         let tcx = cx.tcx();
-        render_attributes_in_code(w, it, tcx);
+        render_attributes_in_code(w, it, cx);
 
         write!(
             w,
@@ -1783,7 +1782,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
 
 fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
     wrap_item(w, |w| {
-        render_attributes_in_code(w, it, cx.tcx());
+        render_attributes_in_code(w, it, cx);
         render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
     });
 
@@ -1843,7 +1842,7 @@ fn item_fields(
 
 fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
     wrap_item(w, |buffer| {
-        render_attributes_in_code(buffer, it, cx.tcx());
+        render_attributes_in_code(buffer, it, cx);
         write!(
             buffer,
             "{vis}static {mutability}{name}: {typ}",
@@ -1861,7 +1860,7 @@ fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item,
 fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item) {
     wrap_item(w, |buffer| {
         buffer.write_str("extern {\n").unwrap();
-        render_attributes_in_code(buffer, it, cx.tcx());
+        render_attributes_in_code(buffer, it, cx);
         write!(
             buffer,
             "    {}type {};\n}}",
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 1420d1086649d..17e2172a27068 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -18,6 +18,7 @@ use rustdoc_json_types::*;
 
 use crate::clean::{self, ItemId};
 use crate::formats::item_type::ItemType;
+use crate::formats::FormatRenderer;
 use crate::json::JsonRenderer;
 use crate::passes::collect_intra_doc_links::UrlFragment;
 
@@ -41,7 +42,7 @@ impl JsonRenderer<'_> {
             })
             .collect();
         let docs = item.opt_doc_value();
-        let attrs = item.attributes(self.tcx, true);
+        let attrs = item.attributes(self.tcx, self.cache(), true);
         let span = item.span(self.tcx);
         let visibility = item.visibility(self.tcx);
         let clean::Item { name, item_id, .. } = item;
diff --git a/tests/codegen/target-feature-inline-closure.rs b/tests/codegen/target-feature-inline-closure.rs
index d075706173fd1..54cb27242d5a7 100644
--- a/tests/codegen/target-feature-inline-closure.rs
+++ b/tests/codegen/target-feature-inline-closure.rs
@@ -31,3 +31,7 @@ unsafe fn without_avx(x: __m256) -> __m256 {
     };
     add(x, x)
 }
+
+// Don't allow the above CHECK-NOT to accidentally match a commit hash in the
+// compiler version.
+// CHECK-LABEL: rustc version
diff --git a/tests/rustdoc/inline_cross/attributes.rs b/tests/rustdoc/inline_cross/attributes.rs
new file mode 100644
index 0000000000000..c0b75c48fee91
--- /dev/null
+++ b/tests/rustdoc/inline_cross/attributes.rs
@@ -0,0 +1,7 @@
+// aux-crate:attributes=attributes.rs
+// edition:2021
+#![crate_name = "user"]
+
+// @has 'user/struct.NonExhaustive.html'
+// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[non_exhaustive]'
+pub use attributes::NonExhaustive;
diff --git a/tests/rustdoc/inline_cross/auxiliary/attributes.rs b/tests/rustdoc/inline_cross/auxiliary/attributes.rs
new file mode 100644
index 0000000000000..c6f155d4ba5a9
--- /dev/null
+++ b/tests/rustdoc/inline_cross/auxiliary/attributes.rs
@@ -0,0 +1,2 @@
+#[non_exhaustive]
+pub struct NonExhaustive;
diff --git a/tests/rustdoc/inline_cross/auxiliary/repr.rs b/tests/rustdoc/inline_cross/auxiliary/repr.rs
index 4a6648a643980..35f08c11b7b3a 100644
--- a/tests/rustdoc/inline_cross/auxiliary/repr.rs
+++ b/tests/rustdoc/inline_cross/auxiliary/repr.rs
@@ -10,7 +10,7 @@ pub struct ReprSimd {
 }
 #[repr(transparent)]
 pub struct ReprTransparent {
-    field: u8,
+    pub field: u8,
 }
 #[repr(isize)]
 pub enum ReprIsize {
@@ -20,3 +20,23 @@ pub enum ReprIsize {
 pub enum ReprU8 {
     Bla,
 }
+
+#[repr(transparent)] // private
+pub struct ReprTransparentPrivField {
+    field: u32, // non-1-ZST field
+}
+
+#[repr(transparent)] // public
+pub struct ReprTransparentPriv1ZstFields {
+    marker0: Marker,
+    pub main: u64, // non-1-ZST field
+    marker1: Marker,
+}
+
+#[repr(transparent)] // private
+pub struct ReprTransparentPrivFieldPub1ZstFields {
+    main: [u16; 0], // non-1-ZST field
+    pub marker: Marker,
+}
+
+pub struct Marker; // 1-ZST
diff --git a/tests/rustdoc/inline_cross/repr.rs b/tests/rustdoc/inline_cross/repr.rs
index 9e107cee9e91b..2f3d8f0038846 100644
--- a/tests/rustdoc/inline_cross/repr.rs
+++ b/tests/rustdoc/inline_cross/repr.rs
@@ -9,21 +9,32 @@ extern crate repr;
 
 // @has 'foo/struct.ReprC.html'
 // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]'
-#[doc(inline)]
 pub use repr::ReprC;
 // @has 'foo/struct.ReprSimd.html'
 // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
-#[doc(inline)]
 pub use repr::ReprSimd;
 // @has 'foo/struct.ReprTransparent.html'
 // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-#[doc(inline)]
 pub use repr::ReprTransparent;
 // @has 'foo/enum.ReprIsize.html'
 // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
-#[doc(inline)]
 pub use repr::ReprIsize;
 // @has 'foo/enum.ReprU8.html'
 // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]'
-#[doc(inline)]
 pub use repr::ReprU8;
+
+// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
+// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one
+// field is public in case all fields are 1-ZST fields.
+
+// @has 'foo/struct.ReprTransparentPrivField.html'
+// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+pub use repr::ReprTransparentPrivField;
+
+// @has 'foo/struct.ReprTransparentPriv1ZstFields.html'
+// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+pub use repr::ReprTransparentPriv1ZstFields;
+
+// @has 'foo/struct.ReprTransparentPrivFieldPub1ZstFields.html'
+// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+pub use repr::ReprTransparentPrivFieldPub1ZstFields;
diff --git a/tests/rustdoc/repr.rs b/tests/rustdoc/repr.rs
new file mode 100644
index 0000000000000..fbb46e126ba6a
--- /dev/null
+++ b/tests/rustdoc/repr.rs
@@ -0,0 +1,29 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
+// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one
+// field is public in case all fields are 1-ZST fields.
+
+// @has 'repr/struct.ReprTransparentPrivField.html'
+// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // private
+pub struct ReprTransparentPrivField {
+    field: u32, // non-1-ZST field
+}
+
+// @has 'repr/struct.ReprTransparentPriv1ZstFields.html'
+// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // public
+pub struct ReprTransparentPriv1ZstFields {
+    marker0: Marker,
+    pub main: u64, // non-1-ZST field
+    marker1: Marker,
+}
+
+// @has 'repr/struct.ReprTransparentPub1ZstField.html'
+// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // public
+pub struct ReprTransparentPub1ZstField {
+    marker0: Marker,
+    pub marker1: Marker,
+}
+
+struct Marker; // 1-ZST
diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
index 69bc174b6beeb..8cbd12654480a 100644
--- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
@@ -7,17 +7,5 @@ LL |         WHAT_A_TYPE => 0,
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
-error[E0015]: cannot match on `TypeId` in constant functions
-  --> $DIR/typeid-equality-by-subtyping.rs:18:9
-   |
-LL |         WHAT_A_TYPE => 0,
-   |         ^^^^^^^^^^^
-   |
-   = note: `TypeId` cannot be compared in compile-time, and therefore cannot be used in `match`es
-note: impl defined here, but it is not `const`
-  --> $SRC_DIR/core/src/any.rs:LL:COL
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs
new file mode 100644
index 0000000000000..6863a3c73badf
--- /dev/null
+++ b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs
@@ -0,0 +1,25 @@
+// This test should never pass!
+
+#![feature(type_alias_impl_trait)]
+
+trait Captures<'a> {}
+impl<T> Captures<'_> for T {}
+
+struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>);
+unsafe impl Send for MyTy<'_, 'static> {}
+
+fn step1<'a, 'b: 'a>() -> impl Sized + Captures<'b> + 'a {
+    MyTy::<'a, 'b>(None)
+}
+
+fn step2<'a, 'b: 'a>() -> impl Sized + 'a {
+    step1::<'a, 'b>()
+    //~^ ERROR hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds
+}
+
+fn step3<'a, 'b: 'a>() -> impl Send + 'a {
+    step2::<'a, 'b>()
+    // This should not be Send unless `'b: 'static`
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr
new file mode 100644
index 0000000000000..168a5aa18ec45
--- /dev/null
+++ b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr
@@ -0,0 +1,18 @@
+error[E0700]: hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds
+  --> $DIR/rpit-hidden-erased-unsoundness.rs:16:5
+   |
+LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a {
+   |              --           --------------- opaque type defined here
+   |              |
+   |              hidden type `impl Captures<'b> + 'a` captures the lifetime `'b` as defined here
+LL |     step1::<'a, 'b>()
+   |     ^^^^^^^^^^^^^^^^^
+   |
+help: to declare that `impl Sized + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
+   |
+LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a + 'b {
+   |                                           ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs
new file mode 100644
index 0000000000000..4de2ffbb80870
--- /dev/null
+++ b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs
@@ -0,0 +1,32 @@
+// This test should never pass!
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+trait Swap: Sized {
+    fn swap(self, other: Self);
+}
+
+impl<T> Swap for Rc<RefCell<T>> {
+    fn swap(self, other: Self) {
+        <RefCell<T>>::swap(&self, &other);
+    }
+}
+
+fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
+    x
+    //~^ ERROR hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds
+}
+
+fn dangle() -> &'static [i32; 3] {
+    let long = Rc::new(RefCell::new(&[4, 5, 6]));
+    let x = [1, 2, 3];
+    let short = Rc::new(RefCell::new(&x));
+    hide(long.clone()).swap(hide(short));
+    let res: &'static [i32; 3] = *long.borrow();
+    res
+}
+
+fn main() {
+    println!("{:?}", dangle());
+}
diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr
new file mode 100644
index 0000000000000..cabba4bafafdd
--- /dev/null
+++ b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr
@@ -0,0 +1,18 @@
+error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds
+  --> $DIR/rpit-hide-lifetime-for-swap.rs:17:5
+   |
+LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
+   |             --                                            -------------- opaque type defined here
+   |             |
+   |             hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
+LL |     x
+   |     ^
+   |
+help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
+   |
+LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b {
+   |                                                                          ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs
new file mode 100644
index 0000000000000..40efd941e338c
--- /dev/null
+++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs
@@ -0,0 +1,28 @@
+// This test should never pass!
+
+#![feature(type_alias_impl_trait)]
+
+trait Captures<'a> {}
+impl<T> Captures<'_> for T {}
+
+struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>);
+unsafe impl Send for MyTy<'_, 'static> {}
+
+fn step1<'a, 'b: 'a>() -> impl Sized + Captures<'b> + 'a {
+    MyTy::<'a, 'b>(None)
+}
+
+mod tait {
+    type Tait<'a> = impl Sized + 'a;
+    pub(super) fn step2<'a, 'b: 'a>() -> Tait<'a> {
+        super::step1::<'a, 'b>()
+        //~^ ERROR hidden type for `Tait<'a>` captures lifetime that does not appear in bounds
+    }
+}
+
+fn step3<'a, 'b: 'a>() -> impl Send + 'a {
+    tait::step2::<'a, 'b>()
+    // This should not be Send unless `'b: 'static`
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr
new file mode 100644
index 0000000000000..baeec6d5892d1
--- /dev/null
+++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr
@@ -0,0 +1,13 @@
+error[E0700]: hidden type for `Tait<'a>` captures lifetime that does not appear in bounds
+  --> $DIR/tait-hidden-erased-unsoundness.rs:18:9
+   |
+LL |     type Tait<'a> = impl Sized + 'a;
+   |                     --------------- opaque type defined here
+LL |     pub(super) fn step2<'a, 'b: 'a>() -> Tait<'a> {
+   |                             -- hidden type `impl Captures<'b> + 'a` captures the lifetime `'b` as defined here
+LL |         super::step1::<'a, 'b>()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/pattern/usefulness/consts-opaque.rs b/tests/ui/pattern/usefulness/consts-opaque.rs
index 2032cf13bc26e..6dc1425cf037e 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.rs
+++ b/tests/ui/pattern/usefulness/consts-opaque.rs
@@ -52,7 +52,6 @@ fn main() {
         BAR => {}
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         _ => {}
-        //~^ ERROR unreachable pattern
     }
 
     match BAR {
@@ -60,7 +59,6 @@ fn main() {
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         Bar => {}
         _ => {}
-        //~^ ERROR unreachable pattern
     }
 
     match BAR {
diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr
index cd88e6a22e4a5..51f2f276bbe2e 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.stderr
+++ b/tests/ui/pattern/usefulness/consts-opaque.stderr
@@ -38,7 +38,7 @@ LL |         BAR => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:59:9
+  --> $DIR/consts-opaque.rs:58:9
    |
 LL |         BAR => {}
    |         ^^^
@@ -47,7 +47,7 @@ LL |         BAR => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:67:9
+  --> $DIR/consts-opaque.rs:65:9
    |
 LL |         BAR => {}
    |         ^^^
@@ -56,7 +56,7 @@ LL |         BAR => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:69:9
+  --> $DIR/consts-opaque.rs:67:9
    |
 LL |         BAR => {}
    |         ^^^
@@ -65,7 +65,7 @@ LL |         BAR => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:75:9
+  --> $DIR/consts-opaque.rs:73:9
    |
 LL |         BAZ => {}
    |         ^^^
@@ -74,7 +74,7 @@ LL |         BAZ => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:83:9
+  --> $DIR/consts-opaque.rs:81:9
    |
 LL |         BAZ => {}
    |         ^^^
@@ -83,7 +83,7 @@ LL |         BAZ => {}
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
 error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:89:9
+  --> $DIR/consts-opaque.rs:87:9
    |
 LL |         BAZ => {}
    |         ^^^
@@ -91,37 +91,14 @@ LL |         BAZ => {}
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:54:9
-   |
-LL |         Bar => {}
-   |         --- matches any value
-...
-LL |         _ => {}
-   |         ^ unreachable pattern
-   |
-note: the lint level is defined here
-  --> $DIR/consts-opaque.rs:6:9
-   |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:62:9
-   |
-LL |         Bar => {}
-   |         --- matches any value
-LL |         _ => {}
-   |         ^ unreachable pattern
-
 error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered
-  --> $DIR/consts-opaque.rs:124:11
+  --> $DIR/consts-opaque.rs:122:11
    |
 LL |     match WRAPQUUX {
    |           ^^^^^^^^ pattern `Wrap(_)` not covered
    |
 note: `Wrap<fn(usize, usize) -> usize>` defined here
-  --> $DIR/consts-opaque.rs:106:12
+  --> $DIR/consts-opaque.rs:104:12
    |
 LL |     struct Wrap<T>(T);
    |            ^^^^
@@ -132,6 +109,6 @@ LL ~         WRAPQUUX => {},
 LL +         Wrap(_) => todo!()
    |
 
-error: aborting due to 12 previous errors; 1 warning emitted
+error: aborting due to 10 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0004`.