about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-23 20:45:23 +0000
committerbors <bors@rust-lang.org>2023-06-23 20:45:23 +0000
commit22e9fe644ea710eec50cb0aabcae7fa8dd9fd675 (patch)
treebcdf9898595f7ddd107a0e810a32b9b8175cc45a
parentc79d6be6a287dcda55236fa6438286d16ec990ae (diff)
parent9d7f297f3c7ad6c18cea1f7fe091c3674ec34806 (diff)
downloadrust-22e9fe644ea710eec50cb0aabcae7fa8dd9fd675.tar.gz
rust-22e9fe644ea710eec50cb0aabcae7fa8dd9fd675.zip
Auto merge of #112974 - matthiaskrgr:rollup-hnk7ans, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #112616 (Improve tests on targets without unwinding)
 - #112643 (Always register sized obligation for argument)
 - #112740 (Add link to rustdoc book search chapter in help popover)
 - #112810 (Don't ICE on unnormalized struct tail in layout computation)
 - #112870 (Migrate `item_bounds` to `ty::Clause`)
 - #112925 (Stop hiding const eval limit in external macros)
 - #112960 ([tests/rustdoc] Add `@files` command)
 - #112962 (Fix rustdoc gui tester)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs34
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs6
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs4
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs2
-rw-r--r--compiler/rustc_infer/src/traits/util.rs24
-rw-r--r--compiler/rustc_lint/src/builtin.rs8
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs4
-rw-r--r--compiler/rustc_lint/src/unused.rs5
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs10
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs2
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs17
-rw-r--r--compiler/rustc_middle/src/ty/context.rs29
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs36
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs14
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs68
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs6
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs35
-rw-r--r--src/bootstrap/download.rs22
-rw-r--r--src/bootstrap/lib.rs14
-rw-r--r--src/bootstrap/run.rs11
-rw-r--r--src/bootstrap/test.rs38
-rw-r--r--src/bootstrap/tool.rs2
-rw-r--r--src/bootstrap/util.rs2
-rwxr-xr-xsrc/etc/htmldocck.py54
-rw-r--r--src/librustdoc/clean/mod.rs21
-rw-r--r--src/librustdoc/clean/utils.rs3
-rw-r--r--src/librustdoc/html/layout.rs2
-rw-r--r--src/librustdoc/html/static/js/main.js8
-rw-r--r--src/librustdoc/html/templates/page.html1
-rw-r--r--src/tools/build_helper/src/util.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs14
-rw-r--r--src/tools/rustdoc-gui-test/src/main.rs9
-rw-r--r--tests/codegen/naked-nocoverage.rs2
-rw-r--r--tests/rustdoc-gui/help-page.goml4
-rw-r--r--tests/rustdoc-gui/search-result-color.goml5
-rw-r--r--tests/rustdoc/files-creation-hidden.rs1
-rw-r--r--tests/rustdoc/files-creation-private.rs4
-rw-r--r--tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs6
-rw-r--r--tests/rustdoc/issue-111249-file-creation.rs6
-rw-r--r--tests/ui/asm/aarch64/may_unwind.rs1
-rw-r--r--tests/ui/closures/cannot-call-unsized-via-ptr-2.rs11
-rw-r--r--tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr21
-rw-r--r--tests/ui/closures/cannot-call-unsized-via-ptr.rs10
-rw-r--r--tests/ui/closures/cannot-call-unsized-via-ptr.stderr12
-rw-r--r--tests/ui/const-generics/issue-112505-overflow.stderr4
-rw-r--r--tests/ui/const-generics/transmute-fail.stderr4
-rw-r--r--tests/ui/consts/timeout.rs25
-rw-r--r--tests/ui/consts/timeout.stderr15
-rw-r--r--tests/ui/issues/issue-5883.rs2
-rw-r--r--tests/ui/issues/issue-5883.stderr18
-rw-r--r--tests/ui/layout/cannot-transmute-unnormalizable-type.rs22
-rw-r--r--tests/ui/layout/cannot-transmute-unnormalizable-type.stderr19
-rw-r--r--tests/ui/test-attrs/test-panic-abort-disabled.rs1
-rw-r--r--tests/ui/test-attrs/test-type.rs3
78 files changed, 579 insertions, 271 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 7119510849a..5c365e98f0b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -705,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
                 .explicit_item_bounds(def_id)
                 .subst_iter_copied(tcx, substs)
-                .find_map(find_fn_kind_from_did),
+                .find_map(|(clause, span)| find_fn_kind_from_did((clause.as_predicate(), span))),
             ty::Closure(_, substs) => match substs.as_closure().kind() {
                 ty::ClosureKind::Fn => Some(hir::Mutability::Not),
                 ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 1dfe053b215..596c5518086 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -409,9 +409,7 @@ fn fn_sig_suggestion<'tcx>(
         output = if let ty::Alias(_, alias_ty) = *output.kind() {
             tcx.explicit_item_bounds(alias_ty.def_id)
                 .subst_iter_copied(tcx, alias_ty.substs)
-                .find_map(|(bound, _)| {
-                    bound.to_opt_poly_projection_pred()?.no_bound_vars()?.term.ty()
-                })
+                .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty())
                 .unwrap_or_else(|| {
                     span_bug!(
                         ident.span,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 51e9b4c4501..814a290178e 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1086,7 +1086,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt
             wfcx.infcx,
             wfcx.param_env,
             wfcx.body_def_id,
-            normalized_bound,
+            normalized_bound.as_predicate(),
             bound_span,
         )
     });
@@ -1562,7 +1562,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
                     self.wfcx.infcx,
                     self.wfcx.param_env,
                     self.wfcx.body_def_id,
-                    bound,
+                    bound.as_predicate(),
                     bound_span,
                 ));
                 // Set the debruijn index back to innermost here, since we already eagerly
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 5f35678d95d..958313fee6f 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -19,7 +19,7 @@ fn associated_type_bounds<'tcx>(
     assoc_item_def_id: LocalDefId,
     ast_bounds: &'tcx [hir::GenericBound<'tcx>],
     span: Span,
-) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+) -> &'tcx [(ty::Clause<'tcx>, Span)] {
     let item_ty = tcx.mk_projection(
         assoc_item_def_id.to_def_id(),
         InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
@@ -33,8 +33,11 @@ fn associated_type_bounds<'tcx>(
     let trait_def_id = tcx.local_parent(assoc_item_def_id);
     let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
 
-    let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
-        match pred.kind().skip_binder() {
+    let bounds_from_parent = trait_predicates
+        .predicates
+        .iter()
+        .copied()
+        .filter(|(pred, _)| match pred.kind().skip_binder() {
             ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.self_ty() == item_ty,
             ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => {
                 proj.projection_ty.self_ty() == item_ty
@@ -43,15 +46,10 @@ fn associated_type_bounds<'tcx>(
                 outlives.0 == item_ty
             }
             _ => false,
-        }
-    });
+        })
+        .map(|(pred, span)| (pred.expect_clause(), span));
 
-    let all_bounds = tcx.arena.alloc_from_iter(
-        bounds
-            .clauses()
-            .map(|(clause, span)| (clause.as_predicate(), span))
-            .chain(bounds_from_parent),
-    );
+    let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
     debug!(
         "associated_type_bounds({}) = {:?}",
         tcx.def_path_str(assoc_item_def_id.to_def_id()),
@@ -71,7 +69,7 @@ fn opaque_type_bounds<'tcx>(
     ast_bounds: &'tcx [hir::GenericBound<'tcx>],
     item_ty: Ty<'tcx>,
     span: Span,
-) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+) -> &'tcx [(ty::Clause<'tcx>, Span)] {
     ty::print::with_no_queries!({
         let icx = ItemCtxt::new(tcx, opaque_def_id);
         let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
@@ -79,15 +77,14 @@ fn opaque_type_bounds<'tcx>(
         icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
         debug!(?bounds);
 
-        tcx.arena
-            .alloc_from_iter(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)))
+        tcx.arena.alloc_from_iter(bounds.clauses())
     })
 }
 
 pub(super) fn explicit_item_bounds(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
-) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> {
+) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
     match tcx.opt_rpitit_info(def_id.to_def_id()) {
         // RPITIT's bounds are the same as opaque type bounds, but with
         // a projection self type.
@@ -139,11 +136,8 @@ pub(super) fn explicit_item_bounds(
 pub(super) fn item_bounds(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
+) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
     tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
-        tcx.mk_predicates_from_iter(util::elaborate(
-            tcx,
-            bounds.iter().map(|&(bound, _span)| bound),
-        ))
+        tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
     })
 }
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index 98f4a8e00ef..48624cefe4d 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -3,7 +3,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt};
+use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
@@ -17,7 +17,7 @@ pub fn provide(providers: &mut Providers) {
     *providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers };
 }
 
-fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::ClauseKind<'_>, Span)] {
+fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] {
     let id = tcx.hir().local_def_id_to_hir_id(item_def_id);
 
     if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst)
