about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-19 08:10:07 +0000
committerbors <bors@rust-lang.org>2023-06-19 08:10:07 +0000
commitf7690454117d30faff4f207cd5a002a4570ed45d (patch)
tree8fc64e3b204fb88be650a82c88c6dce7229f657a
parent5f81d83ddef72816c824909d9f77eb7c3306d496 (diff)
parent6ea503564802813de4f89b8e2556d59c347aefc9 (diff)
downloadrust-f7690454117d30faff4f207cd5a002a4570ed45d.tar.gz
rust-f7690454117d30faff4f207cd5a002a4570ed45d.zip
Auto merge of #2935 - RalfJung:rustup, r=RalfJung
Rustup
-rw-r--r--.github/workflows/dependencies.yml139
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs3
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs8
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core.rs8
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs7
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs583
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs584
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs29
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs5
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs4
-rw-r--r--compiler/rustc_infer/src/traits/util.rs4
-rw-r--r--compiler/rustc_lint/src/builtin.rs6
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs13
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs6
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs5
-rw-r--r--compiler/rustc_middle/src/mir/traversal.rs51
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs39
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs100
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs10
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/prettify.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs6
-rw-r--r--compiler/rustc_privacy/src/lib.rs10
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs30
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs16
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs4
-rw-r--r--library/alloc/src/alloc.rs7
-rw-r--r--library/alloc/src/boxed.rs10
-rw-r--r--library/alloc/src/rc.rs16
-rw-r--r--library/alloc/src/sync.rs16
-rw-r--r--library/core/src/num/nonzero.rs21
-rw-r--r--library/core/src/panicking.rs5
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/io/buffered/bufreader.rs2
-rw-r--r--library/std/src/io/copy.rs110
-rw-r--r--library/std/src/io/copy/tests.rs108
-rw-r--r--library/std/src/io/mod.rs11
-rw-r--r--library/std/src/io/util/tests.rs61
-rw-r--r--library/std/src/os/unix/net/ancillary.rs8
-rw-r--r--library/std/src/personality.rs2
-rw-r--r--library/std/src/sys/unix/l4re.rs6
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs18
m---------library/stdarch0
-rw-r--r--src/bootstrap/test.rs2
-rwxr-xr-xsrc/ci/docker/scripts/fuchsia-test-runner.py237
-rw-r--r--src/doc/rustc/src/platform-support/fuchsia.md19
-rw-r--r--src/doc/unstable-book/src/language-features/lang-items.md16
-rw-r--r--src/librustdoc/clean/mod.rs4
-rw-r--r--src/librustdoc/html/static/js/main.js10
-rw-r--r--src/librustdoc/html/static/js/search.js44
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/compiletest/src/runtest.rs4
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/tests/fail/alloc/stack_free.stderr2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr2
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr2
-rw-r--r--tests/assembly/stack-protector/stack-protector-heuristics-effect.rs2
-rw-r--r--tests/mir-opt/inline/unsized_argument.caller.Inline.diff29
-rw-r--r--tests/mir-opt/spanview_block.main.built.after.html3
-rw-r--r--tests/mir-opt/spanview_statement.main.built.after.html3
-rw-r--r--tests/mir-opt/spanview_terminator.main.built.after.html3
-rw-r--r--tests/rustdoc-gui/setting-go-to-only-result.goml9
-rw-r--r--tests/ui/asm/parse-error.rs (renamed from tests/ui/asm/x86_64/parse-error.rs)34
-rw-r--r--tests/ui/asm/parse-error.stderr (renamed from tests/ui/asm/x86_64/parse-error.stderr)175
-rw-r--r--tests/ui/asm/x86_64/x86_64_parse_error.rs21
-rw-r--r--tests/ui/asm/x86_64/x86_64_parse_error.stderr44
-rw-r--r--tests/ui/mir/ssa-analysis-regression-50041.rs11
-rw-r--r--triagebot.toml7
100 files changed, 1653 insertions, 1287 deletions
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
new file mode 100644
index 00000000000..2eccd28e5bb
--- /dev/null
+++ b/.github/workflows/dependencies.yml
@@ -0,0 +1,139 @@
+# Automatically run `cargo update` periodically
+
+---
+name: Bump dependencies in Cargo.lock
+on:
+  schedule:
+    # Run weekly
+    - cron: '0 0 * * Sun'
+  workflow_dispatch:
+    # Needed so we can run it manually
+permissions:
+  contents: read
+defaults:
+  run:
+    shell: bash
+env:
+  # So cargo doesn't complain about unstable features
+  RUSTC_BOOTSTRAP: 1
+  PR_TITLE: Weekly `cargo update`
+  PR_MESSAGE: |
+    Automation to keep dependencies in `Cargo.lock` current.
+
+    The following is the output from `cargo update`:
+  COMMIT_MESSAGE: "cargo update \n\n"
+
+jobs:
+  not-waiting-on-bors:
+    name: skip if S-waiting-on-bors
+    runs-on: ubuntu-latest
+    steps:
+      - env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: |
+          # Fetch state and labels of PR
+          # Or exit successfully if PR does not exist
+          JSON=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json labels,state || exit 0)
+          STATE=$(echo "$JSON" | jq -r '.state')
+          WAITING_ON_BORS=$(echo "$JSON" | jq '.labels[] | any(.name == "S-waiting-on-bors"; .)')
+
+          # Exit with error if open and S-waiting-on-bors
+          if [[ "$STATE" == "OPEN" && "$WAITING_ON_BORS" == "true" ]]; then
+            exit 1
+          fi
+
+  update:
+    name: update dependencies
+    needs: not-waiting-on-bors
+    runs-on: ubuntu-latest
+    steps:
+      - name: checkout the source code
+        uses: actions/checkout@v3
+        with:
+          submodules: recursive
+      - name: install the bootstrap toolchain
+        run: |
+          # Extract the stage0 version
+          TOOLCHAIN=$(jq -r '.compiler | {version,date} | join("-")' -- src/stage0.json)
+          # Install and set as default
+          rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
+          rustup default $TOOLCHAIN
+
+      - name: cargo update
+        # Remove first line that always just says "Updating crates.io index"
+        run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
+      - name: upload Cargo.lock artifact for use in PR
+        uses: actions/upload-artifact@v3
+        with:
+          name: Cargo-lock
+          path: Cargo.lock
+          retention-days: 1
+      - name: upload cargo-update log artifact for use in PR
+        uses: actions/upload-artifact@v3
+        with:
+          name: cargo-updates
+          path: cargo_update.log
+          retention-days: 1
+
+  pr:
+    name: amend PR
+    needs: update
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write
+      pull-requests: write
+    steps:
+      - name: checkout the source code
+        uses: actions/checkout@v3
+
+      - name: download Cargo.lock from update job
+        uses: actions/download-artifact@v3
+        with:
+          name: Cargo-lock
+      - name: download cargo-update log from update job
+        uses: actions/download-artifact@v3
+        with:
+          name: cargo-updates
+
+      - name: craft PR body and commit message
+        run: |
+          echo "${COMMIT_MESSAGE}" > commit.txt
+          cat cargo_update.log >> commit.txt
+
+          echo "${PR_MESSAGE}" > body.md
+          echo '```txt' >> body.md
+          cat cargo_update.log >> body.md
+          echo '```' >> body.md
+
+      - name: commit
+        run: |
+          git config user.name github-actions
+          git config user.email github-actions@github.com
+          git switch --force-create cargo_update
+          git add ./Cargo.lock
+          git commit --no-verify --file=commit.txt
+
+      - name: push
+        run: git push --no-verify --force --set-upstream origin cargo_update
+
+      - name: edit existing open pull request
+        id: edit
+        # Don't fail job if we need to open new PR
+        continue-on-error: true
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: |
+          # Exit with error if PR is closed
+          STATE=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json state --jq '.state')
+          if [[ "$STATE" != "OPEN" ]]; then
+            exit 1
+          fi
+
+          gh pr edit cargo_update --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
+
+      - name: open new pull request
+        # Only run if there wasn't an existing PR
+        if: steps.edit.outcome != 'success'
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: gh pr create --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index b5d5071dc05..6ca702cfdfc 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -330,7 +330,8 @@ fn check_opaque_type_well_formed<'tcx>(
     // Require the hidden type to be well-formed with only the generics of the opaque type.
     // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
     // hidden type is well formed even without those bounds.
-    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()));
+    let predicate =
+        ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(definition_ty.into())));
     ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate));
 
     // Check that all obligations are satisfied by the implementation's
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 6697e1aff7d..33f75437478 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1419,9 +1419,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 //
                 // See #91068 for an example.
                 self.prove_predicates(
-                    sig.inputs_and_output
-                        .iter()
-                        .map(|ty| ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))),
+                    sig.inputs_and_output.iter().map(|ty| {
+                        ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(
+                            ty.into(),
+                        )))
+                    }),
                     term_location.to_locations(),
                     ConstraintCategory::Boring,
                 );
@@ -1850,7 +1852,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
                 let array_ty = rvalue.ty(body.local_decls(), tcx);
                 self.prove_predicate(
-                    ty::PredicateKind::WellFormed(array_ty.into()),
+                    ty::PredicateKind::Clause(ty::Clause::WellFormed(array_ty.into())),
                     Locations::Single(location),
                     ConstraintCategory::Boring,
                 );
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 5217e317adf..9734fc2b36d 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -379,16 +379,12 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
     }
 
     let mut new_abis = Vec::new();
-    loop {
+    while !p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
         match p.parse_str_lit() {
             Ok(str_lit) => {
                 new_abis.push((str_lit.symbol_unescaped, str_lit.span));
             }
             Err(opt_lit) => {
-                // If the non-string literal is a closing paren then it's the end of the list and is fine
-                if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
-                    break;
-                }
                 let span = opt_lit.map_or(p.token.span, |lit| lit.span);
                 let mut err =
                     p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 772dd98fade..79ca4c03985 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -546,7 +546,8 @@ impl<T> Box<T> {
 
 impl<T: ?Sized, A> Drop for Box<T, A> {
     fn drop(&mut self) {
-        // drop is currently performed by compiler.
+        // inner value is dropped by compiler
+        libc::free(self.0.pointer.0 as *mut u8);
     }
 }
 
@@ -563,11 +564,6 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
     libc::malloc(size)
 }
 
-#[lang = "box_free"]
-unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, _alloc: ()) {
-    libc::free(ptr.pointer.0 as *mut u8);
-}
-
 #[lang = "drop"]
 pub trait Drop {
     fn drop(&mut self);
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index 637b8dc53fe..c27b610f2ab 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -490,7 +490,8 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> fo
 
 impl<T: ?Sized, A: Allocator> Drop for Box<T, A> {
     fn drop(&mut self) {
-        // drop is currently performed by compiler.
+        // inner value is dropped by compiler
+        libc::free(self.pointer.0 as *mut u8);
     }
 }
 
@@ -507,11 +508,6 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
     libc::malloc(size)
 }
 
-#[lang = "box_free"]
-unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, _alloc: ()) {
-    libc::free(ptr.pointer.0 as *mut u8);
-}
-
 #[lang = "drop"]
 pub trait Drop {
     fn drop(&mut self);
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 0e2d9ee8fb2..44b143c77f3 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -14,7 +14,6 @@
 
 use rustc_hir as hir;
 use rustc_middle::mir;
-use rustc_middle::mir::traversal::ReversePostorderIter;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::InternalSubsts;
@@ -53,9 +52,8 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
             return;
         }
 
-        let mut rpo = traversal::reverse_postorder(body);
         let ccx = ConstCx::new(tcx, body);
-        let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
+        let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx);
 
         let promotable_candidates = validate_candidates(&ccx, &mut temps, &all_candidates);
 
@@ -166,14 +164,13 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
 
 pub fn collect_temps_and_candidates<'tcx>(
     ccx: &ConstCx<'_, 'tcx>,
-    rpo: &mut ReversePostorderIter<'_, 'tcx>,
 ) -> (IndexVec<Local, TempState>, Vec<Candidate>) {
     let mut collector = Collector {
         temps: IndexVec::from_elem(TempState::Undefined, &ccx.body.local_decls),
         candidates: vec![],
         ccx,
     };
-    for (bb, data) in rpo {
+    for (bb, data) in traversal::reverse_postorder(ccx.body) {
         collector.visit_basic_block_data(bb, data);
     }
     (collector.temps, collector.candidates)
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 4e23a28b371..302a9498413 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -250,7 +250,6 @@ language_item_table! {
     FormatUnsafeArg,         sym::format_unsafe_arg,   format_unsafe_arg,          Target::Struct,         GenericRequirement::None;
 
     ExchangeMalloc,          sym::exchange_malloc,     exchange_malloc_fn,         Target::Fn,             GenericRequirement::None;
-    BoxFree,                 sym::box_free,            box_free_fn,                Target::Fn,             GenericRequirement::Minimum(1);
     DropInPlace,             sym::drop_in_place,       drop_in_place_fn,           Target::Fn,             GenericRequirement::Minimum(1);
     AllocLayout,             sym::alloc_layout,        alloc_layout,               Target::Struct,         GenericRequirement::None;
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
new file mode 100644
index 00000000000..e4eb0e6abd4
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -0,0 +1,583 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_lint_defs::Applicability;
+use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
+use rustc_span::symbol::Ident;
+use rustc_span::{ErrorGuaranteed, Span};
+use rustc_trait_selection::traits;
+
+use crate::astconv::{AstConv, ConvertedBinding, ConvertedBindingKind};
+use crate::bounds::Bounds;
+use crate::errors::{MultipleRelaxedDefaultBounds, ValueOfAssociatedStructAlreadySpecified};
+
+use super::OnlySelfBounds;
+
+impl<'tcx> dyn AstConv<'tcx> + '_ {
+    /// Sets `implicitly_sized` to true on `Bounds` if necessary
+    pub(crate) fn add_implicitly_sized(
+        &self,
+        bounds: &mut Bounds<'tcx>,
+        self_ty: Ty<'tcx>,
+        ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+        self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+        span: Span,
+    ) {
+        let tcx = self.tcx();
+
+        // Try to find an unbound in bounds.
+        let mut unbound = None;
+        let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
+            for ab in ast_bounds {
+                if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
+                    if unbound.is_none() {
+                        unbound = Some(&ptr.trait_ref);
+                    } else {
+                        tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span });
+                    }
+                }
+            }
+        };
+        search_bounds(ast_bounds);
+        if let Some((self_ty, where_clause)) = self_ty_where_predicates {
+            for clause in where_clause {
+                if let hir::WherePredicate::BoundPredicate(pred) = clause {
+                    if pred.is_param_bound(self_ty.to_def_id()) {
+                        search_bounds(pred.bounds);
+                    }
+                }
+            }
+        }
+
+        let sized_def_id = tcx.lang_items().sized_trait();
+        match (&sized_def_id, unbound) {
+            (Some(sized_def_id), Some(tpb))
+                if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
+            {
+                // There was in fact a `?Sized` bound, return without doing anything
+                return;
+            }
+            (_, Some(_)) => {
+                // There was a `?Trait` bound, but it was not `?Sized`; warn.
+                tcx.sess.span_warn(
+                    span,
+                    "default bound relaxed for a type parameter, but \
+                        this does nothing because the given bound is not \
+                        a default; only `?Sized` is supported",
+                );
+                // Otherwise, add implicitly sized if `Sized` is available.
+            }
+            _ => {
+                // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
+            }
+        }
+        if sized_def_id.is_none() {
+            // No lang item for `Sized`, so we can't add it as a bound.
+            return;
+        }
+        bounds.push_sized(tcx, self_ty, span);
+    }
+
+    /// This helper takes a *converted* parameter type (`param_ty`)
+    /// and an *unconverted* list of bounds:
+    ///
+    /// ```text
+    /// fn foo<T: Debug>
+    ///        ^  ^^^^^ `ast_bounds` parameter, in HIR form
+    ///        |
+    ///        `param_ty`, in ty form
+    /// ```
+    ///
+    /// It adds these `ast_bounds` into the `bounds` structure.
+    ///
+    /// **A note on binders:** there is an implied binder around
+    /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
+    /// for more details.
+    #[instrument(level = "debug", skip(self, ast_bounds, bounds))]
+    pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>(
+        &self,
+        param_ty: Ty<'tcx>,
+        ast_bounds: I,
+        bounds: &mut Bounds<'tcx>,
+        bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
+        only_self_bounds: OnlySelfBounds,
+    ) {
+        for ast_bound in ast_bounds {
+            match ast_bound {
+                hir::GenericBound::Trait(poly_trait_ref, modifier) => {
+                    let (constness, polarity) = match modifier {
+                        hir::TraitBoundModifier::MaybeConst => {
+                            (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
+                        }
+                        hir::TraitBoundModifier::None => {
+                            (ty::BoundConstness::NotConst, ty::ImplPolarity::Positive)
+                        }
+                        hir::TraitBoundModifier::Negative => {
+                            (ty::BoundConstness::NotConst, ty::ImplPolarity::Negative)
+                        }
+                        hir::TraitBoundModifier::Maybe => continue,
+                    };
+                    let _ = self.instantiate_poly_trait_ref(
+                        &poly_trait_ref.trait_ref,
+                        poly_trait_ref.span,
+                        constness,
+                        polarity,
+                        param_ty,
+                        bounds,
+                        false,
+                        only_self_bounds,
+                    );
+                }
+                &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
+                    self.instantiate_lang_item_trait_ref(
+                        lang_item,
+                        span,
+                        hir_id,
+                        args,
+                        param_ty,
+                        bounds,
+                        only_self_bounds,
+                    );
+                }
+                hir::GenericBound::Outlives(lifetime) => {
+                    let region = self.ast_region_to_region(lifetime, None);
+                    bounds.push_region_bound(
+                        self.tcx(),
+                        ty::Binder::bind_with_vars(
+                            ty::OutlivesPredicate(param_ty, region),
+                            bound_vars,
+                        ),
+                        lifetime.ident.span,
+                    );
+                }
+            }
+        }
+    }
+
+    /// Translates a list of bounds from the HIR into the `Bounds` data structure.
+    /// The self-type for the bounds is given by `param_ty`.
+    ///
+    /// Example:
+    ///
+    /// ```ignore (illustrative)
+    /// fn foo<T: Bar + Baz>() { }
+    /// //     ^  ^^^^^^^^^ ast_bounds
+    /// //     param_ty
+    /// ```
+    ///
+    /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
+    /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
+    /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
+    ///
+    /// `span` should be the declaration size of the parameter.
+    pub(crate) fn compute_bounds(
+        &self,
+        param_ty: Ty<'tcx>,
+        ast_bounds: &[hir::GenericBound<'_>],
+        only_self_bounds: OnlySelfBounds,
+    ) -> Bounds<'tcx> {
+        let mut bounds = Bounds::default();
+        self.add_bounds(
+            param_ty,
+            ast_bounds.iter(),
+            &mut bounds,
+            ty::List::empty(),
+            only_self_bounds,
+        );
+        debug!(?bounds);
+
+        bounds
+    }
+
+    /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
+    /// named `assoc_name` into ty::Bounds. Ignore the rest.
+    pub(crate) fn compute_bounds_that_match_assoc_item(
+        &self,
+        param_ty: Ty<'tcx>,
+        ast_bounds: &[hir::GenericBound<'_>],
+        assoc_name: Ident,
+    ) -> Bounds<'tcx> {
+        let mut result = Vec::new();
+
+        for ast_bound in ast_bounds {
+            if let Some(trait_ref) = ast_bound.trait_ref()
+                && let Some(trait_did) = trait_ref.trait_def_id()
+                && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
+            {
+                result.push(ast_bound.clone());
+            }
+        }
+
+        let mut bounds = Bounds::default();
+        self.add_bounds(
+            param_ty,
+            result.iter(),
+            &mut bounds,
+            ty::List::empty(),
+            OnlySelfBounds(true),
+        );
+        debug!(?bounds);
+
+        bounds
+    }
+
+    /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
+    /// onto `bounds`.
+    ///
+    /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
+    /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
+    /// the binder (e.g., `&'a u32`) and hence may reference bound regions.
+    #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))]
+    pub(super) fn add_predicates_for_ast_type_binding(
+        &self,
+        hir_ref_id: hir::HirId,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        binding: &ConvertedBinding<'_, 'tcx>,
+        bounds: &mut Bounds<'tcx>,
+        speculative: bool,
+        dup_bindings: &mut FxHashMap<DefId, Span>,
+        path_span: Span,
+        constness: ty::BoundConstness,
+        only_self_bounds: OnlySelfBounds,
+        polarity: ty::ImplPolarity,
+    ) -> Result<(), ErrorGuaranteed> {
+        // Given something like `U: SomeTrait<T = X>`, we want to produce a
+        // predicate like `<U as SomeTrait>::T = X`. This is somewhat
+        // subtle in the event that `T` is defined in a supertrait of
+        // `SomeTrait`, because in that case we need to upcast.
+        //
+        // That is, consider this case:
+        //
+        // ```
+        // trait SubTrait: SuperTrait<i32> { }
+        // trait SuperTrait<A> { type T; }
+        //
+        // ... B: SubTrait<T = foo> ...
+        // ```
+        //
+        // We want to produce `<B as SuperTrait<i32>>::T == foo`.
+
+        let tcx = self.tcx();
+
+        let return_type_notation =
+            binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
+
+        let candidate = if return_type_notation {
+            if self.trait_defines_associated_item_named(
+                trait_ref.def_id(),
+                ty::AssocKind::Fn,
+                binding.item_name,
+            ) {
+                trait_ref
+            } else {
+                self.one_bound_for_assoc_method(
+                    traits::supertraits(tcx, trait_ref),
+                    trait_ref.print_only_trait_path(),
+                    binding.item_name,
+                    path_span,
+                )?
+            }
+        } else if self.trait_defines_associated_item_named(
+            trait_ref.def_id(),
+            ty::AssocKind::Type,
+            binding.item_name,
+        ) {
+            // Simple case: X is defined in the current trait.
+            trait_ref
+        } else {
+            // Otherwise, we have to walk through the supertraits to find
+            // those that do.
+            self.one_bound_for_assoc_type(
+                || traits::supertraits(tcx, trait_ref),
+                trait_ref.skip_binder().print_only_trait_name(),
+                binding.item_name,
+                path_span,
+                match binding.kind {
+                    ConvertedBindingKind::Equality(term) => Some(term),
+                    _ => None,
+                },
+            )?
+        };
+
+        let (assoc_ident, def_scope) =
+            tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
+
+        // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
+        // of calling `filter_by_name_and_kind`.
+        let find_item_of_kind = |kind| {
+            tcx.associated_items(candidate.def_id())
+                .filter_by_name_unhygienic(assoc_ident.name)
+                .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
+        };
+        let assoc_item = if return_type_notation {
+            find_item_of_kind(ty::AssocKind::Fn)
+        } else {
+            find_item_of_kind(ty::AssocKind::Type)
+                .or_else(|| find_item_of_kind(ty::AssocKind::Const))
+        }
+        .expect("missing associated type");
+
+        if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
+            tcx.sess
+                .struct_span_err(
+                    binding.span,
+                    format!("{} `{}` is private", assoc_item.kind, binding.item_name),
+                )
+                .span_label(binding.span, format!("private {}", assoc_item.kind))
+                .emit();
+        }
+        tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
+
+        if !speculative {
+            dup_bindings
+                .entry(assoc_item.def_id)
+                .and_modify(|prev_span| {
+                    tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
+                        span: binding.span,
+                        prev_span: *prev_span,
+                        item_name: binding.item_name,
+                        def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
+                    });
+                })
+                .or_insert(binding.span);
+        }
+
+        let projection_ty = if return_type_notation {
+            let mut emitted_bad_param_err = false;
+            // If we have an method return type bound, then we need to substitute
+            // the method's early bound params with suitable late-bound params.
+            let mut num_bound_vars = candidate.bound_vars().len();
+            let substs =
+                candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| {
+                    let subst = match param.kind {
+                        ty::GenericParamDefKind::Lifetime => ty::Region::new_late_bound(
+                            tcx,
+                            ty::INNERMOST,
+                            ty::BoundRegion {
+                                var: ty::BoundVar::from_usize(num_bound_vars),
+                                kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name),
+                            },
+                        )
+                        .into(),
+                        ty::GenericParamDefKind::Type { .. } => {
+                            if !emitted_bad_param_err {
+                                tcx.sess.emit_err(
+                                    crate::errors::ReturnTypeNotationIllegalParam::Type {
+                                        span: path_span,
+                                        param_span: tcx.def_span(param.def_id),
+                                    },
+                                );
+                                emitted_bad_param_err = true;
+                            }
+                            tcx.mk_bound(
+                                ty::INNERMOST,
+                                ty::BoundTy {
+                                    var: ty::BoundVar::from_usize(num_bound_vars),
+                                    kind: ty::BoundTyKind::Param(param.def_id, param.name),
+                                },
+                            )
+                            .into()
+                        }
+                        ty::GenericParamDefKind::Const { .. } => {
+                            if !emitted_bad_param_err {
+                                tcx.sess.emit_err(
+                                    crate::errors::ReturnTypeNotationIllegalParam::Const {
+                                        span: path_span,
+                                        param_span: tcx.def_span(param.def_id),
+                                    },
+                                );
+                                emitted_bad_param_err = true;
+                            }
+                            let ty = tcx
+                                .type_of(param.def_id)
+                                .no_bound_vars()
+                                .expect("ct params cannot have early bound vars");
+                            tcx.mk_const(
+                                ty::ConstKind::Bound(
+                                    ty::INNERMOST,
+                                    ty::BoundVar::from_usize(num_bound_vars),
+                                ),
+                                ty,
+                            )
+                            .into()
+                        }
+                    };
+                    num_bound_vars += 1;
+                    subst
+                });
+
+            // Next, we need to check that the return-type notation is being used on
+            // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
+            let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output();
+            let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
+                && tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
+            {
+                alias_ty
+            } else {
+                return Err(self.tcx().sess.emit_err(
+                    crate::errors::ReturnTypeNotationOnNonRpitit {
+                        span: binding.span,
+                        ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
+                        fn_span: tcx.hir().span_if_local(assoc_item.def_id),
+                        note: (),
+                    },
+                ));
+            };
+
+            // Finally, move the fn return type's bound vars over to account for the early bound
+            // params (and trait ref's late bound params). This logic is very similar to
+            // `Predicate::subst_supertrait`, and it's no coincidence why.
+            let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
+            let subst_output = ty::EarlyBinder::bind(shifted_output).subst(tcx, substs);
+
+            let bound_vars = tcx.late_bound_vars(binding.hir_id);
+            ty::Binder::bind_with_vars(subst_output, bound_vars)
+        } else {
+            // Include substitutions for generic parameters of associated types
+            candidate.map_bound(|trait_ref| {
+                let ident = Ident::new(assoc_item.name, binding.item_name.span);
+                let item_segment = hir::PathSegment {
+                    ident,
+                    hir_id: binding.hir_id,
+                    res: Res::Err,
+                    args: Some(binding.gen_args),
+                    infer_args: false,
+                };
+
+                let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
+                    path_span,
+                    assoc_item.def_id,
+                    &item_segment,
+                    trait_ref.substs,
+                );
+
+                debug!(?substs_trait_ref_and_assoc_item);
+
+                tcx.mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
+            })
+        };
+
+        if !speculative {
+            // Find any late-bound regions declared in `ty` that are not
+            // declared in the trait-ref or assoc_item. These are not well-formed.
+            //
+            // Example:
+            //
+            //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+            //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+            if let ConvertedBindingKind::Equality(ty) = binding.kind {
+                let late_bound_in_trait_ref =
+                    tcx.collect_constrained_late_bound_regions(&projection_ty);
+                let late_bound_in_ty =
+                    tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
+                debug!(?late_bound_in_trait_ref);
+                debug!(?late_bound_in_ty);
+
+                // FIXME: point at the type params that don't have appropriate lifetimes:
+                // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
+                //                         ----  ----     ^^^^^^^
+                self.validate_late_bound_regions(
+                    late_bound_in_trait_ref,
+                    late_bound_in_ty,
+                    |br_name| {
+                        struct_span_err!(
+                            tcx.sess,
+                            binding.span,
+                            E0582,
+                            "binding for associated type `{}` references {}, \
+                             which does not appear in the trait input types",
+                            binding.item_name,
+                            br_name
+                        )
+                    },
+                );
+            }
+        }
+
+        match binding.kind {
+            ConvertedBindingKind::Equality(..) if return_type_notation => {
+                return Err(self.tcx().sess.emit_err(
+                    crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
+                ));
+            }
+            ConvertedBindingKind::Equality(mut term) => {
+                // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
+                // the "projection predicate" for:
+                //
+                // `<T as Iterator>::Item = u32`
+                let assoc_item_def_id = projection_ty.skip_binder().def_id;
+                let def_kind = tcx.def_kind(assoc_item_def_id);
+                match (def_kind, term.unpack()) {
+                    (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
+                    | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (),
+                    (_, _) => {
+                        let got = if let Some(_) = term.ty() { "type" } else { "constant" };
+                        let expected = tcx.def_descr(assoc_item_def_id);
+                        let mut err = tcx.sess.struct_span_err(
+                            binding.span,
+                            format!("expected {expected} bound, found {got}"),
+                        );
+                        err.span_note(
+                            tcx.def_span(assoc_item_def_id),
+                            format!("{expected} defined here"),
+                        );
+
+                        if let hir::def::DefKind::AssocConst = def_kind
+                          && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
+                          && tcx.features().associated_const_equality {
+                            err.span_suggestion(
+                                binding.span,
+                                "if equating a const, try wrapping with braces",
+                                format!("{} = {{ const }}", binding.item_name),
+                                Applicability::HasPlaceholders,
+                            );
+                        }
+                        let reported = err.emit();
+                        term = match def_kind {
+                            hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(),
+                            hir::def::DefKind::AssocConst => tcx
+                                .const_error(
+                                    tcx.type_of(assoc_item_def_id)
+                                        .subst(tcx, projection_ty.skip_binder().substs),
+                                    reported,
+                                )
+                                .into(),
+                            _ => unreachable!(),
+                        };
+                    }
+                }
+                bounds.push_projection_bound(
+                    tcx,
+                    projection_ty
+                        .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
+                    binding.span,
+                );
+            }
+            ConvertedBindingKind::Constraint(ast_bounds) => {
+                // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
+                //
+                // `<T as Iterator>::Item: Debug`
+                //
+                // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
+                // parameter to have a skipped binder.
+                //
+                // NOTE: If `only_self_bounds` is true, do NOT expand this associated
+                // type bound into a trait predicate, since we only want to add predicates
+                // for the `Self` type.
+                if !only_self_bounds.0 {
+                    let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
+                    self.add_bounds(
+                        param_ty,
+                        ast_bounds.iter(),
+                        bounds,
+                        projection_ty.bound_vars(),
+                        only_self_bounds,
+                    );
+                }
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 221c7ce4f6f..621569ab321 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2,6 +2,7 @@
 //! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an
 //! instance of `AstConv`.
 
+mod bounds;
 mod errors;
 pub mod generics;
 mod lint;
@@ -11,8 +12,7 @@ use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generi
 use crate::bounds::Bounds;
 use crate::collect::HirPlaceholderCollector;
 use crate::errors::{
-    AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits,
-    TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified,
+    AmbiguousLifetimeBound, TraitObjectDeclaredWithNoTraits, TypeofReservedKeywordUsed,
 };
 use crate::middle::resolve_bound_vars as rbv;
 use crate::require_c_abi_if_c_variadic;
@@ -31,9 +31,10 @@ use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
+use rustc_middle::ty::DynKind;
 use rustc_middle::ty::GenericParamDefKind;
+use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{DynKind, ToPredicate};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
@@ -885,571 +886,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .is_some()
     }
 
-    /// Sets `implicitly_sized` to true on `Bounds` if necessary
-    pub(crate) fn add_implicitly_sized(
-        &self,
-        bounds: &mut Bounds<'tcx>,
-        self_ty: Ty<'tcx>,
-        ast_bounds: &'tcx [hir::GenericBound<'tcx>],
-        self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
-        span: Span,
-    ) {
-        let tcx = self.tcx();
-
-        // Try to find an unbound in bounds.
-        let mut unbound = None;
-        let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
-            for ab in ast_bounds {
-                if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
-                    if unbound.is_none() {
-                        unbound = Some(&ptr.trait_ref);
-                    } else {
-                        tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span });
-                    }
-                }
-            }
-        };
-        search_bounds(ast_bounds);
-        if let Some((self_ty, where_clause)) = self_ty_where_predicates {
-            for clause in where_clause {
-                if let hir::WherePredicate::BoundPredicate(pred) = clause {
-                    if pred.is_param_bound(self_ty.to_def_id()) {
-                        search_bounds(pred.bounds);
-                    }
-                }
-            }
-        }
-
-        let sized_def_id = tcx.lang_items().sized_trait();
-        match (&sized_def_id, unbound) {
-            (Some(sized_def_id), Some(tpb))
-                if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
-            {
-                // There was in fact a `?Sized` bound, return without doing anything
-                return;
-            }
-            (_, Some(_)) => {
-                // There was a `?Trait` bound, but it was not `?Sized`; warn.
-                tcx.sess.span_warn(
-                    span,
-                    "default bound relaxed for a type parameter, but \
-                        this does nothing because the given bound is not \
-                        a default; only `?Sized` is supported",
-                );
-                // Otherwise, add implicitly sized if `Sized` is available.
-            }
-            _ => {
-                // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
-            }
-        }
-        if sized_def_id.is_none() {
-            // No lang item for `Sized`, so we can't add it as a bound.
-            return;
-        }
-        bounds.push_sized(tcx, self_ty, span);
-    }
-
-    /// This helper takes a *converted* parameter type (`param_ty`)
-    /// and an *unconverted* list of bounds:
-    ///
-    /// ```text
-    /// fn foo<T: Debug>
-    ///        ^  ^^^^^ `ast_bounds` parameter, in HIR form
-    ///        |
-    ///        `param_ty`, in ty form
-    /// ```
-    ///
-    /// It adds these `ast_bounds` into the `bounds` structure.
-    ///
-    /// **A note on binders:** there is an implied binder around
-    /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
-    /// for more details.
-    #[instrument(level = "debug", skip(self, ast_bounds, bounds))]
-    pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>(
-        &self,
-        param_ty: Ty<'tcx>,
-        ast_bounds: I,
-        bounds: &mut Bounds<'tcx>,
-        bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
-        only_self_bounds: OnlySelfBounds,
-    ) {
-        for ast_bound in ast_bounds {
-            match ast_bound {
-                hir::GenericBound::Trait(poly_trait_ref, modifier) => {
-                    let (constness, polarity) = match modifier {
-                        hir::TraitBoundModifier::MaybeConst => {
-                            (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
-                        }
-                        hir::TraitBoundModifier::None => {
-                            (ty::BoundConstness::NotConst, ty::ImplPolarity::Positive)
-                        }
-                        hir::TraitBoundModifier::Negative => {
-                            (ty::BoundConstness::NotConst, ty::ImplPolarity::Negative)
-                        }
-                        hir::TraitBoundModifier::Maybe => continue,
-                    };
-                    let _ = self.instantiate_poly_trait_ref(
-                        &poly_trait_ref.trait_ref,
-                        poly_trait_ref.span,
-                        constness,
-                        polarity,
-                        param_ty,
-                        bounds,
-                        false,
-                        only_self_bounds,
-                    );
-                }
-                &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
-                    self.instantiate_lang_item_trait_ref(
-                        lang_item,
-                        span,
-                        hir_id,
-                        args,
-                        param_ty,
-                        bounds,
-                        only_self_bounds,
-                    );
-                }
-                hir::GenericBound::Outlives(lifetime) => {
-                    let region = self.ast_region_to_region(lifetime, None);
-                    bounds.push_region_bound(
-                        self.tcx(),
-                        ty::Binder::bind_with_vars(
-                            ty::OutlivesPredicate(param_ty, region),
-                            bound_vars,
-                        ),
-                        lifetime.ident.span,
-                    );
-                }
-            }
-        }
-    }
-
-    /// Translates a list of bounds from the HIR into the `Bounds` data structure.
-    /// The self-type for the bounds is given by `param_ty`.
-    ///
-    /// Example:
-    ///
-    /// ```ignore (illustrative)
-    /// fn foo<T: Bar + Baz>() { }
-    /// //     ^  ^^^^^^^^^ ast_bounds
-    /// //     param_ty
-    /// ```
-    ///
-    /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
-    /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
-    /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
-    ///
-    /// `span` should be the declaration size of the parameter.
-    pub(crate) fn compute_bounds(
-        &self,
-        param_ty: Ty<'tcx>,
-        ast_bounds: &[hir::GenericBound<'_>],
-        only_self_bounds: OnlySelfBounds,
-    ) -> Bounds<'tcx> {
-        let mut bounds = Bounds::default();
-        self.add_bounds(
-            param_ty,
-            ast_bounds.iter(),
-            &mut bounds,
-            ty::List::empty(),
-            only_self_bounds,
-        );
-        debug!(?bounds);
-
-        bounds
-    }
-
-    /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
-    /// named `assoc_name` into ty::Bounds. Ignore the rest.
-    pub(crate) fn compute_bounds_that_match_assoc_item(
-        &self,
-        param_ty: Ty<'tcx>,
-        ast_bounds: &[hir::GenericBound<'_>],
-        assoc_name: Ident,
-    ) -> Bounds<'tcx> {
-        let mut result = Vec::new();
-
-        for ast_bound in ast_bounds {
-            if let Some(trait_ref) = ast_bound.trait_ref()
-                && let Some(trait_did) = trait_ref.trait_def_id()
-                && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
-            {
-                result.push(ast_bound.clone());
-            }
-        }
-
-        let mut bounds = Bounds::default();
-        self.add_bounds(
-            param_ty,
-            result.iter(),
-            &mut bounds,
-            ty::List::empty(),
-            OnlySelfBounds(true),
-        );
-        debug!(?bounds);
-
-        bounds
-    }
-
-    /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
-    /// onto `bounds`.
-    ///
-    /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
-    /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
-    /// the binder (e.g., `&'a u32`) and hence may reference bound regions.
-    #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))]
-    fn add_predicates_for_ast_type_binding(
-        &self,
-        hir_ref_id: hir::HirId,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        binding: &ConvertedBinding<'_, 'tcx>,
-        bounds: &mut Bounds<'tcx>,
-        speculative: bool,
-        dup_bindings: &mut FxHashMap<DefId, Span>,
-        path_span: Span,
-        constness: ty::BoundConstness,
-        only_self_bounds: OnlySelfBounds,
-        polarity: ty::ImplPolarity,
-    ) -> Result<(), ErrorGuaranteed> {
-        // Given something like `U: SomeTrait<T = X>`, we want to produce a
-        // predicate like `<U as SomeTrait>::T = X`. This is somewhat
-        // subtle in the event that `T` is defined in a supertrait of
-        // `SomeTrait`, because in that case we need to upcast.
-        //
-        // That is, consider this case:
-        //
-        // ```
-        // trait SubTrait: SuperTrait<i32> { }
-        // trait SuperTrait<A> { type T; }
-        //
-        // ... B: SubTrait<T = foo> ...
-        // ```
-        //
-        // We want to produce `<B as SuperTrait<i32>>::T == foo`.
-
-        let tcx = self.tcx();
-
-        let return_type_notation =
-            binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
-
-        let candidate = if return_type_notation {
-            if self.trait_defines_associated_item_named(
-                trait_ref.def_id(),
-                ty::AssocKind::Fn,
-                binding.item_name,
-            ) {
-                trait_ref
-            } else {
-                self.one_bound_for_assoc_method(
-                    traits::supertraits(tcx, trait_ref),
-                    trait_ref.print_only_trait_path(),
-                    binding.item_name,
-                    path_span,
-                )?
-            }
-        } else if self.trait_defines_associated_item_named(
-            trait_ref.def_id(),
-            ty::AssocKind::Type,
-            binding.item_name,
-        ) {
-            // Simple case: X is defined in the current trait.
-            trait_ref
-        } else {
-            // Otherwise, we have to walk through the supertraits to find
-            // those that do.
-            self.one_bound_for_assoc_type(
-                || traits::supertraits(tcx, trait_ref),
-                trait_ref.skip_binder().print_only_trait_name(),
-                binding.item_name,
-                path_span,
-                match binding.kind {
-                    ConvertedBindingKind::Equality(term) => Some(term),
-                    _ => None,
-                },
-            )?
-        };
-
-        let (assoc_ident, def_scope) =
-            tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
-
-        // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
-        // of calling `filter_by_name_and_kind`.
-        let find_item_of_kind = |kind| {
-            tcx.associated_items(candidate.def_id())
-                .filter_by_name_unhygienic(assoc_ident.name)
-                .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
-        };
-        let assoc_item = if return_type_notation {
-            find_item_of_kind(ty::AssocKind::Fn)
-        } else {
-            find_item_of_kind(ty::AssocKind::Type)
-                .or_else(|| find_item_of_kind(ty::AssocKind::Const))
-        }
-        .expect("missing associated type");
-
-        if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
-            tcx.sess
-                .struct_span_err(
-                    binding.span,
-                    format!("{} `{}` is private", assoc_item.kind, binding.item_name),
-                )
-                .span_label(binding.span, format!("private {}", assoc_item.kind))
-                .emit();
-        }
-        tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
-
-        if !speculative {
-            dup_bindings
-                .entry(assoc_item.def_id)
-                .and_modify(|prev_span| {
-                    tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
-                        span: binding.span,
-                        prev_span: *prev_span,
-                        item_name: binding.item_name,
-                        def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
-                    });
-                })
-                .or_insert(binding.span);
-        }
-
-        let projection_ty = if return_type_notation {
-            let mut emitted_bad_param_err = false;
-            // If we have an method return type bound, then we need to substitute
-            // the method's early bound params with suitable late-bound params.
-            let mut num_bound_vars = candidate.bound_vars().len();
-            let substs =
-                candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| {
-                    let subst = match param.kind {
-                        GenericParamDefKind::Lifetime => ty::Region::new_late_bound(
-                            tcx,
-                            ty::INNERMOST,
-                            ty::BoundRegion {
-                                var: ty::BoundVar::from_usize(num_bound_vars),
-                                kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name),
-                            },
-                        )
-                        .into(),
-                        GenericParamDefKind::Type { .. } => {
-                            if !emitted_bad_param_err {
-                                tcx.sess.emit_err(
-                                    crate::errors::ReturnTypeNotationIllegalParam::Type {
-                                        span: path_span,
-                                        param_span: tcx.def_span(param.def_id),
-                                    },
-                                );
-                                emitted_bad_param_err = true;
-                            }
-                            tcx.mk_bound(
-                                ty::INNERMOST,
-                                ty::BoundTy {
-                                    var: ty::BoundVar::from_usize(num_bound_vars),
-                                    kind: ty::BoundTyKind::Param(param.def_id, param.name),
-                                },
-                            )
-                            .into()
-                        }
-                        GenericParamDefKind::Const { .. } => {
-                            if !emitted_bad_param_err {
-                                tcx.sess.emit_err(
-                                    crate::errors::ReturnTypeNotationIllegalParam::Const {
-                                        span: path_span,
-                                        param_span: tcx.def_span(param.def_id),
-                                    },
-                                );
-                                emitted_bad_param_err = true;
-                            }
-                            let ty = tcx
-                                .type_of(param.def_id)
-                                .no_bound_vars()
-                                .expect("ct params cannot have early bound vars");
-                            tcx.mk_const(
-                                ty::ConstKind::Bound(
-                                    ty::INNERMOST,
-                                    ty::BoundVar::from_usize(num_bound_vars),
-                                ),
-                                ty,
-                            )
-                            .into()
-                        }
-                    };
-                    num_bound_vars += 1;
-                    subst
-                });
-
-            // Next, we need to check that the return-type notation is being used on
-            // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
-            let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output();
-            let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
-                && tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
-            {
-                alias_ty
-            } else {
-                return Err(self.tcx().sess.emit_err(
-                    crate::errors::ReturnTypeNotationOnNonRpitit {
-                        span: binding.span,
-                        ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
-                        fn_span: tcx.hir().span_if_local(assoc_item.def_id),
-                        note: (),
-                    },
-                ));
-            };
-
-            // Finally, move the fn return type's bound vars over to account for the early bound
-            // params (and trait ref's late bound params). This logic is very similar to
-            // `Predicate::subst_supertrait`, and it's no coincidence why.
-            let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
-            let subst_output = ty::EarlyBinder::bind(shifted_output).subst(tcx, substs);
-
-            let bound_vars = tcx.late_bound_vars(binding.hir_id);
-            ty::Binder::bind_with_vars(subst_output, bound_vars)
-        } else {
-            // Include substitutions for generic parameters of associated types
-            candidate.map_bound(|trait_ref| {
-                let ident = Ident::new(assoc_item.name, binding.item_name.span);
-                let item_segment = hir::PathSegment {
-                    ident,
-                    hir_id: binding.hir_id,
-                    res: Res::Err,
-                    args: Some(binding.gen_args),
-                    infer_args: false,
-                };
-
-                let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
-                    path_span,
-                    assoc_item.def_id,
-                    &item_segment,
-                    trait_ref.substs,
-                );
-
-                debug!(?substs_trait_ref_and_assoc_item);
-
-                tcx.mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
-            })
-        };
-
-        if !speculative {
-            // Find any late-bound regions declared in `ty` that are not
-            // declared in the trait-ref or assoc_item. These are not well-formed.
-            //
-            // Example:
-            //
-            //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
-            //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
-            if let ConvertedBindingKind::Equality(ty) = binding.kind {
-                let late_bound_in_trait_ref =
-                    tcx.collect_constrained_late_bound_regions(&projection_ty);
-                let late_bound_in_ty =
-                    tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
-                debug!(?late_bound_in_trait_ref);
-                debug!(?late_bound_in_ty);
-
-                // FIXME: point at the type params that don't have appropriate lifetimes:
-                // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
-                //                         ----  ----     ^^^^^^^
-                self.validate_late_bound_regions(
-                    late_bound_in_trait_ref,
-                    late_bound_in_ty,
-                    |br_name| {
-                        struct_span_err!(
-                            tcx.sess,
-                            binding.span,
-                            E0582,
-                            "binding for associated type `{}` references {}, \
-                             which does not appear in the trait input types",
-                            binding.item_name,
-                            br_name
-                        )
-                    },
-                );
-            }
-        }
-
-        match binding.kind {
-            ConvertedBindingKind::Equality(..) if return_type_notation => {
-                return Err(self.tcx().sess.emit_err(
-                    crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
-                ));
-            }
-            ConvertedBindingKind::Equality(mut term) => {
-                // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
-                // the "projection predicate" for:
-                //
-                // `<T as Iterator>::Item = u32`
-                let assoc_item_def_id = projection_ty.skip_binder().def_id;
-                let def_kind = tcx.def_kind(assoc_item_def_id);
-                match (def_kind, term.unpack()) {
-                    (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
-                    | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (),
-                    (_, _) => {
-                        let got = if let Some(_) = term.ty() { "type" } else { "constant" };
-                        let expected = tcx.def_descr(assoc_item_def_id);
-                        let mut err = tcx.sess.struct_span_err(
-                            binding.span,
-                            format!("expected {expected} bound, found {got}"),
-                        );
-                        err.span_note(
-                            tcx.def_span(assoc_item_def_id),
-                            format!("{expected} defined here"),
-                        );
-
-                        if let hir::def::DefKind::AssocConst = def_kind
-                          && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
-                          && tcx.features().associated_const_equality {
-                            err.span_suggestion(
-                                binding.span,
-                                "if equating a const, try wrapping with braces",
-                                format!("{} = {{ const }}", binding.item_name),
-                                Applicability::HasPlaceholders,
-                            );
-                        }
-                        let reported = err.emit();
-                        term = match def_kind {
-                            hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(),
-                            hir::def::DefKind::AssocConst => tcx
-                                .const_error(
-                                    tcx.type_of(assoc_item_def_id)
-                                        .subst(tcx, projection_ty.skip_binder().substs),
-                                    reported,
-                                )
-                                .into(),
-                            _ => unreachable!(),
-                        };
-                    }
-                }
-                bounds.push_projection_bound(
-                    tcx,
-                    projection_ty
-                        .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
-                    binding.span,
-                );
-            }
-            ConvertedBindingKind::Constraint(ast_bounds) => {
-                // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
-                //
-                // `<T as Iterator>::Item: Debug`
-                //
-                // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
-                // parameter to have a skipped binder.
-                //
-                // NOTE: If `only_self_bounds` is true, do NOT expand this associated
-                // type bound into a trait predicate, since we only want to add predicates
-                // for the `Self` type.
-                if !only_self_bounds.0 {
-                    let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
-                    self.add_bounds(
-                        param_ty,
-                        ast_bounds.iter(),
-                        bounds,
-                        projection_ty.bound_vars(),
-                        only_self_bounds,
-                    );
-                }
-            }
-        }
-        Ok(())
-    }
-
     fn ast_path_to_ty(
         &self,
         span: Span,
@@ -1509,7 +945,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         let mut trait_bounds = vec![];
         let mut projection_bounds = vec![];
-        for (pred, span) in bounds.predicates() {
+        for (clause, span) in bounds.predicates() {
+            let pred: ty::Predicate<'tcx> = clause.to_predicate(tcx);
             let bound_pred = pred.kind();
             match bound_pred.skip_binder() {
                 ty::PredicateKind::Clause(clause) => match clause {
@@ -1527,15 +964,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ty::Clause::TypeOutlives(_) => {
                         // Do nothing, we deal with regions separately
                     }
-                    ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(),
+                    ty::Clause::RegionOutlives(_)
+                    | ty::Clause::ConstArgHasType(..)
+                    | ty::Clause::WellFormed(_)
+                    | ty::Clause::ConstEvaluatable(_) => bug!(),
                 },
-                ty::PredicateKind::WellFormed(_)
-                | ty::PredicateKind::AliasRelate(..)
+                ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ObjectSafe(_)
                 | ty::PredicateKind::ClosureKind(_, _, _)
                 | ty::PredicateKind::Subtype(_)
                 | ty::PredicateKind::Coerce(_)
-                | ty::PredicateKind::ConstEvaluatable(_)
                 | ty::PredicateKind::ConstEquate(_, _)
                 | ty::PredicateKind::TypeWellFormedFromEnv(_)
                 | ty::PredicateKind::Ambiguous => bug!(),
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 686066abbf0..8a318e984d7 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -2,6 +2,7 @@
 //! `ty` form from the HIR.
 
 use rustc_hir::LangItem;
+use rustc_middle::ty::Binder;
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
 use rustc_span::Span;
 
@@ -23,52 +24,58 @@ use rustc_span::Span;
 /// include the self type (e.g., `trait_bounds`) but in others we do not
 #[derive(Default, PartialEq, Eq, Clone, Debug)]
 pub struct Bounds<'tcx> {
-    pub predicates: Vec<(ty::Predicate<'tcx>, Span)>,
+    pub predicates: Vec<(Binder<'tcx, ty::Clause<'tcx>>, Span)>,
 }
 
 impl<'tcx> Bounds<'tcx> {
     pub fn push_region_bound(
         &mut self,
-        tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxt<'tcx>,
         region: ty::PolyTypeOutlivesPredicate<'tcx>,
         span: Span,
     ) {
-        self.predicates.push((region.to_predicate(tcx), span));
+        self.predicates.push((region.map_bound(|p| ty::Clause::TypeOutlives(p)), span));
     }
 
     pub fn push_trait_bound(
         &mut self,
-        tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxt<'tcx>,
         trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
         constness: ty::BoundConstness,
         polarity: ty::ImplPolarity,
     ) {
         self.predicates.push((
-            trait_ref
-                .map_bound(|trait_ref| ty::TraitPredicate { trait_ref, constness, polarity })
-                .to_predicate(tcx),
+            trait_ref.map_bound(|trait_ref| {
+                ty::Clause::Trait(ty::TraitPredicate { trait_ref, constness, polarity })
+            }),
             span,
         ));
     }
 
     pub fn push_projection_bound(
         &mut self,
-        tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxt<'tcx>,
         projection: ty::PolyProjectionPredicate<'tcx>,
         span: Span,
     ) {
-        self.predicates.push((projection.to_predicate(tcx), span));
+        self.predicates.push((projection.map_bound(|proj| ty::Clause::Projection(proj)), span));
     }
 
     pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
         let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
         let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]);
         // Preferable to put this obligation first, since we report better errors for sized ambiguity.
-        self.predicates.insert(0, (trait_ref.without_const().to_predicate(tcx), span));
+        self.predicates.insert(
+            0,
+            (
+                ty::Binder::dummy(ty::Clause::Trait(trait_ref.without_const().to_predicate(tcx))),
+                span,
+            ),
+        );
     }
 
-    pub fn predicates(&self) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + '_ {
+    pub fn predicates(&self) -> impl Iterator<Item = (Binder<'tcx, ty::Clause<'tcx>>, Span)> + '_ {
         self.predicates.iter().cloned()
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 17be5fe66cf..c09734d6e69 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -439,7 +439,8 @@ fn check_opaque_meets_bounds<'tcx>(
     // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
     // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
     // hidden type is well formed even without those bounds.
-    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into()));
+    let predicate =
+        ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(hidden_ty.into())));
     ocx.register_obligation(Obligation::new(tcx, misc_cause, param_env, predicate));
 
     // Check that all obligations are satisfied by the implementation's
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 4fbe68b8b6c..838b212ef87 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -321,7 +321,9 @@ fn compare_method_predicate_entailment<'tcx>(
             infcx.tcx,
             ObligationCause::dummy(),
             param_env,