@@ -52,7 +52,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
                 if tcx.has_attr(item_def_id, sym::rustc_outlives) {
                     let mut pred: Vec<String> = predicates
                         .iter()
-                        .map(|(out_pred, _)| match out_pred {
+                        .map(|(out_pred, _)| match out_pred.kind().skip_binder() {
                             ty::ClauseKind::RegionOutlives(p) => p.to_string(),
                             ty::ClauseKind::TypeOutlives(p) => p.to_string(),
                             err => bug!("unexpected clause {:?}", err),
@@ -104,13 +104,15 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
                     |(ty::OutlivesPredicate(kind1, region2), &span)| {
                         match kind1.unpack() {
                             GenericArgKind::Type(ty1) => Some((
-                                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)),
+                                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2))
+                                    .to_predicate(tcx),
                                 span,
                             )),
                             GenericArgKind::Lifetime(region1) => Some((
                                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
                                     region1, *region2,
-                                )),
+                                ))
+                                .to_predicate(tcx),
                                 span,
                             )),
                             GenericArgKind::Const(_) => {
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 8bb9ca2acf2..23d8da88a45 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -162,28 +162,25 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
         // which thus mentions `'a` and should thus accept hidden types that borrow 'a
         // instead of requiring an additional `+ 'a`.
         match pred.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
+            ty::ClauseKind::Trait(ty::TraitPredicate {
                 trait_ref: ty::TraitRef { def_id: _, substs, .. },
                 constness: _,
                 polarity: _,
-            })) => {
+            }) => {
                 for subst in &substs[1..] {
                     subst.visit_with(&mut collector);
                 }
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
+            ty::ClauseKind::Projection(ty::ProjectionPredicate {
                 projection_ty: ty::AliasTy { substs, .. },
                 term,
-            })) => {
+            }) => {
                 for subst in &substs[1..] {
                     subst.visit_with(&mut collector);
                 }
                 term.visit_with(&mut collector);
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
-                _,
-                region,
-            ))) => {
+            ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_, region)) => {
                 region.visit_with(&mut collector);
             }
             _ => {
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index a07580fe72d..c7fa27da1ac 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -536,33 +536,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 for ty in [first_ty, second_ty] {
-                    for (pred, _) in self
+                    for (clause, _) in self
                         .tcx
                         .explicit_item_bounds(rpit_def_id)
                         .subst_iter_copied(self.tcx, substs)
                     {
-                        let pred = pred.kind().rebind(match pred.kind().skip_binder() {
-                            ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
+                        let pred = clause.kind().rebind(match clause.kind().skip_binder() {
+                            ty::ClauseKind::Trait(trait_pred) => {
                                 // FIXME(rpitit): This will need to be fixed when we move to associated types
                                 assert!(matches!(
                                     *trait_pred.trait_ref.self_ty().kind(),
                                     ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
                                     if def_id == rpit_def_id && substs == alias_substs
                                 ));
-                                ty::PredicateKind::Clause(ty::ClauseKind::Trait(
-                                    trait_pred.with_self_ty(self.tcx, ty),
-                                ))
+                                ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty))
                             }
-                            ty::PredicateKind::Clause(ty::ClauseKind::Projection(
-                                mut proj_pred,
-                            )) => {
+                            ty::ClauseKind::Projection(mut proj_pred) => {
                                 assert!(matches!(
                                     *proj_pred.projection_ty.self_ty().kind(),
                                     ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. })
                                     if def_id == rpit_def_id && substs == alias_substs
                                 ));
                                 proj_pred = proj_pred.with_self_ty(self.tcx, ty);
-                                ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_pred))
+                                ty::ClauseKind::Projection(proj_pred)
                             }
                             _ => continue,
                         });
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 69ccbf0b58f..0a1b639af51 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -92,10 +92,7 @@ pub(super) fn check_fn<'a, 'tcx>(
         fcx.check_pat_top(&param.pat, param_ty, ty_span, None);
 
         // Check that argument is Sized.
-        // The check for a non-trivial pattern is a hack to avoid duplicate warnings
-        // for simple cases like `fn foo(x: Trait)`,
-        // where we would error once on the parameter as a whole, and once on the binding `x`.
-        if param.pat.simple_ident().is_none() && !params_can_be_unsized {
+        if !params_can_be_unsized {
             fcx.require_type_is_sized(
                 param_ty,
                 param.pat.span,
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 94b37fb3450..c64b64e925a 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -174,7 +174,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
                 .deduce_closure_signature_from_predicates(
                     expected_ty,
-                    self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
+                    self.tcx
+                        .explicit_item_bounds(def_id)
+                        .subst_iter_copied(self.tcx, substs)
+                        .map(|(c, s)| (c.as_predicate(), s)),
                 ),
             ty::Dynamic(ref object_type, ..) => {
                 let sig = object_type.projection_bounds().find_map(|pb| {
@@ -717,13 +720,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .tcx
                 .explicit_item_bounds(def_id)
                 .subst_iter_copied(self.tcx, substs)
-                .find_map(|(p, s)| get_future_output(p, s))?,
+                .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
             ty::Error(_) => return None,
             ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
                 .tcx
                 .explicit_item_bounds(proj.def_id)
                 .subst_iter_copied(self.tcx, proj.substs)
-                .find_map(|(p, s)| get_future_output(p, s))?,
+                .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
             _ => span_bug!(
                 self.tcx.def_span(expr_def_id),
                 "async fn generator return type not an inference variable: {ret_ty}"
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index dabe7749cb6..fdbb153ec7d 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -577,7 +577,7 @@ fn check_must_not_suspend_ty<'tcx>(
             let mut has_emitted = false;
             for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() {
                 // We only look at the `DefId`, so it is safe to skip the binder here.
-                if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref poly_trait_predicate)) =
+                if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
                     predicate.kind().skip_binder()
                 {
                     let def_id = poly_trait_predicate.trait_ref.def_id;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 63370eec10b..15213c4b023 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -408,9 +408,9 @@ impl<'tcx> InferCtxt<'tcx> {
                 predicate
                     .kind()
                     .map_bound(|kind| match kind {
-                        ty::PredicateKind::Clause(ty::ClauseKind::Projection(
-                            projection_predicate,
-                        )) if projection_predicate.projection_ty.def_id == item_def_id => {
+                        ty::ClauseKind::Projection(projection_predicate)
+                            if projection_predicate.projection_ty.def_id == item_def_id =>
+                        {
                             projection_predicate.term.ty()
                         }
                         _ => None,
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 3cb1788dc19..0390c868c1b 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -649,9 +649,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 ct_op: |ct| ct,
             });
 
-            if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) =
-                predicate.kind().skip_binder()
-            {
+            if let ty::ClauseKind::Projection(projection) = predicate.kind().skip_binder() {
                 if projection.term.references_error() {
                     // No point on adding any obligations since there's a type error involved.
                     obligations.clear();
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 59ae2ce6c60..871171f9447 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -296,7 +296,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         trace!("{:#?}", bounds.skip_binder());
         bounds
             .subst_iter(tcx, alias_ty.substs)
-            .filter_map(|p| p.to_opt_type_outlives())
+            .filter_map(|p| p.as_type_outlives_clause())
             .filter_map(|p| p.no_bound_vars())
             .map(|OutlivesPredicate(_, r)| r)
     }
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 00d4934b749..26919872952 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -167,13 +167,33 @@ impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) {
     }
 }
 
+impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) {
+    fn predicate(&self) -> ty::Predicate<'tcx> {
+        self.0.as_predicate()
+    }
+
+    fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
+        (predicate.expect_clause(), self.1)
+    }
+
+    fn child_with_derived_cause(
+        &self,
+        predicate: ty::Predicate<'tcx>,
+        _span: Span,
+        _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        _index: usize,
+    ) -> Self {
+        (predicate.expect_clause(), self.1)
+    }
+}
+
 impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> {
     fn predicate(&self) -> ty::Predicate<'tcx> {
         self.as_predicate()
     }
 
     fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
-        predicate.as_clause().unwrap()
+        predicate.expect_clause()
     }
 
     fn child_with_derived_cause(
@@ -183,7 +203,7 @@ impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> {
         _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
         _index: usize,
     ) -> Self {
-        predicate.as_clause().unwrap()
+        predicate.expect_clause()
     }
 }
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 9fb83bec993..5c5ec452850 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1984,12 +1984,12 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
 
 impl ExplicitOutlivesRequirements {
     fn lifetimes_outliving_lifetime<'tcx>(
-        inferred_outlives: &'tcx [(ty::ClauseKind<'tcx>, Span)],
+        inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
         def_id: DefId,
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
             .iter()
-            .filter_map(|(clause, _)| match *clause {
+            .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
                     ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b),
                     _ => None,
@@ -2000,12 +2000,12 @@ impl ExplicitOutlivesRequirements {
     }
 
     fn lifetimes_outliving_type<'tcx>(
-        inferred_outlives: &'tcx [(ty::ClauseKind<'tcx>, Span)],
+        inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
         index: u32,
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
             .iter()
-            .filter_map(|(clause, _)| match *clause {
+            .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
                     a.is_param(index).then_some(b)
                 }
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 61c23b4c255..63a56806a45 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
             // Liberate bound regions in the predicate since we
             // don't actually care about lifetimes in this check.
             let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind());
-            let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = predicate else {
+            let ty::ClauseKind::Projection(proj) = predicate else {
                 continue;
             };
             // Only check types, since those are the only things that may
@@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
                     let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
                         (
                             ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
-                            ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)),
+                            ty::ClauseKind::Trait(trait_pred),
                         ) => Some(AddBound {
                             suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
                             trait_ref: trait_pred.print_modifiers_and_trait_path(),
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index e0033c48edb..5015b751eee 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -289,9 +289,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                         .filter_only_self()
                         .find_map(|(pred, _span)| {
                             // We only look at the `DefId`, so it is safe to skip the binder here.
-                            if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
-                                ref poly_trait_predicate,
-                            )) = pred.kind().skip_binder()
+                            if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
+                                pred.kind().skip_binder()
                             {
                                 let def_id = poly_trait_predicate.trait_ref.def_id;
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 53ece08ac3d..cbb4458d1d4 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3464,7 +3464,8 @@ declare_lint! {
     /// out an update in your own time.
     pub LONG_RUNNING_CONST_EVAL,
     Deny,
-    "detects long const eval operations"
+    "detects long const eval operations",
+    report_in_external_macro
 }
 
 declare_lint! {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 21cbab54293..90014bd9267 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -25,7 +25,7 @@ use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::GeneratorDiagnosticData;
-use rustc_middle::ty::{self, ParameterizedOverTcx, Predicate, Ty, TyCtxt, Visibility};
+use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility};
 use rustc_serialize::opaque::MemDecoder;
 use rustc_serialize::{Decodable, Decoder};
 use rustc_session::cstore::{
@@ -642,6 +642,12 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx
     }
 }
 
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
+        ty::codec::RefDecodable::decode(d)
+    }
+}
+
 impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyValue<T> {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
         decoder.read_lazy()
@@ -854,7 +860,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self,
         index: DefIndex,
         tcx: TyCtxt<'tcx>,
-    ) -> ty::EarlyBinder<&'tcx [(Predicate<'tcx>, Span)]> {
+    ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
         let lazy = self.root.tables.explicit_item_bounds.get(self, index);
         let output = if lazy.is_default() {
             &mut []
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index d11308196ea..9cffd96f4a3 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -375,8 +375,8 @@ define_tables! {
     is_type_alias_impl_trait: Table<DefIndex, bool>,
     attr_flags: Table<DefIndex, AttrFlags>,
     def_path_hashes: Table<DefIndex, DefPathHash>,
-    explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
-    inferred_outlives_of: Table<DefIndex, LazyArray<(ty::ClauseKind<'static>, Span)>>,
+    explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
+    inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
     associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
     opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 440dede1700..5d6a477b9ad 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -346,7 +346,7 @@ rustc_queries! {
     /// `key` is the `DefId` of the associated type or opaque type.
     ///
     /// Bounds from the parent (e.g. with nested impl trait) are not included.
-    query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, Span)]> {
+    query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
         desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
@@ -373,7 +373,7 @@ rustc_queries! {
     /// ```
     ///
     /// Bounds from the parent (e.g. with nested impl trait) are not included.
-    query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> {
+    query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> {
         desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
     }
 
@@ -647,7 +647,7 @@ rustc_queries! {
 
     /// Returns the inferred outlives predicates (e.g., for `struct
     /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
-    query inferred_outlives_of(key: DefId) -> &'tcx [(ty::ClauseKind<'tcx>, Span)] {
+    query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Clause<'tcx>, Span)] {
         desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 105667ba1e6..220118ae5cc 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -798,7 +798,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>
     }
 }
 
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::ClauseKind<'tcx>, Span)] {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
     #[inline]
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         RefDecodable::decode(d)
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index ff8cd904ef8..248251e1ef5 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -128,6 +128,12 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Predicate<'tcx>
     }
 }
 
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Clause<'tcx> {
+    fn encode(&self, e: &mut E) {
+        self.as_predicate().encode(e);
+    }
+}
+
 impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Region<'tcx> {
     fn encode(&self, e: &mut E) {
         self.kind().encode(e);
@@ -241,6 +247,13 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx>
     }
 }
 
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Clause<'tcx> {
+    fn decode(decoder: &mut D) -> ty::Clause<'tcx> {
+        let pred: ty::Predicate<'tcx> = Decodable::decode(decoder);
+        pred.expect_clause()
+    }
+}
+
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for SubstsRef<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let len = decoder.read_usize();
@@ -365,9 +378,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
     }
 }
 
-impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
-    for [(ty::ClauseKind<'tcx>, Span)]
-{
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] {
     fn decode(decoder: &mut D) -> &'tcx Self {
         decoder.interner().arena.alloc_from_iter(
             (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 2b4f69167bf..b2ada4882e1 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -25,10 +25,10 @@ use crate::traits::solve::{
     ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
 };
 use crate::ty::{
-    self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid,
-    GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
-    PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions,
-    TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
+    self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, FloatTy, FloatVar,
+    FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst,
+    ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind,
+    ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
 };
 use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_ast::{self as ast, attr};
@@ -141,7 +141,9 @@ pub struct CtxtInterners<'tcx> {
     region: InternedSet<'tcx, RegionKind<'tcx>>,
     poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
     predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
+    // FIXME(clause): remove this when all usages are moved to predicate
     predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
+    clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
     const_: InternedSet<'tcx, ConstData<'tcx>>,
@@ -167,6 +169,7 @@ impl<'tcx> CtxtInterners<'tcx> {
             canonical_var_infos: Default::default(),
             predicate: Default::default(),
             predicates: Default::default(),
+            clauses: Default::default(),
             projs: Default::default(),
             place_elems: Default::default(),
             const_: Default::default(),
@@ -1533,6 +1536,7 @@ slice_interners!(
     canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>),
     poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
     predicates: intern_predicates(Predicate<'tcx>),
+    clauses: intern_clauses(Clause<'tcx>),
     projs: pub mk_projs(ProjectionKind),
     place_elems: pub mk_place_elems(PlaceElem<'tcx>),
     bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
@@ -1564,7 +1568,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let future_trait = self.require_lang_item(LangItem::Future, None);
 
         self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| {
-            let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() else {
+            let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
                 return false;
             };
             trait_predicate.trait_ref.def_id == future_trait
@@ -2084,6 +2088,13 @@ impl<'tcx> TyCtxt<'tcx> {
         self.intern_predicates(preds)
     }
 
+    pub fn mk_clauses(self, preds: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> {
+        // FIXME consider asking the input slice to be sorted to avoid
+        // re-interning permutations, in which case that would be asserted
+        // here.
+        self.intern_clauses(preds)
+    }
+
     pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
@@ -2135,6 +2146,14 @@ impl<'tcx> TyCtxt<'tcx> {
         T::collect_and_apply(iter, |xs| self.mk_predicates(xs))
     }
 
+    pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: CollectAndApply<Clause<'tcx>, &'tcx List<Clause<'tcx>>>,
+    {
+        T::collect_and_apply(iter, |xs| self.mk_clauses(xs))
+    }
+
     pub fn mk_type_list_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index c5a306fdf1f..c1d6856d33c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -318,7 +318,13 @@ impl<'tcx> SizeSkeleton<'tcx> {
             Ok(layout) => {
                 return Ok(SizeSkeleton::Known(layout.size));
             }
-            Err(err) => err,
+            Err(err @ LayoutError::Unknown(_)) => err,
+            // We can't extract SizeSkeleton info from other layout errors
+            Err(
+                e @ LayoutError::Cycle
+                | e @ LayoutError::SizeOverflow(_)
+                | e @ LayoutError::NormalizationFailure(..),
+            ) => return Err(e),
         };
 
         match *ty.kind() {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index cd459130827..0e604fdf6f4 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -602,6 +602,24 @@ impl<'tcx> Clause<'tcx> {
             None
         }
     }
+
+    pub fn as_type_outlives_clause(self) -> Option<Binder<'tcx, TypeOutlivesPredicate<'tcx>>> {
+        let clause = self.kind();
+        if let ty::ClauseKind::TypeOutlives(o) = clause.skip_binder() {
+            Some(clause.rebind(o))
+        } else {
+            None
+        }
+    }
+
+    pub fn as_region_outlives_clause(self) -> Option<Binder<'tcx, RegionOutlivesPredicate<'tcx>>> {
+        let clause = self.kind();
+        if let ty::ClauseKind::RegionOutlives(o) = clause.skip_binder() {
+            Some(clause.rebind(o))
+        } else {
+            None
+        }
+    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
@@ -713,7 +731,7 @@ pub struct CratePredicatesMap<'tcx> {
     /// predicate of its outlive bounds. If an item has no outlives
     /// bounds, it will have no entry.
     // FIXME(clause): should this be a `Clause`?
-    pub predicates: FxHashMap<DefId, &'tcx [(ClauseKind<'tcx>, Span)]>,
+    pub predicates: FxHashMap<DefId, &'tcx [(Clause<'tcx>, Span)]>,
 }
 
 impl<'tcx> Predicate<'tcx> {
@@ -1243,7 +1261,21 @@ impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> {
 impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause)))
+        tcx.mk_predicate(self.map_bound(ty::PredicateKind::Clause))
+    }
+}
+
+impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> {
+    #[inline(always)]
+    fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        self.as_predicate()
+    }
+}
+
+impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ClauseKind<'tcx> {
+    #[inline(always)]
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
+        tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(self))).expect_clause()
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 97d13822adc..cc2b26a5e14 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -128,6 +128,7 @@ parameterized_over_tcx! {
     ty::TraitRef,
     ty::Const,
     ty::Predicate,
+    ty::Clause,
     ty::ClauseKind,
     ty::GeneratorDiagnosticData,
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index fdcc608bf8e..7afda73862d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -928,7 +928,7 @@ pub trait PrettyPrinter<'tcx>:
             let bound_predicate = predicate.kind();
 
             match bound_predicate.skip_binder() {
-                ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
+                ty::ClauseKind::Trait(pred) => {
                     let trait_ref = bound_predicate.rebind(pred.trait_ref);
 
                     // Don't print + Sized, but rather + ?Sized if absent.
@@ -939,7 +939,7 @@ pub trait PrettyPrinter<'tcx>:
 
                     self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits);
                 }
-                ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
+                ty::ClauseKind::Projection(pred) => {
                     let proj_ref = bound_predicate.rebind(pred);
                     let trait_ref = proj_ref.required_poly_trait_ref(tcx);
 
@@ -953,7 +953,7 @@ pub trait PrettyPrinter<'tcx>:
                         &mut fn_traits,
                     );
                 }
-                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
+                ty::ClauseKind::TypeOutlives(outlives) => {
                     lifetimes.push(outlives.1);
                 }
                 _ => {}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index e53e1e0a54c..959bf032a83 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -666,10 +666,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clause<'tcx> {
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        Ok(folder
-            .try_fold_predicate(self.as_predicate())?
-            .as_clause()
-            .expect("no sensible folder would do this"))
+        Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause())
     }
 }
 