-            ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
+            ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(
+                unnormalized_impl_fty.into(),
+            ))),
         ));
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index f93f395caed..73a7ba005b3 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -81,7 +81,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
             self.tcx(),
             cause,
             param_env,
-            ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
+            ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))),
         ));
     }
 }
@@ -1032,9 +1032,9 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b
                     tcx,
                     cause,
                     wfcx.param_env,
-                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
+                    ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(
                         ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
-                    )),
+                    ))),
                 ));
             }
         }
@@ -1876,7 +1876,8 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
             // We lower empty bounds like `Vec<dyn Copy>:` as
             // `WellFormed(Vec<dyn Copy>)`, which will later get checked by
             // regular WF checking
-            if let ty::PredicateKind::WellFormed(..) = pred.kind().skip_binder() {
+            if let ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) = pred.kind().skip_binder()
+            {
                 continue;
             }
             // Match the existing behavior.
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 90e8e523ea3..0479efceaad 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -3,6 +3,7 @@ use crate::astconv::{AstConv, OnlySelfBounds};
 use rustc_hir as hir;
 use rustc_infer::traits::util;
 use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
@@ -44,7 +45,12 @@ fn associated_type_bounds<'tcx>(
         }
     });
 
-    let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent));
+    let all_bounds = tcx.arena.alloc_from_iter(
+        bounds
+            .predicates()
+            .map(|(clause, span)| (clause.to_predicate(tcx), span))
+            .chain(bounds_from_parent),
+    );
     debug!(
         "associated_type_bounds({}) = {:?}",
         tcx.def_path_str(assoc_item_def_id.to_def_id()),
@@ -72,7 +78,9 @@ 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.predicates())
+        tcx.arena.alloc_from_iter(
+            bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)),
+        )
     })
 }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index dcb57902928..c905db06174 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -126,7 +126,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         predicates.extend(
             icx.astconv()
                 .compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
-                .predicates(),
+                .predicates()
+                .map(|(clause, span)| (clause.to_predicate(tcx), span)),
         );
     }
 
@@ -175,7 +176,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     param.span,
                 );
                 trace!(?bounds);
-                predicates.extend(bounds.predicates());
+                predicates.extend(
+                    bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)),
+                );
                 trace!(?predicates);
             }
             GenericParamKind::Const { .. } => {
@@ -219,7 +222,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     } else {
                         let span = bound_pred.bounded_ty.span;
                         let predicate = ty::Binder::bind_with_vars(
-                            ty::PredicateKind::WellFormed(ty.into()),
+                            ty::PredicateKind::Clause(ty::Clause::WellFormed(ty.into())),
                             bound_vars,
                         );
                         predicates.insert((predicate.to_predicate(tcx), span));
@@ -234,7 +237,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     bound_vars,
                     OnlySelfBounds(false),
                 );
-                predicates.extend(bounds.predicates());
+                predicates.extend(
+                    bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)),
+                );
             }
 
             hir::WherePredicate::RegionPredicate(region_pred) => {
@@ -353,7 +358,7 @@ fn const_evaluatable_predicates_of(
             if let ty::ConstKind::Unevaluated(_) = ct.kind() {
                 let span = self.tcx.def_span(c.def_id);
                 self.preds.insert((
-                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
+                    ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)))
                         .to_predicate(self.tcx),
                     span,
                 ));
@@ -658,8 +663,12 @@ pub(super) fn implied_predicates_with_filter(
     };
 
     // Combine the two lists to form the complete set of superbounds:
-    let implied_bounds =
-        &*tcx.arena.alloc_from_iter(superbounds.predicates().chain(where_bounds_that_match));
+    let implied_bounds = &*tcx.arena.alloc_from_iter(
+        superbounds
+            .predicates()
+            .map(|(clause, span)| (clause.to_predicate(tcx), span))
+            .chain(where_bounds_that_match),
+    );
     debug!(?implied_bounds);
 
     // Now require that immediate supertraits are converted, which will, in
@@ -816,7 +825,7 @@ impl<'tcx> ItemCtxt<'tcx> {
             );
         }
 
-        bounds.predicates().collect()
+        bounds.predicates().map(|(clause, span)| (clause.to_predicate(self.tcx), span)).collect()
     }
 
     #[instrument(level = "trace", skip(self))]
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index a653a652231..f2618b3daf1 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -79,7 +79,7 @@ fn diagnostic_hir_wf_check<'tcx>(
                 self.tcx,
                 cause,
                 self.param_env,
-                ty::PredicateKind::WellFormed(tcx_ty.into()),
+                ty::PredicateKind::Clause(ty::Clause::WellFormed(tcx_ty.into())),
             ));
 
             for error in ocx.select_all_or_error() {
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index e84da2519ae..201cb94f0b3 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -542,12 +542,12 @@ fn trait_predicate_kind<'tcx>(
         | ty::PredicateKind::Clause(ty::Clause::Projection(_))
         | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
         | ty::PredicateKind::AliasRelate(..)
-        | ty::PredicateKind::WellFormed(_)
+        | ty::PredicateKind::Clause(ty::Clause::WellFormed(_))
         | ty::PredicateKind::Subtype(_)
         | ty::PredicateKind::Coerce(_)
         | ty::PredicateKind::ObjectSafe(_)
         | ty::PredicateKind::ClosureKind(..)
-        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 7ce48fe1c01..79c56490f3c 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -55,13 +55,13 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     ty::PredicateKind::Clause(ty::Clause::Trait(..))
                     | ty::PredicateKind::Clause(ty::Clause::Projection(..))
                     | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-                    | ty::PredicateKind::WellFormed(..)
+                    | ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
                     | ty::PredicateKind::AliasRelate(..)
                     | ty::PredicateKind::ObjectSafe(..)
                     | ty::PredicateKind::ClosureKind(..)
                     | ty::PredicateKind::Subtype(..)
                     | ty::PredicateKind::Coerce(..)
-                    | ty::PredicateKind::ConstEvaluatable(..)
+                    | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
                     | ty::PredicateKind::ConstEquate(..)
                     | ty::PredicateKind::Ambiguous
                     | ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index fb56b7e74cb..34f98f4310e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -483,7 +483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.tcx,
             cause,
             self.param_env,
-            ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
+            ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))),
         ));
     }
 
@@ -668,10 +668,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
                 | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
-                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::AliasRelate(..)
-                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
                 | ty::PredicateKind::ConstEquate(..)
                 // N.B., this predicate is created by breaking down a
                 // `ClosureType: FnFoo()` predicate, where
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index 3efdab53438..2135643cbeb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -32,7 +32,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => {
                 vec![ty.into(), arg.into()]
             }
-            ty::PredicateKind::ConstEvaluatable(e) => vec![e.into()],
+            ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(e)) => vec![e.into()],
             _ => return false,
         };
 
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 6f4d674ba10..cca97d10517 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -452,7 +452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             tcx,
             obligation.cause,
             self.param_env,
-            ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
+            ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(method_ty.into()))),
         ));
 
         let callee = MethodCallee { def_id, substs, sig: fn_sig };
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index b7b11ff8942..91347c01327 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -838,11 +838,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::Clause(ty::Clause::Projection(..))
                 | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
-                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
-                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::AliasRelate(..)
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 7a484e7ddc5..66e771b794a 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -696,7 +696,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 };
 
                 // Don't point out the span of `WellFormed` predicates.
-                if !matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) {
+                if !matches!(
+                    p.kind().skip_binder(),
+                    ty::PredicateKind::Clause(ty::Clause::Projection(..) | ty::Clause::Trait(..))
+                ) {
                     continue;
                 };
 
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index bb2bd2faec2..152c56572b6 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -417,7 +417,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
                 self.tcx(),
                 self.trace.cause.clone(),
                 self.param_env,
-                ty::Binder::dummy(ty::PredicateKind::WellFormed(b_ty.into())),
+                ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(b_ty.into()))),
             ));
         }
 
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 8a44d503159..c1f0b9253a5 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -29,11 +29,11 @@ pub fn explicit_outlives_bounds<'tcx>(
             | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::Subtype(..)
-            | ty::PredicateKind::WellFormed(..)
+            | ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
             | ty::PredicateKind::ObjectSafe(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
-            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 74a78f38024..5622062ef7e 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -227,7 +227,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
                 debug!(?data, ?obligations, "super_predicates");
                 self.extend_deduped(obligations);
             }
-            ty::PredicateKind::WellFormed(..) => {
+            ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) => {
                 // Currently, we do not elaborate WF predicates,
                 // although we easily could.
             }
@@ -249,7 +249,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
             ty::PredicateKind::ClosureKind(..) => {
                 // Nothing to elaborate when waiting for a closure's kind to be inferred.
             }
-            ty::PredicateKind::ConstEvaluatable(..) => {
+            ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) => {
                 // Currently, we do not elaborate const-evaluatable
                 // predicates.
             }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index f02f3668dc1..785adc0b4fb 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1610,13 +1610,13 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     Clause(Clause::Projection(..)) |
                     AliasRelate(..) |
                     // Ignore bounds that a user can't type
-                    WellFormed(..) |
+                    Clause(Clause::WellFormed(..)) |
+                    // FIXME(generic_const_exprs): `ConstEvaluatable` can be written
+                    Clause(Clause::ConstEvaluatable(..)) |
                     ObjectSafe(..) |
                     ClosureKind(..) |
                     Subtype(..) |
                     Coerce(..) |
-                    // FIXME(generic_const_exprs): `ConstEvaluatable` can be written
-                    ConstEvaluatable(..) |
                     ConstEquate(..) |
                     Ambiguous |
                     TypeWellFormedFromEnv(..) => continue,
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 9d70dbfa072..7722e7b47cf 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -26,7 +26,7 @@ struct Cache {
     predecessors: OnceCell<Predecessors>,
     switch_sources: OnceCell<SwitchSources>,
     is_cyclic: OnceCell<bool>,
-    postorder: OnceCell<Vec<BasicBlock>>,
+    reverse_postorder: OnceCell<Vec<BasicBlock>>,
     dominators: OnceCell<Dominators<BasicBlock>>,
 }
 
@@ -62,11 +62,14 @@ impl<'tcx> BasicBlocks<'tcx> {
         })
     }
 
-    /// Returns basic blocks in a postorder.
+    /// Returns basic blocks in a reverse postorder.
     #[inline]
-    pub fn postorder(&self) -> &[BasicBlock] {
-        self.cache.postorder.get_or_init(|| {
-            Postorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect()
+    pub fn reverse_postorder(&self) -> &[BasicBlock] {
+        self.cache.reverse_postorder.get_or_init(|| {
+            let mut rpo: Vec<_> =
+                Postorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect();
+            rpo.reverse();
+            rpo
         })
     }
 
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index e929240bf30..6aa20dbed92 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -145,7 +145,7 @@ impl MirPhase {
             }
             "analysis" => Self::Analysis(AnalysisPhase::parse(phase)),
             "runtime" => Self::Runtime(RuntimePhase::parse(phase)),
-            _ => panic!("Unknown MIR dialect {}", dialect),
+            _ => bug!("Unknown MIR dialect: '{}'", dialect),
         }
     }
 }
@@ -159,7 +159,7 @@ impl AnalysisPhase {
         match &*phase.to_ascii_lowercase() {
             "initial" => Self::Initial,
             "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
-            _ => panic!("Unknown analysis phase {}", phase),
+            _ => bug!("Unknown analysis phase: '{}'", phase),
         }
     }
 }
@@ -174,7 +174,7 @@ impl RuntimePhase {
             "initial" => Self::Initial,
             "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
             "optimized" => Self::Optimized,
-            _ => panic!("Unknown runtime phase {}", phase),
+            _ => bug!("Unknown runtime phase: '{}'", phase),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 6b036194381..730c551576a 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -15,8 +15,9 @@ const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT B
 const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET`
 const NEW_LINE_SPAN: &str = "</span>\n<span class=\"line\">";
 const HEADER: &str = r#"<!DOCTYPE html>
-<html>
-<head>"#;
+<html lang="en">
+<head>
+<meta charset="utf-8">"#;
 const START_BODY: &str = r#"</head>
 <body>"#;
 const FOOTER: &str = r#"</body>
diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs
index 99ead14139a..ec16a8470c4 100644
--- a/compiler/rustc_middle/src/mir/traversal.rs
+++ b/compiler/rustc_middle/src/mir/traversal.rs
@@ -188,10 +188,6 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
     }
 }
 
-pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> {
-    Postorder::new(&body.basic_blocks, START_BLOCK)
-}
-
 impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
     type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
 
@@ -219,6 +215,17 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
     }
 }
 
+/// Creates an iterator over the `Body`'s basic blocks, that:
+/// - returns basic blocks in a postorder,
+/// - traverses the `BasicBlocks` CFG cache's reverse postorder backwards, and does not cache the
+///   postorder itself.
+pub fn postorder<'a, 'tcx>(
+    body: &'a Body<'tcx>,
+) -> impl Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> + ExactSizeIterator + DoubleEndedIterator
+{
+    reverse_postorder(body).rev()
+}
+
 /// Reverse postorder traversal of a graph
 ///
 /// Reverse postorder is the reverse order of a postorder traversal.
@@ -295,34 +302,12 @@ pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet<BasicBlock> {
     iter.visited
 }
 
-#[derive(Clone)]
-pub struct ReversePostorderIter<'a, 'tcx> {
+/// Creates an iterator over the `Body`'s basic blocks, that:
+/// - returns basic blocks in a reverse postorder,
+/// - makes use of the `BasicBlocks` CFG cache's reverse postorder.
+pub fn reverse_postorder<'a, 'tcx>(
     body: &'a Body<'tcx>,
-    blocks: &'a [BasicBlock],
-    idx: usize,
-}
-
-impl<'a, 'tcx> Iterator for ReversePostorderIter<'a, 'tcx> {
-    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
-
-    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
-        if self.idx == 0 {
-            return None;
-        }
-        self.idx -= 1;
-
-        self.blocks.get(self.idx).map(|&bb| (bb, &self.body[bb]))
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (self.idx, Some(self.idx))
-    }
-}
-
-impl<'a, 'tcx> ExactSizeIterator for ReversePostorderIter<'a, 'tcx> {}
-
-pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> {
-    let blocks = body.basic_blocks.postorder();
-    let len = blocks.len();
-    ReversePostorderIter { body, blocks, idx: len }
+) -> impl Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> + ExactSizeIterator + DoubleEndedIterator
+{
+    body.basic_blocks.reverse_postorder().iter().map(|&bb| (bb, &body.basic_blocks[bb]))
 }
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 9cce9d64d5d..684af1abdf6 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -270,14 +270,14 @@ impl FlagComputation {
                 self.add_alias_ty(projection_ty);
                 self.add_term(term);
             }
-            ty::PredicateKind::WellFormed(arg) => {
+            ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => {
                 self.add_substs(slice::from_ref(&arg));
             }
             ty::PredicateKind::ObjectSafe(_def_id) => {}
             ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
                 self.add_substs(substs);
             }
-            ty::PredicateKind::ConstEvaluatable(uv) => {
+            ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(uv)) => {
                 self.add_const(uv);
             }
             ty::PredicateKind::ConstEquate(expected, found) => {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ff5d99794f1..66aba98fe29 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -523,7 +523,7 @@ impl<'tcx> Predicate<'tcx> {
             ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
                 tcx.trait_is_coinductive(data.def_id())
             }
-            ty::PredicateKind::WellFormed(_) => true,
+            ty::PredicateKind::Clause(ty::Clause::WellFormed(_)) => true,
             _ => false,
         }
     }
@@ -536,7 +536,7 @@ impl<'tcx> Predicate<'tcx> {
     #[inline]
     pub fn allow_normalization(self) -> bool {
         match self.kind().skip_binder() {
-            PredicateKind::WellFormed(_) => false,
+            PredicateKind::Clause(Clause::WellFormed(_)) => false,
             PredicateKind::Clause(Clause::Trait(_))
             | PredicateKind::Clause(Clause::RegionOutlives(_))
             | PredicateKind::Clause(Clause::TypeOutlives(_))
@@ -547,7 +547,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::ClosureKind(_, _, _)
             | PredicateKind::Subtype(_)
             | PredicateKind::Coerce(_)
-            | PredicateKind::ConstEvaluatable(_)
+            | PredicateKind::Clause(Clause::ConstEvaluatable(_))
             | PredicateKind::ConstEquate(_, _)
             | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(_) => true,
@@ -584,6 +584,12 @@ pub enum Clause<'tcx> {
     /// Ensures that a const generic argument to a parameter `const N: u8`
     /// is of type `u8`.
     ConstArgHasType(Const<'tcx>, Ty<'tcx>),
+
+    /// No syntax: `T` well-formed.
+    WellFormed(GenericArg<'tcx>),
+
+    /// Constant initializer must evaluate successfully.
+    ConstEvaluatable(ty::Const<'tcx>),
 }
 
 impl<'tcx> Binder<'tcx, Clause<'tcx>> {
@@ -610,9 +616,6 @@ pub enum PredicateKind<'tcx> {
     /// Prove a clause
     Clause(Clause<'tcx>),
 
-    /// No syntax: `T` well-formed.
-    WellFormed(GenericArg<'tcx>),
-
     /// Trait must be object-safe.
     ObjectSafe(DefId),
 
@@ -638,9 +641,6 @@ pub enum PredicateKind<'tcx> {
     /// logic.
     Coerce(CoercePredicate<'tcx>),
 
-    /// Constant initializer must evaluate successfully.
-    ConstEvaluatable(ty::Const<'tcx>),
-
     /// Constants must be equal. The first component is the const that is expected.
     ConstEquate(Const<'tcx>, Const<'tcx>),
 
@@ -1214,6 +1214,13 @@ impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> {
     }
 }
 
+impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, Clause<'tcx>> {
+    #[inline(always)]
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause)))
+    }
+}
+
 impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
@@ -1324,11 +1331,11 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
-            | PredicateKind::WellFormed(..)
+            | PredicateKind::Clause(Clause::WellFormed(..))
             | PredicateKind::ObjectSafe(..)
             | PredicateKind::ClosureKind(..)
             | PredicateKind::Clause(Clause::TypeOutlives(..))
-            | PredicateKind::ConstEvaluatable(..)
+            | PredicateKind::Clause(Clause::ConstEvaluatable(..))
             | PredicateKind::ConstEquate(..)
             | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
@@ -1345,11 +1352,11 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
-            | PredicateKind::WellFormed(..)
+            | PredicateKind::Clause(Clause::WellFormed(..))
             | PredicateKind::ObjectSafe(..)
             | PredicateKind::ClosureKind(..)
             | PredicateKind::Clause(Clause::TypeOutlives(..))
-            | PredicateKind::ConstEvaluatable(..)
+            | PredicateKind::Clause(Clause::ConstEvaluatable(..))
             | PredicateKind::ConstEquate(..)
             | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
@@ -1367,10 +1374,10 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
-            | PredicateKind::WellFormed(..)
+            | PredicateKind::Clause(Clause::WellFormed(..))
             | PredicateKind::ObjectSafe(..)
             | PredicateKind::ClosureKind(..)
-            | PredicateKind::ConstEvaluatable(..)
+            | PredicateKind::Clause(Clause::ConstEvaluatable(..))
             | PredicateKind::ConstEquate(..)
             | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
@@ -1384,10 +1391,8 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
-            | PredicateKind::WellFormed(..)
             | PredicateKind::ObjectSafe(..)
             | PredicateKind::ClosureKind(..)
-            | PredicateKind::ConstEvaluatable(..)
             | PredicateKind::ConstEquate(..)
             | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index f36b8ad8df6..4bfed74f705 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2877,7 +2877,7 @@ define_print_and_forward_display! {
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
                 p!("the constant `", print(ct), "` has type `", print(ty), "`")
             },
-            ty::PredicateKind::WellFormed(arg) => p!(print(arg), " well-formed"),
+            ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => p!(print(arg), " well-formed"),
             ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
             }
@@ -2886,7 +2886,7 @@ define_print_and_forward_display! {
                 print_value_path(closure_def_id, &[]),
                 write("` implements the trait `{}`", kind)
             ),
-            ty::PredicateKind::ConstEvaluatable(ct) => {
+            ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => {
                 p!("the constant `", print(ct), "` can be evaluated")
             }
             ty::PredicateKind::ConstEquate(c1, c2) => {
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index a965450d27d..a4a2fec07ec 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -179,6 +179,10 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
             ty::Clause::RegionOutlives(ref pair) => pair.fmt(f),
             ty::Clause::TypeOutlives(ref pair) => pair.fmt(f),
             ty::Clause::Projection(ref pair) => pair.fmt(f),
+            ty::Clause::WellFormed(ref data) => write!(f, "WellFormed({:?})", data),
+            ty::Clause::ConstEvaluatable(ct) => {
+                write!(f, "ConstEvaluatable({ct:?})")
+            }
         }
     }
 }
@@ -189,16 +193,12 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
             ty::PredicateKind::Clause(ref a) => a.fmt(f),
             ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
             ty::PredicateKind::Coerce(ref pair) => pair.fmt(f),
-            ty::PredicateKind::WellFormed(data) => write!(f, "WellFormed({:?})", data),
             ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 write!(f, "ObjectSafe({:?})", trait_def_id)
             }
             ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                 write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
             }
-            ty::PredicateKind::ConstEvaluatable(ct) => {
-                write!(f, "ConstEvaluatable({ct:?})")
-            }
             ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 write!(f, "TypeWellFormedFromEnv({:?})", ty)
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index d615c83d621..4fc45eaf522 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -409,8 +409,15 @@ where
         self.drop_ladder(fields, succ, unwind).0
     }
 
+    /// Drops the T contained in a `Box<T>` if it has not been moved out of
     #[instrument(level = "debug", ret)]
-    fn open_drop_for_box(&mut self, adt: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> BasicBlock {
+    fn open_drop_for_box_contents(
+        &mut self,
+        adt: ty::AdtDef<'tcx>,
+        substs: SubstsRef<'tcx>,
+        succ: BasicBlock,
+        unwind: Unwind,
+    ) -> BasicBlock {
         // drop glue is sent straight to codegen
         // box cannot be directly dereferenced
         let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), substs);
@@ -425,11 +432,7 @@ where
 
         let interior_path = self.elaborator.deref_subpath(self.path);
 
-        let succ = self.box_free_block(adt, substs, self.succ, self.unwind);
-        let unwind_succ =
-            self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup));
-
-        self.drop_subpath(interior, interior_path, succ, unwind_succ)
+        self.drop_subpath(interior, interior_path, succ, unwind)
     }
 
     #[instrument(level = "debug", ret)]
@@ -453,7 +456,15 @@ where
             self.open_drop_for_adt_contents(adt, substs)
         };
 
-        if adt.has_dtor(self.tcx()) {
+        if adt.is_box() {
+            // we need to drop the inside of the box before running the destructor
+            let succ = self.destructor_call_block(contents_drop);
+            let unwind = contents_drop
+                .1
+                .map(|unwind| self.destructor_call_block((unwind, Unwind::InCleanup)));
+
+            self.open_drop_for_box_contents(adt, substs, succ, unwind)
+        } else if adt.has_dtor(self.tcx()) {
             self.destructor_call_block(contents_drop)
         } else {
             contents_drop.0
@@ -650,7 +661,13 @@ where
             }),
             is_cleanup: unwind.is_cleanup(),
         };
-        self.elaborator.patch().new_block(result)
+
+        let destructor_block = self.elaborator.patch().new_block(result);
+
+        let block_start = Location { block: destructor_block, statement_index: 0 };
+        self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow);
+
+        self.drop_flag_test_block(destructor_block, succ, unwind)
     }
 
     /// Create a loop that drops an array:
@@ -851,13 +868,7 @@ where
                 self.open_drop_for_tuple(&tys)
             }
             ty::Tuple(fields) => self.open_drop_for_tuple(fields),
-            ty::Adt(def, substs) => {
-                if def.is_box() {
-                    self.open_drop_for_box(*def, substs)
-                } else {
-                    self.open_drop_for_adt(*def, substs)
-                }
-            }
+            ty::Adt(def, substs) => self.open_drop_for_adt(*def, substs),
             ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
             ty::Array(ety, size) => {
                 let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env());
@@ -905,65 +916,6 @@ where
         blk
     }
 
-    /// Creates a block that frees the backing memory of a `Box` if its drop is required (either
-    /// statically or by checking its drop flag).
-    ///
-    /// The contained value will not be dropped.
-    fn box_free_block(
-        &mut self,
-        adt: ty::AdtDef<'tcx>,
-        substs: SubstsRef<'tcx>,
-        target: BasicBlock,
-        unwind: Unwind,
-    ) -> BasicBlock {
-        let block = self.unelaborated_free_block(adt, substs, target, unwind);
-        self.drop_flag_test_block(block, target, unwind)
-    }
-
-    /// Creates a block that frees the backing memory of a `Box` (without dropping the contained
-    /// value).
-    fn unelaborated_free_block(
-        &mut self,
-        adt: ty::AdtDef<'tcx>,
-        substs: SubstsRef<'tcx>,
-        target: BasicBlock,
-        unwind: Unwind,
-    ) -> BasicBlock {
-        let tcx = self.tcx();
-        let unit_temp = Place::from(self.new_temp(tcx.mk_unit()));
-        let free_func = tcx.require_lang_item(LangItem::BoxFree, Some(self.source_info.span));
-        let args = adt
-            .variant(FIRST_VARIANT)
-            .fields
-            .iter()
-            .enumerate()
-            .map(|(i, f)| {
-                let field = FieldIdx::new(i);
-                let field_ty = f.ty(tcx, substs);
-                Operand::Move(tcx.mk_place_field(self.place, field, field_ty))
-            })
-            .collect();
-
-        let call = TerminatorKind::Call {
-            func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
-            args,
-            destination: unit_temp,
-            target: Some(target),
-            unwind: if unwind.is_cleanup() {
-                UnwindAction::Terminate
-            } else {
-                UnwindAction::Continue
-            },
-            from_hir_call: false,
-            fn_span: self.source_info.span,
-        }; // FIXME(#43234)
-        let free_block = self.new_block(unwind, call);
-
-        let block_start = Location { block: free_block, statement_index: 0 };
-        self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow);
-        free_block
-    }
-
     fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
         let block = TerminatorKind::Drop {
             place: self.place,
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index fd349c07040..856327e6ce6 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -9,7 +9,6 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::{Ty, TyCtxt, TypeAndMut};
 use rustc_session::Session;
-use rustc_target::spec::PanicStrategy;
 
 pub struct CheckAlignment;
 
@@ -241,11 +240,10 @@ fn insert_alignment_check<'tcx>(
                 required: Operand::Copy(alignment),
                 found: Operand::Copy(addr),
             }),
-            unwind: if tcx.sess.panic_strategy() == PanicStrategy::Unwind {
-                UnwindAction::Terminate
-            } else {
-                UnwindAction::Unreachable
-            },
+            // The panic symbol that this calls is #[rustc_nounwind]. We never want to insert an
+            // unwind into unsafe code, because unwinding could make a failing UB check turn into
+            // much worse UB when we start unwinding.
+            unwind: UnwindAction::Unreachable,
         },
     });
 }
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 1d43dbda0aa..2f2c7357b00 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -118,8 +118,8 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
 
         // Traverse the body in reverse post-order, to ensure that `FullConstProp` locals are
         // assigned before being read.