@@ -713,6 +710,15 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Predicate<'tcx>> {
     }
 }
 
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Clause<'tcx>> {
+    fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
+        self,
+        folder: &mut F,
+    ) -> Result<Self, F::Error> {
+        ty::util::fold_list(self, folder, |tcx, v| tcx.mk_clauses(v))
+    }
+}
+
 impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
         self,
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 9f58cce2769..029fb2e9ba0 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1824,7 +1824,7 @@ fn check_must_not_suspend_ty<'tcx>(
             let mut has_emitted = false;
             for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() {
                 // We only look at the `DefId`, so it is safe to skip the binder here.
-                if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref poly_trait_predicate)) =
+                if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
                     predicate.kind().skip_binder()
                 {
                     let def_id = poly_trait_predicate.trait_ref.def_id;
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index b897a6198e3..8a848e5db62 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -114,6 +114,12 @@ trait DefIdVisitor<'tcx> {
     ) -> ControlFlow<Self::BreakTy> {
         self.skeleton().visit_predicates(predicates)
     }
+    fn visit_clauses(
+        &mut self,
+        predicates: &[(ty::Clause<'tcx>, Span)],
+    ) -> ControlFlow<Self::BreakTy> {
+        self.skeleton().visit_clauses(predicates)
+    }
 }
 
 struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
@@ -159,42 +165,23 @@ where
         }
     }
 
-    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
-        match predicate.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
-                trait_ref,
-                constness: _,
-                polarity: _,
-            })) => self.visit_trait(trait_ref),
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
-                projection_ty,
-                term,
-            })) => {
+    fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> ControlFlow<V::BreakTy> {
+        match clause.kind().skip_binder() {
+            ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => {
+                self.visit_trait(trait_ref)
+            }
+            ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
                 term.visit_with(self)?;
                 self.visit_projection_ty(projection_ty)
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
-                ty,
-                _region,
-            ))) => ty.visit_with(self),
-            ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => {
-                ControlFlow::Continue(())
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
+            ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => ty.visit_with(self),
+            ty::ClauseKind::RegionOutlives(..) => ControlFlow::Continue(()),
+            ty::ClauseKind::ConstArgHasType(ct, ty) => {
                 ct.visit_with(self)?;
                 ty.visit_with(self)
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => ct.visit_with(self),
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => arg.visit_with(self),
-
-            ty::PredicateKind::ObjectSafe(_)
-            | ty::PredicateKind::ClosureKind(_, _, _)
-            | ty::PredicateKind::Subtype(_)
-            | ty::PredicateKind::Coerce(_)
-            | ty::PredicateKind::ConstEquate(_, _)
-            | ty::PredicateKind::TypeWellFormedFromEnv(_)
-            | ty::PredicateKind::Ambiguous
-            | ty::PredicateKind::AliasRelate(..) => bug!("unexpected predicate: {:?}", predicate),
+            ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self),
+            ty::ClauseKind::WellFormed(arg) => arg.visit_with(self),
         }
     }
 
@@ -203,7 +190,16 @@ where
         predicates: ty::GenericPredicates<'tcx>,
     ) -> ControlFlow<V::BreakTy> {
         let ty::GenericPredicates { parent: _, predicates } = predicates;
-        predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate))
+        predicates.iter().try_for_each(|&(predicate, _span)| {
+            let clause = predicate
+                .as_clause()
+                .unwrap_or_else(|| bug!("unexpected predicate: {:?}", predicate));
+            self.visit_clause(clause)
+        })
+    }
+
+    fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> ControlFlow<V::BreakTy> {
+        clauses.iter().try_for_each(|&(clause, _span)| self.visit_clause(clause))
     }
 }
 
@@ -307,10 +303,7 @@ where
                     // through the trait list (default type visitor doesn't visit those traits).
                     // All traits in the list are considered the "primary" part of the type
                     // and are visited by shallow visitors.
-                    self.visit_predicates(ty::GenericPredicates {
-                        parent: None,
-                        predicates: tcx.explicit_item_bounds(def_id).skip_binder(),
-                    })?;
+                    self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder())?;
                 }
             }
             // These types don't have their own def-ids (but may have subcomponents