-        let postorder = body.basic_blocks.postorder().to_vec();
-        for bb in postorder.into_iter().rev() {
+        let rpo = body.basic_blocks.reverse_postorder().to_vec();
+        for bb in rpo {
             let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
             optimization_finder.visit_basic_block_data(bb, data);
         }
diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs
index 6f46974ea00..745fa30841c 100644
--- a/compiler/rustc_mir_transform/src/prettify.rs
+++ b/compiler/rustc_mir_transform/src/prettify.rs
@@ -24,7 +24,7 @@ impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let rpo: IndexVec<BasicBlock, BasicBlock> =
-            body.basic_blocks.postorder().iter().copied().rev().collect();
+            body.basic_blocks.reverse_postorder().iter().copied().collect();
         if rpo.iter().is_sorted() {
             return;
         }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index f4ee7b75875..4a5953c1149 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -123,12 +123,6 @@
 //! pointers to these functions even if they never get called anywhere. This can
 //! be seen as a special case of taking a function reference.
 //!
-//! #### Boxes
-//! Since `Box` expression have special compiler support, no explicit calls to
-//! `exchange_malloc()` and `box_free()` may show up in MIR, even if the
-//! compiler will generate them. We have to observe `Rvalue::Box` expressions
-//! and Box-typed drop-statements for that purpose.
-//!
 //!
 //! Interaction with Cross-Crate Inlining
 //! -------------------------------------
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 5ef11acadce..620aef9883b 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -182,8 +182,8 @@ where
                 ct.visit_with(self)?;
                 ty.visit_with(self)
             }
-            ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self),
-            ty::PredicateKind::WellFormed(arg) => arg.visit_with(self),
+            ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => ct.visit_with(self),
+            ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => arg.visit_with(self),
 
             ty::PredicateKind::ObjectSafe(_)
             | ty::PredicateKind::ClosureKind(_, _, _)
@@ -1270,13 +1270,13 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
             );
 
             for (pred, _) in bounds.predicates() {
-                match pred.kind().skip_binder() {
-                    ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
+                match pred.skip_binder() {
+                    ty::Clause::Trait(trait_predicate) => {
                         if self.visit_trait(trait_predicate.trait_ref).is_break() {
                             return;
                         }
                     }
-                    ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) => {
+                    ty::Clause::Projection(proj_predicate) => {
                         let term = self.visit(proj_predicate.term);
                         if term.is_break()
                             || self.visit_projection_ty(proj_predicate.projection_ty).is_break()
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 19d986a3152..bd39cbf17ce 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -432,7 +432,6 @@ symbols! {
         bool,
         borrowck_graphviz_format,
         borrowck_graphviz_postflow,
-        box_free,
         box_new,
         box_patterns,
         box_syntax,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 8592fc164d0..8625958ff5a 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -319,14 +319,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                 ty::PredicateKind::ObjectSafe(trait_def_id) => {
                     self.compute_object_safe_goal(trait_def_id)
                 }
-                ty::PredicateKind::WellFormed(arg) => {
+                ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => {
                     self.compute_well_formed_goal(Goal { param_env, predicate: arg })
                 }
                 ty::PredicateKind::Ambiguous => {
                     self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
                 }
                 // FIXME: implement this predicate :)
-                ty::PredicateKind::ConstEvaluatable(_) => {
+                ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(_)) => {
                     self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 }
                 ty::PredicateKind::ConstEquate(_, _) => {
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 212327448c8..65c8d9c8f69 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -119,10 +119,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
                                     )
                                 }
                                 ty::PredicateKind::Clause(_)
-                                | ty::PredicateKind::WellFormed(_)
                                 | ty::PredicateKind::ObjectSafe(_)
                                 | ty::PredicateKind::ClosureKind(_, _, _)
-                                | ty::PredicateKind::ConstEvaluatable(_)
                                 | ty::PredicateKind::Ambiguous => {
                                     FulfillmentErrorCode::CodeSelectionError(
                                         SelectionError::Unimplemented,
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 62d2aad5277..56fde8cd70c 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -826,14 +826,14 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 // we start out with a `ParamEnv` with no inference variables,
                 // and these don't correspond to adding any new bounds to
                 // the `ParamEnv`.
-                ty::PredicateKind::WellFormed(..)
+                ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
                 | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
                 | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
                 // FIXME(generic_const_exprs): you can absolutely add this as a where clauses
-                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
                 | ty::PredicateKind::Coerce(..) => {}
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("predicate should only exist in the environment: {bound_predicate:?}")
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index bd1ea43a78e..f8789b554b1 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -207,7 +207,7 @@ fn satisfied_from_param_env<'tcx>(
 
     for pred in param_env.caller_bounds() {
         match pred.kind().skip_binder() {
-            ty::PredicateKind::ConstEvaluatable(ce) => {
+            ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ce)) => {
                 let b_ct = tcx.expand_abstract_consts(ce);
                 let mut v = Visitor { ct, infcx, param_env, single_match };
                 let _ = b_ct.visit_with(&mut v);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index ffbe2888bf8..398ec28a426 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1048,7 +1048,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         self.report_closure_error(&obligation, closure_def_id, found_kind, kind)
                     }
 
-                    ty::PredicateKind::WellFormed(ty) => {
+                    ty::PredicateKind::Clause(ty::Clause::WellFormed(ty)) => {
                         match self.tcx.sess.opts.unstable_opts.trait_solver {
                             TraitSolver::Classic => {
                                 // WF predicates cannot themselves make
@@ -1069,7 +1069,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         }
                     }
 
-                    ty::PredicateKind::ConstEvaluatable(..) => {
+                    ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) => {
                         // Errors for `ConstEvaluatable` predicates show up as
                         // `SelectionError::ConstEvalFailure`,
                         // not `Unimplemented`.
@@ -2415,7 +2415,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 err
             }
 
-            ty::PredicateKind::WellFormed(arg) => {
+            ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
                 if arg.references_error()
@@ -2487,7 +2487,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
             }
 
-            ty::PredicateKind::ConstEvaluatable(data) => {
+            ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(data)) => {
                 if predicate.references_error() || self.tainted_by_errors().is_some() {
                     return;
                 }
@@ -3325,7 +3325,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         }
 
         match obligation.predicate.kind().skip_binder() {
-            ty::PredicateKind::ConstEvaluatable(ct) => {
+            ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => {
                 let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
                     bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
                 };
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 88d2091de0f..6e4bda3df03 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -354,12 +354,12 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
                 | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
                 | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-                | ty::PredicateKind::WellFormed(_)
+                | ty::PredicateKind::Clause(ty::Clause::WellFormed(_))
                 | ty::PredicateKind::ObjectSafe(_)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(_)
                 | ty::PredicateKind::Coerce(_)
-                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
                 | ty::PredicateKind::ConstEquate(..) => {
                     let pred =
                         ty::Binder::dummy(infcx.instantiate_binder_with_placeholders(binder));
@@ -433,7 +433,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     }
                 }
 
-                ty::PredicateKind::WellFormed(arg) => {
+                ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => {
                     match wf::obligations(
                         self.selcx.infcx,
                         obligation.param_env,
@@ -498,7 +498,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     }
                 }
 
-                ty::PredicateKind::ConstEvaluatable(uv) => {
+                ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(uv)) => {
                     match const_evaluatable::is_const_evaluatable(
                         self.selcx.infcx,
                         uv,
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index b2771915eef..8c42df6e012 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -310,7 +310,7 @@ fn predicate_references_self<'tcx>(
 
         ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"),
 
-        ty::PredicateKind::WellFormed(..)
+        ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
         | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
@@ -318,7 +318,7 @@ fn predicate_references_self<'tcx>(
         | ty::PredicateKind::Subtype(..)
         | ty::PredicateKind::Coerce(..)
         // FIXME(generic_const_exprs): this can mention `Self`
-        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
@@ -361,11 +361,11 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         | ty::PredicateKind::Subtype(..)
         | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
-        | ty::PredicateKind::WellFormed(..)
+        | ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
-        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::AliasRelate(..)
         | ty::PredicateKind::Ambiguous
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
index 01d7a1e7913..7405ca31cde 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
@@ -67,7 +67,8 @@ fn relate_mir_and_user_ty<'tcx>(
     ocx.eq(&cause, param_env, mir_ty, user_ty)?;
 
     // FIXME(#104764): We should check well-formedness before normalization.
-    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
+    let predicate =
+        ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(user_ty.into())));
     ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
     Ok(())
 }
@@ -119,7 +120,9 @@ fn relate_mir_and_user_substs<'tcx>(
         let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
 
         ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
-        let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
+        let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(
+            impl_self_ty.into(),
+        )));
         ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
     }
 
@@ -134,7 +137,7 @@ fn relate_mir_and_user_substs<'tcx>(
     // them?  This would only be relevant if some input
     // type were ill-formed but did not appear in `ty`,
     // which...could happen with normalization...
-    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
+    let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(ty.into())));
     ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
     Ok(())
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 9989fc9c479..8761f4fea6c 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -130,14 +130,14 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
                 | ty::PredicateKind::Clause(ty::Clause::Projection(..))
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::ObjectSafe(..)
-                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
 
                 // We need to search through *all* WellFormed predicates
-                ty::PredicateKind::WellFormed(arg) => {
+                ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => {
                     wf_args.push(arg);
                 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index e72d3ca97d7..ca2ae9b5235 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -674,7 +674,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
 
-                ty::PredicateKind::WellFormed(arg) => {
+                ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => {
                     // So, there is a bit going on here. First, `WellFormed` predicates
                     // are coinductive, like trait predicates with auto traits.
                     // This means that we need to detect if we have recursively
@@ -862,7 +862,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
 
-                ty::PredicateKind::ConstEvaluatable(uv) => {
+                ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(uv)) => {
                     match const_evaluatable::is_const_evaluatable(
                         self.infcx,
                         uv,
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 92d899b0f13..676978fabe4 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -160,11 +160,11 @@ pub fn predicate_obligations<'tcx>(
             wf.compute(ct.into());
             wf.compute(ty.into());
         }
-        ty::PredicateKind::WellFormed(arg) => {
+        ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => {
             wf.compute(arg);
         }
 
-        ty::PredicateKind::ConstEvaluatable(ct) => {
+        ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)) => {
             wf.compute(ct.into());
         }
 
@@ -386,7 +386,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                         cause,
                         depth,
                         param_env,
-                        ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
+                        ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))),
                     )
                 }),
         );
@@ -478,7 +478,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                         cause.clone(),
                         depth,
                         param_env,
-                        ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
+                        ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))),
                     )
                 }),
         );
@@ -521,8 +521,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                                 let obligations = self.nominal_obligations(uv.def, uv.substs);
                                 self.out.extend(obligations);
 
-                                let predicate =
-                                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
+                                let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
+                                    ty::Clause::ConstEvaluatable(ct),
+                                ));
                                 let cause = self.cause(traits::WellFormed(None));
                                 self.out.push(traits::Obligation::with_depth(
                                     self.tcx(),
@@ -541,7 +542,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                                 cause,
                                 self.recursion_depth,
                                 self.param_env,
-                                ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())),
+                                ty::Binder::dummy(ty::PredicateKind::Clause(
+                                    ty::Clause::WellFormed(ct.into()),
+                                )),
                             ));
                         }
                         ty::ConstKind::Expr(_) => {
@@ -552,8 +555,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                             // the future we may allow directly lowering to `ConstKind::Expr` in which case
                             // we would not be proving bounds we should.
 
-                            let predicate =
-                                ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
+                            let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
+                                ty::Clause::ConstEvaluatable(ct),
+                            ));
                             let cause = self.cause(traits::WellFormed(None));
                             self.out.push(traits::Obligation::with_depth(
                                 self.tcx(),
@@ -784,7 +788,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                         cause,
                         self.recursion_depth,
                         param_env,
-                        ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())),
+                        ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(
+                            ty.into(),
+                        ))),
                     ));
                 }
             }
@@ -969,11 +975,11 @@ pub(crate) fn required_region_bounds<'tcx>(
                 | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::Coerce(..)
-                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
-                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::AliasRelate(..)
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index f9a7c8c386a..1d4219bc0c0 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -122,7 +122,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                         predicate.lower_into(interner),
                     ))
                 }
-                ty::PredicateKind::WellFormed(arg) => match arg.unpack() {
+                ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => match arg.unpack() {
                     ty::GenericArgKind::Type(ty) => chalk_ir::DomainGoal::WellFormed(
                         chalk_ir::WellFormed::Ty(ty.lower_into(interner)),
                     ),
@@ -137,7 +137,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::Coerce(..)
-                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
                 | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
             };
@@ -192,7 +192,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
                     chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
                 ))
             }
-            ty::PredicateKind::WellFormed(arg) => match arg.unpack() {
+            ty::PredicateKind::Clause(ty::Clause::WellFormed(arg)) => match arg.unpack() {
                 GenericArgKind::Type(ty) => match ty.kind() {
                     // FIXME(chalk): In Chalk, a placeholder is WellFormed if it
                     // `FromEnv`. However, when we "lower" Params, we don't update
@@ -231,7 +231,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
             | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::Coerce(..)
-            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
             | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::ConstEquate(..) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
@@ -672,7 +672,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => {
                 Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)))
             }
-            ty::PredicateKind::WellFormed(_ty) => None,
+            ty::PredicateKind::Clause(ty::Clause::WellFormed(_ty)) => None,
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
 
             ty::PredicateKind::ObjectSafe(..)
@@ -680,7 +680,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::Coerce(..)
-            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
@@ -807,7 +807,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
                 ))
             }
             ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_predicate)) => None,
-            ty::PredicateKind::WellFormed(_ty) => None,
+            ty::PredicateKind::Clause(ty::Clause::WellFormed(_ty)) => None,
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
 
             ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
@@ -816,7 +816,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::Coerce(..)
-            | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 94c33efaeff..7f6d53fe860 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -62,12 +62,12 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool {
         | ty::PredicateKind::Clause(ty::Clause::Projection(..))
         | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
         | ty::PredicateKind::AliasRelate(..)
-        | ty::PredicateKind::WellFormed(..)
+        | ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::Subtype(..)
         | ty::PredicateKind::Coerce(..)
-        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index 8c4f6a73d7f..e24a0fe51bd 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -4,8 +4,10 @@
 
 #[cfg(not(test))]
 use core::intrinsics;
+#[cfg(all(bootstrap, not(test)))]
 use core::intrinsics::{min_align_of_val, size_of_val};
 
+#[cfg(all(bootstrap, not(test)))]
 use core::ptr::Unique;
 #[cfg(not(test))]
 use core::ptr::{self, NonNull};
@@ -335,14 +337,15 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     }
 }
 
-#[cfg_attr(not(test), lang = "box_free")]
+#[cfg(all(bootstrap, not(test)))]
+#[lang = "box_free"]
 #[inline]
 // This signature has to be the same as `Box`, otherwise an ICE will happen.
 // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as
 // well.
 // For example if `Box` is changed to  `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`,
 // this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well.
-pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
+unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
     unsafe {
         let size = size_of_val(ptr.as_ref());
         let align = min_align_of_val(ptr.as_ref());
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 1768687e8cd..8ef2bac9282 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1211,8 +1211,16 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
+    #[inline]
     fn drop(&mut self) {
-        // FIXME: Do nothing, drop is currently performed by compiler.
+        // the T in the Box is dropped by the compiler before the destructor is run
+
+        let ptr = self.0;
+
+        unsafe {
+            let layout = Layout::for_value_raw(ptr.as_ptr());
+            self.1.deallocate(From::from(ptr.cast()), layout)
+        }
     }
 }
 
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 38a711ac750..34d3acae546 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -270,7 +270,7 @@ use core::slice::from_raw_parts_mut;
 #[cfg(not(no_global_oom_handling))]
 use crate::alloc::handle_alloc_error;
 #[cfg(not(no_global_oom_handling))]
-use crate::alloc::{box_free, WriteCloneIntoRaw};
+use crate::alloc::WriteCloneIntoRaw;
 use crate::alloc::{AllocError, Allocator, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
 #[cfg(not(no_global_oom_handling))]
@@ -1442,23 +1442,21 @@ impl<T: ?Sized> Rc<T> {
     }
 
     #[cfg(not(no_global_oom_handling))]
-    fn from_box(v: Box<T>) -> Rc<T> {
+    fn from_box(src: Box<T>) -> Rc<T> {
         unsafe {
-            let (box_unique, alloc) = Box::into_unique(v);
-            let bptr = box_unique.as_ptr();
-
-            let value_size = size_of_val(&*bptr);
-            let ptr = Self::allocate_for_ptr(bptr);
+            let value_size = size_of_val(&*src);
+            let ptr = Self::allocate_for_ptr(&*src);
 
             // Copy value as bytes
             ptr::copy_nonoverlapping(
-                bptr as *const T as *const u8,
+                &*src as *const T as *const u8,
                 &mut (*ptr).value as *mut _ as *mut u8,
                 value_size,
             );
 
             // Free the allocation without dropping its contents
-            box_free(box_unique, alloc);
+            let src = Box::from_raw(Box::into_raw(src) as *mut mem::ManuallyDrop<T>);
+            drop(src);
 
             Self::from_ptr(ptr)
         }
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index bfdb7a92bef..d2c87cf705c 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -33,7 +33,7 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
 #[cfg(not(no_global_oom_handling))]
 use crate::alloc::handle_alloc_error;
 #[cfg(not(no_global_oom_handling))]
-use crate::alloc::{box_free, WriteCloneIntoRaw};
+use crate::alloc::WriteCloneIntoRaw;
 use crate::alloc::{AllocError, Allocator, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
@@ -1360,23 +1360,21 @@ impl<T: ?Sized> Arc<T> {
     }
 
     #[cfg(not(no_global_oom_handling))]
-    fn from_box(v: Box<T>) -> Arc<T> {
+    fn from_box(src: Box<T>) -> Arc<T> {
         unsafe {
-            let (box_unique, alloc) = Box::into_unique(v);
-            let bptr = box_unique.as_ptr();
-
-            let value_size = size_of_val(&*bptr);
-            let ptr = Self::allocate_for_ptr(bptr);
+            let value_size = size_of_val(&*src);
+            let ptr = Self::allocate_for_ptr(&*src);
 
             // Copy value as bytes
             ptr::copy_nonoverlapping(
-                bptr as *const T as *const u8,
+                &*src as *const T as *const u8,
                 &mut (*ptr).data as *mut _ as *mut u8,
                 value_size,
             );
 
             // Free the allocation without dropping its contents
-            box_free(box_unique, alloc);
+            let src = Box::from_raw(Box::into_raw(src) as *mut mem::ManuallyDrop<T>);
+            drop(src);
 
             Self::from_ptr(ptr)
         }
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 7f06e170ad0..5939dedbd1d 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -348,7 +348,7 @@ macro_rules! nonzero_unsigned_operations {
                 }
 
                 /// Adds an unsigned integer to a non-zero value.
-                #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
+                #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")]
                 ///
                 /// # Examples
                 ///
@@ -579,7 +579,7 @@ macro_rules! nonzero_signed_operations {
 
                 /// Checked absolute value.
                 /// Checks for overflow and returns [`None`] if
-                #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")]
+                #[doc = concat!("`self == ", stringify!($Ty), "::MIN`.")]
                 /// The result cannot be zero.
                 ///
                 /// # Example
@@ -800,7 +800,8 @@ macro_rules! nonzero_signed_operations {
                     self.get().is_negative()
                 }
 
-                /// Checked negation. Computes `-self`, returning `None` if `self == i32::MIN`.
+                /// Checked negation. Computes `-self`,
+                #[doc = concat!("returning `None` if `self == ", stringify!($Ty), "::MIN`.")]
                 ///
                 /// # Example
                 ///
@@ -859,8 +860,10 @@ macro_rules! nonzero_signed_operations {
                     ((unsafe { $Ty::new_unchecked(result) }), overflow)
                 }
 
-                /// Saturating negation. Computes `-self`, returning `MAX` if
-                /// `self == i32::MIN` instead of overflowing.
+                /// Saturating negation. Computes `-self`,
+                #[doc = concat!("returning [`", stringify!($Ty), "::MAX`]")]
+                #[doc = concat!("if `self == ", stringify!($Ty), "::MIN`")]
+                /// instead of overflowing.
                 ///
                 /// # Example
                 ///
@@ -993,7 +996,7 @@ macro_rules! nonzero_unsigned_signed_operations {
                 }
 
                 /// Multiplies two non-zero integers together.
-                #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
+                #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")]
                 ///
                 /// # Examples
                 ///
@@ -1102,11 +1105,11 @@ macro_rules! nonzero_unsigned_signed_operations {
                 #[doc = sign_dependent_expr!{
                     $signedness ?
                     if signed {
-                        concat!("Return [`", stringify!($Int), "::MIN`] ",
-                                    "or [`", stringify!($Int), "::MAX`] on overflow.")
+                        concat!("Return [`", stringify!($Ty), "::MIN`] ",
+                                    "or [`", stringify!($Ty), "::MAX`] on overflow.")
                     }
                     if unsigned {
-                        concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")
+                        concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")
                     }
                 }]
                 ///
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 81be3fb22ee..f0fcdab00ad 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -166,14 +166,15 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[track_caller]
 #[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref
+#[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind
 fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
         super::intrinsics::abort()
     }
 
-    panic!(
+    panic_nounwind_fmt(format_args!(
         "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
-    )
+    ))
 }
 
 /// Panic because we cannot unwind out of a function.
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index e6b05183886..af74efa6bf8 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -38,7 +38,7 @@ features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
 rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
 rand_xorshift = "0.3.0"
 
-[target.'cfg(any(all(target_family = "wasm", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
+[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
 dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
 
 [target.x86_64-fortanix-unknown-sgx.dependencies]
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 3edf9d747ce..a66e6ccf673 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -222,7 +222,7 @@ impl<R: ?Sized> BufReader<R> {
 
     /// Invalidates all data in the internal buffer.
     #[inline]
-    fn discard_buffer(&mut self) {
+    pub(in crate::io) fn discard_buffer(&mut self) {
         self.buf.discard_buffer()
     }
 }
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 420fc400705..ef1f4031ef2 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,6 +1,9 @@
-use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BorrowedBuf, BufReader, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
 use crate::mem::MaybeUninit;
 
+#[cfg(test)]
+mod tests;
+
 /// Copies the entire contents of a reader into a writer.
 ///
 /// This function will continuously read data from `reader` and then
@@ -71,32 +74,113 @@ where
     R: Read,
     W: Write,
 {
-    BufferedCopySpec::copy_to(reader, writer)
+    let read_buf = BufferedReaderSpec::buffer_size(reader);
+    let write_buf = BufferedWriterSpec::buffer_size(writer);
+
+    if read_buf >= DEFAULT_BUF_SIZE && read_buf >= write_buf {
+        return BufferedReaderSpec::copy_to(reader, writer);
+    }
+
+    BufferedWriterSpec::copy_from(writer, reader)
+}
+
+/// Specialization of the read-write loop that reuses the internal
+/// buffer of a BufReader. If there's no buffer then the writer side
+/// should be used intead.
+trait BufferedReaderSpec {
+    fn buffer_size(&self) -> usize;
+
+    fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64>;
+}
+
+impl<T> BufferedReaderSpec for T
+where
+    Self: Read,
+    T: ?Sized,
+{
+    #[inline]
+    default fn buffer_size(&self) -> usize {
+        0
+    }
+
+    default fn copy_to(&mut self, _to: &mut (impl Write + ?Sized)) -> Result<u64> {
+        unimplemented!("only called from specializations");
+    }
+}
+
+impl<I> BufferedReaderSpec for BufReader<I>
+where
+    Self: Read,
+    I: ?Sized,
+{
+    fn buffer_size(&self) -> usize {
+        self.capacity()
+    }
+
+    fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64> {
+        let mut len = 0;
+
+        loop {
+            // Hack: this relies on `impl Read for BufReader` always calling fill_buf
+            // if the buffer is empty, even for empty slices.
+            // It can't be called directly here since specialization prevents us
+            // from adding I: Read
+            match self.read(&mut []) {
+                Ok(_) => {}
+                Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+                Err(e) => return Err(e),
+            }
+            let buf = self.buffer();
+            if self.buffer().len() == 0 {
+                return Ok(len);
+            }
+
+            // In case the writer side is a BufWriter then its write_all
+            // implements an optimization that passes through large
+            // buffers to the underlying writer. That code path is #[cold]
+            // but we're still avoiding redundant memcopies when doing
+            // a copy between buffered inputs and outputs.
+            to.write_all(buf)?;
+            len += buf.len() as u64;
+            self.discard_buffer();
+        }
+    }
 }
 
 /// Specialization of the read-write loop that either uses a stack buffer
 /// or reuses the internal buffer of a BufWriter
-trait BufferedCopySpec: Write {
-    fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64>;
+trait BufferedWriterSpec: Write {
+    fn buffer_size(&self) -> usize;
+
+    fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64>;
 }
 
-impl<W: Write + ?Sized> BufferedCopySpec for W {
-    default fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
-        stack_buffer_copy(reader, writer)
+impl<W: Write + ?Sized> BufferedWriterSpec for W {
+    #[inline]
+    default fn buffer_size(&self) -> usize {
+        0
+    }
+
+    default fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
+        stack_buffer_copy(reader, self)
     }
 }
 
-impl<I: ?Sized + Write> BufferedCopySpec for BufWriter<I> {
-    fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
-        if writer.capacity() < DEFAULT_BUF_SIZE {
-            return stack_buffer_copy(reader, writer);
+impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> {
+    fn buffer_size(&self) -> usize {
+        self.capacity()
+    }
+
+    fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
+        if self.capacity() < DEFAULT_BUF_SIZE {
+            return stack_buffer_copy(reader, self);
         }
 
         let mut len = 0;
         let mut init = 0;
 
         loop {
-            let buf = writer.buffer_mut();
+            let buf = self.buffer_mut();
             let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
 
             unsafe {
@@ -127,7 +211,7 @@ impl<I: ?Sized + Write> BufferedCopySpec for BufWriter<I> {
                     Err(e) => return Err(e),
                 }
             } else {
-                writer.flush_buf()?;
+                self.flush_buf()?;
                 init = 0;
             }
         }
diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs
new file mode 100644
index 00000000000..8c816af15b8
--- /dev/null
+++ b/library/std/src/io/copy/tests.rs
@@ -0,0 +1,108 @@
+use crate::cmp::{max, min};
+use crate::io::*;
+
+#[test]
+fn copy_copies() {
+    let mut r = repeat(0).take(4);
+    let mut w = sink();
+    assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
+
+    let mut r = repeat(0).take(1 << 17);
+    assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
+}
+
+struct ShortReader {
+    cap: usize,
+    read_size: usize,
+    observed_buffer: usize,
+}
+
+impl Read for ShortReader {
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        let bytes = min(self.cap, self.read_size);
+        self.cap -= bytes;
+        self.observed_buffer = max(self.observed_buffer, buf.len());
+        Ok(bytes)
+    }
+}
+
+struct WriteObserver {
+    observed_buffer: usize,
+}
+
+impl Write for WriteObserver {
+    fn write(&mut self, buf: &[u8]) -> Result<usize> {
+        self.observed_buffer = max(self.observed_buffer, buf.len());
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> Result<()> {
+        Ok(())
+    }
+}
+
+#[test]
+fn copy_specializes_bufwriter() {
+    let cap = 117 * 1024;
+    let buf_sz = 16 * 1024;
+    let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
+    let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 });
+    assert_eq!(
+        copy(&mut r, &mut w).unwrap(),
+        cap as u64,
+        "expected the whole capacity to be copied"
+    );
+    assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader");
+    assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes");
+}
+
+#[test]
+fn copy_specializes_bufreader() {
+    let mut source = vec![0; 768 * 1024];
+    source[1] = 42;
+    let mut buffered = BufReader::with_capacity(256 * 1024, Cursor::new(&mut source));
+
+    let mut sink = Vec::new();
+    assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
+    assert_eq!(source.as_slice(), sink.as_slice());
+
+    let buf_sz = 71 * 1024;
+    assert!(buf_sz > DEFAULT_BUF_SIZE, "test precondition");
+
+    let mut buffered = BufReader::with_capacity(buf_sz, Cursor::new(&mut source));
+    let mut sink = WriteObserver { observed_buffer: 0 };
+    assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
+    assert_eq!(
+        sink.observed_buffer, buf_sz,
+        "expected a large buffer to be provided to the writer"
+    );
+}
+
+#[cfg(unix)]
+mod io_benches {
+    use crate::fs::File;
+    use crate::fs::OpenOptions;
+    use crate::io::prelude::*;
+    use crate::io::BufReader;
+
+    use test::Bencher;
+
+    #[bench]
+    fn bench_copy_buf_reader(b: &mut Bencher) {
+        let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed");
+        // use dyn to avoid specializations unrelated to readbuf
+        let dyn_in = &mut file_in as &mut dyn Read;
+        let mut reader = BufReader::with_capacity(256 * 1024, dyn_in.take(0));
+        let mut writer =
+            OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed");
+
+        const BYTES: u64 = 1024 * 1024;
+
+        b.bytes = BYTES;
+
+        b.iter(|| {
+            reader.get_mut().set_limit(BYTES);
+            crate::io::copy(&mut reader, &mut writer).unwrap()
+        });
+    }
+}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 173233d7150..5c1d2d8f46c 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1416,17 +1416,18 @@ pub trait Write {
     ///
     /// This function will attempt to write the entire contents of `buf`, but
     /// the entire write might not succeed, or the write may also generate an
-    /// error. A call to `write` represents *at most one* attempt to write to
+    /// error. Typically, a call to `write` represents one attempt to write to
     /// any wrapped object.
     ///
     /// Calls to `write` are not guaranteed to block waiting for data to be
     /// written, and a write which would otherwise block can be indicated through
     /// an [`Err`] variant.
     ///
-    /// If the return value is [`Ok(n)`] then it must be guaranteed that
-    /// `n <= buf.len()`. A return value of `0` typically means that the
-    /// underlying object is no longer able to accept bytes and will likely not
-    /// be able to in the future as well, or that the buffer provided is empty.
+    /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`].
+    /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`.
+    /// Unless `buf` is empty, this function shouldn’t return `Ok(0)` since the
+    /// caller may interpret that as an error.  To indicate lack of space,
+    /// implementors should return [`ErrorKind::StorageFull`] error instead.
     ///
     /// # Errors
     ///
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index ce5e2c9da1d..1baa94e64c9 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -1,68 +1,9 @@
-use crate::cmp::{max, min};
 use crate::io::prelude::*;
-use crate::io::{
-    copy, empty, repeat, sink, BorrowedBuf, BufWriter, Empty, Repeat, Result, SeekFrom, Sink,
-    DEFAULT_BUF_SIZE,
-};
+use crate::io::{empty, repeat, sink, BorrowedBuf, Empty, Repeat, SeekFrom, Sink};
 
 use crate::mem::MaybeUninit;
 
 #[test]
-fn copy_copies() {
-    let mut r = repeat(0).take(4);
-    let mut w = sink();
-    assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
-
-    let mut r = repeat(0).take(1 << 17);
-    assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
-}
-
-struct ShortReader {
-    cap: usize,
-    read_size: usize,
-    observed_buffer: usize,
-}
-
-impl Read for ShortReader {
-    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
-        let bytes = min(self.cap, self.read_size);
-        self.cap -= bytes;
-        self.observed_buffer = max(self.observed_buffer, buf.len());
-        Ok(bytes)
-    }
-}
-
-struct WriteObserver {
-    observed_buffer: usize,
-}
-
-impl Write for WriteObserver {
-    fn write(&mut self, buf: &[u8]) -> Result<usize> {
-        self.observed_buffer = max(self.observed_buffer, buf.len());
-        Ok(buf.len())
-    }
-
-    fn flush(&mut self) -> Result<()> {
-        Ok(())
-    }
-}
-
-#[test]
-fn copy_specializes_bufwriter() {
-    let cap = 117 * 1024;
-    let buf_sz = 16 * 1024;
-    let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
-    let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 });
-    assert_eq!(
-        copy(&mut r, &mut w).unwrap(),
-        cap as u64,
-        "expected the whole capacity to be copied"
-    );
-    assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader");
-    assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes");
-}
-
-#[test]
 fn sink_sinks() {
     let mut s = sink();
     assert_eq!(s.write(&[]).unwrap(), 0);
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 814f1c7c283..218536689fd 100644
--- a/library/std/src/os/unix/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -11,7 +11,13 @@ use crate::slice::from_raw_parts;
 use crate::sys::net::Socket;
 
 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
-#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android"), not(target_os = "netbsd")))]
+#[cfg(all(
+    doc,
+    not(target_os = "linux"),
+    not(target_os = "android"),
+    not(target_os = "netbsd"),
+    not(target_os = "freebsd")
+))]
 #[allow(non_camel_case_types)]
 mod libc {
     pub use libc::c_int;
diff --git a/library/std/src/personality.rs b/library/std/src/personality.rs
index 63f0ad4f16e..386a399f532 100644
--- a/library/std/src/personality.rs
+++ b/library/std/src/personality.rs
@@ -29,7 +29,7 @@ cfg_if::cfg_if! {
         all(target_family = "windows", target_env = "gnu"),
         target_os = "psp",
         target_os = "solid_asp3",
-        all(target_family = "unix", not(target_os = "espidf")),
+        all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")),
         all(target_vendor = "fortanix", target_env = "sgx"),
     ))] {
         mod gcc;
diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs
index ee016887e70..fe9559f2a56 100644
--- a/library/std/src/sys/unix/l4re.rs
+++ b/library/std/src/sys/unix/l4re.rs
@@ -10,7 +10,7 @@ macro_rules! unimpl {
 pub mod net {
     #![allow(warnings)]
     use crate::fmt;
-    use crate::io::{self, IoSlice, IoSliceMut};
+    use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
     use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
     use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
     use crate::sys::fd::FileDesc;
@@ -218,6 +218,10 @@ pub mod net {
             unimpl!();
         }
 
+        pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> {
+            unimpl!();
+        }
+
         pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
             unimpl!();
         }
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 3721988b405..22d9d6141f4 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -836,31 +836,47 @@ fn signal_string(signal: i32) -> &'static str {
         libc::SIGILL => " (SIGILL)",
         libc::SIGTRAP => " (SIGTRAP)",
         libc::SIGABRT => " (SIGABRT)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGBUS => " (SIGBUS)",
         libc::SIGFPE => " (SIGFPE)",
         libc::SIGKILL => " (SIGKILL)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGUSR1 => " (SIGUSR1)",
         libc::SIGSEGV => " (SIGSEGV)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGUSR2 => " (SIGUSR2)",
         libc::SIGPIPE => " (SIGPIPE)",
         libc::SIGALRM => " (SIGALRM)",
         libc::SIGTERM => " (SIGTERM)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGCHLD => " (SIGCHLD)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGCONT => " (SIGCONT)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGSTOP => " (SIGSTOP)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGTSTP => " (SIGTSTP)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGTTIN => " (SIGTTIN)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGTTOU => " (SIGTTOU)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGURG => " (SIGURG)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGXCPU => " (SIGXCPU)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGXFSZ => " (SIGXFSZ)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGVTALRM => " (SIGVTALRM)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGPROF => " (SIGPROF)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGWINCH => " (SIGWINCH)",
-        #[cfg(not(target_os = "haiku"))]
+        #[cfg(not(any(target_os = "haiku", target_os = "l4re")))]
         libc::SIGIO => " (SIGIO)",
         #[cfg(target_os = "haiku")]
         libc::SIGPOLL => " (SIGPOLL)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGSYS => " (SIGSYS)",
         // For information on Linux signals, run `man 7 signal`
         #[cfg(all(
diff --git a/library/stdarch b/library/stdarch
-Subproject 7e2cdc675b92165c5f8c4c794620252be4605e7
+Subproject d77878b7299dd7e286799a6e8447048b65d2a86
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 13a10b0d3a5..01d0dbafd1e 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1766,7 +1766,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         //
         // Note that if we encounter `PATH` we make sure to append to our own `PATH`
         // rather than stomp over it.
-        if target.contains("msvc") {
+        if !builder.config.dry_run() && target.contains("msvc") {
             for &(ref k, ref v) in builder.cc.borrow()[&target].env() {
                 if k != "PATH" {
                     cmd.env(k, v);
diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py
index 78a8a6662ea..73cf3de6a46 100755
--- a/src/ci/docker/scripts/fuchsia-test-runner.py
+++ b/src/ci/docker/scripts/fuchsia-test-runner.py
@@ -25,13 +25,9 @@ from typing import ClassVar, List, Optional
 
 @dataclass
 class TestEnvironment:
-    rust_dir: str
+    rust_build_dir: str
     sdk_dir: str
     target: str
-    package_server_pid: Optional[int] = None
-    emu_addr: Optional[str] = None
-    libstd_name: Optional[str] = None
-    libtest_name: Optional[str] = None
     verbose: bool = False
 
     @staticmethod
@@ -57,7 +53,7 @@ class TestEnvironment:
     @classmethod
     def from_args(cls, args):
         return cls(
-            os.path.abspath(args.rust),
+            os.path.abspath(args.rust_build),
             os.path.abspath(args.sdk),
             args.target,
             verbose=args.verbose,
@@ -68,13 +64,9 @@ class TestEnvironment:
         with open(cls.env_file_path(), encoding="utf-8") as f:
             test_env = json.loads(f.read())
             return cls(
-                test_env["rust_dir"],
+                test_env["rust_build_dir"],
                 test_env["sdk_dir"],
                 test_env["target"],
-                libstd_name=test_env["libstd_name"],
-                libtest_name=test_env["libtest_name"],
-                emu_addr=test_env["emu_addr"],
-                package_server_pid=test_env["package_server_pid"],
                 verbose=test_env["verbose"],
             )
 
@@ -82,18 +74,6 @@ class TestEnvironment:
         with open(self.env_file_path(), "w", encoding="utf-8") as f:
             f.write(json.dumps(self.__dict__))
 
-    def ssh_dir(self):
-        return os.path.join(self.tmp_dir(), "ssh")
-
-    def ssh_keyfile_path(self):
-        return os.path.join(self.ssh_dir(), "fuchsia_ed25519")
-
-    def ssh_authfile_path(self):
-        return os.path.join(self.ssh_dir(), "fuchsia_authorized_keys")
-
-    def vdl_output_path(self):
-        return os.path.join(self.tmp_dir(), "vdl_output")
-
     def package_server_log_path(self):
         return os.path.join(self.tmp_dir(), "package_server_log")
 
@@ -113,7 +93,9 @@ class TestEnvironment:
 
     def libs_dir(self):
         return os.path.join(
-            self.rust_dir,
+            self.rust_build_dir,
+            "host",
+            "stage2",
             "lib",
         )
 
@@ -212,21 +194,19 @@ class TestEnvironment:
         # Set configs
         configs = {
             "log.enabled": "true",
-            "ssh.pub": self.ssh_authfile_path(),
-            "ssh.priv": self.ssh_keyfile_path(),
             "test.is_isolated": "true",
             "test.experimental_structured_output": "true",
         }
         for key, value in configs.items():
             subprocess.check_call(
                 [
-                    self.tool_path("ffx"),
+                    ffx_path,
                     "config",
                     "set",
                     key,
                     value,
                 ],
-                env=self.ffx_cmd_env(),
+                env=ffx_env,
                 stdout=self.subprocess_output(),
                 stderr=self.subprocess_output(),
             )
@@ -248,6 +228,7 @@ class TestEnvironment:
                 self.tool_path("ffx"),
                 "daemon",
                 "stop",
+                "-w",
             ],
             env=self.ffx_cmd_env(),
             stdout=self.subprocess_output(),
@@ -275,87 +256,62 @@ class TestEnvironment:
         elif len(os.listdir(self.tmp_dir())) != 0:
             raise Exception(f"Temp directory is not clean (in {self.tmp_dir()})")
 
-        os.mkdir(self.ssh_dir())
         os.mkdir(self.output_dir())
 
-        # Find libstd and libtest
-        libstd_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libstd-*.so"))
-        libtest_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libtest-*.so"))
-
-        if not libstd_paths:
-            raise Exception(f"Failed to locate libstd (in {self.rustlibs_dir()})")
-
-        if not libtest_paths:
-            raise Exception(f"Failed to locate libtest (in {self.rustlibs_dir()})")
+        ffx_path = self.tool_path("ffx")
+        ffx_env = self.ffx_cmd_env()
 
-        self.libstd_name = os.path.basename(libstd_paths[0])
-        self.libtest_name = os.path.basename(libtest_paths[0])
+        # Start ffx isolation
+        self.log_info("Starting ffx isolation...")
+        self.start_ffx_isolation()
 
-        # Generate SSH keys for the emulator to use
-        self.log_info("Generating SSH keys...")
+        # Stop any running emulators (there shouldn't be any)
         subprocess.check_call(
             [
-                "ssh-keygen",
-                "-N",
-                "",
-                "-t",
-                "ed25519",
-                "-f",
-                self.ssh_keyfile_path(),
-                "-C",
-                "Generated by fuchsia-test-runner.py",
+                ffx_path,
+                "emu",
+                "stop",
+                "--all",
             ],
+            env=ffx_env,
             stdout=self.subprocess_output(),
             stderr=self.subprocess_output(),
         )
-        authfile_contents = subprocess.check_output(
+
+        # Start emulator
+        self.log_info("Starting emulator...")
+        product_bundle = "terminal.qemu-" + self.triple_to_arch(self.target)
+        subprocess.check_call(
             [
-                "ssh-keygen",
-                "-y",
-                "-f",
-                self.ssh_keyfile_path(),
+                ffx_path,
+                "product-bundle",
+                "get",
+                product_bundle,
             ],
+            env=ffx_env,
+            stdout=self.subprocess_output(),
             stderr=self.subprocess_output(),
         )
-        with open(self.ssh_authfile_path(), "wb") as authfile:
-            authfile.write(authfile_contents)
-
-        # Start ffx isolation
-        self.log_info("Starting ffx isolation...")
-        self.start_ffx_isolation()
-
-        # Start emulator (this will generate the vdl output)
-        self.log_info("Starting emulator...")
+        # FIXME: condition --accel hyper on target arch matching host arch
         subprocess.check_call(
             [
-                self.tool_path("fvdl"),
-                "--sdk",
+                ffx_path,
+                "emu",
                 "start",
-                "--tuntap",
+                product_bundle,
                 "--headless",
-                "--nointeractive",
-                "--ssh",
-                self.ssh_dir(),
-                "--vdl-output",
-                self.vdl_output_path(),
-                "--emulator-log",
+                "--log",
                 self.emulator_log_path(),
-                "--image-name",
-                "qemu-" + self.triple_to_arch(self.target),
+                "--net",
+                "tap",
+                "--accel",
+                "hyper",
             ],
+            env=ffx_env,
             stdout=self.subprocess_output(),
             stderr=self.subprocess_output(),
         )
 
-        # Parse vdl output for relevant information
-        with open(self.vdl_output_path(), encoding="utf-8") as f:
-            vdl_content = f.read()
-            matches = re.search(
-                r'network_address:\s+"\[([0-9a-f]{1,4}:(:[0-9a-f]{1,4}){4}%qemu)\]"',
-                vdl_content,
-            )
-            self.emu_addr = matches.group(1)
-
         # Create new package repo
         self.log_info("Creating package repo...")
         subprocess.check_call(
@@ -369,55 +325,40 @@ class TestEnvironment:
             stderr=self.subprocess_output(),
         )
 
-        # Start package server
-        self.log_info("Starting package server...")
-        with open(
-            self.package_server_log_path(), "w", encoding="utf-8"
-        ) as package_server_log:
-            # We want this to be a long-running process that persists after the script finishes
-            # pylint: disable=consider-using-with
-            self.package_server_pid = subprocess.Popen(
-                [
-                    self.tool_path("pm"),
-                    "serve",
-                    "-vt",
-                    "-repo",
-                    self.repo_dir(),
-                    "-l",
-                    ":8084",
-                ],
-                stdout=package_server_log,
-                stderr=package_server_log,
-            ).pid
-
-        # Register package server with emulator
-        self.log_info("Registering package server...")
-        ssh_client = subprocess.check_output(
+        # Add repo
+        subprocess.check_call(
             [
-                "ssh",
-                "-i",
-                self.ssh_keyfile_path(),
-                "-o",
-                "StrictHostKeyChecking=accept-new",
-                self.emu_addr,
-                "-f",
-                "echo $SSH_CLIENT",
+                ffx_path,
+                "repository",
+                "add-from-pm",
+                self.repo_dir(),
+                "--repository",
+                self.TEST_REPO_NAME,
             ],
-            text=True,
+            env=ffx_env,
+            stdout=self.subprocess_output(),
+            stderr=self.subprocess_output(),
         )
-        repo_addr = ssh_client.split()[0].replace("%", "%25")
-        repo_url = f"http://[{repo_addr}]:8084/config.json"
+
+        # Start repository server
+        subprocess.check_call(
+            [ffx_path, "repository", "server", "start", "--address", "[::]:0"],
+            env=ffx_env,
+            stdout=self.subprocess_output(),
+            stderr=self.subprocess_output(),
+        )
+
+        # Register with newly-started emulator
         subprocess.check_call(
             [
-                "ssh",
-                "-i",
-                self.ssh_keyfile_path(),
-                "-o",
-                "StrictHostKeyChecking=accept-new",
-                self.emu_addr,
-                "-f",
-                f"pkgctl repo add url -f 1 -n {self.TEST_REPO_NAME} {repo_url}",
+                ffx_path,
+                "target",
+                "repository",
+                "register",
+                "--repository",
+                self.TEST_REPO_NAME,
             ],
+            env=ffx_env,
             stdout=self.subprocess_output(),
             stderr=self.subprocess_output(),
         )
@@ -471,8 +412,8 @@ class TestEnvironment:
     meta/package={package_dir}/meta/package
     meta/{package_name}.cm={package_dir}/meta/{package_name}.cm
     bin/{exe_name}={bin_path}
-    lib/{libstd_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libstd_name}
-    lib/{libtest_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libtest_name}
+    lib/{libstd_name}={libstd_path}
+    lib/{libtest_name}={libtest_path}
     lib/ld.so.1={sdk_dir}/arch/{target_arch}/sysroot/dist/lib/ld.so.1
     lib/libfdio.so={sdk_dir}/arch/{target_arch}/dist/libfdio.so
     """
@@ -502,6 +443,16 @@ class TestEnvironment:
 
         bin_path = os.path.abspath(args.bin_path)
 
+        # Find libstd and libtest
+        libstd_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libstd-*.so"))
+        libtest_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libtest-*.so"))
+
+        if not libstd_paths:
+            raise Exception(f"Failed to locate libstd (in {self.rustlibs_dir()})")
+
+        if not libtest_paths:
+            raise Exception(f"Failed to locate libtest (in {self.rustlibs_dir()})")
+
         # Build a unique, deterministic name for the test using the name of the
         # binary and the last 6 hex digits of the hash of the full path
         def path_checksum(path):
@@ -604,11 +555,12 @@ class TestEnvironment:
                         exe_name=exe_name,
                         package_dir=package_dir,
                         package_name=package_name,
-                        rust_dir=self.rust_dir,
-                        rustlib_dir=self.target,
+                        target=self.target,
                         sdk_dir=self.sdk_dir,
-                        libstd_name=self.libstd_name,
-                        libtest_name=self.libtest_name,
+                        libstd_name=os.path.basename(libstd_paths[0]),
+                        libtest_name=os.path.basename(libtest_paths[0]),
+                        libstd_path=libstd_paths[0],
+                        libtest_path=libtest_paths[0],
                         target_arch=self.triple_to_arch(self.target),
                     )
                 )
@@ -779,20 +731,15 @@ class TestEnvironment:
         else:
             self.log_debug("No ffx daemon log found")
 
-        # Stop package server
-        self.log_info("Stopping package server...")
-        os.kill(self.package_server_pid, signal.SIGTERM)
-
         # Shut down the emulator
         self.log_info("Stopping emulator...")
         subprocess.check_call(
             [
-                self.tool_path("fvdl"),
-                "--sdk",
-                "kill",
-                "--launched-proto",
-                self.vdl_output_path(),
+                self.tool_path("ffx"),
+                "emu",
+                "stop",
             ],
+            env=self.ffx_cmd_env(),
             stdout=self.subprocess_output(),
             stderr=self.subprocess_output(),
         )
@@ -969,8 +916,8 @@ def main():
         "start", help="initializes the testing environment"
     )
     start_parser.add_argument(
-        "--rust",
-        help="the directory of the installed Rust compiler for Fuchsia",
+        "--rust-build",
+        help="the current compiler build directory (`$RUST_SRC/build` by default)",
         required=True,
     )
     start_parser.add_argument(
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index 4d97b8c6cb9..f7cce35b123 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -681,12 +681,9 @@ local Rust source checkout:
 cd ${RUST_SRC_PATH}
 ```
 
-To run the Rust test suite on an emulated Fuchsia device, you must install the
-Rust compiler locally. See "[Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source)"
-for the steps to build locally.
-
-You'll also need to download a copy of the Fuchsia SDK. The current minimum
-supported SDK version is [10.20221207.2.89][minimum_supported_sdk_version].
+To run the Rust test suite on an emulated Fuchsia device, you'll also need to
+download a copy of the Fuchsia SDK. The current minimum supported SDK version is
+[10.20221207.2.89][minimum_supported_sdk_version].
 
 [minimum_supported_sdk_version]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:10.20221207.2.89
 
@@ -695,13 +692,13 @@ Fuchsia's test runner interacts with the Fuchsia emulator and is located at
 test environment with:
 
 ```sh
-src/ci/docker/scripts/fuchsia-test-runner.py start
-    --rust ${RUST_SRC_PATH}/install
-    --sdk ${SDK_PATH}
-    --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia}
+src/ci/docker/scripts/fuchsia-test-runner.py start                            \
+    --rust-build ${RUST_SRC_PATH}/build                                       \
+    --sdk ${SDK_PATH}                                                         \
+    --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia}                 \
 ```
 
-Where `${RUST_SRC_PATH}/install` is the `prefix` set in `config.toml` and
+Where `${RUST_SRC_PATH}/build` is the `build-dir` set in `config.toml` and
 `${SDK_PATH}` is the path to the downloaded and unzipped SDK.
 
 Once our environment is started, we can run our tests using `x.py` as usual. The
diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md
index 6adb3506e64..f4bc18bc7da 100644
--- a/src/doc/unstable-book/src/language-features/lang-items.md
+++ b/src/doc/unstable-book/src/language-features/lang-items.md
@@ -11,8 +11,8 @@ it exists. The marker is the attribute `#[lang = "..."]` and there are
 various different values of `...`, i.e. various different 'lang
 items'.
 
-For example, `Box` pointers require two lang items, one for allocation
-and one for deallocation. A freestanding program that uses the `Box`
+For example, `Box` pointers require a lang item for allocation.
+A freestanding program that uses the `Box`
 sugar for dynamic allocations via `malloc` and `free`:
 
 ```rust,ignore (libc-is-finicky)
@@ -48,9 +48,10 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
     p
 }
 
-#[lang = "box_free"]
-unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
-    libc::free(ptr as *mut libc::c_void)
+impl<T> Drop for Box<T> {
+    fn drop(&mut self) {
+      libc::free(self.0.0.0 as *mut libc::c_void)
+    }
 }
 
 #[start]
@@ -84,8 +85,8 @@ Other features provided by lang items include:
   `contravariant_lifetime`, etc.
 
 Lang items are loaded lazily by the compiler; e.g. if one never uses
-`Box` then there is no need to define functions for `exchange_malloc`
-and `box_free`. `rustc` will emit an error when an item is needed
+`Box` then there is no need to define a function for `exchange_malloc`.
+`rustc` will emit an error when an item is needed
 but not found in the current crate or any that it depends on.
 
 Most lang items are defined by `libcore`, but if you're trying to build
@@ -250,7 +251,6 @@ the source code.
 - Allocations
   - `owned_box`: `liballoc/boxed.rs`
   - `exchange_malloc`: `liballoc/heap.rs`
-  - `box_free`: `liballoc/heap.rs`
 - Operands
   - `not`: `libcore/ops/bit.rs`
   - `bitand`: `libcore/ops/bit.rs`
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9f698a3b6bf..29c11e1f335 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -344,8 +344,8 @@ pub(crate) fn clean_predicate<'tcx>(
             Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
         }
         // FIXME(generic_const_exprs): should this do something?
-        ty::PredicateKind::ConstEvaluatable(..) => None,
-        ty::PredicateKind::WellFormed(..) => None,
+        ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..)) => None,
+        ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) => None,
         ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
 
         ty::PredicateKind::Subtype(..)
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index a184b7b705e..f5296abaee6 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -277,14 +277,18 @@ function preLoadCss(cssUrl) {
             searchState.mouseMovedAfterSearch = false;
             document.title = searchState.title;
         },
-        hideResults: () => {
-            switchDisplayedElement(null);
+        removeQueryParameters: () => {
+            // We change the document title.
             document.title = searchState.titleBeforeSearch;
-            // We also remove the query parameter from the URL.
             if (browserSupportsHistoryApi()) {
                 history.replaceState(null, "", getNakedUrl() + window.location.hash);
             }
         },
+        hideResults: () => {
+            switchDisplayedElement(null);
+            // We also remove the query parameter from the URL.
+            searchState.removeQueryParameters();
+        },
         getQueryStringParams: () => {
             const params = {};
             window.location.search.substring(1).split("&").
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index e724bf1601a..3059dac8207 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -2071,6 +2071,20 @@ function initSearch(rawSearchIndex) {
         if (go_to_first || (results.others.length === 1
             && getSettingValue("go-to-only-result") === "true")
         ) {
+            // Needed to force re-execution of JS when coming back to a page. Let's take this
+            // scenario as example:
+            //
+            // 1. You have the "Directly go to item in search if there is only one result" option
+            //    enabled.
+            // 2. You make a search which results only one result, leading you automatically to
+            //    this result.
+            // 3. You go back to previous page.
+            //
+            // Now, without the call below, the JS will not be re-executed and the previous state
+            // will be used, starting search again since the search input is not empty, leading you
+            // back to the previous page again.
+            window.onunload = () => {};
+            searchState.removeQueryParameters();
             const elem = document.createElement("a");
             elem.href = results.others[0].href;
             removeClass(elem, "active");
@@ -2185,6 +2199,18 @@ function initSearch(rawSearchIndex) {
         printTab(currentTab);
     }
 
+    function updateSearchHistory(url) {
+        if (!browserSupportsHistoryApi()) {
+            return;
+        }
+        const params = searchState.getQueryStringParams();
+        if (!history.state && !params.search) {
+            history.pushState(null, "", url);
+        } else {
+            history.replaceState(null, "", url);
+        }
+    }
+
     /**
      * Perform a search based on the current state of the search input element
      * and display the results.
@@ -2195,7 +2221,6 @@ function initSearch(rawSearchIndex) {
         if (e) {
             e.preventDefault();
         }
-
         const query = parseQuery(searchState.input.value.trim());
         let filterCrates = getFilterCrates();
 
@@ -2221,15 +2246,7 @@ function initSearch(rawSearchIndex) {
 
         // Because searching is incremental by character, only the most
         // recent search query is added to the browser history.
-        if (browserSupportsHistoryApi()) {
-            const newURL = buildUrl(query.original, filterCrates);
-
-            if (!history.state && !params.search) {
-                history.pushState(null, "", newURL);
-            } else {
-                history.replaceState(null, "", newURL);
-            }
-        }
+        updateSearchHistory(buildUrl(query.original, filterCrates));
 
         showResults(
             execQuery(query, searchWords, filterCrates, window.currentCrate),
@@ -2695,13 +2712,8 @@ function initSearch(rawSearchIndex) {
     function updateCrate(ev) {
         if (ev.target.value === "all crates") {
             // If we don't remove it from the URL, it'll be picked up again by the search.
-            const params = searchState.getQueryStringParams();
             const query = searchState.input.value.trim();
-            if (!history.state && !params.search) {
-                history.pushState(null, "", buildUrl(query, null));
-            } else {
-                history.replaceState(null, "", buildUrl(query, null));
-            }
+            updateSearchHistory(buildUrl(query, null));
         }
         // In case you "cut" the entry from the search input, then change the crate filter
         // before paste back the previous search, you get the old search results without
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index c0d2c835d63..860a489494c 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -33,8 +33,8 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
                     | ty::Clause::Trait(..)
                     | ty::Clause::ConstArgHasType(..),
                 )
-                | ty::PredicateKind::WellFormed(_)
-                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Clause(ty::Clause::WellFormed(_))
+                | ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
                 ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"),
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 8c744d5d3c4..25b16e38e53 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1951,7 +1951,9 @@ impl<'test> TestCx<'test> {
         rustc.arg("-Ztranslate-remapped-path-to-local-path=no");
 
         // Optionally prevent default --sysroot if specified in test compile-flags.
-        if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) {
+        if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot"))
+            && !self.config.host_rustcflags.iter().any(|flag| flag == "--sysroot")
+        {
             // In stage 0, make sure we use `stage0-sysroot` instead of the bootstrap sysroot.
             rustc.arg("--sysroot").arg(&self.config.sysroot_base);
         }
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index aa382960891..73385aee85d 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-7513407ac8e673f536d34743fe393bd8b7c45441
+677710eaf0a0bdb008959ee8717c9fe1c6d187b3
diff --git a/src/tools/miri/tests/fail/alloc/stack_free.stderr b/src/tools/miri/tests/fail/alloc/stack_free.stderr
index b1636050a78..7c14d372f0c 100644
--- a/src/tools/miri/tests/fail/alloc/stack_free.stderr
+++ b/src/tools/miri/tests/fail/alloc/stack_free.stderr
@@ -9,7 +9,7 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    = note: BACKTRACE:
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
+   = note: inside `<std::boxed::Box<i32> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC
    = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
    = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr
index 81054972a9b..00b2708a651 100644
--- a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr
@@ -27,7 +27,7 @@ LL |             || drop(Box::from_raw(ptr)),
    = note: BACKTRACE (of the first span):
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
+   = note: inside `<std::boxed::Box<i32> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC
    = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
    = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
 note: inside closure
diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr
index 3a3b24fd7d8..aed2e7abebc 100644
--- a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr
@@ -27,7 +27,7 @@ LL |             || drop(Box::from_raw(ptr)),
    = note: BACKTRACE (of the first span):
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
+   = note: inside `<std::boxed::Box<i32> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC
    = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
    = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
 note: inside closure
diff --git a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr
index 516964b9a4e..8ebb35450e5 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr
@@ -9,7 +9,7 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    = note: BACKTRACE:
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
+   = note: inside `<std::boxed::Box<i32> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC
    = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
    = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
 note: inside closure
diff --git a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr
index 97088d5854c..55665e63e8a 100644
--- a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr
@@ -20,7 +20,7 @@ LL | fn inner(x: &mut i32, f: fn(&mut i32)) {
    = note: BACKTRACE (of the first span):
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
+   = note: inside `<std::boxed::Box<i32> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC
    = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
    = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
 note: inside closure
diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs
index 7c2b6055090..011a253c6ff 100644
--- a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs
+++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs
@@ -370,7 +370,7 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
 
 
     // all: __stack_chk_fail
-    // strong-NOT: __stack_chk_fail
+    // strong: __stack_chk_fail
     // basic-NOT: __stack_chk_fail
     // none-NOT: __stack_chk_fail
     // missing-NOT: __stack_chk_fail
diff --git a/tests/mir-opt/inline/unsized_argument.caller.Inline.diff b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff
index 5c64d430559..6ee6a0ffe4c 100644
--- a/tests/mir-opt/inline/unsized_argument.caller.Inline.diff
+++ b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff
@@ -6,36 +6,41 @@
       let mut _0: ();
       let _2: ();
       let mut _3: std::boxed::Box<[i32]>;
-      let mut _4: ();
+      let mut _4: &mut std::boxed::Box<[i32]>;
       let mut _5: ();
-      let mut _6: ();
-      let mut _7: *const [i32];
+      let mut _6: &mut std::boxed::Box<[i32]>;
+      let mut _7: ();
+      let mut _8: &mut std::boxed::Box<[i32]>;
+      let mut _9: ();
+      let mut _10: *const [i32];
   
       bb0: {
           StorageLive(_2);
           StorageLive(_3);
           _3 = move _1;
-          _7 = (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]);
-          _2 = callee(move (*_7)) -> [return: bb3, unwind: bb4];
+          _10 = (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]);
+          _2 = callee(move (*_10)) -> [return: bb3, unwind: bb4];
       }
   
-      bb1: {
+      bb1 (cleanup): {
+          resume;
+      }
+  
+      bb2: {
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
           return;
       }
   
-      bb2 (cleanup): {
-          resume;
-      }
-  
       bb3: {
-          _4 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> bb1;
+          _4 = &mut _3;
+          _5 = <Box<[i32]> as Drop>::drop(move _4) -> [return: bb2, unwind: bb1];
       }
   
       bb4 (cleanup): {
-          _6 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> [return: bb2, unwind terminate];
+          _8 = &mut _3;
+          _9 = <Box<[i32]> as Drop>::drop(move _8) -> [return: bb1, unwind terminate];
       }
   }
   
diff --git a/tests/mir-opt/spanview_block.main.built.after.html b/tests/mir-opt/spanview_block.main.built.after.html
index b962d80c59e..56f4e4f9370 100644
--- a/tests/mir-opt/spanview_block.main.built.after.html
+++ b/tests/mir-opt/spanview_block.main.built.after.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
-<html>
+<html lang="en">
 <head>
+<meta charset="utf-8">
 <title>spanview_block.main.built.after</title>
 <style>
     .line {
diff --git a/tests/mir-opt/spanview_statement.main.built.after.html b/tests/mir-opt/spanview_statement.main.built.after.html
index 43bff7d096e..91af08d80a8 100644
--- a/tests/mir-opt/spanview_statement.main.built.after.html
+++ b/tests/mir-opt/spanview_statement.main.built.after.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
-<html>
+<html lang="en">
 <head>
+<meta charset="utf-8">
 <title>spanview_statement.main.built.after</title>
 <style>
     .line {
diff --git a/tests/mir-opt/spanview_terminator.main.built.after.html b/tests/mir-opt/spanview_terminator.main.built.after.html
index aa7e44c1571..1f42faedd1e 100644
--- a/tests/mir-opt/spanview_terminator.main.built.after.html
+++ b/tests/mir-opt/spanview_terminator.main.built.after.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
-<html>
+<html lang="en">
 <head>
+<meta charset="utf-8">
 <title>spanview_terminator.main.built.after</title>
 <style>
     .line {
diff --git a/tests/rustdoc-gui/setting-go-to-only-result.goml b/tests/rustdoc-gui/setting-go-to-only-result.goml
index c5720b4bf1a..45e0b349051 100644
--- a/tests/rustdoc-gui/setting-go-to-only-result.goml
+++ b/tests/rustdoc-gui/setting-go-to-only-result.goml
@@ -34,7 +34,14 @@ go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
 // We enter it into the search.
 write: (".search-input", "HasALongTraitWithParams")
 wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"}
-assert-document-property: ({"URL": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH)
+assert-window-property: ({"location": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH)
+
+// Regression test for <https://github.com/rust-lang/rust/issues/112676>.
+// If "go-to-only-result" is enabled and you go back to history, it should not lead you back to the
+// page result again automatically.
+history-go-back:
+wait-for-document-property: {"title": "lib2 - Rust"}
+assert-window-property: ({"location": "/lib2/index.html"}, ENDS_WITH)
 
 // We try again to see if it goes to the only result
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams"
diff --git a/tests/ui/asm/x86_64/parse-error.rs b/tests/ui/asm/parse-error.rs
index 2e714d464ae..9e002b1550f 100644
--- a/tests/ui/asm/x86_64/parse-error.rs
+++ b/tests/ui/asm/parse-error.rs
@@ -1,4 +1,4 @@
-// only-x86_64
+// needs-asm-support
 
 #![feature(asm_const)]
 
@@ -38,6 +38,9 @@ fn main() {
         //~^ ERROR expected one of
         asm!("{}", options(), const foo);
         //~^ ERROR attempt to use a non-constant value in a constant
+
+        // test that asm!'s clobber_abi doesn't accept non-string literals
+        // see also https://github.com/rust-lang/rust/issues/112635
         asm!("", clobber_abi());
         //~^ ERROR at least one abi must be provided
         asm!("", clobber_abi(foo));
@@ -46,6 +49,25 @@ fn main() {
         //~^ ERROR expected one of `)` or `,`, found `foo`
         asm!("", clobber_abi("C", foo));
         //~^ ERROR expected string literal
+        asm!("", clobber_abi(1));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi(()));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi(uwu));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi({}));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi(loop {}));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi(if));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi(do));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi(<));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi(.));
+        //~^ ERROR expected string literal
+
         asm!("{}", clobber_abi("C"), const foo);
         //~^ ERROR attempt to use a non-constant value in a constant
         asm!("", options(), clobber_abi("C"));
@@ -56,15 +78,7 @@ fn main() {
         //~^^ ERROR argument never used
         //~^^^ ERROR attempt to use a non-constant value in a constant
         //~^^^^ ERROR attempt to use a non-constant value in a constant
-        asm!("", a = in("eax") foo);
-        //~^ ERROR explicit register arguments cannot have names
-        asm!("{a}", in("eax") foo, a = const bar);
-        //~^ ERROR attempt to use a non-constant value in a constant
-        asm!("{a}", in("eax") foo, a = const bar);
-        //~^ ERROR attempt to use a non-constant value in a constant
-        asm!("{1}", in("eax") foo, const bar);
-        //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
-        //~^^ ERROR attempt to use a non-constant value in a constant
+
         asm!("", options(), "");
         //~^ ERROR expected one of
         asm!("{}", in(reg) foo, "{}", out(reg) foo);
diff --git a/tests/ui/asm/x86_64/parse-error.stderr b/tests/ui/asm/parse-error.stderr
index 0c9d6f71529..075d28e176a 100644
--- a/tests/ui/asm/x86_64/parse-error.stderr
+++ b/tests/ui/asm/parse-error.stderr
@@ -83,31 +83,85 @@ LL |         asm!("", options(nomem, foo));
    |                                 ^^^ expected one of 10 possible tokens
 
 error: at least one abi must be provided as an argument to `clobber_abi`
-  --> $DIR/parse-error.rs:41:30
+  --> $DIR/parse-error.rs:44:30
    |
 LL |         asm!("", clobber_abi());
    |                              ^
 
 error: expected string literal
-  --> $DIR/parse-error.rs:43:30
+  --> $DIR/parse-error.rs:46:30
    |
 LL |         asm!("", clobber_abi(foo));
    |                              ^^^ not a string literal
 
 error: expected one of `)` or `,`, found `foo`
-  --> $DIR/parse-error.rs:45:34
+  --> $DIR/parse-error.rs:48:34
    |
 LL |         asm!("", clobber_abi("C" foo));
    |                                  ^^^ expected one of `)` or `,`
 
 error: expected string literal
-  --> $DIR/parse-error.rs:47:35
+  --> $DIR/parse-error.rs:50:35
    |
 LL |         asm!("", clobber_abi("C", foo));
    |                                   ^^^ not a string literal
 
+error: expected string literal
+  --> $DIR/parse-error.rs:52:30
+   |
+LL |         asm!("", clobber_abi(1));
+   |                              ^ not a string literal
+
+error: expected string literal
+  --> $DIR/parse-error.rs:54:30
+   |
+LL |         asm!("", clobber_abi(()));
+   |                              ^ not a string literal
+
+error: expected string literal
+  --> $DIR/parse-error.rs:56:30
+   |
+LL |         asm!("", clobber_abi(uwu));
+   |                              ^^^ not a string literal
+
+error: expected string literal
+  --> $DIR/parse-error.rs:58:30
+   |
+LL |         asm!("", clobber_abi({}));
+   |                              ^ not a string literal
+
+error: expected string literal
+  --> $DIR/parse-error.rs:60:30
+   |
+LL |         asm!("", clobber_abi(loop {}));
+   |                              ^^^^ not a string literal
+
+error: expected string literal
+  --> $DIR/parse-error.rs:62:30
+   |
+LL |         asm!("", clobber_abi(if));
+   |                              ^^ not a string literal
+
+error: expected string literal
+  --> $DIR/parse-error.rs:64:30
+   |
+LL |         asm!("", clobber_abi(do));
+   |                              ^^ not a string literal
+
+error: expected string literal
+  --> $DIR/parse-error.rs:66:30
+   |
+LL |         asm!("", clobber_abi(<));
+   |                              ^ not a string literal
+
+error: expected string literal
+  --> $DIR/parse-error.rs:68:30
+   |
+LL |         asm!("", clobber_abi(.));
+   |                              ^ not a string literal
+
 error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:54:36
+  --> $DIR/parse-error.rs:76:36
    |
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                     -------------  ^^^^^^^^^^^^^ duplicate argument
@@ -115,41 +169,27 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    |                     previously here
 
 error: argument never used
-  --> $DIR/parse-error.rs:54:36
+  --> $DIR/parse-error.rs:76:36
    |
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                                    ^^^^^^^^^^^^^ argument never used
    |
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
 
-error: explicit register arguments cannot have names
-  --> $DIR/parse-error.rs:59:18
-   |
-LL |         asm!("", a = in("eax") foo);
-   |                  ^^^^^^^^^^^^^^^^^
-
-error: positional arguments cannot follow named arguments or explicit register arguments
-  --> $DIR/parse-error.rs:65:36
-   |
-LL |         asm!("{1}", in("eax") foo, const bar);
-   |                     -------------  ^^^^^^^^^ positional argument
-   |                     |
-   |                     explicit register argument
-
 error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
-  --> $DIR/parse-error.rs:68:29
+  --> $DIR/parse-error.rs:82:29
    |
 LL |         asm!("", options(), "");
    |                             ^^ expected one of 9 possible tokens
 
 error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
-  --> $DIR/parse-error.rs:70:33
+  --> $DIR/parse-error.rs:84:33
    |
 LL |         asm!("{}", in(reg) foo, "{}", out(reg) foo);
    |                                 ^^^^ expected one of 9 possible tokens
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:72:14
+  --> $DIR/parse-error.rs:86:14
    |
 LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
    |              ^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +197,7 @@ LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:74:21
+  --> $DIR/parse-error.rs:88:21
    |
 LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
    |                     ^^^^^^^^^^^^^^^^^^^^
@@ -165,121 +205,121 @@ LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:76:28
+  --> $DIR/parse-error.rs:90:28
    |
 LL |         asm!("{}", in(reg) _);
    |                            ^
 
 error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:78:31
+  --> $DIR/parse-error.rs:92:31
    |
 LL |         asm!("{}", inout(reg) _);
    |                               ^
 
 error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:80:35
+  --> $DIR/parse-error.rs:94:35
    |
 LL |         asm!("{}", inlateout(reg) _);
    |                                   ^
 
 error: requires at least a template string argument
-  --> $DIR/parse-error.rs:87:1
+  --> $DIR/parse-error.rs:101:1
    |
 LL | global_asm!();
    | ^^^^^^^^^^^^^
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:89:13
+  --> $DIR/parse-error.rs:103:13
    |
 LL | global_asm!(FOO);
    |             ^^^
 
 error: expected token: `,`
-  --> $DIR/parse-error.rs:91:18
+  --> $DIR/parse-error.rs:105:18
    |
 LL | global_asm!("{}" FOO);
    |                  ^^^ expected `,`
 
 error: expected operand, options, or additional template string
-  --> $DIR/parse-error.rs:93:19
+  --> $DIR/parse-error.rs:107:19
    |
 LL | global_asm!("{}", FOO);
    |                   ^^^ expected operand, options, or additional template string
 
 error: expected expression, found end of macro arguments
-  --> $DIR/parse-error.rs:95:24
+  --> $DIR/parse-error.rs:109:24
    |
 LL | global_asm!("{}", const);
    |                        ^ expected expression
 
 error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
-  --> $DIR/parse-error.rs:97:30
+  --> $DIR/parse-error.rs:111:30
    |
 LL | global_asm!("{}", const(reg) FOO);
    |                              ^^^ expected one of `,`, `.`, `?`, or an operator
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
-  --> $DIR/parse-error.rs:99:25
+  --> $DIR/parse-error.rs:113:25
    |
 LL | global_asm!("", options(FOO));
    |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
-  --> $DIR/parse-error.rs:101:25
+  --> $DIR/parse-error.rs:115:25
    |
 LL | global_asm!("", options(nomem FOO));
    |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
-  --> $DIR/parse-error.rs:103:25
+  --> $DIR/parse-error.rs:117:25
    |
 LL | global_asm!("", options(nomem, FOO));
    |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected string literal
-  --> $DIR/parse-error.rs:106:29
+  --> $DIR/parse-error.rs:120:29
    |
 LL | global_asm!("", clobber_abi(FOO));
    |                             ^^^ not a string literal
 
 error: expected one of `)` or `,`, found `FOO`
-  --> $DIR/parse-error.rs:108:33
+  --> $DIR/parse-error.rs:122:33
    |
 LL | global_asm!("", clobber_abi("C" FOO));
    |                                 ^^^ expected one of `)` or `,`
 
 error: expected string literal
-  --> $DIR/parse-error.rs:110:34
+  --> $DIR/parse-error.rs:124:34
    |
 LL | global_asm!("", clobber_abi("C", FOO));
    |                                  ^^^ not a string literal
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:112:19
+  --> $DIR/parse-error.rs:126:19
    |
 LL | global_asm!("{}", clobber_abi("C"), const FOO);
    |                   ^^^^^^^^^^^^^^^^
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:114:28
+  --> $DIR/parse-error.rs:128:28
    |
 LL | global_asm!("", options(), clobber_abi("C"));
    |                            ^^^^^^^^^^^^^^^^
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:116:30
+  --> $DIR/parse-error.rs:130:30
    |
 LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
    |                              ^^^^^^^^^^^^^^^^
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:118:17
+  --> $DIR/parse-error.rs:132:17
    |
 LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
    |                 ^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^
 
 error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:120:35
+  --> $DIR/parse-error.rs:134:35
    |
 LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                    -------------  ^^^^^^^^^^^^^ duplicate argument
@@ -287,7 +327,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                    previously here
 
 error: argument never used
-  --> $DIR/parse-error.rs:120:35
+  --> $DIR/parse-error.rs:134:35
    |
 LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                                   ^^^^^^^^^^^^^ argument never used
@@ -295,19 +335,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
 
 error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""`
-  --> $DIR/parse-error.rs:123:28
+  --> $DIR/parse-error.rs:137:28
    |
 LL | global_asm!("", options(), "");
    |                            ^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
 
 error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"`
-  --> $DIR/parse-error.rs:125:30
+  --> $DIR/parse-error.rs:139:30
    |
 LL | global_asm!("{}", const FOO, "{}", const FOO);
    |                              ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:127:13
+  --> $DIR/parse-error.rs:141:13
    |
 LL | global_asm!(format!("{{{}}}", 0), const FOO);
    |             ^^^^^^^^^^^^^^^^^^^^
@@ -315,7 +355,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO);
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:129:20
+  --> $DIR/parse-error.rs:143:20
    |
 LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
    |                    ^^^^^^^^^^^^^^^^^^^^
@@ -332,7 +372,7 @@ LL |         asm!("{}", options(), const foo);
    |                                     ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:49:44
+  --> $DIR/parse-error.rs:71:44
    |
 LL |     let mut foo = 0;
    |     ----------- help: consider using `const` instead of `let`: `const foo`
@@ -341,7 +381,7 @@ LL |         asm!("{}", clobber_abi("C"), const foo);
    |                                            ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:52:55
+  --> $DIR/parse-error.rs:74:55
    |
 LL |     let mut foo = 0;
    |     ----------- help: consider using `const` instead of `let`: `const foo`
@@ -350,7 +390,7 @@ LL |         asm!("{}", options(), clobber_abi("C"), const foo);
    |                                                       ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:54:31
+  --> $DIR/parse-error.rs:76:31
    |
 LL |     let mut foo = 0;
    |     ----------- help: consider using `const` instead of `let`: `const foo`
@@ -359,7 +399,7 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    |                               ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:54:46
+  --> $DIR/parse-error.rs:76:46
    |
 LL |     let mut bar = 0;
    |     ----------- help: consider using `const` instead of `let`: `const bar`
@@ -367,33 +407,6 @@ LL |     let mut bar = 0;
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                                              ^^^ non-constant value
 
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:61:46
-   |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
-LL |         asm!("{a}", in("eax") foo, a = const bar);
-   |                                              ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:63:46
-   |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
-LL |         asm!("{a}", in("eax") foo, a = const bar);
-   |                                              ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:65:42
-   |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
-LL |         asm!("{1}", in("eax") foo, const bar);
-   |                                          ^^^ non-constant value
-
-error: aborting due to 59 previous errors
+error: aborting due to 63 previous errors
 
 For more information about this error, try `rustc --explain E0435`.
diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.rs b/tests/ui/asm/x86_64/x86_64_parse_error.rs
new file mode 100644
index 00000000000..715a67687d1
--- /dev/null
+++ b/tests/ui/asm/x86_64/x86_64_parse_error.rs
@@ -0,0 +1,21 @@
+// only-x86_64
+
+#![feature(asm_const)]
+
+use std::arch::asm;
+
+fn main() {
+    let mut foo = 0;
+    let mut bar = 0;
+    unsafe {
+        asm!("", a = in("eax") foo);
+        //~^ ERROR explicit register arguments cannot have names
+        asm!("{a}", in("eax") foo, a = const bar);
+        //~^ ERROR attempt to use a non-constant value in a constant
+        asm!("{a}", in("eax") foo, a = const bar);
+        //~^ ERROR attempt to use a non-constant value in a constant
+        asm!("{1}", in("eax") foo, const bar);
+        //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
+        //~^^ ERROR attempt to use a non-constant value in a constant
+    }
+}
diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr
new file mode 100644
index 00000000000..f2854ae5128
--- /dev/null
+++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr
@@ -0,0 +1,44 @@
+error: explicit register arguments cannot have names
+  --> $DIR/x86_64_parse_error.rs:11:18
+   |
+LL |         asm!("", a = in("eax") foo);
+   |                  ^^^^^^^^^^^^^^^^^
+
+error: positional arguments cannot follow named arguments or explicit register arguments
+  --> $DIR/x86_64_parse_error.rs:17:36
+   |
+LL |         asm!("{1}", in("eax") foo, const bar);
+   |                     -------------  ^^^^^^^^^ positional argument
+   |                     |
+   |                     explicit register argument
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/x86_64_parse_error.rs:13:46
+   |
+LL |     let mut bar = 0;
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{a}", in("eax") foo, a = const bar);
+   |                                              ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/x86_64_parse_error.rs:15:46
+   |
+LL |     let mut bar = 0;
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{a}", in("eax") foo, a = const bar);
+   |                                              ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/x86_64_parse_error.rs:17:42
+   |
+LL |     let mut bar = 0;
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{1}", in("eax") foo, const bar);
+   |                                          ^^^ non-constant value
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
diff --git a/tests/ui/mir/ssa-analysis-regression-50041.rs b/tests/ui/mir/ssa-analysis-regression-50041.rs
index ebc3e2f8c0e..534f1c465bb 100644
--- a/tests/ui/mir/ssa-analysis-regression-50041.rs
+++ b/tests/ui/mir/ssa-analysis-regression-50041.rs
@@ -13,13 +13,10 @@ struct Unique<T: ?Sized>(NonNull<T>);
 pub struct Box<T: ?Sized>(Unique<T>);
 
 impl<T: ?Sized> Drop for Box<T> {
-    fn drop(&mut self) {}
-}
-
-#[lang = "box_free"]
-#[inline(always)]
-unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
-    dealloc(ptr.0.0)
+    #[inline(always)]
+    fn drop(&mut self) {
+        dealloc(self.0.0.0)
+    }
 }
 
 #[inline(never)]
diff --git a/triagebot.toml b/triagebot.toml
index 0f0b31e9f38..9248e8fc28a 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -477,6 +477,13 @@ message = "This PR changes src/bootstrap/defaults/config.compiler.toml. If appro
 [mentions."src/bootstrap/defaults/config.codegen.toml"]
 message = "This PR changes src/bootstrap/defaults/config.codegen.toml. If appropriate, please also update `config.compiler.toml` so the defaults are in sync."
 
+[mentions."src/bootstrap/llvm.rs"]
+message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp."
+[mentions."compiler/rustc_llvm/build.rs"]
+message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp."
+[mentions."compiler/rustc_llvm/llvm-wrapper"]
+message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp."
+
 [mentions."tests/ui/deriving/deriving-all-codegen.stdout"]
 message = "Changes to the code generated for builtin derived traits."
 cc = ["@nnethercote"]