@@ -1814,10 +1807,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
 
     fn bounds(&mut self) -> &mut Self {
         self.in_primary_interface = false;
-        self.visit_predicates(ty::GenericPredicates {
-            parent: None,
-            predicates: self.tcx.explicit_item_bounds(self.item_def_id).skip_binder(),
-        });
+        self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
         self
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index f2a39faf383..cde8a52cdec 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -522,13 +522,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
         for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs)
         {
-            if let Some(clause) = assumption.as_clause() {
-                match G::consider_alias_bound_candidate(self, goal, clause) {
-                    Ok(result) => {
-                        candidates.push(Candidate { source: CandidateSource::AliasBound, result })
-                    }
-                    Err(NoSolution) => (),
+            match G::consider_alias_bound_candidate(self, goal, assumption) {
+                Ok(result) => {
+                    candidates.push(Candidate { source: CandidateSource::AliasBound, result })
                 }
+                Err(NoSolution) => (),
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 97b86a06c8c..439cf788ab4 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -353,7 +353,11 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
         // FIXME(associated_const_equality): Also add associated consts to
         // the requirements here.
         if item.kind == ty::AssocKind::Type {
-            requirements.extend(tcx.item_bounds(item.def_id).subst(tcx, trait_ref.substs));
+            requirements.extend(
+                tcx.item_bounds(item.def_id)
+                    .subst_iter(tcx, trait_ref.substs)
+                    .map(|clause| clause.as_predicate()),
+            );
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index dba6ffc4c96..71d2380f234 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1157,7 +1157,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
                 ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                     self.tcx.item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
-                        if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = pred.kind().skip_binder()
+                        if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
                         && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
                         // args tuple will always be substs[1]
                         && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 499745473a2..df93c4d45dc 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -271,7 +271,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Type)
         .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied())
-        .filter_map(|pred_span| predicate_references_self(tcx, pred_span))
+        .filter_map(|(clause, span)| predicate_references_self(tcx, (clause.as_predicate(), span)))
         .collect()
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 81b1ecc0d88..2a78c5befa4 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1585,7 +1585,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
         obligation,
         candidate_set,
         ProjectionCandidate::TraitDef,
-        bounds.iter(),
+        bounds.iter().map(|clause| clause.as_predicate()),
         true,
     );
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 3c356978d5c..a50af417a44 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -170,7 +170,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let candidate_predicate = tcx.item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
         let candidate = candidate_predicate
-            .to_opt_poly_trait_pred()
+            .as_trait_clause()
             .expect("projection candidate is not a trait predicate")
             .map_bound(|t| t.trait_ref);
         let mut obligations = Vec::new();
@@ -631,7 +631,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         let assoc_ty_substs = tcx.mk_substs(&substs);
                         let bound =
                             bound.map_bound(|b| b.kind().skip_binder()).subst(tcx, assoc_ty_substs);
-                        tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars))
+                        ty::Binder::bind_with_vars(bound, bound_vars).to_predicate(tcx)
                     };
                 let normalized_bound = normalize_with_depth_to(
                     self,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0f0e3f1f16a..0a8b7b688e7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1668,9 +1668,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .enumerate()
             .filter_map(|(idx, bound)| {
                 let bound_predicate = bound.kind();
-                if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
-                    bound_predicate.skip_binder()
-                {
+                if let ty::ClauseKind::Trait(pred) = bound_predicate.skip_binder() {
                     let bound = bound_predicate.rebind(pred.trait_ref);
                     if self.infcx.probe(|_| {
                         match self.match_normalize_trait_ref(
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 38f94c38861..7e64cbdf54a 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -54,7 +54,9 @@ impl<'tcx> RustIrDatabase<'tcx> {
             .tcx
             .explicit_item_bounds(def_id)
             .subst_iter_copied(self.interner.tcx, &bound_vars)
-            .filter_map(|(bound, _)| LowerInto::<Option<_>>::lower_into(bound, self.interner))
+            .filter_map(|(bound, _)| {
+                LowerInto::<Option<_>>::lower_into(bound.as_predicate(), self.interner)
+            })
             .collect()
     }
 }
@@ -520,7 +522,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                 .filter_map(|bound| {
                     LowerInto::<
                     Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
-                >::lower_into(bound, self.interner)
+                >::lower_into(bound.as_predicate(), self.interner)
                 })
                 .collect();
 
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index f48bba24132..c8c2c8286b0 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -145,17 +145,35 @@ fn layout_of_uncached<'tcx>(
                 return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
             }
 
-            let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
-
             let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
                 // Projection eagerly bails out when the pointee references errors,
                 // fall back to structurally deducing metadata.
                 && !pointee.references_error()
             {
-                let metadata_ty = tcx.normalize_erasing_regions(
+                let pointee_metadata = tcx.mk_projection(metadata_def_id, [pointee]);
+                let metadata_ty = match tcx.try_normalize_erasing_regions(
                     param_env,
-                    tcx.mk_projection(metadata_def_id, [pointee]),
-                );
+                    pointee_metadata,
+                ) {
+                    Ok(metadata_ty) => metadata_ty,
+                    Err(mut err) => {
+                        // Usually `<Ty as Pointee>::Metadata` can't be normalized because
+                        // its struct tail cannot be normalized either, so try to get a
+                        // more descriptive layout error here, which will lead to less confusing
+                        // diagnostics.
+                        match tcx.try_normalize_erasing_regions(
+                            param_env,
+                            tcx.struct_tail_without_normalization(pointee),
+                        ) {
+                            Ok(_) => {},
+                            Err(better_err) => {
+                                err = better_err;
+                            }
+                        }
+                        return Err(LayoutError::NormalizationFailure(pointee, err));
+                    },
+                };
+
                 let metadata_layout = cx.layout_of(metadata_ty)?;
                 // If the metadata is a 1-zst, then the pointer is thin.
                 if metadata_layout.is_zst() && metadata_layout.align.abi.bytes() == 1 {
@@ -163,10 +181,13 @@ fn layout_of_uncached<'tcx>(
                 }
 
                 let Abi::Scalar(metadata) = metadata_layout.abi else {
-                    return Err(LayoutError::Unknown(unsized_part));
+                    return Err(LayoutError::Unknown(pointee));
                 };
+
                 metadata
             } else {
+                let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
+
                 match unsized_part.kind() {
                     ty::Foreign(..) => {
                         return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
@@ -178,7 +199,7 @@ fn layout_of_uncached<'tcx>(
                         vtable
                     }
                     _ => {
-                        return Err(LayoutError::Unknown(unsized_part));
+                        return Err(LayoutError::Unknown(pointee));
                     }
                 }
             };
diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs
index 06f479808b9..cb40521dda7 100644
--- a/src/bootstrap/download.rs
+++ b/src/bootstrap/download.rs
@@ -54,9 +54,9 @@ impl Config {
     /// Runs a command, printing out nice contextual information if it fails.
     /// Exits if the command failed to execute at all, otherwise returns its
     /// `status.success()`.
-    pub(crate) fn try_run(&self, cmd: &mut Command) -> bool {
+    pub(crate) fn try_run(&self, cmd: &mut Command) -> Result<(), ()> {
         if self.dry_run() {
-            return true;
+            return Ok(());
         }
         self.verbose(&format!("running: {:?}", cmd));
         try_run(cmd, self.is_verbose())
@@ -156,12 +156,14 @@ impl Config {
                 ];
             }
             ";
-            nix_build_succeeded = self.try_run(Command::new("nix-build").args(&[
-                Path::new("-E"),
-                Path::new(NIX_EXPR),
-                Path::new("-o"),
-                &nix_deps_dir,
-            ]));
+            nix_build_succeeded = self
+                .try_run(Command::new("nix-build").args(&[
+                    Path::new("-E"),
+                    Path::new(NIX_EXPR),
+                    Path::new("-o"),
+                    &nix_deps_dir,
+                ]))
+                .is_ok();
             nix_deps_dir
         });
         if !nix_build_succeeded {
@@ -186,7 +188,7 @@ impl Config {
             patchelf.args(&["--set-interpreter", dynamic_linker.trim_end()]);
         }
 
-        self.try_run(patchelf.arg(fname));
+        self.try_run(patchelf.arg(fname)).unwrap();
     }
 
     fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) {
@@ -237,7 +239,7 @@ impl Config {
                             "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
                             url, tempfile.to_str().expect("invalid UTF-8 not supported with powershell downloads"),
                         ),
-                    ])) {
+                    ])).is_err() {
                         return;
                     }
                     eprintln!("\nspurious failure, trying again");
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index d7e77aeb338..d389b568f56 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -333,7 +333,7 @@ forward! {
     create(path: &Path, s: &str),
     remove(f: &Path),
     tempdir() -> PathBuf,
-    try_run(cmd: &mut Command) -> bool,
+    try_run(cmd: &mut Command) -> Result<(), ()>,
     llvm_link_shared() -> bool,
     download_rustc() -> bool,
     initial_rustfmt() -> Option<PathBuf>,
@@ -614,11 +614,13 @@ impl Build {
         }
 
         // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error).
-        let has_local_modifications = !self.try_run(
-            Command::new("git")
-                .args(&["diff-index", "--quiet", "HEAD"])
-                .current_dir(&absolute_path),
-        );
+        let has_local_modifications = self
+            .try_run(
+                Command::new("git")
+                    .args(&["diff-index", "--quiet", "HEAD"])
+                    .current_dir(&absolute_path),
+            )
+            .is_err();
         if has_local_modifications {
             self.run(Command::new("git").args(&["stash", "push"]).current_dir(&absolute_path));
         }
diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs
index ec01f744b82..c97b7592737 100644
--- a/src/bootstrap/run.rs
+++ b/src/bootstrap/run.rs
@@ -27,7 +27,8 @@ impl Step for ExpandYamlAnchors {
         try_run(
             builder,
             &mut builder.tool_cmd(Tool::ExpandYamlAnchors).arg("generate").arg(&builder.src),
-        );
+        )
+        .unwrap();
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -39,17 +40,17 @@ impl Step for ExpandYamlAnchors {
     }
 }
 
-fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool {
+fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> Result<(), ()> {
     if !builder.fail_fast {
-        if !builder.try_run(cmd) {
+        if let Err(e) = builder.try_run(cmd) {
             let mut failures = builder.delayed_failures.borrow_mut();
             failures.push(format!("{:?}", cmd));
-            return false;
+            return Err(e);
         }
     } else {
         builder.run(cmd);
     }
-    true
+    Ok(())
 }
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 9212362f6c9..873ed61daf3 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -48,17 +48,17 @@ const MIR_OPT_BLESS_TARGET_MAPPING: &[(&str, &str)] = &[
     // build for, so there is no entry for "aarch64-apple-darwin" here.
 ];
 
-fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool {
+fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> Result<(), ()> {
     if !builder.fail_fast {
-        if !builder.try_run(cmd) {
+        if let Err(e) = builder.try_run(cmd) {
             let mut failures = builder.delayed_failures.borrow_mut();
             failures.push(format!("{:?}", cmd));
-            return false;
+            return Err(e);
         }
     } else {
         builder.run(cmd);
     }
-    true
+    Ok(())
 }
 
 fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool {
@@ -187,7 +187,8 @@ You can skip linkcheck with --exclude src/tools/linkchecker"
         try_run(
             builder,
             builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host.triple).join("doc")),
-        );
+        )
+        .unwrap();
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -240,7 +241,8 @@ impl Step for HtmlCheck {
         builder.default_doc(&[]);
         builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder));
 
-        try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)));
+        try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)))
+            .unwrap();
     }
 }
 
@@ -286,7 +288,8 @@ impl Step for Cargotest {
                 .args(builder.config.test_args())
                 .env("RUSTC", builder.rustc(compiler))
                 .env("RUSTDOC", builder.rustdoc(compiler)),
-        );
+        )
+        .unwrap();
     }
 }
 
@@ -785,7 +788,7 @@ impl Step for Clippy {
         cargo.add_rustc_lib_path(builder, compiler);
         let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
 
-        if builder.try_run(&mut cargo) {
+        if builder.try_run(&mut cargo).is_ok() {
             // The tests succeeded; nothing to do.
             return;
         }
@@ -858,7 +861,7 @@ impl Step for RustdocTheme {
                 util::lld_flag_no_threads(self.compiler.host.contains("windows")),
             );
         }
-        try_run(builder, &mut cmd);
+        try_run(builder, &mut cmd).unwrap();
     }
 }
 
@@ -1109,7 +1112,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy`
         }
 
         builder.info("tidy check");
-        try_run(builder, &mut cmd);
+        try_run(builder, &mut cmd).unwrap();
 
         builder.ensure(ExpandYamlAnchors);
 
@@ -1157,7 +1160,8 @@ impl Step for ExpandYamlAnchors {
         try_run(
             builder,
             &mut builder.tool_cmd(Tool::ExpandYamlAnchors).arg("check").arg(&builder.src),
-        );
+        )
+        .unwrap();
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -1936,7 +1940,7 @@ impl BookTest {
             compiler.host,
         );
         let _time = util::timeit(&builder);
-        let toolstate = if try_run(builder, &mut rustbook_cmd) {
+        let toolstate = if try_run(builder, &mut rustbook_cmd).is_ok() {
             ToolState::TestPass
         } else {
             ToolState::TestFail
@@ -2094,7 +2098,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
     cmd.arg("--test-args").arg(test_args);
 
     if builder.config.verbose_tests {
-        try_run(builder, &mut cmd)
+        try_run(builder, &mut cmd).is_ok()
     } else {
         try_run_quiet(builder, &mut cmd)
     }
@@ -2122,7 +2126,7 @@ impl Step for RustcGuide {
 
         let src = builder.src.join(relative_path);
         let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
-        let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)) {
+        let toolstate = if try_run(builder, rustbook_cmd.arg("linkcheck").arg(&src)).is_ok() {
             ToolState::TestPass
         } else {
             ToolState::TestFail
@@ -2661,7 +2665,7 @@ impl Step for Bootstrap {
     fn run(self, builder: &Builder<'_>) {
         let mut check_bootstrap = Command::new(&builder.python());
         check_bootstrap.arg("bootstrap_test.py").current_dir(builder.src.join("src/bootstrap/"));
-        try_run(builder, &mut check_bootstrap);
+        try_run(builder, &mut check_bootstrap).unwrap();
 
         let host = builder.config.build;
         let compiler = builder.compiler(0, host);
@@ -2733,7 +2737,7 @@ impl Step for TierCheck {
         }
 
         builder.info("platform support check");
-        try_run(builder, &mut cargo.into());
+        try_run(builder, &mut cargo.into()).unwrap();
     }
 }
 
@@ -2813,7 +2817,7 @@ impl Step for RustInstaller {
         cmd.env("CARGO", &builder.initial_cargo);
         cmd.env("RUSTC", &builder.initial_rustc);
         cmd.env("TMP_DIR", &tmpdir);
-        try_run(builder, &mut cmd);
+        try_run(builder, &mut cmd).unwrap();
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 96341b69df0..126f0b1eb31 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -107,7 +107,7 @@ impl Step for ToolBuild {
         );
 
         let mut cargo = Command::from(cargo);
-        let is_expected = builder.try_run(&mut cargo);
+        let is_expected = builder.try_run(&mut cargo).is_ok();
 
         builder.save_toolstate(
             tool,
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 1ec49f80d63..b291584b300 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -228,7 +228,7 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
 }
 
 pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) {
-    if !try_run(cmd, print_cmd_on_fail) {
+    if try_run(cmd, print_cmd_on_fail).is_err() {
         crate::detail_exit_macro!(1);
     }
 }
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index eade9e04559..5ab1874e9ed 100755
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -110,6 +110,9 @@ There are a number of supported commands:
 
 * `@has-dir PATH` checks for the existence of the given directory.
 
+* `@files FOLDER_PATH [ENTRIES]`, checks that `FOLDER_PATH` contains exactly
+  `[ENTRIES]`.
+
 All conditions can be negated with `!`. `@!has foo/type.NoSuch.html`
 checks if the given file does not exist, for example.
 
@@ -321,12 +324,15 @@ class CachedFiles(object):
         else:
             return self.last_path
 
+    def get_absolute_path(self, path):
+        return os.path.join(self.root, path)
+
     def get_file(self, path):
         path = self.resolve_path(path)
         if path in self.files:
             return self.files[path]
 
-        abspath = os.path.join(self.root, path)
+        abspath = self.get_absolute_path(path)
         if not(os.path.exists(abspath) and os.path.isfile(abspath)):
             raise FailedCheck('File does not exist {!r}'.format(path))
 
@@ -340,7 +346,7 @@ class CachedFiles(object):
         if path in self.trees:
             return self.trees[path]
 
-        abspath = os.path.join(self.root, path)
+        abspath = self.get_absolute_path(path)
         if not(os.path.exists(abspath) and os.path.isfile(abspath)):
             raise FailedCheck('File does not exist {!r}'.format(path))
 
@@ -356,7 +362,7 @@ class CachedFiles(object):
 
     def get_dir(self, path):
         path = self.resolve_path(path)
-        abspath = os.path.join(self.root, path)
+        abspath = self.get_absolute_path(path)
         if not(os.path.exists(abspath) and os.path.isdir(abspath)):
             raise FailedCheck('Directory does not exist {!r}'.format(path))
 
@@ -538,6 +544,41 @@ def get_nb_matching_elements(cache, c, regexp, stop_at_first):
         return check_tree_text(cache.get_tree(c.args[0]), pat, c.args[2], regexp, stop_at_first)
 
 
+def check_files_in_folder(c, cache, folder, files):
+    files = files.strip()
+    if not files.startswith('[') or not files.endswith(']'):
+        raise InvalidCheck("Expected list as second argument of @{} (ie '[]')".format(c.cmd))
+
+    folder = cache.get_absolute_path(folder)
+
+    # First we create a set of files to check if there are duplicates.
+    files = shlex.split(files[1:-1].replace(",", ""))
+    files_set = set()
+    for file in files:
+        if file in files_set:
+            raise InvalidCheck("Duplicated file `{}` in @{}".format(file, c.cmd))
+        files_set.add(file)
+    folder_set = set([f for f in os.listdir(folder) if f != "." and f != ".."])
+
+    # Then we remove entries from both sets (we clone `folder_set` so we can iterate it while
+    # removing its elements).
+    for entry in set(folder_set):
+        if entry in files_set:
+            files_set.remove(entry)
+            folder_set.remove(entry)
+
+    error = 0
+    if len(files_set) != 0:
+        print_err(c.lineno, c.context, "Entries not found in folder `{}`: `{}`".format(
+            folder, files_set))
+        error += 1
+    if len(folder_set) != 0:
+        print_err(c.lineno, c.context, "Extra entries in folder `{}`: `{}`".format(
+            folder, folder_set))
+        error += 1
+    return error == 0
+
+
 ERR_COUNT = 0
 
 
@@ -566,6 +607,13 @@ def check_command(c, cache):
             else:
                 raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
 
+        elif c.cmd == 'files': # check files in given folder
+            if len(c.args) != 2: # @files <folder path> <file list>
+                raise InvalidCheck("Invalid number of @{} arguments".format(c.cmd))
+            elif c.negated:
+                raise InvalidCheck("@{} doesn't support negative check".format(c.cmd))
+            ret = check_files_in_folder(c, cache, c.args[0], c.args[1])
+
         elif c.cmd == 'count':  # count test
             if len(c.args) == 3:  # @count <path> <pat> <count> = count test
                 expected = int(c.args[2])
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9a815694e1b..f86c32158e0 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1361,8 +1361,10 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
             }
 
             if let ty::TraitContainer = assoc_item.container {
-                let bounds =
-                    tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied();
+                let bounds = tcx
+                    .explicit_item_bounds(assoc_item.def_id)
+                    .subst_identity_iter_copied()
+                    .map(|(c, s)| (c.as_predicate(), s));
                 let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
                 let predicates =
                     tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
@@ -2117,7 +2119,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
 
 fn clean_middle_opaque_bounds<'tcx>(
     cx: &mut DocContext<'tcx>,
-    bounds: Vec<ty::Predicate<'tcx>>,
+    bounds: Vec<ty::Clause<'tcx>>,
 ) -> Type {
     let mut regions = vec![];
     let mut has_sized = false;
@@ -2126,13 +2128,8 @@ fn clean_middle_opaque_bounds<'tcx>(
         .filter_map(|bound| {
             let bound_predicate = bound.kind();
             let trait_ref = match bound_predicate.skip_binder() {
-                ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => {
-                    bound_predicate.rebind(tr.trait_ref)
-                }
-                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
-                    _ty,
-                    reg,
-                ))) => {
+                ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
+                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
                     if let Some(r) = clean_middle_region(reg) {
                         regions.push(GenericBound::Outlives(r));
                     }
@@ -2149,9 +2146,7 @@ fn clean_middle_opaque_bounds<'tcx>(
             let bindings: ThinVec<_> = bounds
                 .iter()
                 .filter_map(|bound| {
-                    if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
-                        bound.kind().skip_binder()
-                    {
+                    if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() {
                         if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
                             Some(TypeBinding {
                                 assoc: projection_to_path_segment(
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 294de12cea8..f375f0efbd1 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -21,6 +21,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::fmt::Write as _;
 use std::mem;
+use std::sync::LazyLock as Lazy;
 use thin_vec::{thin_vec, ThinVec};
 
 #[cfg(test)]
@@ -582,6 +583,8 @@ pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool {
 ///
 /// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
 pub(crate) const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
+pub(crate) static DOC_CHANNEL: Lazy<&'static str> =
+    Lazy::new(|| DOC_RUST_LANG_ORG_CHANNEL.rsplit("/").filter(|c| !c.is_empty()).next().unwrap());
 
 /// Render a sequence of macro arms in a format suitable for displaying to the user
 /// as part of an item declaration.
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 6ab849c92a0..8c5871d9126 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -55,6 +55,7 @@ struct PageLayout<'a> {
     sidebar: String,
     content: String,
     krate_with_trailing_slash: String,
+    rust_channel: &'static str,
     pub(crate) rustdoc_version: &'a str,
 }
 
@@ -82,6 +83,7 @@ pub(crate) fn render<T: Print, S: Print>(
         sidebar,
         content,
         krate_with_trailing_slash,
+        rust_channel: *crate::clean::utils::DOC_CHANNEL,
         rustdoc_version,
     }
     .render()
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index f5296abaee6..254b0d8bf5a 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1050,9 +1050,10 @@ function preLoadCss(cssUrl) {
 
     function buildHelpMenu() {
         const book_info = document.createElement("span");
+        const channel = getVar("channel");
         book_info.className = "top";
-        book_info.innerHTML = "You can find more information in \
-            <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
+        book_info.innerHTML = `You can find more information in \
+<a href="https://doc.rust-lang.org/${channel}/rustdoc/">the rustdoc book</a>.`;
 
         const shortcuts = [
             ["?", "Show this help dialog"],
@@ -1072,6 +1073,9 @@ function preLoadCss(cssUrl) {
         div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";
 
         const infos = [
+            `For a full list of all search features, take a look <a \
+href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
+#the-search-interface">here</a>.`,
             "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
              restrict the search to a given item kind.",
             "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 9133f899af6..759c4fd6012 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -31,6 +31,7 @@
          data-themes="{{themes|join(",") }}" {#+ #}
          data-resource-suffix="{{page.resource_suffix}}" {#+ #}
          data-rustdoc-version="{{rustdoc_version}}" {#+ #}
+         data-channel="{{rust_channel}}" {#+ #}
          data-search-js="{{files.search_js}}" {#+ #}
          data-settings-js="{{files.settings_js}}" {#+ #}
          data-settings-css="{{files.settings_css}}" {#+ #}
diff --git a/src/tools/build_helper/src/util.rs b/src/tools/build_helper/src/util.rs
index 731095023a9..11b8a228b8a 100644
--- a/src/tools/build_helper/src/util.rs
+++ b/src/tools/build_helper/src/util.rs
@@ -25,17 +25,21 @@ pub fn fail(s: &str) -> ! {
     detail_exit(1, cfg!(test));
 }
 
-pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
+pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> {
     let status = match cmd.status() {
         Ok(status) => status,
         Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
     };
-    if !status.success() && print_cmd_on_fail {
-        println!(
-            "\n\ncommand did not execute successfully: {:?}\n\
-             expected success, got: {}\n\n",
-            cmd, status
-        );
+    if !status.success() {
+        if print_cmd_on_fail {
+            println!(
+                "\n\ncommand did not execute successfully: {:?}\n\
+                 expected success, got: {}\n\n",
+                cmd, status
+            );
+        }
+        Err(())
+    } else {
+        Ok(())
     }
-    status.success()
 }
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index a391b76910a..818ebd1134d 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
             let preds = cx.tcx.explicit_item_bounds(def_id);
             let mut is_future = false;
             for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) {
-                if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
+                if let Some(trait_pred) = p.as_trait_clause() {
                     if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
                         is_future = true;
                         break;
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 12f18614d71..2b185943c59 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -94,7 +94,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                             // and check substitutions to find `U`.
-                            ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
+                            ty::ClauseKind::Trait(trait_predicate) => {
                                 if trait_predicate
                                     .trait_ref
                                     .substs
@@ -107,7 +107,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                             },
                             // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
                             // so we check the term for `U`.
-                            ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection_predicate)) => {
+                            ty::ClauseKind::Projection(projection_predicate) => {
                                 if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
                                     if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) {
                                         return true;
@@ -268,7 +268,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
         ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() {
-                if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() {
+                if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
                     if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
                         return true;
                     }
@@ -665,7 +665,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
         ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds(
             cx,
             ty,
-            cx.tcx.item_bounds(def_id).subst(cx.tcx, substs),
+            cx.tcx.item_bounds(def_id).subst_iter(cx.tcx, substs).map(|c| c.as_predicate()),
             cx.tcx.opt_parent(def_id),
         ),
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
@@ -698,7 +698,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
 fn sig_from_bounds<'tcx>(
     cx: &LateContext<'tcx>,
     ty: Ty<'tcx>,
-    predicates: &'tcx [Predicate<'tcx>],
+    predicates: impl IntoIterator<Item = Predicate<'tcx>>,
     predicates_id: Option<DefId>,
 ) -> Option<ExprFnSig<'tcx>> {
     let mut inputs = None;
@@ -747,7 +747,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
         .subst_iter_copied(cx.tcx, ty.substs)
     {
         match pred.kind().skip_binder() {
-            PredicateKind::Clause(ty::ClauseKind::Trait(p))
+            ty::ClauseKind::Trait(p)
                 if (lang_items.fn_trait() == Some(p.def_id())
                     || lang_items.fn_mut_trait() == Some(p.def_id())
                     || lang_items.fn_once_trait() == Some(p.def_id())) =>
@@ -760,7 +760,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
                 }
                 inputs = Some(i);
             },
-            PredicateKind::Clause(ty::ClauseKind::Projection(p))
+            ty::ClauseKind::Projection(p)
                 if Some(p.projection_ty.def_id) == lang_items.fn_once_output() =>
             {
                 if output.is_some() {
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
index dc902f8cb02..0ddd2c66cf9 100644
--- a/src/tools/rustdoc-gui-test/src/main.rs
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -67,7 +67,7 @@ fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
     None
 }
 
-fn main() {
+fn main() -> Result<(), ()> {
     let config = Arc::new(Config::from_args(env::args().collect()));
 
     // The goal here is to check if the necessary packages are installed, and if not, we
@@ -128,7 +128,10 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse
                 }
             }
 
-            try_run(&mut cargo, config.verbose);
+            if try_run(&mut cargo, config.verbose).is_err() {
+                eprintln!("failed to document `{}`", entry.path().display());
+                panic!("Cannot run rustdoc-gui tests");
+            }
         }
     }
 
@@ -158,5 +161,5 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse
 
     command.args(&config.test_args);
 
-    try_run(&mut command, config.verbose);
+    try_run(&mut command, config.verbose)
 }
diff --git a/tests/codegen/naked-nocoverage.rs b/tests/codegen/naked-nocoverage.rs
index 91a6260bf2a..3c755e49c6d 100644
--- a/tests/codegen/naked-nocoverage.rs
+++ b/tests/codegen/naked-nocoverage.rs
@@ -11,7 +11,7 @@ use std::arch::asm;
 #[naked]
 #[no_mangle]
 pub unsafe extern "C" fn f() {
-    // CHECK:       define void @f()
+    // CHECK:       define {{(dso_local )?}}void @f()
     // CHECK-NEXT:  start:
     // CHECK-NEXT:    call void asm
     // CHECK-NEXT:    unreachable
diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml
index 1a1c1b28f61..6e880302f28 100644
--- a/tests/rustdoc-gui/help-page.goml
+++ b/tests/rustdoc-gui/help-page.goml
@@ -67,5 +67,5 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px.
 assert-false: "#help"
 click: "#help-button > a"
-click: ".popover a[href='https://doc.rust-lang.org/rustdoc/']"
-wait-for-document-property: {"URL": "https://doc.rust-lang.org/rustdoc/"}
+click: "//*[@id='help']//a[text()='the rustdoc book']"
+wait-for-document-property: ({"URL": "https://doc.rust-lang.org/"}, STARTS_WITH)
diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml
index 193a3eb3fd1..e3c628b366f 100644
--- a/tests/rustdoc-gui/search-result-color.goml
+++ b/tests/rustdoc-gui/search-result-color.goml
@@ -31,7 +31,7 @@ define-function: (
         // color of the typename (struct, module, method, ...) before search results
         assert-css: (
             ".result-name .typename",
-            {"color": "#888"},
+            {"color": |grey|},
             ALL,
         )
     },
@@ -75,6 +75,7 @@ store-value: (entry_color, "#0096cf") // color of the search entry
 store-value: (hover_entry_color, "#fff") // color of the hovered/focused search entry
 store-value: (background_color, "transparent") // background color
 store-value: (hover_background_color, "#3c3c3c") // hover background color
+store-value: (grey, "#999")
 
 call-function: (
     "check-result-color", (
@@ -186,6 +187,7 @@ store-value: (entry_color, "#ddd") // color of the search entry
 store-value: (hover_entry_color, "#ddd") // color of the hovered/focused search entry
 store-value: (background_color, "transparent") // background color
 store-value: (hover_background_color, "#616161") // hover background color
+store-value: (grey, "#ccc")
 
 call-function: (
     "check-result-color", (
@@ -282,6 +284,7 @@ store-value: (entry_color, "#000") // color of the search entry
 store-value: (hover_entry_color, "#000") // color of the hovered/focused search entry
 store-value: (background_color, "transparent") // background color
 store-value: (hover_background_color, "#ccc") // hover background color
+store-value: (grey, "#999")
 
 call-function: (
     "check-result-color", (
diff --git a/tests/rustdoc/files-creation-hidden.rs b/tests/rustdoc/files-creation-hidden.rs
index bcabbfc91e8..498d9cdaef1 100644
--- a/tests/rustdoc/files-creation-hidden.rs
+++ b/tests/rustdoc/files-creation-hidden.rs
@@ -1,5 +1,6 @@
 #![crate_name="foo"]
 
+// @files foo '["index.html", "all.html", "sidebar-items.js"]'
 // @!has "foo/struct.Foo.html"
 #[doc(hidden)]
 pub struct Foo;
diff --git a/tests/rustdoc/files-creation-private.rs b/tests/rustdoc/files-creation-private.rs
index ca2327e0f91..e2fdbc068f8 100644
--- a/tests/rustdoc/files-creation-private.rs
+++ b/tests/rustdoc/files-creation-private.rs
@@ -1,5 +1,9 @@
 #![crate_name="foo"]
 
+// @files "foo" \
+// '["index.html", "all.html", "sidebar-items.js", "foo", "bar", "private", "struct.Bar.html"]'
+// @files "foo/bar" '["index.html", "sidebar-items.js"]'
+
 // @!has "foo/priv/index.html"
 // @!has "foo/priv/struct.Foo.html"
 mod private {
diff --git a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs b/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs
index d6832bb7a09..65c26d6a837 100644
--- a/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs
+++ b/tests/rustdoc/issue-111064-reexport-trait-from-hidden-2.rs
@@ -2,6 +2,12 @@
 #![no_core]
 #![crate_name = "foo"]
 
+// @files "foo" "['sidebar-items.js', 'all.html', 'hidden', 'index.html', 'struct.Bar.html', \
+//        'visible']"
+// @files "foo/hidden" "['inner']"
+// @files "foo/hidden/inner" "['trait.Foo.html']"
+// @files "foo/visible" "['index.html', 'sidebar-items.js', 'trait.Foo.html']"
+
 // @!has 'foo/hidden/index.html'
 // @!has 'foo/hidden/inner/index.html'
 // FIXME: Should be `@!has`: https://github.com/rust-lang/rust/issues/111249
diff --git a/tests/rustdoc/issue-111249-file-creation.rs b/tests/rustdoc/issue-111249-file-creation.rs
index d2042b231e4..afd65ddaf94 100644
--- a/tests/rustdoc/issue-111249-file-creation.rs
+++ b/tests/rustdoc/issue-111249-file-creation.rs
@@ -2,6 +2,12 @@
 #![feature(no_core)]
 #![no_core]
 
+// @files "foo" "['all.html', 'visible', 'index.html', 'sidebar-items.js', 'hidden', \
+//        'struct.Bar.html']"
+// @files "foo/visible" "['trait.Foo.html', 'index.html', 'sidebar-items.js']"
+// @files "foo/hidden" "['inner']"
+// @files "foo/hidden/inner" "['trait.Foo.html']"
+
 // The following five should not fail!
 // @!has 'foo/hidden/index.html'
 // @!has 'foo/hidden/inner/index.html'
diff --git a/tests/ui/asm/aarch64/may_unwind.rs b/tests/ui/asm/aarch64/may_unwind.rs
index 6af8728bbaa..cfb75078264 100644
--- a/tests/ui/asm/aarch64/may_unwind.rs
+++ b/tests/ui/asm/aarch64/may_unwind.rs
@@ -1,6 +1,7 @@
 // only-aarch64
 // run-pass
 // needs-asm-support
+// needs-unwind
 
 #![feature(asm_unwind)]
 
diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr-2.rs b/tests/ui/closures/cannot-call-unsized-via-ptr-2.rs
new file mode 100644
index 00000000000..2d8565517e8
--- /dev/null
+++ b/tests/ui/closures/cannot-call-unsized-via-ptr-2.rs
@@ -0,0 +1,11 @@
+#![feature(unsized_fn_params)]
+
+fn main() {
+    // CoerceMany "LUB"
+    let f = if true { |_a| {} } else { |_b| {} };
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    //~| ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+    let slice: Box<[u8]> = Box::new([1; 8]);
+    f(*slice);
+}
diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr b/tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr
new file mode 100644
index 00000000000..d88b84365df
--- /dev/null
+++ b/tests/ui/closures/cannot-call-unsized-via-ptr-2.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/cannot-call-unsized-via-ptr-2.rs:5:24
+   |
+LL |     let f = if true { |_a| {} } else { |_b| {} };
+   |                        ^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all function arguments must have a statically known size
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/cannot-call-unsized-via-ptr-2.rs:5:41
+   |
+LL |     let f = if true { |_a| {} } else { |_b| {} };
+   |                                         ^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all function arguments must have a statically known size
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr.rs b/tests/ui/closures/cannot-call-unsized-via-ptr.rs
new file mode 100644
index 00000000000..5ce4650b033
--- /dev/null
+++ b/tests/ui/closures/cannot-call-unsized-via-ptr.rs
@@ -0,0 +1,10 @@
+#![feature(unsized_fn_params)]
+
+fn main() {
+    // Simple coercion
+    let f: fn([u8]) = |_result| {};
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+    let slice: Box<[u8]> = Box::new([1; 8]);
+    f(*slice);
+}
diff --git a/tests/ui/closures/cannot-call-unsized-via-ptr.stderr b/tests/ui/closures/cannot-call-unsized-via-ptr.stderr
new file mode 100644
index 00000000000..9ecc66d5ce8
--- /dev/null
+++ b/tests/ui/closures/cannot-call-unsized-via-ptr.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/cannot-call-unsized-via-ptr.rs:5:24
+   |
+LL |     let f: fn([u8]) = |_result| {};
+   |                        ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all function arguments must have a statically known size
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/const-generics/issue-112505-overflow.stderr b/tests/ui/const-generics/issue-112505-overflow.stderr
index 0432f2fa8be..bd8a4feeff5 100644
--- a/tests/ui/const-generics/issue-112505-overflow.stderr
+++ b/tests/ui/const-generics/issue-112505-overflow.stderr
@@ -4,8 +4,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-
 LL |     unsafe { std::mem::transmute(v) }
    |              ^^^^^^^^^^^^^^^^^^^
    |
-   = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[[u32; 8888888]; 9999999]; 777777777]` are too big for the current architecture)
-   = note: target type: `[[[u32; 9999999]; 777777777]; 239]` (59484438436515561504 bits)
+   = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture)
+   = note: target type: `[[[u32; 9999999]; 777777777]; 239]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture)
 
 error: aborting due to previous error
 
diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr
index 3d1197afd0f..9e308620a9c 100644
--- a/tests/ui/const-generics/transmute-fail.stderr
+++ b/tests/ui/const-generics/transmute-fail.stderr
@@ -43,8 +43,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-
 LL |     std::mem::transmute(v)
    |     ^^^^^^^^^^^^^^^^^^^
    |
-   = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[[u32; 8888888]; 9999999]; 777777777]` are too big for the current architecture)
-   = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[[u32; 9999999]; 777777777]; 8888888]` are too big for the current architecture)
+   = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture)
+   = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture)
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/consts/timeout.rs b/tests/ui/consts/timeout.rs
new file mode 100644
index 00000000000..c9094999ee2
--- /dev/null
+++ b/tests/ui/consts/timeout.rs
@@ -0,0 +1,25 @@
+//! This test checks that external macros don't hide
+//! the const eval timeout lint and then subsequently
+//! ICE.
+
+// compile-flags: --crate-type=lib -Ztiny-const-eval-limit
+// error-pattern: constant evaluation is taking a long time
+
+static ROOK_ATTACKS_TABLE: () = {
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+    0_u64.count_ones();
+};
diff --git a/tests/ui/consts/timeout.stderr b/tests/ui/consts/timeout.stderr
new file mode 100644
index 00000000000..799b5ec8dd9
--- /dev/null
+++ b/tests/ui/consts/timeout.stderr
@@ -0,0 +1,15 @@
+error: constant evaluation is taking a long time
+  --> $SRC_DIR/core/src/num/mod.rs:LL:COL
+   |
+   = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
+           If your compilation actually takes a long time, you can safely allow the lint.
+help: the constant being evaluated
+  --> $DIR/timeout.rs:8:1
+   |
+LL | static ROOK_ATTACKS_TABLE: () = {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[deny(long_running_const_eval)]` on by default
+   = note: this error originates in the macro `uint_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/issues/issue-5883.rs b/tests/ui/issues/issue-5883.rs
index 82866b35557..f9dd2c54d99 100644
--- a/tests/ui/issues/issue-5883.rs
+++ b/tests/ui/issues/issue-5883.rs
@@ -6,7 +6,7 @@ struct Struct {
 
 fn new_struct(
     r: dyn A + 'static //~ ERROR the size for values of type
-) -> Struct {          //~ ERROR the size for values of type
+) -> Struct {
     Struct { r: r }
 }
 
diff --git a/tests/ui/issues/issue-5883.stderr b/tests/ui/issues/issue-5883.stderr
index ffff403e0d4..a3e2531b5ca 100644
--- a/tests/ui/issues/issue-5883.stderr
+++ b/tests/ui/issues/issue-5883.stderr
@@ -15,22 +15,6 @@ help: function arguments must have a statically known size, borrowed types alway
 LL |     r: &dyn A + 'static
    |        +
 
-error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
-  --> $DIR/issue-5883.rs:9:6
-   |
-LL | ) -> Struct {
-   |      ^^^^^^ doesn't have a size known at compile-time
-LL |     Struct { r: r }
-   |     --------------- this returned value is of type `Struct`
-   |
-   = help: within `Struct`, the trait `Sized` is not implemented for `(dyn A + 'static)`
-note: required because it appears within the type `Struct`
-  --> $DIR/issue-5883.rs:3:8
-   |
-LL | struct Struct {
-   |        ^^^^^^
-   = note: the return type of a function must have a statically known size
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/layout/cannot-transmute-unnormalizable-type.rs b/tests/ui/layout/cannot-transmute-unnormalizable-type.rs
new file mode 100644
index 00000000000..d2b6e1d8eba
--- /dev/null
+++ b/tests/ui/layout/cannot-transmute-unnormalizable-type.rs
@@ -0,0 +1,22 @@
+trait Trait {
+    type RefTarget;
+}
+
+impl Trait for ()
+where
+    Missing: Trait,
+    //~^ ERROR cannot find type `Missing` in this scope
+{
+    type RefTarget = ();
+}
+
+struct Other {
+    data: <() as Trait>::RefTarget,
+}
+
+fn main() {
+    unsafe {
+        std::mem::transmute::<Option<()>, Option<&Other>>(None);
+        //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
+    }
+}
diff --git a/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr
new file mode 100644
index 00000000000..dd5119318ff
--- /dev/null
+++ b/tests/ui/layout/cannot-transmute-unnormalizable-type.stderr
@@ -0,0 +1,19 @@
+error[E0412]: cannot find type `Missing` in this scope
+  --> $DIR/cannot-transmute-unnormalizable-type.rs:7:5
+   |
+LL |     Missing: Trait,
+   |     ^^^^^^^ not found in this scope
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/cannot-transmute-unnormalizable-type.rs:19:9
+   |
+LL |         std::mem::transmute::<Option<()>, Option<&Other>>(None);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `Option<()>` (8 bits)
+   = note: target type: `Option<&Other>` (unable to determine layout for `Other` because `<() as Trait>::RefTarget` cannot be normalized)
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0412, E0512.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/test-attrs/test-panic-abort-disabled.rs b/tests/ui/test-attrs/test-panic-abort-disabled.rs
index 874dbdb42c3..fa67a784de4 100644
--- a/tests/ui/test-attrs/test-panic-abort-disabled.rs
+++ b/tests/ui/test-attrs/test-panic-abort-disabled.rs
@@ -3,6 +3,7 @@
 // compile-flags: --test -Cpanic=abort -Zpanic-abort-tests=no
 // run-flags: --test-threads=1
 
+// needs-unwind
 // ignore-wasm no panic or subprocess support
 // ignore-emscripten no panic or subprocess support
 
diff --git a/tests/ui/test-attrs/test-type.rs b/tests/ui/test-attrs/test-type.rs
index 8416270fd81..d6d44a6b446 100644
--- a/tests/ui/test-attrs/test-type.rs
+++ b/tests/ui/test-attrs/test-type.rs
@@ -1,9 +1,8 @@
-// compile-flags: --test
+// compile-flags: --test -Zpanic-abort-tests
 // run-flags: --test-threads=1
 // check-run-results
 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // ignore-emscripten no threads support
-// needs-unwind
 // run-pass
 
 #[test]