about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock100
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs3
-rw-r--r--compiler/rustc_attr/src/builtin.rs49
-rw-r--r--compiler/rustc_borrowck/src/consumers.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs15
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs102
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock8
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs37
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/abi.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs12
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/type_.rs13
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs30
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/meth.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/mod.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/statics.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs17
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs8
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs60
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs54
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs52
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs107
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs219
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs146
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs42
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs183
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs70
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs84
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs146
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs103
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs52
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/src/lib.rs2
-rw-r--r--compiler/rustc_data_structures/src/stable_map.rs100
-rw-r--r--compiler/rustc_data_structures/src/stable_set.rs77
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_messages/src/lib.rs2
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs17
-rw-r--r--compiler/rustc_expand/src/base.rs6
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs13
-rw-r--r--compiler/rustc_hir/src/hir.rs10
-rw-r--r--compiler/rustc_hir/src/lang_items.rs6
-rw-r--r--compiler/rustc_hir/src/pat_util.rs2
-rw-r--r--compiler/rustc_hir/src/weak_lang_items.rs6
-rw-r--r--compiler/rustc_incremental/src/assert_module_sources.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/work_product.rs2
-rw-r--r--compiler/rustc_index/src/vec.rs8
-rw-r--r--compiler/rustc_infer/src/infer/at.rs1
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs539
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs41
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs67
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs87
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp9
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp2
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs2
-rw-r--r--compiler/rustc_macros/src/diagnostics/fluent.rs6
-rw-r--r--compiler/rustc_metadata/src/locator.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs7
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs15
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs1
-rw-r--r--compiler/rustc_middle/src/middle/mod.rs14
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs24
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs81
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs30
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs52
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs52
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs59
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs16
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs2
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs30
-rw-r--r--compiler/rustc_middle/src/mir/query.rs2
-rw-r--r--compiler/rustc_middle/src/mir/switch_sources.rs2
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs8
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs23
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs1
-rw-r--r--compiler/rustc_middle/src/traits/util.rs2
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs1
-rw-r--r--compiler/rustc_middle/src/ty/consts/valtree.rs10
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs18
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs6
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs14
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs30
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs28
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs18
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/un_derefer.rs2
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs12
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs12
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs2
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs6
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs78
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs8
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/default.rs4
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/mod.rs12
-rw-r--r--compiler/rustc_parse_format/src/lib.rs3
-rw-r--r--compiler/rustc_parse_format/src/tests.rs17
-rw-r--r--compiler/rustc_passes/src/lib_features.rs18
-rw-r--r--compiler/rustc_passes/src/stability.rs123
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs1
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs4
-rw-r--r--compiler/rustc_query_system/src/query/config.rs6
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs2
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs12
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/macros.rs11
-rw-r--r--compiler/rustc_serialize/Cargo.toml2
-rw-r--r--compiler/rustc_session/src/options.rs9
-rw-r--r--compiler/rustc_span/src/source_map.rs5
-rw-r--r--compiler/rustc_span/src/symbol.rs4
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml1
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs9
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid.rs18
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs929
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs38
-rw-r--r--compiler/rustc_target/src/abi/mod.rs12
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs2
-rw-r--r--compiler/rustc_target/src/asm/arm.rs2
-rw-r--r--compiler/rustc_target/src/asm/riscv.rs2
-rw-r--r--compiler/rustc_target/src/asm/x86.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_linux_android.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs4
-rw-r--r--compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs319
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs46
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs32
-rw-r--r--compiler/rustc_trait_selection/src/traits/relationships.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs73
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs13
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs5
-rw-r--r--compiler/rustc_ty_utils/src/representability.rs2
-rw-r--r--compiler/rustc_type_ir/src/codec.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/_match.rs169
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs6
-rw-r--r--compiler/rustc_typeck/src/check/check.rs84
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs6
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs4
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs4
-rw-r--r--compiler/rustc_typeck/src/check/fallback.rs3
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs84
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs48
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs123
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs3
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs2
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs7
-rw-r--r--compiler/rustc_typeck/src/check/inherited.rs7
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs4
-rw-r--r--compiler/rustc_typeck/src/check/intrinsicck.rs2
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs4
-rw-r--r--compiler/rustc_typeck/src/check/op.rs17
-rw-r--r--compiler/rustc_typeck/src/check/regionck.rs2
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs3
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs2
-rw-r--r--compiler/rustc_typeck/src/coherence/builtin.rs4
-rw-r--r--compiler/rustc_typeck/src/collect.rs45
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs13
-rw-r--r--library/alloc/src/collections/btree/map.rs30
-rw-r--r--library/core/src/cell.rs27
-rw-r--r--library/core/src/intrinsics.rs10
-rw-r--r--library/core/src/ops/control_flow.rs35
-rw-r--r--library/core/src/ptr/const_ptr.rs2
-rw-r--r--library/core/src/ptr/metadata.rs29
-rw-r--r--library/core/src/ptr/mut_ptr.rs8
-rw-r--r--library/core/src/result.rs9
-rw-r--r--library/core/src/slice/mod.rs61
-rw-r--r--library/core/tests/simd.rs1
-rw-r--r--library/panic_unwind/src/gcc.rs2
-rw-r--r--library/portable-simd/beginners-guide.md5
-rw-r--r--library/portable-simd/crates/core_simd/Cargo.toml3
-rw-r--r--library/portable-simd/crates/core_simd/src/comparisons.rs120
-rw-r--r--library/portable-simd/crates/core_simd/src/elements.rs11
-rw-r--r--library/portable-simd/crates/core_simd/src/elements/float.rs357
-rw-r--r--library/portable-simd/crates/core_simd/src/elements/int.rs298
-rw-r--r--library/portable-simd/crates/core_simd/src/elements/uint.rs139
-rw-r--r--library/portable-simd/crates/core_simd/src/eq.rs73
-rw-r--r--library/portable-simd/crates/core_simd/src/lane_count.rs8
-rw-r--r--library/portable-simd/crates/core_simd/src/lib.rs2
-rw-r--r--library/portable-simd/crates/core_simd/src/masks.rs55
-rw-r--r--library/portable-simd/crates/core_simd/src/masks/bitmask.rs20
-rw-r--r--library/portable-simd/crates/core_simd/src/masks/full_masks.rs85
-rw-r--r--library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs61
-rw-r--r--library/portable-simd/crates/core_simd/src/math.rs156
-rw-r--r--library/portable-simd/crates/core_simd/src/mod.rs12
-rw-r--r--library/portable-simd/crates/core_simd/src/ops.rs14
-rw-r--r--library/portable-simd/crates/core_simd/src/ops/unary.rs1
-rw-r--r--library/portable-simd/crates/core_simd/src/ord.rs213
-rw-r--r--library/portable-simd/crates/core_simd/src/reduction.rs153
-rw-r--r--library/portable-simd/crates/core_simd/src/round.rs40
-rw-r--r--library/portable-simd/crates/core_simd/src/swizzle.rs52
-rw-r--r--library/portable-simd/crates/core_simd/src/vector.rs157
-rw-r--r--library/portable-simd/crates/core_simd/src/vector/float.rs191
-rw-r--r--library/portable-simd/crates/core_simd/src/vector/int.rs84
-rw-r--r--library/portable-simd/crates/core_simd/src/vector/uint.rs40
-rw-r--r--library/portable-simd/crates/core_simd/tests/i16_ops.rs27
-rw-r--r--library/portable-simd/crates/core_simd/tests/masks.rs56
-rw-r--r--library/portable-simd/crates/core_simd/tests/ops_macros.rs48
-rw-r--r--library/portable-simd/crates/core_simd/tests/round.rs2
-rw-r--r--library/portable-simd/crates/test_helpers/src/lib.rs4
-rw-r--r--library/proc_macro/src/lib.rs8
-rw-r--r--library/std/build.rs1
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/fd/owned.rs4
-rw-r--r--library/std/src/os/mod.rs1
-rw-r--r--library/std/src/os/unix/mod.rs1
-rw-r--r--library/std/src/os/unix/net/stream.rs3
-rw-r--r--library/std/src/os/unix/ucred.rs4
-rw-r--r--library/std/src/os/unix/ucred/tests.rs3
-rw-r--r--library/std/src/sys/unix/args.rs4
-rw-r--r--library/std/src/sys/unix/env.rs11
-rw-r--r--library/std/src/sys/unix/fd.rs4
-rw-r--r--library/std/src/sys/unix/fs.rs25
-rw-r--r--library/std/src/sys/unix/futex.rs28
-rw-r--r--library/std/src/sys/unix/locks/fuchsia_mutex.rs165
-rw-r--r--library/std/src/sys/unix/locks/futex_condvar.rs58
-rw-r--r--library/std/src/sys/unix/locks/futex_mutex.rs (renamed from library/std/src/sys/unix/locks/futex.rs)56
-rw-r--r--library/std/src/sys/unix/locks/mod.rs13
-rw-r--r--library/std/src/sys/unix/locks/pthread_condvar.rs4
-rw-r--r--library/std/src/sys/unix/mod.rs3
-rw-r--r--library/std/src/sys/unix/os.rs6
-rw-r--r--library/std/src/sys/unix/rand.rs3
-rw-r--r--library/std/src/sys/unix/thread.rs237
-rw-r--r--library/std/src/sys/unix/thread_parker.rs15
-rw-r--r--library/std/src/sys/unix/time.rs4
-rw-r--r--library/std/src/sys_common/net.rs2
-rw-r--r--library/std/src/thread/mod.rs7
-rw-r--r--library/test/src/console.rs2
-rw-r--r--library/unwind/src/libunwind.rs6
-rw-r--r--src/bootstrap/test.rs8
m---------src/doc/book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md129
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs4
-rw-r--r--src/librustdoc/clean/inline.rs23
-rw-r--r--src/librustdoc/clean/mod.rs265
-rw-r--r--src/librustdoc/clean/types.rs19
-rw-r--r--src/librustdoc/clean/utils.rs11
-rw-r--r--src/librustdoc/core.rs3
-rw-r--r--src/librustdoc/fold.rs2
-rw-r--r--src/librustdoc/formats/cache.rs2
-rw-r--r--src/librustdoc/formats/item_type.rs2
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs12
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css26
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css8
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css8
-rw-r--r--src/librustdoc/html/static/css/themes/light.css8
-rw-r--r--src/librustdoc/json/conversions.rs10
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs5
-rw-r--r--src/librustdoc/passes/stripper.rs2
-rw-r--r--src/librustdoc/visit.rs2
-rw-r--r--src/stage0.json676
-rw-r--r--src/test/assembly/static-relocation-model.rs7
-rw-r--r--src/test/codegen/function-arguments.rs20
-rw-r--r--src/test/codegen/noalias-box-off.rs8
-rw-r--r--src/test/codegen/noalias-box.rs8
-rw-r--r--src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs (renamed from src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs)5
-rw-r--r--src/test/codegen/sanitizer-cfi-emit-type-checks.rs (renamed from src/test/codegen/sanitizer_cfi_emit_type_checks.rs)5
-rw-r--r--src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs575
-rw-r--r--src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs31
-rw-r--r--src/test/codegen/sanitizer_cfi_emit_type_metadata.rs31
-rw-r--r--src/test/codegen/sanitizer_scs_attr_check.rs17
-rw-r--r--src/test/codegen/simd-wide-sum.rs2
-rw-r--r--src/test/debuginfo/basic-types-globals-lto.rs81
-rw-r--r--src/test/debuginfo/basic-types-globals.rs6
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt21
-rw-r--r--src/test/run-make-fulldeps/coverage/inline-dead.rs20
-rw-r--r--src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/Makefile11
-rw-r--r--src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/test.rs3
-rw-r--r--src/test/run-make-fulldeps/used-cdylib-macos/Makefile11
-rw-r--r--src/test/run-make-fulldeps/used-cdylib-macos/dylib_used.rs4
-rw-r--r--src/test/rustdoc-gui/search-input.goml23
-rw-r--r--src/test/rustdoc-gui/search-result-display.goml2
-rw-r--r--src/test/rustdoc-ui/z-help.stdout2
-rw-r--r--src/test/rustdoc/const-generics/add-impl.rs2
-rw-r--r--src/test/rustdoc/const-generics/const-generic-defaults.rs2
-rw-r--r--src/test/rustdoc/const-generics/const-generics-docs.rs4
-rw-r--r--src/test/ui-fulldeps/gated-plugin.rs1
-rw-r--r--src/test/ui-fulldeps/gated-plugin.stderr4
-rw-r--r--src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs4
-rw-r--r--src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr8
-rw-r--r--src/test/ui-fulldeps/multiple-plugins.rs1
-rw-r--r--src/test/ui-fulldeps/multiple-plugins.stderr4
-rw-r--r--src/test/ui/argument-suggestions/issue-98894.rs4
-rw-r--r--src/test/ui/argument-suggestions/issue-98894.stderr19
-rw-r--r--src/test/ui/argument-suggestions/issue-98897.rs4
-rw-r--r--src/test/ui/argument-suggestions/issue-98897.stderr19
-rw-r--r--src/test/ui/argument-suggestions/issue-99482.rs5
-rw-r--r--src/test/ui/argument-suggestions/issue-99482.stderr19
-rw-r--r--src/test/ui/array-slice-vec/match_arr_unknown_len.stderr2
-rw-r--r--src/test/ui/asm/x86_64/issue-96797.rs26
-rw-r--r--src/test/ui/async-await/async-block-control-flow-static-semantics.stderr18
-rw-r--r--src/test/ui/btreemap/btreemap_dropck.rs16
-rw-r--r--src/test/ui/btreemap/btreemap_dropck.stderr13
-rw-r--r--src/test/ui/closures/issue-99565.rs7
-rw-r--r--src/test/ui/closures/issue-99565.stderr14
-rw-r--r--src/test/ui/const-generics/associated-type-bound-fail.stderr2
-rw-r--r--src/test/ui/const-generics/defaults/generic-expr-default-concrete.stderr6
-rw-r--r--src/test/ui/const-generics/defaults/mismatch.rs22
-rw-r--r--src/test/ui/const-generics/defaults/mismatch.stderr34
-rw-r--r--src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs5
-rw-r--r--src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr18
-rw-r--r--src/test/ui/const-generics/defaults/trait_objects_fail.rs4
-rw-r--r--src/test/ui/const-generics/defaults/trait_objects_fail.stderr10
-rw-r--r--src/test/ui/const-generics/defaults/wfness.rs12
-rw-r--r--src/test/ui/const-generics/defaults/wfness.stderr27
-rw-r--r--src/test/ui/const-generics/different_generic_args.full.stderr6
-rw-r--r--src/test/ui/const-generics/different_generic_args.min.stderr6
-rw-r--r--src/test/ui/const-generics/different_generic_args_array.stderr6
-rw-r--r--src/test/ui/const-generics/exhaustive-value.stderr16
-rw-r--r--src/test/ui/const-generics/generic_arg_infer/in-signature.stderr12
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr24
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr4
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr8
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/simple_fail.rs9
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr10
-rw-r--r--src/test/ui/const-generics/infer/one-param-uninferred.stderr4
-rw-r--r--src/test/ui/const-generics/issue-66451.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-86530.rs1
-rw-r--r--src/test/ui/const-generics/issues/issue-86530.stderr18
-rw-r--r--src/test/ui/const-generics/issues/issue-98629.rs15
-rw-r--r--src/test/ui/const-generics/issues/issue-98629.stderr12
-rw-r--r--src/test/ui/const-generics/nested-type.full.stderr2
-rw-r--r--src/test/ui/const-generics/occurs-check/unused-substs-1.stderr6
-rw-r--r--src/test/ui/const-generics/types-mismatch-const-args.full.stderr10
-rw-r--r--src/test/ui/const-generics/types-mismatch-const-args.min.stderr10
-rw-r--r--src/test/ui/consts/const-eval/const_transmute.rs54
-rw-r--r--src/test/ui/consts/const-eval/issue-85155.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr36
-rw-r--r--src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr36
-rw-r--r--src/test/ui/consts/const-eval/ub-incorrect-vtable.rs62
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr6
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr6
-rw-r--r--src/test/ui/consts/const-eval/ub-upvars.32bit.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-upvars.64bit.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr79
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr79
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.rs20
-rw-r--r--src/test/ui/consts/issue-79690.64bit.stderr4
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr4
-rw-r--r--src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr4
-rw-r--r--src/test/ui/deriving/deriving-all-codegen.stdout99
-rw-r--r--src/test/ui/dropck/reject-specialized-drops-8142.stderr2
-rw-r--r--src/test/ui/extern-flag/empty-extern-arg.stderr4
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.rs3
-rw-r--r--src/test/ui/fmt/ifmt-bad-arg.stderr15
-rw-r--r--src/test/ui/generator/issue-52304.rs11
-rw-r--r--src/test/ui/impl-trait/issue-99073-2.rs17
-rw-r--r--src/test/ui/impl-trait/issue-99073-2.stderr15
-rw-r--r--src/test/ui/impl-trait/issue-99073.rs8
-rw-r--r--src/test/ui/impl-trait/issue-99073.stderr14
-rw-r--r--src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs2
-rw-r--r--src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr22
-rw-r--r--src/test/ui/impl-trait/negative-reasoning.stderr2
-rw-r--r--src/test/ui/inference/deref-suggestion.rs3
-rw-r--r--src/test/ui/inference/deref-suggestion.stderr24
-rw-r--r--src/test/ui/inline-const/const-expr-generic-err.stderr4
-rw-r--r--src/test/ui/invalid/invalid-no-sanitize.stderr2
-rw-r--r--src/test/ui/issues/issue-23041.stderr2
-rw-r--r--src/test/ui/issues/issue-24013.stderr2
-rw-r--r--src/test/ui/issues/issue-59494.stderr2
-rw-r--r--src/test/ui/issues/issue-72554.rs5
-rw-r--r--src/test/ui/issues/issue-72554.stderr19
-rw-r--r--src/test/ui/issues/issue-77919.rs1
-rw-r--r--src/test/ui/issues/issue-77919.stderr16
-rw-r--r--src/test/ui/kindck/kindck-copy.stderr8
-rw-r--r--src/test/ui/lint/auxiliary/add-impl.rs22
-rw-r--r--src/test/ui/lint/function-item-references.stderr4
-rw-r--r--src/test/ui/lint/unused-qualification-in-derive-expansion.rs16
-rw-r--r--src/test/ui/macros/meta-variable-depth-outside-repeat.rs12
-rw-r--r--src/test/ui/macros/meta-variable-depth-outside-repeat.stderr8
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs9
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr6
-rw-r--r--src/test/ui/methods/method-not-found-generic-arg-elision.rs14
-rw-r--r--src/test/ui/methods/method-not-found-generic-arg-elision.stderr8
-rw-r--r--src/test/ui/not-panic/not-panic-safe.stderr7
-rw-r--r--src/test/ui/panic-handler/weak-lang-item.stderr4
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.rs4
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.stderr46
-rw-r--r--src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs2
-rw-r--r--src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr23
-rw-r--r--src/test/ui/simd/intrinsic/generic-shuffle.stderr4
-rw-r--r--src/test/ui/simd/libm_no_std_cant_float.rs1
-rw-r--r--src/test/ui/simd/libm_no_std_cant_float.stderr24
-rw-r--r--src/test/ui/simd/libm_std_can_float.rs2
-rw-r--r--src/test/ui/simd/type-generic-monomorphisation-empty.rs2
-rw-r--r--src/test/ui/simd/type-generic-monomorphisation-empty.stderr2
-rw-r--r--src/test/ui/simd/type-generic-monomorphisation-oversized.rs2
-rw-r--r--src/test/ui/simd/type-generic-monomorphisation-oversized.stderr2
-rw-r--r--src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs8
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-missing.rs10
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr8
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs13
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr21
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs15
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr22
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs17
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr22
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr2
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity.stderr2
-rw-r--r--src/test/ui/suggestions/return-bindings.fixed23
-rw-r--r--src/test/ui/suggestions/return-bindings.rs34
-rw-r--r--src/test/ui/suggestions/return-bindings.stderr70
-rw-r--r--src/test/ui/traits/issue-32963.rs1
-rw-r--r--src/test/ui/traits/issue-32963.stderr17
-rw-r--r--src/test/ui/traits/suggest-where-clause.stderr4
-rw-r--r--src/test/ui/traits/vtable/vtable-diamond.rs5
-rw-r--r--src/test/ui/traits/vtable/vtable-multi-level.rs25
-rw-r--r--src/test/ui/traits/vtable/vtable-multi-level.stderr51
-rw-r--r--src/test/ui/traits/vtable/vtable-multiple.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57961.rs18
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57961.stderr20
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr4
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr4
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr7
-rw-r--r--src/test/ui/unsized/issue-30355.rs1
-rw-r--r--src/test/ui/unsized/issue-30355.stderr16
-rw-r--r--src/tools/bump-stage0/Cargo.toml2
-rw-r--r--src/tools/cargotest/main.rs29
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr10
-rw-r--r--src/tools/compiletest/src/header.rs41
-rw-r--r--src/tools/compiletest/src/runtest.rs27
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs15
-rw-r--r--src/tools/compiletest/src/util.rs19
m---------src/tools/miri16
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/tidy/src/error_codes_check.rs4
491 files changed, 8756 insertions, 4957 deletions
diff --git a/Cargo.lock b/Cargo.lock
index db8e3d5adbb..ed3e30342f2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -319,9 +319,9 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
 
 [[package]]
 name = "camino"
-version = "1.0.5"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b"
+checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412"
 dependencies = [
  "serde",
 ]
@@ -507,6 +507,19 @@ dependencies = [
 ]
 
 [[package]]
+name = "cargo_metadata"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36"
+dependencies = [
+ "camino",
+ "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
 name = "cargotest2"
 version = "0.1.0"
 
@@ -696,7 +709,7 @@ dependencies = [
 name = "clippy_lints"
 version = "0.1.64"
 dependencies = [
- "cargo_metadata",
+ "cargo_metadata 0.14.0",
  "clippy_utils",
  "if_chain",
  "itertools",
@@ -1713,18 +1726,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.11.2"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
-dependencies = [
- "ahash",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 dependencies = [
  "ahash",
  "compiler_builtins",
@@ -1883,12 +1887,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
 
 [[package]]
 name = "indexmap"
-version = "1.8.2"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a"
+checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 dependencies = [
  "autocfg",
- "hashbrown 0.11.2",
+ "hashbrown",
  "rustc-rayon",
  "serde",
 ]
@@ -1959,9 +1963,9 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "0.4.6"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
+checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
 
 [[package]]
 name = "jemalloc-sys"
@@ -2348,9 +2352,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.20"
+version = "0.4.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13cdad8057b09a519c6c63e6d7c93ea854f5d7fbfe284df864d5e1140d215a2d"
+checksum = "23f3e133c6d515528745ffd3b9f0c7d975ae039f0b6abb099f2168daa2afb4f9"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -2376,9 +2380,9 @@ dependencies = [
 
 [[package]]
 name = "measureme"
-version = "10.0.0"
+version = "10.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd460fad6e55ca82fa0cd9dab0d315294188fd9ec6efbf4105e5635d4872ef9c"
+checksum = "cbdc226fa10994e8f66a4d2f6f000148bc563a1c671b6dcd2135737018033d8a"
 dependencies = [
  "log",
  "memmap2",
@@ -2565,25 +2569,13 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.28.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
-dependencies = [
- "crc32fast",
- "flate2",
- "hashbrown 0.11.2",
- "indexmap",
- "memchr",
-]
-
-[[package]]
-name = "object"
 version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
 dependencies = [
  "crc32fast",
- "hashbrown 0.12.0",
+ "flate2",
+ "hashbrown",
  "indexmap",
  "memchr",
 ]
@@ -3316,7 +3308,7 @@ dependencies = [
  "anyhow",
  "cargo",
  "cargo-util",
- "cargo_metadata",
+ "cargo_metadata 0.14.0",
  "clippy_lints",
  "crossbeam-channel",
  "difference",
@@ -4506,6 +4498,7 @@ dependencies = [
 name = "rustc_symbol_mangling"
 version = "0.0.0"
 dependencies = [
+ "bitflags",
  "punycode",
  "rustc-demangle",
  "rustc_data_structures",
@@ -4723,7 +4716,7 @@ dependencies = [
  "annotate-snippets 0.9.1",
  "anyhow",
  "bytecount",
- "cargo_metadata",
+ "cargo_metadata 0.14.0",
  "clap",
  "derive-new",
  "diff",
@@ -4821,27 +4814,27 @@ checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
 
 [[package]]
 name = "semver"
-version = "1.0.3"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe"
+checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.125"
+version = "1.0.140"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
+checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.125"
+version = "1.0.140"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
+checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4859,9 +4852,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.59"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
+checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
 dependencies = [
  "indexmap",
  "itoa",
@@ -5054,7 +5047,7 @@ dependencies = [
  "core",
  "dlmalloc",
  "fortanix-sgx-abi",
- "hashbrown 0.12.0",
+ "hashbrown",
  "hermit-abi 0.2.0",
  "libc",
  "miniz_oxide 0.4.0",
@@ -5265,13 +5258,13 @@ dependencies = [
 
 [[package]]
 name = "thorin-dwp"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd95b4559c196987c8451b4e14d08a4c796c2844f9adf4d2a2dbc9b3142843be"
+checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254"
 dependencies = [
  "gimli 0.26.1",
- "hashbrown 0.11.2",
- "object 0.28.4",
+ "hashbrown",
+ "object 0.29.0",
  "tracing",
 ]
 
@@ -5288,7 +5281,7 @@ dependencies = [
 name = "tidy"
 version = "0.1.0"
 dependencies = [
- "cargo_metadata",
+ "cargo_metadata 0.14.0",
  "crossbeam-utils",
  "lazy_static",
  "regex",
@@ -5518,6 +5511,7 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 name = "ui_test"
 version = "0.1.0"
 dependencies = [
+ "cargo_metadata 0.15.0",
  "color-eyre",
  "colored",
  "crossbeam",
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index cd77dbca3c4..4166b4fc2e5 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -4,8 +4,7 @@ use super::LoweringContext;
 
 use rustc_ast::ptr::P;
 use rustc_ast::*;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index dcfbecedfe8..64a6f91f022 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -135,9 +135,42 @@ impl ConstStability {
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
 #[derive(HashStable_Generic)]
 pub enum StabilityLevel {
-    // Reason for the current stability level and the relevant rust-lang issue
-    Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
-    Stable { since: Symbol, allowed_through_unstable_modules: bool },
+    /// `#[unstable]`
+    Unstable {
+        /// Reason for the current stability level.
+        reason: Option<Symbol>,
+        /// Relevant `rust-lang/rust` issue.
+        issue: Option<NonZeroU32>,
+        is_soft: bool,
+        /// If part of a feature is stabilized and a new feature is added for the remaining parts,
+        /// then the `implied_by` attribute is used to indicate which now-stable feature previously
+        /// contained a item.
+        ///
+        /// ```pseudo-Rust
+        /// #[unstable(feature = "foo", issue = "...")]
+        /// fn foo() {}
+        /// #[unstable(feature = "foo", issue = "...")]
+        /// fn foobar() {}
+        /// ```
+        ///
+        /// ...becomes...
+        ///
+        /// ```pseudo-Rust
+        /// #[stable(feature = "foo", since = "1.XX.X")]
+        /// fn foo() {}
+        /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")]
+        /// fn foobar() {}
+        /// ```
+        implied_by: Option<Symbol>,
+    },
+    /// `#[stable]`
+    Stable {
+        /// Rust release which stabilized this feature.
+        since: Symbol,
+        /// Is this item allowed to be referred to on stable, despite being contained in unstable
+        /// modules?
+        allowed_through_unstable_modules: bool,
+    },
 }
 
 impl StabilityLevel {
@@ -243,6 +276,7 @@ where
                     let mut issue = None;
                     let mut issue_num = None;
                     let mut is_soft = false;
+                    let mut implied_by = None;
                     for meta in metas {
                         let Some(mi) = meta.meta_item() else {
                             handle_errors(
@@ -308,6 +342,11 @@ where
                                 }
                                 is_soft = true;
                             }
+                            sym::implied_by => {
+                                if !get(mi, &mut implied_by) {
+                                    continue 'outer;
+                                }
+                            }
                             _ => {
                                 handle_errors(
                                     &sess.parse_sess,
@@ -332,7 +371,7 @@ where
                                 );
                                 continue;
                             }
-                            let level = Unstable { reason, issue: issue_num, is_soft };
+                            let level = Unstable { reason, issue: issue_num, is_soft, implied_by };
                             if sym::unstable == meta_name {
                                 stab = Some((Stability { level, feature }, attr.span));
                             } else {
@@ -391,7 +430,7 @@ where
                                         meta.span(),
                                         AttrError::UnknownMetaItem(
                                             pprust::path_to_string(&mi.path),
-                                            &["since", "note"],
+                                            &["feature", "since"],
                                         ),
                                     );
                                     continue 'outer;
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
index 97daad201d9..efc17a173f4 100644
--- a/compiler/rustc_borrowck/src/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -2,7 +2,7 @@
 
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::vec::IndexVec;
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
 use rustc_middle::mir::Body;
 use rustc_middle::ty::{self, TyCtxt};
 
@@ -31,7 +31,7 @@ pub fn get_body_with_borrowck_facts<'tcx>(
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> BodyWithBorrowckFacts<'tcx> {
     let (input_body, promoted) = tcx.mir_promoted(def);
-    tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
+    tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| {
         let input_body: &Body<'_> = &input_body.borrow();
         let promoted: &IndexVec<_, _> = &promoted.borrow();
         *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 0e6a05478a0..07aba50f03b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -1,6 +1,6 @@
 //! Error reporting machinery for lifetime errors.
 
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 29f47200b80..9dfefe4d236 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -24,7 +24,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::bit_set::ChunkedBitSet;
 use rustc_index::vec::IndexVec;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::{
     traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
     PlaceRef, VarDebugInfoContents,
@@ -130,11 +130,14 @@ fn mir_borrowck<'tcx>(
     debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
     let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
 
-    let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
-        let input_body: &Body<'_> = &input_body.borrow();
-        let promoted: &IndexVec<_, _> = &promoted.borrow();
-        do_mir_borrowck(&infcx, input_body, promoted, false).0
-    });
+    let opt_closure_req = tcx
+        .infer_ctxt()
+        .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner))
+        .enter(|infcx| {
+            let input_body: &Body<'_> = &input_body.borrow();
+            let promoted: &IndexVec<_, _> = &promoted.borrow();
+            do_mir_borrowck(&infcx, input_body, promoted, false).0
+        });
     debug!("mir_borrowck done");
 
     tcx.arena.alloc(opt_closure_req)
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index de9da845729..407bbf48813 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -3,8 +3,8 @@ use rustc_data_structures::vec_map::VecMap;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::OpaqueTyOrigin;
 use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
-use rustc_infer::infer::InferCtxt;
 use rustc_infer::infer::TyCtxtInferExt as _;
+use rustc_infer::infer::{DefiningAnchor, InferCtxt};
 use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
@@ -269,59 +269,65 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
             let param_env = self.tcx.param_env(def_id);
             let body_id = self.tcx.local_def_id_to_hir_id(def_id);
-            self.tcx.infer_ctxt().enter(move |infcx| {
-                // 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()))
-                        .to_predicate(infcx.tcx);
-                let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
-
-                // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
-                // the bounds that the function supplies.
-                match infcx.register_hidden_type(
-                    OpaqueTypeKey { def_id, substs: id_substs },
-                    ObligationCause::misc(instantiated_ty.span, body_id),
-                    param_env,
-                    definition_ty,
-                    origin,
-                ) {
-                    Ok(infer_ok) => {
-                        for obligation in infer_ok.obligations {
-                            fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+            // HACK This bubble is required for this tests to pass:
+            // type-alias-impl-trait/issue-67844-nested-opaque.rs
+            self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(
+                move |infcx| {
+                    // 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()))
+                            .to_predicate(infcx.tcx);
+                    let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+
+                    // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
+                    // the bounds that the function supplies.
+                    match infcx.register_hidden_type(
+                        OpaqueTypeKey { def_id, substs: id_substs },
+                        ObligationCause::misc(instantiated_ty.span, body_id),
+                        param_env,
+                        definition_ty,
+                        origin,
+                    ) {
+                        Ok(infer_ok) => {
+                            for obligation in infer_ok.obligations {
+                                fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+                            }
+                        }
+                        Err(err) => {
+                            infcx
+                                .report_mismatched_types(
+                                    &ObligationCause::misc(instantiated_ty.span, body_id),
+                                    self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
+                                    definition_ty,
+                                    err,
+                                )
+                                .emit();
                         }
                     }
-                    Err(err) => {
-                        infcx
-                            .report_mismatched_types(
-                                &ObligationCause::misc(instantiated_ty.span, body_id),
-                                self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
-                                definition_ty,
-                                err,
-                            )
-                            .emit();
-                    }
-                }
 
-                fulfillment_cx.register_predicate_obligation(
-                    &infcx,
-                    Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
-                );
+                    fulfillment_cx.register_predicate_obligation(
+                        &infcx,
+                        Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
+                    );
 
-                // Check that all obligations are satisfied by the implementation's
-                // version.
-                let errors = fulfillment_cx.select_all_or_error(&infcx);
+                    // Check that all obligations are satisfied by the implementation's
+                    // version.
+                    let errors = fulfillment_cx.select_all_or_error(&infcx);
 
-                let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+                    // This is still required for many(half of the tests in ui/type-alias-impl-trait)
+                    // tests to pass
+                    let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 
-                if errors.is_empty() {
-                    definition_ty
-                } else {
-                    infcx.report_fulfillment_errors(&errors, None, false);
-                    self.tcx.ty_error()
-                }
-            })
+                    if errors.is_empty() {
+                        definition_ty
+                    } else {
+                        infcx.report_fulfillment_errors(&errors, None, false);
+                        self.tcx.ty_error()
+                    }
+                },
+            )
         } else {
             definition_ty
         }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index cf2140097e6..eb9df281e7d 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -21,6 +21,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
 use rustc_infer::infer::{
     InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
 };
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::AssertKind;
@@ -224,6 +225,26 @@ pub(crate) fn type_check<'mir, 'tcx>(
                     )
                     .unwrap();
                     let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
+                    // Check that RPITs are only constrained in their outermost
+                    // function, otherwise report a mismatched types error.
+                    if let OpaqueTyOrigin::FnReturn(parent) | OpaqueTyOrigin::AsyncFn(parent)
+                            = infcx.opaque_ty_origin_unchecked(opaque_type_key.def_id, hidden_type.span)
+                        && parent.to_def_id() != body.source.def_id()
+                    {
+                        infcx
+                            .report_mismatched_types(
+                                &ObligationCause::misc(
+                                    hidden_type.span,
+                                    infcx.tcx.hir().local_def_id_to_hir_id(
+                                        body.source.def_id().expect_local(),
+                                    ),
+                                ),
+                                infcx.tcx.mk_opaque(opaque_type_key.def_id.to_def_id(), opaque_type_key.substs),
+                                hidden_type.ty,
+                                ty::error::TypeError::Mismatch,
+                            )
+                            .emit();
+                    }
                     trace!(
                         "finalized opaque type {:?} to {:#?}",
                         opaque_type_key,
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 076b627ca79..735017aa5a8 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -727,16 +727,8 @@ impl<'a> TraitDef<'a> {
 
         let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
         let opt_trait_ref = Some(trait_ref);
-        let unused_qual = {
-            let word = rustc_ast::attr::mk_nested_word_item(Ident::new(
-                sym::unused_qualifications,
-                self.span,
-            ));
-            let list = rustc_ast::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]);
-            cx.attribute(list)
-        };
 
-        let mut a = vec![attr, unused_qual];
+        let mut a = vec![attr];
         a.extend(self.attributes.iter().cloned());
 
         cx.item(
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 3b7e2102ffa..ce897abb766 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -485,7 +485,7 @@ impl<'a, 'b> Context<'a, 'b> {
             if let Some(span) = fmt.width_span {
                 let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
                 match fmt.width {
-                    parse::CountIsParam(pos) if pos > self.num_args() => {
+                    parse::CountIsParam(pos) if pos >= self.num_args() => {
                         e.span_label(
                             span,
                             &format!(
@@ -1004,9 +1004,7 @@ fn lint_named_arguments_used_positionally(
                 node_id: ast::CRATE_NODE_ID,
                 lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
                 diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally(
-                    arg_span,
-                    span,
-                    symbol.to_string(),
+                    arg_span, span, symbol,
                 ),
             });
         }
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index da18ac7eacb..2f5d1c0432f 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -163,15 +163,15 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.11.2"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
 [[package]]
 name = "indexmap"
-version = "1.8.0"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
+checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 dependencies = [
  "autocfg",
  "hashbrown",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index ec2c1f2ca71..ff71d7a209e 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -19,7 +19,7 @@ gimli = { version = "0.26.0", default-features = false, features = ["write"]}
 object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
 ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
-indexmap = "1.8.0"
+indexmap = "1.9.1"
 libloading = { version = "0.6.0", optional = true }
 once_cell = "1.10.0"
 smallvec = "1.8.1"
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 48972321a9f..94a2fb2fbdd 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -195,9 +195,8 @@ pub(crate) fn codegen_const_value<'tcx>(
             }
             Scalar::Ptr(ptr, _size) => {
                 let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative
-                let alloc_kind = fx.tcx.get_global_alloc(alloc_id);
-                let base_addr = match alloc_kind {
-                    Some(GlobalAlloc::Memory(alloc)) => {
+                let base_addr = match fx.tcx.global_alloc(alloc_id) {
+                    GlobalAlloc::Memory(alloc) => {
                         let data_id = data_id_for_alloc_id(
                             &mut fx.constants_cx,
                             fx.module,
@@ -211,13 +210,27 @@ pub(crate) fn codegen_const_value<'tcx>(
                         }
                         fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
                     }
-                    Some(GlobalAlloc::Function(instance)) => {
+                    GlobalAlloc::Function(instance) => {
                         let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);
                         let local_func_id =
                             fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
                         fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
                     }
-                    Some(GlobalAlloc::Static(def_id)) => {
+                    GlobalAlloc::VTable(ty, trait_ref) => {
+                        let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref));
+                        let alloc = fx.tcx.global_alloc(alloc_id).unwrap_memory();
+                        // FIXME: factor this common code with the `Memory` arm into a function?
+                        let data_id = data_id_for_alloc_id(
+                            &mut fx.constants_cx,
+                            fx.module,
+                            alloc_id,
+                            alloc.inner().mutability,
+                        );
+                        let local_data_id =
+                            fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+                        fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
+                    }
+                    GlobalAlloc::Static(def_id) => {
                         assert!(fx.tcx.is_static(def_id));
                         let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
                         let local_data_id =
@@ -227,7 +240,6 @@ pub(crate) fn codegen_const_value<'tcx>(
                         }
                         fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
                     }
-                    None => bug!("missing allocation {:?}", alloc_id),
                 };
                 let val = if offset.bytes() != 0 {
                     fx.bcx.ins().iadd_imm(base_addr, i64::try_from(offset.bytes()).unwrap())
@@ -357,10 +369,11 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
     while let Some(todo_item) = cx.todo.pop() {
         let (data_id, alloc, section_name) = match todo_item {
             TodoItem::Alloc(alloc_id) => {
-                //println!("alloc_id {}", alloc_id);
-                let alloc = match tcx.get_global_alloc(alloc_id).unwrap() {
+                let alloc = match tcx.global_alloc(alloc_id) {
                     GlobalAlloc::Memory(alloc) => alloc,
-                    GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(),
+                    GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => {
+                        unreachable!()
+                    }
                 };
                 let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
                     module
@@ -424,7 +437,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 read_target_uint(endianness, bytes).unwrap()
             };
 
-            let reloc_target_alloc = tcx.get_global_alloc(alloc_id).unwrap();
+            let reloc_target_alloc = tcx.global_alloc(alloc_id);
             let data_id = match reloc_target_alloc {
                 GlobalAlloc::Function(instance) => {
                     assert_eq!(addend, 0);
@@ -436,6 +449,10 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 GlobalAlloc::Memory(target_alloc) => {
                     data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability)
                 }
+                GlobalAlloc::VTable(ty, trait_ref) => {
+                    let alloc_id = tcx.vtable_allocation((ty, trait_ref));
+                    data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not)
+                }
                 GlobalAlloc::Static(def_id) => {
                     if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
                     {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 4b2207f3758..d5a79e254a8 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -431,6 +431,16 @@ fn codegen_regular_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
         };
 
+        vtable_size, (v vtable) {
+            let size = crate::vtable::size_of_obj(fx, vtable);
+            ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
+        };
+
+        vtable_align, (v vtable) {
+            let align = crate::vtable::min_align_of_obj(fx, vtable);
+            ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
+        };
+
         unchecked_add | unchecked_sub | unchecked_mul | unchecked_div | exact_div | unchecked_rem
         | unchecked_shl | unchecked_shr, (c x, c y) {
             // FIXME trap on overflow
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index 2c796d0f69e..0ed3e1fbe93 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -1,6 +1,6 @@
 use gccjit::{ToLValue, ToRValue, Type};
 use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::bug;
 use rustc_middle::ty::Ty;
 use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind};
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index fa490fe3f22..4d40dd0994d 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -30,7 +30,7 @@ use rustc_codegen_ssa::traits::{
     OverflowOp,
     StaticBuilderMethods,
 };
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_span::Span;
@@ -784,16 +784,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         // TODO(antoyo)
     }
 
-    fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
-        // Unsupported.
-    }
-
-    fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
-        // Unsupported.
-        self.context.new_rvalue_from_int(self.int_type, 0)
-    }
-
-
     fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
         self.store_with_flags(val, ptr, align, MemFlags::empty())
     }
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index fc391f53f18..ccb6cbbc2c8 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -201,6 +201,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                         GlobalAlloc::Function(fn_instance) => {
                             self.get_fn_addr(fn_instance)
                         },
+                        GlobalAlloc::VTable(ty, trait_ref) => {
+                            let alloc = self.tcx.global_alloc(self.tcx.vtable_allocation((ty, trait_ref))).unwrap_memory();
+                            let init = const_alloc_to_gcc(self, alloc);
+                            self.static_addr_of(init, alloc.inner().align, None)
+                        }
                         GlobalAlloc::Static(def_id) => {
                             assert!(self.tcx.is_static(def_id));
                             self.get_static(def_id).get_address(None)
diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
index 002b95db36d..68bdb8d4e55 100644
--- a/compiler/rustc_codegen_gcc/src/type_.rs
+++ b/compiler/rustc_codegen_gcc/src/type_.rs
@@ -1,7 +1,7 @@
 use std::convert::TryInto;
 
 use gccjit::{RValue, Struct, Type};
-use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods};
+use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods};
 use rustc_codegen_ssa::common::TypeKind;
 use rustc_middle::{bug, ty};
 use rustc_middle::ty::layout::TyAndLayout;
@@ -290,3 +290,14 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
 
     (result, packed)
 }
+
+impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) {
+        // Unsupported.
+    }
+
+    fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> {
+        // Unsupported.
+        self.context.new_rvalue_from_int(self.int_type, 0)
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index d8fbd0a84fb..f9a5463efcd 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -18,7 +18,6 @@ rustc_middle = { path = "../rustc_middle" }
 rustc-demangle = "0.1.21"
 rustc_attr = { path = "../rustc_attr" }
 rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
-rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fs_util = { path = "../rustc_fs_util" }
@@ -30,6 +29,7 @@ rustc_metadata = { path = "../rustc_metadata" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_serialize = { path = "../rustc_serialize" }
+rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_target = { path = "../rustc_target" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 62da99ac3fb..1a96dd8bec4 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -69,6 +69,9 @@ pub fn sanitize_attrs<'ll>(
     if enabled.contains(SanitizerSet::HWADDRESS) {
         attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx));
     }
+    if enabled.contains(SanitizerSet::SHADOWCALLSTACK) {
+        attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx));
+    }
     if enabled.contains(SanitizerSet::MEMTAG) {
         // Check to make sure the mte target feature is actually enabled.
         let features = cx.tcx.global_backend_features(());
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index be539499b56..3731c6bcfe7 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -199,7 +199,7 @@ pub(crate) fn run_thin(
 
 pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBuffer) {
     let name = module.name.clone();
-    let buffer = ThinBuffer::new(module.module_llvm.llmod());
+    let buffer = ThinBuffer::new(module.module_llvm.llmod(), true);
     (name, buffer)
 }
 
@@ -695,9 +695,9 @@ unsafe impl Send for ThinBuffer {}
 unsafe impl Sync for ThinBuffer {}
 
 impl ThinBuffer {
-    pub fn new(m: &llvm::Module) -> ThinBuffer {
+    pub fn new(m: &llvm::Module, is_thin: bool) -> ThinBuffer {
         unsafe {
-            let buffer = llvm::LLVMRustThinLTOBufferCreate(m);
+            let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin);
             ThinBuffer(buffer)
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 2b465ce40e7..534d32e8a90 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -790,7 +790,7 @@ pub(crate) unsafe fn codegen(
             let _timer = cgcx
                 .prof
                 .generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name);
-            let thin = ThinBuffer::new(llmod);
+            let thin = ThinBuffer::new(llmod, config.emit_thin_lto);
             let data = thin.data();
 
             if let Some(bitcode_filename) = bc_out.file_name() {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 4a4cccb490d..d3096c73a8a 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -626,32 +626,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         }
     }
 
-    fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
-        let typeid_metadata = self.typeid_metadata(typeid);
-        let v = [self.const_usize(0), typeid_metadata];
-        unsafe {
-            llvm::LLVMGlobalSetMetadata(
-                function,
-                llvm::MD_type as c_uint,
-                llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
-                    self.cx.llcx,
-                    v.as_ptr(),
-                    v.len() as c_uint,
-                )),
-            )
-        }
-    }
-
-    fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
-        unsafe {
-            llvm::LLVMMDStringInContext(
-                self.cx.llcx,
-                typeid.as_ptr() as *const c_char,
-                typeid.as_bytes().len() as c_uint,
-            )
-        }
-    }
-
     fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
         self.store_with_flags(val, ptr, align, MemFlags::empty())
     }
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 77cbbf4c6ca..fb4da9a5f33 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -257,6 +257,15 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                         self.get_fn_addr(fn_instance.polymorphize(self.tcx)),
                         self.data_layout().instruction_address_space,
                     ),
+                    GlobalAlloc::VTable(ty, trait_ref) => {
+                        let alloc = self
+                            .tcx
+                            .global_alloc(self.tcx.vtable_allocation((ty, trait_ref)))
+                            .unwrap_memory();
+                        let init = const_alloc_to_llvm(self, alloc);
+                        let value = self.static_addr_of(init, alloc.inner().align, None);
+                        (value, AddressSpace::DATA)
+                    }
                     GlobalAlloc::Static(def_id) => {
                         assert!(self.tcx.is_static(def_id));
                         assert!(!self.tcx.is_thread_local_static(def_id));
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 2b16ae1a88d..18467e37082 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -101,7 +101,9 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
 
         let address_space = match cx.tcx.global_alloc(alloc_id) {
             GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
-            GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) => AddressSpace::DATA,
+            GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
+                AddressSpace::DATA
+            }
         };
 
         llvals.push(cx.scalar_to_backend(
@@ -535,10 +537,20 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
 
                 // The semantics of #[used] in Rust only require the symbol to make it into the
                 // object file. It is explicitly allowed for the linker to strip the symbol if it
-                // is dead. As such, use llvm.compiler.used instead of llvm.used.
+                // is dead, which means we are allowed use `llvm.compiler.used` instead of
+                // `llvm.used` here.
+                //
                 // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
                 // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
-                // in some versions of the gold linker.
+                // in the handling of `.init_array` (the static constructor list) in versions of
+                // the gold linker (prior to the one released with binutils 2.36).
+                //
+                // That said, we only ever emit these when compiling for ELF targets, unless
+                // `#[used(compiler)]` is explicitly requested. This is to avoid similar breakage
+                // on other targets, in particular MachO targets have *their* static constructor
+                // lists broken if `llvm.compiler.used` is emitted rather than llvm.used. However,
+                // that check happens when assigning the `CodegenFnAttrFlags` in `rustc_typeck`,
+                // so we don't need to take care of it here.
                 self.add_compiler_used_global(g);
             }
             if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index f8bd2d234f3..bd84100e0e8 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -1420,7 +1420,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
         cx,
         type_map::stub(
             cx,
-            Stub::VtableTy { vtable_holder },
+            Stub::VTableTy { vtable_holder },
             unique_type_id,
             &vtable_type_name,
             (size, pointer_align),
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index 8fc8118849b..ce2f419c4ac 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -146,7 +146,7 @@ impl<'ll> DINodeCreationResult<'ll> {
 pub enum Stub<'ll> {
     Struct,
     Union,
-    VtableTy { vtable_holder: &'ll DIType },
+    VTableTy { vtable_holder: &'ll DIType },
 }
 
 pub struct StubInfo<'ll, 'tcx> {
@@ -180,9 +180,9 @@ pub(super) fn stub<'ll, 'tcx>(
     let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx);
 
     let metadata = match kind {
-        Stub::Struct | Stub::VtableTy { .. } => {
+        Stub::Struct | Stub::VTableTy { .. } => {
             let vtable_holder = match kind {
-                Stub::VtableTy { vtable_holder } => Some(vtable_holder),
+                Stub::VTableTy { vtable_holder } => Some(vtable_holder),
                 _ => None,
             };
             unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 5a5c4f7f860..fa0ecd18fc8 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -18,7 +18,9 @@ use crate::llvm;
 use crate::llvm::AttributePlace::Function;
 use crate::type_::Type;
 use crate::value::Value;
+use rustc_codegen_ssa::traits::TypeMembershipMethods;
 use rustc_middle::ty::Ty;
+use rustc_symbol_mangling::typeid::typeid_for_fnabi;
 use smallvec::SmallVec;
 use tracing::debug;
 
@@ -97,6 +99,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             fn_abi.llvm_type(self),
         );
         fn_abi.apply_attrs_llfn(self, llfn);
+
+        if self.tcx.sess.is_sanitizer_cfi_enabled() {
+            let typeid = typeid_for_fnabi(self.tcx, fn_abi);
+            self.set_type_metadata(llfn, typeid);
+        }
+
         llfn
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 73cedb59349..f64eb79b0a8 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -192,6 +192,7 @@ pub enum AttributeKind {
     NoUndef = 33,
     SanitizeMemTag = 34,
     NoCfCheck = 35,
+    ShadowCallStack = 36,
 }
 
 /// LLVMIntPredicate
@@ -2470,7 +2471,7 @@ extern "C" {
     pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer);
     pub fn LLVMRustModuleCost(M: &Module) -> u64;
 
-    pub fn LLVMRustThinLTOBufferCreate(M: &Module) -> &'static mut ThinLTOBuffer;
+    pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer;
     pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
     pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char;
     pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t;
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index cf2d3c423c3..eeb38d4ecf5 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -19,7 +19,7 @@ use rustc_target::abi::{AddressSpace, Align, Integer, Size};
 use std::fmt;
 use std::ptr;
 
-use libc::c_uint;
+use libc::{c_char, c_uint};
 
 impl PartialEq for Type {
     fn eq(&self, other: &Self) -> bool {
@@ -289,3 +289,31 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         ty.llvm_type(self)
     }
 }
+
+impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+    fn set_type_metadata(&self, function: &'ll Value, typeid: String) {
+        let typeid_metadata = self.typeid_metadata(typeid);
+        let v = [self.const_usize(0), typeid_metadata];
+        unsafe {
+            llvm::LLVMGlobalSetMetadata(
+                function,
+                llvm::MD_type as c_uint,
+                llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
+                    self.llcx,
+                    v.as_ptr(),
+                    v.len() as c_uint,
+                )),
+            )
+        }
+    }
+
+    fn typeid_metadata(&self, typeid: String) -> &'ll Value {
+        unsafe {
+            llvm::LLVMMDStringInContext(
+                self.llcx,
+                typeid.as_ptr() as *const c_char,
+                typeid.len() as c_uint,
+            )
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 81c8b9ceb13..46d6344dbb2 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -14,7 +14,7 @@ tracing = "0.1"
 libc = "0.2.50"
 jobserver = "0.1.22"
 tempfile = "3.2"
-thorin-dwp = "0.2"
+thorin-dwp = "0.3"
 pathdiff = "0.2.0"
 serde_json = "1.0.59"
 snap = "1"
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index c2ac21eec67..ea60f6055f3 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -99,6 +99,7 @@ pub struct ModuleConfig {
     pub emit_ir: bool,
     pub emit_asm: bool,
     pub emit_obj: EmitObj,
+    pub emit_thin_lto: bool,
     pub bc_cmdline: String,
 
     // Miscellaneous flags.  These are mostly copied from command-line
@@ -218,6 +219,7 @@ impl ModuleConfig {
                 false
             ),
             emit_obj,
+            emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto,
             bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(),
 
             verify_llvm_ir: sess.verify_llvm_ir(),
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 7def30af2b3..d95194e320b 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -171,7 +171,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 );
                 let new_vptr = bx.load(ptr_ty, gep, ptr_align);
                 bx.nonnull_metadata(new_vptr);
-                // Vtable loads are invariant.
+                // VTable loads are invariant.
                 bx.set_invariant_load(new_vptr);
                 new_vptr
             } else {
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index df42d804566..27d791d90a5 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> VirtualIndex {
             let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
             let ptr = bx.load(llty, gep, ptr_align);
             bx.nonnull_metadata(ptr);
-            // Vtable loads are invariant.
+            // VTable loads are invariant.
             bx.set_invariant_load(ptr);
             ptr
         }
@@ -58,7 +58,7 @@ impl<'a, 'tcx> VirtualIndex {
         let usize_align = bx.tcx().data_layout.pointer_align.abi;
         let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
         let ptr = bx.load(llty, gep, usize_align);
-        // Vtable loads are invariant.
+        // VTable loads are invariant.
         bx.set_invariant_load(ptr);
         ptr
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 773c55cf551..3eee58d9d1c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty, TypeVisitable};
 use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
-use rustc_symbol_mangling::typeid_for_fnabi;
+use rustc_symbol_mangling::typeid::typeid_for_fnabi;
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
 use rustc_target::abi::{self, HasDataLayout, WrappingRange};
 use rustc_target::spec::abi::Abi;
@@ -918,7 +918,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // FIXME(rcvalle): Add support for generalized identifiers.
             // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
             let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
-            let typeid_metadata = bx.typeid_metadata(typeid);
+            let typeid_metadata = self.cx.typeid_metadata(typeid);
 
             // Test whether the function pointer is associated with the type identifier.
             let cond = bx.type_test(fn_ptr, typeid_metadata);
diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
index a283bf1de76..f1fe495282a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs
@@ -9,11 +9,8 @@ use super::FunctionCx;
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage, scope: SourceScope) {
         // Determine the instance that coverage data was originally generated for.
-        let scope_data = &self.mir.source_scopes[scope];
-        let instance = if let Some((inlined_instance, _)) = scope_data.inlined {
-            self.monomorphize(inlined_instance)
-        } else if let Some(inlined_scope) = scope_data.inlined_parent_scope {
-            self.monomorphize(self.mir.source_scopes[inlined_scope].inlined.unwrap().0)
+        let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) {
+            self.monomorphize(inlined)
         } else {
             self.instance
         };
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 645afae30d8..94ac71a4dd2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -3,12 +3,16 @@ use super::place::PlaceRef;
 use super::FunctionCx;
 use crate::common::{span_invalid_monomorphization_error, IntPredicate};
 use crate::glue;
+use crate::meth;
 use crate::traits::*;
 use crate::MemFlags;
 
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::{sym, Span};
-use rustc_target::abi::call::{FnAbi, PassMode};
+use rustc_target::abi::{
+    call::{FnAbi, PassMode},
+    WrappingRange,
+};
 
 fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
@@ -102,6 +106,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes())
                 }
             }
+            sym::vtable_size | sym::vtable_align => {
+                let vtable = args[0].immediate();
+                let idx = match name {
+                    sym::vtable_size => ty::COMMON_VTABLE_ENTRIES_SIZE,
+                    sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN,
+                    _ => bug!(),
+                };
+                let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable);
+                if name == sym::vtable_align {
+                    // Alignment is always nonzero.
+                    bx.range_metadata(value, WrappingRange { start: 1, end: !0 });
+                };
+                value
+            }
             sym::pref_align_of
             | sym::needs_drop
             | sym::type_id
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index ec3f7a2156a..8ee375fa9e3 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -3,7 +3,6 @@ use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable, TypeVisitable};
-use rustc_symbol_mangling::typeid_for_fnabi;
 use rustc_target::abi::call::{FnAbi, PassMode};
 
 use std::iter;
@@ -247,13 +246,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     for (bb, _) in traversal::reverse_postorder(&mir) {
         fx.codegen_block(bb);
     }
-
-    // For backends that support CFI using type membership (i.e., testing whether a given  pointer
-    // is associated with a type identifier).
-    if cx.tcx().sess.is_sanitizer_cfi_enabled() {
-        let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
-        bx.type_metadata(llfn, typeid);
-    }
 }
 
 /// Produces, for each argument, a `Value` pointing at the
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 1bbe10141fc..9f49749bb41 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -160,8 +160,6 @@ pub trait BuilderMethods<'a, 'tcx>:
 
     fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
     fn nonnull_metadata(&mut self, load: Self::Value);
-    fn type_metadata(&mut self, function: Self::Function, typeid: String);
-    fn typeid_metadata(&mut self, typeid: String) -> Self::Value;
 
     fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
     fn store_with_flags(
diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs
index 396768e0a42..782fdadbfb8 100644
--- a/compiler/rustc_codegen_ssa/src/traits/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs
@@ -40,7 +40,8 @@ pub use self::intrinsic::IntrinsicCallMethods;
 pub use self::misc::MiscMethods;
 pub use self::statics::{StaticBuilderMethods, StaticMethods};
 pub use self::type_::{
-    ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
+    ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMembershipMethods,
+    TypeMethods,
 };
 pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs
index a2a3cb56c78..413d31bb942 100644
--- a/compiler/rustc_codegen_ssa/src/traits/statics.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs
@@ -13,7 +13,9 @@ pub trait StaticMethods: BackendTypes {
     /// Same as add_used_global(), but only prevent the compiler from potentially removing an
     /// otherwise unused symbol. The linker is still permitted to drop it.
     ///
-    /// This corresponds to the semantics of the `#[used]` attribute.
+    /// This corresponds to the documented semantics of the `#[used]` attribute, although
+    /// on some targets (non-ELF), we may use `add_used_global` for `#[used]` statics
+    /// instead.
     fn add_compiler_used_global(&self, global: Self::Value);
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 5d3f07317a3..8158e8dd011 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -117,6 +117,13 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
     ) -> Self::Type;
 }
 
+// For backends that support CFI using type membership (i.e., testing whether a given  pointer is
+// associated with a type identifier).
+pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> {
+    fn set_type_metadata(&self, function: Self::Function, typeid: String);
+    fn typeid_metadata(&self, typeid: String) -> Self::Value;
+}
+
 pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
     fn store_fn_arg(
         &mut self,
@@ -133,6 +140,12 @@ pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
     fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type;
 }
 
-pub trait TypeMethods<'tcx>: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {}
+pub trait TypeMethods<'tcx>:
+    DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx>
+{
+}
 
-impl<'tcx, T> TypeMethods<'tcx> for T where Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {}
+impl<'tcx, T> TypeMethods<'tcx> for T where
+    Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx>
+{
+}
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index e00e667fb71..fc2e6652a3d 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -309,7 +309,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
-        dest: &PlaceTy<'tcx, Self::PointerTag>,
+        dest: &PlaceTy<'tcx, Self::Provenance>,
         target: Option<mir::BasicBlock>,
         _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
@@ -369,7 +369,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 // we don't deallocate it.
                 let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr)?;
                 let is_allocated_in_another_const = matches!(
-                    ecx.tcx.get_global_alloc(alloc_id),
+                    ecx.tcx.try_get_global_alloc(alloc_id),
                     Some(interpret::GlobalAlloc::Memory(_))
                 );
 
@@ -470,14 +470,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     #[inline(always)]
     fn stack<'a>(
         ecx: &'a InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
+    ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] {
         &ecx.machine.stack
     }
 
     #[inline(always)]
     fn stack_mut<'a>(
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
+    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
         &mut ecx.machine.stack
     }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index edc4c13b6e8..948c3349498 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -138,7 +138,7 @@ pub(crate) fn deref_mir_constant<'tcx>(
     let mplace = ecx.deref_operand(&op).unwrap();
     if let Some(alloc_id) = mplace.ptr.provenance {
         assert_eq!(
-            tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability,
+            tcx.global_alloc(alloc_id).unwrap_memory().0.0.mutability,
             Mutability::Not,
             "deref_mir_constant cannot be used with mutable allocations as \
             that could allow pattern matching to observe mutable statics",
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 5d598b65c72..883387851ea 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -18,10 +18,10 @@ use super::{
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn cast(
         &mut self,
-        src: &OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::Provenance>,
         cast_kind: CastKind,
         cast_ty: Ty<'tcx>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         use rustc_middle::mir::CastKind::*;
         // FIXME: In which cases should we trigger UB when the source is uninit?
@@ -114,9 +114,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn misc_cast(
         &mut self,
-        src: &ImmTy<'tcx, M::PointerTag>,
+        src: &ImmTy<'tcx, M::Provenance>,
         cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
         use rustc_type_ir::sty::TyKind::*;
         trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
 
@@ -173,9 +173,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn pointer_expose_address_cast(
         &mut self,
-        src: &ImmTy<'tcx, M::PointerTag>,
+        src: &ImmTy<'tcx, M::Provenance>,
         cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
         assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
         assert!(cast_ty.is_integral());
 
@@ -190,9 +190,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn pointer_from_exposed_address_cast(
         &mut self,
-        src: &ImmTy<'tcx, M::PointerTag>,
+        src: &ImmTy<'tcx, M::Provenance>,
         cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
         assert!(src.layout.ty.is_integral());
         assert_matches!(cast_ty.kind(), ty::RawPtr(_));
 
@@ -208,10 +208,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn cast_from_int_like(
         &self,
-        scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout)
+        scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout)
         src_layout: TyAndLayout<'tcx>,
         cast_ty: Ty<'tcx>,
-    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
         // Let's make sure v is sign-extended *if* it has a signed type.
         let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`.
 
@@ -245,9 +245,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         })
     }
 
-    fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag>
+    fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>
     where
-        F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>,
+        F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
     {
         use rustc_type_ir::sty::TyKind::*;
         match *dest_ty.kind() {
@@ -279,8 +279,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn unsize_into_ptr(
         &mut self,
-        src: &OpTy<'tcx, M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::Provenance>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
         // The pointee types
         source_ty: Ty<'tcx>,
         cast_ty: Ty<'tcx>,
@@ -298,30 +298,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_immediate(val, dest)
             }
             (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
-                let val = self.read_immediate(src)?;
-                if data_a.principal_def_id() == data_b.principal_def_id() {
-                    return self.write_immediate(*val, dest);
-                }
-                // trait upcasting coercion
-                let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
-                    src_pointee_ty,
-                    dest_pointee_ty,
-                ));
-
-                if let Some(entry_idx) = vptr_entry_idx {
-                    let entry_idx = u64::try_from(entry_idx).unwrap();
-                    let (old_data, old_vptr) = val.to_scalar_pair()?;
-                    let old_vptr = self.scalar_to_ptr(old_vptr)?;
-                    let new_vptr = self
-                        .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?;
-                    self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
-                } else {
-                    self.write_immediate(*val, dest)
+                let (old_data, old_vptr) = self.read_immediate(src)?.to_scalar_pair()?;
+                let old_vptr = self.scalar_to_ptr(old_vptr)?;
+                let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
+                if old_trait != data_a.principal() {
+                    throw_ub_format!("upcast on a pointer whose vtable does not match its type");
                 }
+                let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
+                self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
             }
             (_, &ty::Dynamic(ref data, _)) => {
                 // Initial cast from sized to dyn trait
-                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
+                let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?;
                 let ptr = self.read_immediate(src)?.to_scalar()?;
                 let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
                 self.write_immediate(val, dest)
@@ -335,9 +323,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn unsize_into(
         &mut self,
-        src: &OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::Provenance>,
         cast_ty: TyAndLayout<'tcx>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
         match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 6feb5219ab1..fdf243c4108 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -81,7 +81,7 @@ impl Drop for SpanGuard {
 }
 
 /// A stack frame.
-pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> {
+pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> {
     ////////////////////////////////////////////////////////////////////////////////
     // Function and callsite information
     ////////////////////////////////////////////////////////////////////////////////
@@ -102,7 +102,7 @@ pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> {
 
     /// The location where the result of the current stack frame should be written to,
     /// and its layout in the caller.
-    pub return_place: PlaceTy<'tcx, Tag>,
+    pub return_place: PlaceTy<'tcx, Prov>,
 
     /// The list of locals for this stack frame, stored in order as
     /// `[return_ptr, arguments..., variables..., temporaries...]`.
@@ -111,7 +111,7 @@ pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> {
     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
     ///
     /// Do *not* access this directly; always go through the machine hook!
-    pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>,
+    pub locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>,
 
     /// The span of the `tracing` crate is stored here.
     /// When the guard is dropped, the span is exited. This gives us
@@ -166,15 +166,15 @@ pub enum StackPopCleanup {
 
 /// State of a local variable including a memoized layout
 #[derive(Clone, Debug)]
-pub struct LocalState<'tcx, Tag: Provenance = AllocId> {
-    pub value: LocalValue<Tag>,
+pub struct LocalState<'tcx, Prov: Provenance = AllocId> {
+    pub value: LocalValue<Prov>,
     /// Don't modify if `Some`, this is only used to prevent computing the layout twice
     pub layout: Cell<Option<TyAndLayout<'tcx>>>,
 }
 
 /// Current value of a local variable
 #[derive(Copy, Clone, Debug)] // Miri debug-prints these
-pub enum LocalValue<Tag: Provenance = AllocId> {
+pub enum LocalValue<Prov: Provenance = AllocId> {
     /// This local is not currently alive, and cannot be used at all.
     Dead,
     /// A normal, live local.
@@ -182,16 +182,16 @@ pub enum LocalValue<Tag: Provenance = AllocId> {
     /// This is an optimization over just always having a pointer here;
     /// we can thus avoid doing an allocation when the local just stores
     /// immediate values *and* never has its address taken.
-    Live(Operand<Tag>),
+    Live(Operand<Prov>),
 }
 
-impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> {
+impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> {
     /// Read the local's value or error if the local is not yet live or not live anymore.
     ///
     /// Note: This may only be invoked from the `Machine::access_local` hook and not from
     /// anywhere else. You may be invalidating machine invariants if you do!
     #[inline]
-    pub fn access(&self) -> InterpResult<'tcx, &Operand<Tag>> {
+    pub fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
         match &self.value {
             LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
             LocalValue::Live(val) => Ok(val),
@@ -204,7 +204,7 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> {
     /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from
     /// anywhere else. You may be invalidating machine invariants if you do!
     #[inline]
-    pub fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Tag>> {
+    pub fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> {
         match &mut self.value {
             LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
             LocalValue::Live(val) => Ok(val),
@@ -212,8 +212,8 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> {
     }
 }
 
-impl<'mir, 'tcx, Tag: Provenance> Frame<'mir, 'tcx, Tag> {
-    pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'mir, 'tcx, Tag, Extra> {
+impl<'mir, 'tcx, Prov: Provenance> Frame<'mir, 'tcx, Prov> {
+    pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'mir, 'tcx, Prov, Extra> {
         Frame {
             body: self.body,
             instance: self.instance,
@@ -227,7 +227,7 @@ impl<'mir, 'tcx, Tag: Provenance> Frame<'mir, 'tcx, Tag> {
     }
 }
 
-impl<'mir, 'tcx, Tag: Provenance, Extra> Frame<'mir, 'tcx, Tag, Extra> {
+impl<'mir, 'tcx, Prov: Provenance, Extra> Frame<'mir, 'tcx, Prov, Extra> {
     /// Get the current location within the Frame.
     ///
     /// If this is `Err`, we are not currently executing any particular statement in
@@ -422,14 +422,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     #[inline(always)]
-    pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] {
+    pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] {
         M::stack(self)
     }
 
     #[inline(always)]
     pub(crate) fn stack_mut(
         &mut self,
-    ) -> &mut Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>> {
+    ) -> &mut Vec<Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>> {
         M::stack_mut(self)
     }
 
@@ -441,12 +441,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     #[inline(always)]
-    pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
+    pub fn frame(&self) -> &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> {
         self.stack().last().expect("no call frames exist")
     }
 
     #[inline(always)]
-    pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
+    pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> {
         self.stack_mut().last_mut().expect("no call frames exist")
     }
 
@@ -503,7 +503,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// stack frame), to bring it into the proper environment for this interpreter.
     pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
         &self,
-        frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
+        frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
         value: T,
     ) -> Result<T, InterpError<'tcx>> {
         frame
@@ -540,7 +540,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn layout_of_local(
         &self,
-        frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
+        frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
         local: mir::Local,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
@@ -569,7 +569,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// This can fail to provide an answer for extern types.
     pub(super) fn size_and_align_of(
         &self,
-        metadata: &MemPlaceMeta<M::PointerTag>,
+        metadata: &MemPlaceMeta<M::Provenance>,
         layout: &TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
         if !layout.is_unsized() {
@@ -631,7 +631,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             ty::Dynamic(..) => {
                 let vtable = self.scalar_to_ptr(metadata.unwrap_meta())?;
                 // Read size and align from vtable (already checks size).
-                Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
+                Ok(Some(self.get_vtable_size_and_align(vtable)?))
             }
 
             ty::Slice(_) | ty::Str => {
@@ -655,7 +655,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline]
     pub fn size_and_align_of_mplace(
         &self,
-        mplace: &MPlaceTy<'tcx, M::PointerTag>,
+        mplace: &MPlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
         self.size_and_align_of(&mplace.meta, &mplace.layout)
     }
@@ -665,7 +665,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &mut self,
         instance: ty::Instance<'tcx>,
         body: &'mir mir::Body<'tcx>,
-        return_place: &PlaceTy<'tcx, M::PointerTag>,
+        return_place: &PlaceTy<'tcx, M::Provenance>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
         trace!("body: {:#?}", body);
@@ -891,7 +891,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
+    fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> {
         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
             // All locals have a backing allocation, even if the allocation is empty
             // due to the local having ZST type. Hence we can `unwrap`.
@@ -909,7 +909,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn eval_to_allocation(
         &self,
         gid: GlobalId<'tcx>,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
         // and thus don't care about the parameter environment. While we could just use
         // `self.param_env`, that would mean we invoke the query to evaluate the static
@@ -927,7 +927,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     #[must_use]
-    pub fn dump_place(&self, place: Place<M::PointerTag>) -> PlacePrinter<'_, 'mir, 'tcx, M> {
+    pub fn dump_place(&self, place: Place<M::Provenance>) -> PlacePrinter<'_, 'mir, 'tcx, M> {
         PlacePrinter { ecx: self, place }
     }
 
@@ -956,7 +956,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 /// Helper struct for the `dump_place` function.
 pub struct PlacePrinter<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
     ecx: &'a InterpCx<'mir, 'tcx, M>,
-    place: Place<M::PointerTag>,
+    place: Place<M::Provenance>,
 }
 
 impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 7616e7a63d1..23526edcc34 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -33,7 +33,7 @@ pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
     'mir,
     'tcx,
     MemoryKind = T,
-    PointerTag = AllocId,
+    Provenance = AllocId,
     ExtraFnVal = !,
     FrameExtra = (),
     AllocExtra = (),
@@ -94,7 +94,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
         // to validation to error -- it has the much better error messages, pointing out where
         // in the value the dangling reference lies.
         // The `delay_span_bug` ensures that we don't forget such a check in validation.
-        if tcx.get_global_alloc(alloc_id).is_none() {
+        if tcx.try_get_global_alloc(alloc_id).is_none() {
             tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer");
         }
         // treat dangling pointers like other statics
@@ -454,7 +454,7 @@ pub fn intern_const_alloc_recursive<
                 .sess
                 .span_err(ecx.tcx.span, "encountered dangling pointer in final constant");
             return Err(reported);
-        } else if ecx.tcx.get_global_alloc(alloc_id).is_none() {
+        } else if ecx.tcx.try_get_global_alloc(alloc_id).is_none() {
             // We have hit an `AllocId` that is neither in local or global memory and isn't
             // marked as dangling by local memory.  That should be impossible.
             span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id);
@@ -474,7 +474,7 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
         layout: TyAndLayout<'tcx>,
         f: impl FnOnce(
             &mut InterpCx<'mir, 'tcx, M>,
-            &PlaceTy<'tcx, M::PointerTag>,
+            &PlaceTy<'tcx, M::Provenance>,
         ) -> InterpResult<'tcx, ()>,
     ) -> InterpResult<'tcx, ConstAllocation<'tcx>> {
         let dest = self.allocate(layout, MemoryKind::Stack)?;
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index c6030604aed..025f8647c95 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -25,7 +25,7 @@ use super::{
 mod caller_location;
 mod type_name;
 
-fn numeric_intrinsic<Tag>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Tag> {
+fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Prov> {
     let size = match kind {
         Primitive::Int(integer, _) => integer.size(),
         _ => bug!("invalid `{}` argument: {:?}", name, bits),
@@ -114,8 +114,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn emulate_intrinsic(
         &mut self,
         instance: ty::Instance<'tcx>,
-        args: &[OpTy<'tcx, M::PointerTag>],
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        args: &[OpTy<'tcx, M::Provenance>],
+        dest: &PlaceTy<'tcx, M::Provenance>,
         ret: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx, bool> {
         let substs = instance.substs;
@@ -492,6 +492,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
                 self.write_scalar(result, dest)?;
             }
+
+            sym::vtable_size => {
+                let ptr = self.read_pointer(&args[0])?;
+                let (size, _align) = self.get_vtable_size_and_align(ptr)?;
+                self.write_scalar(Scalar::from_machine_usize(size.bytes(), self), dest)?;
+            }
+            sym::vtable_align => {
+                let ptr = self.read_pointer(&args[0])?;
+                let (_size, align) = self.get_vtable_size_and_align(ptr)?;
+                self.write_scalar(Scalar::from_machine_usize(align.bytes(), self), dest)?;
+            }
+
             _ => return Ok(false),
         }
 
@@ -502,9 +514,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn exact_div(
         &mut self,
-        a: &ImmTy<'tcx, M::PointerTag>,
-        b: &ImmTy<'tcx, M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        a: &ImmTy<'tcx, M::Provenance>,
+        b: &ImmTy<'tcx, M::Provenance>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         // Performs an exact division, resulting in undefined behavior where
         // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
@@ -521,9 +533,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn saturating_arith(
         &self,
         mir_op: BinOp,
-        l: &ImmTy<'tcx, M::PointerTag>,
-        r: &ImmTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+        l: &ImmTy<'tcx, M::Provenance>,
+        r: &ImmTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
         assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
         let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?;
         Ok(if overflowed {
@@ -566,10 +578,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
     pub fn ptr_offset_inbounds(
         &self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         pointee_ty: Ty<'tcx>,
         offset_count: i64,
-    ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
+    ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
         // We cannot overflow i64 as a type's size must be <= isize::MAX.
         let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
         // The computed offset, in bytes, must not overflow an isize.
@@ -597,9 +609,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Copy `count*size_of::<T>()` many bytes from `*src` to `*dst`.
     pub(crate) fn copy_intrinsic(
         &mut self,
-        src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+        src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
         nonoverlapping: bool,
     ) -> InterpResult<'tcx> {
         let count = self.read_scalar(&count)?.to_machine_usize(self)?;
@@ -622,9 +634,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub(crate) fn write_bytes_intrinsic(
         &mut self,
-        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+        byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
     ) -> InterpResult<'tcx> {
         let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;
 
@@ -645,9 +657,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub(crate) fn raw_eq_intrinsic(
         &mut self,
-        lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+        lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+        rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+    ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
         let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?;
         assert!(!layout.is_unsized());
 
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index 14fde2c305e..5864b921552 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -79,7 +79,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         filename: Symbol,
         line: u32,
         col: u32,
-    ) -> MPlaceTy<'tcx, M::PointerTag> {
+    ) -> MPlaceTy<'tcx, M::Provenance> {
         let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail;
         let file = if loc_details.file {
             self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
@@ -123,7 +123,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         )
     }
 
-    pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> {
+    pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::Provenance> {
         let (file, line, column) = self.location_triple_for_span(span);
         self.alloc_caller_location(file, line, column)
     }
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 7f8eea94aee..a938a9248e0 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -85,11 +85,11 @@ pub trait Machine<'mir, 'tcx>: Sized {
     type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static;
 
     /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
-    type PointerTag: Provenance + Eq + Hash + 'static;
+    type Provenance: Provenance + Eq + Hash + 'static;
 
-    /// When getting the AllocId of a pointer, some extra data is also obtained from the tag
+    /// When getting the AllocId of a pointer, some extra data is also obtained from the provenance
     /// that is passed to memory access hooks so they can do things with it.
-    type TagExtra: Copy + 'static;
+    type ProvenanceExtra: Copy + 'static;
 
     /// Machines can define extra (non-instance) things that represent values of function pointers.
     /// For example, Miri uses this to return a function pointer from `dlsym`
@@ -105,7 +105,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Memory's allocation map
     type MemoryMap: AllocMap<
             AllocId,
-            (MemoryKind<Self::MemoryKind>, Allocation<Self::PointerTag, Self::AllocExtra>),
+            (MemoryKind<Self::MemoryKind>, Allocation<Self::Provenance, Self::AllocExtra>),
         > + Default
         + Clone;
 
@@ -113,7 +113,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// or None if such memory should not be mutated and thus any such attempt will cause
     /// a `ModifiedStatic` error to be raised.
     /// Statics are copied under two circumstances: When they are mutated, and when
-    /// `tag_allocation` (see below) returns an owned allocation
+    /// `adjust_allocation` (see below) returns an owned allocation
     /// that is added to the memory so that the work is not done twice.
     const GLOBAL_KIND: Option<Self::MemoryKind>;
 
@@ -126,7 +126,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Whether, when checking alignment, we should `force_int` and thus support
     /// custom alignment logic based on whatever the integer address happens to be.
     ///
-    /// Requires PointerTag::OFFSET_IS_ADDR to be true.
+    /// Requires Provenance::OFFSET_IS_ADDR to be true.
     fn force_int_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
     /// Whether to enforce the validity invariant
@@ -170,8 +170,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         abi: CallAbi,
-        args: &[OpTy<'tcx, Self::PointerTag>],
-        destination: &PlaceTy<'tcx, Self::PointerTag>,
+        args: &[OpTy<'tcx, Self::Provenance>],
+        destination: &PlaceTy<'tcx, Self::Provenance>,
         target: Option<mir::BasicBlock>,
         unwind: StackPopUnwind,
     ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>;
@@ -182,8 +182,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         fn_val: Self::ExtraFnVal,
         abi: CallAbi,
-        args: &[OpTy<'tcx, Self::PointerTag>],
-        destination: &PlaceTy<'tcx, Self::PointerTag>,
+        args: &[OpTy<'tcx, Self::Provenance>],
+        destination: &PlaceTy<'tcx, Self::Provenance>,
         target: Option<mir::BasicBlock>,
         unwind: StackPopUnwind,
     ) -> InterpResult<'tcx>;
@@ -193,8 +193,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn call_intrinsic(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        args: &[OpTy<'tcx, Self::PointerTag>],
-        destination: &PlaceTy<'tcx, Self::PointerTag>,
+        args: &[OpTy<'tcx, Self::Provenance>],
+        destination: &PlaceTy<'tcx, Self::Provenance>,
         target: Option<mir::BasicBlock>,
         unwind: StackPopUnwind,
     ) -> InterpResult<'tcx>;
@@ -217,18 +217,18 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn binary_ptr_op(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         bin_op: mir::BinOp,
-        left: &ImmTy<'tcx, Self::PointerTag>,
-        right: &ImmTy<'tcx, Self::PointerTag>,
-    ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;
+        left: &ImmTy<'tcx, Self::Provenance>,
+        right: &ImmTy<'tcx, Self::Provenance>,
+    ) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>;
 
     /// Called to read the specified `local` from the `frame`.
     /// Since reading a ZST is not actually accessing memory or locals, this is never invoked
     /// for ZST reads.
     #[inline]
     fn access_local<'a>(
-        frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
+        frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
         local: mir::Local,
-    ) -> InterpResult<'tcx, &'a Operand<Self::PointerTag>>
+    ) -> InterpResult<'tcx, &'a Operand<Self::Provenance>>
     where
         'tcx: 'mir,
     {
@@ -243,7 +243,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
         frame: usize,
         local: mir::Local,
-    ) -> InterpResult<'tcx, &'a mut Operand<Self::PointerTag>>
+    ) -> InterpResult<'tcx, &'a mut Operand<Self::Provenance>>
     where
         'tcx: 'mir,
     {
@@ -275,7 +275,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn thread_local_static_base_pointer(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         def_id: DefId,
-    ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
+    ) -> InterpResult<'tcx, Pointer<Self::Provenance>> {
         throw_unsup!(ThreadLocalStatic(def_id))
     }
 
@@ -283,35 +283,35 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn extern_static_base_pointer(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         def_id: DefId,
-    ) -> InterpResult<'tcx, Pointer<Self::PointerTag>>;
+    ) -> InterpResult<'tcx, Pointer<Self::Provenance>>;
 
     /// Return a "base" pointer for the given allocation: the one that is used for direct
     /// accesses to this static/const/fn allocation, or the one returned from the heap allocator.
     ///
     /// Not called on `extern` or thread-local statics (those use the methods above).
-    fn tag_alloc_base_pointer(
+    fn adjust_alloc_base_pointer(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         ptr: Pointer,
-    ) -> Pointer<Self::PointerTag>;
+    ) -> Pointer<Self::Provenance>;
 
     /// "Int-to-pointer cast"
     fn ptr_from_addr_cast(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         addr: u64,
-    ) -> InterpResult<'tcx, Pointer<Option<Self::PointerTag>>>;
+    ) -> InterpResult<'tcx, Pointer<Option<Self::Provenance>>>;
 
     /// Hook for returning a pointer from a transmute-like operation on an addr.
     /// This is only needed to support Miri's (unsound) "allow-ptr-int-transmute" flag.
     fn ptr_from_addr_transmute(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         addr: u64,
-    ) -> Pointer<Option<Self::PointerTag>>;
+    ) -> Pointer<Option<Self::Provenance>>;
 
     /// Marks a pointer as exposed, allowing it's provenance
     /// to be recovered. "Pointer-to-int cast"
     fn expose_ptr(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        ptr: Pointer<Self::PointerTag>,
+        ptr: Pointer<Self::Provenance>,
     ) -> InterpResult<'tcx>;
 
     /// Convert a pointer with provenance into an allocation-offset pair
@@ -322,30 +322,30 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// When this fails, that means the pointer does not point to a live allocation.
     fn ptr_get_alloc(
         ecx: &InterpCx<'mir, 'tcx, Self>,
-        ptr: Pointer<Self::PointerTag>,
-    ) -> Option<(AllocId, Size, Self::TagExtra)>;
-
-    /// Called to initialize the "extra" state of an allocation and make the pointers
-    /// it contains (in relocations) tagged.  The way we construct allocations is
-    /// to always first construct it without extra and then add the extra.
-    /// This keeps uniform code paths for handling both allocations created by CTFE
-    /// for globals, and allocations created by Miri during evaluation.
+        ptr: Pointer<Self::Provenance>,
+    ) -> Option<(AllocId, Size, Self::ProvenanceExtra)>;
+
+    /// Called to adjust allocations to the Provenance and AllocExtra of this machine.
+    ///
+    /// The way we construct allocations is to always first construct it without extra and then add
+    /// the extra. This keeps uniform code paths for handling both allocations created by CTFE for
+    /// globals, and allocations created by Miri during evaluation.
     ///
-    /// `kind` is the kind of the allocation being tagged; it can be `None` when
+    /// `kind` is the kind of the allocation being adjusted; it can be `None` when
     /// it's a global and `GLOBAL_KIND` is `None`.
     ///
     /// This should avoid copying if no work has to be done! If this returns an owned
-    /// allocation (because a copy had to be done to add tags or metadata), machine memory will
+    /// allocation (because a copy had to be done to adjust things), machine memory will
     /// cache the result. (This relies on `AllocMap::get_or` being able to add the
     /// owned allocation to the map even when the map is shared.)
     ///
     /// This must only fail if `alloc` contains relocations.
-    fn init_allocation_extra<'b>(
+    fn adjust_allocation<'b>(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         id: AllocId,
         alloc: Cow<'b, Allocation>,
         kind: Option<MemoryKind<Self::MemoryKind>>,
-    ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>>;
+    ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>>;
 
     /// Hook for performing extra checks on a memory read access.
     ///
@@ -357,7 +357,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         _tcx: TyCtxt<'tcx>,
         _machine: &Self,
         _alloc_extra: &Self::AllocExtra,
-        _tag: (AllocId, Self::TagExtra),
+        _prov: (AllocId, Self::ProvenanceExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
         Ok(())
@@ -369,7 +369,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         _tcx: TyCtxt<'tcx>,
         _machine: &mut Self,
         _alloc_extra: &mut Self::AllocExtra,
-        _tag: (AllocId, Self::TagExtra),
+        _prov: (AllocId, Self::ProvenanceExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
         Ok(())
@@ -381,7 +381,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         _tcx: TyCtxt<'tcx>,
         _machine: &mut Self,
         _alloc_extra: &mut Self::AllocExtra,
-        _tag: (AllocId, Self::TagExtra),
+        _prov: (AllocId, Self::ProvenanceExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
         Ok(())
@@ -392,7 +392,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn retag(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _kind: mir::RetagKind,
-        _place: &PlaceTy<'tcx, Self::PointerTag>,
+        _place: &PlaceTy<'tcx, Self::Provenance>,
     ) -> InterpResult<'tcx> {
         Ok(())
     }
@@ -400,18 +400,18 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Called immediately before a new stack frame gets pushed.
     fn init_frame_extra(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        frame: Frame<'mir, 'tcx, Self::PointerTag>,
-    ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>;
+        frame: Frame<'mir, 'tcx, Self::Provenance>,
+    ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>>;
 
     /// Borrow the current thread's stack.
     fn stack<'a>(
         ecx: &'a InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>];
+    ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>];
 
     /// Mutably borrow the current thread's stack.
     fn stack_mut<'a>(
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>;
+    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>>;
 
     /// Called immediately after a stack frame got pushed and its locals got initialized.
     fn after_stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
@@ -422,7 +422,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// The `locals` have already been destroyed!
     fn after_stack_pop(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _frame: Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
+        _frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
         unwinding: bool,
     ) -> InterpResult<'tcx, StackPopJump> {
         // By default, we do not support unwinding from panics
@@ -434,8 +434,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
 // A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
 // (CTFE and ConstProp) use the same instance.  Here, we share that code.
 pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
-    type PointerTag = AllocId;
-    type TagExtra = ();
+    type Provenance = AllocId;
+    type ProvenanceExtra = ();
 
     type ExtraFnVal = !;
 
@@ -485,7 +485,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
         fn_val: !,
         _abi: CallAbi,
         _args: &[OpTy<$tcx>],
-        _destination: &PlaceTy<$tcx, Self::PointerTag>,
+        _destination: &PlaceTy<$tcx, Self::Provenance>,
         _target: Option<mir::BasicBlock>,
         _unwind: StackPopUnwind,
     ) -> InterpResult<$tcx> {
@@ -493,13 +493,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     }
 
     #[inline(always)]
-    fn init_allocation_extra<'b>(
+    fn adjust_allocation<'b>(
         _ecx: &InterpCx<$mir, $tcx, Self>,
         _id: AllocId,
         alloc: Cow<'b, Allocation>,
         _kind: Option<MemoryKind<Self::MemoryKind>>,
-    ) -> InterpResult<$tcx, Cow<'b, Allocation<Self::PointerTag>>> {
-        // We do not use a tag so we can just cheaply forward the allocation
+    ) -> InterpResult<$tcx, Cow<'b, Allocation<Self::Provenance>>> {
         Ok(alloc)
     }
 
@@ -512,7 +511,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     }
 
     #[inline(always)]
-    fn tag_alloc_base_pointer(
+    fn adjust_alloc_base_pointer(
         _ecx: &InterpCx<$mir, $tcx, Self>,
         ptr: Pointer<AllocId>,
     ) -> Pointer<AllocId> {
@@ -541,7 +540,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     fn ptr_get_alloc(
         _ecx: &InterpCx<$mir, $tcx, Self>,
         ptr: Pointer<AllocId>,
-    ) -> Option<(AllocId, Size, Self::TagExtra)> {
+    ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
         // We know `offset` is relative to the allocation, so we can use `into_parts`.
         let (alloc_id, offset) = ptr.into_parts();
         Some((alloc_id, offset, ()))
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 509fe576893..86914f50383 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -16,7 +16,7 @@ use std::ptr;
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::display_allocation;
-use rustc_middle::ty::{Instance, ParamEnv, TyCtxt};
+use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
 use super::{
@@ -62,6 +62,8 @@ pub enum AllocKind {
     LiveData,
     /// A function allocation (that fn ptrs point to).
     Function,
+    /// A (symbolic) vtable allocation.
+    VTable,
     /// A dead allocation.
     Dead,
 }
@@ -112,16 +114,16 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
 /// A reference to some allocation that was already bounds-checked for the given region
 /// and had the on-access machine hooks run.
 #[derive(Copy, Clone)]
-pub struct AllocRef<'a, 'tcx, Tag, Extra> {
-    alloc: &'a Allocation<Tag, Extra>,
+pub struct AllocRef<'a, 'tcx, Prov, Extra> {
+    alloc: &'a Allocation<Prov, Extra>,
     range: AllocRange,
     tcx: TyCtxt<'tcx>,
     alloc_id: AllocId,
 }
 /// A reference to some allocation that was already bounds-checked for the given region
 /// and had the on-access machine hooks run.
-pub struct AllocRefMut<'a, 'tcx, Tag, Extra> {
-    alloc: &'a mut Allocation<Tag, Extra>,
+pub struct AllocRefMut<'a, 'tcx, Prov, Extra> {
+    alloc: &'a mut Allocation<Prov, Extra>,
     range: AllocRange,
     tcx: TyCtxt<'tcx>,
     alloc_id: AllocId,
@@ -156,10 +158,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn global_base_pointer(
         &self,
         ptr: Pointer<AllocId>,
-    ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let alloc_id = ptr.provenance;
         // We need to handle `extern static`.
-        match self.tcx.get_global_alloc(alloc_id) {
+        match self.tcx.try_get_global_alloc(alloc_id) {
             Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => {
                 bug!("global memory cannot point to thread-local static")
             }
@@ -168,14 +170,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             _ => {}
         }
-        // And we need to get the tag.
-        Ok(M::tag_alloc_base_pointer(self, ptr))
+        // And we need to get the provenance.
+        Ok(M::adjust_alloc_base_pointer(self, ptr))
     }
 
     pub fn create_fn_alloc_ptr(
         &mut self,
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
-    ) -> Pointer<M::PointerTag> {
+    ) -> Pointer<M::Provenance> {
         let id = match fn_val {
             FnVal::Instance(instance) => self.tcx.create_fn_alloc(instance),
             FnVal::Other(extra) => {
@@ -196,7 +198,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         size: Size,
         align: Align,
         kind: MemoryKind<M::MemoryKind>,
-    ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?;
         // We can `unwrap` since `alloc` contains no pointers.
         Ok(self.allocate_raw_ptr(alloc, kind).unwrap())
@@ -208,7 +210,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         align: Align,
         kind: MemoryKind<M::MemoryKind>,
         mutability: Mutability,
-    ) -> Pointer<M::PointerTag> {
+    ) -> Pointer<M::Provenance> {
         let alloc = Allocation::from_bytes(bytes, align, mutability);
         // We can `unwrap` since `alloc` contains no pointers.
         self.allocate_raw_ptr(alloc, kind).unwrap()
@@ -219,27 +221,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &mut self,
         alloc: Allocation,
         kind: MemoryKind<M::MemoryKind>,
-    ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let id = self.tcx.reserve_alloc_id();
         debug_assert_ne!(
             Some(kind),
             M::GLOBAL_KIND.map(MemoryKind::Machine),
             "dynamically allocating global memory"
         );
-        let alloc = M::init_allocation_extra(self, id, Cow::Owned(alloc), Some(kind))?;
+        let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
         self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
-        Ok(M::tag_alloc_base_pointer(self, Pointer::from(id)))
+        Ok(M::adjust_alloc_base_pointer(self, Pointer::from(id)))
     }
 
     pub fn reallocate_ptr(
         &mut self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         old_size_and_align: Option<(Size, Align)>,
         new_size: Size,
         new_align: Align,
         kind: MemoryKind<M::MemoryKind>,
-    ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
-        let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
+    ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
+        let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?;
         if offset.bytes() != 0 {
             throw_ub_format!(
                 "reallocating {:?} which does not point to the beginning of an object",
@@ -271,11 +273,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[instrument(skip(self), level = "debug")]
     pub fn deallocate_ptr(
         &mut self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         old_size_and_align: Option<(Size, Align)>,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx> {
-        let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, prov) = self.ptr_get_alloc_id(ptr)?;
         trace!("deallocating: {alloc_id:?}");
 
         if offset.bytes() != 0 {
@@ -287,10 +289,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         let Some((alloc_kind, mut alloc)) = self.memory.alloc_map.remove(&alloc_id) else {
             // Deallocating global memory -- always an error
-            return Err(match self.tcx.get_global_alloc(alloc_id) {
+            return Err(match self.tcx.try_get_global_alloc(alloc_id) {
                 Some(GlobalAlloc::Function(..)) => {
                     err_ub_format!("deallocating {alloc_id:?}, which is a function")
                 }
+                Some(GlobalAlloc::VTable(..)) => {
+                    err_ub_format!("deallocating {alloc_id:?}, which is a vtable")
+                }
                 Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
                     err_ub_format!("deallocating {alloc_id:?}, which is static memory")
                 }
@@ -327,7 +332,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             *self.tcx,
             &mut self.machine,
             &mut alloc.extra,
-            (alloc_id, tag),
+            (alloc_id, prov),
             alloc_range(Size::ZERO, size),
         )?;
 
@@ -344,19 +349,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     fn get_ptr_access(
         &self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         size: Size,
         align: Align,
-    ) -> InterpResult<'tcx, Option<(AllocId, Size, M::TagExtra)>> {
+    ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> {
         let align = M::enforce_alignment(&self).then_some(align);
         self.check_and_deref_ptr(
             ptr,
             size,
             align,
             CheckInAllocMsg::MemoryAccessTest,
-            |alloc_id, offset, tag| {
+            |alloc_id, offset, prov| {
                 let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
-                Ok((size, align, (alloc_id, offset, tag)))
+                Ok((size, align, (alloc_id, offset, prov)))
             },
         )
     }
@@ -367,7 +372,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn check_ptr_access_align(
         &self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         size: Size,
         align: Align,
         msg: CheckInAllocMsg,
@@ -385,11 +390,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned.
     fn check_and_deref_ptr<T>(
         &self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         size: Size,
         align: Option<Align>,
         msg: CheckInAllocMsg,
-        alloc_size: impl FnOnce(AllocId, Size, M::TagExtra) -> InterpResult<'tcx, (Size, Align, T)>,
+        alloc_size: impl FnOnce(
+            AllocId,
+            Size,
+            M::ProvenanceExtra,
+        ) -> InterpResult<'tcx, (Size, Align, T)>,
     ) -> InterpResult<'tcx, Option<T>> {
         fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
             if offset % align.bytes() == 0 {
@@ -417,8 +426,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
                 None
             }
-            Ok((alloc_id, offset, tag)) => {
-                let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, tag)?;
+            Ok((alloc_id, offset, prov)) => {
+                let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?;
                 // Test bounds. This also ensures non-null.
                 // It is sufficient to check this for the end pointer. Also check for overflow!
                 if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) {
@@ -431,7 +440,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     })
                 }
                 // Ensure we never consider the null pointer dereferencable.
-                if M::PointerTag::OFFSET_IS_ADDR {
+                if M::Provenance::OFFSET_IS_ADDR {
                     assert_ne!(ptr.addr(), Size::ZERO);
                 }
                 // Test align. Check this last; if both bounds and alignment are violated
@@ -462,19 +471,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Helper function to obtain a global (tcx) allocation.
     /// This attempts to return a reference to an existing allocation if
     /// one can be found in `tcx`. That, however, is only possible if `tcx` and
-    /// this machine use the same pointer tag, so it is indirected through
-    /// `M::tag_allocation`.
+    /// this machine use the same pointer provenance, so it is indirected through
+    /// `M::adjust_allocation`.
     fn get_global_alloc(
         &self,
         id: AllocId,
         is_write: bool,
-    ) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> {
-        let (alloc, def_id) = match self.tcx.get_global_alloc(id) {
+    ) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra>>> {
+        let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) {
             Some(GlobalAlloc::Memory(mem)) => {
                 // Memory of a constant or promoted or anonymous memory referenced by a static.
                 (mem, None)
             }
             Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)),
+            Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
             None => throw_ub!(PointerUseAfterFree(id)),
             Some(GlobalAlloc::Static(def_id)) => {
                 assert!(self.tcx.is_static(def_id));
@@ -490,6 +500,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // contains a reference to memory that was created during its evaluation (i.e., not
                 // to another static), those inner references only exist in "resolved" form.
                 if self.tcx.is_foreign_item(def_id) {
+                    // This is unreachable in Miri, but can happen in CTFE where we actually *do* support
+                    // referencing arbitrary (declared) extern statics.
                     throw_unsup!(ReadExternStatic(def_id));
                 }
 
@@ -499,7 +511,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         };
         M::before_access_global(*self.tcx, &self.machine, id, alloc, def_id, is_write)?;
         // We got tcx memory. Let the machine initialize its "extra" stuff.
-        M::init_allocation_extra(
+        M::adjust_allocation(
             self,
             id, // always use the ID we got as input, not the "hidden" one.
             Cow::Borrowed(alloc.inner()),
@@ -512,11 +524,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     fn get_alloc_raw(
         &self,
         id: AllocId,
-    ) -> InterpResult<'tcx, &Allocation<M::PointerTag, M::AllocExtra>> {
+    ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra>> {
         // The error type of the inner closure here is somewhat funny.  We have two
         // ways of "erroring": An actual error, or because we got a reference from
         // `get_global_alloc` that we can actually use directly without inserting anything anywhere.
-        // So the error type is `InterpResult<'tcx, &Allocation<M::PointerTag>>`.
+        // So the error type is `InterpResult<'tcx, &Allocation<M::Provenance>>`.
         let a = self.memory.alloc_map.get_or(id, || {
             let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?;
             match alloc {
@@ -545,24 +557,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// "Safe" (bounds and align-checked) allocation access.
     pub fn get_ptr_alloc<'a>(
         &'a self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         size: Size,
         align: Align,
-    ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::PointerTag, M::AllocExtra>>> {
+    ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
         let align = M::enforce_alignment(self).then_some(align);
         let ptr_and_alloc = self.check_and_deref_ptr(
             ptr,
             size,
             align,
             CheckInAllocMsg::MemoryAccessTest,
-            |alloc_id, offset, tag| {
+            |alloc_id, offset, prov| {
                 let alloc = self.get_alloc_raw(alloc_id)?;
-                Ok((alloc.size(), alloc.align, (alloc_id, offset, tag, alloc)))
+                Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc)))
             },
         )?;
-        if let Some((alloc_id, offset, tag, alloc)) = ptr_and_alloc {
+        if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc {
             let range = alloc_range(offset, size);
-            M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, tag), range)?;
+            M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?;
             Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
         } else {
             // Even in this branch we have to be sure that we actually access the allocation, in
@@ -586,7 +598,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     fn get_alloc_raw_mut(
         &mut self,
         id: AllocId,
-    ) -> InterpResult<'tcx, (&mut Allocation<M::PointerTag, M::AllocExtra>, &mut M)> {
+    ) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra>, &mut M)> {
         // We have "NLL problem case #3" here, which cannot be worked around without loss of
         // efficiency even for the common case where the key is in the map.
         // <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions>
@@ -612,18 +624,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// "Safe" (bounds and align-checked) allocation access.
     pub fn get_ptr_alloc_mut<'a>(
         &'a mut self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         size: Size,
         align: Align,
-    ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::PointerTag, M::AllocExtra>>> {
+    ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
         let parts = self.get_ptr_access(ptr, size, align)?;
-        if let Some((alloc_id, offset, tag)) = parts {
+        if let Some((alloc_id, offset, prov)) = parts {
             let tcx = *self.tcx;
             // FIXME: can we somehow avoid looking up the allocation twice here?
             // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
             let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
             let range = alloc_range(offset, size);
-            M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, tag), range)?;
+            M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?;
             Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id }))
         } else {
             Ok(None)
@@ -659,12 +671,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // # Statics
         // Can't do this in the match argument, we may get cycle errors since the lock would
         // be held throughout the match.
-        match self.tcx.get_global_alloc(id) {
-            Some(GlobalAlloc::Static(did)) => {
-                assert!(!self.tcx.is_thread_local_static(did));
+        match self.tcx.try_get_global_alloc(id) {
+            Some(GlobalAlloc::Static(def_id)) => {
+                assert!(self.tcx.is_static(def_id));
+                assert!(!self.tcx.is_thread_local_static(def_id));
                 // Use size and align of the type.
-                let ty = self.tcx.type_of(did);
+                let ty = self.tcx.type_of(def_id);
                 let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
+                assert!(!layout.is_unsized());
                 (layout.size, layout.align.abi, AllocKind::LiveData)
             }
             Some(GlobalAlloc::Memory(alloc)) => {
@@ -674,6 +688,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 (alloc.size(), alloc.align, AllocKind::LiveData)
             }
             Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
+            Some(GlobalAlloc::VTable(..)) => {
+                // No data to be accessed here. But vtables are pointer-aligned.
+                return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable);
+            }
             // The rest must be dead.
             None => {
                 // Deallocated pointers are allowed, we should be able to find
@@ -701,7 +719,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         if let Some(extra) = self.memory.extra_fn_ptr_map.get(&id) {
             Some(FnVal::Other(*extra))
         } else {
-            match self.tcx.get_global_alloc(id) {
+            match self.tcx.try_get_global_alloc(id) {
                 Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)),
                 _ => None,
             }
@@ -710,10 +728,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn get_ptr_fn(
         &self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
     ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
-        trace!("get_fn({:?})", ptr);
-        let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
+        trace!("get_ptr_fn({:?})", ptr);
+        let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?;
         if offset.bytes() != 0 {
             throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
         }
@@ -721,6 +739,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into())
     }
 
+    pub fn get_ptr_vtable(
+        &self,
+        ptr: Pointer<Option<M::Provenance>>,
+    ) -> InterpResult<'tcx, (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)> {
+        trace!("get_ptr_vtable({:?})", ptr);
+        let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
+        if offset.bytes() != 0 {
+            throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
+        }
+        match self.tcx.try_get_global_alloc(alloc_id) {
+            Some(GlobalAlloc::VTable(ty, trait_ref)) => Ok((ty, trait_ref)),
+            _ => throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))),
+        }
+    }
+
     pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
         self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not;
         Ok(())
@@ -759,7 +792,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     // This is a new allocation, add its relocations to `todo`.
                     if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
                         todo.extend(
-                            alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()),
+                            alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()),
                         );
                     }
                 }
@@ -788,14 +821,14 @@ pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
 
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        // Cannot be a closure because it is generic in `Tag`, `Extra`.
-        fn write_allocation_track_relocs<'tcx, Tag: Provenance, Extra>(
+        // Cannot be a closure because it is generic in `Prov`, `Extra`.
+        fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra>(
             fmt: &mut std::fmt::Formatter<'_>,
             tcx: TyCtxt<'tcx>,
             allocs_to_print: &mut VecDeque<AllocId>,
-            alloc: &Allocation<Tag, Extra>,
+            alloc: &Allocation<Prov, Extra>,
         ) -> std::fmt::Result {
-            for alloc_id in alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()) {
+            for alloc_id in alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()) {
                 allocs_to_print.push_back(alloc_id);
             }
             write!(fmt, "{}", display_allocation(tcx, alloc))
@@ -825,7 +858,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
                 }
                 None => {
                     // global alloc
-                    match self.ecx.tcx.get_global_alloc(id) {
+                    match self.ecx.tcx.try_get_global_alloc(id) {
                         Some(GlobalAlloc::Memory(alloc)) => {
                             write!(fmt, " (unchanged global, ")?;
                             write_allocation_track_relocs(
@@ -836,7 +869,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
                             )?;
                         }
                         Some(GlobalAlloc::Function(func)) => {
-                            write!(fmt, " (fn: {})", func)?;
+                            write!(fmt, " (fn: {func})")?;
+                        }
+                        Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => {
+                            write!(fmt, " (vtable: impl {trait_ref} for {ty})")?;
+                        }
+                        Some(GlobalAlloc::VTable(ty, None)) => {
+                            write!(fmt, " (vtable: impl <auto trait> for {ty})")?;
                         }
                         Some(GlobalAlloc::Static(did)) => {
                             write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?;
@@ -854,12 +893,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
 }
 
 /// Reading and writing.
-impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
+impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> {
     /// `range` is relative to this allocation reference, not the base of the allocation.
     pub fn write_scalar(
         &mut self,
         range: AllocRange,
-        val: ScalarMaybeUninit<Tag>,
+        val: ScalarMaybeUninit<Prov>,
     ) -> InterpResult<'tcx> {
         let range = self.range.subrange(range);
         debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id);
@@ -873,7 +912,7 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
     pub fn write_ptr_sized(
         &mut self,
         offset: Size,
-        val: ScalarMaybeUninit<Tag>,
+        val: ScalarMaybeUninit<Prov>,
     ) -> InterpResult<'tcx> {
         self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val)
     }
@@ -887,13 +926,13 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
     }
 }
 
-impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
+impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> {
     /// `range` is relative to this allocation reference, not the base of the allocation.
     pub fn read_scalar(
         &self,
         range: AllocRange,
         read_provenance: bool,
-    ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+    ) -> InterpResult<'tcx, ScalarMaybeUninit<Prov>> {
         let range = self.range.subrange(range);
         let res = self
             .alloc
@@ -904,12 +943,12 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
     }
 
     /// `range` is relative to this allocation reference, not the base of the allocation.
-    pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+    pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Prov>> {
         self.read_scalar(range, /*read_provenance*/ false)
     }
 
     /// `offset` is relative to this allocation reference, not the base of the allocation.
-    pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+    pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Prov>> {
         self.read_scalar(
             alloc_range(offset, self.tcx.data_layout().pointer_size),
             /*read_provenance*/ true,
@@ -941,7 +980,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Performs appropriate bounds checks.
     pub fn read_bytes_ptr(
         &self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         size: Size,
     ) -> InterpResult<'tcx, &[u8]> {
         let Some(alloc_ref) = self.get_ptr_alloc(ptr, size, Align::ONE)? else {
@@ -961,7 +1000,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Performs appropriate bounds checks.
     pub fn write_bytes_ptr(
         &mut self,
-        ptr: Pointer<Option<M::PointerTag>>,
+        ptr: Pointer<Option<M::Provenance>>,
         src: impl IntoIterator<Item = u8>,
     ) -> InterpResult<'tcx> {
         let mut src = src.into_iter();
@@ -998,9 +1037,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn mem_copy(
         &mut self,
-        src: Pointer<Option<M::PointerTag>>,
+        src: Pointer<Option<M::Provenance>>,
         src_align: Align,
-        dest: Pointer<Option<M::PointerTag>>,
+        dest: Pointer<Option<M::Provenance>>,
         dest_align: Align,
         size: Size,
         nonoverlapping: bool,
@@ -1010,9 +1049,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn mem_copy_repeatedly(
         &mut self,
-        src: Pointer<Option<M::PointerTag>>,
+        src: Pointer<Option<M::Provenance>>,
         src_align: Align,
-        dest: Pointer<Option<M::PointerTag>>,
+        dest: Pointer<Option<M::Provenance>>,
         dest_align: Align,
         size: Size,
         num_copies: u64,
@@ -1027,16 +1066,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // and once below to get the underlying `&[mut] Allocation`.
 
         // Source alloc preparations and access hooks.
-        let Some((src_alloc_id, src_offset, src_tag)) = src_parts else {
+        let Some((src_alloc_id, src_offset, src_prov)) = src_parts else {
             // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
             return Ok(());
         };
         let src_alloc = self.get_alloc_raw(src_alloc_id)?;
         let src_range = alloc_range(src_offset, size);
-        M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_tag), src_range)?;
+        M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_prov), src_range)?;
         // We need the `dest` ptr for the next operation, so we get it now.
         // We already did the source checks and called the hooks so we are good to return early.
-        let Some((dest_alloc_id, dest_offset, dest_tag)) = dest_parts else {
+        let Some((dest_alloc_id, dest_offset, dest_prov)) = dest_parts else {
             // Zero-sized *destination*.
             return Ok(());
         };
@@ -1062,7 +1101,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             *tcx,
             extra,
             &mut dest_alloc.extra,
-            (dest_alloc_id, dest_tag),
+            (dest_alloc_id, dest_prov),
             dest_range,
         )?;
         let dest_bytes = dest_alloc
@@ -1135,8 +1174,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn scalar_to_ptr(
         &self,
-        scalar: Scalar<M::PointerTag>,
-    ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
+        scalar: Scalar<M::Provenance>,
+    ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
         // We use `to_bits_or_ptr_internal` since we are just implementing the method people need to
         // call to force getting out a pointer.
         Ok(
@@ -1155,7 +1194,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     /// Test if this value might be null.
     /// If the machine does not support ptr-to-int casts, this is conservative.
-    pub fn scalar_may_be_null(&self, scalar: Scalar<M::PointerTag>) -> InterpResult<'tcx, bool> {
+    pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<'tcx, bool> {
         Ok(match scalar.try_to_int() {
             Ok(int) => int.is_null(),
             Err(_) => {
@@ -1178,13 +1217,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// about where it points), or an absolute address.
     pub fn ptr_try_get_alloc_id(
         &self,
-        ptr: Pointer<Option<M::PointerTag>>,
-    ) -> Result<(AllocId, Size, M::TagExtra), u64> {
+        ptr: Pointer<Option<M::Provenance>>,
+    ) -> Result<(AllocId, Size, M::ProvenanceExtra), u64> {
         match ptr.into_pointer_or_addr() {
             Ok(ptr) => match M::ptr_get_alloc(self, ptr) {
                 Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)),
                 None => {
-                    assert!(M::PointerTag::OFFSET_IS_ADDR);
+                    assert!(M::Provenance::OFFSET_IS_ADDR);
                     let (_, addr) = ptr.into_parts();
                     Err(addr.bytes())
                 }
@@ -1197,8 +1236,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn ptr_get_alloc_id(
         &self,
-        ptr: Pointer<Option<M::PointerTag>>,
-    ) -> InterpResult<'tcx, (AllocId, Size, M::TagExtra)> {
+        ptr: Pointer<Option<M::Provenance>>,
+    ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> {
         self.ptr_try_get_alloc_id(ptr).map_err(|offset| {
             err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into()
         })
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index de6eb1c0336..7e5c6feb048 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -25,14 +25,14 @@ use super::{
 /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
 /// defined on `Immediate`, and do not have to work with a `Place`.
 #[derive(Copy, Clone, Debug)]
-pub enum Immediate<Tag: Provenance = AllocId> {
+pub enum Immediate<Prov: Provenance = AllocId> {
     /// A single scalar value (must have *initialized* `Scalar` ABI).
     /// FIXME: we also currently often use this for ZST.
     /// `ScalarMaybeUninit` should reject ZST, and we should use `Uninit` for them instead.
-    Scalar(ScalarMaybeUninit<Tag>),
+    Scalar(ScalarMaybeUninit<Prov>),
     /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are
     /// `Scalar::Initialized`).
-    ScalarPair(ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>),
+    ScalarPair(ScalarMaybeUninit<Prov>, ScalarMaybeUninit<Prov>),
     /// A value of fully uninitialized memory. Can have and size and layout.
     Uninit,
 }
@@ -40,36 +40,36 @@ pub enum Immediate<Tag: Provenance = AllocId> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Immediate, 56);
 
-impl<Tag: Provenance> From<ScalarMaybeUninit<Tag>> for Immediate<Tag> {
+impl<Prov: Provenance> From<ScalarMaybeUninit<Prov>> for Immediate<Prov> {
     #[inline(always)]
-    fn from(val: ScalarMaybeUninit<Tag>) -> Self {
+    fn from(val: ScalarMaybeUninit<Prov>) -> Self {
         Immediate::Scalar(val)
     }
 }
 
-impl<Tag: Provenance> From<Scalar<Tag>> for Immediate<Tag> {
+impl<Prov: Provenance> From<Scalar<Prov>> for Immediate<Prov> {
     #[inline(always)]
-    fn from(val: Scalar<Tag>) -> Self {
+    fn from(val: Scalar<Prov>) -> Self {
         Immediate::Scalar(val.into())
     }
 }
 
-impl<'tcx, Tag: Provenance> Immediate<Tag> {
-    pub fn from_pointer(p: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
+impl<'tcx, Prov: Provenance> Immediate<Prov> {
+    pub fn from_pointer(p: Pointer<Prov>, cx: &impl HasDataLayout) -> Self {
         Immediate::Scalar(ScalarMaybeUninit::from_pointer(p, cx))
     }
 
-    pub fn from_maybe_pointer(p: Pointer<Option<Tag>>, cx: &impl HasDataLayout) -> Self {
+    pub fn from_maybe_pointer(p: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self {
         Immediate::Scalar(ScalarMaybeUninit::from_maybe_pointer(p, cx))
     }
 
-    pub fn new_slice(val: Scalar<Tag>, len: u64, cx: &impl HasDataLayout) -> Self {
+    pub fn new_slice(val: Scalar<Prov>, len: u64, cx: &impl HasDataLayout) -> Self {
         Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into())
     }
 
     pub fn new_dyn_trait(
-        val: Scalar<Tag>,
-        vtable: Pointer<Option<Tag>>,
+        val: Scalar<Prov>,
+        vtable: Pointer<Option<Prov>>,
         cx: &impl HasDataLayout,
     ) -> Self {
         Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_maybe_pointer(vtable, cx))
@@ -77,7 +77,7 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
 
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
-    pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> {
+    pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Prov> {
         match self {
             Immediate::Scalar(val) => val,
             Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"),
@@ -87,13 +87,13 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
 
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
-    pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> {
+    pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Prov>> {
         self.to_scalar_or_uninit().check_init()
     }
 
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
-    pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>) {
+    pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit<Prov>, ScalarMaybeUninit<Prov>) {
         match self {
             Immediate::ScalarPair(val1, val2) => (val1, val2),
             Immediate::Scalar(..) => bug!("Got a scalar where a scalar pair was expected"),
@@ -103,7 +103,7 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
 
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
-    pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
+    pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Prov>, Scalar<Prov>)> {
         let (val1, val2) = self.to_scalar_or_uninit_pair();
         Ok((val1.check_init()?, val2.check_init()?))
     }
@@ -112,20 +112,20 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
 // ScalarPair needs a type to interpret, so we often have an immediate and a type together
 // as input for binary and cast operations.
 #[derive(Clone, Debug)]
-pub struct ImmTy<'tcx, Tag: Provenance = AllocId> {
-    imm: Immediate<Tag>,
+pub struct ImmTy<'tcx, Prov: Provenance = AllocId> {
+    imm: Immediate<Prov>,
     pub layout: TyAndLayout<'tcx>,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
 
-impl<Tag: Provenance> std::fmt::Display for ImmTy<'_, Tag> {
+impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         /// Helper function for printing a scalar to a FmtPrinter
-        fn p<'a, 'tcx, Tag: Provenance>(
+        fn p<'a, 'tcx, Prov: Provenance>(
             cx: FmtPrinter<'a, 'tcx>,
-            s: ScalarMaybeUninit<Tag>,
+            s: ScalarMaybeUninit<Prov>,
             ty: Ty<'tcx>,
         ) -> Result<FmtPrinter<'a, 'tcx>, std::fmt::Error> {
             match s {
@@ -170,10 +170,10 @@ impl<Tag: Provenance> std::fmt::Display for ImmTy<'_, Tag> {
     }
 }
 
-impl<'tcx, Tag: Provenance> std::ops::Deref for ImmTy<'tcx, Tag> {
-    type Target = Immediate<Tag>;
+impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> {
+    type Target = Immediate<Prov>;
     #[inline(always)]
-    fn deref(&self) -> &Immediate<Tag> {
+    fn deref(&self) -> &Immediate<Prov> {
         &self.imm
     }
 }
@@ -182,17 +182,17 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for ImmTy<'tcx, Tag> {
 /// or still in memory. The latter is an optimization, to delay reading that chunk of
 /// memory and to avoid having to store arbitrary-sized data here.
 #[derive(Copy, Clone, Debug)]
-pub enum Operand<Tag: Provenance = AllocId> {
-    Immediate(Immediate<Tag>),
-    Indirect(MemPlace<Tag>),
+pub enum Operand<Prov: Provenance = AllocId> {
+    Immediate(Immediate<Prov>),
+    Indirect(MemPlace<Prov>),
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Operand, 64);
 
 #[derive(Clone, Debug)]
-pub struct OpTy<'tcx, Tag: Provenance = AllocId> {
-    op: Operand<Tag>, // Keep this private; it helps enforce invariants.
+pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
+    op: Operand<Prov>, // Keep this private; it helps enforce invariants.
     pub layout: TyAndLayout<'tcx>,
     /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
     /// it needs to have a different alignment than the field type would usually have.
@@ -207,50 +207,50 @@ pub struct OpTy<'tcx, Tag: Provenance = AllocId> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(OpTy<'_>, 88);
 
-impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> {
-    type Target = Operand<Tag>;
+impl<'tcx, Prov: Provenance> std::ops::Deref for OpTy<'tcx, Prov> {
+    type Target = Operand<Prov>;
     #[inline(always)]
-    fn deref(&self) -> &Operand<Tag> {
+    fn deref(&self) -> &Operand<Prov> {
         &self.op
     }
 }
 
-impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
     #[inline(always)]
-    fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
+    fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self {
         OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout, align: Some(mplace.align) }
     }
 }
 
-impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
     #[inline(always)]
-    fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
+    fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self {
         OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
     }
 }
 
-impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
     #[inline(always)]
-    fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
+    fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self {
         OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
     }
 }
 
-impl<'tcx, Tag: Provenance> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
     #[inline(always)]
-    fn from(val: ImmTy<'tcx, Tag>) -> Self {
+    fn from(val: ImmTy<'tcx, Prov>) -> Self {
         OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None }
     }
 }
 
-impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
     #[inline]
-    pub fn from_scalar(val: Scalar<Tag>, layout: TyAndLayout<'tcx>) -> Self {
+    pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
         ImmTy { imm: val.into(), layout }
     }
 
     #[inline]
-    pub fn from_immediate(imm: Immediate<Tag>, layout: TyAndLayout<'tcx>) -> Self {
+    pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self {
         ImmTy { imm, layout }
     }
 
@@ -286,7 +286,7 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> {
     }
 }
 
-impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
     pub fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         if self.layout.is_unsized() {
             // There are no unsized immediates.
@@ -302,7 +302,7 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> {
     pub fn offset_with_meta(
         &self,
         offset: Size,
-        meta: MemPlaceMeta<Tag>,
+        meta: MemPlaceMeta<Prov>,
         layout: TyAndLayout<'tcx>,
         cx: &impl HasDataLayout,
     ) -> InterpResult<'tcx, Self> {
@@ -338,9 +338,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// This is an internal function; call `read_immediate` instead.
     fn read_immediate_from_mplace_raw(
         &self,
-        mplace: &MPlaceTy<'tcx, M::PointerTag>,
+        mplace: &MPlaceTy<'tcx, M::Provenance>,
         force: bool,
-    ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::PointerTag>>> {
+    ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::Provenance>>> {
         if mplace.layout.is_unsized() {
             // Don't touch unsized
             return Ok(None);
@@ -418,9 +418,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// ConstProp needs it, though.
     pub fn read_immediate_raw(
         &self,
-        src: &OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::Provenance>,
         force: bool,
-    ) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
+    ) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::Provenance>, MPlaceTy<'tcx, M::Provenance>>> {
         Ok(match src.try_as_mplace() {
             Ok(ref mplace) => {
                 if let Some(val) = self.read_immediate_from_mplace_raw(mplace, force)? {
@@ -437,8 +437,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn read_immediate(
         &self,
-        op: &OpTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         if let Ok(imm) = self.read_immediate_raw(op, /*force*/ false)? {
             Ok(imm)
         } else {
@@ -449,21 +449,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Read a scalar from a place
     pub fn read_scalar(
         &self,
-        op: &OpTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ScalarMaybeUninit<M::Provenance>> {
         Ok(self.read_immediate(op)?.to_scalar_or_uninit())
     }
 
     /// Read a pointer from a place.
     pub fn read_pointer(
         &self,
-        op: &OpTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
         self.scalar_to_ptr(self.read_scalar(op)?.check_init()?)
     }
 
     /// Turn the wide MPlace into a string (must already be dereferenced!)
-    pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> {
+    pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, &str> {
         let len = mplace.len(self)?;
         let bytes = self.read_bytes_ptr(mplace.ptr, Size::from_bytes(len))?;
         let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
@@ -476,8 +476,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Can (but does not always) trigger UB if `op` is uninitialized.
     pub fn operand_to_simd(
         &self,
-        op: &OpTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> {
         // Basically we just transmute this place into an array following simd_size_and_type.
         // This only works in memory, but repr(simd) types should never be immediates anyway.
         assert!(op.layout.ty.is_simd());
@@ -501,10 +501,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// OpTy from a local.
     pub fn local_to_op(
         &self,
-        frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
+        frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
         local: mir::Local,
         layout: Option<TyAndLayout<'tcx>>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         let layout = self.layout_of_local(frame, local, layout)?;
         let op = if layout.is_zst() {
             // Bypass `access_local` (helps in ConstProp)
@@ -521,8 +521,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn place_to_op(
         &self,
-        place: &PlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+        place: &PlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         let op = match **place {
             Place::Ptr(mplace) => Operand::Indirect(mplace),
             Place::Local { frame, local } => {
@@ -538,7 +538,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &self,
         mir_place: mir::Place<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         // Do not use the layout passed in as argument if the base we are looking at
         // here is not the entire place.
         let layout = if mir_place.projection.is_empty() { layout } else { None };
@@ -575,7 +575,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &self,
         mir_op: &mir::Operand<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         use rustc_middle::mir::Operand::*;
         let op = match *mir_op {
             // FIXME: do some more logic on `move` to invalidate the old location
@@ -600,7 +600,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub(super) fn eval_operands(
         &self,
         ops: &[mir::Operand<'tcx>],
-    ) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::PointerTag>>> {
+    ) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>> {
         ops.iter().map(|op| self.eval_operand(op, None)).collect()
     }
 
@@ -612,7 +612,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &self,
         c: ty::Const<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         match c.kind() {
             ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => {
@@ -637,7 +637,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &self,
         val: &mir::ConstantKind<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         match val {
             mir::ConstantKind::Ty(ct) => self.const_to_op(*ct, layout),
             mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, *ty, layout),
@@ -649,9 +649,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         val_val: ConstValue<'tcx>,
         ty: Ty<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         // Other cases need layout.
-        let tag_scalar = |scalar| -> InterpResult<'tcx, _> {
+        let adjust_scalar = |scalar| -> InterpResult<'tcx, _> {
             Ok(match scalar {
                 Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_base_pointer(ptr)?, size),
                 Scalar::Int(int) => Scalar::Int(int),
@@ -666,7 +666,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let ptr = self.global_base_pointer(Pointer::new(id, offset))?;
                 Operand::Indirect(MemPlace::from_ptr(ptr.into()))
             }
-            ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()),
+            ConstValue::Scalar(x) => Operand::Immediate(adjust_scalar(x)?.into()),
             ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit),
             ConstValue::Slice { data, start, end } => {
                 // We rely on mutability being set correctly in `data` to prevent writes
@@ -689,8 +689,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!
     pub fn read_discriminant(
         &self,
-        op: &OpTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, VariantIdx)> {
         trace!("read_discriminant_value {:#?}", op.layout);
         // Get type and layout of the discriminant.
         let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 88999e3b47b..f9912d706fb 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -19,9 +19,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &mut self,
         op: mir::BinOp,
         force_overflow_checks: bool,
-        left: &ImmTy<'tcx, M::PointerTag>,
-        right: &ImmTy<'tcx, M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::Provenance>,
+        right: &ImmTy<'tcx, M::Provenance>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?;
         debug_assert_eq!(
@@ -58,9 +58,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn binop_ignore_overflow(
         &mut self,
         op: mir::BinOp,
-        left: &ImmTy<'tcx, M::PointerTag>,
-        right: &ImmTy<'tcx, M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::Provenance>,
+        right: &ImmTy<'tcx, M::Provenance>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
         assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op);
@@ -74,7 +74,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         bin_op: mir::BinOp,
         l: char,
         r: char,
-    ) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
+    ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) {
         use rustc_middle::mir::BinOp::*;
 
         let res = match bin_op {
@@ -94,7 +94,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         bin_op: mir::BinOp,
         l: bool,
         r: bool,
-    ) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
+    ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) {
         use rustc_middle::mir::BinOp::*;
 
         let res = match bin_op {
@@ -112,13 +112,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         (Scalar::from_bool(res), false, self.tcx.types.bool)
     }
 
-    fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>(
+    fn binary_float_op<F: Float + Into<Scalar<M::Provenance>>>(
         &self,
         bin_op: mir::BinOp,
         ty: Ty<'tcx>,
         l: F,
         r: F,
-    ) -> (Scalar<M::PointerTag>, bool, Ty<'tcx>) {
+    ) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) {
         use rustc_middle::mir::BinOp::*;
 
         let (val, ty) = match bin_op {
@@ -146,7 +146,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         left_layout: TyAndLayout<'tcx>,
         r: u128,
         right_layout: TyAndLayout<'tcx>,
-    ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
+    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
         use rustc_middle::mir::BinOp::*;
 
         // Shift ops can have an RHS with a different numeric type.
@@ -314,9 +314,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn overflowing_binary_op(
         &self,
         bin_op: mir::BinOp,
-        left: &ImmTy<'tcx, M::PointerTag>,
-        right: &ImmTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
+        left: &ImmTy<'tcx, M::Provenance>,
+        right: &ImmTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
         trace!(
             "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
             bin_op,
@@ -393,9 +393,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn binary_op(
         &self,
         bin_op: mir::BinOp,
-        left: &ImmTy<'tcx, M::PointerTag>,
-        right: &ImmTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
+        left: &ImmTy<'tcx, M::Provenance>,
+        right: &ImmTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
         Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
     }
@@ -405,8 +405,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn overflowing_unary_op(
         &self,
         un_op: mir::UnOp,
-        val: &ImmTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
+        val: &ImmTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
         use rustc_middle::mir::UnOp::*;
 
         let layout = val.layout;
@@ -455,8 +455,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn unary_op(
         &self,
         un_op: mir::UnOp,
-        val: &ImmTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
+        val: &ImmTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?;
         Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
     }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index bc71bfe4327..c7d8a744f7c 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -18,9 +18,9 @@ use super::{
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
 /// Information required for the sound usage of a `MemPlace`.
-pub enum MemPlaceMeta<Tag: Provenance = AllocId> {
+pub enum MemPlaceMeta<Prov: Provenance = AllocId> {
     /// The unsized payload (e.g. length for slices or vtable pointer for trait objects).
-    Meta(Scalar<Tag>),
+    Meta(Scalar<Prov>),
     /// `Sized` types or unsized `extern type`
     None,
 }
@@ -28,8 +28,8 @@ pub enum MemPlaceMeta<Tag: Provenance = AllocId> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(MemPlaceMeta, 24);
 
-impl<Tag: Provenance> MemPlaceMeta<Tag> {
-    pub fn unwrap_meta(self) -> Scalar<Tag> {
+impl<Prov: Provenance> MemPlaceMeta<Prov> {
+    pub fn unwrap_meta(self) -> Scalar<Prov> {
         match self {
             Self::Meta(s) => s,
             Self::None => {
@@ -47,13 +47,13 @@ impl<Tag: Provenance> MemPlaceMeta<Tag> {
 }
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
-pub struct MemPlace<Tag: Provenance = AllocId> {
-    /// The pointer can be a pure integer, with the `None` tag.
-    pub ptr: Pointer<Option<Tag>>,
+pub struct MemPlace<Prov: Provenance = AllocId> {
+    /// The pointer can be a pure integer, with the `None` provenance.
+    pub ptr: Pointer<Option<Prov>>,
     /// Metadata for unsized places. Interpretation is up to the type.
     /// Must not be present for sized types, but can be missing for unsized types
     /// (e.g., `extern type`).
-    pub meta: MemPlaceMeta<Tag>,
+    pub meta: MemPlaceMeta<Prov>,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -61,8 +61,8 @@ rustc_data_structures::static_assert_size!(MemPlace, 40);
 
 /// A MemPlace with its layout. Constructing it is only possible in this module.
 #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
-pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> {
-    mplace: MemPlace<Tag>,
+pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
+    mplace: MemPlace<Prov>,
     pub layout: TyAndLayout<'tcx>,
     /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
     /// it needs to have a different alignment than the field type would usually have.
@@ -75,9 +75,9 @@ pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> {
 rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64);
 
 #[derive(Copy, Clone, Debug)]
-pub enum Place<Tag: Provenance = AllocId> {
+pub enum Place<Prov: Provenance = AllocId> {
     /// A place referring to a value allocated in the `Memory` system.
-    Ptr(MemPlace<Tag>),
+    Ptr(MemPlace<Prov>),
 
     /// To support alloc-free locals, we are able to write directly to a local.
     /// (Without that optimization, we'd just always be a `MemPlace`.)
@@ -88,8 +88,8 @@ pub enum Place<Tag: Provenance = AllocId> {
 rustc_data_structures::static_assert_size!(Place, 48);
 
 #[derive(Clone, Debug)]
-pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> {
-    place: Place<Tag>, // Keep this private; it helps enforce invariants.
+pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
+    place: Place<Prov>, // Keep this private; it helps enforce invariants.
     pub layout: TyAndLayout<'tcx>,
     /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
     /// it needs to have a different alignment than the field type would usually have.
@@ -101,58 +101,58 @@ pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72);
 
-impl<'tcx, Tag: Provenance> std::ops::Deref for PlaceTy<'tcx, Tag> {
-    type Target = Place<Tag>;
+impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> {
+    type Target = Place<Prov>;
     #[inline(always)]
-    fn deref(&self) -> &Place<Tag> {
+    fn deref(&self) -> &Place<Prov> {
         &self.place
     }
 }
 
-impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> {
-    type Target = MemPlace<Tag>;
+impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> {
+    type Target = MemPlace<Prov>;
     #[inline(always)]
-    fn deref(&self) -> &MemPlace<Tag> {
+    fn deref(&self) -> &MemPlace<Prov> {
         &self.mplace
     }
 }
 
-impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
     #[inline(always)]
-    fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
+    fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self {
         PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout, align: mplace.align }
     }
 }
 
-impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> From<&'_ MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
     #[inline(always)]
-    fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
+    fn from(mplace: &MPlaceTy<'tcx, Prov>) -> Self {
         PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
     }
 }
 
-impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> From<&'_ mut MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> {
     #[inline(always)]
-    fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
+    fn from(mplace: &mut MPlaceTy<'tcx, Prov>) -> Self {
         PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
     }
 }
 
-impl<Tag: Provenance> MemPlace<Tag> {
+impl<Prov: Provenance> MemPlace<Prov> {
     #[inline(always)]
-    pub fn from_ptr(ptr: Pointer<Option<Tag>>) -> Self {
+    pub fn from_ptr(ptr: Pointer<Option<Prov>>) -> Self {
         MemPlace { ptr, meta: MemPlaceMeta::None }
     }
 
     /// Adjust the provenance of the main pointer (metadata is unaffected).
-    pub fn map_provenance(self, f: impl FnOnce(Option<Tag>) -> Option<Tag>) -> Self {
+    pub fn map_provenance(self, f: impl FnOnce(Option<Prov>) -> Option<Prov>) -> Self {
         MemPlace { ptr: self.ptr.map_provenance(f), ..self }
     }
 
     /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space.
     /// This is the inverse of `ref_to_mplace`.
     #[inline(always)]
-    pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Tag> {
+    pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Prov> {
         match self.meta {
             MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)),
             MemPlaceMeta::Meta(meta) => {
@@ -165,14 +165,14 @@ impl<Tag: Provenance> MemPlace<Tag> {
     pub fn offset_with_meta<'tcx>(
         self,
         offset: Size,
-        meta: MemPlaceMeta<Tag>,
+        meta: MemPlaceMeta<Prov>,
         cx: &impl HasDataLayout,
     ) -> InterpResult<'tcx, Self> {
         Ok(MemPlace { ptr: self.ptr.offset(offset, cx)?, meta })
     }
 }
 
-impl<Tag: Provenance> Place<Tag> {
+impl<Prov: Provenance> Place<Prov> {
     /// Asserts that this points to some local variable.
     /// Returns the frame idx and the variable idx.
     #[inline]
@@ -185,7 +185,7 @@ impl<Tag: Provenance> Place<Tag> {
     }
 }
 
-impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> {
     /// Produces a MemPlace that works for ZST but nothing else.
     /// Conceptually this is a new allocation, but it doesn't actually create an allocation so you
     /// don't need to worry about memory leaks.
@@ -201,7 +201,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
     pub fn offset_with_meta(
         &self,
         offset: Size,
-        meta: MemPlaceMeta<Tag>,
+        meta: MemPlaceMeta<Prov>,
         layout: TyAndLayout<'tcx>,
         cx: &impl HasDataLayout,
     ) -> InterpResult<'tcx, Self> {
@@ -223,15 +223,15 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
     }
 
     #[inline]
-    pub fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) -> Self {
+    pub fn from_aligned_ptr(ptr: Pointer<Option<Prov>>, layout: TyAndLayout<'tcx>) -> Self {
         MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi }
     }
 
     #[inline]
     pub fn from_aligned_ptr_with_meta(
-        ptr: Pointer<Option<Tag>>,
+        ptr: Pointer<Option<Prov>>,
         layout: TyAndLayout<'tcx>,
-        meta: MemPlaceMeta<Tag>,
+        meta: MemPlaceMeta<Prov>,
     ) -> Self {
         let mut mplace = MemPlace::from_ptr(ptr);
         mplace.meta = meta;
@@ -258,7 +258,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
     }
 
     #[inline]
-    pub(super) fn vtable(&self) -> Scalar<Tag> {
+    pub(super) fn vtable(&self) -> Scalar<Prov> {
         match self.layout.ty.kind() {
             ty::Dynamic(..) => self.mplace.meta.unwrap_meta(),
             _ => bug!("vtable not supported on type {:?}", self.layout.ty),
@@ -267,11 +267,11 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
 }
 
 // These are defined here because they produce a place.
-impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
     #[inline(always)]
     /// Note: do not call `as_ref` on the resulting place. This function should only be used to
     /// read from the resulting mplace, not to get its address back.
-    pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
+    pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> {
         match **self {
             Operand::Indirect(mplace) => {
                 Ok(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() })
@@ -284,15 +284,15 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> {
     #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
     /// Note: do not call `as_ref` on the resulting place. This function should only be used to
     /// read from the resulting mplace, not to get its address back.
-    pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Tag> {
+    pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> {
         self.try_as_mplace().unwrap()
     }
 }
 
-impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> {
+impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> {
     /// A place is either an mplace or some local.
     #[inline]
-    pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, (usize, mir::Local)> {
+    pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Prov>, (usize, mir::Local)> {
         match **self {
             Place::Ptr(mplace) => Ok(MPlaceTy { mplace, layout: self.layout, align: self.align }),
             Place::Local { frame, local } => Err((frame, local)),
@@ -301,16 +301,16 @@ impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> {
 
     #[inline(always)]
     #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
-    pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
+    pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Prov> {
         self.try_as_mplace().unwrap()
     }
 }
 
 // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
-impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M>
+impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>
 where
-    Tag: Provenance + Eq + Hash + 'static,
-    M: Machine<'mir, 'tcx, PointerTag = Tag>,
+    Prov: Provenance + Eq + Hash + 'static,
+    M: Machine<'mir, 'tcx, Provenance = Prov>,
 {
     /// Take a value, which represents a (thin or wide) reference, and make it a place.
     /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref()`.
@@ -320,8 +320,8 @@ where
     /// Generally prefer `deref_operand`.
     pub fn ref_to_mplace(
         &self,
-        val: &ImmTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+        val: &ImmTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let pointee_type =
             val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
         let layout = self.layout_of(pointee_type)?;
@@ -342,8 +342,8 @@ where
     #[instrument(skip(self), level = "debug")]
     pub fn deref_operand(
         &self,
-        src: &OpTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+        src: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let val = self.read_immediate(src)?;
         trace!("deref to {} on {:?}", val.layout.ty, *val);
 
@@ -359,8 +359,8 @@ where
     #[inline]
     pub(super) fn get_place_alloc(
         &self,
-        place: &MPlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::PointerTag, M::AllocExtra>>> {
+        place: &MPlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra>>> {
         assert!(!place.layout.is_unsized());
         assert!(!place.meta.has_meta());
         let size = place.layout.size;
@@ -370,8 +370,8 @@ where
     #[inline]
     pub(super) fn get_place_alloc_mut(
         &mut self,
-        place: &MPlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::PointerTag, M::AllocExtra>>> {
+        place: &MPlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra>>> {
         assert!(!place.layout.is_unsized());
         assert!(!place.meta.has_meta());
         let size = place.layout.size;
@@ -381,7 +381,7 @@ where
     /// Check if this mplace is dereferenceable and sufficiently aligned.
     fn check_mplace_access(
         &self,
-        mplace: MPlaceTy<'tcx, M::PointerTag>,
+        mplace: MPlaceTy<'tcx, M::Provenance>,
         msg: CheckInAllocMsg,
     ) -> InterpResult<'tcx> {
         let (size, align) = self
@@ -397,8 +397,8 @@ where
     /// Also returns the number of elements.
     pub fn mplace_to_simd(
         &self,
-        mplace: &MPlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
+        mplace: &MPlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> {
         // Basically we just transmute this place into an array following simd_size_and_type.
         // (Transmuting is okay since this is an in-memory place. We also double-check the size
         // stays the same.)
@@ -413,8 +413,8 @@ where
     /// Also returns the number of elements.
     pub fn place_to_simd(
         &mut self,
-        place: &PlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
+        place: &PlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> {
         let mplace = self.force_allocation(place)?;
         self.mplace_to_simd(&mplace)
     }
@@ -423,7 +423,7 @@ where
         &self,
         frame: usize,
         local: mir::Local,
-    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
         let layout = self.layout_of_local(&self.stack()[frame], local, None)?;
         let place = Place::Local { frame, local };
         Ok(PlaceTy { place, layout, align: layout.align.abi })
@@ -435,7 +435,7 @@ where
     pub fn eval_place(
         &mut self,
         mir_place: mir::Place<'tcx>,
-    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
         let mut place = self.local_to_place(self.frame_idx(), mir_place.local)?;
         // Using `try_fold` turned out to be bad for performance, hence the loop.
         for elem in mir_place.projection.iter() {
@@ -465,8 +465,8 @@ where
     #[instrument(skip(self), level = "debug")]
     pub fn write_immediate(
         &mut self,
-        src: Immediate<M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        src: Immediate<M::Provenance>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         self.write_immediate_no_validate(src, dest)?;
 
@@ -482,8 +482,8 @@ where
     #[inline(always)]
     pub fn write_scalar(
         &mut self,
-        val: impl Into<ScalarMaybeUninit<M::PointerTag>>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        val: impl Into<ScalarMaybeUninit<M::Provenance>>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         self.write_immediate(Immediate::Scalar(val.into()), dest)
     }
@@ -492,8 +492,8 @@ where
     #[inline(always)]
     pub fn write_pointer(
         &mut self,
-        ptr: impl Into<Pointer<Option<M::PointerTag>>>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        ptr: impl Into<Pointer<Option<M::Provenance>>>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest)
     }
@@ -503,8 +503,8 @@ where
     /// right type.
     fn write_immediate_no_validate(
         &mut self,
-        src: Immediate<M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        src: Immediate<M::Provenance>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         assert!(!dest.layout.is_unsized(), "Cannot write unsized data");
         trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
@@ -537,10 +537,10 @@ where
     /// right layout.
     fn write_immediate_to_mplace_no_validate(
         &mut self,
-        value: Immediate<M::PointerTag>,
+        value: Immediate<M::Provenance>,
         layout: TyAndLayout<'tcx>,
         align: Align,
-        dest: MemPlace<M::PointerTag>,
+        dest: MemPlace<M::Provenance>,
     ) -> InterpResult<'tcx> {
         // Note that it is really important that the type here is the right one, and matches the
         // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here
@@ -589,7 +589,7 @@ where
         }
     }
 
-    pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+    pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
         let mplace = match dest.try_as_mplace() {
             Ok(mplace) => mplace,
             Err((frame, local)) => {
@@ -619,8 +619,8 @@ where
     #[instrument(skip(self), level = "debug")]
     pub fn copy_op(
         &mut self,
-        src: &OpTy<'tcx, M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::Provenance>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
         allow_transmute: bool,
     ) -> InterpResult<'tcx> {
         self.copy_op_no_validate(src, dest, allow_transmute)?;
@@ -640,8 +640,8 @@ where
     #[instrument(skip(self), level = "debug")]
     fn copy_op_no_validate(
         &mut self,
-        src: &OpTy<'tcx, M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::Provenance>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
         allow_transmute: bool,
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
@@ -713,8 +713,8 @@ where
     #[instrument(skip(self), level = "debug")]
     pub fn force_allocation(
         &mut self,
-        place: &PlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+        place: &PlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let mplace = match place.place {
             Place::Local { frame, local } => {
                 match M::access_local_mut(self, frame, local)? {
@@ -760,7 +760,7 @@ where
         &mut self,
         layout: TyAndLayout<'tcx>,
         kind: MemoryKind<M::MemoryKind>,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         assert!(!layout.is_unsized());
         let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?;
         Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout))
@@ -772,7 +772,7 @@ where
         str: &str,
         kind: MemoryKind<M::MemoryKind>,
         mutbl: Mutability,
-    ) -> MPlaceTy<'tcx, M::PointerTag> {
+    ) -> MPlaceTy<'tcx, M::Provenance> {
         let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl);
         let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
         let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
@@ -790,7 +790,7 @@ where
     pub fn write_discriminant(
         &mut self,
         variant_index: VariantIdx,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         // This must be an enum or generator.
         match dest.layout.ty.kind() {
@@ -876,7 +876,7 @@ where
     pub fn raw_const_to_mplace(
         &self,
         raw: ConstAlloc<'tcx>,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         // This must be an allocation in `tcx`
         let _ = self.tcx.global_alloc(raw.alloc_id);
         let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?;
@@ -885,28 +885,19 @@ where
     }
 
     /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
-    /// Also return some more information so drop doesn't have to run the same code twice.
     pub(super) fn unpack_dyn_trait(
         &self,
-        mplace: &MPlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
+        mplace: &MPlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let vtable = self.scalar_to_ptr(mplace.vtable())?; // also sanity checks the type
-        let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
+        let (ty, _) = self.get_ptr_vtable(vtable)?;
         let layout = self.layout_of(ty)?;
 
-        // More sanity checks
-        if cfg!(debug_assertions) {
-            let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
-            assert_eq!(size, layout.size);
-            // only ABI alignment is preserved
-            assert_eq!(align, layout.align.abi);
-        }
-
         let mplace = MPlaceTy {
             mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace },
             layout,
             align: layout.align.abi,
         };
-        Ok((instance, mplace))
+        Ok(mplace)
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 61d58232dc2..742339f2b0a 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -20,10 +20,10 @@ use super::{
 };
 
 // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
-impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M>
+impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>
 where
-    Tag: Provenance + Eq + Hash + 'static,
-    M: Machine<'mir, 'tcx, PointerTag = Tag>,
+    Prov: Provenance + Eq + Hash + 'static,
+    M: Machine<'mir, 'tcx, Provenance = Prov>,
 {
     //# Field access
 
@@ -35,9 +35,9 @@ where
     /// For indexing into arrays, use `mplace_index`.
     pub fn mplace_field(
         &self,
-        base: &MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::Provenance>,
         field: usize,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let offset = base.layout.fields.offset(field);
         let field_layout = base.layout.field(self, field);
 
@@ -72,9 +72,9 @@ where
     /// into the field of a local `ScalarPair`, we have to first allocate it.
     pub fn place_field(
         &mut self,
-        base: &PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::Provenance>,
         field: usize,
-    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
         // FIXME: We could try to be smarter and avoid allocation for fields that span the
         // entire place.
         let base = self.force_allocation(base)?;
@@ -83,9 +83,9 @@ where
 
     pub fn operand_field(
         &self,
-        base: &OpTy<'tcx, M::PointerTag>,
+        base: &OpTy<'tcx, M::Provenance>,
         field: usize,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         let base = match base.try_as_mplace() {
             Ok(ref mplace) => {
                 // We can reuse the mplace field computation logic for indirect operands.
@@ -139,9 +139,9 @@ where
 
     pub fn mplace_downcast(
         &self,
-        base: &MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::Provenance>,
         variant: VariantIdx,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         // Downcasts only change the layout.
         // (In particular, no check about whether this is even the active variant -- that's by design,
         // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.)
@@ -153,9 +153,9 @@ where
 
     pub fn place_downcast(
         &self,
-        base: &PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::Provenance>,
         variant: VariantIdx,
-    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
         // Downcast just changes the layout
         let mut base = base.clone();
         base.layout = base.layout.for_variant(self, variant);
@@ -164,9 +164,9 @@ where
 
     pub fn operand_downcast(
         &self,
-        base: &OpTy<'tcx, M::PointerTag>,
+        base: &OpTy<'tcx, M::Provenance>,
         variant: VariantIdx,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         // Downcast just changes the layout
         let mut base = base.clone();
         base.layout = base.layout.for_variant(self, variant);
@@ -178,9 +178,9 @@ where
     #[inline(always)]
     pub fn operand_index(
         &self,
-        base: &OpTy<'tcx, M::PointerTag>,
+        base: &OpTy<'tcx, M::Provenance>,
         index: u64,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         // Not using the layout method because we want to compute on u64
         match base.layout.fields {
             abi::FieldsShape::Array { stride, count: _ } => {
@@ -207,8 +207,8 @@ where
     // same by repeatedly calling `operand_index`.
     pub fn operand_array_fields<'a>(
         &self,
-        base: &'a OpTy<'tcx, Tag>,
-    ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, OpTy<'tcx, Tag>>> + 'a> {
+        base: &'a OpTy<'tcx, Prov>,
+    ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, OpTy<'tcx, Prov>>> + 'a> {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
         let abi::FieldsShape::Array { stride, .. } = base.layout.fields else {
             span_bug!(self.cur_span(), "operand_array_fields: expected an array layout");
@@ -222,17 +222,17 @@ where
     /// Index into an array.
     pub fn mplace_index(
         &self,
-        base: &MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::Provenance>,
         index: u64,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         Ok(self.operand_index(&base.into(), index)?.assert_mem_place())
     }
 
     pub fn place_index(
         &mut self,
-        base: &PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::Provenance>,
         index: u64,
-    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
         // There's not a lot we can do here, since we cannot have a place to a part of a local. If
         // we are accessing the only element of a 1-element array, it's still the entire local...
         // that doesn't seem worth it.
@@ -244,11 +244,11 @@ where
 
     fn operand_constant_index(
         &self,
-        base: &OpTy<'tcx, M::PointerTag>,
+        base: &OpTy<'tcx, M::Provenance>,
         offset: u64,
         min_length: u64,
         from_end: bool,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         let n = base.len(self)?;
         if n < min_length {
             // This can only be reached in ConstProp and non-rustc-MIR.
@@ -268,11 +268,11 @@ where
 
     fn place_constant_index(
         &mut self,
-        base: &PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::Provenance>,
         offset: u64,
         min_length: u64,
         from_end: bool,
-    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
         let base = self.force_allocation(base)?;
         Ok(self
             .operand_constant_index(&base.into(), offset, min_length, from_end)?
@@ -284,11 +284,11 @@ where
 
     fn operand_subslice(
         &self,
-        base: &OpTy<'tcx, M::PointerTag>,
+        base: &OpTy<'tcx, M::Provenance>,
         from: u64,
         to: u64,
         from_end: bool,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
         let actual_to = if from_end {
             if from.checked_add(to).map_or(true, |to| to > len) {
@@ -329,11 +329,11 @@ where
 
     pub fn place_subslice(
         &mut self,
-        base: &PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::Provenance>,
         from: u64,
         to: u64,
         from_end: bool,
-    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
         let base = self.force_allocation(base)?;
         Ok(self.operand_subslice(&base.into(), from, to, from_end)?.assert_mem_place().into())
     }
@@ -344,9 +344,9 @@ where
     #[instrument(skip(self), level = "trace")]
     pub fn place_projection(
         &mut self,
-        base: &PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::Provenance>,
         proj_elem: mir::PlaceElem<'tcx>,
-    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
         use rustc_middle::mir::ProjectionElem::*;
         Ok(match proj_elem {
             Field(field, _) => self.place_field(base, field.index())?,
@@ -368,9 +368,9 @@ where
     #[instrument(skip(self), level = "trace")]
     pub fn operand_projection(
         &self,
-        base: &OpTy<'tcx, M::PointerTag>,
+        base: &OpTy<'tcx, M::Provenance>,
         proj_elem: mir::PlaceElem<'tcx>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         use rustc_middle::mir::ProjectionElem::*;
         Ok(match proj_elem {
             Field(field, _) => self.operand_field(base, field.index())?,
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index d0c9b5319dd..6fef7b3b3cf 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -1,5 +1,4 @@
 use std::borrow::Cow;
-use std::convert::TryFrom;
 
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
 use rustc_middle::ty::Instance;
@@ -267,10 +266,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     fn pass_argument<'x, 'y>(
         &mut self,
         caller_args: &mut impl Iterator<
-            Item = (&'x OpTy<'tcx, M::PointerTag>, &'y ArgAbi<'tcx, Ty<'tcx>>),
+            Item = (&'x OpTy<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>),
         >,
         callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
-        callee_arg: &PlaceTy<'tcx, M::PointerTag>,
+        callee_arg: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx>
     where
         'tcx: 'x,
@@ -336,9 +335,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &mut self,
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
         (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
-        args: &[OpTy<'tcx, M::PointerTag>],
+        args: &[OpTy<'tcx, M::Provenance>],
         with_caller_location: bool,
-        destination: &PlaceTy<'tcx, M::PointerTag>,
+        destination: &PlaceTy<'tcx, M::Provenance>,
         target: Option<mir::BasicBlock>,
         mut unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
@@ -365,7 +364,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic.
                 M::call_intrinsic(self, instance, args, destination, target, unwind)
             }
-            ty::InstanceDef::VtableShim(..)
+            ty::InstanceDef::VTableShim(..)
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::ClosureOnceShim { .. }
             | ty::InstanceDef::FnPtrShim(..)
@@ -437,7 +436,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     // last incoming argument.  These two iterators do not have the same type,
                     // so to keep the code paths uniform we accept an allocation
                     // (for RustCall ABI only).
-                    let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> =
+                    let caller_args: Cow<'_, [OpTy<'tcx, M::Provenance>]> =
                         if caller_abi == Abi::RustCall && !args.is_empty() {
                             // Untuple
                             let (untuple_arg, args) = args.split_last().unwrap();
@@ -449,7 +448,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                                         (0..untuple_arg.layout.fields.count())
                                             .map(|i| self.operand_field(untuple_arg, i)),
                                     )
-                                    .collect::<InterpResult<'_, Vec<OpTy<'tcx, M::PointerTag>>>>(
+                                    .collect::<InterpResult<'_, Vec<OpTy<'tcx, M::Provenance>>>>(
                                     )?,
                             )
                         } else {
@@ -520,7 +519,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
             }
             // cannot use the shim here, because that will only result in infinite recursion
-            ty::InstanceDef::Virtual(_, idx) => {
+            ty::InstanceDef::Virtual(def_id, idx) => {
                 let mut args = args.to_vec();
                 // We have to implement all "object safe receivers". So we have to go search for a
                 // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
@@ -553,17 +552,52 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         }
                     }
                 };
-                // Find and consult vtable. The type now could be something like RcBox<dyn Trait>,
-                // i.e., it is still not necessarily `ty::Dynamic` (so we cannot use
-                // `place.vtable()`), but it should have a `dyn Trait` tail.
-                assert!(matches!(
-                    self.tcx
-                        .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env)
-                        .kind(),
-                    ty::Dynamic(..)
-                ));
-                let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?;
-                let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?;
+                // Obtain the underlying trait we are working on.
+                let receiver_tail = self
+                    .tcx
+                    .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
+                let ty::Dynamic(data, ..) = receiver_tail.kind() else {
+                    span_bug!(self.cur_span(), "dyanmic call on non-`dyn` type {}", receiver_tail)
+                };
+
+                // Get the required information from the vtable.
+                let vptr = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?;
+                let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
+                if dyn_trait != data.principal() {
+                    throw_ub_format!(
+                        "`dyn` call on a pointer whose vtable does not match its type"
+                    );
+                }
+
+                // Now determine the actual method to call. We can do that in two different ways and
+                // compare them to ensure everything fits.
+                let ty::VtblEntry::Method(fn_inst) = self.get_vtable_entries(vptr)?[idx] else {
+                    span_bug!(self.cur_span(), "dyn call index points at something that is not a method")
+                };
+                if cfg!(debug_assertions) {
+                    let tcx = *self.tcx;
+
+                    let trait_def_id = tcx.trait_of_item(def_id).unwrap();
+                    let virtual_trait_ref =
+                        ty::TraitRef::from_method(tcx, trait_def_id, instance.substs);
+                    assert_eq!(
+                        receiver_tail,
+                        virtual_trait_ref.self_ty(),
+                        "mismatch in underlying dyn trait computation within Miri and MIR building",
+                    );
+                    let existential_trait_ref =
+                        ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
+                    let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
+
+                    let concrete_method = Instance::resolve_for_vtable(
+                        tcx,
+                        self.param_env,
+                        def_id,
+                        instance.substs.rebase_onto(tcx, trait_def_id, concrete_trait_ref.substs),
+                    )
+                    .unwrap();
+                    assert_eq!(fn_inst, concrete_method);
+                }
 
                 // `*mut receiver_place.layout.ty` is almost the layout that we
                 // want for args[0]: We have to project to field 0 because we want
@@ -579,7 +613,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 trace!("Patched receiver operand to {:#?}", args[0]);
                 // recurse with concrete function
                 self.eval_fn_call(
-                    fn_val,
+                    FnVal::Instance(fn_inst),
                     (caller_abi, caller_fn_abi),
                     &args,
                     with_caller_location,
@@ -593,7 +627,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn drop_in_place(
         &mut self,
-        place: &PlaceTy<'tcx, M::PointerTag>,
+        place: &PlaceTy<'tcx, M::Provenance>,
         instance: ty::Instance<'tcx>,
         target: mir::BasicBlock,
         unwind: Option<mir::BasicBlock>,
@@ -606,8 +640,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         let (instance, place) = match place.layout.ty.kind() {
             ty::Dynamic(..) => {
-                // Dropping a trait object.
-                self.unpack_dyn_trait(&place)?
+                // Dropping a trait object. Need to find actual drop fn.
+                let place = self.unpack_dyn_trait(&place)?;
+                let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
+                (instance, place)
             }
             _ => (instance, place),
         };
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index 22c23df7b1a..b3a511d5a49 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -1,27 +1,24 @@
-use std::convert::TryFrom;
-
-use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic};
-use rustc_middle::ty::{
-    self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE,
-    COMMON_VTABLE_ENTRIES_SIZE,
-};
+use rustc_middle::mir::interpret::{InterpResult, Pointer};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_target::abi::{Align, Size};
 
 use super::util::ensure_monomorphic_enough;
-use super::{FnVal, InterpCx, Machine};
+use super::{InterpCx, Machine};
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
     /// objects.
     ///
-    /// The `trait_ref` encodes the erased self type. Hence, if we are
-    /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
-    /// `trait_ref` would map `T: Trait`.
-    pub fn get_vtable(
-        &mut self,
+    /// The `trait_ref` encodes the erased self type. Hence, if we are making an object `Foo<Trait>`
+    /// from a value of type `Foo<T>`, then `trait_ref` would map `T: Trait`. `None` here means that
+    /// this is an auto trait without any methods, so we only need the basic vtable (drop, size,
+    /// align).
+    pub fn get_vtable_ptr(
+        &self,
         ty: Ty<'tcx>,
         poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
-    ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
+    ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
         trace!("get_vtable(trait_ref={:?})", poly_trait_ref);
 
         let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref));
@@ -30,114 +27,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         ensure_monomorphic_enough(*self.tcx, ty)?;
         ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
 
-        let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref));
-
-        let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_allocation))?;
-
+        let vtable_symbolic_allocation = self.tcx.create_vtable_alloc(ty, poly_trait_ref);
+        let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_symbolic_allocation))?;
         Ok(vtable_ptr.into())
     }
 
-    /// Resolves the function at the specified slot in the provided
-    /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`)
-    /// corresponds to the first method declared in the trait of the provided vtable.
-    pub fn get_vtable_slot(
-        &self,
-        vtable: Pointer<Option<M::PointerTag>>,
-        idx: u64,
-    ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
-        let ptr_size = self.pointer_size();
-        let vtable_slot = vtable.offset(ptr_size * idx, self)?;
-        let vtable_slot = self
-            .get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
-            .expect("cannot be a ZST");
-        let fn_ptr = self.scalar_to_ptr(vtable_slot.read_pointer(Size::ZERO)?.check_init()?)?;
-        self.get_ptr_fn(fn_ptr)
-    }
-
-    /// Returns the drop fn instance as well as the actual dynamic type.
-    pub fn read_drop_type_from_vtable(
+    /// Returns a high-level representation of the entires of the given vtable.
+    pub fn get_vtable_entries(
         &self,
-        vtable: Pointer<Option<M::PointerTag>>,
-    ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> {
-        let pointer_size = self.pointer_size();
-        // We don't care about the pointee type; we just want a pointer.
-        let vtable = self
-            .get_ptr_alloc(
-                vtable,
-                pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
-                self.tcx.data_layout.pointer_align.abi,
-            )?
-            .expect("cannot be a ZST");
-        let drop_fn = vtable
-            .read_pointer(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap())?
-            .check_init()?;
-        // We *need* an instance here, no other kind of function value, to be able
-        // to determine the type.
-        let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn)?)?.as_instance()?;
-        trace!("Found drop fn: {:?}", drop_instance);
-        let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx);
-        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig);
-        // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
-        let args = fn_sig.inputs();
-        if args.len() != 1 {
-            throw_ub!(InvalidVtableDropFn(fn_sig));
-        }
-        let ty =
-            args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty;
-        Ok((drop_instance, ty))
+        vtable: Pointer<Option<M::Provenance>>,
+    ) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> {
+        let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?;
+        Ok(if let Some(poly_trait_ref) = poly_trait_ref {
+            let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
+            let trait_ref = self.tcx.erase_regions(trait_ref);
+            self.tcx.vtable_entries(trait_ref)
+        } else {
+            TyCtxt::COMMON_VTABLE_ENTRIES
+        })
     }
 
-    pub fn read_size_and_align_from_vtable(
+    pub fn get_vtable_size_and_align(
         &self,
-        vtable: Pointer<Option<M::PointerTag>>,
+        vtable: Pointer<Option<M::Provenance>>,
     ) -> InterpResult<'tcx, (Size, Align)> {
-        let pointer_size = self.pointer_size();
-        // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here),
-        // the size, and the align (which we read below).
-        let vtable = self
-            .get_ptr_alloc(
-                vtable,
-                pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
-                self.tcx.data_layout.pointer_align.abi,
-            )?
-            .expect("cannot be a ZST");
-        let size = vtable
-            .read_integer(alloc_range(
-                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(),
-                pointer_size,
-            ))?
-            .check_init()?;
-        let size = size.to_machine_usize(self)?;
-        let size = Size::from_bytes(size);
-        let align = vtable
-            .read_integer(alloc_range(
-                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(),
-                pointer_size,
-            ))?
-            .check_init()?;
-        let align = align.to_machine_usize(self)?;
-        let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
-
-        if size > self.max_size_of_val() {
-            throw_ub!(InvalidVtableSize);
-        }
-        Ok((size, align))
-    }
-
-    pub fn read_new_vtable_after_trait_upcasting_from_vtable(
-        &self,
-        vtable: Pointer<Option<M::PointerTag>>,
-        idx: u64,
-    ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
-        let pointer_size = self.pointer_size();
-
-        let vtable_slot = vtable.offset(pointer_size * idx, self)?;
-        let new_vtable = self
-            .get_ptr_alloc(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)?
-            .expect("cannot be a ZST");
-
-        let new_vtable = self.scalar_to_ptr(new_vtable.read_pointer(Size::ZERO)?.check_init()?)?;
-
-        Ok(new_vtable)
+        let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?;
+        let layout = self.layout_of(ty)?;
+        assert!(!layout.is_unsized(), "there are no vtables for unsized types");
+        Ok((layout.size, layout.align.abi))
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 2e5492ecf56..f2e104da04a 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -206,7 +206,7 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
     /// starts must not be changed!  `visit_fields` and `visit_array` rely on
     /// this stack discipline.
     path: Vec<PathElem>,
-    ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
+    ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>,
     /// `None` indicates this is not validating for CTFE (but for runtime).
     ctfe_mode: Option<CtfeValidationMode>,
     ecx: &'rt InterpCx<'mir, 'tcx, M>,
@@ -306,57 +306,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
 
     fn check_wide_ptr_meta(
         &mut self,
-        meta: MemPlaceMeta<M::PointerTag>,
+        meta: MemPlaceMeta<M::Provenance>,
         pointee: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx> {
         let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
         match tail.kind() {
             ty::Dynamic(..) => {
                 let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta())?;
-                // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
-                try_validation!(
-                    self.ecx.check_ptr_access_align(
-                        vtable,
-                        3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align
-                        self.ecx.tcx.data_layout.pointer_align.abi,
-                        CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
-                    ),
-                    self.path,
-                    err_ub!(DanglingIntPointer(..)) |
-                    err_ub!(PointerUseAfterFree(..)) =>
-                        { "dangling vtable pointer in wide pointer" },
-                    err_ub!(AlignmentCheckFailed { .. }) =>
-                        { "unaligned vtable pointer in wide pointer" },
-                    err_ub!(PointerOutOfBounds { .. }) =>
-                        { "too small vtable" },
-                );
-                try_validation!(
-                    self.ecx.read_drop_type_from_vtable(vtable),
+                // Make sure it is a genuine vtable pointer.
+                let (_ty, _trait) = try_validation!(
+                    self.ecx.get_ptr_vtable(vtable),
                     self.path,
                     err_ub!(DanglingIntPointer(..)) |
-                    err_ub!(InvalidFunctionPointer(..)) =>
-                        { "invalid drop function pointer in vtable (not pointing to a function)" },
-                    err_ub!(InvalidVtableDropFn(..)) =>
-                        { "invalid drop function pointer in vtable (function has incompatible signature)" },
-                    // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123.
-                    // (We assume there are no other MachineStop errors possible here.)
-                    InterpError::MachineStop(_) =>
-                        { "vtable pointer does not have permission to read drop function pointer" },
-                );
-                try_validation!(
-                    self.ecx.read_size_and_align_from_vtable(vtable),
-                    self.path,
-                    err_ub!(InvalidVtableSize) =>
-                        { "invalid vtable: size is bigger than largest supported object" },
-                    err_ub!(InvalidVtableAlignment(msg)) =>
-                        { "invalid vtable: alignment {}", msg },
-                    err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" },
-                    // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123.
-                    // (We assume there are no other MachineStop errors possible here.)
-                    InterpError::MachineStop(_) =>
-                        { "vtable pointer does not have permission to read size and alignment" },
+                    err_ub!(InvalidVTablePointer(..)) =>
+                        { "{vtable}" } expected { "a vtable pointer" },
                 );
-                // FIXME: More checks for the vtable.
+                // FIXME: check if the type/trait match what ty::Dynamic says?
             }
             ty::Slice(..) | ty::Str => {
                 let _len = try_validation!(
@@ -380,7 +345,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
     /// Check a reference or `Box`.
     fn check_safe_pointer(
         &mut self,
-        value: &OpTy<'tcx, M::PointerTag>,
+        value: &OpTy<'tcx, M::Provenance>,
         kind: &str,
     ) -> InterpResult<'tcx> {
         let value = try_validation!(
@@ -445,9 +410,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         if let Some(ref mut ref_tracking) = self.ref_tracking {
             // Proceed recursively even for ZST, no reason to skip them!
             // `!` is a ZST and we want to validate it.
-            if let Ok((alloc_id, _offset, _tag)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
+            if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
                 // Special handling for pointers to statics (irrespective of their type).
-                let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id);
+                let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id);
                 if let Some(GlobalAlloc::Static(did)) = alloc_kind {
                     assert!(!self.ecx.tcx.is_thread_local_static(did));
                     assert!(self.ecx.tcx.is_static(did));
@@ -491,8 +456,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
 
     fn read_scalar(
         &self,
-        op: &OpTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ScalarMaybeUninit<M::Provenance>> {
         Ok(try_validation!(
             self.ecx.read_scalar(op),
             self.path,
@@ -502,8 +467,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
 
     fn read_immediate_forced(
         &self,
-        op: &OpTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
         Ok(*try_validation!(
             self.ecx.read_immediate_raw(op, /*force*/ true),
             self.path,
@@ -515,7 +480,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
     /// at that type.  Return `true` if the type is indeed primitive.
     fn try_visit_primitive(
         &mut self,
-        value: &OpTy<'tcx, M::PointerTag>,
+        value: &OpTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, bool> {
         // Go over all the primitive types
         let ty = value.layout.ty;
@@ -607,11 +572,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                     let _fn = try_validation!(
                         self.ecx.get_ptr_fn(ptr),
                         self.path,
-                        err_ub!(DanglingIntPointer(0, _)) =>
-                            { "a null function pointer" },
                         err_ub!(DanglingIntPointer(..)) |
                         err_ub!(InvalidFunctionPointer(..)) =>
-                            { "{:x}", value } expected { "a function pointer" },
+                            { "{ptr}" } expected { "a function pointer" },
                     );
                     // FIXME: Check if the signature matches
                 } else {
@@ -652,7 +615,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
 
     fn visit_scalar(
         &mut self,
-        scalar: ScalarMaybeUninit<M::PointerTag>,
+        scalar: ScalarMaybeUninit<M::Provenance>,
         scalar_layout: ScalarAbi,
     ) -> InterpResult<'tcx> {
         // We check `is_full_range` in a slightly complicated way because *if* we are checking
@@ -735,7 +698,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
 impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     for ValidityVisitor<'rt, 'mir, 'tcx, M>
 {
-    type V = OpTy<'tcx, M::PointerTag>;
+    type V = OpTy<'tcx, M::Provenance>;
 
     #[inline(always)]
     fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> {
@@ -744,7 +707,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
 
     fn read_discriminant(
         &mut self,
-        op: &OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, VariantIdx> {
         self.with_elem(PathElem::EnumTag, move |this| {
             Ok(try_validation!(
@@ -764,9 +727,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     #[inline]
     fn visit_field(
         &mut self,
-        old_op: &OpTy<'tcx, M::PointerTag>,
+        old_op: &OpTy<'tcx, M::Provenance>,
         field: usize,
-        new_op: &OpTy<'tcx, M::PointerTag>,
+        new_op: &OpTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         let elem = self.aggregate_field_path_elem(old_op.layout, field);
         self.with_elem(elem, move |this| this.visit_value(new_op))
@@ -775,9 +738,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     #[inline]
     fn visit_variant(
         &mut self,
-        old_op: &OpTy<'tcx, M::PointerTag>,
+        old_op: &OpTy<'tcx, M::Provenance>,
         variant_id: VariantIdx,
-        new_op: &OpTy<'tcx, M::PointerTag>,
+        new_op: &OpTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         let name = match old_op.layout.ty.kind() {
             ty::Adt(adt, _) => PathElem::Variant(adt.variant(variant_id).name),
@@ -791,7 +754,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     #[inline(always)]
     fn visit_union(
         &mut self,
-        op: &OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::Provenance>,
         _fields: NonZeroUsize,
     ) -> InterpResult<'tcx> {
         // Special check preventing `UnsafeCell` inside unions in the inner part of constants.
@@ -804,13 +767,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     }
 
     #[inline]
-    fn visit_box(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+    fn visit_box(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
         self.check_safe_pointer(op, "box")?;
         Ok(())
     }
 
     #[inline]
-    fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+    fn visit_value(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
         trace!("visit_value: {:?}, {:?}", *op, op.layout);
 
         // Check primitive types -- the leaves of our recursive descent.
@@ -881,7 +844,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
 
     fn visit_aggregate(
         &mut self,
-        op: &OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::Provenance>,
         fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
     ) -> InterpResult<'tcx> {
         match op.layout.ty.kind() {
@@ -992,9 +955,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     fn validate_operand_internal(
         &self,
-        op: &OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::Provenance>,
         path: Vec<PathElem>,
-        ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
+        ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>,
         ctfe_mode: Option<CtfeValidationMode>,
     ) -> InterpResult<'tcx> {
         trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty);
@@ -1031,9 +994,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn const_validate_operand(
         &self,
-        op: &OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::Provenance>,
         path: Vec<PathElem>,
-        ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
+        ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>,
         ctfe_mode: CtfeValidationMode,
     ) -> InterpResult<'tcx> {
         self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode))
@@ -1043,7 +1006,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// `op` is assumed to cover valid memory if it is an indirect operand.
     /// It will error if the bits at the destination do not match the ones described by the layout.
     #[inline(always)]
-    pub fn validate_operand(&self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+    pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
         self.validate_operand_internal(op, vec![], None, None)
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 5956b7e4cb9..aee1f93b1a3 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -21,20 +21,20 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized {
     fn to_op_for_read(
         &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>;
 
     /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections.
     fn to_op_for_proj(
         &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         self.to_op_for_read(ecx)
     }
 
     /// Creates this from an `OpTy`.
     ///
     /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`.
-    fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self;
+    fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self;
 
     /// Projects to the given enum variant.
     fn project_downcast(
@@ -62,18 +62,18 @@ pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized {
     fn to_op_for_read(
         &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>;
 
     /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections.
     fn to_op_for_proj(
         &self,
         ecx: &mut InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>>;
 
     /// Creates this from an `OpTy`.
     ///
     /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`.
-    fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self;
+    fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self;
 
     /// Projects to the given enum variant.
     fn project_downcast(
@@ -95,7 +95,7 @@ pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized {
 // So we have some copy-paste here. (We could have a macro but since we only have 2 types with this
 // double-impl, that would barely make the code shorter, if at all.)
 
-impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::PointerTag> {
+impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::Provenance> {
     #[inline(always)]
     fn layout(&self) -> TyAndLayout<'tcx> {
         self.layout
@@ -105,12 +105,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc
     fn to_op_for_read(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         Ok(self.clone())
     }
 
     #[inline(always)]
-    fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self {
+    fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self {
         op.clone()
     }
 
@@ -134,7 +134,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc
 }
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
-    for OpTy<'tcx, M::PointerTag>
+    for OpTy<'tcx, M::Provenance>
 {
     #[inline(always)]
     fn layout(&self) -> TyAndLayout<'tcx> {
@@ -145,7 +145,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
     fn to_op_for_read(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         Ok(self.clone())
     }
 
@@ -153,12 +153,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
     fn to_op_for_proj(
         &self,
         _ecx: &mut InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         Ok(self.clone())
     }
 
     #[inline(always)]
-    fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self {
+    fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self {
         op.clone()
     }
 
@@ -182,7 +182,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
 }
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M>
-    for MPlaceTy<'tcx, M::PointerTag>
+    for MPlaceTy<'tcx, M::Provenance>
 {
     #[inline(always)]
     fn layout(&self) -> TyAndLayout<'tcx> {
@@ -193,12 +193,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M>
     fn to_op_for_read(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         Ok(self.into())
     }
 
     #[inline(always)]
-    fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self {
+    fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self {
         // assert is justified because our `to_op_for_read` only ever produces `Indirect` operands.
         op.assert_mem_place()
     }
@@ -223,7 +223,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M>
 }
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
-    for MPlaceTy<'tcx, M::PointerTag>
+    for MPlaceTy<'tcx, M::Provenance>
 {
     #[inline(always)]
     fn layout(&self) -> TyAndLayout<'tcx> {
@@ -234,7 +234,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
     fn to_op_for_read(
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         Ok(self.into())
     }
 
@@ -242,12 +242,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
     fn to_op_for_proj(
         &self,
         _ecx: &mut InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         Ok(self.into())
     }
 
     #[inline(always)]
-    fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self {
+    fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self {
         // assert is justified because our `to_op_for_proj` only ever produces `Indirect` operands.
         op.assert_mem_place()
     }
@@ -272,7 +272,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
 }
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
-    for PlaceTy<'tcx, M::PointerTag>
+    for PlaceTy<'tcx, M::Provenance>
 {
     #[inline(always)]
     fn layout(&self) -> TyAndLayout<'tcx> {
@@ -283,7 +283,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
     fn to_op_for_read(
         &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         // We `force_allocation` here so that `from_op` below can work.
         ecx.place_to_op(self)
     }
@@ -292,13 +292,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
     fn to_op_for_proj(
         &self,
         ecx: &mut InterpCx<'mir, 'tcx, M>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         // We `force_allocation` here so that `from_op` below can work.
         Ok(ecx.force_allocation(self)?.into())
     }
 
     #[inline(always)]
-    fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self {
+    fn from_op(op: &OpTy<'tcx, M::Provenance>) -> Self {
         // assert is justified because our `to_op` only ever produces `Indirect` operands.
         op.assert_mem_place().into()
     }
@@ -336,7 +336,7 @@ macro_rules! make_value_visitor {
             #[inline(always)]
             fn read_discriminant(
                 &mut self,
-                op: &OpTy<'tcx, M::PointerTag>,
+                op: &OpTy<'tcx, M::Provenance>,
             ) -> InterpResult<'tcx, VariantIdx> {
                 Ok(self.ecx().read_discriminant(op)?.1)
             }
@@ -425,7 +425,7 @@ macro_rules! make_value_visitor {
                         // unsized values are never immediate, so we can assert_mem_place
                         let op = v.to_op_for_read(self.ecx())?;
                         let dest = op.assert_mem_place();
-                        let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.1;
+                        let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?;
                         trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout);
                         // recurse with the inner type
                         return self.visit_field(&v, 0, &$value_trait::from_op(&inner_mplace.into()));
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 2a801d0e702..5c641f54f68 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@ doctest = false
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 ena = "0.14"
-indexmap = { version = "1.8.2" }
+indexmap = { version = "1.9.1" }
 tracing = "0.1"
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 0a2d2b40709..265f45b72d1 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -61,12 +61,10 @@ pub mod sip128;
 pub mod small_c_str;
 pub mod small_str;
 pub mod snapshot_map;
-pub mod stable_map;
 pub mod svh;
 pub use ena::snapshot_vec;
 pub mod memmap;
 pub mod sorted_map;
-pub mod stable_set;
 #[macro_use]
 pub mod stable_hasher;
 mod atomic_ref;
diff --git a/compiler/rustc_data_structures/src/stable_map.rs b/compiler/rustc_data_structures/src/stable_map.rs
deleted file mode 100644
index 670452d0d8c..00000000000
--- a/compiler/rustc_data_structures/src/stable_map.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-pub use rustc_hash::FxHashMap;
-use std::borrow::Borrow;
-use std::collections::hash_map::Entry;
-use std::fmt;
-use std::hash::Hash;
-
-/// A deterministic wrapper around FxHashMap that does not provide iteration support.
-///
-/// It supports insert, remove, get and get_mut functions from FxHashMap.
-/// It also allows to convert hashmap to a sorted vector with the method `into_sorted_vector()`.
-#[derive(Clone)]
-pub struct StableMap<K, V> {
-    base: FxHashMap<K, V>,
-}
-
-impl<K, V> Default for StableMap<K, V>
-where
-    K: Eq + Hash,
-{
-    fn default() -> StableMap<K, V> {
-        StableMap::new()
-    }
-}
-
-impl<K, V> fmt::Debug for StableMap<K, V>
-where
-    K: Eq + Hash + fmt::Debug,
-    V: fmt::Debug,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self.base)
-    }
-}
-
-impl<K, V> PartialEq for StableMap<K, V>
-where
-    K: Eq + Hash,
-    V: PartialEq,
-{
-    fn eq(&self, other: &StableMap<K, V>) -> bool {
-        self.base == other.base
-    }
-}
-
-impl<K, V> Eq for StableMap<K, V>
-where
-    K: Eq + Hash,
-    V: Eq,
-{
-}
-
-impl<K, V> StableMap<K, V>
-where
-    K: Eq + Hash,
-{
-    pub fn new() -> StableMap<K, V> {
-        StableMap { base: FxHashMap::default() }
-    }
-
-    pub fn into_sorted_vector(self) -> Vec<(K, V)>
-    where
-        K: Ord + Copy,
-    {
-        let mut vector = self.base.into_iter().collect::<Vec<_>>();
-        vector.sort_unstable_by_key(|pair| pair.0);
-        vector
-    }
-
-    pub fn entry(&mut self, k: K) -> Entry<'_, K, V> {
-        self.base.entry(k)
-    }
-
-    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
-    where
-        K: Borrow<Q>,
-        Q: Hash + Eq,
-    {
-        self.base.get(k)
-    }
-
-    pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
-    where
-        K: Borrow<Q>,
-        Q: Hash + Eq,
-    {
-        self.base.get_mut(k)
-    }
-
-    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
-        self.base.insert(k, v)
-    }
-
-    pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
-    where
-        K: Borrow<Q>,
-        Q: Hash + Eq,
-    {
-        self.base.remove(k)
-    }
-}
diff --git a/compiler/rustc_data_structures/src/stable_set.rs b/compiler/rustc_data_structures/src/stable_set.rs
deleted file mode 100644
index c7ca74f5fbd..00000000000
--- a/compiler/rustc_data_structures/src/stable_set.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-pub use rustc_hash::FxHashSet;
-use std::borrow::Borrow;
-use std::fmt;
-use std::hash::Hash;
-
-/// A deterministic wrapper around FxHashSet that does not provide iteration support.
-///
-/// It supports insert, remove, get functions from FxHashSet.
-/// It also allows to convert hashset to a sorted vector with the method `into_sorted_vector()`.
-#[derive(Clone)]
-pub struct StableSet<T> {
-    base: FxHashSet<T>,
-}
-
-impl<T> Default for StableSet<T>
-where
-    T: Eq + Hash,
-{
-    fn default() -> StableSet<T> {
-        StableSet::new()
-    }
-}
-
-impl<T> fmt::Debug for StableSet<T>
-where
-    T: Eq + Hash + fmt::Debug,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self.base)
-    }
-}
-
-impl<T> PartialEq<StableSet<T>> for StableSet<T>
-where
-    T: Eq + Hash,
-{
-    fn eq(&self, other: &StableSet<T>) -> bool {
-        self.base == other.base
-    }
-}
-
-impl<T> Eq for StableSet<T> where T: Eq + Hash {}
-
-impl<T: Hash + Eq> StableSet<T> {
-    pub fn new() -> StableSet<T> {
-        StableSet { base: FxHashSet::default() }
-    }
-
-    pub fn into_sorted_vector(self) -> Vec<T>
-    where
-        T: Ord,
-    {
-        let mut vector = self.base.into_iter().collect::<Vec<_>>();
-        vector.sort_unstable();
-        vector
-    }
-
-    pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T>
-    where
-        T: Borrow<Q>,
-        Q: Hash + Eq,
-    {
-        self.base.get(value)
-    }
-
-    pub fn insert(&mut self, value: T) -> bool {
-        self.base.insert(value)
-    }
-
-    pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
-    where
-        T: Borrow<Q>,
-        Q: Hash + Eq,
-    {
-        self.base.remove(value)
-    }
-}
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 97766b8368a..854625579ee 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -559,7 +559,7 @@ E0790: include_str!("./error_codes/E0790.md"),
 //  E0273, // on_unimplemented #1
 //  E0274, // on_unimplemented #2
 //  E0278, // requirement is not satisfied
-    E0279, // requirement is not satisfied
+//  E0279,
     E0280, // requirement is not satisfied
 //  E0285, // overflow evaluation builtin bounds
 //  E0296, // replaced with a generic attribute input check
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 6b961eaeb42..2ac5c1960cd 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -299,7 +299,7 @@ impl DiagnosticMessage {
     /// - If `self` is non-translatable then return `self`'s message.
     pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
         let attr = match sub {
-            SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s.clone()),
+            SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
             SubdiagnosticMessage::FluentIdentifier(id) => {
                 return DiagnosticMessage::FluentIdentifier(id, None);
             }
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 7d7f3e18335..2a4f609a2d8 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -3,7 +3,7 @@ use crate::{
     CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan,
     SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
 };
-use rustc_data_structures::stable_map::FxHashMap;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_error_messages::FluentValue;
 use rustc_hir as hir;
 use rustc_lint_defs::{Applicability, LintExpectationId};
@@ -390,18 +390,17 @@ impl Diagnostic {
         expected: DiagnosticStyledString,
         found: DiagnosticStyledString,
     ) -> &mut Self {
-        let mut msg: Vec<_> =
-            vec![("required when trying to coerce from type `".to_string(), Style::NoStyle)];
+        let mut msg: Vec<_> = vec![("required when trying to coerce from type `", Style::NoStyle)];
         msg.extend(expected.0.iter().map(|x| match *x {
-            StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
-            StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+            StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle),
+            StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight),
         }));
-        msg.push(("` to type '".to_string(), Style::NoStyle));
+        msg.push(("` to type '", Style::NoStyle));
         msg.extend(found.0.iter().map(|x| match *x {
-            StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
-            StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+            StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle),
+            StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight),
         }));
-        msg.push(("`".to_string(), Style::NoStyle));
+        msg.push(("`", Style::NoStyle));
 
         // For now, just attach these as notes
         self.highlighted_note(msg);
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index e1f19064d52..6e093811fcf 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -8,7 +8,7 @@ use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, Attribute, HasAttrs, Item, NodeId, PatKind};
 use rustc_attr::{self as attr, Deprecation, Stability};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::{self, Lrc};
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult};
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
@@ -985,7 +985,7 @@ pub struct ExtCtxt<'a> {
     /// Error recovery mode entered when expansion is stuck
     /// (or during eager expansion, but that's a hack).
     pub force_mode: bool,
-    pub expansions: FxHashMap<Span, Vec<String>>,
+    pub expansions: FxIndexMap<Span, Vec<String>>,
     /// Used for running pre-expansion lints on freshly loaded modules.
     pub(super) lint_store: LintStoreExpandDyn<'a>,
     /// Used for storing lints generated during expansion, like `NAMED_ARGUMENTS_USED_POSITIONALLY`
@@ -1020,7 +1020,7 @@ impl<'a> ExtCtxt<'a> {
                 is_trailing_mac: false,
             },
             force_mode: false,
-            expansions: FxHashMap::default(),
+            expansions: FxIndexMap::default(),
             expanded_inert_attrs: MarkedAttrs::new(),
             buffered_early_lint: vec![],
         }
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 03b75d809a0..20d01b6dc26 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,4 +1,3 @@
-#![allow(rustc::potential_query_instability)]
 #![feature(array_windows)]
 #![feature(associated_type_bounds)]
 #![feature(associated_type_defaults)]
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 3e9ddd6aec0..3d44c408d8f 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -13,7 +13,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream};
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_feature::Features;
 use rustc_lint_defs::builtin::{
@@ -198,7 +198,7 @@ fn macro_rules_dummy_expander<'cx>(
     DummyResult::any(span)
 }
 
-fn trace_macros_note(cx_expansions: &mut FxHashMap<Span, Vec<String>>, sp: Span, message: String) {
+fn trace_macros_note(cx_expansions: &mut FxIndexMap<Span, Vec<String>>, sp: Span, message: String) {
     let sp = sp.macro_backtrace().last().map_or(sp, |trace| trace.call_site);
     cx_expansions.entry(sp).or_default().push(message);
 }
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index fdd8dc93fc1..3037855ae28 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -512,7 +512,18 @@ fn out_of_bounds_err<'a>(
     span: Span,
     ty: &str,
 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-    cx.struct_span_err(span, &format!("{ty} depth must be less than {max}"))
+    let msg = if max == 0 {
+        format!(
+            "meta-variable expression `{ty}` with depth parameter \
+             must be called inside of a macro repetition"
+        )
+    } else {
+        format!(
+            "depth parameter on meta-variable expression `{ty}` \
+             must be less than {max}"
+        )
+    };
+    cx.struct_span_err(span, &msg)
 }
 
 fn transcribe_metavar_expr<'a>(
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 48a41c8bd24..18ffc227fed 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -954,6 +954,16 @@ pub struct Block<'hir> {
     pub targeted_by_break: bool,
 }
 
+impl<'hir> Block<'hir> {
+    pub fn innermost_block(&self) -> &Block<'hir> {
+        let mut block = self;
+        while let Some(Expr { kind: ExprKind::Block(inner_block, _), .. }) = block.expr {
+            block = inner_block;
+        }
+        block
+    }
+}
+
 #[derive(Debug, HashStable_Generic)]
 pub struct Pat<'hir> {
     #[stable_hasher(ignore)]
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index b0bfac8e1f5..13b3e954e1f 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -11,7 +11,7 @@ use crate::def_id::DefId;
 use crate::{MethodKind, Target};
 
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable_Generic;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -134,8 +134,8 @@ macro_rules! language_item_table {
         }
 
         /// A mapping from the name of the lang item to its order and the form it must be of.
-        pub static ITEM_REFS: LazyLock<FxHashMap<Symbol, (usize, Target)>> = LazyLock::new(|| {
-            let mut item_refs = FxHashMap::default();
+        pub static ITEM_REFS: LazyLock<FxIndexMap<Symbol, (usize, Target)>> = LazyLock::new(|| {
+            let mut item_refs = FxIndexMap::default();
             $( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )*
             item_refs
         });
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index b30076100bb..93112199b60 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -1,7 +1,7 @@
 use crate::def::{CtorOf, DefKind, Res};
 use crate::def_id::DefId;
 use crate::hir::{self, HirId, PatKind};
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs
index dad22725511..b6a85c0472e 100644
--- a/compiler/rustc_hir/src/weak_lang_items.rs
+++ b/compiler/rustc_hir/src/weak_lang_items.rs
@@ -4,7 +4,7 @@ use crate::def_id::DefId;
 use crate::{lang_items, LangItem, LanguageItems};
 
 use rustc_ast as ast;
-use rustc_data_structures::stable_map::StableMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_span::symbol::{sym, Symbol};
 
 use std::sync::LazyLock;
@@ -12,8 +12,8 @@ use std::sync::LazyLock;
 macro_rules! weak_lang_items {
     ($($name:ident, $item:ident, $sym:ident;)*) => (
 
-pub static WEAK_ITEMS_REFS: LazyLock<StableMap<Symbol, LangItem>> = LazyLock::new(|| {
-    let mut map = StableMap::default();
+pub static WEAK_ITEMS_REFS: LazyLock<FxIndexMap<Symbol, LangItem>> = LazyLock::new(|| {
+    let mut map = FxIndexMap::default();
     $(map.insert(sym::$name, LangItem::$item);)*
     map
 });
diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs
index 00aefac645f..89d419bc8e9 100644
--- a/compiler/rustc_incremental/src/assert_module_sources.rs
+++ b/compiler/rustc_incremental/src/assert_module_sources.rs
@@ -23,7 +23,7 @@
 //! was re-used.
 
 use rustc_ast as ast;
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::mir::mono::CodegenUnitNameBuilder;
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs
index 1b184eca964..2f1853c441e 100644
--- a/compiler/rustc_incremental/src/persist/work_product.rs
+++ b/compiler/rustc_incremental/src/persist/work_product.rs
@@ -3,7 +3,7 @@
 //! [work products]: WorkProduct
 
 use crate::persist::fs::*;
-use rustc_data_structures::stable_map::FxHashMap;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_fs_util::link_or_copy;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_session::Session;
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 1a55519d7b1..30ff364210d 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -234,7 +234,9 @@ impl<I: Idx, T> IndexVec<I, T> {
         self.raw.get_mut(index.index())
     }
 
-    /// Returns mutable references to two distinct elements, a and b. Panics if a == b.
+    /// Returns mutable references to two distinct elements, `a` and `b`.
+    ///
+    /// Panics if `a == b`.
     #[inline]
     pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) {
         let (ai, bi) = (a.index(), b.index());
@@ -249,7 +251,9 @@ impl<I: Idx, T> IndexVec<I, T> {
         }
     }
 
-    /// Returns mutable references to three distinct elements or panics otherwise.
+    /// Returns mutable references to three distinct elements.
+    ///
+    /// Panics if the elements are not distinct.
     #[inline]
     pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) {
         let (ai, bi, ci) = (a.index(), b.index(), c.index());
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index ce2698ef44c..130214a653f 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -65,6 +65,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         Self {
             tcx: self.tcx,
             defining_use_anchor: self.defining_use_anchor,
+            considering_regions: self.considering_regions,
             in_progress_typeck_results: self.in_progress_typeck_results,
             inner: self.inner.clone(),
             skip_leak_check: self.skip_leak_check.clone(),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index d7505717bf3..4e87ec86658 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -316,37 +316,6 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
     err
 }
 
-/// Structurally compares two types, modulo any inference variables.
-///
-/// Returns `true` if two types are equal, or if one type is an inference variable compatible
-/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or
-/// FloatVar inference type are compatible with themselves or their concrete types (Int and
-/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
-pub fn same_type_modulo_infer<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
-    match (&a.kind(), &b.kind()) {
-        (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
-            if did_a != did_b {
-                return false;
-            }
-
-            substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type_modulo_infer(a, b))
-        }
-        (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_)))
-        | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_)))
-        | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
-        | (
-            &ty::Infer(ty::InferTy::FloatVar(_)),
-            &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
-        )
-        | (&ty::Infer(ty::InferTy::TyVar(_)), _)
-        | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
-        (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => {
-            mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b)
-        }
-        _ => a == b,
-    }
-}
-
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn report_region_errors(
         &self,
@@ -645,13 +614,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 err.span_label(span, "expected due to this");
             }
             ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                semi_span,
+                arm_block_id,
+                arm_span,
+                arm_ty,
+                prior_arm_block_id,
+                prior_arm_span,
+                prior_arm_ty,
                 source,
                 ref prior_arms,
-                last_ty,
                 scrut_hir_id,
                 opt_suggest_box_span,
-                arm_span,
                 scrut_span,
                 ..
             }) => match source {
@@ -682,10 +654,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     }
                 }
                 _ => {
-                    // `last_ty` can be `!`, `expected` will have better info when present.
+                    // `prior_arm_ty` can be `!`, `expected` will have better info when present.
                     let t = self.resolve_vars_if_possible(match exp_found {
                         Some(ty::error::ExpectedFound { expected, .. }) => expected,
-                        _ => last_ty,
+                        _ => prior_arm_ty,
                     });
                     let source_map = self.tcx.sess.source_map();
                     let mut any_multiline_arm = source_map.is_multiline(arm_span);
@@ -710,37 +682,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     };
                     let msg = "`match` arms have incompatible types";
                     err.span_label(outer_error_span, msg);
-                    if let Some((sp, boxed)) = semi_span {
-                        if let (StatementAsExpression::NeedsBoxing, [.., prior_arm]) =
-                            (boxed, &prior_arms[..])
-                        {
-                            err.multipart_suggestion(
-                                "consider removing this semicolon and boxing the expressions",
-                                vec![
-                                    (prior_arm.shrink_to_lo(), "Box::new(".to_string()),
-                                    (prior_arm.shrink_to_hi(), ")".to_string()),
-                                    (arm_span.shrink_to_lo(), "Box::new(".to_string()),
-                                    (arm_span.shrink_to_hi(), ")".to_string()),
-                                    (sp, String::new()),
-                                ],
-                                Applicability::HasPlaceholders,
-                            );
-                        } else if matches!(boxed, StatementAsExpression::NeedsBoxing) {
-                            err.span_suggestion_short(
-                                sp,
-                                "consider removing this semicolon and boxing the expressions",
-                                "",
-                                Applicability::MachineApplicable,
-                            );
-                        } else {
-                            err.span_suggestion_short(
-                                sp,
-                                "consider removing this semicolon",
-                                "",
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    }
+                    self.suggest_remove_semi_or_return_binding(
+                        err,
+                        prior_arm_block_id,
+                        prior_arm_ty,
+                        prior_arm_span,
+                        arm_block_id,
+                        arm_ty,
+                        arm_span,
+                    );
                     if let Some(ret_sp) = opt_suggest_box_span {
                         // Get return type span and point to it.
                         self.suggest_boxing_for_return_impl_trait(
@@ -752,43 +702,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 }
             },
             ObligationCauseCode::IfExpression(box IfExpressionCause {
-                then,
-                else_sp,
-                outer,
-                semicolon,
+                then_id,
+                else_id,
+                then_ty,
+                else_ty,
+                outer_span,
                 opt_suggest_box_span,
             }) => {
-                err.span_label(then, "expected because of this");
-                if let Some(sp) = outer {
+                let then_span = self.find_block_span_from_hir_id(then_id);
+                let else_span = self.find_block_span_from_hir_id(then_id);
+                err.span_label(then_span, "expected because of this");
+                if let Some(sp) = outer_span {
                     err.span_label(sp, "`if` and `else` have incompatible types");
                 }
-                if let Some((sp, boxed)) = semicolon {
-                    if matches!(boxed, StatementAsExpression::NeedsBoxing) {
-                        err.multipart_suggestion(
-                            "consider removing this semicolon and boxing the expression",
-                            vec![
-                                (then.shrink_to_lo(), "Box::new(".to_string()),
-                                (then.shrink_to_hi(), ")".to_string()),
-                                (else_sp.shrink_to_lo(), "Box::new(".to_string()),
-                                (else_sp.shrink_to_hi(), ")".to_string()),
-                                (sp, String::new()),
-                            ],
-                            Applicability::MachineApplicable,
-                        );
-                    } else {
-                        err.span_suggestion_short(
-                            sp,
-                            "consider removing this semicolon",
-                            "",
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                }
+                self.suggest_remove_semi_or_return_binding(
+                    err,
+                    Some(then_id),
+                    then_ty,
+                    then_span,
+                    Some(else_id),
+                    else_ty,
+                    else_span,
+                );
                 if let Some(ret_sp) = opt_suggest_box_span {
                     self.suggest_boxing_for_return_impl_trait(
                         err,
                         ret_sp,
-                        [then, else_sp].into_iter(),
+                        [then_span, else_span].into_iter(),
                     );
                 }
             }
@@ -808,6 +748,56 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
+    fn suggest_remove_semi_or_return_binding(
+        &self,
+        err: &mut Diagnostic,
+        first_id: Option<hir::HirId>,
+        first_ty: Ty<'tcx>,
+        first_span: Span,
+        second_id: Option<hir::HirId>,
+        second_ty: Ty<'tcx>,
+        second_span: Span,
+    ) {
+        let remove_semicolon =
+            [(first_id, second_ty), (second_id, first_ty)].into_iter().find_map(|(id, ty)| {
+                let hir::Node::Block(blk) = self.tcx.hir().get(id?) else { return None };
+                self.could_remove_semicolon(blk, ty)
+            });
+        match remove_semicolon {
+            Some((sp, StatementAsExpression::NeedsBoxing)) => {
+                err.multipart_suggestion(
+                    "consider removing this semicolon and boxing the expressions",
+                    vec![
+                        (first_span.shrink_to_lo(), "Box::new(".to_string()),
+                        (first_span.shrink_to_hi(), ")".to_string()),
+                        (second_span.shrink_to_lo(), "Box::new(".to_string()),
+                        (second_span.shrink_to_hi(), ")".to_string()),
+                        (sp, String::new()),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            }
+            Some((sp, StatementAsExpression::CorrectType)) => {
+                err.span_suggestion_short(
+                    sp,
+                    "consider removing this semicolon",
+                    "",
+                    Applicability::MachineApplicable,
+                );
+            }
+            None => {
+                for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
+                    if let Some(id) = id
+                        && let hir::Node::Block(blk) = self.tcx.hir().get(id)
+                        && self.consider_returning_binding(blk, ty, err)
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
     fn suggest_boxing_for_return_impl_trait(
         &self,
         err: &mut Diagnostic,
@@ -1723,15 +1713,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         };
         debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code());
         if let Some(exp_found) = exp_found {
-            let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } =
-                cause.code()
-            {
-                // Skip if the root_ty of the pattern is not the same as the expected_ty.
-                // If these types aren't equal then we've probably peeled off a layer of arrays.
-                same_type_modulo_infer(self.resolve_vars_if_possible(*root_ty), exp_found.expected)
-            } else {
-                true
-            };
+            let should_suggest_fixes =
+                if let ObligationCauseCode::Pattern { root_ty, .. } = cause.code() {
+                    // Skip if the root_ty of the pattern is not the same as the expected_ty.
+                    // If these types aren't equal then we've probably peeled off a layer of arrays.
+                    self.same_type_modulo_infer(*root_ty, exp_found.expected)
+                } else {
+                    true
+                };
 
             if should_suggest_fixes {
                 self.suggest_tuple_pattern(cause, &exp_found, diag);
@@ -1786,7 +1775,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     .filter_map(|variant| {
                         let sole_field = &variant.fields[0];
                         let sole_field_ty = sole_field.ty(self.tcx, substs);
-                        if same_type_modulo_infer(sole_field_ty, exp_found.found) {
+                        if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
                             let variant_path =
                                 with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
                             // FIXME #56861: DRYer prelude filtering
@@ -1902,12 +1891,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             self.get_impl_future_output_ty(exp_found.expected).map(Binder::skip_binder),
             self.get_impl_future_output_ty(exp_found.found).map(Binder::skip_binder),
         ) {
-            (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match cause.code() {
-                ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
+            (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause
+                .code()
+            {
+                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
+                    let then_span = self.find_block_span_from_hir_id(*then_id);
                     diag.multipart_suggestion(
                         "consider `await`ing on both `Future`s",
                         vec![
-                            (then.shrink_to_hi(), ".await".to_string()),
+                            (then_span.shrink_to_hi(), ".await".to_string()),
                             (exp_span.shrink_to_hi(), ".await".to_string()),
                         ],
                         Applicability::MaybeIncorrect,
@@ -1934,7 +1926,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     diag.help("consider `await`ing on both `Future`s");
                 }
             },
-            (_, Some(ty)) if same_type_modulo_infer(exp_found.expected, ty) => {
+            (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
                 diag.span_suggestion_verbose(
                     exp_span.shrink_to_hi(),
                     "consider `await`ing on the `Future`",
@@ -1942,11 +1934,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     Applicability::MaybeIncorrect,
                 );
             }
-            (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code() {
-                ObligationCauseCode::Pattern { span: Some(span), .. }
-                | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => {
+            (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
+            {
+                ObligationCauseCode::Pattern { span: Some(then_span), .. } => {
                     diag.span_suggestion_verbose(
-                        span.shrink_to_hi(),
+                        then_span.shrink_to_hi(),
+                        "consider `await`ing on the `Future`",
+                        ".await",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
+                    let then_span = self.find_block_span_from_hir_id(*then_id);
+                    diag.span_suggestion_verbose(
+                        then_span.shrink_to_hi(),
                         "consider `await`ing on the `Future`",
                         ".await",
                         Applicability::MaybeIncorrect,
@@ -1992,7 +1993,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 .iter()
                 .filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
                 .map(|field| (field.name, field.ty(self.tcx, expected_substs)))
-                .find(|(_, ty)| same_type_modulo_infer(*ty, exp_found.found))
+                .find(|(_, ty)| self.same_type_modulo_infer(*ty, exp_found.found))
             {
                 if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -2057,7 +2058,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                         | (_, ty::Infer(_))
                                         | (ty::Param(_), _)
                                         | (ty::Infer(_), _) => {}
-                                        _ if same_type_modulo_infer(exp_ty, found_ty) => {}
+                                        _ if self.same_type_modulo_infer(exp_ty, found_ty) => {}
                                         _ => show_suggestion = false,
                                     };
                                 }
@@ -2179,7 +2180,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     ) {
         let [expected_tup_elem] = expected_fields[..] else { return };
 
-        if !same_type_modulo_infer(expected_tup_elem, found) {
+        if !self.same_type_modulo_infer(expected_tup_elem, found) {
             return;
         }
 
@@ -2647,6 +2648,76 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         span.is_desugaring(DesugaringKind::QuestionMark)
             && self.tcx.is_diagnostic_item(sym::From, trait_def_id)
     }
+
+    /// Structurally compares two types, modulo any inference variables.
+    ///
+    /// Returns `true` if two types are equal, or if one type is an inference variable compatible
+    /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or
+    /// FloatVar inference type are compatible with themselves or their concrete types (Int and
+    /// Float types, respectively). When comparing two ADTs, these rules apply recursively.
+    pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+        let (a, b) = self.resolve_vars_if_possible((a, b));
+        match (a.kind(), b.kind()) {
+            (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) => {
+                if def_a != def_b {
+                    return false;
+                }
+
+                substs_a
+                    .types()
+                    .zip(substs_b.types())
+                    .all(|(a, b)| self.same_type_modulo_infer(a, b))
+            }
+            (&ty::FnDef(did_a, substs_a), &ty::FnDef(did_b, substs_b)) => {
+                if did_a != did_b {
+                    return false;
+                }
+
+                substs_a
+                    .types()
+                    .zip(substs_b.types())
+                    .all(|(a, b)| self.same_type_modulo_infer(a, b))
+            }
+            (&ty::Int(_) | &ty::Uint(_), &ty::Infer(ty::InferTy::IntVar(_)))
+            | (
+                &ty::Infer(ty::InferTy::IntVar(_)),
+                &ty::Int(_) | &ty::Uint(_) | &ty::Infer(ty::InferTy::IntVar(_)),
+            )
+            | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
+            | (
+                &ty::Infer(ty::InferTy::FloatVar(_)),
+                &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
+            )
+            | (&ty::Infer(ty::InferTy::TyVar(_)), _)
+            | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
+            (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => {
+                mut_a == mut_b && self.same_type_modulo_infer(ty_a, ty_b)
+            }
+            (&ty::RawPtr(a), &ty::RawPtr(b)) => {
+                a.mutbl == b.mutbl && self.same_type_modulo_infer(a.ty, b.ty)
+            }
+            (&ty::Slice(a), &ty::Slice(b)) => self.same_type_modulo_infer(a, b),
+            (&ty::Array(a_ty, a_ct), &ty::Array(b_ty, b_ct)) => {
+                self.same_type_modulo_infer(a_ty, b_ty) && a_ct == b_ct
+            }
+            (&ty::Tuple(a), &ty::Tuple(b)) => {
+                if a.len() != b.len() {
+                    return false;
+                }
+                std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b))
+            }
+            (&ty::FnPtr(a), &ty::FnPtr(b)) => {
+                let a = a.skip_binder().inputs_and_output;
+                let b = b.skip_binder().inputs_and_output;
+                if a.len() != b.len() {
+                    return false;
+                }
+                std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b))
+            }
+            // FIXME(compiler-errors): This needs to be generalized more
+            _ => a == b,
+        }
+    }
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
@@ -2798,3 +2869,237 @@ impl TyCategory {
         }
     }
 }
+
+impl<'tcx> InferCtxt<'_, 'tcx> {
+    /// Given a [`hir::Block`], get the span of its last expression or
+    /// statement, peeling off any inner blocks.
+    pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
+        let block = block.innermost_block();
+        if let Some(expr) = &block.expr {
+            expr.span
+        } else if let Some(stmt) = block.stmts.last() {
+            // possibly incorrect trailing `;` in the else arm
+            stmt.span
+        } else {
+            // empty block; point at its entirety
+            block.span
+        }
+    }
+
+    /// Given a [`hir::HirId`] for a block, get the span of its last expression
+    /// or statement, peeling off any inner blocks.
+    pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
+        match self.tcx.hir().get(hir_id) {
+            hir::Node::Block(blk) => self.find_block_span(blk),
+            // The parser was in a weird state if either of these happen, but
+            // it's better not to panic.
+            hir::Node::Expr(e) => e.span,
+            _ => rustc_span::DUMMY_SP,
+        }
+    }
+
+    /// Be helpful when the user wrote `{... expr; }` and taking the `;` off
+    /// is enough to fix the error.
+    pub fn could_remove_semicolon(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) -> Option<(Span, StatementAsExpression)> {
+        let blk = blk.innermost_block();
+        // Do not suggest if we have a tail expr.
+        if blk.expr.is_some() {
+            return None;
+        }
+        let last_stmt = blk.stmts.last()?;
+        let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else {
+            return None;
+        };
+        let last_expr_ty = self.in_progress_typeck_results?.borrow().expr_ty_opt(*last_expr)?;
+        let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
+            _ if last_expr_ty.references_error() => return None,
+            _ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
+                StatementAsExpression::CorrectType
+            }
+            (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
+                if last_def_id == exp_def_id =>
+            {
+                StatementAsExpression::CorrectType
+            }
+            (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
+                debug!(
+                    "both opaque, likely future {:?} {:?} {:?} {:?}",
+                    last_def_id, last_bounds, exp_def_id, exp_bounds
+                );
+
+                let last_local_id = last_def_id.as_local()?;
+                let exp_local_id = exp_def_id.as_local()?;
+
+                match (
+                    &self.tcx.hir().expect_item(last_local_id).kind,
+                    &self.tcx.hir().expect_item(exp_local_id).kind,
+                ) {
+                    (
+                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
+                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
+                    ) if iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| {
+                        match (left, right) {
+                            (
+                                hir::GenericBound::Trait(tl, ml),
+                                hir::GenericBound::Trait(tr, mr),
+                            ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
+                                && ml == mr =>
+                            {
+                                true
+                            }
+                            (
+                                hir::GenericBound::LangItemTrait(langl, _, _, argsl),
+                                hir::GenericBound::LangItemTrait(langr, _, _, argsr),
+                            ) if langl == langr => {
+                                // FIXME: consider the bounds!
+                                debug!("{:?} {:?}", argsl, argsr);
+                                true
+                            }
+                            _ => false,
+                        }
+                    }) =>
+                    {
+                        StatementAsExpression::NeedsBoxing
+                    }
+                    _ => StatementAsExpression::CorrectType,
+                }
+            }
+            _ => return None,
+        };
+        let span = if last_stmt.span.from_expansion() {
+            let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span);
+            self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)?
+        } else {
+            last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1))
+        };
+        Some((span, needs_box))
+    }
+
+    /// Suggest returning a local binding with a compatible type if the block
+    /// has no return expression.
+    pub fn consider_returning_binding(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+        err: &mut Diagnostic,
+    ) -> bool {
+        let blk = blk.innermost_block();
+        // Do not suggest if we have a tail expr.
+        if blk.expr.is_some() {
+            return false;
+        }
+        let mut shadowed = FxHashSet::default();
+        let mut candidate_idents = vec![];
+        let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
+            if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
+                && let Some(pat_ty) = self
+                    .in_progress_typeck_results
+                    .and_then(|typeck_results| typeck_results.borrow().node_type_opt(*hir_id))
+            {
+                let pat_ty = self.resolve_vars_if_possible(pat_ty);
+                if self.same_type_modulo_infer(pat_ty, expected_ty)
+                    && !(pat_ty, expected_ty).references_error()
+                    && shadowed.insert(ident.name)
+                {
+                    candidate_idents.push((*ident, pat_ty));
+                }
+            }
+            true
+        };
+
+        let hir = self.tcx.hir();
+        for stmt in blk.stmts.iter().rev() {
+            let hir::StmtKind::Local(local) = &stmt.kind else { continue; };
+            local.pat.walk(&mut find_compatible_candidates);
+        }
+        match hir.find(hir.get_parent_node(blk.hir_id)) {
+            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
+                match hir.find(hir.get_parent_node(*hir_id)) {
+                    Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
+                        pat.walk(&mut find_compatible_candidates);
+                    }
+                    Some(
+                        hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
+                        | hir::Node::ImplItem(hir::ImplItem {
+                            kind: hir::ImplItemKind::Fn(_, body),
+                            ..
+                        })
+                        | hir::Node::TraitItem(hir::TraitItem {
+                            kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
+                            ..
+                        })
+                        | hir::Node::Expr(hir::Expr {
+                            kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
+                            ..
+                        }),
+                    ) => {
+                        for param in hir.body(*body).params {
+                            param.pat.walk(&mut find_compatible_candidates);
+                        }
+                    }
+                    Some(hir::Node::Expr(hir::Expr {
+                        kind:
+                            hir::ExprKind::If(
+                                hir::Expr { kind: hir::ExprKind::Let(let_), .. },
+                                then_block,
+                                _,
+                            ),
+                        ..
+                    })) if then_block.hir_id == *hir_id => {
+                        let_.pat.walk(&mut find_compatible_candidates);
+                    }
+                    _ => {}
+                }
+            }
+            _ => {}
+        }
+
+        match &candidate_idents[..] {
+            [(ident, _ty)] => {
+                let sm = self.tcx.sess.source_map();
+                if let Some(stmt) = blk.stmts.last() {
+                    let stmt_span = sm.stmt_span(stmt.span, blk.span);
+                    let sugg = if sm.is_multiline(blk.span)
+                        && let Some(spacing) = sm.indentation_before(stmt_span)
+                    {
+                        format!("\n{spacing}{ident}")
+                    } else {
+                        format!(" {ident}")
+                    };
+                    err.span_suggestion_verbose(
+                        stmt_span.shrink_to_hi(),
+                        format!("consider returning the local binding `{ident}`"),
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    let sugg = if sm.is_multiline(blk.span)
+                        && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
+                    {
+                        format!("\n{spacing}    {ident}\n{spacing}")
+                    } else {
+                        format!(" {ident} ")
+                    };
+                    let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
+                    err.span_suggestion_verbose(
+                        sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
+                        format!("consider returning the local binding `{ident}`"),
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                true
+            }
+            values if (1..3).contains(&values.len()) => {
+                let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
+                err.span_note(spans, "consider returning one of these bindings");
+                true
+            }
+            _ => false,
+        }
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index b267140daa9..561d1354edd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -1,4 +1,4 @@
-use crate::infer::type_variable::TypeVariableOriginKind;
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::InferCtxt;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
@@ -8,12 +8,12 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::infer::unify_key::ConstVariableOriginKind;
+use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
 use rustc_middle::ty::{self, DefIdTree, InferConst};
-use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
+use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{BytePos, Span};
 use std::borrow::Cow;
@@ -407,11 +407,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
                 err.span_label(span, cannot_infer_msg);
 
-                let printer = fmt_printer(self, Namespace::TypeNS);
-                let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer();
+                let args = fmt_printer(self, Namespace::TypeNS)
+                    .comma_sep(generic_args.iter().copied().map(|arg| {
+                        if arg.is_suggestable(self.tcx, true) {
+                            return arg;
+                        }
+
+                        match arg.unpack() {
+                            GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
+                            GenericArgKind::Type(_) => self
+                                .next_ty_var(TypeVariableOrigin {
+                                    span: rustc_span::DUMMY_SP,
+                                    kind: TypeVariableOriginKind::MiscVariable,
+                                })
+                                .into(),
+                            GenericArgKind::Const(arg) => self
+                                .next_const_var(
+                                    arg.ty(),
+                                    ConstVariableOrigin {
+                                        span: rustc_span::DUMMY_SP,
+                                        kind: ConstVariableOriginKind::MiscVariable,
+                                    },
+                                )
+                                .into(),
+                        }
+                    }))
+                    .unwrap()
+                    .into_buffer();
+
                 err.span_suggestion_verbose(
                     insert_span,
-                    &format!("consider specifying the generic argument{}", pluralize!(args.len()),),
+                    &format!(
+                        "consider specifying the generic argument{}",
+                        pluralize!(generic_args.len()),
+                    ),
                     format!("::<{}>", args),
                     Applicability::HasPlaceholders,
                 );
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 43d5c9fdf33..893ca3cf79d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -6,7 +6,7 @@ use crate::infer::error_reporting::note_and_explain_region;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::ObligationCauseCode;
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 02928c4aa57..246d27be71c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -4,7 +4,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_ty, Visitor};
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 67bbace39e3..b6d41bedd56 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -357,7 +357,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
                 let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
 
-                let impl_predicates: rustc_data_structures::stable_set::FxHashSet<_> =
+                let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
                     impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
                 let clauses: Vec<_> = trait_predicates
                     .predicates
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index b3dc2e586d2..85692e109be 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -239,17 +239,36 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum DefiningAnchor {
+    /// `DefId` of the item.
+    Bind(LocalDefId),
+    /// When opaque types are not resolved, we `Bubble` up, meaning
+    /// return the opaque/hidden type pair from query, for caller of query to handle it.
+    Bubble,
+    /// Used to catch type mismatch errors when handling opaque types.
+    Error,
+}
+
 pub struct InferCtxt<'a, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
     /// The `DefId` of the item in whose context we are performing inference or typeck.
     /// It is used to check whether an opaque type use is a defining use.
     ///
-    /// If it is `None`, we can't resolve opaque types here and need to bubble up
+    /// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up
     /// the obligation. This frequently happens for
     /// short lived InferCtxt within queries. The opaque type obligations are forwarded
     /// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
-    pub defining_use_anchor: Option<LocalDefId>,
+    ///
+    /// It is default value is `DefiningAnchor::Error`, this way it is easier to catch errors that
+    /// might come up during inference or typeck.
+    pub defining_use_anchor: DefiningAnchor,
+
+    /// Whether this inference context should care about region obligations in
+    /// the root universe. Most notably, this is used during hir typeck as region
+    /// solving is left to borrowck instead.
+    pub considering_regions: bool,
 
     /// During type-checking/inference of a body, `in_progress_typeck_results`
     /// contains a reference to the typeck results being built up, which are
@@ -525,8 +544,9 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
 /// without using `Rc` or something similar.
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
+    defining_use_anchor: DefiningAnchor,
+    considering_regions: bool,
     fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
-    defining_use_anchor: Option<LocalDefId>,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -535,7 +555,12 @@ pub trait TyCtxtInferExt<'tcx> {
 
 impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
+        InferCtxtBuilder {
+            tcx: self,
+            defining_use_anchor: DefiningAnchor::Error,
+            considering_regions: true,
+            fresh_typeck_results: None,
+        }
     }
 }
 
@@ -545,7 +570,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     /// Will also change the scope for opaque type defining use checks to the given owner.
     pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
         self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
-        self.with_opaque_type_inference(table_owner)
+        self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner))
     }
 
     /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
@@ -554,8 +579,13 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     /// It is only meant to be called in two places, for typeck
     /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
     /// in mir borrowck.
-    pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
-        self.defining_use_anchor = Some(defining_use_anchor);
+    pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self {
+        self.defining_use_anchor = defining_use_anchor;
+        self
+    }
+
+    pub fn ignoring_regions(mut self) -> Self {
+        self.considering_regions = false;
         self
     }
 
@@ -583,11 +613,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     }
 
     pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
-        let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
+        let InferCtxtBuilder {
+            tcx,
+            defining_use_anchor,
+            considering_regions,
+            ref fresh_typeck_results,
+        } = *self;
         let in_progress_typeck_results = fresh_typeck_results.as_ref();
         f(InferCtxt {
             tcx,
             defining_use_anchor,
+            considering_regions,
             in_progress_typeck_results,
             inner: RefCell::new(InferCtxtInner::new()),
             lexical_region_resolutions: RefCell::new(None),
@@ -1025,16 +1061,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         &self,
         cause: &traits::ObligationCause<'tcx>,
         predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
-    ) -> UnitResult<'tcx> {
-        self.commit_if_ok(|_snapshot| {
-            let ty::OutlivesPredicate(r_a, r_b) =
-                self.replace_bound_vars_with_placeholders(predicate);
-            let origin = SubregionOrigin::from_obligation_cause(cause, || {
-                RelateRegionParamBound(cause.span)
-            });
-            self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
-            Ok(())
-        })
+    ) {
+        let ty::OutlivesPredicate(r_a, r_b) = self.replace_bound_vars_with_placeholders(predicate);
+        let origin =
+            SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
+        self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
     }
 
     /// Number of type variables created so far.
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 4ee9c4eeda4..7b0ff9552a3 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,4 +1,4 @@
-use crate::infer::{InferCtxt, InferOk};
+use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
 use crate::traits;
 use hir::def_id::{DefId, LocalDefId};
 use hir::{HirId, OpaqueTyOrigin};
@@ -101,44 +101,46 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
             ty::Opaque(def_id, substs) if def_id.is_local() => {
                 let def_id = def_id.expect_local();
-                let origin = if self.defining_use_anchor.is_some() {
-                    // Check that this is `impl Trait` type is
-                    // declared by `parent_def_id` -- i.e., one whose
-                    // value we are inferring.  At present, this is
-                    // always true during the first phase of
-                    // type-check, but not always true later on during
-                    // NLL. Once we support named opaque types more fully,
-                    // this same scenario will be able to arise during all phases.
-                    //
-                    // Here is an example using type alias `impl Trait`
-                    // that indicates the distinction we are checking for:
-                    //
-                    // ```rust
-                    // mod a {
-                    //   pub type Foo = impl Iterator;
-                    //   pub fn make_foo() -> Foo { .. }
-                    // }
-                    //
-                    // mod b {
-                    //   fn foo() -> a::Foo { a::make_foo() }
-                    // }
-                    // ```
-                    //
-                    // Here, the return type of `foo` references an
-                    // `Opaque` indeed, but not one whose value is
-                    // presently being inferred. You can get into a
-                    // similar situation with closure return types
-                    // today:
-                    //
-                    // ```rust
-                    // fn foo() -> impl Iterator { .. }
-                    // fn bar() {
-                    //     let x = || foo(); // returns the Opaque assoc with `foo`
-                    // }
-                    // ```
-                    self.opaque_type_origin(def_id, cause.span)?
-                } else {
-                    self.opaque_ty_origin_unchecked(def_id, cause.span)
+                let origin = match self.defining_use_anchor {
+                    DefiningAnchor::Bind(_) => {
+                        // Check that this is `impl Trait` type is
+                        // declared by `parent_def_id` -- i.e., one whose
+                        // value we are inferring.  At present, this is
+                        // always true during the first phase of
+                        // type-check, but not always true later on during
+                        // NLL. Once we support named opaque types more fully,
+                        // this same scenario will be able to arise during all phases.
+                        //
+                        // Here is an example using type alias `impl Trait`
+                        // that indicates the distinction we are checking for:
+                        //
+                        // ```rust
+                        // mod a {
+                        //   pub type Foo = impl Iterator;
+                        //   pub fn make_foo() -> Foo { .. }
+                        // }
+                        //
+                        // mod b {
+                        //   fn foo() -> a::Foo { a::make_foo() }
+                        // }
+                        // ```
+                        //
+                        // Here, the return type of `foo` references an
+                        // `Opaque` indeed, but not one whose value is
+                        // presently being inferred. You can get into a
+                        // similar situation with closure return types
+                        // today:
+                        //
+                        // ```rust
+                        // fn foo() -> impl Iterator { .. }
+                        // fn bar() {
+                        //     let x = || foo(); // returns the Opaque assoc with `foo`
+                        // }
+                        // ```
+                        self.opaque_type_origin(def_id, cause.span)?
+                    }
+                    DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
+                    DefiningAnchor::Error => return None,
                 };
                 if let ty::Opaque(did2, _) = *b.kind() {
                     // We could accept this, but there are various ways to handle this situation, and we don't
@@ -407,7 +409,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     #[instrument(skip(self), level = "trace")]
     pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
         let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-        let parent_def_id = self.defining_use_anchor?;
+        let parent_def_id = match self.defining_use_anchor {
+            DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
+            DefiningAnchor::Bind(bind) => bind,
+        };
         let item_kind = &self.tcx.hir().expect_item(def_id).kind;
 
         let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, ..  }) = item_kind else {
@@ -433,7 +438,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "trace")]
-    fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
+    pub fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
         let origin = match self.tcx.hir().expect_item(def_id).kind {
             hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
             ref itemkind => {
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 9c0b534798e..d07e17f6792 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -718,6 +718,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(asm_comments, true);
     tracked!(assume_incomplete_release, true);
     tracked!(binary_dep_depinfo, true);
+    tracked!(box_noalias, Some(false));
     tracked!(
         branch_protection,
         Some(BranchProtection {
@@ -734,6 +735,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(drop_tracking, true);
     tracked!(dual_proc_macros, true);
     tracked!(dwarf_version, Some(5));
+    tracked!(emit_thin_lto, false);
     tracked!(fewer_names, Some(true));
     tracked!(force_unstable_if_unmarked, true);
     tracked!(fuel, Some(("abc".to_string(), 99)));
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 4fd57ed8533..3872d866dee 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -467,7 +467,7 @@ pub enum BuiltinLintDiagnostics {
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
     },
-    NamedArgumentUsedPositionally(Option<Span>, Span, String),
+    NamedArgumentUsedPositionally(Option<Span>, Span, Symbol),
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 9fe84a6309b..bca5425e728 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -85,6 +85,7 @@ enum LLVMRustAttribute {
   NoUndef = 33,
   SanitizeMemTag = 34,
   NoCfCheck = 35,
+  ShadowCallStack = 36,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index be8fbf7677b..e0f10f77e89 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -34,6 +34,7 @@
 #include "llvm/Transforms/Utils/AddDiscriminators.h"
 #include "llvm/Transforms/Utils/FunctionImportUtils.h"
 #include "llvm/LTO/LTO.h"
+#include "llvm/Bitcode/BitcodeWriterPass.h"
 #include "llvm-c/Transforms/PassManagerBuilder.h"
 
 #include "llvm/Transforms/Instrumentation.h"
@@ -1638,13 +1639,17 @@ struct LLVMRustThinLTOBuffer {
 };
 
 extern "C" LLVMRustThinLTOBuffer*
-LLVMRustThinLTOBufferCreate(LLVMModuleRef M) {
+LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
   auto Ret = std::make_unique<LLVMRustThinLTOBuffer>();
   {
     raw_string_ostream OS(Ret->data);
     {
       legacy::PassManager PM;
-      PM.add(createWriteThinLTOBitcodePass(OS));
+      if (is_thin) {
+        PM.add(createWriteThinLTOBitcodePass(OS));
+      } else {
+        PM.add(createBitcodeWriterPass(OS));
+      }
       PM.run(*unwrap(M));
     }
   }
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 2d35ee8976e..4615558b912 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -232,6 +232,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::NoUndef;
   case SanitizeMemTag:
     return Attribute::SanitizeMemTag;
+  case ShadowCallStack:
+    return Attribute::ShadowCallStack;
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 5c5275b7cfb..6c9561925fe 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -212,7 +212,7 @@ impl DiagnosticDeriveBuilder {
                 }
                 NestedMeta::Meta(meta @ Meta::NameValue(_))
                     if !is_help_note_or_warn
-                        && meta.path().segments.last().unwrap().ident.to_string() == "code" =>
+                        && meta.path().segments.last().unwrap().ident == "code" =>
                 {
                     // don't error for valid follow-up attributes
                 }
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
index 1170d2b3c59..562d5e9f4d2 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -194,8 +194,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                 let snake_name = Ident::new(
                     // FIXME: should probably trim prefix, not replace all occurrences
                     &name
-                        .replace(&format!("{}-", res.ident).replace("_", "-"), "")
-                        .replace("-", "_"),
+                        .replace(&format!("{}-", res.ident).replace('_', "-"), "")
+                        .replace('-', "_"),
                     span,
                 );
                 constants.extend(quote! {
@@ -207,7 +207,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                 });
 
                 for Attribute { id: Identifier { name: attr_name }, .. } in attributes {
-                    let snake_name = Ident::new(&attr_name.replace("-", "_"), span);
+                    let snake_name = Ident::new(&attr_name.replace('-', "_"), span);
                     if !previous_attrs.insert(snake_name.clone()) {
                         continue;
                     }
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index a72bcb9a2db..2c1c84b0be2 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -67,7 +67,7 @@
 //!
 //! ## What criterion to select on?
 //!
-//! This a pretty tricky area of loading crates. Given a file, how do we know
+//! This is a pretty tricky area of loading crates. Given a file, how do we know
 //! whether it's the right crate? Currently, the rules look along these lines:
 //!
 //! 1. Does the filename match an rlib/dylib pattern? That is to say, does the
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index f0874f8f2da..aa5705d3fcd 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -951,6 +951,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         tcx.arena.alloc_from_iter(self.root.lib_features.decode(self))
     }
 
+    /// Iterates over the stability implications in the given crate (when a `#[unstable]` attribute
+    /// has an `implied_by` meta item, then the mapping from the implied feature to the actual
+    /// feature is a stability implication).
+    fn get_stability_implications(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Symbol)] {
+        tcx.arena.alloc_from_iter(self.root.stability_implications.decode(self))
+    }
+
     /// Iterates over the language items in the given crate.
     fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
         tcx.arena.alloc_from_iter(
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 565eec18ea9..65cae29c58d 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -291,6 +291,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
         tcx.arena.alloc_slice(&result)
     }
     defined_lib_features => { cdata.get_lib_features(tcx) }
+    stability_implications => {
+        cdata.get_stability_implications(tcx).iter().copied().collect()
+    }
     is_intrinsic => { cdata.get_is_intrinsic(def_id.index) }
     defined_lang_items => { cdata.get_lang_items(tcx) }
     diagnostic_items => { cdata.get_diagnostic_items() }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 8e973009777..50d983754e8 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -538,6 +538,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let lib_features = self.encode_lib_features();
         let lib_feature_bytes = self.position() - i;
 
+        // Encode the stability implications.
+        i = self.position();
+        let stability_implications = self.encode_stability_implications();
+        let stability_implications_bytes = self.position() - i;
+
         // Encode the language items.
         i = self.position();
         let lang_items = self.encode_lang_items();
@@ -686,6 +691,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             crate_deps,
             dylib_dependency_formats,
             lib_features,
+            stability_implications,
             lang_items,
             diagnostic_items,
             lang_items_missing,
@@ -710,6 +716,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let computed_total_bytes = preamble_bytes
             + dep_bytes
             + lib_feature_bytes
+            + stability_implications_bytes
             + lang_item_bytes
             + diagnostic_item_bytes
             + native_lib_bytes
@@ -761,6 +768,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             p("preamble", preamble_bytes);
             p("dep", dep_bytes);
             p("lib feature", lib_feature_bytes);
+            p("stability_implications", stability_implications_bytes);
             p("lang item", lang_item_bytes);
             p("diagnostic item", diagnostic_item_bytes);
             p("native lib", native_lib_bytes);
@@ -1777,6 +1785,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy_array(lib_features.to_vec())
     }
 
+    fn encode_stability_implications(&mut self) -> LazyArray<(Symbol, Symbol)> {
+        empty_proc_macro!(self);
+        let tcx = self.tcx;
+        let implications = tcx.stability_implications(LOCAL_CRATE);
+        self.lazy_array(implications.iter().map(|(k, v)| (*k, *v)))
+    }
+
     fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index af1c09f4ae8..0f291f92647 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -226,6 +226,7 @@ pub(crate) struct CrateRoot {
     crate_deps: LazyArray<CrateDep>,
     dylib_dependency_formats: LazyArray<Option<LinkagePreference>>,
     lib_features: LazyArray<(Symbol, Option<Symbol>)>,
+    stability_implications: LazyArray<(Symbol, Symbol)>,
     lang_items: LazyArray<(DefIndex, usize)>,
     lang_items_missing: LazyArray<lang_items::LangItem>,
     diagnostic_items: LazyArray<(Symbol, DefIndex)>,
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
index fc35cafcc77..8dc68b1f5a8 100644
--- a/compiler/rustc_middle/src/middle/mod.rs
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -3,14 +3,14 @@ pub mod dependency_format;
 pub mod exported_symbols;
 pub mod lang_items;
 pub mod lib_features {
-    use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-    use rustc_span::symbol::Symbol;
+    use rustc_data_structures::fx::FxHashMap;
+    use rustc_span::{symbol::Symbol, Span};
 
     #[derive(HashStable, Debug)]
     pub struct LibFeatures {
-        // A map from feature to stabilisation version.
-        pub stable: FxHashMap<Symbol, Symbol>,
-        pub unstable: FxHashSet<Symbol>,
+        /// A map from feature to stabilisation version.
+        pub stable: FxHashMap<Symbol, (Symbol, Span)>,
+        pub unstable: FxHashMap<Symbol, Span>,
     }
 
     impl LibFeatures {
@@ -18,8 +18,8 @@ pub mod lib_features {
             let mut all_features: Vec<_> = self
                 .stable
                 .iter()
-                .map(|(f, s)| (*f, Some(*s)))
-                .chain(self.unstable.iter().map(|f| (*f, None)))
+                .map(|(f, (s, _))| (*f, Some(*s)))
+                .chain(self.unstable.iter().map(|(f, _)| (*f, None)))
                 .collect();
             all_features.sort_unstable_by(|a, b| a.0.as_str().partial_cmp(b.0.as_str()).unwrap());
             all_features
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 96e068a3601..0fbad3f0f0f 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -62,6 +62,19 @@ pub struct Index {
     pub stab_map: FxHashMap<LocalDefId, Stability>,
     pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
     pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
+    /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
+    /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
+    /// exists, then this map will have a `impliee -> implier` entry.
+    ///
+    /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should
+    /// specify their implications (both `implies` and `implied_by`). If only one of the two
+    /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this
+    /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is
+    /// reported, only the `#[stable]` attribute information is available, so the map is necessary
+    /// to know that the feature implies another feature. If it were reversed, and the `#[stable]`
+    /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of
+    /// unstable feature" error for a feature that was implied.
+    pub implications: FxHashMap<Symbol, Symbol>,
 }
 
 impl Index {
@@ -423,7 +436,9 @@ impl<'tcx> TyCtxt<'tcx> {
 
         match stability {
             Some(Stability {
-                level: attr::Unstable { reason, issue, is_soft }, feature, ..
+                level: attr::Unstable { reason, issue, is_soft, implied_by },
+                feature,
+                ..
             }) => {
                 if span.allows_unstable(feature) {
                     debug!("stability: skipping span={:?} since it is internal", span);
@@ -433,6 +448,13 @@ impl<'tcx> TyCtxt<'tcx> {
                     return EvalResult::Allow;
                 }
 
+                // If this item was previously part of a now-stabilized feature which is still
+                // active (i.e. the user hasn't removed the attribute for the stabilized feature
+                // yet) then allow use of this item.
+                if let Some(implied_by) = implied_by && self.features().active(implied_by) {
+                    return EvalResult::Allow;
+                }
+
                 // When we're compiling the compiler itself we may pull in
                 // crates from crates.io, but those crates may depend on other
                 // crates also pulled in from crates.io. We want to ideally be
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index eed52ca3eea..db7e0fb8a3b 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -30,7 +30,7 @@ use crate::ty;
 // hashed. (see the `Hash` impl below for more details), so the impl is not derived.
 #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
-pub struct Allocation<Tag = AllocId, Extra = ()> {
+pub struct Allocation<Prov = AllocId, Extra = ()> {
     /// The actual bytes of the allocation.
     /// Note that the bytes of a pointer represent the offset of the pointer.
     bytes: Box<[u8]>,
@@ -38,7 +38,7 @@ pub struct Allocation<Tag = AllocId, Extra = ()> {
     /// Only the first byte of a pointer is inserted into the map; i.e.,
     /// every entry in this map applies to `pointer_size` consecutive bytes starting
     /// at the given offset.
-    relocations: Relocations<Tag>,
+    relocations: Relocations<Prov>,
     /// Denotes which part of this allocation is initialized.
     init_mask: InitMask,
     /// The alignment of the allocation to detect unaligned reads.
@@ -102,8 +102,8 @@ impl hash::Hash for Allocation {
 /// (`ConstAllocation`) are used quite a bit.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
 #[rustc_pass_by_value]
-pub struct ConstAllocation<'tcx, Tag = AllocId, Extra = ()>(
-    pub Interned<'tcx, Allocation<Tag, Extra>>,
+pub struct ConstAllocation<'tcx, Prov = AllocId, Extra = ()>(
+    pub Interned<'tcx, Allocation<Prov, Extra>>,
 );
 
 impl<'tcx> fmt::Debug for ConstAllocation<'tcx> {
@@ -114,8 +114,8 @@ impl<'tcx> fmt::Debug for ConstAllocation<'tcx> {
     }
 }
 
-impl<'tcx, Tag, Extra> ConstAllocation<'tcx, Tag, Extra> {
-    pub fn inner(self) -> &'tcx Allocation<Tag, Extra> {
+impl<'tcx, Prov, Extra> ConstAllocation<'tcx, Prov, Extra> {
+    pub fn inner(self) -> &'tcx Allocation<Prov, Extra> {
         self.0.0
     }
 }
@@ -200,7 +200,7 @@ impl AllocRange {
 }
 
 // The constructors are all without extra; the extra gets added by a machine hook later.
-impl<Tag> Allocation<Tag> {
+impl<Prov> Allocation<Prov> {
     /// Creates an allocation initialized by the given bytes
     pub fn from_bytes<'a>(
         slice: impl Into<Cow<'a, [u8]>>,
@@ -256,14 +256,15 @@ impl<Tag> Allocation<Tag> {
 }
 
 impl Allocation {
-    /// Convert Tag and add Extra fields
-    pub fn convert_tag_add_extra<Tag, Extra, Err>(
+    /// Adjust allocation from the ones in tcx to a custom Machine instance
+    /// with a different Provenance and Extra type.
+    pub fn adjust_from_tcx<Prov, Extra, Err>(
         self,
         cx: &impl HasDataLayout,
         extra: Extra,
-        mut tagger: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Tag>, Err>,
-    ) -> Result<Allocation<Tag, Extra>, Err> {
-        // Compute new pointer tags, which also adjusts the bytes.
+        mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>,
+    ) -> Result<Allocation<Prov, Extra>, Err> {
+        // Compute new pointer provenance, which also adjusts the bytes.
         let mut bytes = self.bytes;
         let mut new_relocations = Vec::with_capacity(self.relocations.0.len());
         let ptr_size = cx.data_layout().pointer_size.bytes_usize();
@@ -272,10 +273,10 @@ impl Allocation {
             let idx = offset.bytes_usize();
             let ptr_bytes = &mut bytes[idx..idx + ptr_size];
             let bits = read_target_uint(endian, ptr_bytes).unwrap();
-            let (ptr_tag, ptr_offset) =
-                tagger(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts();
+            let (ptr_prov, ptr_offset) =
+                adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts();
             write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap();
-            new_relocations.push((offset, ptr_tag));
+            new_relocations.push((offset, ptr_prov));
         }
         // Create allocation.
         Ok(Allocation {
@@ -290,7 +291,7 @@ impl Allocation {
 }
 
 /// Raw accessors. Provide access to otherwise private bytes.
-impl<Tag, Extra> Allocation<Tag, Extra> {
+impl<Prov, Extra> Allocation<Prov, Extra> {
     pub fn len(&self) -> usize {
         self.bytes.len()
     }
@@ -313,13 +314,13 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
     }
 
     /// Returns the relocation list.
-    pub fn relocations(&self) -> &Relocations<Tag> {
+    pub fn relocations(&self) -> &Relocations<Prov> {
         &self.relocations
     }
 }
 
 /// Byte accessors.
-impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
+impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
     /// This is the entirely abstraction-violating way to just grab the raw bytes without
     /// caring about relocations. It just deduplicates some code between `read_scalar`
     /// and `get_bytes_internal`.
@@ -413,7 +414,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
 }
 
 /// Reading and writing.
-impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
+impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
     /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
     /// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the
     /// given range contains no uninitialized bytes/relocations.
@@ -451,7 +452,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
         cx: &impl HasDataLayout,
         range: AllocRange,
         read_provenance: bool,
-    ) -> AllocResult<ScalarMaybeUninit<Tag>> {
+    ) -> AllocResult<ScalarMaybeUninit<Prov>> {
         if read_provenance {
             assert_eq!(range.size, cx.data_layout().pointer_size);
         }
@@ -475,7 +476,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
 
         // If we are *not* reading a pointer, and we can just ignore relocations,
         // then do exactly that.
-        if !read_provenance && Tag::OFFSET_IS_ADDR {
+        if !read_provenance && Prov::OFFSET_IS_ADDR {
             // We just strip provenance.
             let bytes = self.get_bytes_even_more_internal(range);
             let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
@@ -506,7 +507,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
         &mut self,
         cx: &impl HasDataLayout,
         range: AllocRange,
-        val: ScalarMaybeUninit<Tag>,
+        val: ScalarMaybeUninit<Prov>,
     ) -> AllocResult {
         assert!(self.mutability == Mutability::Mut);
 
@@ -548,9 +549,9 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
 }
 
 /// Relocations.
-impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<Prov: Copy, Extra> Allocation<Prov, Extra> {
     /// Returns all relocations overlapping with the given pointer-offset pair.
-    fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Tag)] {
+    fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Prov)] {
         // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
         // the beginning of this range.
         let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1);
@@ -580,7 +581,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// immediately in that case.
     fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult
     where
-        Tag: Provenance,
+        Prov: Provenance,
     {
         // Find the start and end of the given range and its outermost relocations.
         let (first, last) = {
@@ -602,7 +603,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
         // FIXME: Miri should preserve partial relocations; see
         // https://github.com/rust-lang/miri/issues/2181.
         if first < start {
-            if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
+            if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE {
                 return Err(AllocError::PartialPointerOverwrite(first));
             }
             warn!(
@@ -611,7 +612,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
             self.init_mask.set_range(first, start, false);
         }
         if last > end {
-            if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
+            if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE {
                 return Err(AllocError::PartialPointerOverwrite(
                     last - cx.data_layout().pointer_size,
                 ));
@@ -642,22 +643,22 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
 
 /// "Relocations" stores the provenance information of pointers stored in memory.
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-pub struct Relocations<Tag = AllocId>(SortedMap<Size, Tag>);
+pub struct Relocations<Prov = AllocId>(SortedMap<Size, Prov>);
 
-impl<Tag> Relocations<Tag> {
+impl<Prov> Relocations<Prov> {
     pub fn new() -> Self {
         Relocations(SortedMap::new())
     }
 
     // The caller must guarantee that the given relocations are already sorted
     // by address and contain no duplicates.
-    pub fn from_presorted(r: Vec<(Size, Tag)>) -> Self {
+    pub fn from_presorted(r: Vec<(Size, Prov)>) -> Self {
         Relocations(SortedMap::from_presorted_elements(r))
     }
 }
 
-impl<Tag> Deref for Relocations<Tag> {
-    type Target = SortedMap<Size, Tag>;
+impl<Prov> Deref for Relocations<Prov> {
+    type Target = SortedMap<Size, Prov>;
 
     fn deref(&self) -> &Self::Target {
         &self.0
@@ -667,18 +668,18 @@ impl<Tag> Deref for Relocations<Tag> {
 /// A partial, owned list of relocations to transfer into another allocation.
 ///
 /// Offsets are already adjusted to the destination allocation.
-pub struct AllocationRelocations<Tag> {
-    dest_relocations: Vec<(Size, Tag)>,
+pub struct AllocationRelocations<Prov> {
+    dest_relocations: Vec<(Size, Prov)>,
 }
 
-impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<Prov: Copy, Extra> Allocation<Prov, Extra> {
     pub fn prepare_relocation_copy(
         &self,
         cx: &impl HasDataLayout,
         src: AllocRange,
         dest: Size,
         count: u64,
-    ) -> AllocationRelocations<Tag> {
+    ) -> AllocationRelocations<Prov> {
         let relocations = self.get_relocations(cx, src);
         if relocations.is_empty() {
             return AllocationRelocations { dest_relocations: Vec::new() };
@@ -688,7 +689,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
         let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize));
 
         // If `count` is large, this is rather wasteful -- we are allocating a big array here, which
-        // is mostly filled with redundant information since it's just N copies of the same `Tag`s
+        // is mostly filled with redundant information since it's just N copies of the same `Prov`s
         // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range`
         // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces
         // the right sequence of relocations for all N copies.
@@ -713,7 +714,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
     ///
     /// This is dangerous to use as it can violate internal `Allocation` invariants!
     /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
-    pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Tag>) {
+    pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Prov>) {
         self.relocations.0.insert_presorted(relocations.dest_relocations);
     }
 }
@@ -1178,7 +1179,7 @@ impl<'a> Iterator for InitChunkIter<'a> {
 }
 
 /// Uninitialized bytes.
-impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<Prov: Copy, Extra> Allocation<Prov, Extra> {
     /// Checks whether the given range  is entirely initialized.
     ///
     /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
@@ -1226,7 +1227,7 @@ impl InitMaskCompressed {
 }
 
 /// Transferring the initialization mask to other allocations.
-impl<Tag, Extra> Allocation<Tag, Extra> {
+impl<Prov, Extra> Allocation<Prov, Extra> {
     /// Creates a run-length encoding of the initialization mask; panics if range is empty.
     ///
     /// This is essentially a more space-efficient version of
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 795f23edb31..cecb55578d3 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -1,7 +1,7 @@
 use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
 
 use crate::mir::interpret::ConstValue;
-use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree};
+use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree};
 
 use rustc_data_structures::sync::Lock;
 use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
@@ -219,7 +219,7 @@ pub struct ScalarSizeMismatch {
 }
 
 /// Error information for when the program caused Undefined Behavior.
-pub enum UndefinedBehaviorInfo<'tcx> {
+pub enum UndefinedBehaviorInfo {
     /// Free-form case. Only for errors that are never caught!
     Ub(String),
     /// Unreachable code was executed.
@@ -241,12 +241,6 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     PointerArithOverflow,
     /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
     InvalidMeta(&'static str),
-    /// Invalid drop function in vtable.
-    InvalidVtableDropFn(FnSig<'tcx>),
-    /// Invalid size in a vtable: too large.
-    InvalidVtableSize,
-    /// Invalid alignment in a vtable: too large, or not a power of 2.
-    InvalidVtableAlignment(String),
     /// Reading a C string that does not end within its allocation.
     UnterminatedCString(Pointer),
     /// Dereferencing a dangling pointer after it got freed.
@@ -271,6 +265,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     WriteToReadOnly(AllocId),
     // Trying to access the data behind a function pointer.
     DerefFunctionPointer(AllocId),
+    // Trying to access the data behind a vtable pointer.
+    DerefVTablePointer(AllocId),
     /// The value validity check found a problem.
     /// Should only be thrown by `validity.rs` and always point out which part of the value
     /// is the problem.
@@ -288,6 +284,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     InvalidTag(Scalar),
     /// Using a pointer-not-to-a-function as function pointer.
     InvalidFunctionPointer(Pointer),
+    /// Using a pointer-not-to-a-vtable as vtable pointer.
+    InvalidVTablePointer(Pointer),
     /// Using a string that is not valid UTF-8,
     InvalidStr(std::str::Utf8Error),
     /// Using uninitialized data where it is not allowed.
@@ -300,7 +298,7 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     UninhabitedEnumVariantWritten,
 }
 
-impl fmt::Display for UndefinedBehaviorInfo<'_> {
+impl fmt::Display for UndefinedBehaviorInfo {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use UndefinedBehaviorInfo::*;
         match self {
@@ -315,14 +313,6 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
             RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
             PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
             InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"),
-            InvalidVtableDropFn(sig) => write!(
-                f,
-                "invalid drop function signature: got {sig}, expected exactly one argument which must be a pointer type",
-            ),
-            InvalidVtableSize => {
-                write!(f, "invalid vtable: size is bigger than largest supported object")
-            }
-            InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {msg}"),
             UnterminatedCString(p) => write!(
                 f,
                 "reading a null-terminated string starting at {p:?} with no null found before end of allocation",
@@ -359,6 +349,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
             ),
             WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"),
             DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"),
+            DerefVTablePointer(a) => write!(f, "accessing {a:?} which contains a vtable"),
             ValidationFailure { path: None, msg } => {
                 write!(f, "constructing invalid value: {msg}")
             }
@@ -375,6 +366,9 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
             InvalidFunctionPointer(p) => {
                 write!(f, "using {p:?} as function pointer but it does not point to a function")
             }
+            InvalidVTablePointer(p) => {
+                write!(f, "using {p:?} as vtable pointer but it does not point to a vtable")
+            }
             InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"),
             InvalidUninitBytes(Some((alloc, info))) => write!(
                 f,
@@ -494,7 +488,7 @@ impl dyn MachineStopType {
 
 pub enum InterpError<'tcx> {
     /// The program caused undefined behavior.
-    UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
+    UndefinedBehavior(UndefinedBehaviorInfo),
     /// The program did something the interpreter does not support (some of these *might* be UB
     /// but the interpreter is not sure).
     Unsupported(UnsupportedOpInfo),
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 698024b2330..967f8ece16c 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -196,6 +196,7 @@ impl fmt::Debug for AllocId {
 enum AllocDiscriminant {
     Alloc,
     Fn,
+    VTable,
     Static,
 }
 
@@ -215,6 +216,12 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
             AllocDiscriminant::Fn.encode(encoder);
             fn_instance.encode(encoder);
         }
+        GlobalAlloc::VTable(ty, poly_trait_ref) => {
+            trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id);
+            AllocDiscriminant::VTable.encode(encoder);
+            ty.encode(encoder);
+            poly_trait_ref.encode(encoder);
+        }
         GlobalAlloc::Static(did) => {
             assert!(!tcx.is_thread_local_static(did));
             // References to statics doesn't need to know about their allocations,
@@ -305,7 +312,9 @@ impl<'s> AllocDecodingSession<'s> {
                                 State::InProgress(TinyList::new_single(self.session_id), alloc_id);
                             Some(alloc_id)
                         }
-                        AllocDiscriminant::Fn | AllocDiscriminant::Static => {
+                        AllocDiscriminant::Fn
+                        | AllocDiscriminant::Static
+                        | AllocDiscriminant::VTable => {
                             // Fns and statics cannot be cyclic, and their `AllocId`
                             // is determined later by interning.
                             *entry =
@@ -355,6 +364,16 @@ impl<'s> AllocDecodingSession<'s> {
                     let alloc_id = decoder.interner().create_fn_alloc(instance);
                     alloc_id
                 }
+                AllocDiscriminant::VTable => {
+                    assert!(alloc_id.is_none());
+                    trace!("creating vtable alloc ID");
+                    let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
+                    let poly_trait_ref =
+                        <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
+                    trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
+                    let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref);
+                    alloc_id
+                }
                 AllocDiscriminant::Static => {
                     assert!(alloc_id.is_none());
                     trace!("creating extern static alloc ID");
@@ -380,6 +399,8 @@ impl<'s> AllocDecodingSession<'s> {
 pub enum GlobalAlloc<'tcx> {
     /// The alloc ID is used as a function pointer.
     Function(Instance<'tcx>),
+    /// This alloc ID points to a symbolic (not-reified) vtable.
+    VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
     /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
     /// This is also used to break the cycle in recursive statics.
     Static(DefId),
@@ -407,6 +428,16 @@ impl<'tcx> GlobalAlloc<'tcx> {
             _ => bug!("expected function, got {:?}", self),
         }
     }
+
+    /// Panics if the `GlobalAlloc` is not `GlobalAlloc::VTable`
+    #[track_caller]
+    #[inline]
+    pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
+        match *self {
+            GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref),
+            _ => bug!("expected vtable, got {:?}", self),
+        }
+    }
 }
 
 pub(crate) struct AllocMap<'tcx> {
@@ -454,12 +485,12 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Reserves a new ID *if* this allocation has not been dedup-reserved before.
-    /// Should only be used for function pointers and statics, we don't want
-    /// to dedup IDs for "real" memory!
+    /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we
+    /// don't want to dedup IDs for "real" memory!
     fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId {
         let mut alloc_map = self.alloc_map.lock();
         match alloc {
-            GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {}
+            GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {}
             GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"),
         }
         if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) {
@@ -504,6 +535,15 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    /// Generates an `AllocId` for a (symbolic, not-reified) vtable.  Will get deduplicated.
+    pub fn create_vtable_alloc(
+        self,
+        ty: Ty<'tcx>,
+        poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    ) -> AllocId {
+        self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref))
+    }
+
     /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical
     /// `Allocation` with a different `AllocId`.
     /// Statics with identical content will still point to the same `Allocation`, i.e.,
@@ -521,7 +561,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// This function exists to allow const eval to detect the difference between evaluation-
     /// local dangling pointers and allocations in constants/statics.
     #[inline]
-    pub fn get_global_alloc(self, id: AllocId) -> Option<GlobalAlloc<'tcx>> {
+    pub fn try_get_global_alloc(self, id: AllocId) -> Option<GlobalAlloc<'tcx>> {
         self.alloc_map.lock().alloc_map.get(&id).cloned()
     }
 
@@ -532,7 +572,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// ids), this function is frequently used throughout rustc, but should not be used within
     /// the miri engine.
     pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> {
-        match self.get_global_alloc(id) {
+        match self.try_get_global_alloc(id) {
             Some(alloc) => alloc,
             None => bug!("could not find allocation for {id:?}"),
         }
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index d4cdf45d186..384954cbbd5 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -159,34 +159,34 @@ impl Provenance for AllocId {
 /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
-pub struct Pointer<Tag = AllocId> {
-    pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Tag` type)
-    pub provenance: Tag,
+pub struct Pointer<Prov = AllocId> {
+    pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Prov` type)
+    pub provenance: Prov,
 }
 
 static_assert_size!(Pointer, 16);
-// `Option<Tag>` pointers are also passed around quite a bit
+// `Option<Prov>` pointers are also passed around quite a bit
 // (but not stored in permanent machine state).
 static_assert_size!(Pointer<Option<AllocId>>, 16);
 
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
 // all the Miri types.
-impl<Tag: Provenance> fmt::Debug for Pointer<Tag> {
+impl<Prov: Provenance> fmt::Debug for Pointer<Prov> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         Provenance::fmt(self, f)
     }
 }
 
-impl<Tag: Provenance> fmt::Debug for Pointer<Option<Tag>> {
+impl<Prov: Provenance> fmt::Debug for Pointer<Option<Prov>> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.provenance {
-            Some(tag) => Provenance::fmt(&Pointer::new(tag, self.offset), f),
+            Some(prov) => Provenance::fmt(&Pointer::new(prov, self.offset), f),
             None => write!(f, "{:#x}[noalloc]", self.offset.bytes()),
         }
     }
 }
 
-impl<Tag: Provenance> fmt::Display for Pointer<Option<Tag>> {
+impl<Prov: Provenance> fmt::Display for Pointer<Option<Prov>> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if self.provenance.is_none() && self.offset.bytes() == 0 {
             write!(f, "null pointer")
@@ -204,38 +204,38 @@ impl From<AllocId> for Pointer {
     }
 }
 
-impl<Tag> From<Pointer<Tag>> for Pointer<Option<Tag>> {
+impl<Prov> From<Pointer<Prov>> for Pointer<Option<Prov>> {
     #[inline(always)]
-    fn from(ptr: Pointer<Tag>) -> Self {
-        let (tag, offset) = ptr.into_parts();
-        Pointer::new(Some(tag), offset)
+    fn from(ptr: Pointer<Prov>) -> Self {
+        let (prov, offset) = ptr.into_parts();
+        Pointer::new(Some(prov), offset)
     }
 }
 
-impl<Tag> Pointer<Option<Tag>> {
-    /// Convert this pointer that *might* have a tag into a pointer that *definitely* has a tag, or
-    /// an absolute address.
+impl<Prov> Pointer<Option<Prov>> {
+    /// Convert this pointer that *might* have a provenance into a pointer that *definitely* has a
+    /// provenance, or an absolute address.
     ///
     /// This is rarely what you want; call `ptr_try_get_alloc_id` instead.
-    pub fn into_pointer_or_addr(self) -> Result<Pointer<Tag>, Size> {
+    pub fn into_pointer_or_addr(self) -> Result<Pointer<Prov>, Size> {
         match self.provenance {
-            Some(tag) => Ok(Pointer::new(tag, self.offset)),
+            Some(prov) => Ok(Pointer::new(prov, self.offset)),
             None => Err(self.offset),
         }
     }
 
     /// Returns the absolute address the pointer points to.
-    /// Only works if Tag::OFFSET_IS_ADDR is true!
+    /// Only works if Prov::OFFSET_IS_ADDR is true!
     pub fn addr(self) -> Size
     where
-        Tag: Provenance,
+        Prov: Provenance,
     {
-        assert!(Tag::OFFSET_IS_ADDR);
+        assert!(Prov::OFFSET_IS_ADDR);
         self.offset
     }
 }
 
-impl<Tag> Pointer<Option<Tag>> {
+impl<Prov> Pointer<Option<Prov>> {
     #[inline(always)]
     pub fn from_addr(addr: u64) -> Self {
         Pointer { provenance: None, offset: Size::from_bytes(addr) }
@@ -247,21 +247,21 @@ impl<Tag> Pointer<Option<Tag>> {
     }
 }
 
-impl<'tcx, Tag> Pointer<Tag> {
+impl<'tcx, Prov> Pointer<Prov> {
     #[inline(always)]
-    pub fn new(provenance: Tag, offset: Size) -> Self {
+    pub fn new(provenance: Prov, offset: Size) -> Self {
         Pointer { provenance, offset }
     }
 
-    /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Tag`!
+    /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Prov`!
     /// This function must only be used in the implementation of `Machine::ptr_get_alloc`,
     /// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`.
     #[inline(always)]
-    pub fn into_parts(self) -> (Tag, Size) {
+    pub fn into_parts(self) -> (Prov, Size) {
         (self.provenance, self.offset)
     }
 
-    pub fn map_provenance(self, f: impl FnOnce(Tag) -> Tag) -> Self {
+    pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self {
         Pointer { provenance: f(self.provenance), ..self }
     }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 22bbe29c105..17088cf13a5 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -126,7 +126,7 @@ impl<'tcx> ConstValue<'tcx> {
 /// Do *not* match on a `Scalar`! Use the various `to_*` methods instead.
 #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
-pub enum Scalar<Tag = AllocId> {
+pub enum Scalar<Prov = AllocId> {
     /// The raw bytes of a simple value.
     Int(ScalarInt),
 
@@ -137,7 +137,7 @@ pub enum Scalar<Tag = AllocId> {
     /// We also store the size of the pointer, such that a `Scalar` always knows how big it is.
     /// The size is always the pointer size of the current target, but this is not information
     /// that we always have readily available.
-    Ptr(Pointer<Tag>, u8),
+    Ptr(Pointer<Prov>, u8),
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -145,7 +145,7 @@ static_assert_size!(Scalar, 24);
 
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
 // all the Miri types.
-impl<Tag: Provenance> fmt::Debug for Scalar<Tag> {
+impl<Prov: Provenance> fmt::Debug for Scalar<Prov> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Scalar::Ptr(ptr, _size) => write!(f, "{:?}", ptr),
@@ -154,7 +154,7 @@ impl<Tag: Provenance> fmt::Debug for Scalar<Tag> {
     }
 }
 
-impl<Tag: Provenance> fmt::Display for Scalar<Tag> {
+impl<Prov: Provenance> fmt::Display for Scalar<Prov> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
@@ -163,7 +163,7 @@ impl<Tag: Provenance> fmt::Display for Scalar<Tag> {
     }
 }
 
-impl<Tag: Provenance> fmt::LowerHex for Scalar<Tag> {
+impl<Prov: Provenance> fmt::LowerHex for Scalar<Prov> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
@@ -172,37 +172,38 @@ impl<Tag: Provenance> fmt::LowerHex for Scalar<Tag> {
     }
 }
 
-impl<Tag> From<Single> for Scalar<Tag> {
+impl<Prov> From<Single> for Scalar<Prov> {
     #[inline(always)]
     fn from(f: Single) -> Self {
         Scalar::from_f32(f)
     }
 }
 
-impl<Tag> From<Double> for Scalar<Tag> {
+impl<Prov> From<Double> for Scalar<Prov> {
     #[inline(always)]
     fn from(f: Double) -> Self {
         Scalar::from_f64(f)
     }
 }
 
-impl<Tag> From<ScalarInt> for Scalar<Tag> {
+impl<Prov> From<ScalarInt> for Scalar<Prov> {
     #[inline(always)]
     fn from(ptr: ScalarInt) -> Self {
         Scalar::Int(ptr)
     }
 }
 
-impl<Tag> Scalar<Tag> {
+impl<Prov> Scalar<Prov> {
     #[inline(always)]
-    pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
+    pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self {
         Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap())
     }
 
-    /// Create a Scalar from a pointer with an `Option<_>` tag (where `None` represents a plain integer).
-    pub fn from_maybe_pointer(ptr: Pointer<Option<Tag>>, cx: &impl HasDataLayout) -> Self {
+    /// Create a Scalar from a pointer with an `Option<_>` provenance (where `None` represents a
+    /// plain integer / "invalid" pointer).
+    pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self {
         match ptr.into_parts() {
-            (Some(tag), offset) => Scalar::from_pointer(Pointer::new(tag, offset), cx),
+            (Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx),
             (None, offset) => {
                 Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap())
             }
@@ -310,7 +311,7 @@ impl<Tag> Scalar<Tag> {
     pub fn to_bits_or_ptr_internal(
         self,
         target_size: Size,
-    ) -> Result<Result<u128, Pointer<Tag>>, ScalarSizeMismatch> {
+    ) -> Result<Result<u128, Pointer<Prov>>, ScalarSizeMismatch> {
         assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
         Ok(match self {
             Scalar::Int(int) => Ok(int.to_bits(target_size).map_err(|size| {
@@ -329,7 +330,7 @@ impl<Tag> Scalar<Tag> {
     }
 }
 
-impl<'tcx, Tag: Provenance> Scalar<Tag> {
+impl<'tcx, Prov: Provenance> Scalar<Prov> {
     /// Fundamental scalar-to-int (cast) operation. Many convenience wrappers exist below, that you
     /// likely want to use instead.
     ///
@@ -341,13 +342,13 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> {
         match self {
             Scalar::Int(int) => Ok(int),
             Scalar::Ptr(ptr, sz) => {
-                if Tag::OFFSET_IS_ADDR {
+                if Prov::OFFSET_IS_ADDR {
                     Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap())
                 } else {
                     // We know `offset` is relative, since `OFFSET_IS_ADDR == false`.
-                    let (tag, offset) = ptr.into_parts();
+                    let (prov, offset) = ptr.into_parts();
                     // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail.
-                    Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id().unwrap(), offset), sz))
+                    Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz))
                 }
             }
         }
@@ -489,24 +490,24 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> {
 }
 
 #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)]
-pub enum ScalarMaybeUninit<Tag = AllocId> {
-    Scalar(Scalar<Tag>),
+pub enum ScalarMaybeUninit<Prov = AllocId> {
+    Scalar(Scalar<Prov>),
     Uninit,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(ScalarMaybeUninit, 24);
 
-impl<Tag> From<Scalar<Tag>> for ScalarMaybeUninit<Tag> {
+impl<Prov> From<Scalar<Prov>> for ScalarMaybeUninit<Prov> {
     #[inline(always)]
-    fn from(s: Scalar<Tag>) -> Self {
+    fn from(s: Scalar<Prov>) -> Self {
         ScalarMaybeUninit::Scalar(s)
     }
 }
 
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
 // all the Miri types.
-impl<Tag: Provenance> fmt::Debug for ScalarMaybeUninit<Tag> {
+impl<Prov: Provenance> fmt::Debug for ScalarMaybeUninit<Prov> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             ScalarMaybeUninit::Uninit => write!(f, "<uninitialized>"),
@@ -515,7 +516,7 @@ impl<Tag: Provenance> fmt::Debug for ScalarMaybeUninit<Tag> {
     }
 }
 
-impl<Tag: Provenance> fmt::LowerHex for ScalarMaybeUninit<Tag> {
+impl<Prov: Provenance> fmt::LowerHex for ScalarMaybeUninit<Prov> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"),
@@ -524,19 +525,19 @@ impl<Tag: Provenance> fmt::LowerHex for ScalarMaybeUninit<Tag> {
     }
 }
 
-impl<Tag> ScalarMaybeUninit<Tag> {
+impl<Prov> ScalarMaybeUninit<Prov> {
     #[inline]
-    pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
+    pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self {
         ScalarMaybeUninit::Scalar(Scalar::from_pointer(ptr, cx))
     }
 
     #[inline]
-    pub fn from_maybe_pointer(ptr: Pointer<Option<Tag>>, cx: &impl HasDataLayout) -> Self {
+    pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self {
         ScalarMaybeUninit::Scalar(Scalar::from_maybe_pointer(ptr, cx))
     }
 
     #[inline]
-    pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar<Tag>> {
+    pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar<Prov>> {
         match self {
             ScalarMaybeUninit::Scalar(scalar) => Ok(scalar),
             ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)),
@@ -544,7 +545,7 @@ impl<Tag> ScalarMaybeUninit<Tag> {
     }
 }
 
-impl<'tcx, Tag: Provenance> ScalarMaybeUninit<Tag> {
+impl<'tcx, Prov: Provenance> ScalarMaybeUninit<Prov> {
     #[inline(always)]
     pub fn to_bool(self) -> InterpResult<'tcx, bool> {
         self.check_init()?.to_bool()
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index f61cb7e8c47..702cc48ff7b 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1662,6 +1662,22 @@ impl SourceScope {
             ClearCrossCrate::Clear => None,
         }
     }
+
+    /// The instance this source scope was inlined from, if any.
+    #[inline]
+    pub fn inlined_instance<'tcx>(
+        self,
+        source_scopes: &IndexVec<SourceScope, SourceScopeData<'tcx>>,
+    ) -> Option<ty::Instance<'tcx>> {
+        let scope_data = &source_scopes[self];
+        if let Some((inlined_instance, _)) = scope_data.inlined {
+            Some(inlined_instance)
+        } else if let Some(inlined_scope) = scope_data.inlined_parent_scope {
+            Some(source_scopes[inlined_scope].inlined.unwrap().0)
+        } else {
+            None
+        }
+    }
 }
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 8b51c5b3da5..21ae121e1ce 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -362,7 +362,7 @@ impl<'tcx> CodegenUnit<'tcx> {
                             // the codegen tests and can even make item order
                             // unstable.
                             InstanceDef::Item(def) => def.did.as_local().map(Idx::index),
-                            InstanceDef::VtableShim(..)
+                            InstanceDef::VTableShim(..)
                             | InstanceDef::ReifyShim(..)
                             | InstanceDef::Intrinsic(..)
                             | InstanceDef::FnPtrShim(..)
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 970043d427f..78b5131bac6 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -720,11 +720,17 @@ pub fn write_allocations<'tcx>(
                 write!(w, "{}", display_allocation(tcx, alloc.inner()))
             };
         write!(w, "\n{id:?}")?;
-        match tcx.get_global_alloc(id) {
+        match tcx.try_get_global_alloc(id) {
             // This can't really happen unless there are bugs, but it doesn't cost us anything to
             // gracefully handle it and allow buggy rustc to be debugged via allocation printing.
             None => write!(w, " (deallocated)")?,
             Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?,
+            Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => {
+                write!(w, " (vtable: impl {trait_ref} for {ty})")?
+            }
+            Some(GlobalAlloc::VTable(ty, None)) => {
+                write!(w, " (vtable: impl <auto trait> for {ty})")?
+            }
             Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
                 match tcx.eval_static_initializer(did) {
                     Ok(alloc) => {
@@ -767,21 +773,21 @@ pub fn write_allocations<'tcx>(
 /// After the hex dump, an ascii dump follows, replacing all unprintable characters (control
 /// characters or characters whose value is larger than 127) with a `.`
 /// This also prints relocations adequately.
-pub fn display_allocation<'a, 'tcx, Tag, Extra>(
+pub fn display_allocation<'a, 'tcx, Prov, Extra>(
     tcx: TyCtxt<'tcx>,
-    alloc: &'a Allocation<Tag, Extra>,
-) -> RenderAllocation<'a, 'tcx, Tag, Extra> {
+    alloc: &'a Allocation<Prov, Extra>,
+) -> RenderAllocation<'a, 'tcx, Prov, Extra> {
     RenderAllocation { tcx, alloc }
 }
 
 #[doc(hidden)]
-pub struct RenderAllocation<'a, 'tcx, Tag, Extra> {
+pub struct RenderAllocation<'a, 'tcx, Prov, Extra> {
     tcx: TyCtxt<'tcx>,
-    alloc: &'a Allocation<Tag, Extra>,
+    alloc: &'a Allocation<Prov, Extra>,
 }
 
-impl<'a, 'tcx, Tag: Provenance, Extra> std::fmt::Display
-    for RenderAllocation<'a, 'tcx, Tag, Extra>
+impl<'a, 'tcx, Prov: Provenance, Extra> std::fmt::Display
+    for RenderAllocation<'a, 'tcx, Prov, Extra>
 {
     fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let RenderAllocation { tcx, alloc } = *self;
@@ -825,9 +831,9 @@ fn write_allocation_newline(
 /// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there
 /// is only one line). Note that your prefix should contain a trailing space as the lines are
 /// printed directly after it.
-fn write_allocation_bytes<'tcx, Tag: Provenance, Extra>(
+fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>(
     tcx: TyCtxt<'tcx>,
-    alloc: &Allocation<Tag, Extra>,
+    alloc: &Allocation<Prov, Extra>,
     w: &mut dyn std::fmt::Write,
     prefix: &str,
 ) -> std::fmt::Result {
@@ -861,7 +867,7 @@ fn write_allocation_bytes<'tcx, Tag: Provenance, Extra>(
         if i != line_start {
             write!(w, " ")?;
         }
-        if let Some(&tag) = alloc.relocations().get(&i) {
+        if let Some(&prov) = alloc.relocations().get(&i) {
             // Memory with a relocation must be defined
             assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok());
             let j = i.bytes_usize();
@@ -870,7 +876,7 @@ fn write_allocation_bytes<'tcx, Tag: Provenance, Extra>(
             let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap();
             let offset = Size::from_bytes(offset);
             let relocation_width = |bytes| bytes * 3;
-            let ptr = Pointer::new(tag, offset);
+            let ptr = Pointer::new(prov, offset);
             let mut target = format!("{:?}", ptr);
             if target.len() > relocation_width(ptr_size.bytes_usize() - 1) {
                 // This is too long, try to save some space.
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 423e84d88cf..dd9f8795f94 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -2,7 +2,7 @@
 
 use crate::mir::{Body, ConstantKind, Promoted};
 use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
-use rustc_data_structures::stable_map::FxHashMap;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs
index d1f3e6b6fe6..b91c0c25782 100644
--- a/compiler/rustc_middle/src/mir/switch_sources.rs
+++ b/compiler/rustc_middle/src/mir/switch_sources.rs
@@ -1,8 +1,8 @@
 //! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after
 //! `Predecessors`/`PredecessorCache`.
 
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::stable_map::FxHashMap;
 use rustc_data_structures::sync::OnceCell;
 use rustc_index::vec::IndexVec;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index d285728ec07..89160876401 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -394,7 +394,7 @@ macro_rules! make_mir_visitor {
                         ty::InstanceDef::Item(_def_id) => {}
 
                         ty::InstanceDef::Intrinsic(_def_id) |
-                        ty::InstanceDef::VtableShim(_def_id) |
+                        ty::InstanceDef::VTableShim(_def_id) |
                         ty::InstanceDef::ReifyShim(_def_id) |
                         ty::InstanceDef::Virtual(_def_id, _) |
                         ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 0581ef41f66..466a0fc25f7 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1634,11 +1634,15 @@ rustc_queries! {
         storage(ArenaCacheSelector<'tcx>)
         desc { "calculating the lib features map" }
     }
-    query defined_lib_features(_: CrateNum)
-        -> &'tcx [(Symbol, Option<Symbol>)] {
+    query defined_lib_features(_: CrateNum) -> &'tcx [(Symbol, Option<Symbol>)] {
         desc { "calculating the lib features defined in a crate" }
         separate_provide_extern
     }
+    query stability_implications(_: CrateNum) -> FxHashMap<Symbol, Symbol> {
+        storage(ArenaCacheSelector<'tcx>)
+        desc { "calculating the implications between `#[unstable]` features defined in a crate" }
+        separate_provide_extern
+    }
     /// Whether the function is an intrinsic
     query is_intrinsic(def_id: DefId) -> bool {
         desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 75559d4f8b8..c55971557fa 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -351,7 +351,7 @@ pub enum ObligationCauseCode<'tcx> {
     ConstPatternStructural,
 
     /// Computing common supertype in an if expression
-    IfExpression(Box<IfExpressionCause>),
+    IfExpression(Box<IfExpressionCause<'tcx>>),
 
     /// Computing common supertype of an if expression with no else counter-part
     IfExpressionWithNoElse,
@@ -488,22 +488,27 @@ impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
 pub struct MatchExpressionArmCause<'tcx> {
+    pub arm_block_id: Option<hir::HirId>,
+    pub arm_ty: Ty<'tcx>,
     pub arm_span: Span,
+    pub prior_arm_block_id: Option<hir::HirId>,
+    pub prior_arm_ty: Ty<'tcx>,
+    pub prior_arm_span: Span,
     pub scrut_span: Span,
-    pub semi_span: Option<(Span, StatementAsExpression)>,
     pub source: hir::MatchSource,
     pub prior_arms: Vec<Span>,
-    pub last_ty: Ty<'tcx>,
     pub scrut_hir_id: hir::HirId,
     pub opt_suggest_box_span: Option<Span>,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub struct IfExpressionCause {
-    pub then: Span,
-    pub else_sp: Span,
-    pub outer: Option<Span>,
-    pub semicolon: Option<(Span, StatementAsExpression)>,
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Lift, TypeFoldable, TypeVisitable)]
+pub struct IfExpressionCause<'tcx> {
+    pub then_id: hir::HirId,
+    pub else_id: hir::HirId,
+    pub then_ty: Ty<'tcx>,
+    pub else_ty: Ty<'tcx>,
+    pub outer_span: Option<Span>,
     pub opt_suggest_box_span: Option<Span>,
 }
 
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index 8f1a1564fc8..7fbd57ac735 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -130,7 +130,6 @@ impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDestructData<N> {
 // Lift implementations
 
 TrivialTypeTraversalAndLiftImpls! {
-    super::IfExpressionCause,
     super::ImplSourceDiscriminantKindData,
     super::ImplSourcePointeeData,
 }
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
index 8ce428c9799..d54b8c599d9 100644
--- a/compiler/rustc_middle/src/traits/util.rs
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 
 use crate::ty::{PolyTraitRef, TyCtxt};
 
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index e6ea3d88853..51137c52659 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -523,4 +523,5 @@ impl_binder_encode_decode! {
     ty::ExistentialPredicate<'tcx>,
     ty::TraitRef<'tcx>,
     Vec<ty::GeneratorInteriorTypeCause<'tcx>>,
+    ty::ExistentialTraitRef<'tcx>,
 }
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index 973dc3dd4a1..c7653bdbe84 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -88,19 +88,17 @@ impl<'tcx> ValTree<'tcx> {
                     let leafs = self
                         .unwrap_branch()
                         .into_iter()
-                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap())
-                        .collect::<Vec<_>>();
+                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap());
 
-                    return Some(tcx.arena.alloc_from_iter(leafs.into_iter()));
+                    return Some(tcx.arena.alloc_from_iter(leafs));
                 }
                 ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {
                     let leafs = self
                         .unwrap_branch()
                         .into_iter()
-                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap())
-                        .collect::<Vec<_>>();
+                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap());
 
-                    return Some(tcx.arena.alloc_from_iter(leafs.into_iter()));
+                    return Some(tcx.arena.alloc_from_iter(leafs));
                 }
                 _ => {}
             },
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 25bc6dc6167..dd2f4321060 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -3,7 +3,7 @@
 use std::ops::ControlFlow;
 
 use crate::ty::{
-    visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
+    visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy,
     PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
 };
 
@@ -82,15 +82,18 @@ pub trait IsSuggestable<'tcx> {
     /// meaningful rendered suggestions when pretty-printed. We leave some
     /// nonsense, such as region vars, since those render as `'_` and are
     /// usually okay to reinterpret as elided lifetimes.
-    fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool;
+    ///
+    /// Only if `infer_suggestable` is true, we consider type and const
+    /// inference variables to be suggestable.
+    fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
 }
 
 impl<'tcx, T> IsSuggestable<'tcx> for T
 where
     T: TypeVisitable<'tcx>,
 {
-    fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
-        self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue()
+    fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool {
+        self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
     }
 }
 
@@ -100,7 +103,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>(
     err: &mut Diagnostic,
     trait_pred: PolyTraitPredicate<'tcx>,
 ) -> bool {
-    if !trait_pred.is_suggestable(tcx) {
+    if !trait_pred.is_suggestable(tcx, false) {
         return false;
     }
 
@@ -419,6 +422,7 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
 
 pub struct IsSuggestableVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
+    infer_suggestable: bool,
 }
 
 impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
@@ -426,6 +430,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
+            Infer(InferTy::TyVar(_)) if self.infer_suggestable => {}
+
             FnDef(..)
             | Closure(..)
             | Infer(..)
@@ -479,6 +485,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
 
     fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         match c.kind() {
+            ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {}
+
             ConstKind::Infer(..)
             | ConstKind::Bound(..)
             | ConstKind::Placeholder(..)
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index 88397a2bb56..263d64a5777 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -147,15 +147,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
         ty::tls::with_opt(|tcx| {
             trace!("hashing {:?}", *self);
             let tcx = tcx.expect("can't hash AllocIds during hir lowering");
-            tcx.get_global_alloc(*self).hash_stable(hcx, hasher);
+            tcx.try_get_global_alloc(*self).hash_stable(hcx, hasher);
         });
     }
 }
 
 // `Relocations` with default type parameters is a sorted map.
-impl<'a, Tag> HashStable<StableHashingContext<'a>> for mir::interpret::Relocations<Tag>
+impl<'a, Prov> HashStable<StableHashingContext<'a>> for mir::interpret::Relocations<Prov>
 where
-    Tag: HashStable<StableHashingContext<'a>>,
+    Prov: HashStable<StableHashingContext<'a>>,
 {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         self.len().hash_stable(hcx, hasher);
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 4f9bbc135ec..33a46f809b0 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -49,7 +49,7 @@ pub enum InstanceDef<'tcx> {
     ///
     /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` -
     /// and dereference the argument to call the original function.
-    VtableShim(DefId),
+    VTableShim(DefId),
 
     /// `fn()` pointer where the function itself cannot be turned into a pointer.
     ///
@@ -145,7 +145,7 @@ impl<'tcx> InstanceDef<'tcx> {
     pub fn def_id(self) -> DefId {
         match self {
             InstanceDef::Item(def) => def.did,
-            InstanceDef::VtableShim(def_id)
+            InstanceDef::VTableShim(def_id)
             | InstanceDef::ReifyShim(def_id)
             | InstanceDef::FnPtrShim(def_id, _)
             | InstanceDef::Virtual(def_id, _)
@@ -161,7 +161,7 @@ impl<'tcx> InstanceDef<'tcx> {
         match self {
             ty::InstanceDef::Item(def) => Some(def.did),
             ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id),
-            InstanceDef::VtableShim(..)
+            InstanceDef::VTableShim(..)
             | InstanceDef::ReifyShim(..)
             | InstanceDef::FnPtrShim(..)
             | InstanceDef::Virtual(..)
@@ -176,7 +176,7 @@ impl<'tcx> InstanceDef<'tcx> {
     pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
         match self {
             InstanceDef::Item(def) => def,
-            InstanceDef::VtableShim(def_id)
+            InstanceDef::VTableShim(def_id)
             | InstanceDef::ReifyShim(def_id)
             | InstanceDef::FnPtrShim(def_id, _)
             | InstanceDef::Virtual(def_id, _)
@@ -273,7 +273,7 @@ impl<'tcx> InstanceDef<'tcx> {
             | InstanceDef::Intrinsic(..)
             | InstanceDef::ReifyShim(..)
             | InstanceDef::Virtual(..)
-            | InstanceDef::VtableShim(..) => true,
+            | InstanceDef::VTableShim(..) => true,
         }
     }
 }
@@ -290,7 +290,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
 
         match self.def {
             InstanceDef::Item(_) => Ok(()),
-            InstanceDef::VtableShim(_) => write!(f, " - shim(vtable)"),
+            InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"),
             InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
             InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
             InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num),
@@ -434,7 +434,7 @@ impl<'tcx> Instance<'tcx> {
             && tcx.generics_of(def_id).has_self;
         if is_vtable_shim {
             debug!(" => associated item with unsizeable self: Self");
-            Some(Instance { def: InstanceDef::VtableShim(def_id), substs })
+            Some(Instance { def: InstanceDef::VTableShim(def_id), substs })
         } else {
             Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| {
                 match resolved.def {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index c41a8318ec5..dde55dd9655 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2618,14 +2618,14 @@ where
                     // Use conservative pointer kind if not optimizing. This saves us the
                     // Freeze/Unpin queries, and can save time in the codegen backend (noalias
                     // attributes in LLVM have compile-time cost even in unoptimized builds).
-                    PointerKind::Shared
+                    PointerKind::SharedMutable
                 } else {
                     match mt {
                         hir::Mutability::Not => {
                             if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) {
                                 PointerKind::Frozen
                             } else {
-                                PointerKind::Shared
+                                PointerKind::SharedMutable
                             }
                         }
                         hir::Mutability::Mut => {
@@ -2636,7 +2636,7 @@ where
                             if ty.is_unpin(tcx.at(DUMMY_SP), cx.param_env()) {
                                 PointerKind::UniqueBorrowed
                             } else {
-                                PointerKind::Shared
+                                PointerKind::UniqueBorrowedPinned
                             }
                         }
                     }
@@ -2771,7 +2771,7 @@ impl<'tcx> ty::Instance<'tcx> {
                     _ => unreachable!(),
                 };
 
-                if let ty::InstanceDef::VtableShim(..) = self.def {
+                if let ty::InstanceDef::VTableShim(..) = self.def {
                     // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
                     sig = sig.map_bound(|mut sig| {
                         let mut inputs_and_output = sig.inputs_and_output.to_vec();
@@ -3255,10 +3255,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                     // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
                     // for the entire duration of the function as they can be deallocated
-                    // at any time. Set their valid size to 0.
+                    // at any time. Same for shared mutable references. If LLVM had a
+                    // way to say "dereferenceable on entry" we could use it here.
                     attrs.pointee_size = match kind {
-                        PointerKind::UniqueOwned => Size::ZERO,
-                        _ => pointee.size,
+                        PointerKind::UniqueBorrowed
+                        | PointerKind::UniqueBorrowedPinned
+                        | PointerKind::Frozen => pointee.size,
+                        PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
                     };
 
                     // `Box`, `&T`, and `&mut T` cannot be undef.
@@ -3266,7 +3269,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     // this attribute doesn't make it UB for the pointed-to data to be undef.
                     attrs.set(ArgAttribute::NoUndef);
 
-                    // `Box` pointer parameters never alias because ownership is transferred
+                    // The aliasing rules for `Box<T>` are still not decided, but currently we emit
+                    // `noalias` for it. This can be turned off using an unstable flag.
+                    // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
+                    let noalias_for_box =
+                        self.tcx().sess.opts.unstable_opts.box_noalias.unwrap_or(true);
+
                     // `&mut` pointer parameters never alias other parameters,
                     // or mutable global data
                     //
@@ -3280,8 +3288,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     // or not to actually emit the attribute. It can also be controlled with the
                     // `-Zmutable-noalias` debugging option.
                     let no_alias = match kind {
-                        PointerKind::Shared | PointerKind::UniqueBorrowed => false,
-                        PointerKind::UniqueOwned => true,
+                        PointerKind::SharedMutable
+                        | PointerKind::UniqueBorrowed
+                        | PointerKind::UniqueBorrowedPinned => false,
+                        PointerKind::UniqueOwned => noalias_for_box,
                         PointerKind::Frozen => !is_return,
                     };
                     if no_alias {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 53919826bf6..281a1265546 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -575,6 +575,19 @@ impl<'tcx> Predicate<'tcx> {
 
         Some(tcx.mk_predicate(kind))
     }
+
+    pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self {
+        if let PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) = self.kind().skip_binder()
+            && constness != BoundConstness::NotConst
+        {
+            self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Trait(TraitPredicate {
+                trait_ref,
+                constness: BoundConstness::NotConst,
+                polarity,
+            })));
+        }
+        self
+    }
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
@@ -790,22 +803,15 @@ pub struct TraitPredicate<'tcx> {
 pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
 
 impl<'tcx> TraitPredicate<'tcx> {
-    pub fn remap_constness(&mut self, tcx: TyCtxt<'tcx>, param_env: &mut ParamEnv<'tcx>) {
-        if std::intrinsics::unlikely(Some(self.trait_ref.def_id) == tcx.lang_items().drop_trait()) {
-            // remap without changing constness of this predicate.
-            // this is because `T: ~const Drop` has a different meaning to `T: Drop`
-            // FIXME(fee1-dead): remove this logic after beta bump
-            param_env.remap_constness_with(self.constness)
-        } else {
-            *param_env = param_env.with_constness(self.constness.and(param_env.constness()))
-        }
+    pub fn remap_constness(&mut self, param_env: &mut ParamEnv<'tcx>) {
+        *param_env = param_env.with_constness(self.constness.and(param_env.constness()))
     }
 
     /// Remap the constness of this predicate before emitting it for diagnostics.
     pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) {
         // this is different to `remap_constness` that callees want to print this predicate
         // in case of selection errors. `T: ~const Drop` bounds cannot end up here when the
-        // param_env is not const because we it is always satisfied in non-const contexts.
+        // param_env is not const because it is always satisfied in non-const contexts.
         if let hir::Constness::NotConst = param_env.constness() {
             self.constness = ty::BoundConstness::NotConst;
         }
@@ -2135,7 +2141,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     }
                 }
             }
-            ty::InstanceDef::VtableShim(..)
+            ty::InstanceDef::VTableShim(..)
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::Intrinsic(..)
             | ty::InstanceDef::FnPtrShim(..)
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 96e84bc8f0a..03bb515904c 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1269,7 +1269,7 @@ pub trait PrettyPrinter<'tcx>:
                 if let ty::Array(elem, len) = inner.kind() {
                     if let ty::Uint(ty::UintTy::U8) = elem.kind() {
                         if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() {
-                            match self.tcx().get_global_alloc(alloc_id) {
+                            match self.tcx().try_get_global_alloc(alloc_id) {
                                 Some(GlobalAlloc::Memory(alloc)) => {
                                     let len = int.assert_bits(self.tcx().data_layout.pointer_size);
                                     let range =
@@ -1282,11 +1282,12 @@ pub trait PrettyPrinter<'tcx>:
                                         p!("<too short allocation>")
                                     }
                                 }
-                                // FIXME: for statics and functions, we could in principle print more detail.
+                                // FIXME: for statics, vtables, and functions, we could in principle print more detail.
                                 Some(GlobalAlloc::Static(def_id)) => {
                                     p!(write("<static({:?})>", def_id))
                                 }
                                 Some(GlobalAlloc::Function(_)) => p!("<function>"),
+                                Some(GlobalAlloc::VTable(..)) => p!("<vtable>"),
                                 None => p!("<dangling pointer>"),
                             }
                             return Ok(self);
@@ -1297,7 +1298,8 @@ pub trait PrettyPrinter<'tcx>:
             ty::FnPtr(_) => {
                 // FIXME: We should probably have a helper method to share code with the "Byte strings"
                 // printing above (which also has to handle pointers to all sorts of things).
-                if let Some(GlobalAlloc::Function(instance)) = self.tcx().get_global_alloc(alloc_id)
+                if let Some(GlobalAlloc::Function(instance)) =
+                    self.tcx().try_get_global_alloc(alloc_id)
                 {
                     self = self.typed_value(
                         |this| this.print_value_path(instance.def_id(), instance.substs),
@@ -1377,9 +1379,9 @@ pub trait PrettyPrinter<'tcx>:
 
     /// This is overridden for MIR printing because we only want to hide alloc ids from users, not
     /// from MIR where it is actually useful.
-    fn pretty_print_const_pointer<Tag: Provenance>(
+    fn pretty_print_const_pointer<Prov: Provenance>(
         mut self,
-        _: Pointer<Tag>,
+        _: Pointer<Prov>,
         ty: Ty<'tcx>,
         print_ty: bool,
     ) -> Result<Self::Const, Self::Error> {
@@ -1727,7 +1729,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
     }
 
     fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
-        self.pretty_print_const(ct, true)
+        self.pretty_print_const(ct, false)
     }
 
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
@@ -1952,9 +1954,9 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
         }
     }
 
-    fn pretty_print_const_pointer<Tag: Provenance>(
+    fn pretty_print_const_pointer<Prov: Provenance>(
         self,
-        p: Pointer<Tag>,
+        p: Pointer<Prov>,
         ty: Ty<'tcx>,
         print_ty: bool,
     ) -> Result<Self::Const, Self::Error> {
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 391a0a20c96..a4be3d02d19 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -624,7 +624,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         match self {
             ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)),
-            ty::InstanceDef::VtableShim(def_id) => Some(ty::InstanceDef::VtableShim(def_id)),
+            ty::InstanceDef::VTableShim(def_id) => Some(ty::InstanceDef::VTableShim(def_id)),
             ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)),
             ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)),
             ty::InstanceDef::FnPtrShim(def_id, ty) => {
@@ -927,7 +927,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
             substs: self.substs.try_fold_with(folder)?,
             def: match self.def {
                 Item(def) => Item(def.try_fold_with(folder)?),
-                VtableShim(did) => VtableShim(did.try_fold_with(folder)?),
+                VTableShim(did) => VTableShim(did.try_fold_with(folder)?),
                 ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?),
                 Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?),
                 FnPtrShim(did, ty) => {
@@ -954,7 +954,7 @@ impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> {
         self.substs.visit_with(visitor)?;
         match self.def {
             Item(def) => def.visit_with(visitor),
-            VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
+            VTableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
                 did.visit_with(visitor)
             }
             FnPtrShim(did, ty) | CloneShim(did, ty) => {
diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs
index ec2e516f7ac..2ab7eddcac9 100644
--- a/compiler/rustc_mir_dataflow/src/un_derefer.rs
+++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::stable_map::FxHashMap;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 2fd026b1bca..f6484a9b54d 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -234,9 +234,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     }
 
     fn access_local<'a>(
-        frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
+        frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
         local: Local,
-    ) -> InterpResult<'tcx, &'a interpret::Operand<Self::PointerTag>> {
+    ) -> InterpResult<'tcx, &'a interpret::Operand<Self::Provenance>> {
         let l = &frame.locals[local];
 
         if matches!(
@@ -255,7 +255,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
         frame: usize,
         local: Local,
-    ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::PointerTag>> {
+    ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::Provenance>> {
         if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
             throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
         }
@@ -274,7 +274,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         _tcx: TyCtxt<'tcx>,
         _machine: &Self,
         _alloc_id: AllocId,
-        alloc: ConstAllocation<'tcx, Self::PointerTag, Self::AllocExtra>,
+        alloc: ConstAllocation<'tcx, Self::Provenance, Self::AllocExtra>,
         _static_def_id: Option<DefId>,
         is_write: bool,
     ) -> InterpResult<'tcx> {
@@ -309,14 +309,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     #[inline(always)]
     fn stack<'a>(
         ecx: &'a InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
+    ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] {
         &ecx.machine.stack
     }
 
     #[inline(always)]
     fn stack_mut<'a>(
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
+    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
         &mut ecx.machine.stack
     }
 }
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 9c843f11c1e..97b1433f5d2 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -230,9 +230,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     }
 
     fn access_local<'a>(
-        frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
+        frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
         local: Local,
-    ) -> InterpResult<'tcx, &'a interpret::Operand<Self::PointerTag>> {
+    ) -> InterpResult<'tcx, &'a interpret::Operand<Self::Provenance>> {
         let l = &frame.locals[local];
 
         if matches!(
@@ -251,7 +251,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
         frame: usize,
         local: Local,
-    ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::PointerTag>> {
+    ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::Provenance>> {
         if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
             throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
         }
@@ -270,7 +270,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         _tcx: TyCtxt<'tcx>,
         _machine: &Self,
         _alloc_id: AllocId,
-        alloc: ConstAllocation<'tcx, Self::PointerTag, Self::AllocExtra>,
+        alloc: ConstAllocation<'tcx, Self::Provenance, Self::AllocExtra>,
         _static_def_id: Option<DefId>,
         is_write: bool,
     ) -> InterpResult<'tcx> {
@@ -305,14 +305,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     #[inline(always)]
     fn stack<'a>(
         ecx: &'a InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
+    ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] {
         &ecx.machine.stack
     }
 
     #[inline(always)]
     fn stack_mut<'a>(
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
+    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
         &mut ecx.machine.stack
     }
 }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index dc5d5cee879..1e46b0a0e81 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -246,7 +246,7 @@ impl<'tcx> Inliner<'tcx> {
             // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we
             // do not need to catch this here, we can wait until the inliner decides to continue
             // inlining a second time.
-            InstanceDef::VtableShim(_)
+            InstanceDef::VTableShim(_)
             | InstanceDef::ReifyShim(_)
             | InstanceDef::FnPtrShim(..)
             | InstanceDef::ClosureOnceShim { .. }
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index a3a35f95071..7810218fd67 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -79,7 +79,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
                 // These have MIR and if that MIR is inlined, substituted and then inlining is run
                 // again, a function item can end up getting inlined. Thus we'll be able to cause
                 // a cycle that way
-                InstanceDef::VtableShim(_)
+                InstanceDef::VTableShim(_)
                 | InstanceDef::ReifyShim(_)
                 | InstanceDef::FnPtrShim(..)
                 | InstanceDef::ClosureOnceShim { .. }
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index eaa61d8614d..3620e94bec7 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -32,7 +32,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
 
     let mut result = match instance {
         ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
-        ty::InstanceDef::VtableShim(def_id) => {
+        ty::InstanceDef::VTableShim(def_id) => {
             build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id))
         }
         ty::InstanceDef::FnPtrShim(def_id, ty) => {
@@ -113,7 +113,7 @@ enum Adjustment {
     /// We get passed `&[mut] self` and call the target with `*self`.
     ///
     /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
-    /// (for `VtableShim`, which effectively is passed `&own Self`).
+    /// (for `VTableShim`, which effectively is passed `&own Self`).
     Deref,
 
     /// We get passed `self: Self` and call the target with `&mut self`.
@@ -569,7 +569,7 @@ fn build_call_shim<'tcx>(
 
     // FIXME(eddyb) avoid having this snippet both here and in
     // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
-    if let ty::InstanceDef::VtableShim(..) = instance {
+    if let ty::InstanceDef::VTableShim(..) = instance {
         // Modify fn(self, ...) to fn(self: *mut Self, ...)
         let mut inputs_and_output = sig.inputs_and_output.to_vec();
         let self_arg = &mut inputs_and_output[0];
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 980af984362..d305960b485 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -28,6 +28,7 @@
 //! return.
 
 use crate::MirPass;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@@ -267,7 +268,8 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         return;
     }
 
-    let basic_blocks = body.basic_blocks_mut();
+    let basic_blocks = body.basic_blocks.as_mut();
+    let source_scopes = &body.source_scopes;
     let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
     let mut used_blocks = 0;
     for alive_index in reachable.iter() {
@@ -282,7 +284,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     }
 
     if tcx.sess.instrument_coverage() {
-        save_unreachable_coverage(basic_blocks, used_blocks);
+        save_unreachable_coverage(basic_blocks, source_scopes, used_blocks);
     }
 
     basic_blocks.raw.truncate(used_blocks);
@@ -311,56 +313,62 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 /// `Unreachable` coverage statements. These are non-executable statements whose
 /// code regions are still recorded in the coverage map, representing regions
 /// with `0` executions.
+///
+/// If there are no live `Counter` `Coverage` statements remaining, we remove
+/// dead `Coverage` statements along with the dead blocks. Since at least one
+/// counter per function is required by LLVM (and necessary, to add the
+/// `function_hash` to the counter's call to the LLVM intrinsic
+/// `instrprof.increment()`).
+///
+/// The `generator::StateTransform` MIR pass and MIR inlining can create
+/// atypical conditions, where all live `Counter`s are dropped from the MIR.
+///
+/// With MIR inlining we can have coverage counters belonging to different
+/// instances in a single body, so the strategy described above is applied to
+/// coverage counters from each instance individually.
 fn save_unreachable_coverage(
     basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+    source_scopes: &IndexVec<SourceScope, SourceScopeData<'_>>,
     first_dead_block: usize,
 ) {
-    let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| {
-        live_block.statements.iter().any(|statement| {
-            if let StatementKind::Coverage(coverage) = &statement.kind {
-                matches!(coverage.kind, CoverageKind::Counter { .. })
-            } else {
-                false
-            }
-        })
-    });
-    if !has_live_counters {
-        // If there are no live `Counter` `Coverage` statements anymore, don't
-        // move dead coverage to the `START_BLOCK`. Just allow the dead
-        // `Coverage` statements to be dropped with the dead blocks.
-        //
-        // The `generator::StateTransform` MIR pass can create atypical
-        // conditions, where all live `Counter`s are dropped from the MIR.
-        //
-        // At least one Counter per function is required by LLVM (and necessary,
-        // to add the `function_hash` to the counter's call to the LLVM
-        // intrinsic `instrprof.increment()`).
+    // Identify instances that still have some live coverage counters left.
+    let mut live = FxHashSet::default();
+    for basic_block in &basic_blocks.raw[0..first_dead_block] {
+        for statement in &basic_block.statements {
+            let StatementKind::Coverage(coverage) = &statement.kind else { continue };
+            let CoverageKind::Counter { .. } = coverage.kind else { continue };
+            let instance = statement.source_info.scope.inlined_instance(source_scopes);
+            live.insert(instance);
+        }
+    }
+
+    if live.is_empty() {
         return;
     }
 
-    // Retain coverage info for dead blocks, so coverage reports will still
-    // report `0` executions for the uncovered code regions.
-    let mut dropped_coverage = Vec::new();
-    for dead_block in basic_blocks.raw[first_dead_block..].iter() {
-        for statement in dead_block.statements.iter() {
-            if let StatementKind::Coverage(coverage) = &statement.kind {
-                if let Some(code_region) = &coverage.code_region {
-                    dropped_coverage.push((statement.source_info, code_region.clone()));
-                }
+    // Retain coverage for instances that still have some live counters left.
+    let mut retained_coverage = Vec::new();
+    for dead_block in &basic_blocks.raw[first_dead_block..] {
+        for statement in &dead_block.statements {
+            let StatementKind::Coverage(coverage) = &statement.kind else { continue };
+            let Some(code_region) = &coverage.code_region else { continue };
+            let instance = statement.source_info.scope.inlined_instance(source_scopes);
+            if live.contains(&instance) {
+                retained_coverage.push((statement.source_info, code_region.clone()));
             }
         }
     }
 
     let start_block = &mut basic_blocks[START_BLOCK];
-    for (source_info, code_region) in dropped_coverage {
-        start_block.statements.push(Statement {
+    start_block.statements.extend(retained_coverage.into_iter().map(
+        |(source_info, code_region)| Statement {
             source_info,
             kind: StatementKind::Coverage(Box::new(Coverage {
                 kind: CoverageKind::Unreachable,
                 code_region: Some(code_region),
             })),
-        })
-    }
+        },
+    ));
 }
 
 pub struct SimplifyLocals;
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index bd196f11879..30be64f5b2f 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -1,7 +1,7 @@
 //! A pass that eliminates branches on uninhabited enum variants.
 
 use crate::MirPass;
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::{
     BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, Terminator,
     TerminatorKind,
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index e3cfb034e40..68b65658c72 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -25,7 +25,7 @@
 //! codegen unit:
 //!
 //! - Constants
-//! - Vtables
+//! - VTables
 //! - Object Shims
 //!
 //!
@@ -992,7 +992,7 @@ fn visit_instance_use<'tcx>(
             }
         }
         ty::InstanceDef::DropGlue(_, Some(_))
-        | ty::InstanceDef::VtableShim(..)
+        | ty::InstanceDef::VTableShim(..)
         | ty::InstanceDef::ReifyShim(..)
         | ty::InstanceDef::ClosureOnceShim { .. }
         | ty::InstanceDef::Item(..)
@@ -1427,6 +1427,10 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte
                 output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP));
             }
         }
+        GlobalAlloc::VTable(ty, trait_ref) => {
+            let alloc_id = tcx.vtable_allocation((ty, trait_ref));
+            collect_miri(tcx, alloc_id, output)
+        }
     }
 }
 
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index d18b1c26c17..15276569c32 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -271,7 +271,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
         MonoItem::Fn(instance) => {
             let def_id = match instance.def {
                 ty::InstanceDef::Item(def) => def.did,
-                ty::InstanceDef::VtableShim(..)
+                ty::InstanceDef::VTableShim(..)
                 | ty::InstanceDef::ReifyShim(..)
                 | ty::InstanceDef::FnPtrShim(..)
                 | ty::InstanceDef::ClosureOnceShim { .. }
@@ -425,7 +425,7 @@ fn mono_item_visibility<'tcx>(
         InstanceDef::DropGlue(def_id, Some(_)) => def_id,
 
         // These are all compiler glue and such, never exported, always hidden.
-        InstanceDef::VtableShim(..)
+        InstanceDef::VTableShim(..)
         | InstanceDef::ReifyShim(..)
         | InstanceDef::FnPtrShim(..)
         | InstanceDef::Virtual(..)
diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs
index 36243803f99..ff2d3869328 100644
--- a/compiler/rustc_monomorphize/src/partitioning/mod.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs
@@ -98,6 +98,7 @@ mod merging;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync;
 use rustc_hir::def_id::DefIdSet;
+use rustc_middle::mir;
 use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::mir::mono::{CodegenUnit, Linkage};
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -479,9 +480,14 @@ fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSe
                 if !visited.insert(did) {
                     continue;
                 }
-                for scope in &tcx.instance_mir(instance.def).source_scopes {
-                    if let Some((ref inlined, _)) = scope.inlined {
-                        result.insert(inlined.def_id());
+                let body = tcx.instance_mir(instance.def);
+                for block in body.basic_blocks() {
+                    for statement in &block.statements {
+                        let mir::StatementKind::Coverage(_) = statement.kind else { continue };
+                        let scope = statement.source_info.scope;
+                        if let Some(inlined) = scope.inlined_instance(&body.source_scopes) {
+                            result.insert(inlined.def_id());
+                        }
                     }
                 }
             }
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index f6fa19030ac..6e7553f5e49 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -572,9 +572,10 @@ impl<'a> Parser<'a> {
             // '0' flag and then an ill-formatted format string with just a '$'
             // and no count, but this is better if we instead interpret this as
             // no '0' flag and '0$' as the width instead.
-            if self.consume('$') {
+            if let Some(end) = self.consume_pos('$') {
                 spec.width = CountIsParam(0);
                 havewidth = true;
+                spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1)));
             } else {
                 spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
             }
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index c9667922ee7..9c305b4996a 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -179,6 +179,23 @@ fn format_counts() {
         })],
     );
     same(
+        "{1:0$.10x}",
+        &[NextArgument(Argument {
+            position: ArgumentIs(1),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIs(10),
+                width: CountIsParam(0),
+                precision_span: None,
+                width_span: Some(InnerSpan::new(4, 6)),
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
         "{:.*x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(1),
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 26bfa4737a7..e05994f13e4 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -1,8 +1,8 @@
-// Detecting lib features (i.e., features that are not lang features).
-//
-// These are declared using stability attributes (e.g., `#[stable (..)]`
-// and `#[unstable (..)]`), but are not declared in one single location
-// (unlike lang features), which means we need to collect them instead.
+//! Detecting lib features (i.e., features that are not lang features).
+//!
+//! These are declared using stability attributes (e.g., `#[stable (..)]` and `#[unstable (..)]`),
+//! but are not declared in one single location (unlike lang features), which means we need to
+//! collect them instead.
 
 use rustc_ast::{Attribute, MetaItemKind};
 use rustc_errors::struct_span_err;
@@ -71,11 +71,11 @@ impl<'tcx> LibFeatureCollector<'tcx> {
 
     fn collect_feature(&mut self, feature: Symbol, since: Option<Symbol>, span: Span) {
         let already_in_stable = self.lib_features.stable.contains_key(&feature);
-        let already_in_unstable = self.lib_features.unstable.contains(&feature);
+        let already_in_unstable = self.lib_features.unstable.contains_key(&feature);
 
         match (since, already_in_stable, already_in_unstable) {
             (Some(since), _, false) => {
-                if let Some(prev_since) = self.lib_features.stable.get(&feature) {
+                if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
                     if *prev_since != since {
                         self.span_feature_error(
                             span,
@@ -89,10 +89,10 @@ impl<'tcx> LibFeatureCollector<'tcx> {
                     }
                 }
 
-                self.lib_features.stable.insert(feature, since);
+                self.lib_features.stable.insert(feature, (since, span));
             }
             (None, false, _) => {
-                self.lib_features.unstable.insert(feature);
+                self.lib_features.unstable.insert(feature, span);
             }
             (Some(_), _, true) | (None, true, _) => {
                 self.span_feature_error(
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 4e091c5b70d..81b04c414ed 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -2,9 +2,9 @@
 //! propagating default levels lexically from parent to children ast nodes.
 
 use attr::StabilityLevel;
-use rustc_attr::{self as attr, ConstStability, Stability};
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
-use rustc_errors::struct_span_err;
+use rustc_attr::{self as attr, ConstStability, Stability, Unstable};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -29,13 +29,13 @@ use std::num::NonZeroU32;
 
 #[derive(PartialEq)]
 enum AnnotationKind {
-    // Annotation is required if not inherited from unstable parents
+    /// Annotation is required if not inherited from unstable parents.
     Required,
-    // Annotation is useless, reject it
+    /// Annotation is useless, reject it.
     Prohibited,
-    // Deprecation annotation is useless, reject it. (Stability attribute is still required.)
+    /// Deprecation annotation is useless, reject it. (Stability attribute is still required.)
     DeprecationProhibited,
-    // Annotation itself is useless, but it can be propagated to children
+    /// Annotation itself is useless, but it can be propagated to children.
     Container,
 }
 
@@ -83,7 +83,7 @@ impl InheritStability {
     }
 }
 
-// A private tree-walker for producing an Index.
+/// A private tree-walker for producing an `Index`.
 struct Annotator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     index: &'a mut Index,
@@ -94,9 +94,9 @@ struct Annotator<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Annotator<'a, 'tcx> {
-    // Determine the stability for a node based on its attributes and inherited
-    // stability. The stability is recorded in the index and used as the parent.
-    // If the node is a function, `fn_sig` is its signature
+    /// Determine the stability for a node based on its attributes and inherited stability. The
+    /// stability is recorded in the index and used as the parent. If the node is a function,
+    /// `fn_sig` is its signature.
     fn annotate<F>(
         &mut self,
         def_id: LocalDefId,
@@ -265,6 +265,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 }
             }
 
+            if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab {
+                self.index.implications.insert(implied_by, feature);
+            }
+
             self.index.stab_map.insert(def_id, stab);
             stab
         });
@@ -610,6 +614,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
         stab_map: Default::default(),
         const_stab_map: Default::default(),
         depr_map: Default::default(),
+        implications: Default::default(),
     };
 
     {
@@ -637,6 +642,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
                     reason: Some(Symbol::intern(reason)),
                     issue: NonZeroU32::new(27812),
                     is_soft: false,
+                    implied_by: None,
                 },
                 feature: sym::rustc_private,
             };
@@ -667,6 +673,7 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         check_mod_unstable_api_usage,
         stability_index,
+        stability_implications: |tcx, _| tcx.stability().implications.clone(),
         lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
         lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
         lookup_deprecation_entry: |tcx, id| {
@@ -945,32 +952,51 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     remaining_lib_features.remove(&sym::libc);
     remaining_lib_features.remove(&sym::test);
 
-    let check_features = |remaining_lib_features: &mut FxIndexMap<_, _>, defined_features: &[_]| {
-        for &(feature, since) in defined_features {
-            if let Some(since) = since {
-                if let Some(span) = remaining_lib_features.get(&feature) {
-                    // Warn if the user has enabled an already-stable lib feature.
-                    unnecessary_stable_feature_lint(tcx, *span, feature, since);
-                }
-            }
-            remaining_lib_features.remove(&feature);
-            if remaining_lib_features.is_empty() {
-                break;
-            }
-        }
-    };
-
     // We always collect the lib features declared in the current crate, even if there are
     // no unknown features, because the collection also does feature attribute validation.
-    let local_defined_features = tcx.lib_features(()).to_vec();
-    if !remaining_lib_features.is_empty() {
-        check_features(&mut remaining_lib_features, &local_defined_features);
+    let local_defined_features = tcx.lib_features(());
+    let mut all_lib_features: FxHashMap<_, _> =
+        local_defined_features.to_vec().iter().map(|el| *el).collect();
+    let mut implications = tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE).clone();
+    for &cnum in tcx.crates(()) {
+        implications.extend(tcx.stability_implications(cnum));
+        all_lib_features.extend(tcx.defined_lib_features(cnum).iter().map(|el| *el));
+    }
 
-        for &cnum in tcx.crates(()) {
+    // Check that every feature referenced by an `implied_by` exists (for features defined in the
+    // local crate).
+    for (implied_by, feature) in tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE) {
+        // Only `implied_by` needs to be checked, `feature` is guaranteed to exist.
+        if !all_lib_features.contains_key(implied_by) {
+            let span = local_defined_features
+                .stable
+                .get(feature)
+                .map(|(_, span)| span)
+                .or_else(|| local_defined_features.unstable.get(feature))
+                .expect("feature that implied another does not exist");
+            tcx.sess
+                .struct_span_err(
+                    *span,
+                    format!("feature `{implied_by}` implying `{feature}` does not exist"),
+                )
+                .emit();
+        }
+    }
+
+    if !remaining_lib_features.is_empty() {
+        for (feature, since) in all_lib_features.iter() {
+            if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) {
+                // Warn if the user has enabled an already-stable lib feature.
+                if let Some(implies) = implications.get(&feature) {
+                    unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since);
+                } else {
+                    unnecessary_stable_feature_lint(tcx, *span, *feature, *since);
+                }
+            }
+            remaining_lib_features.remove(&feature);
             if remaining_lib_features.is_empty() {
                 break;
             }
-            check_features(&mut remaining_lib_features, tcx.defined_lib_features(cnum));
         }
     }
 
@@ -982,12 +1008,41 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     // don't lint about unused features. We should re-enable this one day!
 }
 
+fn unnecessary_partially_stable_feature_lint(
+    tcx: TyCtxt<'_>,
+    span: Span,
+    feature: Symbol,
+    implies: Symbol,
+    since: Symbol,
+) {
+    tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
+        lint.build(&format!(
+            "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
+             by the feature `{implies}`"
+        ))
+        .span_suggestion(
+            span,
+            &format!(
+                "if you are using features which are still unstable, change to using `{implies}`"
+            ),
+            implies,
+            Applicability::MaybeIncorrect,
+        )
+        .span_suggestion(
+            tcx.sess.source_map().span_extend_to_line(span),
+            "if you are using features which are now stable, remove this line",
+            "",
+            Applicability::MaybeIncorrect,
+        )
+        .emit();
+    });
+}
+
 fn unnecessary_stable_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol, since: Symbol) {
     tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
         lint.build(&format!(
-            "the feature `{}` has been stable since {} and no longer requires \
-                      an attribute to enable",
-            feature, since
+            "the feature `{feature}` has been stable since {since} and no longer requires an \
+             attribute to enable",
         ))
         .emit();
     });
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 3291be05807..c48b4ecf87a 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -68,7 +68,7 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
         }
     }
 
-    for (name, item) in WEAK_ITEMS_REFS.clone().into_sorted_vector().into_iter() {
+    for (name, &item) in WEAK_ITEMS_REFS.iter() {
         if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
             if item == LangItem::PanicImpl {
                 tcx.sess.err("`#[panic_handler]` function required, but not found");
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 9a835808d49..390d6f5a856 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1754,7 +1754,6 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                 || self.in_assoc_ty
                 || self.tcx.resolutions(()).has_pub_restricted
             {
-                let descr = descr.to_string();
                 let vis_span =
                     self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
                 if kind == "trait" {
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 7c1fdc4e306..eda61df7700 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -37,7 +37,7 @@ mod values;
 use self::values::Value;
 
 pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::{QueryDescription, QueryVtable};
+pub(crate) use rustc_query_system::query::{QueryDescription, QueryVTable};
 
 mod on_disk_cache;
 pub use on_disk_cache::OnDiskCache;
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 333dc5aa668..eda4401c81d 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -340,11 +340,11 @@ macro_rules! define_queries {
 
             #[inline]
             fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
-                QueryVtable<QueryCtxt<$tcx>, Self::Key, Self::Value>
+                QueryVTable<QueryCtxt<$tcx>, Self::Key, Self::Value>
             {
                 let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
                 let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
-                QueryVtable {
+                QueryVTable {
                     anon: is_anon!([$($modifiers)*]),
                     eval_always: is_eval_always!([$($modifiers)*]),
                     dep_kind: dep_graph::DepKind::$name,
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index 7ca668f8a1f..964914a1326 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -19,7 +19,7 @@ pub trait QueryConfig {
     type Stored: Clone;
 }
 
-pub struct QueryVtable<CTX: QueryContext, K, V> {
+pub struct QueryVTable<CTX: QueryContext, K, V> {
     pub anon: bool,
     pub dep_kind: CTX::DepKind,
     pub eval_always: bool,
@@ -31,7 +31,7 @@ pub struct QueryVtable<CTX: QueryContext, K, V> {
     pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>,
 }
 
-impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
+impl<CTX: QueryContext, K, V> QueryVTable<CTX, K, V> {
     pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode<CTX::DepKind>
     where
         K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
@@ -69,7 +69,7 @@ pub trait QueryDescription<CTX: QueryContext>: QueryConfig {
         CTX: 'a;
 
     // Don't use this method to compute query results, instead use the methods on TyCtxt
-    fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVtable<CTX, Self::Key, Self::Value>;
+    fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVTable<CTX, Self::Key, Self::Value>;
 
     fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool;
 }
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index f698a853d1e..fb2258434f4 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -12,7 +12,7 @@ pub use self::caches::{
 };
 
 mod config;
-pub use self::config::{QueryConfig, QueryDescription, QueryVtable};
+pub use self::config::{QueryConfig, QueryDescription, QueryVTable};
 
 use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
 
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 792f2b03173..5e8ea07d00f 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -4,7 +4,7 @@
 
 use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
 use crate::query::caches::QueryCache;
-use crate::query::config::{QueryDescription, QueryVtable};
+use crate::query::config::{QueryDescription, QueryVTable};
 use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
 use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -331,7 +331,7 @@ fn try_execute_query<CTX, C>(
     span: Span,
     key: C::Key,
     dep_node: Option<DepNode<CTX::DepKind>>,
-    query: &QueryVtable<CTX, C::Key, C::Value>,
+    query: &QueryVTable<CTX, C::Key, C::Value>,
 ) -> (C::Stored, Option<DepNodeIndex>)
 where
     C: QueryCache,
@@ -368,7 +368,7 @@ fn execute_job<CTX, K, V>(
     tcx: CTX,
     key: K,
     mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
-    query: &QueryVtable<CTX, K, V>,
+    query: &QueryVTable<CTX, K, V>,
     job_id: QueryJobId,
 ) -> (V, DepNodeIndex)
 where
@@ -437,7 +437,7 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
     tcx: CTX,
     key: &K,
     dep_node: &DepNode<CTX::DepKind>,
-    query: &QueryVtable<CTX, K, V>,
+    query: &QueryVTable<CTX, K, V>,
 ) -> Option<(V, DepNodeIndex)>
 where
     K: Clone,
@@ -530,7 +530,7 @@ fn incremental_verify_ich<CTX, K, V: Debug>(
     tcx: CTX::DepContext,
     result: &V,
     dep_node: &DepNode<CTX::DepKind>,
-    query: &QueryVtable<CTX, K, V>,
+    query: &QueryVTable<CTX, K, V>,
 ) where
     CTX: QueryContext,
 {
@@ -642,7 +642,7 @@ fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: D
 fn ensure_must_run<CTX, K, V>(
     tcx: CTX,
     key: &K,
-    query: &QueryVtable<CTX, K, V>,
+    query: &QueryVTable<CTX, K, V>,
 ) -> (bool, Option<DepNode<CTX::DepKind>>)
 where
     K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 7a1695fc862..d74e26fc844 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2603,12 +2603,12 @@ fn show_candidates(
                 .skip(1)
                 .all(|(_, descr, _, _)| descr == descr_first)
             {
-                descr_first.to_string()
+                descr_first
             } else {
-                "item".to_string()
+                "item"
             };
             let plural_descr =
-                if descr.ends_with("s") { format!("{}es", descr) } else { format!("{}s", descr) };
+                if descr.ends_with('s') { format!("{}es", descr) } else { format!("{}s", descr) };
 
             let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr);
             let mut has_colon = false;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 49761023ec3..e739ed678d8 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2111,7 +2111,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             let res = match kind {
                 ItemRibKind(..) | AssocItemRibKind => Res::Def(def_kind, def_id.to_def_id()),
                 NormalRibKind => Res::Err,
-                _ => bug!("Unexpected rib kind {:?}", kind),
+                _ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
             };
             self.r.record_partial_res(param.id, PartialRes::new(res));
             rib.bindings.insert(ident, res);
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 54dd15270a1..2b5eb12a8a8 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -796,9 +796,16 @@ impl<'a> Resolver<'a> {
     ) {
         let span = path.span;
         if let Some(stability) = &ext.stability {
-            if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level {
+            if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level
+            {
                 let feature = stability.feature;
-                if !self.active_features.contains(&feature) && !span.allows_unstable(feature) {
+
+                let is_allowed = |feature| {
+                    self.active_features.contains(&feature) || span.allows_unstable(feature)
+                };
+                let allowed_by_implication =
+                    implied_by.map(|feature| is_allowed(feature)).unwrap_or(false);
+                if !is_allowed(feature) && !allowed_by_implication {
                     let lint_buffer = &mut self.lint_buffer;
                     let soft_handler =
                         |lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg);
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index 5056163b7fe..dbc5c15195c 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-indexmap = "1.8.0"
+indexmap = "1.9.1"
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 
 [dev-dependencies]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 01ff9e254f7..1b583417ca0 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -377,7 +377,7 @@ mod desc {
     pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
     pub const parse_oom_strategy: &str = "either `panic` or `abort`";
     pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`";
+    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`";
     pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
     pub const parse_cfguard: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -535,7 +535,7 @@ mod parse {
     ) -> bool {
         match v {
             Some(s) => {
-                for s in s.split(",") {
+                for s in s.split(',') {
                     let Some(pass_name) = s.strip_prefix(&['+', '-'][..]) else { return false };
                     slot.push((pass_name.to_string(), &s[..1] == "+"));
                 }
@@ -683,6 +683,7 @@ mod parse {
                     "leak" => SanitizerSet::LEAK,
                     "memory" => SanitizerSet::MEMORY,
                     "memtag" => SanitizerSet::MEMTAG,
+                    "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
                     "thread" => SanitizerSet::THREAD,
                     "hwaddress" => SanitizerSet::HWADDRESS,
                     _ => return false,
@@ -1209,6 +1210,8 @@ options! {
     binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
         "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
         (default: no)"),
+    box_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "emit noalias metadata for box (default: yes)"),
     branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
         "set options for branch target identification and pointer authentication on AArch64"),
     cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
@@ -1277,6 +1280,8 @@ options! {
         "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
         "emit a section containing stack size metadata (default: no)"),
+    emit_thin_lto: bool = (true, parse_bool, [TRACKED],
+        "emit the bc module with thin LTO info (default: yes)"),
     fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
         (default: no)"),
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index afbb88e9233..b4a4424e876 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -718,6 +718,11 @@ impl SourceMap {
         sp
     }
 
+    /// Extends the given `Span` to contain the entire line it is on.
+    pub fn span_extend_to_line(&self, sp: Span) -> Span {
+        self.span_extend_to_prev_char(self.span_extend_to_next_char(sp, '\n', true), '\n', true)
+    }
+
     /// Given a `Span`, tries to get a shorter span ending before the first occurrence of `char`
     /// `c`.
     pub fn span_until_char(&self, sp: Span, c: char) -> Span {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ec1d2c39b80..cb15132bd4b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -800,6 +800,7 @@ symbols! {
         impl_lint_pass,
         impl_macros,
         impl_trait_in_bindings,
+        implied_by,
         import,
         import_shadowing,
         imported_main,
@@ -1283,6 +1284,7 @@ symbols! {
         self_in_typedefs,
         self_struct_ctor,
         semitransparent,
+        shadow_call_stack,
         shl,
         shl_assign,
         should_panic,
@@ -1564,6 +1566,8 @@ symbols! {
         volatile_store,
         vreg,
         vreg_low16,
+        vtable_align,
+        vtable_size,
         warn,
         wasm_abi,
         wasm_import_module,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index d5befa10e23..b104a40c231 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 doctest = false
 
 [dependencies]
+bitflags = "1.2.1"
 tracing = "0.1"
 punycode = "0.4.0"
 rustc-demangle = "0.1.21"
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index e3045c9321d..9241fd82c74 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -67,7 +67,7 @@ pub(super) fn mangle<'tcx>(
         )
         .unwrap();
 
-    if let ty::InstanceDef::VtableShim(..) = instance.def {
+    if let ty::InstanceDef::VTableShim(..) = instance.def {
         let _ = printer.write_str("{{vtable-shim}}");
     }
 
@@ -129,7 +129,7 @@ fn get_symbol_hash<'tcx>(
                 }
 
                 // We want to avoid accidental collision between different types of instances.
-                // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
+                // Especially, `VTableShim`s and `ReifyShim`s may overlap with their original
                 // instances without this.
                 discriminant(&instance.def).hash_stable(hcx, &mut hasher);
             });
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index bed0e81e66e..5fc992023ca 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -102,9 +102,8 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, TyCtxt};
 use rustc_session::config::SymbolManglingVersion;
-use rustc_target::abi::call::FnAbi;
 
 use tracing::debug;
 
@@ -112,6 +111,7 @@ mod legacy;
 mod v0;
 
 pub mod test;
+pub mod typeid;
 
 /// This function computes the symbol name for the given `instance` and the
 /// given instantiating crate. That is, if you know that instance X is
@@ -150,11 +150,6 @@ fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty
     ty::SymbolName::new(tcx, &symbol_name)
 }
 
-/// This function computes the typeid for the given function ABI.
-pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
-    v0::mangle_typeid_for_fnabi(tcx, fn_abi)
-}
-
 pub fn typeid_for_trait_ref<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyExistentialTraitRef<'tcx>,
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
new file mode 100644
index 00000000000..9228bea43f9
--- /dev/null
+++ b/compiler/rustc_symbol_mangling/src/typeid.rs
@@ -0,0 +1,18 @@
+// For more information about type metadata and type metadata identifiers for cross-language LLVM
+// CFI support, see Type metadata in the design document in the tracking issue #89653.
+
+use rustc_middle::ty::{FnSig, Ty, TyCtxt};
+use rustc_target::abi::call::FnAbi;
+
+mod typeid_itanium_cxx_abi;
+use typeid_itanium_cxx_abi::TypeIdOptions;
+
+/// Returns a type metadata identifier for the specified FnAbi.
+pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
+    typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS)
+}
+
+/// Returns a type metadata identifier for the specified FnSig.
+pub fn typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> String {
+    typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS)
+}
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
new file mode 100644
index 00000000000..a09b52fbfdf
--- /dev/null
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -0,0 +1,929 @@
+// For more information about type metadata and type metadata identifiers for cross-language LLVM
+// CFI support, see Type metadata in the design document in the tracking issue #89653.
+
+// FIXME(rcvalle): Identify C char and integer type uses and encode them with their respective
+// builtin type encodings as specified by the Itanium C++ ABI for extern function types with the "C"
+// calling convention to use this encoding for cross-language LLVM CFI.
+
+use bitflags::bitflags;
+use core::fmt::Display;
+use rustc_data_structures::base_n;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
+use rustc_middle::ty::{
+    self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind,
+    Term, Ty, TyCtxt, UintTy,
+};
+use rustc_span::def_id::DefId;
+use rustc_span::symbol::sym;
+use rustc_target::abi::call::{Conv, FnAbi};
+use rustc_target::spec::abi::Abi;
+use std::fmt::Write as _;
+
+/// Type and extended type qualifiers.
+#[derive(Eq, Hash, PartialEq)]
+enum TyQ {
+    None,
+    Const,
+    Mut,
+}
+
+/// Substitution dictionary key.
+#[derive(Eq, Hash, PartialEq)]
+enum DictKey<'tcx> {
+    Ty(Ty<'tcx>, TyQ),
+    Region(Region<'tcx>),
+    Const(Const<'tcx>),
+    Predicate(ExistentialPredicate<'tcx>),
+}
+
+bitflags! {
+    /// Options for typeid_for_fnabi and typeid_for_fnsig.
+    pub struct TypeIdOptions: u32 {
+        const NO_OPTIONS = 0;
+        const GENERALIZE_POINTERS = 1;
+        const GENERALIZE_REPR_C = 2;
+    }
+}
+
+/// Options for encode_ty.
+type EncodeTyOptions = TypeIdOptions;
+
+/// Options for transform_ty.
+type TransformTyOptions = TypeIdOptions;
+
+/// Converts a number to a disambiguator (see
+/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>).
+fn to_disambiguator(num: u64) -> String {
+    if let Some(num) = num.checked_sub(1) {
+        format!("s{}_", base_n::encode(num as u128, 62))
+    } else {
+        "s_".to_string()
+    }
+}
+
+/// Converts a number to a sequence number (see
+/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>).
+fn to_seq_id(num: usize) -> String {
+    if let Some(num) = num.checked_sub(1) {
+        base_n::encode(num as u128, 36).to_uppercase()
+    } else {
+        "".to_string()
+    }
+}
+
+/// Substitutes a component if found in the substitution dictionary (see
+/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression>).
+fn compress<'tcx>(
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    key: DictKey<'tcx>,
+    comp: &mut String,
+) {
+    match dict.get(&key) {
+        Some(num) => {
+            comp.clear();
+            let _ = write!(comp, "S{}_", to_seq_id(*num));
+        }
+        None => {
+            dict.insert(key, dict.len());
+        }
+    }
+}
+
+// FIXME(rcvalle): Move to compiler/rustc_middle/src/ty/sty.rs after C types work is done, possibly
+// along with other is_c_type methods.
+/// Returns whether a `ty::Ty` is `c_void`.
+fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
+    match ty.kind() {
+        ty::Adt(adt_def, ..) => {
+            let def_id = adt_def.0.did;
+            let crate_name = tcx.crate_name(def_id.krate);
+            if tcx.item_name(def_id).as_str() == "c_void"
+                && (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc)
+            {
+                true
+            } else {
+                false
+            }
+        }
+        _ => false,
+    }
+}
+
+/// Encodes a const using the Itanium C++ ABI as a literal argument (see
+/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
+fn encode_const<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    c: Const<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    // L<element-type>[n]<element-value>E as literal argument
+    let mut s = String::from('L');
+
+    // Element type
+    s.push_str(&encode_ty(tcx, c.ty(), dict, options));
+
+    // The only allowed types of const parameters are bool, u8, u16, u32, u64, u128, usize i8, i16,
+    // i32, i64, i128, isize, and char. The bool value false is encoded as 0 and true as 1.
+    fn push_signed_value<T: Display + PartialOrd>(s: &mut String, value: T, zero: T) {
+        if value < zero {
+            s.push('n')
+        };
+        let _ = write!(s, "{}", value);
+    }
+
+    fn push_unsigned_value<T: Display>(s: &mut String, value: T) {
+        let _ = write!(s, "{}", value);
+    }
+
+    if let Some(scalar_int) = c.kind().try_to_scalar_int() {
+        let signed = c.ty().is_signed();
+        match scalar_int.size().bits() {
+            8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0),
+            16 if signed => push_signed_value(&mut s, scalar_int.try_to_i16().unwrap(), 0),
+            32 if signed => push_signed_value(&mut s, scalar_int.try_to_i32().unwrap(), 0),
+            64 if signed => push_signed_value(&mut s, scalar_int.try_to_i64().unwrap(), 0),
+            128 if signed => push_signed_value(&mut s, scalar_int.try_to_i128().unwrap(), 0),
+            8 => push_unsigned_value(&mut s, scalar_int.try_to_u8().unwrap()),
+            16 => push_unsigned_value(&mut s, scalar_int.try_to_u16().unwrap()),
+            32 => push_unsigned_value(&mut s, scalar_int.try_to_u32().unwrap()),
+            64 => push_unsigned_value(&mut s, scalar_int.try_to_u64().unwrap()),
+            128 => push_unsigned_value(&mut s, scalar_int.try_to_u128().unwrap()),
+            _ => {
+                bug!("encode_const: unexpected size `{:?}`", scalar_int.size().bits());
+            }
+        };
+    } else {
+        bug!("encode_const: unexpected type `{:?}`", c.ty());
+    }
+
+    // Close the "L..E" pair
+    s.push('E');
+
+    compress(dict, DictKey::Const(c), &mut s);
+
+    s
+}
+
+/// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for
+/// Rust types that are not used at the FFI boundary.
+fn encode_fnsig<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_sig: &FnSig<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: TypeIdOptions,
+) -> String {
+    // Function types are delimited by an "F..E" pair
+    let mut s = String::from("F");
+
+    let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
+    match fn_sig.abi {
+        Abi::C { .. } => {
+            encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+        _ => {
+            encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+    }
+
+    // Encode the return type
+    let transform_ty_options = TransformTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
+    let ty = transform_ty(tcx, fn_sig.output(), transform_ty_options);
+    s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
+
+    // Encode the parameter types
+    let tys = fn_sig.inputs();
+    if !tys.is_empty() {
+        for ty in tys {
+            let ty = transform_ty(tcx, *ty, transform_ty_options);
+            s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
+        }
+
+        if fn_sig.c_variadic {
+            s.push('z');
+        }
+    } else {
+        if fn_sig.c_variadic {
+            s.push('z');
+        } else {
+            // Empty parameter lists, whether declared as () or conventionally as (void), are
+            // encoded with a void parameter specifier "v".
+            s.push('v')
+        }
+    }
+
+    // Close the "F..E" pair
+    s.push('E');
+
+    s
+}
+
+/// Encodes a predicate using the Itanium C++ ABI with vendor extended type qualifiers and types for
+/// Rust types that are not used at the FFI boundary.
+fn encode_predicate<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    predicate: Binder<'tcx, ExistentialPredicate<'tcx>>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>, as vendor
+    // extended type.
+    let mut s = String::new();
+    match predicate.as_ref().skip_binder() {
+        ty::ExistentialPredicate::Trait(trait_ref) => {
+            let name = encode_ty_name(tcx, trait_ref.def_id);
+            let _ = write!(s, "u{}{}", name.len(), &name);
+            s.push_str(&encode_substs(tcx, trait_ref.substs, dict, options));
+        }
+        ty::ExistentialPredicate::Projection(projection) => {
+            let name = encode_ty_name(tcx, projection.item_def_id);
+            let _ = write!(s, "u{}{}", name.len(), &name);
+            s.push_str(&encode_substs(tcx, projection.substs, dict, options));
+            match projection.term {
+                Term::Ty(ty) => {
+                    s.push_str(&encode_ty(tcx, ty, dict, options));
+                }
+                Term::Const(c) => {
+                    s.push_str(&encode_const(tcx, c, dict, options));
+                }
+            }
+        }
+        ty::ExistentialPredicate::AutoTrait(def_id) => {
+            let name = encode_ty_name(tcx, *def_id);
+            let _ = write!(s, "u{}{}", name.len(), &name);
+        }
+    };
+    compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s);
+    s
+}
+
+/// Encodes predicates using the Itanium C++ ABI with vendor extended type qualifiers and types for
+/// Rust types that are not used at the FFI boundary.
+fn encode_predicates<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    predicates: &List<Binder<'tcx, ExistentialPredicate<'tcx>>>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    // <predicate1[..predicateN]>E as part of vendor extended type
+    let mut s = String::new();
+    let predicates: Vec<Binder<'tcx, ExistentialPredicate<'tcx>>> =
+        predicates.iter().map(|predicate| predicate).collect();
+    for predicate in predicates {
+        s.push_str(&encode_predicate(tcx, predicate, dict, options));
+    }
+    s
+}
+
+/// Encodes a region using the Itanium C++ ABI as a vendor extended type.
+fn encode_region<'tcx>(
+    _tcx: TyCtxt<'tcx>,
+    region: Region<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    _options: EncodeTyOptions,
+) -> String {
+    // u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type
+    let mut s = String::new();
+    match region.kind() {
+        RegionKind::ReLateBound(debruijn, r) => {
+            s.push_str("u6regionI");
+            // Debruijn index, which identifies the binder, as region disambiguator
+            let num = debruijn.index() as u64;
+            if num > 0 {
+                s.push_str(&to_disambiguator(num));
+            }
+            // Index within the binder
+            let _ = write!(s, "{}", r.var.index() as u64);
+            s.push('E');
+            compress(dict, DictKey::Region(region), &mut s);
+        }
+        RegionKind::ReErased => {
+            s.push_str("u6region");
+            compress(dict, DictKey::Region(region), &mut s);
+        }
+        RegionKind::ReEarlyBound(..)
+        | RegionKind::ReFree(..)
+        | RegionKind::ReStatic
+        | RegionKind::ReVar(..)
+        | RegionKind::RePlaceholder(..)
+        | RegionKind::ReEmpty(..) => {
+            bug!("encode_region: unexpected `{:?}`", region.kind());
+        }
+    }
+    s
+}
+
+/// Encodes substs using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust
+/// types that are not used at the FFI boundary.
+fn encode_substs<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    substs: SubstsRef<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    // [I<subst1..substN>E] as part of vendor extended type
+    let mut s = String::new();
+    let substs: Vec<GenericArg<'_>> = substs.iter().map(|subst| subst).collect();
+    if !substs.is_empty() {
+        s.push('I');
+        for subst in substs {
+            match subst.unpack() {
+                GenericArgKind::Lifetime(region) => {
+                    s.push_str(&encode_region(tcx, region, dict, options));
+                }
+                GenericArgKind::Type(ty) => {
+                    s.push_str(&encode_ty(tcx, ty, dict, options));
+                }
+                GenericArgKind::Const(c) => {
+                    s.push_str(&encode_const(tcx, c, dict, options));
+                }
+            }
+        }
+        s.push('E');
+    }
+    s
+}
+
+/// Encodes a ty:Ty name, including its crate and path disambiguators and names.
+fn encode_ty_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> String {
+    // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where
+    // <element-type> is <subst>, using v0's <path> without v0's extended form of paths:
+    //
+    // N<namespace-tagN>..N<namespace-tag1>
+    // C<crate-disambiguator><crate-name>
+    // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN>
+    //
+    // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance:
+    //
+    //     pub type Type1 = impl Send;
+    //     let _: Type1 = <Struct1<i32>>::foo;
+    //     fn foo1(_: Type1) { }
+    //
+    //     pub type Type2 = impl Send;
+    //     let _: Type2 = <Trait1<i32>>::foo;
+    //     fn foo2(_: Type2) { }
+    //
+    //     pub type Type3 = impl Send;
+    //     let _: Type3 = <i32 as Trait1<i32>>::foo;
+    //     fn foo3(_: Type3) { }
+    //
+    //     pub type Type4 = impl Send;
+    //     let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo;
+    //     fn foo3(_: Type4) { }
+    //
+    // Are encoded as:
+    //
+    //     _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE
+    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE
+    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE
+    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE
+    //
+    // The reason for not using v0's extended form of paths is to use a consistent and simpler
+    // encoding, as the reasoning for using it isn't relevand for type metadata identifiers (i.e.,
+    // keep symbol names close to how methods are represented in error messages). See
+    // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods.
+    let mut s = String::new();
+
+    // Start and namespace tags
+    let mut def_path = tcx.def_path(def_id);
+    def_path.data.reverse();
+    for disambiguated_data in &def_path.data {
+        s.push('N');
+        s.push_str(match disambiguated_data.data {
+            hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace>
+            hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace>
+            hir::definitions::DefPathData::TypeNs(..) => "t",
+            hir::definitions::DefPathData::ValueNs(..) => "v",
+            hir::definitions::DefPathData::ClosureExpr => "C",
+            hir::definitions::DefPathData::Ctor => "c",
+            hir::definitions::DefPathData::AnonConst => "k",
+            hir::definitions::DefPathData::ImplTrait => "i",
+            hir::definitions::DefPathData::CrateRoot
+            | hir::definitions::DefPathData::Use
+            | hir::definitions::DefPathData::GlobalAsm
+            | hir::definitions::DefPathData::MacroNs(..)
+            | hir::definitions::DefPathData::LifetimeNs(..) => {
+                bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
+            }
+        });
+    }
+
+    // Crate disambiguator and name
+    s.push('C');
+    s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).to_u64()));
+    let crate_name = tcx.crate_name(def_path.krate).to_string();
+    let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
+
+    // Disambiguators and names
+    def_path.data.reverse();
+    for disambiguated_data in &def_path.data {
+        let num = disambiguated_data.disambiguator as u64;
+        if num > 0 {
+            s.push_str(&to_disambiguator(num));
+        }
+
+        let name = disambiguated_data.data.to_string();
+        let _ = write!(s, "{}", name.len());
+
+        // Prepend a '_' if name starts with a digit or '_'
+        if let Some(first) = name.as_bytes().get(0) {
+            if first.is_ascii_digit() || *first == b'_' {
+                s.push('_');
+            }
+        } else {
+            bug!("encode_ty_name: invalid name `{:?}`", name);
+        }
+
+        s.push_str(&name);
+    }
+
+    s
+}
+
+/// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for
+/// Rust types that are not used at the FFI boundary.
+fn encode_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    let mut typeid = String::new();
+
+    match ty.kind() {
+        // Primitive types
+        ty::Bool => {
+            typeid.push('b');
+        }
+
+        ty::Int(..) | ty::Uint(..) | ty::Float(..) => {
+            // u<length><type-name> as vendor extended type
+            let mut s = String::from(match ty.kind() {
+                ty::Int(IntTy::I8) => "u2i8",
+                ty::Int(IntTy::I16) => "u3i16",
+                ty::Int(IntTy::I32) => "u3i32",
+                ty::Int(IntTy::I64) => "u3i64",
+                ty::Int(IntTy::I128) => "u4i128",
+                ty::Int(IntTy::Isize) => "u5isize",
+                ty::Uint(UintTy::U8) => "u2u8",
+                ty::Uint(UintTy::U16) => "u3u16",
+                ty::Uint(UintTy::U32) => "u3u32",
+                ty::Uint(UintTy::U64) => "u3u64",
+                ty::Uint(UintTy::U128) => "u4u128",
+                ty::Uint(UintTy::Usize) => "u5usize",
+                ty::Float(FloatTy::F32) => "u3f32",
+                ty::Float(FloatTy::F64) => "u3f64",
+                _ => "",
+            });
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Char => {
+            // u4char as vendor extended type
+            let mut s = String::from("u4char");
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Str => {
+            // u3str as vendor extended type
+            let mut s = String::from("u3str");
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Never => {
+            // u5never as vendor extended type
+            let mut s = String::from("u5never");
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Compound types
+        // () in Rust is equivalent to void return type in C
+        _ if ty.is_unit() => {
+            typeid.push('v');
+        }
+
+        // Sequence types
+        ty::Tuple(tys) => {
+            // u5tupleI<element-type1..element-typeN>E as vendor extended type
+            let mut s = String::from("u5tupleI");
+            for ty in tys.iter() {
+                s.push_str(&encode_ty(tcx, ty, dict, options));
+            }
+            s.push('E');
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Array(ty0, len) => {
+            // A<array-length><element-type>
+            let mut s = String::from("A");
+            let _ = write!(s, "{}", &len.kind().try_to_scalar().unwrap().to_u64().unwrap());
+            s.push_str(&encode_ty(tcx, *ty0, dict, options));
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Slice(ty0) => {
+            // u5sliceI<element-type>E as vendor extended type
+            let mut s = String::from("u5sliceI");
+            s.push_str(&encode_ty(tcx, *ty0, dict, options));
+            s.push('E');
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // User-defined types
+        ty::Adt(adt_def, substs) => {
+            let mut s = String::new();
+            let def_id = adt_def.0.did;
+            if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
+                // For for cross-language CFI support, the encoding must be compatible at the FFI
+                // boundary. For instance:
+                //
+                //     struct type1 {};
+                //     void foo(struct type1* bar) {}
+                //
+                // Is encoded as:
+                //
+                //     _ZTSFvP5type1E
+                //
+                // So, encode any repr(C) user-defined type for extern function types with the "C"
+                // calling convention (or extern types [i.e., ty::Foreign]) as <length><name>, where
+                // <name> is <unscoped-name>.
+                let name = tcx.item_name(def_id).to_string();
+                let _ = write!(s, "{}{}", name.len(), &name);
+                compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            } else {
+                // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is
+                // <subst>, as vendor extended type.
+                let name = encode_ty_name(tcx, def_id);
+                let _ = write!(s, "u{}{}", name.len(), &name);
+                s.push_str(&encode_substs(tcx, substs, dict, options));
+                compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            }
+            typeid.push_str(&s);
+        }
+
+        ty::Foreign(def_id) => {
+            // <length><name>, where <name> is <unscoped-name>
+            let mut s = String::new();
+            let name = tcx.item_name(*def_id).to_string();
+            let _ = write!(s, "{}{}", name.len(), &name);
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Function types
+        ty::FnDef(def_id, substs)
+        | ty::Closure(def_id, substs)
+        | ty::Generator(def_id, substs, ..) => {
+            // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
+            // as vendor extended type.
+            let mut s = String::new();
+            let name = encode_ty_name(tcx, *def_id);
+            let _ = write!(s, "u{}{}", name.len(), &name);
+            s.push_str(&encode_substs(tcx, substs, dict, options));
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Pointer types
+        ty::Ref(region, ty0, ..) => {
+            // [U3mut]u3refI<element-type>E as vendor extended type qualifier and type
+            let mut s = String::new();
+            s.push_str("u3refI");
+            s.push_str(&encode_ty(tcx, *ty0, dict, options));
+            s.push('E');
+            compress(dict, DictKey::Ty(tcx.mk_imm_ref(*region, *ty0), TyQ::None), &mut s);
+            if ty.is_mutable_ptr() {
+                s = format!("{}{}", "U3mut", &s);
+                compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
+            }
+            typeid.push_str(&s);
+        }
+
+        ty::RawPtr(tm) => {
+            // P[K]<element-type>
+            let mut s = String::new();
+            s.push_str(&encode_ty(tcx, tm.ty, dict, options));
+            if !ty.is_mutable_ptr() {
+                s = format!("{}{}", "K", &s);
+                compress(dict, DictKey::Ty(tm.ty, TyQ::Const), &mut s);
+            };
+            s = format!("{}{}", "P", &s);
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::FnPtr(fn_sig) => {
+            // PF<return-type><parameter-type1..parameter-typeN>E
+            let mut s = String::from("P");
+            s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::NO_OPTIONS));
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Trait types
+        ty::Dynamic(predicates, region) => {
+            // u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, as
+            // vendor extended type.
+            let mut s = String::from("u3dynI");
+            s.push_str(&encode_predicates(tcx, predicates, dict, options));
+            s.push_str(&encode_region(tcx, *region, dict, options));
+            s.push('E');
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Unexpected types
+        ty::Bound(..)
+        | ty::Error(..)
+        | ty::GeneratorWitness(..)
+        | ty::Infer(..)
+        | ty::Opaque(..)
+        | ty::Param(..)
+        | ty::Placeholder(..)
+        | ty::Projection(..) => {
+            bug!("encode_ty: unexpected `{:?}`", ty.kind());
+        }
+    };
+
+    typeid
+}
+
+// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
+// c_void types into unit types unconditionally, and generalizes all pointers if
+// TransformTyOptions::GENERALIZE_POINTERS option is set.
+fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
+    let mut ty = ty;
+
+    match ty.kind() {
+        ty::Bool
+        | ty::Int(..)
+        | ty::Uint(..)
+        | ty::Float(..)
+        | ty::Char
+        | ty::Str
+        | ty::Never
+        | ty::Foreign(..)
+        | ty::Dynamic(..) => {}
+
+        _ if ty.is_unit() => {}
+
+        ty::Tuple(tys) => {
+            ty = tcx.mk_tup(tys.iter().map(|ty| transform_ty(tcx, ty, options)));
+        }
+
+        ty::Array(ty0, len) => {
+            let len = len.kind().try_to_scalar().unwrap().to_u64().unwrap();
+            ty = tcx.mk_array(transform_ty(tcx, *ty0, options), len);
+        }
+
+        ty::Slice(ty0) => {
+            ty = tcx.mk_slice(transform_ty(tcx, *ty0, options));
+        }
+
+        ty::Adt(adt_def, substs) => {
+            if is_c_void_ty(tcx, ty) {
+                ty = tcx.mk_unit();
+            } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
+            {
+                ty = tcx.mk_adt(*adt_def, ty::List::empty());
+            } else if adt_def.repr().transparent() && adt_def.is_struct() {
+                let variant = adt_def.non_enum_variant();
+                let param_env = tcx.param_env(variant.def_id);
+                let field = variant.fields.iter().find(|field| {
+                    let ty = tcx.type_of(field.did);
+                    let is_zst =
+                        tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst());
+                    !is_zst
+                });
+                if field.is_none() {
+                    // Transform repr(transparent) types without non-ZST field into ()
+                    ty = tcx.mk_unit();
+                } else {
+                    let ty0 = tcx.type_of(field.unwrap().did);
+                    // Generalize any repr(transparent) user-defined type that is either a pointer
+                    // or reference, and either references itself or any other type that contains or
+                    // references itself, to avoid a reference cycle.
+                    if ty0.is_any_ptr() && ty0.contains(ty) {
+                        ty = transform_ty(
+                            tcx,
+                            ty0,
+                            options | TransformTyOptions::GENERALIZE_POINTERS,
+                        );
+                    } else {
+                        ty = transform_ty(tcx, ty0, options);
+                    }
+                }
+            } else {
+                ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options));
+            }
+        }
+
+        ty::FnDef(def_id, substs) => {
+            ty = tcx.mk_fn_def(*def_id, transform_substs(tcx, substs, options));
+        }
+
+        ty::Closure(def_id, substs) => {
+            ty = tcx.mk_closure(*def_id, transform_substs(tcx, substs, options));
+        }
+
+        ty::Generator(def_id, substs, movability) => {
+            ty = tcx.mk_generator(*def_id, transform_substs(tcx, substs, options), *movability);
+        }
+
+        ty::Ref(region, ty0, ..) => {
+            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                if ty.is_mutable_ptr() {
+                    ty = tcx.mk_mut_ref(tcx.lifetimes.re_static, tcx.mk_unit());
+                } else {
+                    ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_unit());
+                }
+            } else {
+                if ty.is_mutable_ptr() {
+                    ty = tcx.mk_mut_ref(*region, transform_ty(tcx, *ty0, options));
+                } else {
+                    ty = tcx.mk_imm_ref(*region, transform_ty(tcx, *ty0, options));
+                }
+            }
+        }
+
+        ty::RawPtr(tm) => {
+            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                if ty.is_mutable_ptr() {
+                    ty = tcx.mk_mut_ptr(tcx.mk_unit());
+                } else {
+                    ty = tcx.mk_imm_ptr(tcx.mk_unit());
+                }
+            } else {
+                if ty.is_mutable_ptr() {
+                    ty = tcx.mk_mut_ptr(transform_ty(tcx, tm.ty, options));
+                } else {
+                    ty = tcx.mk_imm_ptr(transform_ty(tcx, tm.ty, options));
+                }
+            }
+        }
+
+        ty::FnPtr(fn_sig) => {
+            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                ty = tcx.mk_imm_ptr(tcx.mk_unit());
+            } else {
+                let parameters: Vec<Ty<'tcx>> = fn_sig
+                    .skip_binder()
+                    .inputs()
+                    .iter()
+                    .map(|ty| transform_ty(tcx, *ty, options))
+                    .collect();
+                let output = transform_ty(tcx, fn_sig.skip_binder().output(), options);
+                ty = tcx.mk_fn_ptr(ty::Binder::bind_with_vars(
+                    tcx.mk_fn_sig(
+                        parameters.iter(),
+                        &output,
+                        fn_sig.c_variadic(),
+                        fn_sig.unsafety(),
+                        fn_sig.abi(),
+                    ),
+                    fn_sig.bound_vars(),
+                ));
+            }
+        }
+
+        ty::Bound(..)
+        | ty::Error(..)
+        | ty::GeneratorWitness(..)
+        | ty::Infer(..)
+        | ty::Opaque(..)
+        | ty::Param(..)
+        | ty::Placeholder(..)
+        | ty::Projection(..) => {
+            bug!("transform_ty: unexpected `{:?}`", ty.kind());
+        }
+    }
+
+    ty
+}
+
+/// Transforms substs for being encoded and used in the substitution dictionary.
+fn transform_substs<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    substs: SubstsRef<'tcx>,
+    options: TransformTyOptions,
+) -> SubstsRef<'tcx> {
+    let substs: Vec<GenericArg<'tcx>> = substs
+        .iter()
+        .map(|subst| {
+            if let GenericArgKind::Type(ty) = subst.unpack() {
+                if is_c_void_ty(tcx, ty) {
+                    tcx.mk_unit().into()
+                } else {
+                    transform_ty(tcx, ty, options).into()
+                }
+            } else {
+                subst
+            }
+        })
+        .collect();
+    tcx.mk_substs(substs.iter())
+}
+
+/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
+/// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+pub fn typeid_for_fnabi<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+    options: TypeIdOptions,
+) -> String {
+    // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
+    // its type.
+    let mut typeid = String::from("_Z");
+
+    // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
+    // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
+    // code (i.e., 'TS') prefixed to the type encoding for the function.
+    typeid.push_str("TS");
+
+    // Function types are delimited by an "F..E" pair
+    typeid.push('F');
+
+    // A dictionary of substitution candidates used for compression (see
+    // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
+    let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
+
+    let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
+    match fn_abi.conv {
+        Conv::C => {
+            encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+        _ => {
+            encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+    }
+
+    // Encode the return type
+    let transform_ty_options = TransformTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
+    let ty = transform_ty(tcx, fn_abi.ret.layout.ty, transform_ty_options);
+    typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+
+    // Encode the parameter types
+    if !fn_abi.c_variadic {
+        if !fn_abi.args.is_empty() {
+            for arg in fn_abi.args.iter() {
+                let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options);
+                typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+            }
+        } else {
+            // Empty parameter lists, whether declared as () or conventionally as (void), are
+            // encoded with a void parameter specifier "v".
+            typeid.push('v');
+        }
+    } else {
+        for n in 0..fn_abi.fixed_count {
+            let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options);
+            typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+        }
+
+        typeid.push('z');
+    }
+
+    // Close the "F..E" pair
+    typeid.push('E');
+
+    typeid
+}
+
+/// Returns a type metadata identifier for the specified FnSig using the Itanium C++ ABI with vendor
+/// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+pub fn typeid_for_fnsig<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_sig: &FnSig<'tcx>,
+    options: TypeIdOptions,
+) -> String {
+    // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
+    // its type.
+    let mut typeid = String::from("_Z");
+
+    // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
+    // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
+    // code (i.e., 'TS') prefixed to the type encoding for the function.
+    typeid.push_str("TS");
+
+    // A dictionary of substitution candidates used for compression (see
+    // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
+    let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
+
+    // Encode the function signature
+    typeid.push_str(&encode_fnsig(tcx, fn_sig, &mut dict, options));
+
+    typeid
+}
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 13229a3995c..71fa5a44887 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -12,7 +12,6 @@ use rustc_middle::ty::{
     self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, UintTy,
 };
 use rustc_span::symbol::kw;
-use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
 
@@ -42,7 +41,7 @@ pub(super) fn mangle<'tcx>(
 
     // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance.
     let shim_kind = match instance.def {
-        ty::InstanceDef::VtableShim(_) => Some("vtable"),
+        ty::InstanceDef::VTableShim(_) => Some("vtable"),
         ty::InstanceDef::ReifyShim(_) => Some("reify"),
 
         _ => None,
@@ -59,41 +58,6 @@ pub(super) fn mangle<'tcx>(
     std::mem::take(&mut cx.out)
 }
 
-pub(super) fn mangle_typeid_for_fnabi<'tcx>(
-    _tcx: TyCtxt<'tcx>,
-    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
-) -> String {
-    // LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This
-    // type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is
-    // associated with a type identifier (i.e., test type membership).
-    //
-    // Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as
-    // type metadata identifiers for function pointers. The typeinfo name encoding is a
-    // two-character code (i.e., “TS”) prefixed to the type encoding for the function.
-    //
-    // For cross-language LLVM CFI support, a compatible encoding must be used by either
-    //
-    //  a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's
-    //     type encodings[4]), or at least types used at the FFI boundary.
-    //  b. Reducing the types to the least common denominator between types used by Clang (or at
-    //     least types used at the FFI boundary) and Rust compilers (if even possible).
-    //  c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and
-    //     possibly other compilers).
-    //
-    // Option (b) may weaken the protection for Rust-compiled only code, so it should be provided
-    // as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled
-    // code. Option (c) would require changes to Clang to use the new ABI.
-    //
-    // [1] https://llvm.org/docs/TypeMetadata.html
-    // [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html
-    // [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables
-    // [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type
-    //
-    // FIXME(rcvalle): See comment above.
-    let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
-    format!("typeid{}", arg_count)
-}
-
 pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyExistentialTraitRef<'tcx>,
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 6f4d073d704..b35502d9ee4 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -1350,15 +1350,19 @@ impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PointerKind {
     /// Most general case, we know no restrictions to tell LLVM.
-    Shared,
+    SharedMutable,
 
-    /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`.
+    /// `&T` where `T` contains no `UnsafeCell`, is `dereferenceable`, `noalias` and `readonly`.
     Frozen,
 
-    /// `&mut T` which is `noalias` but not `readonly`.
+    /// `&mut T` which is `dereferenceable` and `noalias` but not `readonly`.
     UniqueBorrowed,
 
-    /// `Box<T>`, unlike `UniqueBorrowed`, it also has `noalias` on returns.
+    /// `&mut !Unpin`, which is `dereferenceable` but neither `noalias` nor `readonly`.
+    UniqueBorrowedPinned,
+
+    /// `Box<T>`, which is `noalias` (even on return types, unlike the above) but neither `readonly`
+    /// nor `dereferenceable`.
     UniqueOwned,
 }
 
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index 25842049413..62a0f9fb034 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -1,6 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::{RelocModel, Target};
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
index aaa632333db..0db3eb6fcac 100644
--- a/compiler/rustc_target/src/asm/arm.rs
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -1,6 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::{RelocModel, Target};
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_macros::HashStable_Generic;
 use rustc_span::{sym, Symbol};
 use std::fmt;
diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs
index 987bf970529..e41bdc9a58c 100644
--- a/compiler/rustc_target/src/asm/riscv.rs
+++ b/compiler/rustc_target/src/asm/riscv.rs
@@ -1,6 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::{RelocModel, Target};
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_macros::HashStable_Generic;
 use rustc_span::{sym, Symbol};
 use std::fmt;
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
index e35035fd25a..238c365093f 100644
--- a/compiler/rustc_target/src/asm/x86.rs
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -1,6 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::{RelocModel, Target};
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
index 5e31859aaef..c85f7f62a42 100644
--- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
@@ -17,6 +17,7 @@ pub fn target() -> Target {
             supported_sanitizers: SanitizerSet::CFI
                 | SanitizerSet::HWADDRESS
                 | SanitizerSet::MEMTAG
+                | SanitizerSet::SHADOWCALLSTACK
                 | SanitizerSet::ADDRESS,
             ..super::android_base::opts()
         },
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 1a6bb4a2eaf..f7abeafd38f 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -618,6 +618,7 @@ bitflags::bitflags! {
         const HWADDRESS = 1 << 4;
         const CFI     = 1 << 5;
         const MEMTAG  = 1 << 6;
+        const SHADOWCALLSTACK = 1 << 7;
     }
 }
 
@@ -632,6 +633,7 @@ impl SanitizerSet {
             SanitizerSet::LEAK => "leak",
             SanitizerSet::MEMORY => "memory",
             SanitizerSet::MEMTAG => "memtag",
+            SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
             SanitizerSet::THREAD => "thread",
             SanitizerSet::HWADDRESS => "hwaddress",
             _ => return None,
@@ -666,6 +668,7 @@ impl IntoIterator for SanitizerSet {
             SanitizerSet::LEAK,
             SanitizerSet::MEMORY,
             SanitizerSet::MEMTAG,
+            SanitizerSet::SHADOWCALLSTACK,
             SanitizerSet::THREAD,
             SanitizerSet::HWADDRESS,
         ]
@@ -1960,6 +1963,7 @@ impl Target {
                                 Some("leak") => SanitizerSet::LEAK,
                                 Some("memory") => SanitizerSet::MEMORY,
                                 Some("memtag") => SanitizerSet::MEMTAG,
+                                Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
                                 Some("thread") => SanitizerSet::THREAD,
                                 Some("hwaddress") => SanitizerSet::HWADDRESS,
                                 Some(s) => return Err(format!("unknown sanitizer {}", s)),
diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
index 2546ab9b7e6..dffa19ae55c 100644
--- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
@@ -14,8 +14,9 @@ pub fn target() -> Target {
             // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
             // with +strict-align.
             features: "+strict-align".into(),
-            // There are no atomic CAS instructions available in the instruction set of the ARMv6-M
+            // There are no atomic instructions available in the instruction set of the ARMv6-M
             // architecture
+            max_atomic_width: Some(0),
             atomic_cas: false,
             ..super::thumb_base::opts()
         },
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 65ff9ceb67e..5763e6d1b55 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -793,9 +793,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 }
                 ty::PredicateKind::RegionOutlives(binder) => {
                     let binder = bound_predicate.rebind(binder);
-                    if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() {
-                        return false;
-                    }
+                    select.infcx().region_outlives_predicate(&dummy_cause, binder)
                 }
                 ty::PredicateKind::TypeOutlives(binder) => {
                     let binder = bound_predicate.rebind(binder);
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 6ca630b74cc..5fcaa52d417 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -3,7 +3,7 @@
 // seems likely that they should eventually be merged into more
 // general routines.
 
-use crate::infer::TyCtxtInferExt;
+use crate::infer::{DefiningAnchor, TyCtxtInferExt};
 use crate::traits::{
     FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
     Unimplemented,
@@ -30,7 +30,11 @@ pub fn codegen_fulfill_obligation<'tcx>(
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
-    tcx.infer_ctxt().enter(|infcx| {
+    let mut infcx_builder =
+        tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble);
+    infcx_builder.enter(|infcx| {
+        //~^ HACK `Bubble` is required for
+        // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
         let mut selcx = SelectionContext::new(&infcx);
 
         let obligation_cause = ObligationCause::dummy();
@@ -69,7 +73,8 @@ pub fn codegen_fulfill_obligation<'tcx>(
 
         // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
         // as they will get constrained elsewhere, too.
-        let _opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+        // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
+        let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 
         debug!("Cache miss: {trait_ref:?} => {impl_source:?}");
         Ok(&*tcx.arena.alloc(impl_source))
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 52ca23c4b30..9983438233e 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -22,11 +22,12 @@ use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
+use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 use std::fmt::Debug;
 use std::iter;
+use std::ops::ControlFlow;
 
 /// Whether we do the orphan check relative to this crate or
 /// to some remote crate.
@@ -578,220 +579,146 @@ fn orphan_check_trait_ref<'tcx>(
         );
     }
 
-    // Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only
-    // if at least one of the following is true:
-    //
-    // - Trait is a local trait
-    // (already checked in orphan_check prior to calling this function)
-    // - All of
-    //     - At least one of the types T0..=Tn must be a local type.
-    //      Let Ti be the first such type.
-    //     - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
-    //
-    fn uncover_fundamental_ty<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        ty: Ty<'tcx>,
-        in_crate: InCrate,
-    ) -> Vec<Ty<'tcx>> {
-        // FIXME: this is currently somewhat overly complicated,
-        // but fixing this requires a more complicated refactor.
-        if !contained_non_local_types(tcx, ty, in_crate).is_empty() {
-            if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
-                return inner_tys
-                    .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-                    .collect();
+    let mut checker = OrphanChecker::new(tcx, in_crate);
+    match trait_ref.visit_with(&mut checker) {
+        ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
+        ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => {
+            // Does there exist some local type after the `ParamTy`.
+            checker.search_first_local_ty = true;
+            if let Some(OrphanCheckEarlyExit::LocalTy(local_ty)) =
+                trait_ref.visit_with(&mut checker).break_value()
+            {
+                Err(OrphanCheckErr::UncoveredTy(ty, Some(local_ty)))
+            } else {
+                Err(OrphanCheckErr::UncoveredTy(ty, None))
             }
         }
-
-        vec![ty]
-    }
-
-    let mut non_local_spans = vec![];
-    for (i, input_ty) in trait_ref
-        .substs
-        .types()
-        .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-        .enumerate()
-    {
-        debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
-        let non_local_tys = contained_non_local_types(tcx, input_ty, in_crate);
-        if non_local_tys.is_empty() {
-            debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
-            return Ok(());
-        } else if let ty::Param(_) = input_ty.kind() {
-            debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty);
-            let local_type = trait_ref
-                .substs
-                .types()
-                .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-                .find(|&ty| ty_is_local_constructor(tcx, ty, in_crate));
-
-            debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
-
-            return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type));
-        }
-
-        non_local_spans.extend(non_local_tys.into_iter().map(|input_ty| (input_ty, i == 0)));
+        ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()),
     }
-    // If we exit above loop, never found a local type.
-    debug!("orphan_check_trait_ref: no local type");
-    Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
 }
 
-/// Returns a list of relevant non-local types for `ty`.
-///
-/// This is just `ty` itself unless `ty` is `#[fundamental]`,
-/// in which case we recursively look into this type.
-///
-/// If `ty` is local itself, this method returns an empty `Vec`.
-///
-/// # Examples
-///
-/// - `u32` is not local, so this returns `[u32]`.
-/// - for `Foo<u32>`, where `Foo` is a local type, this returns `[]`.
-/// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`.
-/// - `Box<Foo<u32>>` returns `[]`, as `Box` is a fundamental type and `Foo` is local.
-fn contained_non_local_types<'tcx>(
+struct OrphanChecker<'tcx> {
     tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
     in_crate: InCrate,
-) -> Vec<Ty<'tcx>> {
-    if ty_is_local_constructor(tcx, ty, in_crate) {
-        Vec::new()
-    } else {
-        match fundamental_ty_inner_tys(tcx, ty) {
-            Some(inner_tys) => {
-                inner_tys.flat_map(|ty| contained_non_local_types(tcx, ty, in_crate)).collect()
-            }
-            None => vec![ty],
+    in_self_ty: bool,
+    /// Ignore orphan check failures and exclusively search for the first
+    /// local type.
+    search_first_local_ty: bool,
+    non_local_tys: Vec<(Ty<'tcx>, bool)>,
+}
+
+impl<'tcx> OrphanChecker<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self {
+        OrphanChecker {
+            tcx,
+            in_crate,
+            in_self_ty: true,
+            search_first_local_ty: false,
+            non_local_tys: Vec::new(),
         }
     }
-}
 
-/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the
-/// type parameters of the ADT, or `T`, respectively. For non-fundamental
-/// types, returns `None`.
-fn fundamental_ty_inner_tys<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> Option<impl Iterator<Item = Ty<'tcx>>> {
-    let (first_ty, rest_tys) = match *ty.kind() {
-        ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()),
-        ty::Adt(def, substs) if def.is_fundamental() => {
-            let mut types = substs.types();
-
-            // FIXME(eddyb) actually validate `#[fundamental]` up-front.
-            match types.next() {
-                None => {
-                    tcx.sess.span_err(
-                        tcx.def_span(def.did()),
-                        "`#[fundamental]` requires at least one type parameter",
-                    );
-
-                    return None;
-                }
+    fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
+        self.non_local_tys.push((t, self.in_self_ty));
+        ControlFlow::CONTINUE
+    }
 
-                Some(first_ty) => (first_ty, types),
-            }
+    fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
+        if self.search_first_local_ty {
+            ControlFlow::CONTINUE
+        } else {
+            ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t))
         }
-        _ => return None,
-    };
+    }
 
-    Some(iter::once(first_ty).chain(rest_tys))
+    fn def_id_is_local(&mut self, def_id: DefId) -> bool {
+        match self.in_crate {
+            InCrate::Local => def_id.is_local(),
+            InCrate::Remote => false,
+        }
+    }
 }
 
-fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
-    match in_crate {
-        // The type is local to *this* crate - it will not be
-        // local in any other crate.
-        InCrate::Remote => false,
-        InCrate::Local => def_id.is_local(),
-    }
+enum OrphanCheckEarlyExit<'tcx> {
+    ParamTy(Ty<'tcx>),
+    LocalTy(Ty<'tcx>),
 }
 
-fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
-    debug!("ty_is_local_constructor({:?})", ty);
-
-    match *ty.kind() {
-        ty::Bool
-        | ty::Char
-        | ty::Int(..)
-        | ty::Uint(..)
-        | ty::Float(..)
-        | ty::Str
-        | ty::FnDef(..)
-        | ty::FnPtr(_)
-        | ty::Array(..)
-        | ty::Slice(..)
-        | ty::RawPtr(..)
-        | ty::Ref(..)
-        | ty::Never
-        | ty::Tuple(..)
-        | ty::Param(..)
-        | ty::Projection(..) => false,
-
-        ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate {
-            InCrate::Local => false,
-            // The inference variable might be unified with a local
-            // type in that remote crate.
-            InCrate::Remote => true,
-        },
-
-        ty::Adt(def, _) => def_id_is_local(def.did(), in_crate),
-        ty::Foreign(did) => def_id_is_local(did, in_crate),
-        ty::Opaque(..) => {
-            // This merits some explanation.
-            // Normally, opaque types are not involved when performing
-            // coherence checking, since it is illegal to directly
-            // implement a trait on an opaque type. However, we might
-            // end up looking at an opaque type during coherence checking
-            // if an opaque type gets used within another type (e.g. as
-            // a type parameter). This requires us to decide whether or
-            // not an opaque type should be considered 'local' or not.
-            //
-            // We choose to treat all opaque types as non-local, even
-            // those that appear within the same crate. This seems
-            // somewhat surprising at first, but makes sense when
-            // you consider that opaque types are supposed to hide
-            // the underlying type *within the same crate*. When an
-            // opaque type is used from outside the module
-            // where it is declared, it should be impossible to observe
-            // anything about it other than the traits that it implements.
-            //
-            // The alternative would be to look at the underlying type
-            // to determine whether or not the opaque type itself should
-            // be considered local. However, this could make it a breaking change
-            // to switch the underlying ('defining') type from a local type
-            // to a remote type. This would violate the rule that opaque
-            // types should be completely opaque apart from the traits
-            // that they implement, so we don't use this behavior.
-            false
-        }
+impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
+    type BreakTy = OrphanCheckEarlyExit<'tcx>;
+    fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        ControlFlow::CONTINUE
+    }
 
-        ty::Dynamic(ref tt, ..) => {
-            if let Some(principal) = tt.principal() {
-                def_id_is_local(principal.def_id(), in_crate)
-            } else {
-                false
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        let result = match *ty.kind() {
+            ty::Bool
+            | ty::Char
+            | ty::Int(..)
+            | ty::Uint(..)
+            | ty::Float(..)
+            | ty::Str
+            | ty::FnDef(..)
+            | ty::FnPtr(_)
+            | ty::Array(..)
+            | ty::Slice(..)
+            | ty::RawPtr(..)
+            | ty::Never
+            | ty::Tuple(..)
+            | ty::Projection(..) => self.found_non_local_ty(ty),
+
+            ty::Param(..) => self.found_param_ty(ty),
+
+            ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match self.in_crate {
+                InCrate::Local => self.found_non_local_ty(ty),
+                // The inference variable might be unified with a local
+                // type in that remote crate.
+                InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+            },
+
+            // For fundamental types, we just look inside of them.
+            ty::Ref(_, ty, _) => ty.visit_with(self),
+            ty::Adt(def, substs) => {
+                if self.def_id_is_local(def.did()) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else if def.is_fundamental() {
+                    substs.visit_with(self)
+                } else {
+                    self.found_non_local_ty(ty)
+                }
             }
-        }
+            ty::Foreign(def_id) => {
+                if self.def_id_is_local(def_id) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            ty::Dynamic(tt, ..) => {
+                let principal = tt.principal().map(|p| p.def_id());
+                if principal.map_or(false, |p| self.def_id_is_local(p)) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+            ty::Opaque(..) | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+                self.tcx.sess.delay_span_bug(
+                    DUMMY_SP,
+                    format!("ty_is_local invoked on closure or generator: {:?}", ty),
+                );
+                ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+            }
+        };
+        // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
+        // the first type we visit is always the self type.
+        self.in_self_ty = false;
+        result
+    }
 
-        ty::Error(_) => true,
-
-        // These variants should never appear during coherence checking because they
-        // cannot be named directly.
-        //
-        // They could be indirectly used through an opaque type. While using opaque types
-        // in impls causes an error, this path can still be hit afterwards.
-        //
-        // See `test/ui/coherence/coherence-with-closure.rs` for an example where this
-        // could happens.
-        ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
-            tcx.sess.delay_span_bug(
-                DUMMY_SP,
-                format!("ty_is_local invoked on closure or generator: {:?}", ty),
-            );
-            true
-        }
+    // FIXME: Constants should participate in orphan checking.
+    fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        ControlFlow::CONTINUE
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index e6284b1c4ac..decbf013311 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -185,14 +185,20 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
         }
         let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
         match concrete {
-            Err(ErrorHandled::TooGeneric) => Err(if !uv.has_infer_types_or_consts() {
+            Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
+                NotConstEvaluatable::MentionsInfer
+            } else if uv.has_param_types_or_consts() {
                 infcx
                     .tcx
                     .sess
                     .delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv));
                 NotConstEvaluatable::MentionsParam
             } else {
-                NotConstEvaluatable::MentionsInfer
+                let guar = infcx.tcx.sess.delay_span_bug(
+                    span,
+                    format!("Missing value for constant, but no error reported?"),
+                );
+                NotConstEvaluatable::Error(guar)
             }),
             Err(ErrorHandled::Linted) => {
                 let reported = infcx
@@ -240,8 +246,11 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
 
             Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
                 NotConstEvaluatable::MentionsInfer
-                } else {
+                } else if uv.has_param_types_or_consts() {
                 NotConstEvaluatable::MentionsParam
+            } else {
+                let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
+                NotConstEvaluatable::Error(guar)
             }),
             Err(ErrorHandled::Linted) => {
                 let reported =
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 0f7dc6a1257..6c177f63887 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -15,8 +15,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 
 pub trait TraitEngineExt<'tcx> {
     fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
-
-    fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box<Self>;
 }
 
 impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
@@ -27,14 +25,6 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
             Box::new(FulfillmentContext::new())
         }
     }
-
-    fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box<Self> {
-        if tcx.sess.opts.unstable_opts.chalk {
-            Box::new(ChalkFulfillmentContext::new())
-        } else {
-            Box::new(FulfillmentContext::new_ignoring_regions())
-        }
-    }
 }
 
 /// Used if you want to have pleasant experience when dealing
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 29df771b957..2f92a77a795 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -22,7 +22,6 @@ use rustc_hir::intravisit::Visitor;
 use rustc_hir::GenericParam;
 use rustc_hir::Item;
 use rustc_hir::Node;
-use rustc_infer::infer::error_reporting::same_type_modulo_infer;
 use rustc_infer::traits::TraitEngine;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -640,7 +639,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                             if expected.len() == 1 { "" } else { "s" },
                                         )
                                     );
-                                } else if !same_type_modulo_infer(given_ty, expected_ty) {
+                                } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
                                     // Print type mismatch
                                     let (expected_args, given_args) =
                                         self.cmp(given_ty, expected_ty);
@@ -789,24 +788,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)
                     }
 
-                    ty::PredicateKind::RegionOutlives(predicate) => {
-                        let predicate = bound_predicate.rebind(predicate);
-                        let predicate = self.resolve_vars_if_possible(predicate);
-                        let err = self
-                            .region_outlives_predicate(&obligation.cause, predicate)
-                            .err()
-                            .unwrap();
-                        struct_span_err!(
-                            self.tcx.sess,
-                            span,
-                            E0279,
-                            "the requirement `{}` is not satisfied (`{}`)",
-                            predicate,
-                            err,
-                        )
-                    }
-
-                    ty::PredicateKind::Projection(..) | ty::PredicateKind::TypeOutlives(..) => {
+                    ty::PredicateKind::RegionOutlives(..)
+                    | ty::PredicateKind::Projection(..)
+                    | ty::PredicateKind::TypeOutlives(..) => {
                         let predicate = self.resolve_vars_if_possible(obligation.predicate);
                         struct_span_err!(
                             self.tcx.sess,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index bca80e7ab8a..7ab85e7fa66 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -378,7 +378,7 @@ fn suggest_restriction<'tcx>(
             replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))
                 .to_ty(tcx),
         });
-        if !trait_pred.is_suggestable(tcx) {
+        if !trait_pred.is_suggestable(tcx, false) {
             return;
         }
         // We know we have an `impl Trait` that doesn't satisfy a required projection.
@@ -417,7 +417,7 @@ fn suggest_restriction<'tcx>(
             Applicability::MaybeIncorrect,
         );
     } else {
-        if !trait_pred.is_suggestable(tcx) {
+        if !trait_pred.is_suggestable(tcx, false) {
             return;
         }
         // Trivial case: `T` needs an extra bound: `T: Bound`.
@@ -586,7 +586,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     // else in the predicate.
                     if !trait_pred.skip_binder().trait_ref.substs[1..]
                         .iter()
-                        .all(|g| g.is_suggestable(self.tcx))
+                        .all(|g| g.is_suggestable(self.tcx, false))
                     {
                         return;
                     }
@@ -607,10 +607,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                 "{}, {}={}>",
                                 &constraint[..constraint.len() - 1],
                                 item.name,
-                                term.to_string()
+                                term
                             );
                         } else {
-                            constraint.push_str(&format!("<{}={}>", item.name, term.to_string()));
+                            constraint.push_str(&format!("<{}={}>", item.name, term));
                         }
                     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 34b37c4e410..556ef466cd1 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -58,19 +58,6 @@ pub struct FulfillmentContext<'tcx> {
 
     relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
 
-    // Should this fulfillment context register type-lives-for-region
-    // obligations on its parent infcx? In some cases, region
-    // obligations are either already known to hold (normalization) or
-    // hopefully verified elsewhere (type-impls-bound), and therefore
-    // should not be checked.
-    //
-    // Note that if we are normalizing a type that we already
-    // know is well-formed, there should be no harm setting this
-    // to true - all the region variables should be determinable
-    // using the RFC 447 rules, which don't depend on
-    // type-lives-for-region constraints, and because the type
-    // is well-formed, the constraints should hold.
-    register_region_obligations: bool,
     // Is it OK to register obligations into this infcx inside
     // an infcx snapshot?
     //
@@ -103,7 +90,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
             relationships: FxHashMap::default(),
-            register_region_obligations: true,
             usable_in_snapshot: false,
         }
     }
@@ -112,30 +98,18 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
             relationships: FxHashMap::default(),
-            register_region_obligations: true,
             usable_in_snapshot: true,
         }
     }
 
-    pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
-        FulfillmentContext {
-            predicates: ObligationForest::new(),
-            relationships: FxHashMap::default(),
-            register_region_obligations: false,
-            usable_in_snapshot: false,
-        }
-    }
-
     /// Attempts to select obligations using `selcx`.
     fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
         let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
         let _enter = span.enter();
 
         // Process pending obligations.
-        let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut FulfillProcessor {
-            selcx,
-            register_region_obligations: self.register_region_obligations,
-        });
+        let outcome: Outcome<_, _> =
+            self.predicates.process_obligations(&mut FulfillProcessor { selcx });
 
         // FIXME: if we kept the original cache key, we could mark projection
         // obligations as complete for the projection cache here.
@@ -239,7 +213,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
 
 struct FulfillProcessor<'a, 'b, 'tcx> {
     selcx: &'a mut SelectionContext<'b, 'tcx>,
-    register_region_obligations: bool,
 }
 
 fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> {
@@ -385,19 +358,16 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                 }
 
                 ty::PredicateKind::RegionOutlives(data) => {
-                    match infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)) {
-                        Ok(()) => ProcessResult::Changed(vec![]),
-                        Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
+                    if infcx.considering_regions || data.has_placeholders() {
+                        infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
                     }
+
+                    ProcessResult::Changed(vec![])
                 }
 
                 ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
-                    if self.register_region_obligations {
-                        self.selcx.infcx().register_region_obligation_with_cause(
-                            t_a,
-                            r_b,
-                            &obligation.cause,
-                        );
+                    if infcx.considering_regions {
+                        infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause);
                     }
                     ProcessResult::Changed(vec![])
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index a14bf72242b..3ef51b0c27a 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -163,7 +163,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
         // The handling of regions in this area of the code is terrible,
         // see issue #29149. We should be able to improve on this with
         // NLL.
-        let mut fulfill_cx = FulfillmentContext::new_ignoring_regions();
+        let mut fulfill_cx = FulfillmentContext::new();
 
         // We can use a dummy node-id here because we won't pay any mind
         // to region obligations that arise (there shouldn't really be any
@@ -207,21 +207,21 @@ fn do_normalize_predicates<'tcx>(
     predicates: Vec<ty::Predicate<'tcx>>,
 ) -> Result<Vec<ty::Predicate<'tcx>>, ErrorGuaranteed> {
     let span = cause.span;
-    tcx.infer_ctxt().enter(|infcx| {
-        // FIXME. We should really... do something with these region
-        // obligations. But this call just continues the older
-        // behavior (i.e., doesn't cause any new bugs), and it would
-        // take some further refactoring to actually solve them. In
-        // particular, we would have to handle implied bounds
-        // properly, and that code is currently largely confined to
-        // regionck (though I made some efforts to extract it
-        // out). -nmatsakis
-        //
-        // @arielby: In any case, these obligations are checked
-        // by wfcheck anyway, so I'm not sure we have to check
-        // them here too, and we will remove this function when
-        // we move over to lazy normalization *anyway*.
-        let fulfill_cx = FulfillmentContext::new_ignoring_regions();
+    // FIXME. We should really... do something with these region
+    // obligations. But this call just continues the older
+    // behavior (i.e., doesn't cause any new bugs), and it would
+    // take some further refactoring to actually solve them. In
+    // particular, we would have to handle implied bounds
+    // properly, and that code is currently largely confined to
+    // regionck (though I made some efforts to extract it
+    // out). -nmatsakis
+    //
+    // @arielby: In any case, these obligations are checked
+    // by wfcheck anyway, so I'm not sure we have to check
+    // them here too, and we will remove this function when
+    // we move over to lazy normalization *anyway*.
+    tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
+        let fulfill_cx = FulfillmentContext::new();
         let predicates =
             match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
                 Ok(predicates) => predicates,
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
index 56bdeafeeca..8148e2b7871 100644
--- a/compiler/rustc_trait_selection/src/traits/relationships.rs
+++ b/compiler/rustc_trait_selection/src/traits/relationships.rs
@@ -31,14 +31,14 @@ pub(crate) fn update<'tcx, T>(
             obligation
                 .predicate
                 .kind()
-                .map_bound(|_| {
+                .rebind(
                     // (*) binder moved here
                     ty::PredicateKind::Trait(ty::TraitPredicate {
                         trait_ref,
                         constness: tpred.constness,
                         polarity: tpred.polarity,
                     })
-                })
+                )
                 .to_predicate(infcx.tcx),
         );
         // Don't report overflow errors. Otherwise equivalent to may_hold.
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index da8ca6e5749..d4c9fd1c5f9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -42,115 +42,96 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         candidate: SelectionCandidate<'tcx>,
     ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
-        let mut obligation = obligation;
-        let new_obligation;
-
-        // HACK(const_trait_impl): the surrounding environment is remapped to a non-const context
-        // because nested obligations might be actually `~const` then (incorrectly) requiring
-        // const impls. for example:
-        // ```
-        // pub trait Super {}
-        // pub trait Sub: Super {}
-        //
-        // impl<A> const Super for &A where A: ~const Super {}
-        // impl<A> const Sub for &A where A: ~const Sub {}
-        // ```
-        //
-        // The procedure to check the code above without the remapping code is as follows:
-        // ```
-        // CheckWf(impl const Sub for &A where A: ~const Sub) // <- const env
-        // CheckPredicate(&A: Super)
-        // CheckPredicate(A: ~const Super) // <- still const env, failure
-        // ```
-        if obligation.param_env.is_const() && !obligation.predicate.is_const_if_const() {
-            new_obligation = TraitObligation {
-                cause: obligation.cause.clone(),
-                param_env: obligation.param_env.without_const(),
-                ..*obligation
-            };
-            obligation = &new_obligation;
-        }
-
-        match candidate {
+        let mut impl_src = match candidate {
             BuiltinCandidate { has_nested } => {
                 let data = self.confirm_builtin_candidate(obligation, has_nested);
-                Ok(ImplSource::Builtin(data))
+                ImplSource::Builtin(data)
             }
 
             ParamCandidate(param) => {
                 let obligations =
                     self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
-                Ok(ImplSource::Param(obligations, param.skip_binder().constness))
+                ImplSource::Param(obligations, param.skip_binder().constness)
             }
 
             ImplCandidate(impl_def_id) => {
-                Ok(ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id)))
+                ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))
             }
 
             AutoImplCandidate(trait_def_id) => {
                 let data = self.confirm_auto_impl_candidate(obligation, trait_def_id);
-                Ok(ImplSource::AutoImpl(data))
+                ImplSource::AutoImpl(data)
             }
 
             ProjectionCandidate(idx) => {
                 let obligations = self.confirm_projection_candidate(obligation, idx)?;
                 // FIXME(jschievink): constness
-                Ok(ImplSource::Param(obligations, ty::BoundConstness::NotConst))
+                ImplSource::Param(obligations, ty::BoundConstness::NotConst)
             }
 
             ObjectCandidate(idx) => {
                 let data = self.confirm_object_candidate(obligation, idx)?;
-                Ok(ImplSource::Object(data))
+                ImplSource::Object(data)
             }
 
             ClosureCandidate => {
                 let vtable_closure = self.confirm_closure_candidate(obligation)?;
-                Ok(ImplSource::Closure(vtable_closure))
+                ImplSource::Closure(vtable_closure)
             }
 
             GeneratorCandidate => {
                 let vtable_generator = self.confirm_generator_candidate(obligation)?;
-                Ok(ImplSource::Generator(vtable_generator))
+                ImplSource::Generator(vtable_generator)
             }
 
             FnPointerCandidate { .. } => {
                 let data = self.confirm_fn_pointer_candidate(obligation)?;
-                Ok(ImplSource::FnPointer(data))
+                ImplSource::FnPointer(data)
             }
 
             DiscriminantKindCandidate => {
-                Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData))
+                ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
             }
 
-            PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)),
+            PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData),
 
             TraitAliasCandidate(alias_def_id) => {
                 let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
-                Ok(ImplSource::TraitAlias(data))
+                ImplSource::TraitAlias(data)
             }
 
             BuiltinObjectCandidate => {
                 // This indicates something like `Trait + Send: Send`. In this case, we know that
                 // this holds because that's what the object type is telling us, and there's really
                 // no additional obligations to prove and no types in particular to unify, etc.
-                Ok(ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst))
+                ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst)
             }
 
             BuiltinUnsizeCandidate => {
                 let data = self.confirm_builtin_unsize_candidate(obligation)?;
-                Ok(ImplSource::Builtin(data))
+                ImplSource::Builtin(data)
             }
 
             TraitUpcastingUnsizeCandidate(idx) => {
                 let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
-                Ok(ImplSource::TraitUpcasting(data))
+                ImplSource::TraitUpcasting(data)
             }
 
             ConstDestructCandidate(def_id) => {
                 let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
-                Ok(ImplSource::ConstDestruct(data))
+                ImplSource::ConstDestruct(data)
             }
+        };
+
+        if !obligation.predicate.is_const_if_const() {
+            // normalize nested predicates according to parent predicate's constness.
+            impl_src = impl_src.map(|mut o| {
+                o.predicate = o.predicate.without_const(self.tcx());
+                o
+            });
         }
+
+        Ok(impl_src)
     }
 
     fn confirm_projection_candidate(
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index fa2d2c751d9..17f34012d1d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -789,7 +789,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let mut param_env = obligation.param_env;
 
         fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| {
-            pred.remap_constness(self.tcx(), &mut param_env);
+            pred.remap_constness(&mut param_env);
             pred
         });
 
@@ -1321,7 +1321,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
         let tcx = self.tcx();
         let mut pred = cache_fresh_trait_pred.skip_binder();
-        pred.remap_constness(tcx, &mut param_env);
+        pred.remap_constness(&mut param_env);
 
         if self.can_use_global_caches(param_env) {
             if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) {
@@ -1375,7 +1375,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let tcx = self.tcx();
         let mut pred = cache_fresh_trait_pred.skip_binder();
 
-        pred.remap_constness(tcx, &mut param_env);
+        pred.remap_constness(&mut param_env);
 
         if !self.can_cache_candidate(&candidate) {
             debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable");
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 2c4a453aefc..5f77aae6f22 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -207,18 +207,7 @@ fn fulfill_implication<'a, 'tcx>(
     // (which are packed up in penv)
 
     infcx.save_and_restore_in_snapshot_flag(|infcx| {
-        // If we came from `translate_substs`, we already know that the
-        // predicates for our impl hold (after all, we know that a more
-        // specialized impl holds, so our impl must hold too), and
-        // we only want to process the projections to determine the
-        // the types in our substs using RFC 447, so we can safely
-        // ignore region obligations, which allows us to avoid threading
-        // a node-id to assign them with.
-        //
-        // If we came from specialization graph construction, then
-        // we already make a mockery out of the region system, so
-        // why not ignore them a bit earlier?
-        let mut fulfill_cx = FulfillmentContext::new_ignoring_regions();
+        let mut fulfill_cx = FulfillmentContext::new();
         for oblig in obligations.chain(more_obligations) {
             fulfill_cx.register_predicate_obligation(&infcx, oblig);
         }
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index c7cac8fca89..4d4d55de5f4 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -47,7 +47,7 @@ fn compute_implied_outlives_bounds<'tcx>(
     // process it next. Because the resulting predicates aren't always
     // guaranteed to be a subset of the original type, so we need to store the
     // WF args we've computed in a set.
-    let mut checked_wf_args = rustc_data_structures::stable_set::FxHashSet::default();
+    let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
     let mut wf_args = vec![ty.into()];
 
     let mut implied_bounds = vec![];
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 5e58f237982..979e997f244 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -280,6 +280,11 @@ fn resolve_associated_item<'tcx>(
                 return Ok(None);
             }
 
+            // If the item does not have a value, then we cannot return an instance.
+            if !leaf_def.item.defaultness.has_value() {
+                return Ok(None);
+            }
+
             let substs = tcx.erase_regions(substs);
 
             // Check if we just resolved an associated `const` declaration from
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index 7efc82efd15..eded7891682 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -1,5 +1,5 @@
 //! Check whether a type is representable.
-use rustc_data_structures::stable_map::FxHashMap;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs
index 6a9ea790a30..ee249050cc6 100644
--- a/compiler/rustc_type_ir/src/codec.rs
+++ b/compiler/rustc_type_ir/src/codec.rs
@@ -1,6 +1,6 @@
 use crate::Interner;
 
-use rustc_data_structures::stable_map::FxHashMap;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_serialize::{Decoder, Encoder};
 
 /// The shorthand encoding uses an enum's variant index `usize`
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 612dc384521..40aa27a29e9 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -86,7 +86,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         let param_type = tcx.infer_ctxt().enter(|infcx| {
                             infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
                         });
-                        if param_type.is_suggestable(tcx) {
+                        if param_type.is_suggestable(tcx, false) {
                             err.span_suggestion(
                                 tcx.def_span(src_def_id),
                                 "consider changing this type parameter to be a `const` generic",
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 9e4da058052..7111812f0b0 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2676,7 +2676,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     span,
                     ty,
                     opt_sugg: Some((span, Applicability::MachineApplicable))
-                        .filter(|_| ty.is_suggestable(tcx)),
+                        .filter(|_| ty.is_suggestable(tcx, false)),
                 });
 
                 ty
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index c733f0d3c86..f629f6a0099 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -9,7 +9,6 @@ use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
-    StatementAsExpression,
 };
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -75,8 +74,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let mut other_arms = vec![]; // Used only for diagnostics.
-        let mut prior_arm_ty = None;
-        for (i, arm) in arms.iter().enumerate() {
+        let mut prior_arm = None;
+        for arm in arms {
             if let Some(g) = &arm.guard {
                 self.diverges.set(Diverges::Maybe);
                 match g {
@@ -96,21 +95,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected);
 
-            let (arm_span, semi_span) =
-                self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
-            let (span, code) = match i {
+            let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind {
+                (Some(blk.hir_id), self.find_block_span(blk))
+            } else {
+                (None, arm.body.span)
+            };
+
+            let (span, code) = match prior_arm {
                 // The reason for the first arm to fail is not that the match arms diverge,
                 // but rather that there's a prior obligation that doesn't hold.
-                0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
-                _ => (
+                None => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
+                Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => (
                     expr.span,
                     ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause {
+                        arm_block_id,
                         arm_span,
+                        arm_ty,
+                        prior_arm_block_id,
+                        prior_arm_ty,
+                        prior_arm_span,
                         scrut_span: scrut.span,
-                        semi_span,
                         source: match_src,
                         prior_arms: other_arms.clone(),
-                        last_ty: prior_arm_ty.unwrap(),
                         scrut_hir_id: scrut.hir_id,
                         opt_suggest_box_span,
                     })),
@@ -139,7 +145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             let ret_ty = ret_coercion.borrow().expected_ty();
                             let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
                             self.can_coerce(arm_ty, ret_ty)
-                                && prior_arm_ty.map_or(true, |t| self.can_coerce(t, ret_ty))
+                                && prior_arm.map_or(true, |(_, t, _)| self.can_coerce(t, ret_ty))
                                 // The match arms need to unify for the case of `impl Trait`.
                                 && !matches!(ret_ty.kind(), ty::Opaque(..))
                         }
@@ -181,7 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if other_arms.len() > 5 {
                 other_arms.remove(0);
             }
-            prior_arm_ty = Some(arm_ty);
+
+            prior_arm = Some((arm_block_id, arm_ty, arm_span));
         }
 
         // If all of the arms in the `match` diverge,
@@ -207,28 +214,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match_ty
     }
 
-    fn get_appropriate_arm_semicolon_removal_span(
-        &self,
-        arms: &'tcx [hir::Arm<'tcx>],
-        i: usize,
-        prior_arm_ty: Option<Ty<'tcx>>,
-        arm_ty: Ty<'tcx>,
-    ) -> (Span, Option<(Span, StatementAsExpression)>) {
-        let arm = &arms[i];
-        let (arm_span, mut semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind {
-            self.find_block_span(blk, prior_arm_ty)
-        } else {
-            (arm.body.span, None)
-        };
-        if semi_span.is_none() && i > 0 {
-            if let hir::ExprKind::Block(blk, _) = &arms[i - 1].body.kind {
-                let (_, semi_span_prev) = self.find_block_span(blk, Some(arm_ty));
-                semi_span = semi_span_prev;
-            }
-        }
-        (arm_span, semi_span)
-    }
-
     /// When the previously checked expression (the scrutinee) diverges,
     /// warn the user about the match arms being unreachable.
     fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) {
@@ -313,7 +298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         else_ty: Ty<'tcx>,
         opt_suggest_box_span: Option<Span>,
     ) -> ObligationCause<'tcx> {
-        let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) {
+        let mut outer_span = if self.tcx.sess.source_map().is_multiline(span) {
             // The `if`/`else` isn't in one line in the output, include some context to make it
             // clear it is an if/else expression:
             // ```
@@ -339,69 +324,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             None
         };
 
-        let mut remove_semicolon = None;
-        let error_sp = if let ExprKind::Block(block, _) = &else_expr.kind {
-            let (error_sp, semi_sp) = self.find_block_span(block, Some(then_ty));
-            remove_semicolon = semi_sp;
-            if block.expr.is_none() && block.stmts.is_empty() {
-                // Avoid overlapping spans that aren't as readable:
-                // ```
-                // 2 |        let x = if true {
-                //   |   _____________-
-                // 3 |  |         3
-                //   |  |         - expected because of this
-                // 4 |  |     } else {
-                //   |  |____________^
-                // 5 | ||
-                // 6 | ||     };
-                //   | ||     ^
-                //   | ||_____|
-                //   | |______if and else have incompatible types
-                //   |        expected integer, found `()`
-                // ```
-                // by not pointing at the entire expression:
-                // ```
-                // 2 |       let x = if true {
-                //   |               ------- `if` and `else` have incompatible types
-                // 3 |           3
-                //   |           - expected because of this
-                // 4 |       } else {
-                //   |  ____________^
-                // 5 | |
-                // 6 | |     };
-                //   | |_____^ expected integer, found `()`
-                // ```
-                if outer_sp.is_some() {
-                    outer_sp = Some(self.tcx.sess.source_map().guess_head_span(span));
-                }
+        let (error_sp, else_id) = if let ExprKind::Block(block, _) = &else_expr.kind {
+            let block = block.innermost_block();
+
+            // Avoid overlapping spans that aren't as readable:
+            // ```
+            // 2 |        let x = if true {
+            //   |   _____________-
+            // 3 |  |         3
+            //   |  |         - expected because of this
+            // 4 |  |     } else {
+            //   |  |____________^
+            // 5 | ||
+            // 6 | ||     };
+            //   | ||     ^
+            //   | ||_____|
+            //   | |______if and else have incompatible types
+            //   |        expected integer, found `()`
+            // ```
+            // by not pointing at the entire expression:
+            // ```
+            // 2 |       let x = if true {
+            //   |               ------- `if` and `else` have incompatible types
+            // 3 |           3
+            //   |           - expected because of this
+            // 4 |       } else {
+            //   |  ____________^
+            // 5 | |
+            // 6 | |     };
+            //   | |_____^ expected integer, found `()`
+            // ```
+            if block.expr.is_none() && block.stmts.is_empty()
+                && let Some(outer_span) = &mut outer_span
+            {
+                *outer_span = self.tcx.sess.source_map().guess_head_span(*outer_span);
             }
-            error_sp
+
+            (self.find_block_span(block), block.hir_id)
         } else {
-            // shouldn't happen unless the parser has done something weird
-            else_expr.span
+            (else_expr.span, else_expr.hir_id)
         };
 
-        // Compute `Span` of `then` part of `if`-expression.
-        let then_sp = if let ExprKind::Block(block, _) = &then_expr.kind {
-            let (then_sp, semi_sp) = self.find_block_span(block, Some(else_ty));
-            remove_semicolon = remove_semicolon.or(semi_sp);
+        let then_id = if let ExprKind::Block(block, _) = &then_expr.kind {
+            let block = block.innermost_block();
+            // Exclude overlapping spans
             if block.expr.is_none() && block.stmts.is_empty() {
-                outer_sp = None; // same as in `error_sp`; cleanup output
+                outer_span = None;
             }
-            then_sp
+            block.hir_id
         } else {
-            // shouldn't happen unless the parser has done something weird
-            then_expr.span
+            then_expr.hir_id
         };
 
         // Finally construct the cause:
         self.cause(
             error_sp,
             ObligationCauseCode::IfExpression(Box::new(IfExpressionCause {
-                then: then_sp,
-                else_sp: error_sp,
-                outer: outer_sp,
-                semicolon: remove_semicolon,
+                else_id,
+                then_id,
+                then_ty,
+                else_ty,
+                outer_span,
                 opt_suggest_box_span,
             })),
         )
@@ -482,22 +465,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn find_block_span(
-        &self,
-        block: &'tcx hir::Block<'tcx>,
-        expected_ty: Option<Ty<'tcx>>,
-    ) -> (Span, Option<(Span, StatementAsExpression)>) {
-        if let Some(expr) = &block.expr {
-            (expr.span, None)
-        } else if let Some(stmt) = block.stmts.last() {
-            // possibly incorrect trailing `;` in the else arm
-            (stmt.span, expected_ty.and_then(|ty| self.could_remove_semicolon(block, ty)))
-        } else {
-            // empty block; point at its entirety
-            (block.span, None)
-        }
-    }
-
     // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
     // we check if the different arms would work with boxed trait objects instead and
     // provide a structured suggestion in that case.
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 66dd5582490..7aaddc2bd7a 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -69,7 +69,7 @@ enum PointerKind<'tcx> {
     /// No metadata attached, ie pointer to sized type or foreign type
     Thin,
     /// A trait object
-    Vtable(Option<DefId>),
+    VTable(Option<DefId>),
     /// Slice
     Length,
     /// The unsize info of this projection
@@ -102,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         Ok(match *t.kind() {
             ty::Slice(_) | ty::Str => Some(PointerKind::Length),
-            ty::Dynamic(ref tty, ..) => Some(PointerKind::Vtable(tty.principal_def_id())),
+            ty::Dynamic(ref tty, ..) => Some(PointerKind::VTable(tty.principal_def_id())),
             ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() {
                 None => Some(PointerKind::Thin),
                 Some(f) => {
@@ -951,7 +951,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         match fcx.pointer_kind(m_cast.ty, self.span)? {
             None => Err(CastError::UnknownCastPtrKind),
             Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
-            Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
+            Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
             Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
             Some(
                 PointerKind::OfProjection(_)
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 69f3f03cfa9..9497d5c4528 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -14,7 +14,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ItemKind, Node, PathSegment};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::hir::nested_filter;
@@ -731,52 +731,52 @@ fn check_opaque_meets_bounds<'tcx>(
     };
     let param_env = tcx.param_env(defining_use_anchor);
 
-    tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| {
-        let ocx = ObligationCtxt::new(&infcx);
-        let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+    tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)).enter(
+        move |infcx| {
+            let ocx = ObligationCtxt::new(&infcx);
+            let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
 
-        let misc_cause = traits::ObligationCause::misc(span, hir_id);
+            let misc_cause = traits::ObligationCause::misc(span, hir_id);
 
-        match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
-            Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
-            Err(ty_err) => {
-                tcx.sess.delay_span_bug(
-                    span,
-                    &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
-                );
+            match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
+                Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
+                Err(ty_err) => {
+                    tcx.sess.delay_span_bug(
+                        span,
+                        &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
+                    );
+                }
             }
-        }
 
-        // 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_type.into())).to_predicate(tcx);
-        ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
-
-        // Check that all obligations are satisfied by the implementation's
-        // version.
-        let errors = ocx.select_all_or_error();
-        if !errors.is_empty() {
-            infcx.report_fulfillment_errors(&errors, None, false);
-        }
-
-        match origin {
-            // Checked when type checking the function containing them.
-            hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
-            // Can have different predicates to their defining use
-            hir::OpaqueTyOrigin::TyAlias => {
-                let outlives_environment = OutlivesEnvironment::new(param_env);
-                infcx.check_region_obligations_and_report_errors(
-                    defining_use_anchor,
-                    &outlives_environment,
-                );
+            // 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_type.into()))
+                .to_predicate(tcx);
+            ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
+
+            // Check that all obligations are satisfied by the implementation's
+            // version.
+            let errors = ocx.select_all_or_error();
+            if !errors.is_empty() {
+                infcx.report_fulfillment_errors(&errors, None, false);
             }
-        }
-
-        // Clean up after ourselves
-        let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-    });
+            match origin {
+                // Checked when type checking the function containing them.
+                hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
+                // Can have different predicates to their defining use
+                hir::OpaqueTyOrigin::TyAlias => {
+                    let outlives_environment = OutlivesEnvironment::new(param_env);
+                    infcx.check_region_obligations_and_report_errors(
+                        defining_use_anchor,
+                        &outlives_environment,
+                    );
+                }
+            }
+            // Clean up after ourselves
+            let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+        },
+    );
 }
 
 fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 1681e6af812..2005fc24ed0 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -182,9 +182,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ty::PredicateKind::Projection(proj_predicate) => self
                             .deduce_sig_from_projection(
                                 Some(span.0),
-                                pred.0.kind().rebind(
-                                    pred.map_bound(|_| proj_predicate).subst(self.tcx, substs),
-                                ),
+                                pred.0
+                                    .kind()
+                                    .rebind(pred.rebind(proj_predicate).subst(self.tcx, substs)),
                             ),
                         _ => None,
                     });
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 3fb8e5080f3..1a9354f5d20 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -2,7 +2,7 @@ use super::potentially_plural_count;
 use crate::check::regionck::OutlivesEnvironmentExt;
 use crate::check::wfcheck;
 use crate::errors::LifetimesOrBoundsMismatchOnTrait;
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -1460,6 +1460,7 @@ pub fn check_type_bounds<'tcx>(
             .map(|e| e.map_bound(|e| *e).transpose_tuple2())
             .map(|(bound, span)| {
                 debug!(?bound);
+                // this is where opaque type is found
                 let concrete_ty_bound = bound.subst(tcx, rebased_substs);
                 debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
 
@@ -1481,7 +1482,6 @@ pub fn check_type_bounds<'tcx>(
             ocx.register_obligations(obligations);
             ocx.register_obligation(obligation);
         }
-
         // Check that all obligations are satisfied by the implementation's
         // version.
         let errors = ocx.select_all_or_error();
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 2d22e9bc76e..8e4cd2392e0 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1803,7 +1803,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .source_map()
                 .span_to_snippet(range_end.expr.span)
                 .map(|s| format!(" from `{s}`"))
-                .unwrap_or(String::new());
+                .unwrap_or_default();
             err.span_suggestion(
                 range_start.span.shrink_to_hi(),
                 &format!("to set the remaining fields{instead}, separate the last named field with a comma"),
@@ -2362,7 +2362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 false
             };
         let expr_snippet =
-            self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new());
+            self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or_default();
         let is_wrapped = expr_snippet.starts_with('(') && expr_snippet.ends_with(')');
         let after_open = expr.span.lo() + rustc_span::BytePos(1);
         let before_close = expr.span.hi() - rustc_span::BytePos(1);
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs
index 15788f410f1..67a89a69f65 100644
--- a/compiler/rustc_typeck/src/check/fallback.rs
+++ b/compiler/rustc_typeck/src/check/fallback.rs
@@ -1,9 +1,8 @@
 use crate::check::FnCtxt;
 use rustc_data_structures::{
-    fx::FxHashMap,
+    fx::{FxHashMap, FxHashSet},
     graph::WithSuccessors,
     graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
-    stable_set::FxHashSet,
 };
 use rustc_middle::ty::{self, Ty};
 
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index d079aeb4801..21b3c9063a7 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -30,17 +30,15 @@ use rustc_middle::ty::{
 };
 use rustc_session::lint;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::source_map::{original_sp, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{self, BytePos, Span};
+use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt,
+    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
 };
 
 use std::collections::hash_map::Entry;
-use std::iter;
 use std::slice;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -1059,84 +1057,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ));
     }
 
-    pub(in super::super) fn could_remove_semicolon(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-    ) -> Option<(Span, StatementAsExpression)> {
-        // Be helpful when the user wrote `{... expr;}` and
-        // taking the `;` off is enough to fix the error.
-        let last_stmt = blk.stmts.last()?;
-        let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else {
-            return None;
-        };
-        let last_expr_ty = self.node_ty(last_expr.hir_id);
-        let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
-            (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
-                if last_def_id == exp_def_id =>
-            {
-                StatementAsExpression::CorrectType
-            }
-            (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
-                debug!(
-                    "both opaque, likely future {:?} {:?} {:?} {:?}",
-                    last_def_id, last_bounds, exp_def_id, exp_bounds
-                );
-
-                let last_local_id = last_def_id.as_local()?;
-                let exp_local_id = exp_def_id.as_local()?;
-
-                match (
-                    &self.tcx.hir().expect_item(last_local_id).kind,
-                    &self.tcx.hir().expect_item(exp_local_id).kind,
-                ) {
-                    (
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
-                    ) if iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| {
-                        match (left, right) {
-                            (
-                                hir::GenericBound::Trait(tl, ml),
-                                hir::GenericBound::Trait(tr, mr),
-                            ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
-                                && ml == mr =>
-                            {
-                                true
-                            }
-                            (
-                                hir::GenericBound::LangItemTrait(langl, _, _, argsl),
-                                hir::GenericBound::LangItemTrait(langr, _, _, argsr),
-                            ) if langl == langr => {
-                                // FIXME: consider the bounds!
-                                debug!("{:?} {:?}", argsl, argsr);
-                                true
-                            }
-                            _ => false,
-                        }
-                    }) =>
-                    {
-                        StatementAsExpression::NeedsBoxing
-                    }
-                    _ => StatementAsExpression::CorrectType,
-                }
-            }
-            _ => StatementAsExpression::CorrectType,
-        };
-        if (matches!(last_expr_ty.kind(), ty::Error(_))
-            || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err())
-            && matches!(needs_box, StatementAsExpression::CorrectType)
-        {
-            return None;
-        }
-        let span = if last_stmt.span.from_expansion() {
-            let mac_call = original_sp(last_stmt.span, blk.span);
-            self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)?
-        } else {
-            last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1))
-        };
-        Some((span, needs_box))
-    }
-
     // Instantiates the given path, which must refer to an item with the given
     // number of type parameters and type.
     #[instrument(skip(self, span), level = "debug")]
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index e6fa95b91e9..84d2878308a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -481,6 +481,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.set_tainted_by_errors();
         let tcx = self.tcx;
 
+        // Get the argument span in the context of the call span so that
+        // suggestions and labels are (more) correct when an arg is a
+        // macro invocation.
+        let normalize_span = |span: Span| -> Span {
+            let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span);
+            // Sometimes macros mess up the spans, so do not normalize the
+            // arg span to equal the error span, because that's less useful
+            // than pointing out the arg expr in the wrong context.
+            if normalized_span.source_equal(error_span) { span } else { normalized_span }
+        };
+
         // Precompute the provided types and spans, since that's all we typically need for below
         let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args
             .iter()
@@ -490,7 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .borrow()
                     .expr_ty_adjusted_opt(*expr)
                     .unwrap_or_else(|| tcx.ty_error());
-                (self.resolve_vars_if_possible(ty), expr.span)
+                (self.resolve_vars_if_possible(ty), normalize_span(expr.span))
             })
             .collect();
         let callee_expr = match &call_expr.peel_blocks().kind {
@@ -573,6 +584,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // If so, we might have just forgotten to wrap some args in a tuple.
             if let Some(ty::Tuple(tys)) =
                 formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind())
+                // If the tuple is unit, we're not actually wrapping any arguments.
+                && !tys.is_empty()
                 && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
             {
                 // Wrap up the N provided arguments starting at this position in a tuple.
@@ -598,11 +611,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Take some care with spans, so we don't suggest wrapping a macro's
                 // innards in parenthesis, for example.
                 if satisfied
-                    && let Some(lo) =
-                        provided_args[mismatch_idx.into()].span.find_ancestor_inside(error_span)
-                    && let Some(hi) = provided_args[(mismatch_idx + tys.len() - 1).into()]
-                        .span
-                        .find_ancestor_inside(error_span)
+                    && let Some((_, lo)) =
+                        provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx))
+                    && let Some((_, hi)) =
+                        provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1))
                 {
                     let mut err;
                     if tys.len() == 1 {
@@ -610,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // so don't do anything special here.
                         err = self.report_and_explain_type_error(
                             TypeTrace::types(
-                                &self.misc(lo),
+                                &self.misc(*lo),
                                 true,
                                 formal_and_expected_inputs[mismatch_idx.into()].1,
                                 provided_arg_tys[mismatch_idx.into()].0,
@@ -1050,7 +1062,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let suggestion_text = if let Some(provided_idx) = provided_idx
                     && let (_, provided_span) = provided_arg_tys[*provided_idx]
                     && let Ok(arg_text) =
-                        source_map.span_to_snippet(provided_span.source_callsite())
+                        source_map.span_to_snippet(provided_span)
                 {
                     arg_text
                 } else {
@@ -1058,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
                     if expected_ty.is_unit() {
                         "()".to_string()
-                    } else if expected_ty.is_suggestable(tcx) {
+                    } else if expected_ty.is_suggestable(tcx, false) {
                         format!("/* {} */", expected_ty)
                     } else {
                         "/* value */".to_string()
@@ -1755,19 +1767,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .flat_map(|a| a.args.iter())
                         {
                             if let hir::GenericArg::Type(hir_ty) = &arg {
-                                if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
-                                    &hir_ty.kind
-                                {
-                                    // Avoid ICE with associated types. As this is best
-                                    // effort only, it's ok to ignore the case. It
-                                    // would trigger in `is_send::<T::AssocType>();`
-                                    // from `typeck-default-trait-impl-assoc-type.rs`.
-                                } else {
-                                    let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
-                                    let ty = self.resolve_vars_if_possible(ty);
-                                    if ty == predicate.self_ty() {
-                                        error.obligation.cause.span = hir_ty.span;
-                                    }
+                                let ty = self.resolve_vars_if_possible(
+                                    self.typeck_results.borrow().node_type(hir_ty.hir_id),
+                                );
+                                if ty == predicate.self_ty() {
+                                    error.obligation.cause.span = hir_ty.span;
                                 }
                             }
                         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index d5ee299c0f9..097fff6418e 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -3,7 +3,6 @@ use crate::astconv::AstConv;
 use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
 
 use rustc_ast::util::parser::ExprPrecedence;
-use rustc_data_structures::stable_set::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
@@ -14,7 +13,7 @@ use rustc_hir::{
 use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty, TypeVisitable};
+use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -507,7 +506,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
         // Only suggest changing the return type for methods that
         // haven't set a return type at all (and aren't `fn main()` or an impl).
-        match (&fn_decl.output, found.is_suggestable(self.tcx), can_suggest, expected.is_unit()) {
+        match (
+            &fn_decl.output,
+            found.is_suggestable(self.tcx, false),
+            can_suggest,
+            expected.is_unit(),
+        ) {
             (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
                 err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found });
                 true
@@ -904,117 +908,4 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             false
         }
     }
-
-    pub(crate) fn consider_returning_binding(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-        err: &mut Diagnostic,
-    ) {
-        let mut shadowed = FxHashSet::default();
-        let mut candidate_idents = vec![];
-        let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
-            if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
-                && let Some(pat_ty) = self.typeck_results.borrow().node_type_opt(*hir_id)
-            {
-                let pat_ty = self.resolve_vars_if_possible(pat_ty);
-                if self.can_coerce(pat_ty, expected_ty)
-                    && !(pat_ty, expected_ty).references_error()
-                    && shadowed.insert(ident.name)
-                {
-                    candidate_idents.push((*ident, pat_ty));
-                }
-            }
-            true
-        };
-
-        let hir = self.tcx.hir();
-        for stmt in blk.stmts.iter().rev() {
-            let StmtKind::Local(local) = &stmt.kind else { continue; };
-            local.pat.walk(&mut find_compatible_candidates);
-        }
-        match hir.find(hir.get_parent_node(blk.hir_id)) {
-            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
-                match hir.find(hir.get_parent_node(*hir_id)) {
-                    Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
-                        pat.walk(&mut find_compatible_candidates);
-                    }
-                    Some(
-                        hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
-                        | hir::Node::ImplItem(hir::ImplItem {
-                            kind: hir::ImplItemKind::Fn(_, body),
-                            ..
-                        })
-                        | hir::Node::TraitItem(hir::TraitItem {
-                            kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
-                            ..
-                        })
-                        | hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
-                            ..
-                        }),
-                    ) => {
-                        for param in hir.body(*body).params {
-                            param.pat.walk(&mut find_compatible_candidates);
-                        }
-                    }
-                    Some(hir::Node::Expr(hir::Expr {
-                        kind:
-                            hir::ExprKind::If(
-                                hir::Expr { kind: hir::ExprKind::Let(let_), .. },
-                                then_block,
-                                _,
-                            ),
-                        ..
-                    })) if then_block.hir_id == *hir_id => {
-                        let_.pat.walk(&mut find_compatible_candidates);
-                    }
-                    _ => {}
-                }
-            }
-            _ => {}
-        }
-
-        match &candidate_idents[..] {
-            [(ident, _ty)] => {
-                let sm = self.tcx.sess.source_map();
-                if let Some(stmt) = blk.stmts.last() {
-                    let stmt_span = sm.stmt_span(stmt.span, blk.span);
-                    let sugg = if sm.is_multiline(blk.span)
-                        && let Some(spacing) = sm.indentation_before(stmt_span)
-                    {
-                        format!("\n{spacing}{ident}")
-                    } else {
-                        format!(" {ident}")
-                    };
-                    err.span_suggestion_verbose(
-                        stmt_span.shrink_to_hi(),
-                        format!("consider returning the local binding `{ident}`"),
-                        sugg,
-                        Applicability::MachineApplicable,
-                    );
-                } else {
-                    let sugg = if sm.is_multiline(blk.span)
-                        && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
-                    {
-                        format!("\n{spacing}    {ident}\n{spacing}")
-                    } else {
-                        format!(" {ident} ")
-                    };
-                    let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
-                    err.span_suggestion_verbose(
-                        sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
-                        format!("consider returning the local binding `{ident}`"),
-                        sugg,
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            values if (1..3).contains(&values.len()) => {
-                let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
-                err.span_note(spans, "consider returning one of these bindings");
-            }
-            _ => {}
-        }
-    }
 }
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
index 14b226d91cb..518cd734236 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
@@ -17,8 +17,7 @@ use self::record_consumed_borrow::find_consumed_and_borrowed;
 use crate::check::FnCtxt;
 use hir::def_id::DefId;
 use hir::{Body, HirId, HirIdMap, Node};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
index da2db3f2e30..a2c23db162b 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
@@ -6,7 +6,7 @@ use hir::{
     intravisit::{self, Visitor},
     Body, Expr, ExprKind, Guard, HirId, LoopIdError,
 };
-use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_index::vec::IndexVec;
 use rustc_middle::{
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
index 67cc46f21f0..ded0888c33e 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -4,7 +4,7 @@ use crate::{
     expr_use_visitor::{self, ExprUseVisitor},
 };
 use hir::{def_id::DefId, Body, HirId, HirIdMap};
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind};
 use rustc_middle::ty::{ParamEnv, TyCtxt};
@@ -72,9 +72,8 @@ impl<'tcx> ExprUseDelegate<'tcx> {
     }
 
     fn mark_consumed(&mut self, consumer: HirId, target: TrackedValue) {
-        if !self.places.consumed.contains_key(&consumer) {
-            self.places.consumed.insert(consumer, <_>::default());
-        }
+        self.places.consumed.entry(consumer).or_insert_with(|| <_>::default());
+
         debug!(?consumer, ?target, "mark_consumed");
         self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
     }
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index 4afbc00b37c..2f841fc277d 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -86,7 +86,10 @@ impl<'tcx> Inherited<'_, 'tcx> {
         let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
 
         InheritedBuilder {
-            infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner),
+            infcx: tcx
+                .infer_ctxt()
+                .ignoring_regions()
+                .with_fresh_in_progress_typeck_results(hir_owner),
             def_id,
         }
     }
@@ -113,7 +116,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
                 maybe_typeck_results: infcx.in_progress_typeck_results,
             },
             infcx,
-            fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new_ignoring_regions(tcx)),
+            fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
             locals: RefCell::new(Default::default()),
             deferred_sized_obligations: RefCell::new(Vec::new()),
             deferred_call_resolutions: RefCell::new(Default::default()),
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 7fe710cf8f4..3f2a0da8d65 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -400,6 +400,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
 
             sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)),
 
+            sym::vtable_size | sym::vtable_align => {
+                (0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize)
+            }
+
             other => {
                 tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
                 return;
diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs
index 0adf0d28aae..df94abbafb1 100644
--- a/compiler/rustc_typeck/src/check/intrinsicck.rs
+++ b/compiler/rustc_typeck/src/check/intrinsicck.rs
@@ -1,5 +1,5 @@
 use rustc_ast::InlineAsmTemplatePiece;
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 2b037c3fd2b..b088fc9eddb 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -87,10 +87,10 @@ mod op;
 mod pat;
 mod place_op;
 mod region;
-mod regionck;
+pub mod regionck;
 pub mod rvalue_scopes;
 mod upvar;
-mod wfcheck;
+pub mod wfcheck;
 pub mod writeback;
 
 use check::{check_abi, check_fn, check_mod_item_types};
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index a2daf6886f1..9858cd8fa19 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -630,18 +630,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let rm_borrow_msg = "remove the borrow to obtain an owned `String`";
         let to_owned_msg = "create an owned `String` from a string reference";
 
-        let string_type = self.tcx.get_diagnostic_item(sym::String);
-        let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() {
-            Some(ty_def) => Some(ty_def.did()) == string_type,
-            None => false,
+        let is_std_string = |ty: Ty<'tcx>| {
+            ty.ty_adt_def()
+                .map_or(false, |ty_def| self.tcx.is_diagnostic_item(sym::String, ty_def.did()))
         };
 
         match (lhs_ty.kind(), rhs_ty.kind()) {
             (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str
-                if (*l_ty.kind() == Str || is_std_string(l_ty)) && (
-                        *r_ty.kind() == Str || is_std_string(r_ty) ||
-                        &format!("{:?}", rhs_ty) == "&&str"
-                    ) =>
+                if (*l_ty.kind() == Str || is_std_string(l_ty))
+                    && (*r_ty.kind() == Str
+                        || is_std_string(r_ty)
+                        || matches!(
+                            r_ty.kind(), Ref(_, inner_ty, _) if *inner_ty.kind() == Str
+                        )) =>
             {
                 if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str`
                     err.span_label(op.span, "`+` cannot be used to concatenate two `&str` strings");
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 1c3c5f999bc..d49a6138f7a 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -1,5 +1,5 @@
 use crate::outlives::outlives_bounds::InferCtxtExt as _;
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::InferCtxt;
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 3bd3e2d8091..d175d7e0695 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -49,8 +49,7 @@ use rustc_span::sym;
 use rustc_span::{BytePos, Pos, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
 
-use rustc_data_structures::stable_map::FxHashMap;
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::vec::Idx;
 use rustc_target::abi::VariantIdx;
 
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 6df59ea1096..1b80e4edca9 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -1913,7 +1913,7 @@ impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> {
     }
 }
 
-pub(super) fn impl_implied_bounds<'tcx>(
+pub fn impl_implied_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     impl_def_id: LocalDefId,
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 23ac638b2f4..d102fb45a8c 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -5,7 +5,7 @@
 use crate::check::FnCtxt;
 
 use hir::def_id::LocalDefId;
-use rustc_data_structures::stable_map::FxHashMap;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index a92c37ff143..d8e42729ff3 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -116,8 +116,8 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                 // why this field does not implement Copy. This is useful because sometimes
                 // it is not immediately clear why Copy is not implemented for a field, since
                 // all we point at is the field itself.
-                tcx.infer_ctxt().enter(|infcx| {
-                    let mut fulfill_cx = traits::FulfillmentContext::new_ignoring_regions();
+                tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
+                    let mut fulfill_cx = traits::FulfillmentContext::new();
                     fulfill_cx.register_bound(
                         &infcx,
                         param_env,
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 6ec741269e8..c562599e2cc 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1929,7 +1929,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             visitor.visit_ty(ty);
             let mut diag = bad_placeholder(tcx, visitor.0, "return type");
             let ret_ty = fn_sig.skip_binder().output();
-            if ret_ty.is_suggestable(tcx) {
+            if ret_ty.is_suggestable(tcx, false) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with the correct return type",
@@ -1938,7 +1938,12 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                 );
             } else if matches!(ret_ty.kind(), ty::FnDef(..)) {
                 let fn_sig = ret_ty.fn_sig(tcx);
-                if fn_sig.skip_binder().inputs_and_output.iter().all(|t| t.is_suggestable(tcx)) {
+                if fn_sig
+                    .skip_binder()
+                    .inputs_and_output
+                    .iter()
+                    .all(|t| t.is_suggestable(tcx, false))
+                {
                     diag.span_suggestion(
                         ty.span,
                         "replace with the correct return type",
@@ -2813,7 +2818,37 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                         )
                         .emit();
                 }
-                None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED,
+                None => {
+                    // Unfortunately, unconditionally using `llvm.used` causes
+                    // issues in handling `.init_array` with the gold linker,
+                    // but using `llvm.compiler.used` caused a nontrival amount
+                    // of unintentional ecosystem breakage -- particularly on
+                    // Mach-O targets.
+                    //
+                    // As a result, we emit `llvm.compiler.used` only on ELF
+                    // targets. This is somewhat ad-hoc, but actually follows
+                    // our pre-LLVM 13 behavior (prior to the ecosystem
+                    // breakage), and seems to match `clang`'s behavior as well
+                    // (both before and after LLVM 13), possibly because they
+                    // have similar compatibility concerns to us. See
+                    // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
+                    // and following comments for some discussion of this, as
+                    // well as the comments in `rustc_codegen_llvm` where these
+                    // flags are handled.
+                    //
+                    // Anyway, to be clear: this is still up in the air
+                    // somewhat, and is subject to change in the future (which
+                    // is a good thing, because this would ideally be a bit
+                    // more firmed up).
+                    let is_like_elf = !(tcx.sess.target.is_like_osx
+                        || tcx.sess.target.is_like_windows
+                        || tcx.sess.target.is_like_wasm);
+                    codegen_fn_attrs.flags = if is_like_elf {
+                        CodegenFnAttrFlags::USED
+                    } else {
+                        CodegenFnAttrFlags::USED_LINKER
+                    };
+                }
             }
         } else if attr.has_name(sym::cmse_nonsecure_entry) {
             if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
@@ -2939,6 +2974,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
                     } else if item.has_name(sym::memtag) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
+                    } else if item.has_name(sym::shadow_call_stack) {
+                        codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
                     } else if item.has_name(sym::thread) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
                     } else if item.has_name(sym::hwaddress) {
@@ -2946,7 +2983,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                     } else {
                         tcx.sess
                             .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
-                            .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`")
+                            .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
                             .emit();
                     }
                 }
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index 6ece955de64..f16888345e9 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -65,6 +65,8 @@
 //! cause use after frees with purely safe code in the same way as specializing
 //! on traits with methods can.
 
+use crate::check::regionck::OutlivesEnvironmentExt;
+use crate::check::wfcheck::impl_implied_bounds;
 use crate::constrained_generic_params as cgp;
 use crate::errors::SubstsOnOverriddenImpl;
 
@@ -148,8 +150,15 @@ fn get_impl_substs<'tcx>(
     let impl2_substs =
         translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
 
-    // Conservatively use an empty `ParamEnv`.
-    let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
+    let mut outlives_env = OutlivesEnvironment::new(param_env);
+    let implied_bounds =
+        impl_implied_bounds(infcx.tcx, param_env, impl1_def_id, tcx.def_span(impl1_def_id));
+    outlives_env.add_implied_bounds(
+        infcx,
+        implied_bounds,
+        tcx.hir().local_def_id_to_hir_id(impl1_def_id),
+    );
+    infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
     infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
     let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
         let span = tcx.def_span(impl1_def_id);
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 0bddd7a9906..cacbd54b6c2 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -178,6 +178,8 @@ pub struct BTreeMap<
     length: usize,
     /// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes).
     pub(super) alloc: ManuallyDrop<A>,
+    // For dropck; the `Box` avoids making the `Unpin` impl more strict than before
+    _marker: PhantomData<crate::boxed::Box<(K, V)>>,
 }
 
 #[stable(feature = "btree_drop", since = "1.7.0")]
@@ -187,6 +189,19 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V, A: Allocator + Clone> Drop for BTr
     }
 }
 
+// FIXME: This implementation is "wrong", but changing it would be a breaking change.
+// (The bounds of the automatic `UnwindSafe` implementation have been like this since Rust 1.50.)
+// Maybe we can fix it nonetheless with a crater run, or if the `UnwindSafe`
+// traits are deprecated, or disarmed (no longer causing hard errors) in the future.
+#[stable(feature = "btree_unwindsafe", since = "1.64.0")]
+impl<K, V, A: Allocator + Clone> core::panic::UnwindSafe for BTreeMap<K, V, A>
+where
+    A: core::panic::UnwindSafe,
+    K: core::panic::RefUnwindSafe,
+    V: core::panic::RefUnwindSafe,
+{
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K: Clone, V: Clone, A: Allocator + Clone> Clone for BTreeMap<K, V, A> {
     fn clone(&self) -> BTreeMap<K, V, A> {
@@ -204,6 +219,7 @@ impl<K: Clone, V: Clone, A: Allocator + Clone> Clone for BTreeMap<K, V, A> {
                         root: Some(Root::new(alloc.clone())),
                         length: 0,
                         alloc: ManuallyDrop::new(alloc),
+                        _marker: PhantomData,
                     };
 
                     {
@@ -567,7 +583,7 @@ impl<K, V> BTreeMap<K, V> {
     #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
     #[must_use]
     pub const fn new() -> BTreeMap<K, V> {
-        BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(Global) }
+        BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(Global), _marker: PhantomData }
     }
 }
 
@@ -593,6 +609,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
             root: mem::replace(&mut self.root, None),
             length: mem::replace(&mut self.length, 0),
             alloc: self.alloc.clone(),
+            _marker: PhantomData,
         });
     }
 
@@ -615,7 +632,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// ```
     #[unstable(feature = "btreemap_alloc", issue = "32838")]
     pub fn new_in(alloc: A) -> BTreeMap<K, V, A> {
-        BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(alloc) }
+        BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(alloc), _marker: PhantomData }
     }
 }
 
@@ -1320,7 +1337,12 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         let (new_left_len, right_len) = Root::calc_split_length(total_num, &left_root, &right_root);
         self.length = new_left_len;
 
-        BTreeMap { root: Some(right_root), length: right_len, alloc: self.alloc.clone() }
+        BTreeMap {
+            root: Some(right_root),
+            length: right_len,
+            alloc: self.alloc.clone(),
+            _marker: PhantomData,
+        }
     }
 
     /// Creates an iterator that visits all elements (key-value pairs) in
@@ -1445,7 +1467,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         let mut root = Root::new(alloc.clone());
         let mut length = 0;
         root.bulk_push(DedupSortedIter::new(iter.into_iter()), &mut length, alloc.clone());
-        BTreeMap { root: Some(root), length, alloc: ManuallyDrop::new(alloc) }
+        BTreeMap { root: Some(root), length, alloc: ManuallyDrop::new(alloc), _marker: PhantomData }
     }
 }
 
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 8a37fadc56f..fb4454c94cb 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1766,15 +1766,24 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
 ///
 /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious:
 ///
-/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T`
-/// reference) that is accessible by safe code (for example, because you returned it),
-/// then you must not access the data in any way that contradicts that reference for the
-/// remainder of `'a`. For example, this means that if you take the `*mut T` from an
-/// `UnsafeCell<T>` and cast it to an `&T`, then the data in `T` must remain immutable
-/// (modulo any `UnsafeCell` data found within `T`, of course) until that reference's
-/// lifetime expires. Similarly, if you create a `&mut T` reference that is released to
-/// safe code, then you must not access the data within the `UnsafeCell` until that
-/// reference expires.
+/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` reference), then
+/// you must not access the data in any way that contradicts that reference for the remainder of
+/// `'a`. For example, this means that if you take the `*mut T` from an `UnsafeCell<T>` and cast it
+/// to an `&T`, then the data in `T` must remain immutable (modulo any `UnsafeCell` data found
+/// within `T`, of course) until that reference's lifetime expires. Similarly, if you create a `&mut
+/// T` reference that is released to safe code, then you must not access the data within the
+/// `UnsafeCell` until that reference expires.
+///
+/// - For both `&T` without `UnsafeCell<_>` and `&mut T`, you must also not deallocate the data
+/// until the reference expires. As a special exception, given an `&T`, any part of it that is
+/// inside an `UnsafeCell<_>` may be deallocated during the lifetime of the reference, after the
+/// last time the reference is used (dereferenced or reborrowed). Since you cannot deallocate a part
+/// of what a reference points to, this means the memory an `&T` points to can be deallocted only if
+/// *every part of it* (including padding) is inside an `UnsafeCell`.
+///
+///     However, whenever a `&UnsafeCell<T>` is constructed or dereferenced, it must still point to
+/// live memory and the compiler is allowed to insert spurious reads if it can prove that this
+/// memory has not yet been deallocated.
 ///
 /// - At all times, you must avoid data races. If multiple threads have access to
 /// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 32fb0f82f10..9ae31a31aaa 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2291,6 +2291,16 @@ extern "rust-intrinsic" {
     /// [`std::hint::black_box`]: crate::hint::black_box
     #[rustc_const_unstable(feature = "const_black_box", issue = "none")]
     pub fn black_box<T>(dummy: T) -> T;
+
+    /// `ptr` must point to a vtable.
+    /// The intrinsic will return the size stored in that vtable.
+    #[cfg(not(bootstrap))]
+    pub fn vtable_size(ptr: *const ()) -> usize;
+
+    /// `ptr` must point to a vtable.
+    /// The intrinsic will return the alignment stored in that vtable.
+    #[cfg(not(bootstrap))]
+    pub fn vtable_align(ptr: *const ()) -> usize;
 }
 
 // Some functions are defined here because they accidentally got made
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index e34e26746c0..b1f5559dcfc 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -195,6 +195,41 @@ impl<B, C> ControlFlow<B, C> {
             ControlFlow::Break(x) => ControlFlow::Break(f(x)),
         }
     }
+
+    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
+    /// `ControlFlow` was `Continue` and `None` otherwise.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(control_flow_enum)]
+    /// use std::ops::ControlFlow;
+    ///
+    /// assert_eq!(ControlFlow::<i32, String>::Break(3).continue_value(), None);
+    /// assert_eq!(ControlFlow::<String, i32>::Continue(3).continue_value(), Some(3));
+    /// ```
+    #[inline]
+    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+    pub fn continue_value(self) -> Option<C> {
+        match self {
+            ControlFlow::Continue(x) => Some(x),
+            ControlFlow::Break(..) => None,
+        }
+    }
+
+    /// Maps `ControlFlow<B, C>` to `ControlFlow<B, T>` by applying a function
+    /// to the continue value in case it exists.
+    #[inline]
+    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+    pub fn map_continue<T, F>(self, f: F) -> ControlFlow<B, T>
+    where
+        F: FnOnce(C) -> T,
+    {
+        match self {
+            ControlFlow::Continue(x) => ControlFlow::Continue(f(x)),
+            ControlFlow::Break(x) => ControlFlow::Break(x),
+        }
+    }
 }
 
 /// These are used only as part of implementing the iterator adapters.
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index b961d875c0e..6cdbab30589 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -97,7 +97,7 @@ impl<T: ?Sized> *const T {
     /// refactored.
     #[unstable(feature = "ptr_const_cast", issue = "92675")]
     #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
-    pub const fn as_mut(self) -> *mut T {
+    pub const fn cast_mut(self) -> *mut T {
         self as _
     }
 
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 287ae69acd1..cd5edee0460 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -180,10 +180,20 @@ pub struct DynMetadata<Dyn: ?Sized> {
     phantom: crate::marker::PhantomData<Dyn>,
 }
 
+#[cfg(not(bootstrap))]
+extern "C" {
+    /// Opaque type for accessing vtables.
+    ///
+    /// Private implementation detail of `DynMetadata::size_of` etc.
+    /// There is conceptually not actually any Abstract Machine memory behind this pointer.
+    type VTable;
+}
+
 /// The common prefix of all vtables. It is followed by function pointers for trait methods.
 ///
 /// Private implementation detail of `DynMetadata::size_of` etc.
 #[repr(C)]
+#[cfg(bootstrap)]
 struct VTable {
     drop_in_place: fn(*mut ()),
     size_of: usize,
@@ -194,13 +204,28 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
     /// Returns the size of the type associated with this vtable.
     #[inline]
     pub fn size_of(self) -> usize {
-        self.vtable_ptr.size_of
+        // Note that "size stored in vtable" is *not* the same as "result of size_of_val_raw".
+        // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the
+        // `Send` part!
+        #[cfg(bootstrap)]
+        return self.vtable_ptr.size_of;
+        #[cfg(not(bootstrap))]
+        // SAFETY: DynMetadata always contains a valid vtable pointer
+        return unsafe {
+            crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ())
+        };
     }
 
     /// Returns the alignment of the type associated with this vtable.
     #[inline]
     pub fn align_of(self) -> usize {
-        self.vtable_ptr.align_of
+        #[cfg(bootstrap)]
+        return self.vtable_ptr.align_of;
+        #[cfg(not(bootstrap))]
+        // SAFETY: DynMetadata always contains a valid vtable pointer
+        return unsafe {
+            crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ())
+        };
     }
 
     /// Returns the size and alignment together as a `Layout`
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 21dc1911918..e323f63115b 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -96,11 +96,13 @@ impl<T: ?Sized> *mut T {
     /// refactored.
     ///
     /// While not strictly required (`*mut T` coerces to `*const T`), this is provided for symmetry
-    /// with `as_mut()` on `*const T` and may have documentation value if used instead of implicit
+    /// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit
     /// coercion.
+    ///
+    /// [`cast_mut`]: #method.cast_mut
     #[unstable(feature = "ptr_const_cast", issue = "92675")]
     #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
-    pub const fn as_const(self) -> *const T {
+    pub const fn cast_const(self) -> *const T {
         self as _
     }
 
@@ -289,7 +291,7 @@ impl<T: ?Sized> *mut T {
     /// For the mutable counterpart see [`as_mut`].
     ///
     /// [`as_uninit_ref`]: #method.as_uninit_ref-1
-    /// [`as_mut`]: #method.as_mut-1
+    /// [`as_mut`]: #method.as_mut
     ///
     /// # Safety
     ///
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 8a68cdf7d65..45b052c824d 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1009,6 +1009,15 @@ impl<T, E> Result<T, E> {
 
     /// Returns the contained [`Ok`] value, consuming the `self` value.
     ///
+    /// Because this function may panic, its use is generally discouraged.
+    /// Instead, prefer to use pattern matching and handle the [`Err`]
+    /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or
+    /// [`unwrap_or_default`].
+    ///
+    /// [`unwrap_or`]: Result::unwrap_or
+    /// [`unwrap_or_else`]: Result::unwrap_or_else
+    /// [`unwrap_or_default`]: Result::unwrap_or_default
+    ///
     /// # Panics
     ///
     /// Panics if the value is an [`Err`], with a panic message including the
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 1270a72634b..e6ca6ef8267 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -3569,6 +3569,7 @@ impl<T> [T] {
     ///
     /// ```
     /// #![feature(portable_simd)]
+    /// use core::simd::SimdFloat;
     ///
     /// let short = &[1, 2, 3];
     /// let (prefix, middle, suffix) = short.as_simd::<4>();
@@ -4100,6 +4101,66 @@ impl<T, const N: usize> [[T; N]] {
     }
 }
 
+#[cfg(not(bootstrap))]
+#[cfg(not(test))]
+impl [f32] {
+    /// Sorts the slice of floats.
+    ///
+    /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses
+    /// the ordering defined by [`f32::total_cmp`].
+    ///
+    /// # Current implementation
+    ///
+    /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(sort_floats)]
+    /// let mut v = [2.6, -5e-8, f32::NAN, 8.29, f32::INFINITY, -1.0, 0.0, -f32::INFINITY, -0.0];
+    ///
+    /// v.sort_floats();
+    /// let sorted = [-f32::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f32::INFINITY, f32::NAN];
+    /// assert_eq!(&v[..8], &sorted[..8]);
+    /// assert!(v[8].is_nan());
+    /// ```
+    #[unstable(feature = "sort_floats", issue = "93396")]
+    #[inline]
+    pub fn sort_floats(&mut self) {
+        self.sort_unstable_by(f32::total_cmp);
+    }
+}
+
+#[cfg(not(bootstrap))]
+#[cfg(not(test))]
+impl [f64] {
+    /// Sorts the slice of floats.
+    ///
+    /// This sort is in-place (i.e. does not allocate), *O*(*n* \* log(*n*)) worst-case, and uses
+    /// the ordering defined by [`f64::total_cmp`].
+    ///
+    /// # Current implementation
+    ///
+    /// This uses the same sorting algorithm as [`sort_unstable_by`](slice::sort_unstable_by).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(sort_floats)]
+    /// let mut v = [2.6, -5e-8, f64::NAN, 8.29, f64::INFINITY, -1.0, 0.0, -f64::INFINITY, -0.0];
+    ///
+    /// v.sort_floats();
+    /// let sorted = [-f64::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f64::INFINITY, f64::NAN];
+    /// assert_eq!(&v[..8], &sorted[..8]);
+    /// assert!(v[8].is_nan());
+    /// ```
+    #[unstable(feature = "sort_floats", issue = "93396")]
+    #[inline]
+    pub fn sort_floats(&mut self) {
+        self.sort_unstable_by(f64::total_cmp);
+    }
+}
+
 trait CloneFromSpec<T> {
     fn spec_clone_from(&mut self, src: &[T]);
 }
diff --git a/library/core/tests/simd.rs b/library/core/tests/simd.rs
index 5b516a72360..565c8975eb9 100644
--- a/library/core/tests/simd.rs
+++ b/library/core/tests/simd.rs
@@ -1,4 +1,5 @@
 use core::simd::f32x4;
+use core::simd::SimdFloat;
 
 #[test]
 fn testing() {
diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs
index a0297b4b2f5..057e47bfdd1 100644
--- a/library/panic_unwind/src/gcc.rs
+++ b/library/panic_unwind/src/gcc.rs
@@ -131,7 +131,7 @@ const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11
 // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
 
 cfg_if::cfg_if! {
-    if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "netbsd")))] {
+    if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] {
         // ARM EHABI personality routine.
         // https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
         //
diff --git a/library/portable-simd/beginners-guide.md b/library/portable-simd/beginners-guide.md
index 75158e5aa85..17ade06ae80 100644
--- a/library/portable-simd/beginners-guide.md
+++ b/library/portable-simd/beginners-guide.md
@@ -82,5 +82,10 @@ Fortunately, most SIMD types have a fairly predictable size. `i32x4` is bit-equi
 
 However, this is not the same as alignment. Computer architectures generally prefer aligned accesses, especially when moving data between memory and vector registers, and while some support specialized operations that can bend the rules to help with this, unaligned access is still typically slow, or even undefined behavior. In addition, different architectures can require different alignments when interacting with their native SIMD types. For this reason, any `#[repr(simd)]` type has a non-portable alignment. If it is necessary to directly interact with the alignment of these types, it should be via [`mem::align_of`].
 
+When working with slices, data correctly aligned for SIMD can be acquired using the [`as_simd`] and [`as_simd_mut`] methods of the slice primitive.
+
 [`mem::transmute`]: https://doc.rust-lang.org/core/mem/fn.transmute.html
 [`mem::align_of`]: https://doc.rust-lang.org/core/mem/fn.align_of.html
+[`as_simd`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_simd
+[`as_simd_mut`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.as_simd_mut
+
diff --git a/library/portable-simd/crates/core_simd/Cargo.toml b/library/portable-simd/crates/core_simd/Cargo.toml
index 8877c6df66e..8a29cf15696 100644
--- a/library/portable-simd/crates/core_simd/Cargo.toml
+++ b/library/portable-simd/crates/core_simd/Cargo.toml
@@ -9,7 +9,8 @@ categories = ["hardware-support", "no-std"]
 license = "MIT OR Apache-2.0"
 
 [features]
-default = []
+default = ["as_crate"]
+as_crate = []
 std = []
 generic_const_exprs = []
 
diff --git a/library/portable-simd/crates/core_simd/src/comparisons.rs b/library/portable-simd/crates/core_simd/src/comparisons.rs
deleted file mode 100644
index 7b0d0a6864b..00000000000
--- a/library/portable-simd/crates/core_simd/src/comparisons.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use crate::simd::intrinsics;
-use crate::simd::{LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};
-
-impl<T, const LANES: usize> Simd<T, LANES>
-where
-    T: SimdElement + PartialEq,
-    LaneCount<LANES>: SupportedLaneCount,
-{
-    /// Test if each lane is equal to the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_eq(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
-    }
-
-    /// Test if each lane is not equal to the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_ne(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
-    }
-}
-
-impl<T, const LANES: usize> Simd<T, LANES>
-where
-    T: SimdElement + PartialOrd,
-    LaneCount<LANES>: SupportedLaneCount,
-{
-    /// Test if each lane is less than the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_lt(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
-    }
-
-    /// Test if each lane is greater than the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_gt(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
-    }
-
-    /// Test if each lane is less than or equal to the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_le(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
-    }
-
-    /// Test if each lane is greater than or equal to the corresponding lane in `other`.
-    #[inline]
-    #[must_use = "method returns a new mask and does not mutate the original value"]
-    pub fn lanes_ge(self, other: Self) -> Mask<T::Mask, LANES> {
-        // Safety: `self` is a vector, and the result of the comparison
-        // is always a valid mask.
-        unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
-    }
-}
-
-macro_rules! impl_ord_methods_vector {
-    { $type:ty } => {
-        impl<const LANES: usize> Simd<$type, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-            /// Returns the lane-wise minimum with `other`.
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            #[inline]
-            pub fn min(self, other: Self) -> Self {
-                self.lanes_gt(other).select(other, self)
-            }
-
-            /// Returns the lane-wise maximum with `other`.
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            #[inline]
-            pub fn max(self, other: Self) -> Self {
-                self.lanes_lt(other).select(other, self)
-            }
-
-            /// Restrict each lane to a certain interval.
-            ///
-            /// For each lane, returns `max` if `self` is greater than `max`, and `min` if `self` is
-            /// less than `min`. Otherwise returns `self`.
-            ///
-            /// # Panics
-            ///
-            /// Panics if `min > max` on any lane.
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            #[inline]
-            pub fn clamp(self, min: Self, max: Self) -> Self {
-                assert!(
-                    min.lanes_le(max).all(),
-                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
-                );
-                self.max(min).min(max)
-            }
-        }
-    }
-}
-
-impl_ord_methods_vector!(i8);
-impl_ord_methods_vector!(i16);
-impl_ord_methods_vector!(i32);
-impl_ord_methods_vector!(i64);
-impl_ord_methods_vector!(isize);
-impl_ord_methods_vector!(u8);
-impl_ord_methods_vector!(u16);
-impl_ord_methods_vector!(u32);
-impl_ord_methods_vector!(u64);
-impl_ord_methods_vector!(usize);
diff --git a/library/portable-simd/crates/core_simd/src/elements.rs b/library/portable-simd/crates/core_simd/src/elements.rs
new file mode 100644
index 00000000000..701eb66b248
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/elements.rs
@@ -0,0 +1,11 @@
+mod float;
+mod int;
+mod uint;
+
+mod sealed {
+    pub trait Sealed {}
+}
+
+pub use float::*;
+pub use int::*;
+pub use uint::*;
diff --git a/library/portable-simd/crates/core_simd/src/elements/float.rs b/library/portable-simd/crates/core_simd/src/elements/float.rs
new file mode 100644
index 00000000000..d6022327055
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/elements/float.rs
@@ -0,0 +1,357 @@
+use super::sealed::Sealed;
+use crate::simd::{
+    intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialEq, SimdPartialOrd,
+    SupportedLaneCount,
+};
+
+/// Operations on SIMD vectors of floats.
+pub trait SimdFloat: Copy + Sealed {
+    /// Mask type used for manipulating this SIMD vector type.
+    type Mask;
+
+    /// Scalar type contained by this SIMD vector type.
+    type Scalar;
+
+    /// Bit representation of this SIMD vector type.
+    type Bits;
+
+    /// Raw transmutation to an unsigned integer vector type with the
+    /// same size and number of lanes.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn to_bits(self) -> Self::Bits;
+
+    /// Raw transmutation from an unsigned integer vector type with the
+    /// same size and number of lanes.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn from_bits(bits: Self::Bits) -> Self;
+
+    /// Produces a vector where every lane has the absolute value of the
+    /// equivalently-indexed lane in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn abs(self) -> Self;
+
+    /// Takes the reciprocal (inverse) of each lane, `1/x`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn recip(self) -> Self;
+
+    /// Converts each lane from radians to degrees.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn to_degrees(self) -> Self;
+
+    /// Converts each lane from degrees to radians.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn to_radians(self) -> Self;
+
+    /// Returns true for each lane if it has a positive sign, including
+    /// `+0.0`, `NaN`s with positive sign bit and positive infinity.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn is_sign_positive(self) -> Self::Mask;
+
+    /// Returns true for each lane if it has a negative sign, including
+    /// `-0.0`, `NaN`s with negative sign bit and negative infinity.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn is_sign_negative(self) -> Self::Mask;
+
+    /// Returns true for each lane if its value is `NaN`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn is_nan(self) -> Self::Mask;
+
+    /// Returns true for each lane if its value is positive infinity or negative infinity.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn is_infinite(self) -> Self::Mask;
+
+    /// Returns true for each lane if its value is neither infinite nor `NaN`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn is_finite(self) -> Self::Mask;
+
+    /// Returns true for each lane if its value is subnormal.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn is_subnormal(self) -> Self::Mask;
+
+    /// Returns true for each lane if its value is neither zero, infinite,
+    /// subnormal, nor `NaN`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn is_normal(self) -> Self::Mask;
+
+    /// Replaces each lane with a number that represents its sign.
+    ///
+    /// * `1.0` if the number is positive, `+0.0`, or `INFINITY`
+    /// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY`
+    /// * `NAN` if the number is `NAN`
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn signum(self) -> Self;
+
+    /// Returns each lane with the magnitude of `self` and the sign of `sign`.
+    ///
+    /// For any lane containing a `NAN`, a `NAN` with the sign of `sign` is returned.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn copysign(self, sign: Self) -> Self;
+
+    /// Returns the minimum of each lane.
+    ///
+    /// If one of the values is `NAN`, then the other value is returned.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn simd_min(self, other: Self) -> Self;
+
+    /// Returns the maximum of each lane.
+    ///
+    /// If one of the values is `NAN`, then the other value is returned.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn simd_max(self, other: Self) -> Self;
+
+    /// Restrict each lane to a certain interval unless it is NaN.
+    ///
+    /// For each lane in `self`, returns the corresponding lane in `max` if the lane is
+    /// greater than `max`, and the corresponding lane in `min` if the lane is less
+    /// than `min`.  Otherwise returns the lane in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn simd_clamp(self, min: Self, max: Self) -> Self;
+
+    /// Returns the sum of the lanes of the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{f32x2, SimdFloat};
+    /// let v = f32x2::from_array([1., 2.]);
+    /// assert_eq!(v.reduce_sum(), 3.);
+    /// ```
+    fn reduce_sum(self) -> Self::Scalar;
+
+    /// Reducing multiply.  Returns the product of the lanes of the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{f32x2, SimdFloat};
+    /// let v = f32x2::from_array([3., 4.]);
+    /// assert_eq!(v.reduce_product(), 12.);
+    /// ```
+    fn reduce_product(self) -> Self::Scalar;
+
+    /// Returns the maximum lane in the vector.
+    ///
+    /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
+    /// return either.
+    ///
+    /// This function will not return `NaN` unless all lanes are `NaN`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{f32x2, SimdFloat};
+    /// let v = f32x2::from_array([1., 2.]);
+    /// assert_eq!(v.reduce_max(), 2.);
+    ///
+    /// // NaN values are skipped...
+    /// let v = f32x2::from_array([1., f32::NAN]);
+    /// assert_eq!(v.reduce_max(), 1.);
+    ///
+    /// // ...unless all values are NaN
+    /// let v = f32x2::from_array([f32::NAN, f32::NAN]);
+    /// assert!(v.reduce_max().is_nan());
+    /// ```
+    fn reduce_max(self) -> Self::Scalar;
+
+    /// Returns the minimum lane in the vector.
+    ///
+    /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
+    /// return either.
+    ///
+    /// This function will not return `NaN` unless all lanes are `NaN`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{f32x2, SimdFloat};
+    /// let v = f32x2::from_array([3., 7.]);
+    /// assert_eq!(v.reduce_min(), 3.);
+    ///
+    /// // NaN values are skipped...
+    /// let v = f32x2::from_array([1., f32::NAN]);
+    /// assert_eq!(v.reduce_min(), 1.);
+    ///
+    /// // ...unless all values are NaN
+    /// let v = f32x2::from_array([f32::NAN, f32::NAN]);
+    /// assert!(v.reduce_min().is_nan());
+    /// ```
+    fn reduce_min(self) -> Self::Scalar;
+}
+
+macro_rules! impl_trait {
+    { $($ty:ty { bits: $bits_ty:ty, mask: $mask_ty:ty }),* } => {
+        $(
+        impl<const LANES: usize> Sealed for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+        }
+
+        impl<const LANES: usize> SimdFloat for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            type Mask = Mask<<$mask_ty as SimdElement>::Mask, LANES>;
+            type Scalar = $ty;
+            type Bits = Simd<$bits_ty, LANES>;
+
+            #[inline]
+            fn to_bits(self) -> Simd<$bits_ty, LANES> {
+                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Self::Bits>());
+                // Safety: transmuting between vector types is safe
+                unsafe { core::mem::transmute_copy(&self) }
+            }
+
+            #[inline]
+            fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self {
+                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Self::Bits>());
+                // Safety: transmuting between vector types is safe
+                unsafe { core::mem::transmute_copy(&bits) }
+            }
+
+            #[inline]
+            fn abs(self) -> Self {
+                // Safety: `self` is a float vector
+                unsafe { intrinsics::simd_fabs(self) }
+            }
+
+            #[inline]
+            fn recip(self) -> Self {
+                Self::splat(1.0) / self
+            }
+
+            #[inline]
+            fn to_degrees(self) -> Self {
+                // to_degrees uses a special constant for better precision, so extract that constant
+                self * Self::splat(Self::Scalar::to_degrees(1.))
+            }
+
+            #[inline]
+            fn to_radians(self) -> Self {
+                self * Self::splat(Self::Scalar::to_radians(1.))
+            }
+
+            #[inline]
+            fn is_sign_positive(self) -> Self::Mask {
+                !self.is_sign_negative()
+            }
+
+            #[inline]
+            fn is_sign_negative(self) -> Self::Mask {
+                let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1);
+                sign_bits.simd_gt(Simd::splat(0))
+            }
+
+            #[inline]
+            fn is_nan(self) -> Self::Mask {
+                self.simd_ne(self)
+            }
+
+            #[inline]
+            fn is_infinite(self) -> Self::Mask {
+                self.abs().simd_eq(Self::splat(Self::Scalar::INFINITY))
+            }
+
+            #[inline]
+            fn is_finite(self) -> Self::Mask {
+                self.abs().simd_lt(Self::splat(Self::Scalar::INFINITY))
+            }
+
+            #[inline]
+            fn is_subnormal(self) -> Self::Mask {
+                self.abs().simd_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(Self::Scalar::INFINITY).to_bits()).simd_eq(Simd::splat(0))
+            }
+
+            #[inline]
+            #[must_use = "method returns a new mask and does not mutate the original value"]
+            fn is_normal(self) -> Self::Mask {
+                !(self.abs().simd_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
+            }
+
+            #[inline]
+            fn signum(self) -> Self {
+                self.is_nan().select(Self::splat(Self::Scalar::NAN), Self::splat(1.0).copysign(self))
+            }
+
+            #[inline]
+            fn copysign(self, sign: Self) -> Self {
+                let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits();
+                let magnitude = self.to_bits() & !Self::splat(-0.).to_bits();
+                Self::from_bits(sign_bit | magnitude)
+            }
+
+            #[inline]
+            fn simd_min(self, other: Self) -> Self {
+                // Safety: `self` and `other` are float vectors
+                unsafe { intrinsics::simd_fmin(self, other) }
+            }
+
+            #[inline]
+            fn simd_max(self, other: Self) -> Self {
+                // Safety: `self` and `other` are floating point vectors
+                unsafe { intrinsics::simd_fmax(self, other) }
+            }
+
+            #[inline]
+            fn simd_clamp(self, min: Self, max: Self) -> Self {
+                assert!(
+                    min.simd_le(max).all(),
+                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
+                );
+                let mut x = self;
+                x = x.simd_lt(min).select(min, x);
+                x = x.simd_gt(max).select(max, x);
+                x
+            }
+
+            #[inline]
+            fn reduce_sum(self) -> Self::Scalar {
+                // LLVM sum is inaccurate on i586
+                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
+                    self.as_array().iter().sum()
+                } else {
+                    // Safety: `self` is a float vector
+                    unsafe { intrinsics::simd_reduce_add_ordered(self, 0.) }
+                }
+            }
+
+            #[inline]
+            fn reduce_product(self) -> Self::Scalar {
+                // LLVM product is inaccurate on i586
+                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
+                    self.as_array().iter().product()
+                } else {
+                    // Safety: `self` is a float vector
+                    unsafe { intrinsics::simd_reduce_mul_ordered(self, 1.) }
+                }
+            }
+
+            #[inline]
+            fn reduce_max(self) -> Self::Scalar {
+                // Safety: `self` is a float vector
+                unsafe { intrinsics::simd_reduce_max(self) }
+            }
+
+            #[inline]
+            fn reduce_min(self) -> Self::Scalar {
+                // Safety: `self` is a float vector
+                unsafe { intrinsics::simd_reduce_min(self) }
+            }
+        }
+        )*
+    }
+}
+
+impl_trait! { f32 { bits: u32, mask: i32 }, f64 { bits: u64, mask: i64 } }
diff --git a/library/portable-simd/crates/core_simd/src/elements/int.rs b/library/portable-simd/crates/core_simd/src/elements/int.rs
new file mode 100644
index 00000000000..9b8c37ed466
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/elements/int.rs
@@ -0,0 +1,298 @@
+use super::sealed::Sealed;
+use crate::simd::{
+    intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialOrd, SupportedLaneCount,
+};
+
+/// Operations on SIMD vectors of signed integers.
+pub trait SimdInt: Copy + Sealed {
+    /// Mask type used for manipulating this SIMD vector type.
+    type Mask;
+
+    /// Scalar type contained by this SIMD vector type.
+    type Scalar;
+
+    /// Lanewise saturating add.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, SimdInt};
+    /// use core::i32::{MIN, MAX};
+    /// let x = Simd::from_array([MIN, 0, 1, MAX]);
+    /// let max = Simd::splat(MAX);
+    /// let unsat = x + max;
+    /// let sat = x.saturating_add(max);
+    /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
+    /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
+    /// ```
+    fn saturating_add(self, second: Self) -> Self;
+
+    /// Lanewise saturating subtract.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, SimdInt};
+    /// use core::i32::{MIN, MAX};
+    /// let x = Simd::from_array([MIN, -2, -1, MAX]);
+    /// let max = Simd::splat(MAX);
+    /// let unsat = x - max;
+    /// let sat = x.saturating_sub(max);
+    /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
+    /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
+    fn saturating_sub(self, second: Self) -> Self;
+
+    /// Lanewise absolute value, implemented in Rust.
+    /// Every lane becomes its absolute value.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, SimdInt};
+    /// use core::i32::{MIN, MAX};
+    /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
+    /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
+    /// ```
+    fn abs(self) -> Self;
+
+    /// Lanewise saturating absolute value, implemented in Rust.
+    /// As abs(), except the MIN value becomes MAX instead of itself.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, SimdInt};
+    /// use core::i32::{MIN, MAX};
+    /// let xs = Simd::from_array([MIN, -2, 0, 3]);
+    /// let unsat = xs.abs();
+    /// let sat = xs.saturating_abs();
+    /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
+    /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
+    /// ```
+    fn saturating_abs(self) -> Self;
+
+    /// Lanewise saturating negation, implemented in Rust.
+    /// As neg(), except the MIN value becomes MAX instead of itself.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, SimdInt};
+    /// use core::i32::{MIN, MAX};
+    /// let x = Simd::from_array([MIN, -2, 3, MAX]);
+    /// let unsat = -x;
+    /// let sat = x.saturating_neg();
+    /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
+    /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
+    /// ```
+    fn saturating_neg(self) -> Self;
+
+    /// Returns true for each positive lane and false if it is zero or negative.
+    fn is_positive(self) -> Self::Mask;
+
+    /// Returns true for each negative lane and false if it is zero or positive.
+    fn is_negative(self) -> Self::Mask;
+
+    /// Returns numbers representing the sign of each lane.
+    /// * `0` if the number is zero
+    /// * `1` if the number is positive
+    /// * `-1` if the number is negative
+    fn signum(self) -> Self;
+
+    /// Returns the sum of the lanes of the vector, with wrapping addition.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{i32x4, SimdInt};
+    /// let v = i32x4::from_array([1, 2, 3, 4]);
+    /// assert_eq!(v.reduce_sum(), 10);
+    ///
+    /// // SIMD integer addition is always wrapping
+    /// let v = i32x4::from_array([i32::MAX, 1, 0, 0]);
+    /// assert_eq!(v.reduce_sum(), i32::MIN);
+    /// ```
+    fn reduce_sum(self) -> Self::Scalar;
+
+    /// Returns the product of the lanes of the vector, with wrapping multiplication.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{i32x4, SimdInt};
+    /// let v = i32x4::from_array([1, 2, 3, 4]);
+    /// assert_eq!(v.reduce_product(), 24);
+    ///
+    /// // SIMD integer multiplication is always wrapping
+    /// let v = i32x4::from_array([i32::MAX, 2, 1, 1]);
+    /// assert!(v.reduce_product() < i32::MAX);
+    /// ```
+    fn reduce_product(self) -> Self::Scalar;
+
+    /// Returns the maximum lane in the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{i32x4, SimdInt};
+    /// let v = i32x4::from_array([1, 2, 3, 4]);
+    /// assert_eq!(v.reduce_max(), 4);
+    /// ```
+    fn reduce_max(self) -> Self::Scalar;
+
+    /// Returns the minimum lane in the vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{i32x4, SimdInt};
+    /// let v = i32x4::from_array([1, 2, 3, 4]);
+    /// assert_eq!(v.reduce_min(), 1);
+    /// ```
+    fn reduce_min(self) -> Self::Scalar;
+
+    /// Returns the cumulative bitwise "and" across the lanes of the vector.
+    fn reduce_and(self) -> Self::Scalar;
+
+    /// Returns the cumulative bitwise "or" across the lanes of the vector.
+    fn reduce_or(self) -> Self::Scalar;
+
+    /// Returns the cumulative bitwise "xor" across the lanes of the vector.
+    fn reduce_xor(self) -> Self::Scalar;
+}
+
+macro_rules! impl_trait {
+    { $($ty:ty),* } => {
+        $(
+        impl<const LANES: usize> Sealed for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+        }
+
+        impl<const LANES: usize> SimdInt for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            type Mask = Mask<<$ty as SimdElement>::Mask, LANES>;
+            type Scalar = $ty;
+
+            #[inline]
+            fn saturating_add(self, second: Self) -> Self {
+                // Safety: `self` is a vector
+                unsafe { intrinsics::simd_saturating_add(self, second) }
+            }
+
+            #[inline]
+            fn saturating_sub(self, second: Self) -> Self {
+                // Safety: `self` is a vector
+                unsafe { intrinsics::simd_saturating_sub(self, second) }
+            }
+
+            #[inline]
+            fn abs(self) -> Self {
+                const SHR: $ty = <$ty>::BITS as $ty - 1;
+                let m = self >> Simd::splat(SHR);
+                (self^m) - m
+            }
+
+            #[inline]
+            fn saturating_abs(self) -> Self {
+                // arith shift for -1 or 0 mask based on sign bit, giving 2s complement
+                const SHR: $ty = <$ty>::BITS as $ty - 1;
+                let m = self >> Simd::splat(SHR);
+                (self^m).saturating_sub(m)
+            }
+
+            #[inline]
+            fn saturating_neg(self) -> Self {
+                Self::splat(0).saturating_sub(self)
+            }
+
+            #[inline]
+            fn is_positive(self) -> Self::Mask {
+                self.simd_gt(Self::splat(0))
+            }
+
+            #[inline]
+            fn is_negative(self) -> Self::Mask {
+                self.simd_lt(Self::splat(0))
+            }
+
+            #[inline]
+            fn signum(self) -> Self {
+                self.is_positive().select(
+                    Self::splat(1),
+                    self.is_negative().select(Self::splat(-1), Self::splat(0))
+                )
+            }
+
+            #[inline]
+            fn reduce_sum(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_add_ordered(self, 0) }
+            }
+
+            #[inline]
+            fn reduce_product(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) }
+            }
+
+            #[inline]
+            fn reduce_max(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_max(self) }
+            }
+
+            #[inline]
+            fn reduce_min(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_min(self) }
+            }
+
+            #[inline]
+            fn reduce_and(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_and(self) }
+            }
+
+            #[inline]
+            fn reduce_or(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_or(self) }
+            }
+
+            #[inline]
+            fn reduce_xor(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_xor(self) }
+            }
+        }
+        )*
+    }
+}
+
+impl_trait! { i8, i16, i32, i64, isize }
diff --git a/library/portable-simd/crates/core_simd/src/elements/uint.rs b/library/portable-simd/crates/core_simd/src/elements/uint.rs
new file mode 100644
index 00000000000..21e7e76eb3d
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/elements/uint.rs
@@ -0,0 +1,139 @@
+use super::sealed::Sealed;
+use crate::simd::{intrinsics, LaneCount, Simd, SupportedLaneCount};
+
+/// Operations on SIMD vectors of unsigned integers.
+pub trait SimdUint: Copy + Sealed {
+    /// Scalar type contained by this SIMD vector type.
+    type Scalar;
+
+    /// Lanewise saturating add.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, SimdUint};
+    /// use core::u32::MAX;
+    /// let x = Simd::from_array([2, 1, 0, MAX]);
+    /// let max = Simd::splat(MAX);
+    /// let unsat = x + max;
+    /// let sat = x.saturating_add(max);
+    /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
+    /// assert_eq!(sat, max);
+    /// ```
+    fn saturating_add(self, second: Self) -> Self;
+
+    /// Lanewise saturating subtract.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, SimdUint};
+    /// use core::u32::MAX;
+    /// let x = Simd::from_array([2, 1, 0, MAX]);
+    /// let max = Simd::splat(MAX);
+    /// let unsat = x - max;
+    /// let sat = x.saturating_sub(max);
+    /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
+    /// assert_eq!(sat, Simd::splat(0));
+    fn saturating_sub(self, second: Self) -> Self;
+
+    /// Returns the sum of the lanes of the vector, with wrapping addition.
+    fn reduce_sum(self) -> Self::Scalar;
+
+    /// Returns the product of the lanes of the vector, with wrapping multiplication.
+    fn reduce_product(self) -> Self::Scalar;
+
+    /// Returns the maximum lane in the vector.
+    fn reduce_max(self) -> Self::Scalar;
+
+    /// Returns the minimum lane in the vector.
+    fn reduce_min(self) -> Self::Scalar;
+
+    /// Returns the cumulative bitwise "and" across the lanes of the vector.
+    fn reduce_and(self) -> Self::Scalar;
+
+    /// Returns the cumulative bitwise "or" across the lanes of the vector.
+    fn reduce_or(self) -> Self::Scalar;
+
+    /// Returns the cumulative bitwise "xor" across the lanes of the vector.
+    fn reduce_xor(self) -> Self::Scalar;
+}
+
+macro_rules! impl_trait {
+    { $($ty:ty),* } => {
+        $(
+        impl<const LANES: usize> Sealed for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+        }
+
+        impl<const LANES: usize> SimdUint for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            type Scalar = $ty;
+
+            #[inline]
+            fn saturating_add(self, second: Self) -> Self {
+                // Safety: `self` is a vector
+                unsafe { intrinsics::simd_saturating_add(self, second) }
+            }
+
+            #[inline]
+            fn saturating_sub(self, second: Self) -> Self {
+                // Safety: `self` is a vector
+                unsafe { intrinsics::simd_saturating_sub(self, second) }
+            }
+
+            #[inline]
+            fn reduce_sum(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_add_ordered(self, 0) }
+            }
+
+            #[inline]
+            fn reduce_product(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) }
+            }
+
+            #[inline]
+            fn reduce_max(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_max(self) }
+            }
+
+            #[inline]
+            fn reduce_min(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_min(self) }
+            }
+
+            #[inline]
+            fn reduce_and(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_and(self) }
+            }
+
+            #[inline]
+            fn reduce_or(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_or(self) }
+            }
+
+            #[inline]
+            fn reduce_xor(self) -> Self::Scalar {
+                // Safety: `self` is an integer vector
+                unsafe { intrinsics::simd_reduce_xor(self) }
+            }
+        }
+        )*
+    }
+}
+
+impl_trait! { u8, u16, u32, u64, usize }
diff --git a/library/portable-simd/crates/core_simd/src/eq.rs b/library/portable-simd/crates/core_simd/src/eq.rs
new file mode 100644
index 00000000000..c7111f720a8
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/eq.rs
@@ -0,0 +1,73 @@
+use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};
+
+/// Parallel `PartialEq`.
+pub trait SimdPartialEq {
+    /// The mask type returned by each comparison.
+    type Mask;
+
+    /// Test if each lane is equal to the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_eq(self, other: Self) -> Self::Mask;
+
+    /// Test if each lane is equal to the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_ne(self, other: Self) -> Self::Mask;
+}
+
+macro_rules! impl_number {
+    { $($number:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialEq for Simd<$number, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            type Mask = Mask<<$number as SimdElement>::Mask, LANES>;
+
+            #[inline]
+            fn simd_eq(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
+            }
+
+            #[inline]
+            fn simd_ne(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
+            }
+        }
+        )*
+    }
+}
+
+impl_number! { f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }
+
+macro_rules! impl_mask {
+    { $($integer:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialEq for Mask<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            type Mask = Self;
+
+            #[inline]
+            fn simd_eq(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_eq(self.to_int(), other.to_int())) }
+            }
+
+            #[inline]
+            fn simd_ne(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_ne(self.to_int(), other.to_int())) }
+            }
+        }
+        )*
+    }
+}
+
+impl_mask! { i8, i16, i32, i64, isize }
diff --git a/library/portable-simd/crates/core_simd/src/lane_count.rs b/library/portable-simd/crates/core_simd/src/lane_count.rs
index 3b316f12b3e..63723e2ec13 100644
--- a/library/portable-simd/crates/core_simd/src/lane_count.rs
+++ b/library/portable-simd/crates/core_simd/src/lane_count.rs
@@ -3,7 +3,7 @@ mod sealed {
 }
 use sealed::Sealed;
 
-/// A type representing a vector lane count.
+/// Specifies the number of lanes in a SIMD vector as a type.
 pub struct LaneCount<const LANES: usize>;
 
 impl<const LANES: usize> LaneCount<LANES> {
@@ -11,7 +11,11 @@ impl<const LANES: usize> LaneCount<LANES> {
     pub const BITMASK_LEN: usize = (LANES + 7) / 8;
 }
 
-/// Helper trait for vector lane counts.
+/// Statically guarantees that a lane count is marked as supported.
+///
+/// This trait is *sealed*: the list of implementors below is total.
+/// Users do not have the ability to mark additional `LaneCount<N>` values as supported.
+/// Only SIMD vectors with supported lane counts are constructable.
 pub trait SupportedLaneCount: Sealed {
     #[doc(hidden)]
     type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>;
diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs
index 2632073622e..715f258f617 100644
--- a/library/portable-simd/crates/core_simd/src/lib.rs
+++ b/library/portable-simd/crates/core_simd/src/lib.rs
@@ -12,7 +12,7 @@
 #![cfg_attr(feature = "generic_const_exprs", feature(generic_const_exprs))]
 #![cfg_attr(feature = "generic_const_exprs", allow(incomplete_features))]
 #![warn(missing_docs)]
-#![deny(unsafe_op_in_unsafe_fn)]
+#![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)]
 #![unstable(feature = "portable_simd", issue = "86656")]
 //! Portable SIMD module.
 
diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs
index e1cd7930450..c36c336d8a2 100644
--- a/library/portable-simd/crates/core_simd/src/masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks.rs
@@ -15,7 +15,10 @@ mod mask_impl;
 mod to_bitmask;
 pub use to_bitmask::ToBitMask;
 
-use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SupportedLaneCount};
+#[cfg(feature = "generic_const_exprs")]
+pub use to_bitmask::{bitmask_len, ToBitMaskArray};
+
+use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount};
 use core::cmp::Ordering;
 use core::{fmt, mem};
 
@@ -56,7 +59,7 @@ macro_rules! impl_element {
             where
                 LaneCount<LANES>: SupportedLaneCount,
             {
-                (value.lanes_eq(Simd::splat(0)) | value.lanes_eq(Simd::splat(-1))).all()
+                (value.simd_eq(Simd::splat(0 as _)) | value.simd_eq(Simd::splat(-1 as _))).all()
             }
 
             fn eq(self, other: Self) -> bool { self == other }
@@ -65,6 +68,7 @@ macro_rules! impl_element {
             const FALSE: Self = 0;
         }
 
+        // Safety: this is a valid mask element type
         unsafe impl MaskElement for $ty {}
     }
 }
@@ -77,6 +81,8 @@ impl_element! { isize }
 
 /// A SIMD vector mask for `LANES` elements of width specified by `Element`.
 ///
+/// Masks represent boolean inclusion/exclusion on a per-lane basis.
+///
 /// The layout of this type is unspecified.
 #[repr(transparent)]
 pub struct Mask<T, const LANES: usize>(mask_impl::Mask<T, LANES>)
@@ -179,6 +185,13 @@ where
         self.0.to_int()
     }
 
+    /// Converts the mask to a mask of any other lane size.
+    #[inline]
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    pub fn cast<U: MaskElement>(self) -> Mask<U, LANES> {
+        Mask(self.0.convert())
+    }
+
     /// Tests the value of the specified lane.
     ///
     /// # Safety
@@ -507,58 +520,58 @@ where
     }
 }
 
-/// Vector of eight 8-bit masks
+/// A mask for SIMD vectors with eight elements of 8 bits.
 pub type mask8x8 = Mask<i8, 8>;
 
-/// Vector of 16 8-bit masks
+/// A mask for SIMD vectors with 16 elements of 8 bits.
 pub type mask8x16 = Mask<i8, 16>;
 
-/// Vector of 32 8-bit masks
+/// A mask for SIMD vectors with 32 elements of 8 bits.
 pub type mask8x32 = Mask<i8, 32>;
 
-/// Vector of 16 8-bit masks
+/// A mask for SIMD vectors with 64 elements of 8 bits.
 pub type mask8x64 = Mask<i8, 64>;
 
-/// Vector of four 16-bit masks
+/// A mask for SIMD vectors with four elements of 16 bits.
 pub type mask16x4 = Mask<i16, 4>;
 
-/// Vector of eight 16-bit masks
+/// A mask for SIMD vectors with eight elements of 16 bits.
 pub type mask16x8 = Mask<i16, 8>;
 
-/// Vector of 16 16-bit masks
+/// A mask for SIMD vectors with 16 elements of 16 bits.
 pub type mask16x16 = Mask<i16, 16>;
 
-/// Vector of 32 16-bit masks
+/// A mask for SIMD vectors with 32 elements of 16 bits.
 pub type mask16x32 = Mask<i16, 32>;
 
-/// Vector of two 32-bit masks
+/// A mask for SIMD vectors with two elements of 32 bits.
 pub type mask32x2 = Mask<i32, 2>;
 
-/// Vector of four 32-bit masks
+/// A mask for SIMD vectors with four elements of 32 bits.
 pub type mask32x4 = Mask<i32, 4>;
 
-/// Vector of eight 32-bit masks
+/// A mask for SIMD vectors with eight elements of 32 bits.
 pub type mask32x8 = Mask<i32, 8>;
 
-/// Vector of 16 32-bit masks
+/// A mask for SIMD vectors with 16 elements of 32 bits.
 pub type mask32x16 = Mask<i32, 16>;
 
-/// Vector of two 64-bit masks
+/// A mask for SIMD vectors with two elements of 64 bits.
 pub type mask64x2 = Mask<i64, 2>;
 
-/// Vector of four 64-bit masks
+/// A mask for SIMD vectors with four elements of 64 bits.
 pub type mask64x4 = Mask<i64, 4>;
 
-/// Vector of eight 64-bit masks
+/// A mask for SIMD vectors with eight elements of 64 bits.
 pub type mask64x8 = Mask<i64, 8>;
 
-/// Vector of two pointer-width masks
+/// A mask for SIMD vectors with two elements of pointer width.
 pub type masksizex2 = Mask<isize, 2>;
 
-/// Vector of four pointer-width masks
+/// A mask for SIMD vectors with four elements of pointer width.
 pub type masksizex4 = Mask<isize, 4>;
 
-/// Vector of eight pointer-width masks
+/// A mask for SIMD vectors with eight elements of pointer width.
 pub type masksizex8 = Mask<isize, 8>;
 
 macro_rules! impl_from {
@@ -569,7 +582,7 @@ macro_rules! impl_from {
             LaneCount<LANES>: SupportedLaneCount,
         {
             fn from(value: Mask<$from, LANES>) -> Self {
-                Self(value.0.convert())
+                value.cast()
             }
         }
         )*
diff --git a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
index ec4dd357ee9..365ecc0a325 100644
--- a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
+++ b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
@@ -115,6 +115,26 @@ where
         unsafe { Self(intrinsics::simd_bitmask(value), PhantomData) }
     }
 
+    #[cfg(feature = "generic_const_exprs")]
+    #[inline]
+    #[must_use = "method returns a new array and does not mutate the original value"]
+    pub fn to_bitmask_array<const N: usize>(self) -> [u8; N] {
+        assert!(core::mem::size_of::<Self>() == N);
+
+        // Safety: converting an integer to an array of bytes of the same size is safe
+        unsafe { core::mem::transmute_copy(&self.0) }
+    }
+
+    #[cfg(feature = "generic_const_exprs")]
+    #[inline]
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    pub fn from_bitmask_array<const N: usize>(bitmask: [u8; N]) -> Self {
+        assert!(core::mem::size_of::<Self>() == N);
+
+        // Safety: converting an array of bytes to an integer of the same size is safe
+        Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData)
+    }
+
     #[inline]
     pub fn to_bitmask_integer<U>(self) -> U
     where
diff --git a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
index 8bbdf637de8..adf0fcbeae2 100644
--- a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
@@ -4,6 +4,9 @@ use super::MaskElement;
 use crate::simd::intrinsics;
 use crate::simd::{LaneCount, Simd, SupportedLaneCount, ToBitMask};
 
+#[cfg(feature = "generic_const_exprs")]
+use crate::simd::ToBitMaskArray;
+
 #[repr(transparent)]
 pub struct Mask<T, const LANES: usize>(Simd<T, LANES>)
 where
@@ -68,14 +71,26 @@ where
 
 // Used for bitmask bit order workaround
 pub(crate) trait ReverseBits {
-    fn reverse_bits(self) -> Self;
+    // Reverse the least significant `n` bits of `self`.
+    // (Remaining bits must be 0.)
+    fn reverse_bits(self, n: usize) -> Self;
 }
 
 macro_rules! impl_reverse_bits {
     { $($int:ty),* } => {
         $(
         impl ReverseBits for $int {
-            fn reverse_bits(self) -> Self { <$int>::reverse_bits(self) }
+            #[inline(always)]
+            fn reverse_bits(self, n: usize) -> Self {
+                let rev = <$int>::reverse_bits(self);
+                let bitsize = core::mem::size_of::<$int>() * 8;
+                if n < bitsize {
+                    // Shift things back to the right
+                    rev >> (bitsize - n)
+                } else {
+                    rev
+                }
+            }
         }
         )*
     }
@@ -127,6 +142,68 @@ where
         unsafe { Mask(intrinsics::simd_cast(self.0)) }
     }
 
+    #[cfg(feature = "generic_const_exprs")]
+    #[inline]
+    #[must_use = "method returns a new array and does not mutate the original value"]
+    pub fn to_bitmask_array<const N: usize>(self) -> [u8; N]
+    where
+        super::Mask<T, LANES>: ToBitMaskArray,
+        [(); <super::Mask<T, LANES> as ToBitMaskArray>::BYTES]: Sized,
+    {
+        assert_eq!(<super::Mask<T, LANES> as ToBitMaskArray>::BYTES, N);
+
+        // Safety: N is the correct bitmask size
+        unsafe {
+            // Compute the bitmask
+            let bitmask: [u8; <super::Mask<T, LANES> as ToBitMaskArray>::BYTES] =
+                intrinsics::simd_bitmask(self.0);
+
+            // Transmute to the return type, previously asserted to be the same size
+            let mut bitmask: [u8; N] = core::mem::transmute_copy(&bitmask);
+
+            // LLVM assumes bit order should match endianness
+            if cfg!(target_endian = "big") {
+                for x in bitmask.as_mut() {
+                    *x = x.reverse_bits();
+                }
+            };
+
+            bitmask
+        }
+    }
+
+    #[cfg(feature = "generic_const_exprs")]
+    #[inline]
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    pub fn from_bitmask_array<const N: usize>(mut bitmask: [u8; N]) -> Self
+    where
+        super::Mask<T, LANES>: ToBitMaskArray,
+        [(); <super::Mask<T, LANES> as ToBitMaskArray>::BYTES]: Sized,
+    {
+        assert_eq!(<super::Mask<T, LANES> as ToBitMaskArray>::BYTES, N);
+
+        // Safety: N is the correct bitmask size
+        unsafe {
+            // LLVM assumes bit order should match endianness
+            if cfg!(target_endian = "big") {
+                for x in bitmask.as_mut() {
+                    *x = x.reverse_bits();
+                }
+            }
+
+            // Transmute to the bitmask type, previously asserted to be the same size
+            let bitmask: [u8; <super::Mask<T, LANES> as ToBitMaskArray>::BYTES] =
+                core::mem::transmute_copy(&bitmask);
+
+            // Compute the regular mask
+            Self::from_int_unchecked(intrinsics::simd_select_bitmask(
+                bitmask,
+                Self::splat(true).to_int(),
+                Self::splat(false).to_int(),
+            ))
+        }
+    }
+
     #[inline]
     pub(crate) fn to_bitmask_integer<U: ReverseBits>(self) -> U
     where
@@ -137,7 +214,7 @@ where
 
         // LLVM assumes bit order should match endianness
         if cfg!(target_endian = "big") {
-            bitmask.reverse_bits()
+            bitmask.reverse_bits(LANES)
         } else {
             bitmask
         }
@@ -150,7 +227,7 @@ where
     {
         // LLVM assumes bit order should match endianness
         let bitmask = if cfg!(target_endian = "big") {
-            bitmask.reverse_bits()
+            bitmask.reverse_bits(LANES)
         } else {
             bitmask
         };
diff --git a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs
index c263f6a4eec..65d3ce9be65 100644
--- a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs
+++ b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs
@@ -16,11 +16,7 @@ where
 /// Converts masks to and from integer bitmasks.
 ///
 /// Each bit of the bitmask corresponds to a mask lane, starting with the LSB.
-///
-/// # Safety
-/// This trait is `unsafe` and sealed, since the `BitMask` type must match the number of lanes in
-/// the mask.
-pub unsafe trait ToBitMask: Sealed {
+pub trait ToBitMask: Sealed {
     /// The integer bitmask type.
     type BitMask;
 
@@ -31,10 +27,25 @@ pub unsafe trait ToBitMask: Sealed {
     fn from_bitmask(bitmask: Self::BitMask) -> Self;
 }
 
+/// Converts masks to and from byte array bitmasks.
+///
+/// Each bit of the bitmask corresponds to a mask lane, starting with the LSB of the first byte.
+#[cfg(feature = "generic_const_exprs")]
+pub trait ToBitMaskArray: Sealed {
+    /// The length of the bitmask array.
+    const BYTES: usize;
+
+    /// Converts a mask to a bitmask.
+    fn to_bitmask_array(self) -> [u8; Self::BYTES];
+
+    /// Converts a bitmask to a mask.
+    fn from_bitmask_array(bitmask: [u8; Self::BYTES]) -> Self;
+}
+
 macro_rules! impl_integer_intrinsic {
-    { $(unsafe impl ToBitMask<BitMask=$int:ty> for Mask<_, $lanes:literal>)* } => {
+    { $(impl ToBitMask<BitMask=$int:ty> for Mask<_, $lanes:literal>)* } => {
         $(
-        unsafe impl<T: MaskElement> ToBitMask for Mask<T, $lanes> {
+        impl<T: MaskElement> ToBitMask for Mask<T, $lanes> {
             type BitMask = $int;
 
             fn to_bitmask(self) -> $int {
@@ -50,11 +61,33 @@ macro_rules! impl_integer_intrinsic {
 }
 
 impl_integer_intrinsic! {
-    unsafe impl ToBitMask<BitMask=u8> for Mask<_, 1>
-    unsafe impl ToBitMask<BitMask=u8> for Mask<_, 2>
-    unsafe impl ToBitMask<BitMask=u8> for Mask<_, 4>
-    unsafe impl ToBitMask<BitMask=u8> for Mask<_, 8>
-    unsafe impl ToBitMask<BitMask=u16> for Mask<_, 16>
-    unsafe impl ToBitMask<BitMask=u32> for Mask<_, 32>
-    unsafe impl ToBitMask<BitMask=u64> for Mask<_, 64>
+    impl ToBitMask<BitMask=u8> for Mask<_, 1>
+    impl ToBitMask<BitMask=u8> for Mask<_, 2>
+    impl ToBitMask<BitMask=u8> for Mask<_, 4>
+    impl ToBitMask<BitMask=u8> for Mask<_, 8>
+    impl ToBitMask<BitMask=u16> for Mask<_, 16>
+    impl ToBitMask<BitMask=u32> for Mask<_, 32>
+    impl ToBitMask<BitMask=u64> for Mask<_, 64>
+}
+
+/// Returns the minimum numnber of bytes in a bitmask with `lanes` lanes.
+#[cfg(feature = "generic_const_exprs")]
+pub const fn bitmask_len(lanes: usize) -> usize {
+    (lanes + 7) / 8
+}
+
+#[cfg(feature = "generic_const_exprs")]
+impl<T: MaskElement, const LANES: usize> ToBitMaskArray for Mask<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    const BYTES: usize = bitmask_len(LANES);
+
+    fn to_bitmask_array(self) -> [u8; Self::BYTES] {
+        self.0.to_bitmask_array()
+    }
+
+    fn from_bitmask_array(bitmask: [u8; Self::BYTES]) -> Self {
+        Mask(mask_impl::Mask::from_bitmask_array(bitmask))
+    }
 }
diff --git a/library/portable-simd/crates/core_simd/src/math.rs b/library/portable-simd/crates/core_simd/src/math.rs
deleted file mode 100644
index 606021e983e..00000000000
--- a/library/portable-simd/crates/core_simd/src/math.rs
+++ /dev/null
@@ -1,156 +0,0 @@
-use crate::simd::intrinsics::{simd_saturating_add, simd_saturating_sub};
-use crate::simd::{LaneCount, Simd, SupportedLaneCount};
-
-macro_rules! impl_uint_arith {
-    ($($ty:ty),+) => {
-        $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
-
-            /// Lanewise saturating add.
-            ///
-            /// # Examples
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
-            /// let x = Simd::from_array([2, 1, 0, MAX]);
-            /// let max = Simd::splat(MAX);
-            /// let unsat = x + max;
-            /// let sat = x.saturating_add(max);
-            /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
-            /// assert_eq!(sat, max);
-            /// ```
-            #[inline]
-            pub fn saturating_add(self, second: Self) -> Self {
-                // Safety: `self` is a vector
-                unsafe { simd_saturating_add(self, second) }
-            }
-
-            /// Lanewise saturating subtract.
-            ///
-            /// # Examples
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
-            /// let x = Simd::from_array([2, 1, 0, MAX]);
-            /// let max = Simd::splat(MAX);
-            /// let unsat = x - max;
-            /// let sat = x.saturating_sub(max);
-            /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
-            /// assert_eq!(sat, Simd::splat(0));
-            #[inline]
-            pub fn saturating_sub(self, second: Self) -> Self {
-                // Safety: `self` is a vector
-                unsafe { simd_saturating_sub(self, second) }
-            }
-        })+
-    }
-}
-
-macro_rules! impl_int_arith {
-    ($($ty:ty),+) => {
-        $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
-
-            /// Lanewise saturating add.
-            ///
-            /// # Examples
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
-            /// let x = Simd::from_array([MIN, 0, 1, MAX]);
-            /// let max = Simd::splat(MAX);
-            /// let unsat = x + max;
-            /// let sat = x.saturating_add(max);
-            /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
-            /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
-            /// ```
-            #[inline]
-            pub fn saturating_add(self, second: Self) -> Self {
-                // Safety: `self` is a vector
-                unsafe { simd_saturating_add(self, second) }
-            }
-
-            /// Lanewise saturating subtract.
-            ///
-            /// # Examples
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
-            /// let x = Simd::from_array([MIN, -2, -1, MAX]);
-            /// let max = Simd::splat(MAX);
-            /// let unsat = x - max;
-            /// let sat = x.saturating_sub(max);
-            /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
-            /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
-            #[inline]
-            pub fn saturating_sub(self, second: Self) -> Self {
-                // Safety: `self` is a vector
-                unsafe { simd_saturating_sub(self, second) }
-            }
-
-            /// Lanewise absolute value, implemented in Rust.
-            /// Every lane becomes its absolute value.
-            ///
-            /// # Examples
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
-            /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
-            /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
-            /// ```
-            #[inline]
-            pub fn abs(self) -> Self {
-                const SHR: $ty = <$ty>::BITS as $ty - 1;
-                let m = self >> Simd::splat(SHR);
-                (self^m) - m
-            }
-
-            /// Lanewise saturating absolute value, implemented in Rust.
-            /// As abs(), except the MIN value becomes MAX instead of itself.
-            ///
-            /// # Examples
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
-            /// let xs = Simd::from_array([MIN, -2, 0, 3]);
-            /// let unsat = xs.abs();
-            /// let sat = xs.saturating_abs();
-            /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
-            /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
-            /// ```
-            #[inline]
-            pub fn saturating_abs(self) -> Self {
-                // arith shift for -1 or 0 mask based on sign bit, giving 2s complement
-                const SHR: $ty = <$ty>::BITS as $ty - 1;
-                let m = self >> Simd::splat(SHR);
-                (self^m).saturating_sub(m)
-            }
-
-            /// Lanewise saturating negation, implemented in Rust.
-            /// As neg(), except the MIN value becomes MAX instead of itself.
-            ///
-            /// # Examples
-            /// ```
-            /// # #![feature(portable_simd)]
-            /// # use core::simd::Simd;
-            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
-            /// let x = Simd::from_array([MIN, -2, 3, MAX]);
-            /// let unsat = -x;
-            /// let sat = x.saturating_neg();
-            /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
-            /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
-            /// ```
-            #[inline]
-            pub fn saturating_neg(self) -> Self {
-                Self::splat(0).saturating_sub(self)
-            }
-        })+
-    }
-}
-
-impl_uint_arith! { u8, u16, u32, u64, usize }
-impl_int_arith! { i8, i16, i32, i64, isize }
diff --git a/library/portable-simd/crates/core_simd/src/mod.rs b/library/portable-simd/crates/core_simd/src/mod.rs
index 85026265956..b472aa3abe2 100644
--- a/library/portable-simd/crates/core_simd/src/mod.rs
+++ b/library/portable-simd/crates/core_simd/src/mod.rs
@@ -1,7 +1,4 @@
 #[macro_use]
-mod reduction;
-
-#[macro_use]
 mod swizzle;
 
 pub(crate) mod intrinsics;
@@ -9,14 +6,14 @@ pub(crate) mod intrinsics;
 #[cfg(feature = "generic_const_exprs")]
 mod to_bytes;
 
-mod comparisons;
+mod elements;
+mod eq;
 mod fmt;
 mod iter;
 mod lane_count;
 mod masks;
-mod math;
 mod ops;
-mod round;
+mod ord;
 mod select;
 mod vector;
 mod vendor;
@@ -25,8 +22,11 @@ mod vendor;
 pub mod simd {
     pub(crate) use crate::core_simd::intrinsics;
 
+    pub use crate::core_simd::elements::*;
+    pub use crate::core_simd::eq::*;
     pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
     pub use crate::core_simd::masks::*;
+    pub use crate::core_simd::ord::*;
     pub use crate::core_simd::swizzle::*;
     pub use crate::core_simd::vector::*;
 }
diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs
index 1b35b3e717a..5a077a469d8 100644
--- a/library/portable-simd/crates/core_simd/src/ops.rs
+++ b/library/portable-simd/crates/core_simd/src/ops.rs
@@ -1,4 +1,4 @@
-use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use crate::simd::{LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount};
 use core::ops::{Add, Mul};
 use core::ops::{BitAnd, BitOr, BitXor};
 use core::ops::{Div, Rem, Sub};
@@ -33,6 +33,7 @@ where
 
 macro_rules! unsafe_base {
     ($lhs:ident, $rhs:ident, {$simd_call:ident}, $($_:tt)*) => {
+        // Safety: $lhs and $rhs are vectors
         unsafe { $crate::simd::intrinsics::$simd_call($lhs, $rhs) }
     };
 }
@@ -48,6 +49,8 @@ macro_rules! unsafe_base {
 // cg_clif defaults to this, and scalar MIR shifts also default to wrapping
 macro_rules! wrap_bitshift {
     ($lhs:ident, $rhs:ident, {$simd_call:ident}, $int:ident) => {
+        #[allow(clippy::suspicious_arithmetic_impl)]
+        // Safety: $lhs and the bitand result are vectors
         unsafe {
             $crate::simd::intrinsics::$simd_call(
                 $lhs,
@@ -74,7 +77,7 @@ macro_rules! int_divrem_guard {
             $simd_call:ident
         },
         $int:ident ) => {
-        if $rhs.lanes_eq(Simd::splat(0)).any() {
+        if $rhs.simd_eq(Simd::splat(0 as _)).any() {
             panic!($zero);
         } else {
             // Prevent otherwise-UB overflow on the MIN / -1 case.
@@ -82,14 +85,15 @@ macro_rules! int_divrem_guard {
                 // This should, at worst, optimize to a few branchless logical ops
                 // Ideally, this entire conditional should evaporate
                 // Fire LLVM and implement those manually if it doesn't get the hint
-                ($lhs.lanes_eq(Simd::splat(<$int>::MIN))
+                ($lhs.simd_eq(Simd::splat(<$int>::MIN))
                 // type inference can break here, so cut an SInt to size
-                & $rhs.lanes_eq(Simd::splat(-1i64 as _)))
-                .select(Simd::splat(1), $rhs)
+                & $rhs.simd_eq(Simd::splat(-1i64 as _)))
+                .select(Simd::splat(1 as _), $rhs)
             } else {
                 // Nice base case to make it easy to const-fold away the other branch.
                 $rhs
             };
+            // Safety: $lhs and rhs are vectors
             unsafe { $crate::simd::intrinsics::$simd_call($lhs, rhs) }
         }
     };
diff --git a/library/portable-simd/crates/core_simd/src/ops/unary.rs b/library/portable-simd/crates/core_simd/src/ops/unary.rs
index 4ebea560fc6..4ad02215034 100644
--- a/library/portable-simd/crates/core_simd/src/ops/unary.rs
+++ b/library/portable-simd/crates/core_simd/src/ops/unary.rs
@@ -14,6 +14,7 @@ macro_rules! neg {
             #[inline]
             #[must_use = "operator returns a new vector without mutating the input"]
             fn neg(self) -> Self::Output {
+                // Safety: `self` is a signed vector
                 unsafe { intrinsics::simd_neg(self) }
             }
         })*
diff --git a/library/portable-simd/crates/core_simd/src/ord.rs b/library/portable-simd/crates/core_simd/src/ord.rs
new file mode 100644
index 00000000000..9a87bc2e344
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/ord.rs
@@ -0,0 +1,213 @@
+use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
+
+/// Parallel `PartialOrd`.
+pub trait SimdPartialOrd: SimdPartialEq {
+    /// Test if each lane is less than the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_lt(self, other: Self) -> Self::Mask;
+
+    /// Test if each lane is less than or equal to the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_le(self, other: Self) -> Self::Mask;
+
+    /// Test if each lane is greater than the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_gt(self, other: Self) -> Self::Mask;
+
+    /// Test if each lane is greater than or equal to the corresponding lane in `other`.
+    #[must_use = "method returns a new mask and does not mutate the original value"]
+    fn simd_ge(self, other: Self) -> Self::Mask;
+}
+
+/// Parallel `Ord`.
+pub trait SimdOrd: SimdPartialOrd {
+    /// Returns the lane-wise maximum with `other`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn simd_max(self, other: Self) -> Self;
+
+    /// Returns the lane-wise minimum with `other`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn simd_min(self, other: Self) -> Self;
+
+    /// Restrict each lane to a certain interval.
+    ///
+    /// For each lane, returns `max` if `self` is greater than `max`, and `min` if `self` is
+    /// less than `min`. Otherwise returns `self`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `min > max` on any lane.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn simd_clamp(self, min: Self, max: Self) -> Self;
+}
+
+macro_rules! impl_integer {
+    { $($integer:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialOrd for Simd<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_lt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
+            }
+
+            #[inline]
+            fn simd_le(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
+            }
+
+            #[inline]
+            fn simd_gt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
+            }
+
+            #[inline]
+            fn simd_ge(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
+            }
+        }
+
+        impl<const LANES: usize> SimdOrd for Simd<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_max(self, other: Self) -> Self {
+                self.simd_lt(other).select(other, self)
+            }
+
+            #[inline]
+            fn simd_min(self, other: Self) -> Self {
+                self.simd_gt(other).select(other, self)
+            }
+
+            #[inline]
+            fn simd_clamp(self, min: Self, max: Self) -> Self {
+                assert!(
+                    min.simd_le(max).all(),
+                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
+                );
+                self.simd_max(min).simd_min(max)
+            }
+        }
+        )*
+    }
+}
+
+impl_integer! { u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }
+
+macro_rules! impl_float {
+    { $($float:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialOrd for Simd<$float, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_lt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
+            }
+
+            #[inline]
+            fn simd_le(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
+            }
+
+            #[inline]
+            fn simd_gt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
+            }
+
+            #[inline]
+            fn simd_ge(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
+            }
+        }
+        )*
+    }
+}
+
+impl_float! { f32, f64 }
+
+macro_rules! impl_mask {
+    { $($integer:ty),* } => {
+        $(
+        impl<const LANES: usize> SimdPartialOrd for Mask<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_lt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_lt(self.to_int(), other.to_int())) }
+            }
+
+            #[inline]
+            fn simd_le(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_le(self.to_int(), other.to_int())) }
+            }
+
+            #[inline]
+            fn simd_gt(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_gt(self.to_int(), other.to_int())) }
+            }
+
+            #[inline]
+            fn simd_ge(self, other: Self) -> Self::Mask {
+                // Safety: `self` is a vector, and the result of the comparison
+                // is always a valid mask.
+                unsafe { Self::from_int_unchecked(intrinsics::simd_ge(self.to_int(), other.to_int())) }
+            }
+        }
+
+        impl<const LANES: usize> SimdOrd for Mask<$integer, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            #[inline]
+            fn simd_max(self, other: Self) -> Self {
+                self.simd_gt(other).select_mask(other, self)
+            }
+
+            #[inline]
+            fn simd_min(self, other: Self) -> Self {
+                self.simd_lt(other).select_mask(other, self)
+            }
+
+            #[inline]
+            fn simd_clamp(self, min: Self, max: Self) -> Self {
+                assert!(
+                    min.simd_le(max).all(),
+                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
+                );
+                self.simd_max(min).simd_min(max)
+            }
+        }
+        )*
+    }
+}
+
+impl_mask! { i8, i16, i32, i64, isize }
diff --git a/library/portable-simd/crates/core_simd/src/reduction.rs b/library/portable-simd/crates/core_simd/src/reduction.rs
deleted file mode 100644
index 3177fd167fc..00000000000
--- a/library/portable-simd/crates/core_simd/src/reduction.rs
+++ /dev/null
@@ -1,153 +0,0 @@
-use crate::simd::intrinsics::{
-    simd_reduce_add_ordered, simd_reduce_and, simd_reduce_max, simd_reduce_min,
-    simd_reduce_mul_ordered, simd_reduce_or, simd_reduce_xor,
-};
-use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
-use core::ops::{BitAnd, BitOr, BitXor};
-
-macro_rules! impl_integer_reductions {
-    { $scalar:ty } => {
-        impl<const LANES: usize> Simd<$scalar, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-            /// Reducing wrapping add.  Returns the sum of the lanes of the vector, with wrapping addition.
-            #[inline]
-            pub fn reduce_sum(self) -> $scalar {
-                // Safety: `self` is an integer vector
-                unsafe { simd_reduce_add_ordered(self, 0) }
-            }
-
-            /// Reducing wrapping multiply.  Returns the product of the lanes of the vector, with wrapping multiplication.
-            #[inline]
-            pub fn reduce_product(self) -> $scalar {
-                // Safety: `self` is an integer vector
-                unsafe { simd_reduce_mul_ordered(self, 1) }
-            }
-
-            /// Reducing maximum.  Returns the maximum lane in the vector.
-            #[inline]
-            pub fn reduce_max(self) -> $scalar {
-                // Safety: `self` is an integer vector
-                unsafe { simd_reduce_max(self) }
-            }
-
-            /// Reducing minimum.  Returns the minimum lane in the vector.
-            #[inline]
-            pub fn reduce_min(self) -> $scalar {
-                // Safety: `self` is an integer vector
-                unsafe { simd_reduce_min(self) }
-            }
-        }
-    }
-}
-
-impl_integer_reductions! { i8 }
-impl_integer_reductions! { i16 }
-impl_integer_reductions! { i32 }
-impl_integer_reductions! { i64 }
-impl_integer_reductions! { isize }
-impl_integer_reductions! { u8 }
-impl_integer_reductions! { u16 }
-impl_integer_reductions! { u32 }
-impl_integer_reductions! { u64 }
-impl_integer_reductions! { usize }
-
-macro_rules! impl_float_reductions {
-    { $scalar:ty } => {
-        impl<const LANES: usize> Simd<$scalar, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-
-            /// Reducing add.  Returns the sum of the lanes of the vector.
-            #[inline]
-            pub fn reduce_sum(self) -> $scalar {
-                // LLVM sum is inaccurate on i586
-                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
-                    self.as_array().iter().sum()
-                } else {
-                    // Safety: `self` is a float vector
-                    unsafe { simd_reduce_add_ordered(self, 0.) }
-                }
-            }
-
-            /// Reducing multiply.  Returns the product of the lanes of the vector.
-            #[inline]
-            pub fn reduce_product(self) -> $scalar {
-                // LLVM product is inaccurate on i586
-                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
-                    self.as_array().iter().product()
-                } else {
-                    // Safety: `self` is a float vector
-                    unsafe { simd_reduce_mul_ordered(self, 1.) }
-                }
-            }
-
-            /// Reducing maximum.  Returns the maximum lane in the vector.
-            ///
-            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
-            /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
-            #[inline]
-            pub fn reduce_max(self) -> $scalar {
-                // Safety: `self` is a float vector
-                unsafe { simd_reduce_max(self) }
-            }
-
-            /// Reducing minimum.  Returns the minimum lane in the vector.
-            ///
-            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
-            /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
-            #[inline]
-            pub fn reduce_min(self) -> $scalar {
-                // Safety: `self` is a float vector
-                unsafe { simd_reduce_min(self) }
-            }
-        }
-    }
-}
-
-impl_float_reductions! { f32 }
-impl_float_reductions! { f64 }
-
-impl<T, const LANES: usize> Simd<T, LANES>
-where
-    Self: BitAnd<Self, Output = Self>,
-    T: SimdElement + BitAnd<T, Output = T>,
-    LaneCount<LANES>: SupportedLaneCount,
-{
-    /// Reducing bitwise "and".  Returns the cumulative bitwise "and" across the lanes of
-    /// the vector.
-    #[inline]
-    pub fn reduce_and(self) -> T {
-        unsafe { simd_reduce_and(self) }
-    }
-}
-
-impl<T, const LANES: usize> Simd<T, LANES>
-where
-    Self: BitOr<Self, Output = Self>,
-    T: SimdElement + BitOr<T, Output = T>,
-    LaneCount<LANES>: SupportedLaneCount,
-{
-    /// Reducing bitwise "or".  Returns the cumulative bitwise "or" across the lanes of
-    /// the vector.
-    #[inline]
-    pub fn reduce_or(self) -> T {
-        unsafe { simd_reduce_or(self) }
-    }
-}
-
-impl<T, const LANES: usize> Simd<T, LANES>
-where
-    Self: BitXor<Self, Output = Self>,
-    T: SimdElement + BitXor<T, Output = T>,
-    LaneCount<LANES>: SupportedLaneCount,
-{
-    /// Reducing bitwise "xor".  Returns the cumulative bitwise "xor" across the lanes of
-    /// the vector.
-    #[inline]
-    pub fn reduce_xor(self) -> T {
-        unsafe { simd_reduce_xor(self) }
-    }
-}
diff --git a/library/portable-simd/crates/core_simd/src/round.rs b/library/portable-simd/crates/core_simd/src/round.rs
deleted file mode 100644
index 556bc2cc1fe..00000000000
--- a/library/portable-simd/crates/core_simd/src/round.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use crate::simd::intrinsics;
-use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
-use core::convert::FloatToInt;
-
-macro_rules! implement {
-    {
-        $type:ty
-    } => {
-        impl<const LANES: usize> Simd<$type, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-            /// Rounds toward zero and converts to the same-width integer type, assuming that
-            /// the value is finite and fits in that type.
-            ///
-            /// # Safety
-            /// The value must:
-            ///
-            /// * Not be NaN
-            /// * Not be infinite
-            /// * Be representable in the return type, after truncating off its fractional part
-            ///
-            /// If these requirements are infeasible or costly, consider using the safe function [cast],
-            /// which saturates on conversion.
-            ///
-            /// [cast]: Simd::cast
-            #[inline]
-            pub unsafe fn to_int_unchecked<I>(self) -> Simd<I, LANES>
-            where
-                $type: FloatToInt<I>,
-                I: SimdElement,
-            {
-                unsafe { intrinsics::simd_cast(self) }
-            }
-        }
-    }
-}
-
-implement! { f32 }
-implement! { f64 }
diff --git a/library/portable-simd/crates/core_simd/src/swizzle.rs b/library/portable-simd/crates/core_simd/src/swizzle.rs
index ef47c4f3a4c..22999d24950 100644
--- a/library/portable-simd/crates/core_simd/src/swizzle.rs
+++ b/library/portable-simd/crates/core_simd/src/swizzle.rs
@@ -1,44 +1,46 @@
 use crate::simd::intrinsics;
 use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
 
-/// Constructs a new vector by selecting values from the lanes of the source vector or vectors to use.
+/// Constructs a new SIMD vector by copying elements from selected lanes in other vectors.
 ///
-/// When swizzling one vector, the indices of the result vector are indicated by a `const` array
-/// of `usize`, like [`Swizzle`].
-/// When swizzling two vectors, the indices are indicated by a `const` array of [`Which`], like
-/// [`Swizzle2`].
+/// When swizzling one vector, lanes are selected by a `const` array of `usize`,
+/// like [`Swizzle`].
+///
+/// When swizzling two vectors, lanes are selected by a `const` array of [`Which`],
+/// like [`Swizzle2`].
 ///
 /// # Examples
-/// ## One source vector
+///
+/// With a single SIMD vector, the const array specifies lane indices in that vector:
 /// ```
 /// # #![feature(portable_simd)]
-/// # use core::simd::{Simd, simd_swizzle};
-/// let v = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
+/// # use core::simd::{u32x2, u32x4, simd_swizzle};
+/// let v = u32x4::from_array([10, 11, 12, 13]);
 ///
 /// // Keeping the same size
-/// let r = simd_swizzle!(v, [3, 0, 1, 2]);
-/// assert_eq!(r.to_array(), [3., 0., 1., 2.]);
+/// let r: u32x4 = simd_swizzle!(v, [3, 0, 1, 2]);
+/// assert_eq!(r.to_array(), [13, 10, 11, 12]);
 ///
 /// // Changing the number of lanes
-/// let r = simd_swizzle!(v, [3, 1]);
-/// assert_eq!(r.to_array(), [3., 1.]);
+/// let r: u32x2 = simd_swizzle!(v, [3, 1]);
+/// assert_eq!(r.to_array(), [13, 11]);
 /// ```
 ///
-/// ## Two source vectors
+/// With two input SIMD vectors, the const array uses `Which` to specify the source of each index:
 /// ```
 /// # #![feature(portable_simd)]
-/// # use core::simd::{Simd, simd_swizzle, Which};
-/// use Which::*;
-/// let a = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
-/// let b = Simd::<f32, 4>::from_array([4., 5., 6., 7.]);
+/// # use core::simd::{u32x2, u32x4, simd_swizzle, Which};
+/// use Which::{First, Second};
+/// let a = u32x4::from_array([0, 1, 2, 3]);
+/// let b = u32x4::from_array([4, 5, 6, 7]);
 ///
 /// // Keeping the same size
-/// let r = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]);
-/// assert_eq!(r.to_array(), [0., 1., 6., 7.]);
+/// let r: u32x4 = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]);
+/// assert_eq!(r.to_array(), [0, 1, 6, 7]);
 ///
 /// // Changing the number of lanes
-/// let r = simd_swizzle!(a, b, [First(0), Second(0)]);
-/// assert_eq!(r.to_array(), [0., 4.]);
+/// let r: u32x2 = simd_swizzle!(a, b, [First(0), Second(0)]);
+/// assert_eq!(r.to_array(), [0, 4]);
 /// ```
 #[allow(unused_macros)]
 pub macro simd_swizzle {
@@ -68,12 +70,14 @@ pub macro simd_swizzle {
     }
 }
 
-/// An index into one of two vectors.
+/// Specifies a lane index into one of two SIMD vectors.
+///
+/// This is an input type for [Swizzle2] and helper macros like [simd_swizzle].
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum Which {
-    /// Indexes the first vector.
+    /// Index of a lane in the first input SIMD vector.
     First(usize),
-    /// Indexes the second vector.
+    /// Index of a lane in the second input SIMD vector.
     Second(usize),
 }
 
diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs
index b9cd2e2021e..78f56402eba 100644
--- a/library/portable-simd/crates/core_simd/src/vector.rs
+++ b/library/portable-simd/crates/core_simd/src/vector.rs
@@ -9,8 +9,9 @@ pub use uint::*;
 // Vectors of pointers are not for public use at the current time.
 pub(crate) mod ptr;
 
-use crate::simd::intrinsics;
-use crate::simd::{LaneCount, Mask, MaskElement, SupportedLaneCount};
+use crate::simd::{
+    intrinsics, LaneCount, Mask, MaskElement, SimdPartialOrd, SupportedLaneCount, Swizzle,
+};
 
 /// A SIMD vector of `LANES` elements of type `T`. `Simd<T, N>` has the same shape as [`[T; N]`](array), but operates like `T`.
 ///
@@ -99,17 +100,50 @@ where
     /// Number of lanes in this vector.
     pub const LANES: usize = LANES;
 
-    /// Get the number of lanes in this vector.
+    /// Returns the number of lanes in this SIMD vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # use core::simd::u32x4;
+    /// let v = u32x4::splat(0);
+    /// assert_eq!(v.lanes(), 4);
+    /// ```
     pub const fn lanes(&self) -> usize {
         LANES
     }
 
-    /// Construct a SIMD vector by setting all lanes to the given value.
-    pub const fn splat(value: T) -> Self {
-        Self([value; LANES])
+    /// Constructs a new SIMD vector with all lanes set to the given value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # use core::simd::u32x4;
+    /// let v = u32x4::splat(8);
+    /// assert_eq!(v.as_array(), &[8, 8, 8, 8]);
+    /// ```
+    pub fn splat(value: T) -> Self {
+        // This is preferred over `[value; LANES]`, since it's explicitly a splat:
+        // https://github.com/rust-lang/rust/issues/97804
+        struct Splat;
+        impl<const LANES: usize> Swizzle<1, LANES> for Splat {
+            const INDEX: [usize; LANES] = [0; LANES];
+        }
+        Splat::swizzle(Simd::<T, 1>::from([value]))
     }
 
     /// Returns an array reference containing the entire SIMD vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # use core::simd::{Simd, u64x4};
+    /// let v: u64x4 = Simd::from_array([0, 1, 2, 3]);
+    /// assert_eq!(v.as_array(), &[0, 1, 2, 3]);
+    /// ```
     pub const fn as_array(&self) -> &[T; LANES] {
         &self.0
     }
@@ -129,9 +163,21 @@ where
         self.0
     }
 
-    /// Converts a slice to a SIMD vector containing `slice[..LANES]`
+    /// Converts a slice to a SIMD vector containing `slice[..LANES]`.
+    ///
     /// # Panics
-    /// `from_slice` will panic if the slice's `len` is less than the vector's `Simd::LANES`.
+    ///
+    /// Panics if the slice's length is less than the vector's `Simd::LANES`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # use core::simd::u32x4;
+    /// let source = vec![1, 2, 3, 4, 5, 6];
+    /// let v = u32x4::from_slice(&source);
+    /// assert_eq!(v.as_array(), &[1, 2, 3, 4]);
+    /// ```
     #[must_use]
     pub const fn from_slice(slice: &[T]) -> Self {
         assert!(slice.len() >= LANES, "slice length must be at least the number of lanes");
@@ -145,6 +191,7 @@ where
     }
 
     /// Performs lanewise conversion of a SIMD vector's elements to another SIMD-valid type.
+    ///
     /// This follows the semantics of Rust's `as` conversion for casting
     /// integers to unsigned integers (interpreting as the other type, so `-1` to `MAX`),
     /// and from floats to integers (truncating, or saturating at the limits) for each lane,
@@ -169,10 +216,35 @@ where
     #[must_use]
     #[inline]
     pub fn cast<U: SimdElement>(self) -> Simd<U, LANES> {
-        // Safety: The input argument is a vector of a known SIMD type.
+        // Safety: The input argument is a vector of a valid SIMD element type.
         unsafe { intrinsics::simd_as(self) }
     }
 
+    /// Rounds toward zero and converts to the same-width integer type, assuming that
+    /// the value is finite and fits in that type.
+    ///
+    /// # Safety
+    /// The value must:
+    ///
+    /// * Not be NaN
+    /// * Not be infinite
+    /// * Be representable in the return type, after truncating off its fractional part
+    ///
+    /// If these requirements are infeasible or costly, consider using the safe function [cast],
+    /// which saturates on conversion.
+    ///
+    /// [cast]: Simd::cast
+    #[inline]
+    pub unsafe fn to_int_unchecked<I>(self) -> Simd<I, LANES>
+    where
+        T: core::convert::FloatToInt<I>,
+        I: SimdElement,
+    {
+        // Safety: `self` is a vector, and `FloatToInt` ensures the type can be casted to
+        // an integer.
+        unsafe { intrinsics::simd_cast(self) }
+    }
+
     /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
     /// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
     ///
@@ -239,7 +311,7 @@ where
         idxs: Simd<usize, LANES>,
         or: Self,
     ) -> Self {
-        let enable: Mask<isize, LANES> = enable & idxs.lanes_lt(Simd::splat(slice.len()));
+        let enable: Mask<isize, LANES> = enable & idxs.simd_lt(Simd::splat(slice.len()));
         // Safety: We have masked-off out-of-bounds lanes.
         unsafe { Self::gather_select_unchecked(slice, enable, idxs, or) }
     }
@@ -256,13 +328,15 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # use core::simd::{Simd, Mask};
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, SimdPartialOrd, Mask};
     /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 5]);
     /// let alt = Simd::from_array([-5, -4, -3, -2]);
     /// let enable = Mask::from_array([true, true, true, false]); // Note the final mask lane.
     /// // If this mask was used to gather, it would be unsound. Let's fix that.
-    /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len()));
+    /// let enable = enable & idxs.simd_lt(Simd::splat(vec.len()));
     ///
     /// // We have masked the OOB lane, so it's safe to gather now.
     /// let result = unsafe { Simd::gather_select_unchecked(&vec, enable, idxs, alt) };
@@ -313,7 +387,9 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # use core::simd::{Simd, Mask};
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, Mask};
     /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 0]);
     /// let vals = Simd::from_array([-27, 82, -41, 124]);
@@ -329,7 +405,7 @@ where
         enable: Mask<isize, LANES>,
         idxs: Simd<usize, LANES>,
     ) {
-        let enable: Mask<isize, LANES> = enable & idxs.lanes_lt(Simd::splat(slice.len()));
+        let enable: Mask<isize, LANES> = enable & idxs.simd_lt(Simd::splat(slice.len()));
         // Safety: We have masked-off out-of-bounds lanes.
         unsafe { self.scatter_select_unchecked(slice, enable, idxs) }
     }
@@ -347,13 +423,15 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # use core::simd::{Simd, Mask};
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, SimdPartialOrd, Mask};
     /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 0]);
     /// let vals = Simd::from_array([-27, 82, -41, 124]);
     /// let enable = Mask::from_array([true, true, true, false]); // Note the mask of the last lane.
     /// // If this mask was used to scatter, it would be unsound. Let's fix that.
-    /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len()));
+    /// let enable = enable & idxs.simd_lt(Simd::splat(vec.len()));
     ///
     /// // We have masked the OOB lane, so it's safe to scatter now.
     /// unsafe { vals.scatter_select_unchecked(&mut vec, enable, idxs); }
@@ -425,8 +503,27 @@ where
 {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
-        // TODO use SIMD equality
-        self.to_array() == other.to_array()
+        // Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask.
+        let mask = unsafe {
+            let tfvec: Simd<<T as SimdElement>::Mask, LANES> = intrinsics::simd_eq(*self, *other);
+            Mask::from_int_unchecked(tfvec)
+        };
+
+        // Two vectors are equal if all lanes tested true for vertical equality.
+        mask.all()
+    }
+
+    #[allow(clippy::partialeq_ne_impl)]
+    #[inline]
+    fn ne(&self, other: &Self) -> bool {
+        // Safety: All SIMD vectors are SimdPartialEq, and the comparison produces a valid mask.
+        let mask = unsafe {
+            let tfvec: Simd<<T as SimdElement>::Mask, LANES> = intrinsics::simd_ne(*self, *other);
+            Mask::from_int_unchecked(tfvec)
+        };
+
+        // Two vectors are non-equal if any lane tested true for vertical non-equality.
+        mask.any()
     }
 }
 
@@ -561,61 +658,85 @@ pub unsafe trait SimdElement: Sealed + Copy {
 }
 
 impl Sealed for u8 {}
+
+// Safety: u8 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for u8 {
     type Mask = i8;
 }
 
 impl Sealed for u16 {}
+
+// Safety: u16 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for u16 {
     type Mask = i16;
 }
 
 impl Sealed for u32 {}
+
+// Safety: u32 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for u32 {
     type Mask = i32;
 }
 
 impl Sealed for u64 {}
+
+// Safety: u64 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for u64 {
     type Mask = i64;
 }
 
 impl Sealed for usize {}
+
+// Safety: usize is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for usize {
     type Mask = isize;
 }
 
 impl Sealed for i8 {}
+
+// Safety: i8 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for i8 {
     type Mask = i8;
 }
 
 impl Sealed for i16 {}
+
+// Safety: i16 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for i16 {
     type Mask = i16;
 }
 
 impl Sealed for i32 {}
+
+// Safety: i32 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for i32 {
     type Mask = i32;
 }
 
 impl Sealed for i64 {}
+
+// Safety: i64 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for i64 {
     type Mask = i64;
 }
 
 impl Sealed for isize {}
+
+// Safety: isize is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for isize {
     type Mask = isize;
 }
 
 impl Sealed for f32 {}
+
+// Safety: f32 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for f32 {
     type Mask = i32;
 }
 
 impl Sealed for f64 {}
+
+// Safety: f64 is a valid SIMD element type, and is supported by this API
 unsafe impl SimdElement for f64 {
     type Mask = i64;
 }
diff --git a/library/portable-simd/crates/core_simd/src/vector/float.rs b/library/portable-simd/crates/core_simd/src/vector/float.rs
index fcc7f6d8d1c..f836c99b1e2 100644
--- a/library/portable-simd/crates/core_simd/src/vector/float.rs
+++ b/library/portable-simd/crates/core_simd/src/vector/float.rs
@@ -1,199 +1,24 @@
 #![allow(non_camel_case_types)]
 
-use crate::simd::intrinsics;
-use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount};
+use crate::simd::Simd;
 
-/// Implements inherent methods for a float vector containing multiple
-/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
-/// representation.
-macro_rules! impl_float_vector {
-    { $type:ty, $bits_ty:ty, $mask_ty:ty } => {
-        impl<const LANES: usize> Simd<$type, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-            /// Raw transmutation to an unsigned integer vector type with the
-            /// same size and number of lanes.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn to_bits(self) -> Simd<$bits_ty, LANES> {
-                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
-                unsafe { core::mem::transmute_copy(&self) }
-            }
-
-            /// Raw transmutation from an unsigned integer vector type with the
-            /// same size and number of lanes.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self {
-                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
-                unsafe { core::mem::transmute_copy(&bits) }
-            }
-
-            /// Produces a vector where every lane has the absolute value of the
-            /// equivalently-indexed lane in `self`.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn abs(self) -> Self {
-                unsafe { intrinsics::simd_fabs(self) }
-            }
-
-            /// Takes the reciprocal (inverse) of each lane, `1/x`.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn recip(self) -> Self {
-                Self::splat(1.0) / self
-            }
-
-            /// Converts each lane from radians to degrees.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn to_degrees(self) -> Self {
-                // to_degrees uses a special constant for better precision, so extract that constant
-                self * Self::splat(<$type>::to_degrees(1.))
-            }
-
-            /// Converts each lane from degrees to radians.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn to_radians(self) -> Self {
-                self * Self::splat(<$type>::to_radians(1.))
-            }
-
-            /// Returns true for each lane if it has a positive sign, including
-            /// `+0.0`, `NaN`s with positive sign bit and positive infinity.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_sign_positive(self) -> Mask<$mask_ty, LANES> {
-                !self.is_sign_negative()
-            }
-
-            /// Returns true for each lane if it has a negative sign, including
-            /// `-0.0`, `NaN`s with negative sign bit and negative infinity.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_sign_negative(self) -> Mask<$mask_ty, LANES> {
-                let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1);
-                sign_bits.lanes_gt(Simd::splat(0))
-            }
-
-            /// Returns true for each lane if its value is `NaN`.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_nan(self) -> Mask<$mask_ty, LANES> {
-                self.lanes_ne(self)
-            }
-
-            /// Returns true for each lane if its value is positive infinity or negative infinity.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_infinite(self) -> Mask<$mask_ty, LANES> {
-                self.abs().lanes_eq(Self::splat(<$type>::INFINITY))
-            }
-
-            /// Returns true for each lane if its value is neither infinite nor `NaN`.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_finite(self) -> Mask<$mask_ty, LANES> {
-                self.abs().lanes_lt(Self::splat(<$type>::INFINITY))
-            }
-
-            /// Returns true for each lane if its value is subnormal.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_subnormal(self) -> Mask<$mask_ty, LANES> {
-                self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(Simd::splat(0))
-            }
-
-            /// Returns true for each lane if its value is neither zero, infinite,
-            /// subnormal, nor `NaN`.
-            #[inline]
-            #[must_use = "method returns a new mask and does not mutate the original value"]
-            pub fn is_normal(self) -> Mask<$mask_ty, LANES> {
-                !(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
-            }
-
-            /// Replaces each lane with a number that represents its sign.
-            ///
-            /// * `1.0` if the number is positive, `+0.0`, or `INFINITY`
-            /// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY`
-            /// * `NAN` if the number is `NAN`
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn signum(self) -> Self {
-                self.is_nan().select(Self::splat(<$type>::NAN), Self::splat(1.0).copysign(self))
-            }
-
-            /// Returns each lane with the magnitude of `self` and the sign of `sign`.
-            ///
-            /// If any lane is a `NAN`, then a `NAN` with the sign of `sign` is returned.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn copysign(self, sign: Self) -> Self {
-                let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits();
-                let magnitude = self.to_bits() & !Self::splat(-0.).to_bits();
-                Self::from_bits(sign_bit | magnitude)
-            }
-
-            /// Returns the minimum of each lane.
-            ///
-            /// If one of the values is `NAN`, then the other value is returned.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn min(self, other: Self) -> Self {
-                unsafe { intrinsics::simd_fmin(self, other) }
-            }
-
-            /// Returns the maximum of each lane.
-            ///
-            /// If one of the values is `NAN`, then the other value is returned.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn max(self, other: Self) -> Self {
-                unsafe { intrinsics::simd_fmax(self, other) }
-            }
-
-            /// Restrict each lane to a certain interval unless it is NaN.
-            ///
-            /// For each lane in `self`, returns the corresponding lane in `max` if the lane is
-            /// greater than `max`, and the corresponding lane in `min` if the lane is less
-            /// than `min`.  Otherwise returns the lane in `self`.
-            #[inline]
-            #[must_use = "method returns a new vector and does not mutate the original value"]
-            pub fn clamp(self, min: Self, max: Self) -> Self {
-                assert!(
-                    min.lanes_le(max).all(),
-                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
-                );
-                let mut x = self;
-                x = x.lanes_lt(min).select(min, x);
-                x = x.lanes_gt(max).select(max, x);
-                x
-            }
-        }
-    };
-}
-
-impl_float_vector! { f32, u32, i32 }
-impl_float_vector! { f64, u64, i64 }
-
-/// Vector of two `f32` values
+/// A 64-bit SIMD vector with two elements of type `f32`.
 pub type f32x2 = Simd<f32, 2>;
 
-/// Vector of four `f32` values
+/// A 128-bit SIMD vector with four elements of type `f32`.
 pub type f32x4 = Simd<f32, 4>;
 
-/// Vector of eight `f32` values
+/// A 256-bit SIMD vector with eight elements of type `f32`.
 pub type f32x8 = Simd<f32, 8>;
 
-/// Vector of 16 `f32` values
+/// A 512-bit SIMD vector with 16 elements of type `f32`.
 pub type f32x16 = Simd<f32, 16>;
 
-/// Vector of two `f64` values
+/// A 128-bit SIMD vector with two elements of type `f64`.
 pub type f64x2 = Simd<f64, 2>;
 
-/// Vector of four `f64` values
+/// A 256-bit SIMD vector with four elements of type `f64`.
 pub type f64x4 = Simd<f64, 4>;
 
-/// Vector of eight `f64` values
+/// A 512-bit SIMD vector with eight elements of type `f64`.
 pub type f64x8 = Simd<f64, 8>;
diff --git a/library/portable-simd/crates/core_simd/src/vector/int.rs b/library/portable-simd/crates/core_simd/src/vector/int.rs
index 3eac02a2761..20e56c7dc64 100644
--- a/library/portable-simd/crates/core_simd/src/vector/int.rs
+++ b/library/portable-simd/crates/core_simd/src/vector/int.rs
@@ -1,103 +1,63 @@
 #![allow(non_camel_case_types)]
 
-use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount};
-
-/// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`.
-macro_rules! impl_integer_vector {
-    { $type:ty } => {
-        impl<const LANES: usize> Simd<$type, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-        {
-            /// Returns true for each positive lane and false if it is zero or negative.
-            #[inline]
-            pub fn is_positive(self) -> Mask<$type, LANES> {
-                self.lanes_gt(Self::splat(0))
-            }
-
-            /// Returns true for each negative lane and false if it is zero or positive.
-            #[inline]
-            pub fn is_negative(self) -> Mask<$type, LANES> {
-                self.lanes_lt(Self::splat(0))
-            }
-
-            /// Returns numbers representing the sign of each lane.
-            /// * `0` if the number is zero
-            /// * `1` if the number is positive
-            /// * `-1` if the number is negative
-            #[inline]
-            pub fn signum(self) -> Self {
-                self.is_positive().select(
-                    Self::splat(1),
-                    self.is_negative().select(Self::splat(-1), Self::splat(0))
-                )
-            }
-        }
-    }
-}
-
-impl_integer_vector! { isize }
-impl_integer_vector! { i16 }
-impl_integer_vector! { i32 }
-impl_integer_vector! { i64 }
-impl_integer_vector! { i8 }
-
-/// Vector of two `isize` values
+use crate::simd::Simd;
+
+/// A SIMD vector with two elements of type `isize`.
 pub type isizex2 = Simd<isize, 2>;
 
-/// Vector of four `isize` values
+/// A SIMD vector with four elements of type `isize`.
 pub type isizex4 = Simd<isize, 4>;
 
-/// Vector of eight `isize` values
+/// A SIMD vector with eight elements of type `isize`.
 pub type isizex8 = Simd<isize, 8>;
 
-/// Vector of two `i16` values
+/// A 32-bit SIMD vector with two elements of type `i16`.
 pub type i16x2 = Simd<i16, 2>;
 
-/// Vector of four `i16` values
+/// A 64-bit SIMD vector with four elements of type `i16`.
 pub type i16x4 = Simd<i16, 4>;
 
-/// Vector of eight `i16` values
+/// A 128-bit SIMD vector with eight elements of type `i16`.
 pub type i16x8 = Simd<i16, 8>;
 
-/// Vector of 16 `i16` values
+/// A 256-bit SIMD vector with 16 elements of type `i16`.
 pub type i16x16 = Simd<i16, 16>;
 
-/// Vector of 32 `i16` values
+/// A 512-bit SIMD vector with 32 elements of type `i16`.
 pub type i16x32 = Simd<i16, 32>;
 
-/// Vector of two `i32` values
+/// A 64-bit SIMD vector with two elements of type `i32`.
 pub type i32x2 = Simd<i32, 2>;
 
-/// Vector of four `i32` values
+/// A 128-bit SIMD vector with four elements of type `i32`.
 pub type i32x4 = Simd<i32, 4>;
 
-/// Vector of eight `i32` values
+/// A 256-bit SIMD vector with eight elements of type `i32`.
 pub type i32x8 = Simd<i32, 8>;
 
-/// Vector of 16 `i32` values
+/// A 512-bit SIMD vector with 16 elements of type `i32`.
 pub type i32x16 = Simd<i32, 16>;
 
-/// Vector of two `i64` values
+/// A 128-bit SIMD vector with two elements of type `i64`.
 pub type i64x2 = Simd<i64, 2>;
 
-/// Vector of four `i64` values
+/// A 256-bit SIMD vector with four elements of type `i64`.
 pub type i64x4 = Simd<i64, 4>;
 
-/// Vector of eight `i64` values
+/// A 512-bit SIMD vector with eight elements of type `i64`.
 pub type i64x8 = Simd<i64, 8>;
 
-/// Vector of four `i8` values
+/// A 32-bit SIMD vector with four elements of type `i8`.
 pub type i8x4 = Simd<i8, 4>;
 
-/// Vector of eight `i8` values
+/// A 64-bit SIMD vector with eight elements of type `i8`.
 pub type i8x8 = Simd<i8, 8>;
 
-/// Vector of 16 `i8` values
+/// A 128-bit SIMD vector with 16 elements of type `i8`.
 pub type i8x16 = Simd<i8, 16>;
 
-/// Vector of 32 `i8` values
+/// A 256-bit SIMD vector with 32 elements of type `i8`.
 pub type i8x32 = Simd<i8, 32>;
 
-/// Vector of 64 `i8` values
+/// A 512-bit SIMD vector with 64 elements of type `i8`.
 pub type i8x64 = Simd<i8, 64>;
diff --git a/library/portable-simd/crates/core_simd/src/vector/uint.rs b/library/portable-simd/crates/core_simd/src/vector/uint.rs
index ed91fc3640e..b4a69c44363 100644
--- a/library/portable-simd/crates/core_simd/src/vector/uint.rs
+++ b/library/portable-simd/crates/core_simd/src/vector/uint.rs
@@ -2,62 +2,62 @@
 
 use crate::simd::Simd;
 
-/// Vector of two `usize` values
+/// A SIMD vector with two elements of type `usize`.
 pub type usizex2 = Simd<usize, 2>;
 
-/// Vector of four `usize` values
+/// A SIMD vector with four elements of type `usize`.
 pub type usizex4 = Simd<usize, 4>;
 
-/// Vector of eight `usize` values
+/// A SIMD vector with eight elements of type `usize`.
 pub type usizex8 = Simd<usize, 8>;
 
-/// Vector of two `u16` values
+/// A 32-bit SIMD vector with two elements of type `u16`.
 pub type u16x2 = Simd<u16, 2>;
 
-/// Vector of four `u16` values
+/// A 64-bit SIMD vector with four elements of type `u16`.
 pub type u16x4 = Simd<u16, 4>;
 
-/// Vector of eight `u16` values
+/// A 128-bit SIMD vector with eight elements of type `u16`.
 pub type u16x8 = Simd<u16, 8>;
 
-/// Vector of 16 `u16` values
+/// A 256-bit SIMD vector with 16 elements of type `u16`.
 pub type u16x16 = Simd<u16, 16>;
 
-/// Vector of 32 `u16` values
+/// A 512-bit SIMD vector with 32 elements of type `u16`.
 pub type u16x32 = Simd<u16, 32>;
 
-/// Vector of two `u32` values
+/// A 64-bit SIMD vector with two elements of type `u32`.
 pub type u32x2 = Simd<u32, 2>;
 
-/// Vector of four `u32` values
+/// A 128-bit SIMD vector with four elements of type `u32`.
 pub type u32x4 = Simd<u32, 4>;
 
-/// Vector of eight `u32` values
+/// A 256-bit SIMD vector with eight elements of type `u32`.
 pub type u32x8 = Simd<u32, 8>;
 
-/// Vector of 16 `u32` values
+/// A 512-bit SIMD vector with 16 elements of type `u32`.
 pub type u32x16 = Simd<u32, 16>;
 
-/// Vector of two `u64` values
+/// A 128-bit SIMD vector with two elements of type `u64`.
 pub type u64x2 = Simd<u64, 2>;
 
-/// Vector of four `u64` values
+/// A 256-bit SIMD vector with four elements of type `u64`.
 pub type u64x4 = Simd<u64, 4>;
 
-/// Vector of eight `u64` values
+/// A 512-bit SIMD vector with eight elements of type `u64`.
 pub type u64x8 = Simd<u64, 8>;
 
-/// Vector of four `u8` values
+/// A 32-bit SIMD vector with four elements of type `u8`.
 pub type u8x4 = Simd<u8, 4>;
 
-/// Vector of eight `u8` values
+/// A 64-bit SIMD vector with eight elements of type `u8`.
 pub type u8x8 = Simd<u8, 8>;
 
-/// Vector of 16 `u8` values
+/// A 128-bit SIMD vector with 16 elements of type `u8`.
 pub type u8x16 = Simd<u8, 16>;
 
-/// Vector of 32 `u8` values
+/// A 256-bit SIMD vector with 32 elements of type `u8`.
 pub type u8x32 = Simd<u8, 32>;
 
-/// Vector of 64 `u8` values
+/// A 512-bit SIMD vector with 64 elements of type `u8`.
 pub type u8x64 = Simd<u8, 64>;
diff --git a/library/portable-simd/crates/core_simd/tests/i16_ops.rs b/library/portable-simd/crates/core_simd/tests/i16_ops.rs
index 171e5b472fa..f6c5d74fbbc 100644
--- a/library/portable-simd/crates/core_simd/tests/i16_ops.rs
+++ b/library/portable-simd/crates/core_simd/tests/i16_ops.rs
@@ -1,32 +1,5 @@
 #![feature(portable_simd)]
-use core_simd::i16x2;
 
 #[macro_use]
 mod ops_macros;
 impl_signed_tests! { i16 }
-
-#[test]
-fn max_is_not_lexicographic() {
-    let a = i16x2::splat(10);
-    let b = i16x2::from_array([-4, 12]);
-    assert_eq!(a.max(b), i16x2::from_array([10, 12]));
-}
-
-#[test]
-fn min_is_not_lexicographic() {
-    let a = i16x2::splat(10);
-    let b = i16x2::from_array([12, -4]);
-    assert_eq!(a.min(b), i16x2::from_array([10, -4]));
-}
-
-#[test]
-fn clamp_is_not_lexicographic() {
-    let a = i16x2::splat(10);
-    let lo = i16x2::from_array([-12, -4]);
-    let up = i16x2::from_array([-4, 12]);
-    assert_eq!(a.clamp(lo, up), i16x2::from_array([-4, 10]));
-
-    let x = i16x2::from_array([1, 10]);
-    let y = x.clamp(i16x2::splat(0), i16x2::splat(9));
-    assert_eq!(y, i16x2::from_array([1, 9]));
-}
diff --git a/library/portable-simd/crates/core_simd/tests/masks.rs b/library/portable-simd/crates/core_simd/tests/masks.rs
index 3aec36ca7b7..673d0db93fe 100644
--- a/library/portable-simd/crates/core_simd/tests/masks.rs
+++ b/library/portable-simd/crates/core_simd/tests/masks.rs
@@ -80,6 +80,62 @@ macro_rules! test_mask_api {
                 assert_eq!(bitmask, 0b1000001101001001);
                 assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
             }
+
+            #[test]
+            fn roundtrip_bitmask_conversion_short() {
+                use core_simd::ToBitMask;
+
+                let values = [
+                    false, false, false, true,
+                ];
+                let mask = core_simd::Mask::<$type, 4>::from_array(values);
+                let bitmask = mask.to_bitmask();
+                assert_eq!(bitmask, 0b1000);
+                assert_eq!(core_simd::Mask::<$type, 4>::from_bitmask(bitmask), mask);
+
+                let values = [true, false];
+                let mask = core_simd::Mask::<$type, 2>::from_array(values);
+                let bitmask = mask.to_bitmask();
+                assert_eq!(bitmask, 0b01);
+                assert_eq!(core_simd::Mask::<$type, 2>::from_bitmask(bitmask), mask);
+            }
+
+            #[test]
+            fn cast() {
+                fn cast_impl<T: core_simd::MaskElement>()
+                where
+                    core_simd::Mask<$type, 8>: Into<core_simd::Mask<T, 8>>,
+                {
+                    let values = [true, false, false, true, false, false, true, false];
+                    let mask = core_simd::Mask::<$type, 8>::from_array(values);
+
+                    let cast_mask = mask.cast::<T>();
+                    assert_eq!(values, cast_mask.to_array());
+
+                    let into_mask: core_simd::Mask<T, 8> = mask.into();
+                    assert_eq!(values, into_mask.to_array());
+                }
+
+                cast_impl::<i8>();
+                cast_impl::<i16>();
+                cast_impl::<i32>();
+                cast_impl::<i64>();
+                cast_impl::<isize>();
+            }
+
+            #[cfg(feature = "generic_const_exprs")]
+            #[test]
+            fn roundtrip_bitmask_array_conversion() {
+                use core_simd::ToBitMaskArray;
+                let values = [
+                    true, false, false, true, false, false, true, false,
+                    true, true, false, false, false, false, false, true,
+                ];
+                let mask = core_simd::Mask::<$type, 16>::from_array(values);
+                let bitmask = mask.to_bitmask_array();
+                assert_eq!(bitmask, [0b01001001, 0b10000011]);
+                assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask_array(bitmask), mask);
+            }
         }
     }
 }
diff --git a/library/portable-simd/crates/core_simd/tests/ops_macros.rs b/library/portable-simd/crates/core_simd/tests/ops_macros.rs
index 7c9b17673ef..f759394d075 100644
--- a/library/portable-simd/crates/core_simd/tests/ops_macros.rs
+++ b/library/portable-simd/crates/core_simd/tests/ops_macros.rs
@@ -172,6 +172,7 @@ macro_rules! impl_common_integer_tests {
 macro_rules! impl_signed_tests {
     { $scalar:tt } => {
         mod $scalar {
+            use core_simd::simd::SimdInt;
             type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
             type Scalar = $scalar;
 
@@ -222,34 +223,37 @@ macro_rules! impl_signed_tests {
                     assert_eq!(a % b, Vector::<LANES>::splat(0));
                 }
 
-                fn min<const LANES: usize>() {
+                fn simd_min<const LANES: usize>() {
+                    use core_simd::simd::SimdOrd;
                     let a = Vector::<LANES>::splat(Scalar::MIN);
                     let b = Vector::<LANES>::splat(0);
-                    assert_eq!(a.min(b), a);
+                    assert_eq!(a.simd_min(b), a);
                     let a = Vector::<LANES>::splat(Scalar::MAX);
                     let b = Vector::<LANES>::splat(0);
-                    assert_eq!(a.min(b), b);
+                    assert_eq!(a.simd_min(b), b);
                 }
 
-                fn max<const LANES: usize>() {
+                fn simd_max<const LANES: usize>() {
+                    use core_simd::simd::SimdOrd;
                     let a = Vector::<LANES>::splat(Scalar::MIN);
                     let b = Vector::<LANES>::splat(0);
-                    assert_eq!(a.max(b), b);
+                    assert_eq!(a.simd_max(b), b);
                     let a = Vector::<LANES>::splat(Scalar::MAX);
                     let b = Vector::<LANES>::splat(0);
-                    assert_eq!(a.max(b), a);
+                    assert_eq!(a.simd_max(b), a);
                 }
 
-                fn clamp<const LANES: usize>() {
+                fn simd_clamp<const LANES: usize>() {
+                    use core_simd::simd::SimdOrd;
                     let min = Vector::<LANES>::splat(Scalar::MIN);
                     let max = Vector::<LANES>::splat(Scalar::MAX);
                     let zero = Vector::<LANES>::splat(0);
                     let one = Vector::<LANES>::splat(1);
                     let negone = Vector::<LANES>::splat(-1);
-                    assert_eq!(zero.clamp(min, max), zero);
-                    assert_eq!(zero.clamp(min, one), zero);
-                    assert_eq!(zero.clamp(one, max), one);
-                    assert_eq!(zero.clamp(min, negone), negone);
+                    assert_eq!(zero.simd_clamp(min, max), zero);
+                    assert_eq!(zero.simd_clamp(min, one), zero);
+                    assert_eq!(zero.simd_clamp(one, max), one);
+                    assert_eq!(zero.simd_clamp(min, negone), negone);
                 }
             }
 
@@ -309,6 +313,7 @@ macro_rules! impl_signed_tests {
 macro_rules! impl_unsigned_tests {
     { $scalar:tt } => {
         mod $scalar {
+            use core_simd::simd::SimdUint;
             type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
             type Scalar = $scalar;
 
@@ -343,6 +348,7 @@ macro_rules! impl_unsigned_tests {
 macro_rules! impl_float_tests {
     { $scalar:tt, $int_scalar:tt } => {
         mod $scalar {
+            use core_simd::SimdFloat;
             type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
             type Scalar = $scalar;
 
@@ -458,10 +464,10 @@ macro_rules! impl_float_tests {
                     )
                 }
 
-                fn min<const LANES: usize>() {
+                fn simd_min<const LANES: usize>() {
                     // Regular conditions (both values aren't zero)
                     test_helpers::test_binary_elementwise(
-                        &Vector::<LANES>::min,
+                        &Vector::<LANES>::simd_min,
                         &Scalar::min,
                         // Reject the case where both values are zero with different signs
                         &|a, b| {
@@ -477,14 +483,14 @@ macro_rules! impl_float_tests {
                     // Special case where both values are zero
                     let p_zero = Vector::<LANES>::splat(0.);
                     let n_zero = Vector::<LANES>::splat(-0.);
-                    assert!(p_zero.min(n_zero).to_array().iter().all(|x| *x == 0.));
-                    assert!(n_zero.min(p_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(p_zero.simd_min(n_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(n_zero.simd_min(p_zero).to_array().iter().all(|x| *x == 0.));
                 }
 
-                fn max<const LANES: usize>() {
+                fn simd_max<const LANES: usize>() {
                     // Regular conditions (both values aren't zero)
                     test_helpers::test_binary_elementwise(
-                        &Vector::<LANES>::max,
+                        &Vector::<LANES>::simd_max,
                         &Scalar::max,
                         // Reject the case where both values are zero with different signs
                         &|a, b| {
@@ -500,11 +506,11 @@ macro_rules! impl_float_tests {
                     // Special case where both values are zero
                     let p_zero = Vector::<LANES>::splat(0.);
                     let n_zero = Vector::<LANES>::splat(-0.);
-                    assert!(p_zero.max(n_zero).to_array().iter().all(|x| *x == 0.));
-                    assert!(n_zero.max(p_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(p_zero.simd_max(n_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(n_zero.simd_max(p_zero).to_array().iter().all(|x| *x == 0.));
                 }
 
-                fn clamp<const LANES: usize>() {
+                fn simd_clamp<const LANES: usize>() {
                     test_helpers::test_3(&|value: [Scalar; LANES], mut min: [Scalar; LANES], mut max: [Scalar; LANES]| {
                         for (min, max) in min.iter_mut().zip(max.iter_mut()) {
                             if max < min {
@@ -522,7 +528,7 @@ macro_rules! impl_float_tests {
                         for i in 0..LANES {
                             result_scalar[i] = value[i].clamp(min[i], max[i]);
                         }
-                        let result_vector = Vector::from_array(value).clamp(min.into(), max.into()).to_array();
+                        let result_vector = Vector::from_array(value).simd_clamp(min.into(), max.into()).to_array();
                         test_helpers::prop_assert_biteq!(result_scalar, result_vector);
                         Ok(())
                     })
diff --git a/library/portable-simd/crates/core_simd/tests/round.rs b/library/portable-simd/crates/core_simd/tests/round.rs
index 7feb0320a16..484fd5bf47d 100644
--- a/library/portable-simd/crates/core_simd/tests/round.rs
+++ b/library/portable-simd/crates/core_simd/tests/round.rs
@@ -59,7 +59,7 @@ macro_rules! float_rounding_test {
                     const MAX_REPRESENTABLE_VALUE: Scalar =
                         (ALL_MANTISSA_BITS << (core::mem::size_of::<Scalar>() * 8 - <Scalar>::MANTISSA_DIGITS as usize - 1)) as Scalar;
 
-                    let mut runner = proptest::test_runner::TestRunner::default();
+                    let mut runner = test_helpers::make_runner();
                     runner.run(
                         &test_helpers::array::UniformArrayStrategy::new(-MAX_REPRESENTABLE_VALUE..MAX_REPRESENTABLE_VALUE),
                         |x| {
diff --git a/library/portable-simd/crates/test_helpers/src/lib.rs b/library/portable-simd/crates/test_helpers/src/lib.rs
index 8bf7f5ed3d2..141bee18a9a 100644
--- a/library/portable-simd/crates/test_helpers/src/lib.rs
+++ b/library/portable-simd/crates/test_helpers/src/lib.rs
@@ -78,11 +78,11 @@ impl<T: core::fmt::Debug + DefaultStrategy, const LANES: usize> DefaultStrategy
 }
 
 #[cfg(not(miri))]
-fn make_runner() -> proptest::test_runner::TestRunner {
+pub fn make_runner() -> proptest::test_runner::TestRunner {
     Default::default()
 }
 #[cfg(miri)]
-fn make_runner() -> proptest::test_runner::TestRunner {
+pub fn make_runner() -> proptest::test_runner::TestRunner {
     // Only run a few tests on Miri
     proptest::test_runner::TestRunner::new(proptest::test_runner::Config::with_cases(4))
 }
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 5cf16bdd08c..08b45ac11a1 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -1484,7 +1484,7 @@ impl fmt::Debug for Literal {
 }
 
 /// Tracked access to environment variables.
-#[unstable(feature = "proc_macro_tracked_env", issue = "74690")]
+#[unstable(feature = "proc_macro_tracked_env", issue = "99515")]
 pub mod tracked_env {
     use std::env::{self, VarError};
     use std::ffi::OsStr;
@@ -1494,7 +1494,7 @@ pub mod tracked_env {
     /// compilation, and will be able to rerun the build when the value of that variable changes.
     /// Besides the dependency tracking this function should be equivalent to `env::var` from the
     /// standard library, except that the argument must be UTF-8.
-    #[unstable(feature = "proc_macro_tracked_env", issue = "74690")]
+    #[unstable(feature = "proc_macro_tracked_env", issue = "99515")]
     pub fn var<K: AsRef<OsStr> + AsRef<str>>(key: K) -> Result<String, VarError> {
         let key: &str = key.as_ref();
         let value = env::var(key);
@@ -1504,13 +1504,13 @@ pub mod tracked_env {
 }
 
 /// Tracked access to additional files.
-#[unstable(feature = "track_path", issue = "73921")]
+#[unstable(feature = "track_path", issue = "99515")]
 pub mod tracked_path {
 
     /// Track a file explicitly.
     ///
     /// Commonly used for tracking asset preprocessing.
-    #[unstable(feature = "track_path", issue = "73921")]
+    #[unstable(feature = "track_path", issue = "99515")]
     pub fn path<P: AsRef<str>>(path: P) {
         let path: &str = path.as_ref();
         crate::bridge::client::FreeFunctions::track_path(path);
diff --git a/library/std/build.rs b/library/std/build.rs
index bffbe802fd0..8b1a06ee750 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -15,6 +15,7 @@ fn main() {
         || target.contains("illumos")
         || target.contains("apple-darwin")
         || target.contains("apple-ios")
+        || target.contains("apple-watchos")
         || target.contains("uwp")
         || target.contains("windows")
         || target.contains("fuchsia")
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 9fd426d3ac4..6b0c0ad7c21 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -276,6 +276,7 @@
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
+#![feature(is_some_with)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(mixed_integer_ops)]
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index d661a13edc5..a463bc41db7 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -356,7 +356,7 @@ impl From<OwnedFd> for crate::net::UdpSocket {
     }
 }
 
-#[stable(feature = "io_safety", since = "1.63.0")]
+#[stable(feature = "asfd_ptrs", since = "1.64.0")]
 /// This impl allows implementing traits that require `AsFd` on Arc.
 /// ```
 /// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
@@ -379,7 +379,7 @@ impl<T: AsFd> AsFd for crate::sync::Arc<T> {
     }
 }
 
-#[stable(feature = "io_safety", since = "1.63.0")]
+#[stable(feature = "asfd_ptrs", since = "1.64.0")]
 impl<T: AsFd> AsFd for Box<T> {
     #[inline]
     fn as_fd(&self) -> BorrowedFd<'_> {
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index a1df72a8a04..6fbaa42c768 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -141,7 +141,6 @@ pub mod openbsd;
 pub mod redox;
 #[cfg(target_os = "solaris")]
 pub mod solaris;
-
 #[cfg(target_os = "solid_asp3")]
 pub mod solid;
 #[cfg(target_os = "vxworks")]
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index cef546487f3..411cc0925c4 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -90,6 +90,7 @@ pub mod thread;
     target_os = "dragonfly",
     target_os = "freebsd",
     target_os = "ios",
+    target_os = "watchos",
     target_os = "macos",
     target_os = "netbsd",
     target_os = "openbsd"
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 1d6083e66e1..cc3a8858793 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -12,6 +12,7 @@ use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Owned
     target_os = "freebsd",
     target_os = "ios",
     target_os = "macos",
+    target_os = "watchos",
     target_os = "netbsd",
     target_os = "openbsd"
 ))]
@@ -30,6 +31,7 @@ use crate::time::Duration;
     target_os = "freebsd",
     target_os = "ios",
     target_os = "macos",
+    target_os = "watchos",
     target_os = "netbsd",
     target_os = "openbsd"
 ))]
@@ -238,6 +240,7 @@ impl UnixStream {
         target_os = "freebsd",
         target_os = "ios",
         target_os = "macos",
+        target_os = "watchos",
         target_os = "netbsd",
         target_os = "openbsd"
     ))]
diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs
index 32e6430d3f6..ae4faf27b4d 100644
--- a/library/std/src/os/unix/ucred.rs
+++ b/library/std/src/os/unix/ucred.rs
@@ -36,7 +36,7 @@ pub use self::impl_linux::peer_cred;
 ))]
 pub use self::impl_bsd::peer_cred;
 
-#[cfg(any(target_os = "macos", target_os = "ios",))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
 pub use self::impl_mac::peer_cred;
 
 #[cfg(any(target_os = "linux", target_os = "android"))]
@@ -97,7 +97,7 @@ pub mod impl_bsd {
     }
 }
 
-#[cfg(any(target_os = "macos", target_os = "ios",))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
 pub mod impl_mac {
     use super::UCred;
     use crate::os::unix::io::AsRawFd;
diff --git a/library/std/src/os/unix/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs
index 42d79418cf7..e63a2fc248e 100644
--- a/library/std/src/os/unix/ucred/tests.rs
+++ b/library/std/src/os/unix/ucred/tests.rs
@@ -9,6 +9,7 @@ use libc::{getegid, geteuid, getpid};
     target_os = "freebsd",
     target_os = "ios",
     target_os = "macos",
+    target_os = "watchos",
     target_os = "openbsd"
 ))]
 fn test_socket_pair() {
@@ -25,7 +26,7 @@ fn test_socket_pair() {
 }
 
 #[test]
-#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))]
+#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))]
 fn test_socket_pair_pids(arg: Type) -> RetType {
     // Create two connected sockets and get their peer credentials.
     let (sock_a, sock_b) = UnixStream::pair().unwrap();
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index 79964e2b238..a342f0f5e85 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -151,7 +151,7 @@ mod imp {
     }
 }
 
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
 mod imp {
     use super::Args;
     use crate::ffi::CStr;
@@ -192,7 +192,7 @@ mod imp {
     // for i in (0..[args count])
     //      res.push([args objectAtIndex:i])
     // res
-    #[cfg(target_os = "ios")]
+    #[cfg(any(target_os = "ios", target_os = "watchos"))]
     pub fn args() -> Args {
         use crate::ffi::OsString;
         use crate::mem;
diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs
index 4d8391656a4..c9ba661c829 100644
--- a/library/std/src/sys/unix/env.rs
+++ b/library/std/src/sys/unix/env.rs
@@ -31,6 +31,17 @@ pub mod os {
     pub const EXE_EXTENSION: &str = "";
 }
 
+#[cfg(target_os = "watchos")]
+pub mod os {
+    pub const FAMILY: &str = "unix";
+    pub const OS: &str = "watchos";
+    pub const DLL_PREFIX: &str = "lib";
+    pub const DLL_SUFFIX: &str = ".dylib";
+    pub const DLL_EXTENSION: &str = "dylib";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
+
 #[cfg(target_os = "freebsd")]
 pub mod os {
     pub const FAMILY: &str = "unix";
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 137ca3a7633..30812dabb4e 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -47,6 +47,7 @@ const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
     target_os = "macos",
     target_os = "netbsd",
     target_os = "openbsd",
+    target_os = "watchos",
 ))]
 const fn max_iov() -> usize {
     libc::IOV_MAX as usize
@@ -67,7 +68,8 @@ const fn max_iov() -> usize {
     target_os = "macos",
     target_os = "netbsd",
     target_os = "openbsd",
-    target_os = "horizon"
+    target_os = "horizon",
+    target_os = "watchos",
 )))]
 const fn max_iov() -> usize {
     16 // The minimum value required by POSIX.
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 8b0bbd6a55c..7c882469440 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -17,6 +17,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
     all(target_os = "linux", target_env = "gnu"),
     target_os = "macos",
     target_os = "ios",
+    target_os = "watchos",
 ))]
 use crate::sys::weak::syscall;
 #[cfg(target_os = "macos")]
@@ -27,6 +28,7 @@ use libc::{c_int, mode_t};
 #[cfg(any(
     target_os = "macos",
     target_os = "ios",
+    target_os = "watchos",
     all(target_os = "linux", target_env = "gnu")
 ))]
 use libc::c_char;
@@ -443,7 +445,8 @@ impl FileAttr {
         target_os = "freebsd",
         target_os = "openbsd",
         target_os = "macos",
-        target_os = "ios"
+        target_os = "ios",
+        target_os = "watchos",
     ))]
     pub fn created(&self) -> io::Result<SystemTime> {
         Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64))
@@ -453,7 +456,8 @@ impl FileAttr {
         target_os = "freebsd",
         target_os = "openbsd",
         target_os = "macos",
-        target_os = "ios"
+        target_os = "ios",
+        target_os = "watchos",
     )))]
     pub fn created(&self) -> io::Result<SystemTime> {
         cfg_has_statx! {
@@ -707,6 +711,7 @@ impl DirEntry {
     #[cfg(any(
         target_os = "macos",
         target_os = "ios",
+        target_os = "watchos",
         target_os = "linux",
         target_os = "emscripten",
         target_os = "android",
@@ -737,6 +742,7 @@ impl DirEntry {
     #[cfg(any(
         target_os = "macos",
         target_os = "ios",
+        target_os = "watchos",
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "freebsd",
@@ -754,6 +760,7 @@ impl DirEntry {
     #[cfg(not(any(
         target_os = "macos",
         target_os = "ios",
+        target_os = "watchos",
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "freebsd",
@@ -911,11 +918,11 @@ impl File {
         cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?;
         return Ok(());
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
         unsafe fn os_fsync(fd: c_int) -> c_int {
             libc::fcntl(fd, libc::F_FULLFSYNC)
         }
-        #[cfg(not(any(target_os = "macos", target_os = "ios")))]
+        #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))]
         unsafe fn os_fsync(fd: c_int) -> c_int {
             libc::fsync(fd)
         }
@@ -925,7 +932,7 @@ impl File {
         cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?;
         return Ok(());
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
         unsafe fn os_datasync(fd: c_int) -> c_int {
             libc::fcntl(fd, libc::F_FULLFSYNC)
         }
@@ -946,7 +953,8 @@ impl File {
             target_os = "linux",
             target_os = "macos",
             target_os = "netbsd",
-            target_os = "openbsd"
+            target_os = "openbsd",
+            target_os = "watchos",
         )))]
         unsafe fn os_datasync(fd: c_int) -> c_int {
             libc::fsync(fd)
@@ -1396,7 +1404,8 @@ fn open_to_and_set_permissions(
     target_os = "linux",
     target_os = "android",
     target_os = "macos",
-    target_os = "ios"
+    target_os = "ios",
+    target_os = "watchos",
 )))]
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     let (mut reader, reader_metadata) = open_from(from)?;
@@ -1423,7 +1432,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     }
 }
 
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     use crate::sync::atomic::{AtomicBool, Ordering};
 
diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs
index ab516a7f76d..8d5b540212a 100644
--- a/library/std/src/sys/unix/futex.rs
+++ b/library/std/src/sys/unix/futex.rs
@@ -240,17 +240,25 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 }
 
 #[cfg(target_os = "fuchsia")]
-mod zircon {
-    type zx_time_t = i64;
-    type zx_futex_t = crate::sync::atomic::AtomicU32;
-    type zx_handle_t = u32;
-    type zx_status_t = i32;
+pub mod zircon {
+    pub type zx_futex_t = crate::sync::atomic::AtomicU32;
+    pub type zx_handle_t = u32;
+    pub type zx_status_t = i32;
+    pub type zx_time_t = i64;
 
     pub const ZX_HANDLE_INVALID: zx_handle_t = 0;
-    pub const ZX_ERR_TIMED_OUT: zx_status_t = -21;
+
     pub const ZX_TIME_INFINITE: zx_time_t = zx_time_t::MAX;
 
+    pub const ZX_OK: zx_status_t = 0;
+    pub const ZX_ERR_INVALID_ARGS: zx_status_t = -10;
+    pub const ZX_ERR_BAD_HANDLE: zx_status_t = -11;
+    pub const ZX_ERR_WRONG_TYPE: zx_status_t = -12;
+    pub const ZX_ERR_BAD_STATE: zx_status_t = -20;
+    pub const ZX_ERR_TIMED_OUT: zx_status_t = -21;
+
     extern "C" {
+        pub fn zx_clock_get_monotonic() -> zx_time_t;
         pub fn zx_futex_wait(
             value_ptr: *const zx_futex_t,
             current_value: zx_futex_t,
@@ -258,7 +266,8 @@ mod zircon {
             deadline: zx_time_t,
         ) -> zx_status_t;
         pub fn zx_futex_wake(value_ptr: *const zx_futex_t, wake_count: u32) -> zx_status_t;
-        pub fn zx_clock_get_monotonic() -> zx_time_t;
+        pub fn zx_futex_wake_single_owner(value_ptr: *const zx_futex_t) -> zx_status_t;
+        pub fn zx_thread_self() -> zx_handle_t;
     }
 }
 
@@ -287,3 +296,8 @@ pub fn futex_wake(futex: &AtomicU32) -> bool {
     unsafe { zircon::zx_futex_wake(futex, 1) };
     false
 }
+
+#[cfg(target_os = "fuchsia")]
+pub fn futex_wake_all(futex: &AtomicU32) {
+    unsafe { zircon::zx_futex_wake(futex, u32::MAX) };
+}
diff --git a/library/std/src/sys/unix/locks/fuchsia_mutex.rs b/library/std/src/sys/unix/locks/fuchsia_mutex.rs
new file mode 100644
index 00000000000..ce427599c3b
--- /dev/null
+++ b/library/std/src/sys/unix/locks/fuchsia_mutex.rs
@@ -0,0 +1,165 @@
+//! A priority inheriting mutex for Fuchsia.
+//!
+//! This is a port of the [mutex in Fuchsia's libsync]. Contrary to the original,
+//! it does not abort the process when reentrant locking is detected, but deadlocks.
+//!
+//! Priority inheritance is achieved by storing the owning thread's handle in an
+//! atomic variable. Fuchsia's futex operations support setting an owner thread
+//! for a futex, which can boost that thread's priority while the futex is waited
+//! upon.
+//!
+//! libsync is licenced under the following BSD-style licence:
+//!
+//! Copyright 2016 The Fuchsia Authors.
+//!
+//! Redistribution and use in source and binary forms, with or without
+//! modification, are permitted provided that the following conditions are
+//! met:
+//!
+//!    * Redistributions of source code must retain the above copyright
+//!      notice, this list of conditions and the following disclaimer.
+//!    * Redistributions in binary form must reproduce the above
+//!      copyright notice, this list of conditions and the following
+//!      disclaimer in the documentation and/or other materials provided
+//!      with the distribution.
+//!
+//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+//! A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+//! OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+//! LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+//! DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+//! THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//! (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+//! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//!
+//! [mutex in Fuchsia's libsync]: https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/system/ulib/sync/mutex.c
+
+use crate::sync::atomic::{
+    AtomicU32,
+    Ordering::{Acquire, Relaxed, Release},
+};
+use crate::sys::futex::zircon::{
+    zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t, zx_thread_self, ZX_ERR_BAD_HANDLE,
+    ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE, ZX_OK,
+    ZX_TIME_INFINITE,
+};
+
+// The lowest two bits of a `zx_handle_t` are always set, so the lowest bit is used to mark the
+// mutex as contested by clearing it.
+const CONTESTED_BIT: u32 = 1;
+// This can never be a valid `zx_handle_t`.
+const UNLOCKED: u32 = 0;
+
+pub type MovableMutex = Mutex;
+
+pub struct Mutex {
+    futex: AtomicU32,
+}
+
+#[inline]
+fn to_state(owner: zx_handle_t) -> u32 {
+    owner
+}
+
+#[inline]
+fn to_owner(state: u32) -> zx_handle_t {
+    state | CONTESTED_BIT
+}
+
+#[inline]
+fn is_contested(state: u32) -> bool {
+    state & CONTESTED_BIT == 0
+}
+
+#[inline]
+fn mark_contested(state: u32) -> u32 {
+    state & !CONTESTED_BIT
+}
+
+impl Mutex {
+    #[inline]
+    pub const fn new() -> Mutex {
+        Mutex { futex: AtomicU32::new(UNLOCKED) }
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {}
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        let thread_self = zx_thread_self();
+        self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed).is_ok()
+    }
+
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let thread_self = zx_thread_self();
+        if let Err(state) =
+            self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed)
+        {
+            self.lock_contested(state, thread_self);
+        }
+    }
+
+    #[cold]
+    fn lock_contested(&self, mut state: u32, thread_self: zx_handle_t) {
+        let owned_state = mark_contested(to_state(thread_self));
+        loop {
+            // Mark the mutex as contested if it is not already.
+            let contested = mark_contested(state);
+            if is_contested(state)
+                || self.futex.compare_exchange(state, contested, Relaxed, Relaxed).is_ok()
+            {
+                // The mutex has been marked as contested, wait for the state to change.
+                unsafe {
+                    match zx_futex_wait(
+                        &self.futex,
+                        AtomicU32::new(contested),
+                        to_owner(state),
+                        ZX_TIME_INFINITE,
+                    ) {
+                        ZX_OK | ZX_ERR_BAD_STATE | ZX_ERR_TIMED_OUT => (),
+                        // Note that if a thread handle is reused after its associated thread
+                        // exits without unlocking the mutex, an arbitrary thread's priority
+                        // could be boosted by the wait, but there is currently no way to
+                        // prevent that.
+                        ZX_ERR_INVALID_ARGS | ZX_ERR_BAD_HANDLE | ZX_ERR_WRONG_TYPE => {
+                            panic!(
+                                "either the current thread is trying to lock a mutex it has
+                                already locked, or the previous owner did not unlock the mutex
+                                before exiting"
+                            )
+                        }
+                        error => panic!("unexpected error in zx_futex_wait: {error}"),
+                    }
+                }
+            }
+
+            // The state has changed or a wakeup occured, try to lock the mutex.
+            match self.futex.compare_exchange(UNLOCKED, owned_state, Acquire, Relaxed) {
+                Ok(_) => return,
+                Err(updated) => state = updated,
+            }
+        }
+    }
+
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        if is_contested(self.futex.swap(UNLOCKED, Release)) {
+            // The woken thread will mark the mutex as contested again,
+            // and return here, waking until there are no waiters left,
+            // in which case this is a noop.
+            self.wake();
+        }
+    }
+
+    #[cold]
+    fn wake(&self) {
+        unsafe {
+            zx_futex_wake_single_owner(&self.futex);
+        }
+    }
+}
diff --git a/library/std/src/sys/unix/locks/futex_condvar.rs b/library/std/src/sys/unix/locks/futex_condvar.rs
new file mode 100644
index 00000000000..c0576c17880
--- /dev/null
+++ b/library/std/src/sys/unix/locks/futex_condvar.rs
@@ -0,0 +1,58 @@
+use super::Mutex;
+use crate::sync::atomic::{AtomicU32, Ordering::Relaxed};
+use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
+use crate::time::Duration;
+
+pub type MovableCondvar = Condvar;
+
+pub struct Condvar {
+    // The value of this atomic is simply incremented on every notification.
+    // This is used by `.wait()` to not miss any notifications after
+    // unlocking the mutex and before waiting for notifications.
+    futex: AtomicU32,
+}
+
+impl Condvar {
+    #[inline]
+    pub const fn new() -> Self {
+        Self { futex: AtomicU32::new(0) }
+    }
+
+    // All the memory orderings here are `Relaxed`,
+    // because synchronization is done by unlocking and locking the mutex.
+
+    pub unsafe fn notify_one(&self) {
+        self.futex.fetch_add(1, Relaxed);
+        futex_wake(&self.futex);
+    }
+
+    pub unsafe fn notify_all(&self) {
+        self.futex.fetch_add(1, Relaxed);
+        futex_wake_all(&self.futex);
+    }
+
+    pub unsafe fn wait(&self, mutex: &Mutex) {
+        self.wait_optional_timeout(mutex, None);
+    }
+
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, timeout: Duration) -> bool {
+        self.wait_optional_timeout(mutex, Some(timeout))
+    }
+
+    unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option<Duration>) -> bool {
+        // Examine the notification counter _before_ we unlock the mutex.
+        let futex_value = self.futex.load(Relaxed);
+
+        // Unlock the mutex before going to sleep.
+        mutex.unlock();
+
+        // Wait, but only if there hasn't been any
+        // notification since we unlocked the mutex.
+        let r = futex_wait(&self.futex, futex_value, timeout);
+
+        // Lock the mutex again.
+        mutex.lock();
+
+        r
+    }
+}
diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex_mutex.rs
index a9a1a32c5af..99ba86e5f99 100644
--- a/library/std/src/sys/unix/locks/futex.rs
+++ b/library/std/src/sys/unix/locks/futex_mutex.rs
@@ -2,11 +2,9 @@ use crate::sync::atomic::{
     AtomicU32,
     Ordering::{Acquire, Relaxed, Release},
 };
-use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
-use crate::time::Duration;
+use crate::sys::futex::{futex_wait, futex_wake};
 
 pub type MovableMutex = Mutex;
-pub type MovableCondvar = Condvar;
 
 pub struct Mutex {
     /// 0: unlocked
@@ -101,55 +99,3 @@ impl Mutex {
         futex_wake(&self.futex);
     }
 }
-
-pub struct Condvar {
-    // The value of this atomic is simply incremented on every notification.
-    // This is used by `.wait()` to not miss any notifications after
-    // unlocking the mutex and before waiting for notifications.
-    futex: AtomicU32,
-}
-
-impl Condvar {
-    #[inline]
-    pub const fn new() -> Self {
-        Self { futex: AtomicU32::new(0) }
-    }
-
-    // All the memory orderings here are `Relaxed`,
-    // because synchronization is done by unlocking and locking the mutex.
-
-    pub unsafe fn notify_one(&self) {
-        self.futex.fetch_add(1, Relaxed);
-        futex_wake(&self.futex);
-    }
-
-    pub unsafe fn notify_all(&self) {
-        self.futex.fetch_add(1, Relaxed);
-        futex_wake_all(&self.futex);
-    }
-
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        self.wait_optional_timeout(mutex, None);
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, timeout: Duration) -> bool {
-        self.wait_optional_timeout(mutex, Some(timeout))
-    }
-
-    unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option<Duration>) -> bool {
-        // Examine the notification counter _before_ we unlock the mutex.
-        let futex_value = self.futex.load(Relaxed);
-
-        // Unlock the mutex before going to sleep.
-        mutex.unlock();
-
-        // Wait, but only if there hasn't been any
-        // notification since we unlocked the mutex.
-        let r = futex_wait(&self.futex, futex_value, timeout);
-
-        // Lock the mutex again.
-        mutex.lock();
-
-        r
-    }
-}
diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs
index 03400efa3c9..f5f92f69358 100644
--- a/library/std/src/sys/unix/locks/mod.rs
+++ b/library/std/src/sys/unix/locks/mod.rs
@@ -7,10 +7,19 @@ cfg_if::cfg_if! {
         target_os = "openbsd",
         target_os = "dragonfly",
     ))] {
-        mod futex;
+        mod futex_mutex;
         mod futex_rwlock;
-        pub(crate) use futex::{Mutex, MovableMutex, MovableCondvar};
+        mod futex_condvar;
+        pub(crate) use futex_mutex::{Mutex, MovableMutex};
         pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
+        pub(crate) use futex_condvar::MovableCondvar;
+    } else if #[cfg(target_os = "fuchsia")] {
+        mod fuchsia_mutex;
+        mod futex_rwlock;
+        mod futex_condvar;
+        pub(crate) use fuchsia_mutex::{Mutex, MovableMutex};
+        pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
+        pub(crate) use futex_condvar::MovableCondvar;
     } else {
         mod pthread_mutex;
         mod pthread_rwlock;
diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs
index 78f10f0534c..abf27e7db78 100644
--- a/library/std/src/sys/unix/locks/pthread_condvar.rs
+++ b/library/std/src/sys/unix/locks/pthread_condvar.rs
@@ -37,6 +37,7 @@ impl Condvar {
     #[cfg(any(
         target_os = "macos",
         target_os = "ios",
+        target_os = "watchos",
         target_os = "l4re",
         target_os = "android",
         target_os = "redox"
@@ -58,6 +59,7 @@ impl Condvar {
     #[cfg(not(any(
         target_os = "macos",
         target_os = "ios",
+        target_os = "watchos",
         target_os = "l4re",
         target_os = "android",
         target_os = "redox",
@@ -102,6 +104,7 @@ impl Condvar {
     #[cfg(not(any(
         target_os = "macos",
         target_os = "ios",
+        target_os = "watchos",
         target_os = "android",
         target_os = "espidf",
         target_os = "horizon"
@@ -135,6 +138,7 @@ impl Condvar {
     #[cfg(any(
         target_os = "macos",
         target_os = "ios",
+        target_os = "watchos",
         target_os = "android",
         target_os = "espidf",
         target_os = "horizon"
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 34a023b02c4..3d0d91460f7 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -86,6 +86,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
             // The poll on Darwin doesn't set POLLNVAL for closed fds.
             target_os = "macos",
             target_os = "ios",
+            target_os = "watchos",
             target_os = "redox",
             target_os = "l4re",
             target_os = "horizon",
@@ -329,7 +330,7 @@ cfg_if::cfg_if! {
         // See #41582 and https://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
         #[link(name = "resolv")]
         extern "C" {}
-    } else if #[cfg(target_os = "ios")] {
+    } else if #[cfg(any(target_os = "ios", target_os = "watchos"))] {
         #[link(name = "System")]
         #[link(name = "objc")]
         #[link(name = "Security", kind = "framework")]
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 7252ad32184..46545a0839f 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -61,7 +61,7 @@ extern "C" {
     )]
     #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
     #[cfg_attr(
-        any(target_os = "macos", target_os = "ios", target_os = "freebsd"),
+        any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"),
         link_name = "__error"
     )]
     #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
@@ -361,7 +361,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     }
 }
 
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
 pub fn current_exe() -> io::Result<PathBuf> {
     unsafe {
         let mut sz: u32 = 0;
@@ -598,6 +598,7 @@ pub fn home_dir() -> Option<PathBuf> {
     #[cfg(any(
         target_os = "android",
         target_os = "ios",
+        target_os = "watchos",
         target_os = "emscripten",
         target_os = "redox",
         target_os = "vxworks",
@@ -610,6 +611,7 @@ pub fn home_dir() -> Option<PathBuf> {
     #[cfg(not(any(
         target_os = "android",
         target_os = "ios",
+        target_os = "watchos",
         target_os = "emscripten",
         target_os = "redox",
         target_os = "vxworks",
diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs
index 56d01074c20..bf49204881d 100644
--- a/library/std/src/sys/unix/rand.rs
+++ b/library/std/src/sys/unix/rand.rs
@@ -14,6 +14,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
     unix,
     not(target_os = "macos"),
     not(target_os = "ios"),
+    not(target_os = "watchos"),
     not(target_os = "openbsd"),
     not(target_os = "freebsd"),
     not(target_os = "netbsd"),
@@ -195,7 +196,7 @@ mod imp {
 // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
 // only used on iOS where direct access to `/dev/urandom` is blocked by the
 // sandbox.
-#[cfg(target_os = "ios")]
+#[cfg(any(target_os = "ios", target_os = "watchos"))]
 mod imp {
     use crate::io;
     use crate::ptr;
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index d191e1fe7a6..36a3fa6023b 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -139,7 +139,7 @@ impl Thread {
         }
     }
 
-    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
     pub fn set_name(name: &CStr) {
         unsafe {
             libc::pthread_setname_np(name.as_ptr());
@@ -285,7 +285,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
         ))] {
             #[cfg(any(target_os = "android", target_os = "linux"))]
             {
-                let quota = cgroup2_quota().max(1);
+                let quota = cgroups::quota().max(1);
                 let mut set: libc::cpu_set_t = unsafe { mem::zeroed() };
                 unsafe {
                     if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 {
@@ -379,49 +379,88 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     }
 }
 
-/// Returns cgroup CPU quota in core-equivalents, rounded down, or usize::MAX if the quota cannot
-/// be determined or is not set.
 #[cfg(any(target_os = "android", target_os = "linux"))]
-fn cgroup2_quota() -> usize {
+mod cgroups {
+    //! Currently not covered
+    //! * cgroup v2 in non-standard mountpoints
+    //! * paths containing control characters or spaces, since those would be escaped in procfs
+    //!   output and we don't unescape
+    use crate::borrow::Cow;
     use crate::ffi::OsString;
     use crate::fs::{try_exists, File};
     use crate::io::Read;
+    use crate::io::{BufRead, BufReader};
     use crate::os::unix::ffi::OsStringExt;
+    use crate::path::Path;
     use crate::path::PathBuf;
+    use crate::str::from_utf8;
 
-    let mut quota = usize::MAX;
-    if cfg!(miri) {
-        // Attempting to open a file fails under default flags due to isolation.
-        // And Miri does not have parallelism anyway.
-        return quota;
-    }
-
-    let _: Option<()> = try {
-        let mut buf = Vec::with_capacity(128);
-        // find our place in the cgroup hierarchy
-        File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?;
-        let cgroup_path = buf
-            .split(|&c| c == b'\n')
-            .filter_map(|line| {
-                let mut fields = line.splitn(3, |&c| c == b':');
-                // expect cgroupv2 which has an empty 2nd field
-                if fields.nth(1) != Some(b"") {
-                    return None;
-                }
-                let path = fields.last()?;
-                // skip leading slash
-                Some(path[1..].to_owned())
-            })
-            .next()?;
-        let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path));
+    #[derive(PartialEq)]
+    enum Cgroup {
+        V1,
+        V2,
+    }
+
+    /// Returns cgroup CPU quota in core-equivalents, rounded down or usize::MAX if the quota cannot
+    /// be determined or is not set.
+    pub(super) fn quota() -> usize {
+        let mut quota = usize::MAX;
+        if cfg!(miri) {
+            // Attempting to open a file fails under default flags due to isolation.
+            // And Miri does not have parallelism anyway.
+            return quota;
+        }
+
+        let _: Option<()> = try {
+            let mut buf = Vec::with_capacity(128);
+            // find our place in the cgroup hierarchy
+            File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?;
+            let (cgroup_path, version) =
+                buf.split(|&c| c == b'\n').fold(None, |previous, line| {
+                    let mut fields = line.splitn(3, |&c| c == b':');
+                    // 2nd field is a list of controllers for v1 or empty for v2
+                    let version = match fields.nth(1) {
+                        Some(b"") => Cgroup::V2,
+                        Some(controllers)
+                            if from_utf8(controllers)
+                                .is_ok_and(|c| c.split(",").any(|c| c == "cpu")) =>
+                        {
+                            Cgroup::V1
+                        }
+                        _ => return previous,
+                    };
+
+                    // already-found v1 trumps v2 since it explicitly specifies its controllers
+                    if previous.is_some() && version == Cgroup::V2 {
+                        return previous;
+                    }
+
+                    let path = fields.last()?;
+                    // skip leading slash
+                    Some((path[1..].to_owned(), version))
+                })?;
+            let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path));
+
+            quota = match version {
+                Cgroup::V1 => quota_v1(cgroup_path),
+                Cgroup::V2 => quota_v2(cgroup_path),
+            };
+        };
+
+        quota
+    }
+
+    fn quota_v2(group_path: PathBuf) -> usize {
+        let mut quota = usize::MAX;
 
         let mut path = PathBuf::with_capacity(128);
         let mut read_buf = String::with_capacity(20);
 
+        // standard mount location defined in file-hierarchy(7) manpage
         let cgroup_mount = "/sys/fs/cgroup";
 
         path.push(cgroup_mount);
-        path.push(&cgroup_path);
+        path.push(&group_path);
 
         path.push("cgroup.controllers");
 
@@ -432,30 +471,134 @@ fn cgroup2_quota() -> usize {
 
         path.pop();
 
-        while path.starts_with(cgroup_mount) {
-            path.push("cpu.max");
+        let _: Option<()> = try {
+            while path.starts_with(cgroup_mount) {
+                path.push("cpu.max");
+
+                read_buf.clear();
+
+                if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() {
+                    let raw_quota = read_buf.lines().next()?;
+                    let mut raw_quota = raw_quota.split(' ');
+                    let limit = raw_quota.next()?;
+                    let period = raw_quota.next()?;
+                    match (limit.parse::<usize>(), period.parse::<usize>()) {
+                        (Ok(limit), Ok(period)) => {
+                            quota = quota.min(limit / period);
+                        }
+                        _ => {}
+                    }
+                }
 
-            read_buf.clear();
+                path.pop(); // pop filename
+                path.pop(); // pop dir
+            }
+        };
 
-            if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() {
-                let raw_quota = read_buf.lines().next()?;
-                let mut raw_quota = raw_quota.split(' ');
-                let limit = raw_quota.next()?;
-                let period = raw_quota.next()?;
-                match (limit.parse::<usize>(), period.parse::<usize>()) {
-                    (Ok(limit), Ok(period)) => {
-                        quota = quota.min(limit / period);
-                    }
+        quota
+    }
+
+    fn quota_v1(group_path: PathBuf) -> usize {
+        let mut quota = usize::MAX;
+        let mut path = PathBuf::with_capacity(128);
+        let mut read_buf = String::with_capacity(20);
+
+        // Hardcode commonly used locations mentioned in the cgroups(7) manpage
+        // if that doesn't work scan mountinfo and adjust `group_path` for bind-mounts
+        let mounts: &[fn(&Path) -> Option<(_, &Path)>] = &[
+            |p| Some((Cow::Borrowed("/sys/fs/cgroup/cpu"), p)),
+            |p| Some((Cow::Borrowed("/sys/fs/cgroup/cpu,cpuacct"), p)),
+            // this can be expensive on systems with tons of mountpoints
+            // but we only get to this point when /proc/self/cgroups explicitly indicated
+            // this process belongs to a cpu-controller cgroup v1 and the defaults didn't work
+            find_mountpoint,
+        ];
+
+        for mount in mounts {
+            let Some((mount, group_path)) = mount(&group_path) else { continue };
+
+            path.clear();
+            path.push(mount.as_ref());
+            path.push(&group_path);
+
+            // skip if we guessed the mount incorrectly
+            if matches!(try_exists(&path), Err(_) | Ok(false)) {
+                continue;
+            }
+
+            while path.starts_with(mount.as_ref()) {
+                let mut parse_file = |name| {
+                    path.push(name);
+                    read_buf.clear();
+
+                    let f = File::open(&path);
+                    path.pop(); // restore buffer before any early returns
+                    f.ok()?.read_to_string(&mut read_buf).ok()?;
+                    let parsed = read_buf.trim().parse::<usize>().ok()?;
+
+                    Some(parsed)
+                };
+
+                let limit = parse_file("cpu.cfs_quota_us");
+                let period = parse_file("cpu.cfs_period_us");
+
+                match (limit, period) {
+                    (Some(limit), Some(period)) => quota = quota.min(limit / period),
                     _ => {}
                 }
+
+                path.pop();
             }
 
-            path.pop(); // pop filename
-            path.pop(); // pop dir
+            // we passed the try_exists above so we should have traversed the correct hierarchy
+            // when reaching this line
+            break;
         }
-    };
 
-    quota
+        quota
+    }
+
+    /// Scan mountinfo for cgroup v1 mountpoint with a cpu controller
+    ///
+    /// If the cgroupfs is a bind mount then `group_path` is adjusted to skip
+    /// over the already-included prefix
+    fn find_mountpoint(group_path: &Path) -> Option<(Cow<'static, str>, &Path)> {
+        let mut reader = BufReader::new(File::open("/proc/self/mountinfo").ok()?);
+        let mut line = String::with_capacity(256);
+        loop {
+            line.clear();
+            if reader.read_line(&mut line).ok()? == 0 {
+                break;
+            }
+
+            let line = line.trim();
+            let mut items = line.split(' ');
+
+            let sub_path = items.nth(3)?;
+            let mount_point = items.next()?;
+            let mount_opts = items.next_back()?;
+            let filesystem_type = items.nth_back(1)?;
+
+            if filesystem_type != "cgroup" || !mount_opts.split(',').any(|opt| opt == "cpu") {
+                // not a cgroup / not a cpu-controller
+                continue;
+            }
+
+            let sub_path = Path::new(sub_path).strip_prefix("/").ok()?;
+
+            if !group_path.starts_with(sub_path) {
+                // this is a bind-mount and the bound subdirectory
+                // does not contain the cgroup this process belongs to
+                continue;
+            }
+
+            let trimmed_group_path = group_path.strip_prefix(sub_path).ok()?;
+
+            return Some((Cow::Owned(mount_point.to_owned()), trimmed_group_path));
+        }
+
+        None
+    }
 }
 
 #[cfg(all(
diff --git a/library/std/src/sys/unix/thread_parker.rs b/library/std/src/sys/unix/thread_parker.rs
index 9f4d4f7e736..ca1a7138fde 100644
--- a/library/std/src/sys/unix/thread_parker.rs
+++ b/library/std/src/sys/unix/thread_parker.rs
@@ -52,7 +52,12 @@ unsafe fn wait_timeout(
 ) {
     // Use the system clock on systems that do not support pthread_condattr_setclock.
     // This unfortunately results in problems when the system time changes.
-    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "espidf"))]
+    #[cfg(any(
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "watchos",
+        target_os = "espidf"
+    ))]
     let (now, dur) = {
         use super::time::SystemTime;
         use crate::cmp::min;
@@ -73,7 +78,12 @@ unsafe fn wait_timeout(
         (now, dur)
     };
     // Use the monotonic clock on other systems.
-    #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "espidf")))]
+    #[cfg(not(any(
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "watchos",
+        target_os = "espidf"
+    )))]
     let (now, dur) = {
         use super::time::Timespec;
 
@@ -111,6 +121,7 @@ impl Parker {
             if #[cfg(any(
                 target_os = "macos",
                 target_os = "ios",
+                target_os = "watchos",
                 target_os = "l4re",
                 target_os = "android",
                 target_os = "redox"
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index d114af49d26..dff973f59d1 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -141,7 +141,7 @@ impl From<libc::timespec> for Timespec {
     }
 }
 
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
 mod inner {
     use crate::sync::atomic::{AtomicU64, Ordering};
     use crate::sys::cvt;
@@ -257,7 +257,7 @@ mod inner {
     }
 }
 
-#[cfg(not(any(target_os = "macos", target_os = "ios")))]
+#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))]
 mod inner {
     use crate::fmt;
     use crate::mem::MaybeUninit;
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index f5730a2cea5..c13bda32823 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -18,7 +18,7 @@ use libc::{c_int, c_void};
 cfg_if::cfg_if! {
     if #[cfg(any(
         target_os = "dragonfly", target_os = "freebsd",
-        target_os = "ios", target_os = "macos",
+        target_os = "ios", target_os = "macos", target_os = "watchos",
         target_os = "openbsd", target_os = "netbsd", target_os = "illumos",
         target_os = "solaris", target_os = "haiku", target_os = "l4re"))] {
         use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index d28c7b58b20..44c8a50fd86 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1577,10 +1577,15 @@ fn _assert_sync_and_send() {
 ///
 /// On Linux:
 /// - It may overcount the amount of parallelism available when limited by a
-///   process-wide affinity mask or cgroup quotas and cgroup2 fs or `sched_getaffinity()` can't be
+///   process-wide affinity mask or cgroup quotas and `sched_getaffinity()` or cgroup fs can't be
 ///   queried, e.g. due to sandboxing.
 /// - It may undercount the amount of parallelism if the current thread's affinity mask
 ///   does not reflect the process' cpuset, e.g. due to pinned threads.
+/// - If the process is in a cgroup v1 cpu controller, this may need to
+///   scan mountpoints to find the corresponding cgroup v1 controller,
+///   which may take time on systems with large numbers of mountpoints.
+///   (This does not apply to cgroup v2, or to processes not in a
+///   cgroup.)
 ///
 /// On all targets:
 /// - It may overcount the amount of parallelism available when running in a VM
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index dc0123cf432..e9dda98966d 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -137,7 +137,7 @@ impl ConsoleTestState {
 // List the tests to console, and optionally to logfile. Filters are honored.
 pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
     let mut output = match term::stdout() {
-        None => OutputLocation::Raw(io::stdout()),
+        None => OutputLocation::Raw(io::stdout().lock()),
         Some(t) => OutputLocation::Pretty(t),
     };
 
diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs
index 7b78bda424b..a5b6193b086 100644
--- a/library/unwind/src/libunwind.rs
+++ b/library/unwind/src/libunwind.rs
@@ -30,10 +30,10 @@ pub const unwinder_private_data_size: usize = 5;
 #[cfg(target_arch = "x86_64")]
 pub const unwinder_private_data_size: usize = 6;
 
-#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
+#[cfg(all(target_arch = "arm", not(any(target_os = "ios", target_os = "watchos"))))]
 pub const unwinder_private_data_size: usize = 20;
 
-#[cfg(all(target_arch = "arm", target_os = "ios"))]
+#[cfg(all(target_arch = "arm", any(target_os = "ios", target_os = "watchos")))]
 pub const unwinder_private_data_size: usize = 5;
 
 #[cfg(all(target_arch = "aarch64", target_pointer_width = "64"))]
@@ -105,7 +105,7 @@ extern "C" {
 }
 
 cfg_if::cfg_if! {
-if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))] {
+if #[cfg(any(target_os = "ios", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] {
     // Not ARM EHABI
     #[repr(C)]
     #[derive(Copy, Clone, PartialEq)]
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 4c6b5ba0afc..078207d85fe 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -475,6 +475,9 @@ impl Step for Miri {
         let stage = self.stage;
         let host = self.host;
         let compiler = builder.compiler(stage, host);
+        // We need the stdlib for the *next* stage, as it was built with this compiler that also built Miri.
+        // Except if we are at stage 2, the bootstrap loop is complete and we can stick with our current stage.
+        let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host);
 
         let miri =
             builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
@@ -483,6 +486,10 @@ impl Step for Miri {
             target: self.host,
             extra_features: Vec::new(),
         });
+        // The stdlib we need might be at a different stage. And just asking for the
+        // sysroot does not seem to populate it, so we do that first.
+        builder.ensure(compile::Std::new(compiler_std, host));
+        let sysroot = builder.sysroot(compiler_std);
         if let (Some(miri), Some(_cargo_miri)) = (miri, cargo_miri) {
             let mut cargo =
                 builder.cargo(compiler, Mode::ToolRustc, SourceType::Submodule, host, "install");
@@ -562,6 +569,7 @@ impl Step for Miri {
 
             // miri tests need to know about the stage sysroot
             cargo.env("MIRI_SYSROOT", miri_sysroot);
+            cargo.env("MIRI_HOST_SYSROOT", sysroot);
             cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
             cargo.env("MIRI", miri);
 
diff --git a/src/doc/book b/src/doc/book
-Subproject cf2653a5ca553cbbb4a17f1a7db1947820f6a77
+Subproject 36383b4da21dbd0a0781473bc8ad7ef0ed1b675
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 70db9e4189f64d1d8e2451b1046111fb356b6dc
+Subproject 8d1e4dccf71114ff56f328f671f2026d8e6b62a
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 9fce337a55ee4a4629205f6094656195cecad23
+Subproject a92be0fef439b3d8e0468d82cb24812d303520a
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 83724ca387a2a1cd3e8d848f62820020760e358
+Subproject 3155db49b0d57cd82c65456ac210b69ecec5ccb
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject eb83839e903a0a8f1406f7e941886273f189b26
+Subproject d5201cddace979b299ec1bf9fd8997338151aa9
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index e83c4d98cc7..7f7549aaf5a 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -18,11 +18,13 @@ This feature allows for use of one of following sanitizers:
 * [MemorySanitizer][clang-msan] a detector of uninitialized reads.
 * [MemTagSanitizer][clang-memtag] fast memory error detector based on
   Armv8.5-A Memory Tagging Extension.
+* [ShadowCallStack][clang-scs] provides backward-edge control flow protection.
 * [ThreadSanitizer][clang-tsan] a fast data race detector.
 
 To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
 `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
-`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. Example:
+`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`.
+You might also need the `--target` and `build-std` flags. Example:
 ```shell
 $ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
 ```
@@ -191,7 +193,8 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
 
 The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
 provides forward-edge control flow protection for Rust-compiled code only by
-aggregating function pointers in groups identified by their number of arguments.
+aggregating function pointers in groups identified by their return and parameter
+types.
 
 Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
 binaries" (i.e., for when C or C++ and Rust -compiled code share the same
@@ -243,7 +246,7 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
 fn main() {
     let answer = do_twice(add_one, 5);
 
-    println!("The answer is: {answer}");
+    println!("The answer is: {}", answer);
 
     println!("With CFI enabled, you should not see the next answer");
     let f: fn(i32) -> i32 = unsafe {
@@ -253,18 +256,18 @@ fn main() {
     };
     let next_answer = do_twice(f, 5);
 
-    println!("The next answer is: {next_answer}");
+    println!("The next answer is: {}", next_answer);
 }
 ```
 Fig. 1. Modified example from the [Advanced Functions and
 Closures][rust-book-ch19-05] chapter of the [The Rust Programming
 Language][rust-book] book.
 
-[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
-
 ```shell
-$ rustc rust_cfi.rs -o rust_cfi
-$ ./rust_cfi
+$ cargo run --release
+   Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
+    Finished release [optimized] target(s) in 0.76s
+     Running `target/release/rust-cfi-1`
 The answer is: 12
 With CFI enabled, you should not see the next answer
 The next answer is: 14
@@ -272,11 +275,11 @@ $
 ```
 Fig. 2. Build and execution of the modified example with LLVM CFI disabled.
 
-[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
-
 ```shell
-$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
-$ ./rust_cfi
+$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
+   Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
+    Finished release [optimized] target(s) in 3.39s
+     Running `target/release/rust-cfi-1`
 The answer is: 12
 With CFI enabled, you should not see the next answer
 Illegal instruction
@@ -306,25 +309,25 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
 fn main() {
     let answer = do_twice(add_one, 5);
 
-    println!("The answer is: {answer}");
+    println!("The answer is: {}", answer);
 
     println!("With CFI enabled, you should not see the next answer");
     let f: fn(i32) -> i32 =
         unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
     let next_answer = do_twice(f, 5);
 
-    println!("The next answer is: {next_answer}");
+    println!("The next answer is: {}", next_answer);
 }
 ```
 Fig. 4. Another modified example from the [Advanced Functions and
 Closures][rust-book-ch19-05] chapter of the [The Rust Programming
 Language][rust-book] book.
 
-[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
-
 ```shell
-$ rustc rust_cfi.rs -o rust_cfi
-$ ./rust_cfi
+$ cargo run --release
+   Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
+    Finished release [optimized] target(s) in 0.76s
+     Running `target/release/rust-cfi-2`
 The answer is: 12
 With CFI enabled, you should not see the next answer
 The next answer is: 14
@@ -332,11 +335,11 @@ $
 ```
 Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
 
-[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
-
 ```shell
-$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
-$ ./rust_cfi
+$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
+   Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
+    Finished release [optimized] target(s) in 3.38s
+     Running `target/release/rust-cfi-2`
 The answer is: 12
 With CFI enabled, you should not see the next answer
 Illegal instruction
@@ -346,14 +349,69 @@ Fig. 6. Build and execution of the modified example with LLVM CFI enabled.
 
 When LLVM CFI is enabled, if there are any attempts to change/hijack control
 flow using an indirect branch/call to a function with different number of
-arguments than intended/passed in the call/branch site, the execution is also
-terminated (see Fig. 6).
+parameters than arguments intended/passed in the call/branch site, the
+execution is also terminated (see Fig. 6).
+
+```rust
+use std::mem;
+
+fn add_one(x: i32) -> i32 {
+    x + 1
+}
+
+fn add_two(x: i64) -> i64 {
+    x + 2
+}
+
+fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
+    f(arg) + f(arg)
+}
+
+fn main() {
+    let answer = do_twice(add_one, 5);
+
+    println!("The answer is: {}", answer);
+
+    println!("With CFI enabled, you should not see the next answer");
+    let f: fn(i32) -> i32 =
+        unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
+    let next_answer = do_twice(f, 5);
 
-Forward-edge control flow protection not only by aggregating function pointers
-in groups identified by their number of arguments, but also their argument
-types, will also be provided in later work by defining and using compatible type
-identifiers (see Type metadata in the design document in the tracking
-issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
+    println!("The next answer is: {}", next_answer);
+}
+```
+Fig. 7. Another modified example from the [Advanced Functions and
+Closures][rust-book-ch19-05] chapter of the [The Rust Programming
+Language][rust-book] book.
+
+```shell
+ cargo run --release
+   Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
+    Finished release [optimized] target(s) in 0.74s
+     Running `target/release/rust-cfi-3`
+The answer is: 12
+With CFI enabled, you should not see the next answer
+The next answer is: 14
+$
+```
+Fig. 8. Build and execution of the modified example with LLVM CFI disabled.
+
+```shell
+$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
+   Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
+    Finished release [optimized] target(s) in 3.40s
+     Running `target/release/rust-cfi-3`
+The answer is: 12
+With CFI enabled, you should not see the next answer
+Illegal instruction
+$
+```
+Fig. 9. Build and execution of the modified example with LLVM CFI enabled.
+
+When LLVM CFI is enabled, if there are any attempts to change/hijack control
+flow using an indirect branch/call to a function with different return and
+parameter types than the return type expected and arguments intended/passed in
+the call/branch site, the execution is also terminated (see Fig. 9).
 
 [rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
 [rust-book]: https://doc.rust-lang.org/book/title-page.html
@@ -513,6 +571,18 @@ To enable this target feature compile with `-C target-feature="+mte"`.
 
 More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html).
 
+# ShadowCallStack
+
+ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack.
+
+ShadowCallStack requires a platform ABI which reserves `x18` as the instrumentation makes use of this register.
+
+ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and is supported on the following targets:
+
+* `aarch64-linux-android`
+
+A runtime must be provided by the application or operating system. See the [LLVM documentation][clang-scs] for further details.
+
 # ThreadSanitizer
 
 ThreadSanitizer is a data race detection tool. It is supported on the following
@@ -610,4 +680,5 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 [clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
 [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
 [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
+[clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
 [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index e6f006135e2..c43fd1ad241 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -121,7 +121,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                 unsafety: hir::Unsafety::Normal,
                 generics: new_generics,
                 trait_: Some(trait_ref.clean(self.cx)),
-                for_: ty.clean(self.cx),
+                for_: clean_middle_ty(ty, self.cx, None),
                 items: Vec::new(),
                 polarity,
                 kind: ImplKind::Auto,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 12137667e7b..c64c5895079 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -116,14 +116,14 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             // FIXME(eddyb) compute both `trait_` and `for_` from
                             // the post-inference `trait_ref`, as it's more accurate.
                             trait_: Some(trait_ref.0.clean(cx)),
-                            for_: ty.0.clean(cx),
+                            for_: clean_middle_ty(ty.0, cx, None),
                             items: cx.tcx
                                 .associated_items(impl_def_id)
                                 .in_definition_order()
                                 .map(|x| x.clean(cx))
                                 .collect::<Vec<_>>(),
                             polarity: ty::ImplPolarity::Positive,
-                            kind: ImplKind::Blanket(Box::new(trait_ref.0.self_ty().clean(cx))),
+                            kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))),
                         })),
                         cfg: None,
                     });
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index ce10ca9aa3d..7a4ec889ac7 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -16,8 +16,8 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 
 use crate::clean::{
-    self, clean_fn_decl_from_did_and_sig, clean_ty_generics, utils, Attributes, AttributesExt,
-    Clean, ImplKind, ItemId, Type, Visibility,
+    self, clean_fn_decl_from_did_and_sig, clean_middle_ty, clean_ty, clean_ty_generics, utils,
+    Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -214,14 +214,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
     let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
     let generics = filter_non_trait_generics(did, generics);
     let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
-    let is_auto = cx.tcx.trait_is_auto(did);
-    clean::Trait {
-        unsafety: cx.tcx.trait_def(did).unsafety,
-        generics,
-        items: trait_items,
-        bounds: supertrait_bounds,
-        is_auto,
-    }
+    clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
 }
 
 fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> clean::Function {
@@ -268,7 +261,7 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
 
 fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef {
     let predicates = cx.tcx.explicit_predicates_of(did);
-    let type_ = cx.tcx.type_of(did).clean(cx);
+    let type_ = clean_middle_ty(cx.tcx.type_of(did), cx, Some(did));
 
     clean::Typedef {
         type_,
@@ -364,8 +357,8 @@ pub(crate) fn build_impl(
     };
 
     let for_ = match &impl_item {
-        Some(impl_) => impl_.self_ty.clean(cx),
-        None => tcx.type_of(did).clean(cx),
+        Some(impl_) => clean_ty(impl_.self_ty, cx),
+        None => clean_middle_ty(tcx.type_of(did), cx, Some(did)),
     };
 
     // Only inline impl if the implementing type is
@@ -584,14 +577,14 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
 
 fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
     clean::Constant {
-        type_: cx.tcx.type_of(def_id).clean(cx),
+        type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)),
         kind: clean::ConstantKind::Extern { def_id },
     }
 }
 
 fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
     clean::Static {
-        type_: cx.tcx.type_of(did).clean(cx),
+        type_: clean_middle_ty(cx.tcx.type_of(did), cx, Some(did)),
         mutability: if mutable { Mutability::Mut } else { Mutability::Not },
         expr: None,
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9865601da5f..6160783f652 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -239,11 +239,9 @@ impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime {
 
 impl<'tcx> Clean<'tcx, Constant> for hir::ConstArg {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant {
+        let def_id = cx.tcx.hir().body_owner_def_id(self.value.body).to_def_id();
         Constant {
-            type_: cx
-                .tcx
-                .type_of(cx.tcx.hir().body_owner_def_id(self.value.body).to_def_id())
-                .clean(cx),
+            type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)),
             kind: ConstantKind::Anonymous { body: self.value.body },
         }
     }
@@ -297,7 +295,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
                     })
                     .collect();
                 WherePredicate::BoundPredicate {
-                    ty: wbp.bounded_ty.clean(cx),
+                    ty: clean_ty(wbp.bounded_ty, cx),
                     bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
                     bound_params,
                 }
@@ -309,8 +307,8 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
             },
 
             hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
-                lhs: wrp.lhs_ty.clean(cx),
-                rhs: wrp.rhs_ty.clean(cx).into(),
+                lhs: clean_ty(wrp.lhs_ty, cx),
+                rhs: clean_ty(wrp.rhs_ty, cx).into(),
             },
         })
     }
@@ -348,7 +346,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::PolyTraitPredicate<'tcx>
 
         let poly_trait_ref = self.map_bound(|pred| pred.trait_ref);
         Some(WherePredicate::BoundPredicate {
-            ty: poly_trait_ref.skip_binder().self_ty().clean(cx),
+            ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
             bounds: vec![poly_trait_ref.clean(cx)],
             bound_params: Vec::new(),
         })
@@ -383,7 +381,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>>
         }
 
         Some(WherePredicate::BoundPredicate {
-            ty: ty.clean(cx),
+            ty: clean_middle_ty(*ty, cx, None),
             bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
             bound_params: Vec::new(),
         })
@@ -393,7 +391,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>>
 impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Term {
         match self {
-            ty::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            ty::Term::Ty(ty) => Term::Type(clean_middle_ty(*ty, cx, None)),
             ty::Term::Const(c) => Term::Constant(c.clean(cx)),
         }
     }
@@ -402,7 +400,7 @@ impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> {
 impl<'tcx> Clean<'tcx, Term> for hir::Term<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Term {
         match self {
-            hir::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
             hir::Term::Const(c) => {
                 let def_id = cx.tcx.hir().local_def_id(c.hir_id);
                 Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx))
@@ -425,7 +423,7 @@ fn clean_projection<'tcx>(
 ) -> Type {
     let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
     let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
-    let self_type = ty.self_ty().clean(cx);
+    let self_type = clean_middle_ty(ty.self_ty(), cx, None);
     let self_def_id = if let Some(def_id) = def_id {
         cx.tcx.opt_parent(def_id).or(Some(def_id))
     } else {
@@ -476,7 +474,7 @@ impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef {
             }
             ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
                 let default = if has_default {
-                    Some(clean_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id)))
+                    Some(clean_middle_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id)))
                 } else {
                     None
                 };
@@ -494,7 +492,11 @@ impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef {
                 self.name,
                 GenericParamDefKind::Const {
                     did: self.def_id,
-                    ty: Box::new(cx.tcx.type_of(self.def_id).clean(cx)),
+                    ty: Box::new(clean_middle_ty(
+                        cx.tcx.type_of(self.def_id),
+                        cx,
+                        Some(self.def_id),
+                    )),
                     default: match has_default {
                         true => Some(Box::new(cx.tcx.const_param_default(self.def_id).to_string())),
                         false => None,
@@ -546,7 +548,7 @@ fn clean_generic_param<'tcx>(
                 GenericParamDefKind::Type {
                     did: did.to_def_id(),
                     bounds,
-                    default: default.map(|t| t.clean(cx)).map(Box::new),
+                    default: default.map(|t| clean_ty(t, cx)).map(Box::new),
                     synthetic,
                 },
             )
@@ -555,7 +557,7 @@ fn clean_generic_param<'tcx>(
             param.name.ident().name,
             GenericParamDefKind::Const {
                 did: did.to_def_id(),
-                ty: Box::new(ty.clean(cx)),
+                ty: Box::new(clean_ty(ty, cx)),
                 default: default.map(|ct| {
                     let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
                     Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
@@ -752,7 +754,7 @@ fn clean_ty_generics<'tcx>(
         if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
             if let Some(proj) = impl_trait_proj.remove(&idx) {
                 for (trait_did, name, rhs) in proj {
-                    let rhs = rhs.clean(cx);
+                    let rhs = clean_middle_ty(rhs, cx, None);
                     simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
                 }
             }
@@ -926,7 +928,7 @@ fn clean_args_from_types_and_names<'tcx>(
                 if name.is_empty() {
                     name = kw::Underscore;
                 }
-                Argument { name, type_: ty.clean(cx), is_const: false }
+                Argument { name, type_: clean_ty(ty, cx), is_const: false }
             })
             .collect(),
     }
@@ -945,7 +947,7 @@ fn clean_args_from_types_and_body_id<'tcx>(
             .enumerate()
             .map(|(i, ty)| Argument {
                 name: name_from_pat(body.params[i].pat),
-                type_: ty.clean(cx),
+                type_: clean_ty(ty, cx),
                 is_const: false,
             })
             .collect(),
@@ -969,7 +971,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
 
     // We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
     // but shouldn't change any code meaning.
-    let output = match sig.skip_binder().output().clean(cx) {
+    let output = match clean_middle_ty(sig.skip_binder().output(), cx, None) {
         Type::Tuple(inner) if inner.is_empty() => DefaultReturn,
         ty => Return(ty),
     };
@@ -983,7 +985,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
                 .inputs()
                 .iter()
                 .map(|t| Argument {
-                    type_: t.clean(cx),
+                    type_: clean_middle_ty(*t, cx, None),
                     name: names.next().map_or(kw::Empty, |i| i.name),
                     is_const: false,
                 })
@@ -995,7 +997,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
 impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy {
         match *self {
-            Self::Return(typ) => Return(typ.clean(cx)),
+            Self::Return(typ) => Return(clean_ty(typ, cx)),
             Self::DefaultReturn(..) => DefaultReturn,
         }
     }
@@ -1038,10 +1040,10 @@ impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> {
         cx.with_param_env(local_did, |cx| {
             let inner = match self.kind {
                 hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
-                    ty.clean(cx),
+                    clean_ty(ty, cx),
                     ConstantKind::Local { def_id: local_did, body: default },
                 ),
-                hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(ty.clean(cx)),
+                hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
                 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
                     let m = clean_function(cx, sig, self.generics, body);
                     MethodItem(m, None)
@@ -1059,9 +1061,13 @@ impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> {
                 hir::TraitItemKind::Type(bounds, Some(default)) => {
                     let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
                     let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
-                    let item_type = hir_ty_to_ty(cx.tcx, default).clean(cx);
+                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
                     AssocTypeItem(
-                        Typedef { type_: default.clean(cx), generics, item_type: Some(item_type) },
+                        Typedef {
+                            type_: clean_ty(default, cx),
+                            generics,
+                            item_type: Some(item_type),
+                        },
                         bounds,
                     )
                 }
@@ -1086,7 +1092,7 @@ impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
             let inner = match self.kind {
                 hir::ImplItemKind::Const(ty, expr) => {
                     let default = ConstantKind::Local { def_id: local_did, body: expr };
-                    AssocConstItem(ty.clean(cx), default)
+                    AssocConstItem(clean_ty(ty, cx), default)
                 }
                 hir::ImplItemKind::Fn(ref sig, body) => {
                     let m = clean_function(cx, sig, self.generics, body);
@@ -1094,9 +1100,9 @@ impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
                     MethodItem(m, Some(defaultness))
                 }
                 hir::ImplItemKind::TyAlias(hir_ty) => {
-                    let type_ = hir_ty.clean(cx);
+                    let type_ = clean_ty(hir_ty, cx);
                     let generics = self.generics.clean(cx);
-                    let item_type = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
+                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
                     AssocTypeItem(
                         Typedef { type_, generics, item_type: Some(item_type) },
                         Vec::new(),
@@ -1125,7 +1131,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
         let tcx = cx.tcx;
         let kind = match self.kind {
             ty::AssocKind::Const => {
-                let ty = tcx.type_of(self.def_id).clean(cx);
+                let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id));
 
                 let provided = match self.container {
                     ty::ImplContainer(_) => true,
@@ -1272,7 +1278,11 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
                     if self.defaultness.has_value() {
                         AssocTypeItem(
                             Typedef {
-                                type_: tcx.type_of(self.def_id).clean(cx),
+                                type_: clean_middle_ty(
+                                    tcx.type_of(self.def_id),
+                                    cx,
+                                    Some(self.def_id),
+                                ),
                                 generics,
                                 // FIXME: should we obtain the Type from HIR and pass it on here?
                                 item_type: None,
@@ -1286,7 +1296,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
                     // FIXME: when could this happen? Associated items in inherent impls?
                     AssocTypeItem(
                         Typedef {
-                            type_: tcx.type_of(self.def_id).clean(cx),
+                            type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)),
                             generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
                             item_type: None,
                         },
@@ -1337,7 +1347,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             // Try to normalize `<X as Y>::T` to a type
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
             if let Some(normalized_value) = normalize(cx, ty) {
-                return normalized_value.clean(cx);
+                return clean_middle_ty(normalized_value, cx, None);
             }
 
             let trait_segments = &p.segments[..p.segments.len() - 1];
@@ -1348,7 +1358,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             };
             register_res(cx, trait_.res);
             let self_def_id = DefId::local(qself.hir_id.owner.local_def_index);
-            let self_type = qself.clean(cx);
+            let self_type = clean_ty(qself, cx);
             let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type);
             Type::QPath {
                 assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)),
@@ -1368,7 +1378,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             let trait_ = hir::Path { span, res, segments: &[] }.clean(cx);
             register_res(cx, trait_.res);
             let self_def_id = res.opt_def_id();
-            let self_type = qself.clean(cx);
+            let self_type = clean_ty(qself, cx);
             let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
             Type::QPath {
                 assoc: Box::new(segment.clean(cx)),
@@ -1435,9 +1445,12 @@ fn maybe_expand_private_type_alias<'tcx>(
                     _ => None,
                 });
                 if let Some(ty) = type_ {
-                    substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(ty.clean(cx)));
+                    substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx)));
                 } else if let Some(default) = *default {
-                    substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(default.clean(cx)));
+                    substs.insert(
+                        ty_param_def_id.to_def_id(),
+                        SubstParam::Type(clean_ty(default, cx)),
+                    );
                 }
                 indices.types += 1;
             }
@@ -1464,70 +1477,68 @@ fn maybe_expand_private_type_alias<'tcx>(
         }
     }
 
-    Some(cx.enter_alias(substs, |cx| ty.clean(cx)))
+    Some(cx.enter_alias(substs, |cx| clean_ty(ty, cx)))
 }
 
-impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
-        use rustc_hir::*;
-
-        match self.kind {
-            TyKind::Never => Primitive(PrimitiveType::Never),
-            TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(m.ty.clean(cx))),
-            TyKind::Rptr(ref l, ref m) => {
-                // There are two times a `Fresh` lifetime can be created:
-                // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
-                // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
-                //    See #59286 for more information.
-                // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
-                // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
-                // there's no case where it could cause the function to fail to compile.
-                let elided =
-                    l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
-                let lifetime = if elided { None } else { Some(l.clean(cx)) };
-                BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(m.ty.clean(cx)) }
-            }
-            TyKind::Slice(ty) => Slice(Box::new(ty.clean(cx))),
-            TyKind::Array(ty, ref length) => {
-                let length = match length {
-                    hir::ArrayLen::Infer(_, _) => "_".to_string(),
-                    hir::ArrayLen::Body(anon_const) => {
-                        let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
-                        // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
-                        // as we currently do not supply the parent generics to anonymous constants
-                        // but do allow `ConstKind::Param`.
-                        //
-                        // `const_eval_poly` tries to to first substitute generic parameters which
-                        // results in an ICE while manually constructing the constant and using `eval`
-                        // does nothing for `ConstKind::Param`.
-                        let ct = ty::Const::from_anon_const(cx.tcx, def_id);
-                        let param_env = cx.tcx.param_env(def_id);
-                        print_const(cx, ct.eval(cx.tcx, param_env))
-                    }
-                };
+pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
+    use rustc_hir::*;
 
-                Array(Box::new(ty.clean(cx)), length)
-            }
-            TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()),
-            TyKind::OpaqueDef(item_id, _) => {
-                let item = cx.tcx.hir().item(item_id);
-                if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
-                    ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
-                } else {
-                    unreachable!()
+    match ty.kind {
+        TyKind::Never => Primitive(PrimitiveType::Never),
+        TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
+        TyKind::Rptr(ref l, ref m) => {
+            // There are two times a `Fresh` lifetime can be created:
+            // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
+            // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
+            //    See #59286 for more information.
+            // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
+            // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
+            // there's no case where it could cause the function to fail to compile.
+            let elided =
+                l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
+            let lifetime = if elided { None } else { Some(l.clean(cx)) };
+            BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
+        }
+        TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
+        TyKind::Array(ty, ref length) => {
+            let length = match length {
+                hir::ArrayLen::Infer(_, _) => "_".to_string(),
+                hir::ArrayLen::Body(anon_const) => {
+                    let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
+                    // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
+                    // as we currently do not supply the parent generics to anonymous constants
+                    // but do allow `ConstKind::Param`.
+                    //
+                    // `const_eval_poly` tries to to first substitute generic parameters which
+                    // results in an ICE while manually constructing the constant and using `eval`
+                    // does nothing for `ConstKind::Param`.
+                    let ct = ty::Const::from_anon_const(cx.tcx, def_id);
+                    let param_env = cx.tcx.param_env(def_id);
+                    print_const(cx, ct.eval(cx.tcx, param_env))
                 }
+            };
+
+            Array(Box::new(clean_ty(ty, cx)), length)
+        }
+        TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
+        TyKind::OpaqueDef(item_id, _) => {
+            let item = cx.tcx.hir().item(item_id);
+            if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
+                ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
+            } else {
+                unreachable!()
             }
-            TyKind::Path(_) => clean_qpath(self, cx),
-            TyKind::TraitObject(bounds, ref lifetime, _) => {
-                let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
-                let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
-                DynTrait(bounds, lifetime)
-            }
-            TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))),
-            // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
-            TyKind::Infer | TyKind::Err => Infer,
-            TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
         }
+        TyKind::Path(_) => clean_qpath(ty, cx),
+        TyKind::TraitObject(bounds, ref lifetime, _) => {
+            let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
+            let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
+            DynTrait(bounds, lifetime)
+        }
+        TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))),
+        // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
+        TyKind::Infer | TyKind::Err => Infer,
+        TyKind::Typeof(..) => panic!("unimplemented type {:?}", ty.kind),
     }
 }
 
@@ -1562,7 +1573,11 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
     }
 }
 
-fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefId>) -> Type {
+pub(crate) fn clean_middle_ty<'tcx>(
+    this: Ty<'tcx>,
+    cx: &mut DocContext<'tcx>,
+    def_id: Option<DefId>,
+) -> Type {
     trace!("cleaning type: {:?}", this);
     let ty = normalize(cx, this).unwrap_or(this);
     match *ty.kind() {
@@ -1573,17 +1588,19 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI
         ty::Uint(uint_ty) => Primitive(uint_ty.into()),
         ty::Float(float_ty) => Primitive(float_ty.into()),
         ty::Str => Primitive(PrimitiveType::Str),
-        ty::Slice(ty) => Slice(Box::new(ty.clean(cx))),
+        ty::Slice(ty) => Slice(Box::new(clean_middle_ty(ty, cx, None))),
         ty::Array(ty, n) => {
             let mut n = cx.tcx.lift(n).expect("array lift failed");
             n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
             let n = print_const(cx, n);
-            Array(Box::new(ty.clean(cx)), n)
-        }
-        ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(mt.ty.clean(cx))),
-        ty::Ref(r, ty, mutbl) => {
-            BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: Box::new(ty.clean(cx)) }
+            Array(Box::new(clean_middle_ty(ty, cx, None)), n)
         }
+        ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
+        ty::Ref(r, ty, mutbl) => BorrowedRef {
+            lifetime: r.clean(cx),
+            mutability: mutbl,
+            type_: Box::new(clean_middle_ty(ty, cx, None)),
+        },
         ty::FnDef(..) | ty::FnPtr(_) => {
             let ty = cx.tcx.lift(this).expect("FnPtr lift failed");
             let sig = ty.fn_sig(cx.tcx);
@@ -1660,7 +1677,7 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI
 
             DynTrait(bounds, lifetime)
         }
-        ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()),
+        ty::Tuple(t) => Tuple(t.iter().map(|t| clean_middle_ty(t, cx, None)).collect()),
 
         ty::Projection(ref data) => clean_projection(*data, cx, def_id),
 
@@ -1747,17 +1764,11 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI
     }
 }
 
-impl<'tcx> Clean<'tcx, Type> for Ty<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
-        clean_ty(*self, cx, None)
-    }
-}
-
 impl<'tcx> Clean<'tcx, Constant> for ty::Const<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant {
         // FIXME: instead of storing the stringified expression, store `self` directly instead.
         Constant {
-            type_: self.ty().clean(cx),
+            type_: clean_middle_ty(self.ty(), cx, None),
             kind: ConstantKind::TyConst { expr: self.to_string() },
         }
     }
@@ -1766,13 +1777,18 @@ impl<'tcx> Clean<'tcx, Constant> for ty::Const<'tcx> {
 impl<'tcx> Clean<'tcx, Item> for hir::FieldDef<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
         let def_id = cx.tcx.hir().local_def_id(self.hir_id).to_def_id();
-        clean_field(def_id, self.ident.name, self.ty.clean(cx), cx)
+        clean_field(def_id, self.ident.name, clean_ty(self.ty, cx), cx)
     }
 }
 
 impl<'tcx> Clean<'tcx, Item> for ty::FieldDef {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        clean_field(self.did, self.name, cx.tcx.type_of(self.did).clean(cx), cx)
+        clean_field(
+            self.did,
+            self.name,
+            clean_middle_ty(cx.tcx.type_of(self.did), cx, Some(self.did)),
+            cx,
+        )
     }
 }
 
@@ -1863,10 +1879,10 @@ impl<'tcx> Clean<'tcx, Path> for hir::Path<'tcx> {
 impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs {
         if self.parenthesized {
-            let output = self.bindings[0].ty().clean(cx);
+            let output = clean_ty(self.bindings[0].ty(), cx);
             let output =
                 if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
-            let inputs = self.inputs().iter().map(|x| x.clean(cx)).collect::<Vec<_>>().into();
+            let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
             GenericArgs::Parenthesized { inputs, output }
         } else {
             let args = self
@@ -1877,7 +1893,7 @@ impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
                         GenericArg::Lifetime(lt.clean(cx))
                     }
                     hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
-                    hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)),
+                    hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
                     hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))),
                     hir::GenericArg::Infer(_inf) => GenericArg::Infer,
                 })
@@ -1925,10 +1941,10 @@ fn clean_maybe_renamed_item<'tcx>(
     cx.with_param_env(def_id, |cx| {
         let kind = match item.kind {
             ItemKind::Static(ty, mutability, body_id) => {
-                StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
+                StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) })
             }
             ItemKind::Const(ty, body_id) => ConstantItem(Constant {
-                type_: ty.clean(cx),
+                type_: clean_ty(ty, cx),
                 kind: ConstantKind::Local { body: body_id, def_id },
             }),
             ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
@@ -1936,8 +1952,8 @@ fn clean_maybe_renamed_item<'tcx>(
                 generics: ty.generics.clean(cx),
             }),
             ItemKind::TyAlias(hir_ty, generics) => {
-                let rustdoc_ty = hir_ty.clean(cx);
-                let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
+                let rustdoc_ty = clean_ty(hir_ty, cx);
+                let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
                 TypedefItem(Typedef {
                     type_: rustdoc_ty,
                     generics: generics.clean(cx),
@@ -1972,15 +1988,14 @@ fn clean_maybe_renamed_item<'tcx>(
                     source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
                 })
             }
-            ItemKind::Trait(is_auto, unsafety, generics, bounds, item_ids) => {
+            ItemKind::Trait(_, _, generics, bounds, item_ids) => {
                 let items =
                     item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
                 TraitItem(Trait {
-                    unsafety,
+                    def_id,
                     items,
                     generics: generics.clean(cx),
                     bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
-                    is_auto: is_auto.clean(cx),
                 })
             }
             ItemKind::ExternCrate(orig_name) => {
@@ -2024,9 +2039,9 @@ fn clean_impl<'tcx>(
         build_deref_target_impls(cx, &items, &mut ret);
     }
 
-    let for_ = impl_.self_ty.clean(cx);
+    let for_ = clean_ty(impl_.self_ty, cx);
     let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) {
-        DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
+        DefKind::TyAlias => Some(clean_middle_ty(tcx.type_of(did), cx, Some(did))),
         _ => None,
     });
     let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
@@ -2235,7 +2250,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
                 ForeignFunctionItem(Function { decl, generics })
             }
             hir::ForeignItemKind::Static(ty, mutability) => {
-                ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None })
+                ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None })
             }
             hir::ForeignItemKind::Type => ForeignTypeItem,
         };
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 8c08f776679..2d364f3402e 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -496,8 +496,7 @@ impl Item {
         // Primitives and Keywords are written in the source code as private modules.
         // The modules need to be private so that nobody actually uses them, but the
         // keywords and primitives that they are documenting are public.
-        let visibility = if matches!(&kind, ItemKind::KeywordItem(..) | ItemKind::PrimitiveItem(..))
-        {
+        let visibility = if matches!(&kind, ItemKind::KeywordItem | ItemKind::PrimitiveItem(..)) {
             Visibility::Public
         } else {
             cx.tcx.visibility(def_id).clean(cx)
@@ -769,7 +768,7 @@ pub(crate) enum ItemKind {
     AssocTypeItem(Typedef, Vec<GenericBound>),
     /// An item that has been stripped by a rustdoc pass
     StrippedItem(Box<ItemKind>),
-    KeywordItem(Symbol),
+    KeywordItem,
 }
 
 impl ItemKind {
@@ -808,7 +807,7 @@ impl ItemKind {
             | TyAssocTypeItem(..)
             | AssocTypeItem(..)
             | StrippedItem(_)
-            | KeywordItem(_) => [].iter(),
+            | KeywordItem => [].iter(),
         }
     }
 }
@@ -1514,11 +1513,19 @@ impl FnRetTy {
 
 #[derive(Clone, Debug)]
 pub(crate) struct Trait {
-    pub(crate) unsafety: hir::Unsafety,
+    pub(crate) def_id: DefId,
     pub(crate) items: Vec<Item>,
     pub(crate) generics: Generics,
     pub(crate) bounds: Vec<GenericBound>,
-    pub(crate) is_auto: bool,
+}
+
+impl Trait {
+    pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
+        tcx.trait_is_auto(self.def_id)
+    }
+    pub(crate) fn unsafety(&self, tcx: TyCtxt<'_>) -> hir::Unsafety {
+        tcx.trait_def(self.def_id).unsafety
+    }
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 22b1e2335fd..00d62b37484 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -2,8 +2,9 @@ use crate::clean::auto_trait::AutoTraitFinder;
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
-    inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item,
-    ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
+    clean_middle_ty, inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs,
+    ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type,
+    TypeBinding, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -69,7 +70,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
             )
         }));
         m.items.extend(keywords.into_iter().map(|(def_id, kw)| {
-            Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem(kw), cx)
+            Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem, cx)
         }));
     }
 
@@ -91,7 +92,7 @@ pub(crate) fn substs_to_args<'tcx>(
             skip_first = false;
             None
         }
-        GenericArgKind::Type(ty) => Some(GenericArg::Type(ty.clean(cx))),
+        GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty(ty, cx, None))),
         GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(ct.clean(cx)))),
     }));
     ret_val
@@ -110,7 +111,7 @@ fn external_generic_args<'tcx>(
         let inputs =
             // The trait's first substitution is the one after self, if there is one.
             match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() {
-                ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect::<Vec<_>>().into(),
+                ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(t, cx, None)).collect::<Vec<_>>().into(),
                 _ => return GenericArgs::AngleBracketed { args: args.into(), bindings: bindings.into() },
             };
         let output = None;
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 0e9a9e0e506..f46fde7b35a 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -390,8 +390,7 @@ pub(crate) fn run_global_ctxt(
     //
     // Note that in case of `#![no_core]`, the trait is not available.
     if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
-        let mut sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
-        sized_trait.is_auto = true;
+        let sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
         ctxt.external_traits
             .borrow_mut()
             .insert(sized_trait_did, TraitWithExtraInfo { trait_: sized_trait, is_notable: false });
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index 336448904d1..c93897236db 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -69,7 +69,7 @@ pub(crate) trait DocFolder: Sized {
             | AssocConstItem(..)
             | TyAssocTypeItem(..)
             | AssocTypeItem(..)
-            | KeywordItem(_) => kind,
+            | KeywordItem => kind,
         }
     }
 
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index d7276a427c4..b9774eb70ea 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -413,7 +413,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             | clean::TyAssocTypeItem(..)
             | clean::AssocTypeItem(..)
             | clean::StrippedItem(..)
-            | clean::KeywordItem(..) => {
+            | clean::KeywordItem => {
                 // FIXME: Do these need handling?
                 // The person writing this comment doesn't know.
                 // So would rather leave them to an expert,
diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index 9cb3327d7c7..0a7ee200591 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -91,7 +91,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
             clean::TyAssocConstItem(..) | clean::AssocConstItem(..) => ItemType::AssocConst,
             clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType,
             clean::ForeignTypeItem => ItemType::ForeignType,
-            clean::KeywordItem(..) => ItemType::Keyword,
+            clean::KeywordItem => ItemType::Keyword,
             clean::TraitAliasItem(..) => ItemType::TraitAlias,
             clean::ProcMacroItem(ref mac) => match mac.kind {
                 MacroKind::Bang => ItemType::Macro,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index c1fdece9ec6..89d372da322 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2295,7 +2295,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
     sidebar_assoc_items(cx, buf, it);
 
     print_sidebar_title(buf, "implementors", "Implementors");
-    if t.is_auto {
+    if t.is_auto(cx.tcx()) {
         print_sidebar_title(buf, "synthetic-implementors", "Auto Implementors");
     }
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index daacc57a55a..81cc12c9d55 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -104,7 +104,7 @@ pub(super) fn print_item(
         clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ",
         clean::ConstantItem(..) => "Constant ",
         clean::ForeignTypeItem => "Foreign Type ",
-        clean::KeywordItem(..) => "Keyword ",
+        clean::KeywordItem => "Keyword ",
         clean::OpaqueTyItem(..) => "Opaque Type ",
         clean::TraitAliasItem(..) => "Trait Alias ",
         _ => {
@@ -175,7 +175,7 @@ pub(super) fn print_item(
         clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i),
         clean::ConstantItem(ref c) => item_constant(buf, cx, item, c),
         clean::ForeignTypeItem => item_foreign_type(buf, cx, item),
-        clean::KeywordItem(_) => item_keyword(buf, cx, item),
+        clean::KeywordItem => item_keyword(buf, cx, item),
         clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e),
         clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta),
         _ => {
@@ -548,8 +548,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
                 w,
                 "{}{}{}trait {}{}{}",
                 it.visibility.print_with_space(it.item_id, cx),
-                t.unsafety.print_with_space(),
-                if t.is_auto { "auto " } else { "" },
+                t.unsafety(cx.tcx()).print_with_space(),
+                if t.is_auto(cx.tcx()) { "auto " } else { "" },
                 it.name.unwrap(),
                 t.generics.print(cx),
                 bounds
@@ -883,7 +883,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
         }
         w.write_str("</div>");
 
-        if t.is_auto {
+        if t.is_auto(cx.tcx()) {
             write_small_section_header(
                 w,
                 "synthetic-implementors",
@@ -912,7 +912,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
             "<div class=\"item-list\" id=\"implementors-list\"></div>",
         );
 
-        if t.is_auto {
+        if t.is_auto(cx.tcx()) {
             write_small_section_header(
                 w,
                 "synthetic-implementors",
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index c6933a8254b..70b7a47bcd5 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -216,6 +216,15 @@ details.rustdoc-toggle > summary::before,
 div.impl-items > div:not(.docblock):not(.item-info),
 .content ul.crate a.crate,
 a.srclink,
+#main-content > .since,
+#help-button > button,
+details.rustdoc-toggle.top-doc > summary,
+details.rustdoc-toggle.top-doc > summary::before,
+details.rustdoc-toggle.non-exhaustive > summary,
+details.rustdoc-toggle.non-exhaustive > summary::before,
+.scraped-example-title,
+.more-examples-toggle summary, .more-examples-toggle .hide-more,
+.example-links a,
 /* This selector is for the items listed in the "all items" page. */
 #main-content > ul.docblock > li > a {
 	font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
@@ -702,7 +711,6 @@ pre, .rustdoc.source .example-wrap {
 }
 #main-content > .since {
 	top: inherit;
-	font-family: "Fira Sans", Arial, sans-serif;
 }
 
 .content table:not(.table-display) {
@@ -949,7 +957,7 @@ table,
 #crate-search {
 	min-width: 115px;
 	margin-top: 5px;
-	padding-left: 0.3125em;
+	padding-left: 0.15em;
 	padding-right: 23px;
 	border: 1px solid;
 	border-radius: 4px;
@@ -958,8 +966,6 @@ table,
 	-moz-appearance: none;
 	-webkit-appearance: none;
 	/* Removes default arrow from firefox */
-	text-indent: 0.01px;
-	text-overflow: "";
 	background-repeat: no-repeat;
 	background-color: transparent;
 	background-size: 20px;
@@ -986,7 +992,6 @@ table,
 	border-radius: 2px;
 	padding: 8px;
 	font-size: 1rem;
-	transition: border-color 300ms ease;
 	width: 100%;
 }
 
@@ -1521,7 +1526,6 @@ input:checked + .slider {
 }
 
 #help-button > button {
-	font-family: "Fira Sans", Arial, sans-serif;
 	text-align: center;
 	/* Rare exception to specifying font sizes in rem. Since this is acting
 	   as an icon, it's okay to specify their sizes in pixels. */
@@ -1693,7 +1697,6 @@ details.rustdoc-toggle.top-doc > summary,
 details.rustdoc-toggle.top-doc > summary::before,
 details.rustdoc-toggle.non-exhaustive > summary,
 details.rustdoc-toggle.non-exhaustive > summary::before {
-	font-family: 'Fira Sans';
 	font-size: 1rem;
 }
 
@@ -2179,10 +2182,6 @@ in storage.js plus the media query with (min-width: 701px)
 	border-radius: 50px;
 }
 
-.scraped-example-title {
-	font-family: 'Fira Sans';
-}
-
 .scraped-example .code-wrapper {
 	position: relative;
 	display: flex;
@@ -2286,10 +2285,6 @@ in storage.js plus the media query with (min-width: 701px)
 	cursor: pointer;
 }
 
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
-	font-family: 'Fira Sans';
-}
-
 .more-scraped-examples {
 	margin-left: 5px;
 	display: flex;
@@ -2324,7 +2319,6 @@ in storage.js plus the media query with (min-width: 701px)
 
 .example-links a {
 	margin-top: 20px;
-	font-family: 'Fira Sans';
 }
 
 .example-links ul {
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 142ce456c52..7ff8063904a 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -184,7 +184,13 @@ details.rustdoc-toggle > summary::before {
 
 #crate-search, .search-input {
 	background-color: #141920;
-	/* Without the `!important`, the border-color is ignored for `<select>`... */
+	border-color: #424c57;
+}
+
+#crate-search {
+	/* Without the `!important`, the border-color is ignored for `<select>`...
+	   It cannot be in the group above because `.search-input` has a different border color on
+	   hover. */
 	border-color: #424c57 !important;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index aeaca7515f9..8e753f57682 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -159,7 +159,13 @@ details.rustdoc-toggle > summary::before {
 #crate-search, .search-input {
 	color: #111;
 	background-color: #f0f0f0;
-	/* Without the `!important`, the border-color is ignored for `<select>`... */
+	border-color: #f0f0f0;
+}
+
+#crate-search {
+	/* Without the `!important`, the border-color is ignored for `<select>`...
+	   It cannot be in the group above because `.search-input` has a different border color on
+	   hover. */
 	border-color: #f0f0f0 !important;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 54d1a7b65d6..40d965c39c3 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -146,7 +146,13 @@ details.rustdoc-toggle > summary::before {
 
 #crate-search, .search-input {
 	background-color: white;
-	/* Without the `!important`, the border-color is ignored for `<select>`... */
+	border-color: #e0e0e0;
+}
+
+#crate-search {
+	/* Without the `!important`, the border-color is ignored for `<select>`...
+	   It cannot be in the group above because `.search-input` has a different border color on
+	   hover. */
 	border-color: #e0e0e0 !important;
 }
 
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 9000ab472d9..5f3dd570610 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -43,7 +43,7 @@ impl JsonRenderer<'_> {
         let span = item.span(self.tcx);
         let clean::Item { name, attrs: _, kind: _, visibility, item_id, cfg: _ } = item;
         let inner = match *item.kind {
-            clean::KeywordItem(_) => return None,
+            clean::KeywordItem => return None,
             clean::StrippedItem(ref inner) => {
                 match &**inner {
                     // We document non-empty stripped modules as with `Module::is_stripped` set to
@@ -269,7 +269,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
             default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
         },
         // `convert_item` early returns `None` for stripped items and keywords.
-        KeywordItem(_) => unreachable!(),
+        KeywordItem => unreachable!(),
         StrippedItem(inner) => {
             match *inner {
                 ModuleItem(m) => ItemEnum::Module(Module {
@@ -554,10 +554,12 @@ impl FromWithTcx<clean::FnDecl> for FnDecl {
 
 impl FromWithTcx<clean::Trait> for Trait {
     fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self {
-        let clean::Trait { unsafety, items, generics, bounds, is_auto } = trait_;
+        let is_auto = trait_.is_auto(tcx);
+        let is_unsafe = trait_.unsafety(tcx) == rustc_hir::Unsafety::Unsafe;
+        let clean::Trait { items, generics, bounds, .. } = trait_;
         Trait {
             is_auto,
-            is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
+            is_unsafe,
             items: ids(items, tcx),
             generics: generics.into_tcx(tcx),
             bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 735a077fe1f..e80a94fe749 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -69,7 +69,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
                 | clean::ExternCrateItem { .. }
                 | clean::ImportItem(_)
                 | clean::PrimitiveItem(_)
-                | clean::KeywordItem(_)
+                | clean::KeywordItem
                 // check for trait impl
                 | clean::ImplItem(clean::Impl { trait_: Some(_), .. })
         )
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 83d8fe9ef11..1751249fa62 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -4,7 +4,10 @@
 
 use pulldown_cmark::LinkType;
 use rustc_ast::util::comments::may_have_doc_links;
-use rustc_data_structures::{fx::FxHashMap, intern::Interned, stable_set::FxHashSet};
+use rustc_data_structures::{
+    fx::{FxHashMap, FxHashSet},
+    intern::Interned,
+};
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{DefKind, Namespace, PerNS};
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 5f2f50e712b..0d419042a10 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -98,7 +98,7 @@ impl<'a> DocFolder for Stripper<'a> {
             clean::PrimitiveItem(..) => {}
 
             // Keywords are never stripped
-            clean::KeywordItem(..) => {}
+            clean::KeywordItem => {}
         }
 
         let fastreturn = match *i.kind {
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index 75e1dd41a63..0bb41977c97 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -43,7 +43,7 @@ pub(crate) trait DocVisitor: Sized {
             | AssocConstItem(..)
             | TyAssocTypeItem(..)
             | AssocTypeItem(..)
-            | KeywordItem(_) => {}
+            | KeywordItem => {}
         }
     }
 
diff --git a/src/stage0.json b/src/stage0.json
index ab8a79e2af5..aa80d08e084 100644
--- a/src/stage0.json
+++ b/src/stage0.json
@@ -17,349 +17,349 @@
     "tool is executed."
   ],
   "compiler": {
-    "date": "2022-06-29",
+    "date": "2022-07-16",
     "version": "beta"
   },
   "rustfmt": {
-    "date": "2022-06-29",
+    "date": "2022-07-21",
     "version": "nightly"
   },
   "checksums_sha256": {
-    "dist/2022-06-29/cargo-beta-aarch64-apple-darwin.tar.gz": "8e50ef7a6fbc0e7212621e124de66d123b9c772a04cdb04b5528cb68543f89d0",
-    "dist/2022-06-29/cargo-beta-aarch64-apple-darwin.tar.xz": "f74e110c8740321406acde67c37fc3dbb47e9d98e25bf20f5ad19790b89b9b9c",
-    "dist/2022-06-29/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "14067f4013c5e112531ee4f76e7ba61149b46a67d1d8bf0256dc2ee1410f44c9",
-    "dist/2022-06-29/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "9252a221a244308228a16f5e9729755d9f09421e2e316ea82f64da1d9a8c4725",
-    "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "38c0b9186fb251a6ac15ced667d3cd719e81acc0eb7a92303c6422c92b701842",
-    "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "b328753578ecb5ca9578f9ac89107804249eb4f802ca0f07c9bdd063aab931b5",
-    "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "747d836695e7a385e6af22911966f72410abafe8b400b33690804e4290e750ee",
-    "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "94cb8c5e70ba4da6de86777c3c2092ab0616da9d12fbff6928e901fd6c48c099",
-    "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "d3fa253a3a470d65f726dd59201c3b6e90e8d2343d3b5a1d27ba395d16ebe025",
-    "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "84f4684cb6e86e58279b768e8cc00c55da09a0ee8cdad77dfe4153748eaa3b60",
-    "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "58c3faea04e4a21425555afa5486e2f7704c8e5d5773cda73d618b1049e0575d",
-    "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "6b16b89b4e7b3ca9ba6ca7b0ae881aeb7c81a450ff4f32eca3d0907aadf10fd1",
-    "dist/2022-06-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "eb504aea2b96402b371e7b7bba7cbc5fdeb9f470be70927b11a340b5937513be",
-    "dist/2022-06-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c78dba1f0c58a7e8817ee9d5ddeb377e087432a1375ea3d99ee27b4a9f7d0ba2",
-    "dist/2022-06-29/cargo-beta-i686-pc-windows-gnu.tar.gz": "4d29aed70bd5df7525c8c8e8d88cdabee235c229821a9adba08c38a3a7e3b967",
-    "dist/2022-06-29/cargo-beta-i686-pc-windows-gnu.tar.xz": "2fdb9c3c42a3c97d3f8eec7b0e4bcd7a6db24abdf928d51a3c645f24aa7e41a4",
-    "dist/2022-06-29/cargo-beta-i686-pc-windows-msvc.tar.gz": "afdb95f020eb318ea66b3150593787ead14f1e8590ab950bec5516d1641c39da",
-    "dist/2022-06-29/cargo-beta-i686-pc-windows-msvc.tar.xz": "f1156f6f02262d12c777cee11d02b9c5cf9b4f28a27f4f9de9c154a8843d3d4b",
-    "dist/2022-06-29/cargo-beta-i686-unknown-linux-gnu.tar.gz": "aa972fcd1411e69464233fc54f34ac09aa04eb593410c7345718495e2ba684f9",
-    "dist/2022-06-29/cargo-beta-i686-unknown-linux-gnu.tar.xz": "ffa60e4ef87e7bb7229be6cd14f562d652e30e5badaa5892c0a7bc9563c56fbe",
-    "dist/2022-06-29/cargo-beta-mips-unknown-linux-gnu.tar.gz": "cb827715805de35449a17b190e1cb978bcd7d8b0a5501fe06d8f4313dce5b06d",
-    "dist/2022-06-29/cargo-beta-mips-unknown-linux-gnu.tar.xz": "63bc1122b296a89371d4a3560c06e1ce2f3a00482879d0ded87bd52f87fdec9e",
-    "dist/2022-06-29/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "b4d4222040865e4aa1d034f85511f436e08a1502c5213b6eacaf103d417755c6",
-    "dist/2022-06-29/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e1d19f8de4278c01914d3999038c49001c214ab9ec5286beab327322d30fb564",
-    "dist/2022-06-29/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "b82d0a96510ca9933540bd8fc1534a1f91f92f92512a018b10cc007240ea13f1",
-    "dist/2022-06-29/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "e4805b270f9763adef25a0f970d28d2d69a92ddd9ab6d7f14fa746ad61b4e635",
-    "dist/2022-06-29/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "f3f9ed7f57299511610bf0d44abc79d9a0cf994c979546895b9a42b72b17734f",
-    "dist/2022-06-29/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "08c1c3cef4f257841f9600bfe2f67312cd76fbeca1e4326963715ca77668a0eb",
-    "dist/2022-06-29/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "1a1bba0cb974217cbff68001c83270c631f13193b5e3227f22a8b32613f7d570",
-    "dist/2022-06-29/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "cb32c1d4addc20433b15751db0da67cef5bcc576c17319bd79566596c153af80",
-    "dist/2022-06-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "7b6713071c93bdbb68f80f4045deaa8078382abe3179c60c92e0de5a0d93f161",
-    "dist/2022-06-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "313e6b05c3178b7e481ab09b71c1491b7136a47a9577649506823bdc698b279d",
-    "dist/2022-06-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0d7d4dc600ff03857b60767c50a79c0de8a0a6a78ef3f309121b8338583526c5",
-    "dist/2022-06-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "4b7d7da12ffe1ee279db21f6ef5b6124330ccee03711f3801561f68b303e15c0",
-    "dist/2022-06-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "154938148945148682bd165836e503064c248752cb24f1437d20a3ad128d6c91",
-    "dist/2022-06-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "be4c8a5b14fa9db00ad2f8efac052bbd6f7981610baf692b1d01f3bfb3be96f4",
-    "dist/2022-06-29/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "9ed70575f47e5a6bec063ed19eff165e35efbf6941403def15e48bf6560b949a",
-    "dist/2022-06-29/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "ad90bd85638cf26ecd72ffc0b09d1384c64fb990b4aa62f69e39d205609ba06f",
-    "dist/2022-06-29/cargo-beta-x86_64-apple-darwin.tar.gz": "54f71eff8e1ad3d22f49106b2c7b04713e7927a3f54cfc452c61e810e2b57129",
-    "dist/2022-06-29/cargo-beta-x86_64-apple-darwin.tar.xz": "b3f136e3d2bd5776887fb0071bc6434a1eb2cd42fccfe95eb8a32ca1bd36de29",
-    "dist/2022-06-29/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "e57239d7d3b889ec4dad8db20bbaa0140a2f0a471ab62e4a1c48558490f33d36",
-    "dist/2022-06-29/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "4f14c69c15e3038508df42e254027f0b59ed798cc26f0952fcaa8068341fb55b",
-    "dist/2022-06-29/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "2898e0a9dc793fe85835b8167b8e4e4cd4d0b044fff37a85034624a92a8e8f76",
-    "dist/2022-06-29/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "667a8a268fda0c44878498b2c68239bfe7387d9d8f9d39ec4445a79409e65a1a",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-freebsd.tar.gz": "da4ab4baae0f241653591c0f69091724ac8949b18e261c69069ff368f86e76b3",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-freebsd.tar.xz": "333295a07edac2f7aa9acec4284c3f2417ec764a9c09e8735ebbb69621d80aa5",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-illumos.tar.gz": "3b0899c1cdeebe01d8dabf5d0cd4f9762c07012e874111c77909840f917295d0",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-illumos.tar.xz": "ad698922172524912ecba24c966df6bdf18a21e530c2467d835c297709f1f413",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "f9efa10a31e31857644ecd8877b08ae96f80962bc96efbb374128220d659c2c5",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "5392a4bc11097ac95e208c9cea7b0773b966f713f3b1e0ba42f1323484b1d27c",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "a6177b8b69eb5d4bd3507d50054009734854775f8821b74b6ad603cda1e0b351",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "33a00ce744789c49438fe8accf40a17c99282339ca69adc7a3e8a810cad9f1f0",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-netbsd.tar.gz": "4b042e30402804c20abd84b39384b0b7d88743d27a9f0a34f90d7626f07a4f47",
-    "dist/2022-06-29/cargo-beta-x86_64-unknown-netbsd.tar.xz": "2e9fe2e92129a3952f1ae32760fd818a637b829a575194b84ab6d793d74c2c04",
-    "dist/2022-06-29/rust-std-beta-aarch64-apple-darwin.tar.gz": "031b3c2134e2c54aeb29ba2e46a5b6db11c65ff3a364cedd14c79d741a1f9ddc",
-    "dist/2022-06-29/rust-std-beta-aarch64-apple-darwin.tar.xz": "55f82ac681d5c8b6f0777939e747e8856707822e34b3060e9a85ec5935c8a406",
-    "dist/2022-06-29/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "53cc84de66c0c70b988b6136aa55c4051e51d27952e67db066ea409d56166fbb",
-    "dist/2022-06-29/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "6e9fa64aa157eb32e3ea4deb8d42256e5bbfee5fd4dae111f107033d792d28ad",
-    "dist/2022-06-29/rust-std-beta-aarch64-apple-ios.tar.gz": "d0e27984f1a2133af4e2fe9fd79a22f3e8a792a81111a496f80cfd9f3019b5e0",
-    "dist/2022-06-29/rust-std-beta-aarch64-apple-ios.tar.xz": "404780fc534501fbdd6fb34aeb3f338086feadebfef420a9530c6c4b48b803bb",
-    "dist/2022-06-29/rust-std-beta-aarch64-fuchsia.tar.gz": "bdafb54b1798812a0144029c421cc784a441ee82fc433f5788712f2c05fe4391",
-    "dist/2022-06-29/rust-std-beta-aarch64-fuchsia.tar.xz": "198be344c4a1c4247d8fb21efd9c84787272c0ae6208b341cae508adb8ba0ca4",
-    "dist/2022-06-29/rust-std-beta-aarch64-linux-android.tar.gz": "9c51ebdba4c211050cc8c6733e21faec7d7fb2591abb38226b0593f449d7e8b2",
-    "dist/2022-06-29/rust-std-beta-aarch64-linux-android.tar.xz": "f97595685703d22b0689b3f2822b3f69780eefc74a3169fdd1cf1d9a4538342d",
-    "dist/2022-06-29/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "2c32867f2e8ef81d1a8b0b3af14055be79f1da6dfe514155c9f9fd1eb98a99bb",
-    "dist/2022-06-29/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "bfc34e4077ece9675ed044a0e518bf8c38d0f351b62b6ea0d674f0c77c7af671",
-    "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "547505e533d6654d33df44e362cb421ea8fc69458efe51a357afc3665e19c826",
-    "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "f14478bd5bc6fea393111cd6f2dbbd1bc5a8d50adf0faa95b6d804c882d30415",
-    "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "ed17ac700cb1e4e773fd832c59aec036cebad714009786fec422077af35336e8",
-    "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "32b670e1e29d50c8af4ec0647b34855a07f9ab7a0142305a6a629cd4124c067e",
-    "dist/2022-06-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "225d33281ca9c69c3cdea76714e0383ae543c4f778859dd63cdd37dac09fa9d4",
-    "dist/2022-06-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "d55f5260e2c50a608f760d50e7fa653284f2a8b8a64588a80dfb13419061b014",
-    "dist/2022-06-29/rust-std-beta-aarch64-unknown-none.tar.gz": "3719244c77c4d5870accfe562f30a9dc3290a14dc3da399e64909402d116c482",
-    "dist/2022-06-29/rust-std-beta-aarch64-unknown-none.tar.xz": "78bb343bb519070c0761ea7ed3c4e56b6d821095ac931ad7f812743600dffb64",
-    "dist/2022-06-29/rust-std-beta-arm-linux-androideabi.tar.gz": "452973239e8c0995a8b9522417e020b883f2f4052764b18b8cd50c9d08cb4f14",
-    "dist/2022-06-29/rust-std-beta-arm-linux-androideabi.tar.xz": "b1952ef69d1c4c32bc0aad4b4beddc6e6bd56155eafce1ffcaafceff8cb6d77d",
-    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "c1ad87f6a2f4e1bc1eb2f732285546fb062faad9b27c4dc248ff174e4a2ec60e",
-    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "ef6611b0ee43efdfc0a27dc3a7b65eeb8cba0d10624233fb473d521392c7d3f4",
-    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "4efd4c3e06a3bc3c2f873901a956827e69cecfd38ed62ba1d8cfaf979d6a67e6",
-    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "2c99a7541c6ca5b1c1fad00e76736e74d7ae50af3cd891aeed8f4f8747d4292d",
-    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "3d5c2be1e0e5b4ce33e2aa4765e869872b247709db1b194512d12146be439c80",
-    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e0b7e25f78e29a62d05eec6220000bcee815bcda24d857225ae47fcf3612fcf9",
-    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "0639d8e52de274f02f34ca547a2c692defb329bae290a4ee977b05e9a3deca52",
-    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "256a4ddafddacad0024be539cb038e7742b37f34038a774a06e9a43b29558d5a",
-    "dist/2022-06-29/rust-std-beta-armebv7r-none-eabi.tar.gz": "468113b22041adf0b7746838643ee316063f6049c20d499aa52ac2d9241091ce",
-    "dist/2022-06-29/rust-std-beta-armebv7r-none-eabi.tar.xz": "5b614aa0b7a360a8ee79bb0dca0b2adc3cc0b8f4f2266806bfb0d07b811c11d0",
-    "dist/2022-06-29/rust-std-beta-armebv7r-none-eabihf.tar.gz": "d13f0a0abcc35bf6ccd035ba9bdd5b0760b995c885902bae73cf8a22cddc847e",
-    "dist/2022-06-29/rust-std-beta-armebv7r-none-eabihf.tar.xz": "c7ffd2f6df10e754480bb1cb84b823084cf95cb6bbae2017437d5b9ffcd90b77",
-    "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "ad94a6356dbee95031bd943212eedc441d596cb11da1206010cef611e436975f",
-    "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "b8c78492bb88d317580d01e96a70d9eb42d2f9f8396806bd810e348706924d25",
-    "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "cd09bcb2d9d9fa25ddbcc81d9bf2ed2e68a177a1d61e1f9611516c95ca4f5e3e",
-    "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "efd2795a1484cd7331cbd849757a3b6cdbd50ae466bff760d9ec8e7ff965536f",
-    "dist/2022-06-29/rust-std-beta-armv7-linux-androideabi.tar.gz": "10ac8daf897263a1c51f0ed9df13f707261048c6d11e7a024470ba71c3d3ef34",
-    "dist/2022-06-29/rust-std-beta-armv7-linux-androideabi.tar.xz": "3968db993db3c861856dfa0974207b0709fba871cc17bc857c29f59063af15e5",
-    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "33d19cbc173f71771b7a00a009789eef8f0b2cf65072642e0689bb86b191df4c",
-    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "e896810ee1322ed011d662678839161e7c39faa27f1a8af963bc0a1e3b40a88f",
-    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "d6b81169c6b77b7b93e03ac2d8289539e7ce6436106709f63b79a195b98d6fe8",
-    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "6db5dfcdb0bba850db005a11e76cb3750befde0b6ef03b600c3c0e67a4c5d46a",
-    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "5a729bb3471ccd07de54ca8fbc570fb617d4ba059a620754becc7aa48620f092",
-    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "deb76d6f0bb0e4c9931df9976e869dcfc2548a851a06db89d656856bcab4fa8a",
-    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "464bcf3a881d107747e241f88e71361dc5cabe7c27fe0e0f370c7ef90f8b77ad",
-    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0b66291a56ea5b7aa6b194fcf08d844a067940a3ec4cac11a377c87947a5cf4e",
-    "dist/2022-06-29/rust-std-beta-armv7a-none-eabi.tar.gz": "583e0b2e03386dcc0397dec2802659937e73dad04a52263218128ee2bab8c412",
-    "dist/2022-06-29/rust-std-beta-armv7a-none-eabi.tar.xz": "b9ebb07f4b461cef81b5fbbb38ac89245f4df13215fc64ad04e6972c1c2d405a",
-    "dist/2022-06-29/rust-std-beta-armv7r-none-eabi.tar.gz": "12a5b49d776cbdb26a1a6c1e2c38d62f562cf9f99fd4868da317b08d4df1bb84",
-    "dist/2022-06-29/rust-std-beta-armv7r-none-eabi.tar.xz": "a1b7b2c27236e36893056dccfd9d15db906db53e8c0f931d1dfc9daa147642a0",
-    "dist/2022-06-29/rust-std-beta-armv7r-none-eabihf.tar.gz": "9d1f6a6694e82528a6dc98d94f63aa253c0f2eac2cf1e9db97fb1fd9d9e68f46",
-    "dist/2022-06-29/rust-std-beta-armv7r-none-eabihf.tar.xz": "179e6d158a2f27bca2be54059414526de20de76a9eaf26c99e01ef9b1c7743be",
-    "dist/2022-06-29/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "eda6db1398471b8cda7b7449ba86db47587398c7b322e995039f59caabe8c815",
-    "dist/2022-06-29/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "9a079f124309edf9a187a0980b59085f5a1cb9c94236154a9f53cd7ca67a71e9",
-    "dist/2022-06-29/rust-std-beta-i586-pc-windows-msvc.tar.gz": "af4a7d3da748a9f2ff867fb7e6b87e0b4696904bab60a2e38df21cf41c658ee3",
-    "dist/2022-06-29/rust-std-beta-i586-pc-windows-msvc.tar.xz": "420801efc6deddaaee5a7e17672e0ff520d965ece9a2b8aa1534d86ce839777b",
-    "dist/2022-06-29/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "82d3b6bbc71b5e138f8715bfcba5107f0d1cde6aee8fe6bddaf85fa646ddf1d1",
-    "dist/2022-06-29/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "1eba8240509d6d5d0650f7e8e42cce89246aa1d416b859db496013d83983d4bd",
-    "dist/2022-06-29/rust-std-beta-i586-unknown-linux-musl.tar.gz": "d846e2ea559ad467945369d8230321734cca6634b8d1a4088475f8cafc9854d8",
-    "dist/2022-06-29/rust-std-beta-i586-unknown-linux-musl.tar.xz": "d5d8df8255a252af0c3eb66596d42a6d6cb9fcf3036fa8ab3f85ca1f344394c0",
-    "dist/2022-06-29/rust-std-beta-i686-linux-android.tar.gz": "55bca00de9caed1f5443592373b8a2581b1bc1ade24bd062a8f2ba396c82e520",
-    "dist/2022-06-29/rust-std-beta-i686-linux-android.tar.xz": "4db58c08b4e58584bf1a38205f100e0bfe79a74a4ff00280d5a29a3367302ca3",
-    "dist/2022-06-29/rust-std-beta-i686-pc-windows-gnu.tar.gz": "76c72088f1d77d84270b8ad00ee87a79cc8607c852291c5d2b82f59e6efd96cd",
-    "dist/2022-06-29/rust-std-beta-i686-pc-windows-gnu.tar.xz": "17eb428984599dd696554d9710cec60fcb01c8d341c0e59a0c1c00370c0d9c72",
-    "dist/2022-06-29/rust-std-beta-i686-pc-windows-msvc.tar.gz": "9dd0184f99be287f318952ace8190af2cd7accc47a7b3f388d34c77cff60c5ae",
-    "dist/2022-06-29/rust-std-beta-i686-pc-windows-msvc.tar.xz": "d76d255d3db0b9a5b5e8b1670b3eff4feaed8dc938187a6783a3323fb4998b8a",
-    "dist/2022-06-29/rust-std-beta-i686-unknown-freebsd.tar.gz": "8f8d60ba72543402b0c62bd68192891ee290fc7daff104e9ff8b10c9d109d791",
-    "dist/2022-06-29/rust-std-beta-i686-unknown-freebsd.tar.xz": "030629f57e1f05c7a1e96a147f7a2086c0968a6abfecbd375f9093c4a2859fbb",
-    "dist/2022-06-29/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "a5d01dba11d59ac1a11404905c54425594bc69f40cad8814d3ffd00d1b38c52a",
-    "dist/2022-06-29/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "5f2ea9f7e62fb429f4f0575a267eb46a014b9ae727939f909ec5e3777e32e65b",
-    "dist/2022-06-29/rust-std-beta-i686-unknown-linux-musl.tar.gz": "6e76c8616ee86d1b51c9b055b324f715c1a9cbb1c1564982d1f7e6fd623cd292",
-    "dist/2022-06-29/rust-std-beta-i686-unknown-linux-musl.tar.xz": "54641f169e424a73cb386e41563af5ed9ba833379edc148579f67bdcdab281ba",
-    "dist/2022-06-29/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "64303412deb9264dfd15a16341203df39af2e9206ce1d22ca5eaa83762e1f62a",
-    "dist/2022-06-29/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "4c4cb3fb0ee51f9294cb805c7263f716a921e7d76503cbbd24f8600c485c58aa",
-    "dist/2022-06-29/rust-std-beta-mips-unknown-linux-musl.tar.gz": "e197dab9c9b11cf98404aed094d1d8bc03a6755ebf4046423c11baeb0143f254",
-    "dist/2022-06-29/rust-std-beta-mips-unknown-linux-musl.tar.xz": "81a80fa315dc3da8111f487b9dd6dbe56991276fac138de4469c0e0b688bae07",
-    "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "9cc065dd7fe550716efa403c910d9eaf8c18d90d7d3e316772fac72f7f16c45f",
-    "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "6bde95f6c57f6ce4de4f1ce9837b386e374eb291d8778956bee0956b150c3917",
-    "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "1262105c31f7ec6248b24b71f0003014a8558220444cfc88c611ad2aa94efebd",
-    "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "cb35ba7184ba5a74f5d6c8592e67e08faed205e091784f85137872e02541ae99",
-    "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "31d7af84b431c9185b2ef98c18eaadb957e22e427b331a8ed4ab8b2b6ae364ae",
-    "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "674b1c886ae4a2273edd6e49539d45a2a02e73874f6a65ba820dbea75d8ca8c6",
-    "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "cc620438e90fbd086b4f237454b099a81e4cc3dae9582e7526b2a10648663e4c",
-    "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "425ce38ad1bb048756a37e8642ab6b43f8189bee244e4ee011e95fd45f3a3747",
-    "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "40b0df32d5df53fe8774000804738d56e7c8768cba1baaf52721a9956d62c557",
-    "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7df34f8ddb1b14698c6473eaaeffd5d6da23ddcde23a74a3482194e01fa5ace7",
-    "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "65b3db3bac29c8aad57c8cabe7fbe622acfdcd9221c11af4419d74c24452a939",
-    "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "9a4a382945631425fc8227d6b42d0f97988dc39c8e79646280e080595d82aa31",
-    "dist/2022-06-29/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "30fc151ae3a6423e027aacd70bcd45d13243aa5394ff2d6cf285c55d3c5c6e23",
-    "dist/2022-06-29/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "28cef1191d2181004b8e5032bc3f7b548996149dac8ffb5b8a5431b32d396683",
-    "dist/2022-06-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "a6b79a07cdd6cd6d0e468132ab504464e3d6c41f28111cf15c6053d7d560b8b7",
-    "dist/2022-06-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "67aa93c917f234b0b61dbd3fac21a1d6d4ef20cc8dd7fdc6a8bb8e688e3920ca",
-    "dist/2022-06-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "e4dd3483a85060d75a7dff95dda7a121943f1121983e5d33eff166f4c3e97e6c",
-    "dist/2022-06-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "36f2b7305e8ed58666c206c26e28cc5e8708fdf104f1d67dd0c692f9e36a1482",
-    "dist/2022-06-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "f232913783443410614af3e27a832740b06d392563f5d0aa6d0ac0558d7bbb6f",
-    "dist/2022-06-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f54f1f0c7fe7b31ff97bde512573225f7380bd1c35876862ea798fc2b38cd4fc",
-    "dist/2022-06-29/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "728135a1f7c89a129c78c2adf360ab06feb79f28b10f993797d498a9effab9e9",
-    "dist/2022-06-29/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "ba91db121409dc9414377759fd27e8947e46dbb9f3788521d82a67b063c2a9d6",
-    "dist/2022-06-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "c092940c2eaea9c9168061b8f5b87f1b735c1d0ffe05bc834252719c42f3ff33",
-    "dist/2022-06-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "2906008d17bb17bc84709d8e47c8c065b2749355240e630cdb1f0c173721a05a",
-    "dist/2022-06-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "7815f8bf5838e2f497e2d42cad55c3e738f64957e031af90f82d80fa7ce78f1a",
-    "dist/2022-06-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "16bbac000585cc3985582698b42635d1e3af68445e2ef4340600087e1fc38e26",
-    "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "2fdb717d0fa4f3e162ab8603d2b5233c6ec20a587af874d0987b1b040ea95dfa",
-    "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f4f2445d1e9f8cd0af34ce0063a44041465df0b6d5b73546595d0d37f0342087",
-    "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "a2df1578a4ec47fb925102fd6604add216ed7d27bdf323176328afef48f2faca",
-    "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "e3839aa18e35d7d050ce00210774a63b84b3070bc28be1d70ffd4c939b6d8cc0",
-    "dist/2022-06-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "4ad1c23982c5d5b45935e52fc1a0e36e08e853a993a0adb5c9fb9e703ee2cb7f",
-    "dist/2022-06-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "1308041c43eca228f265cd1cdb3d419bb7e4e1461e117536b719cc3ec8527798",
-    "dist/2022-06-29/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "0fdbbe00f9b655e657d93e97bd1b625afd1531249cd32d013c0a1d62e48fdbad",
-    "dist/2022-06-29/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "cd9120d576a533106721b11e4e457c317be7ff484613d2c7592606a379c0fb3f",
-    "dist/2022-06-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "c570c55584f9d725c69bf092e0187dd7830839b6badc6fba62b5fbaa19b75548",
-    "dist/2022-06-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "d3e63b5f8f139e32a40ccbc7d877714e88d68a31e1644cf4d1cc91771d5459c9",
-    "dist/2022-06-29/rust-std-beta-sparcv9-sun-solaris.tar.gz": "61169fbfdab7d66712f04a53d6ab8766766158a566bf606075132002a67bda0f",
-    "dist/2022-06-29/rust-std-beta-sparcv9-sun-solaris.tar.xz": "f137dbdf000903de091c076fd3800466097caf2f9c48e4ebae9c3072fc2aaca4",
-    "dist/2022-06-29/rust-std-beta-thumbv6m-none-eabi.tar.gz": "b81429647fa2fd42fa7a5b4c15d15b1595023e81a7e4289e06bd214c6666127b",
-    "dist/2022-06-29/rust-std-beta-thumbv6m-none-eabi.tar.xz": "4a741ba60918138ab24cac1d6fda432d38d02bbf0a22103270df13e0d40c8a86",
-    "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabi.tar.gz": "ac20977687a1831ea2883568eac148821ad9f1ad199a9b728447f7d15f518e1e",
-    "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabi.tar.xz": "57262c3ddf2351b80ff8dcc03fe8e16b441e1b0014c0e4534e2e493902928ea7",
-    "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "be9111bfcd464b5f107642b18fc375eeea16a1d758de71cfb6258e0302c9ae7a",
-    "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "63f84a900c52caac4eed1c58bbfc604e591c56e0fc1afcebe7ae832a9610c060",
-    "dist/2022-06-29/rust-std-beta-thumbv7m-none-eabi.tar.gz": "51f5266d9790f4e691493e403edcd664541afd448123fea3fbd1de2d50c87f1e",
-    "dist/2022-06-29/rust-std-beta-thumbv7m-none-eabi.tar.xz": "12f7be43c58de67c761ed17bb555509e639c31c5cc0783d9ca55e78c4586317a",
-    "dist/2022-06-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "37f3baa3a2db1b15315915910447332bcf5b9f36666f4cc08868b551d27022cb",
-    "dist/2022-06-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "e1f457d3da72a9989b90395692310c78c5e5fdcea35fc1bc2f450eba62b7d21d",
-    "dist/2022-06-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "77a461b06eff56bc00361e9f771e0a81087fed2999e5d1f2f53632a61e90829b",
-    "dist/2022-06-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "29a4f3a426e380b886bc7a468b08d2dad38ff704d74ec2f243ba5ba7720c7e9a",
-    "dist/2022-06-29/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "cd0285f0254f4042ee70f02ea576ec713e34ec00e2fc0309cd7c891ca26674ca",
-    "dist/2022-06-29/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "43dd490c8068897a5f45ee0da36ea8854496cfb54faff9f759e2795f22d46cb7",
-    "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "cea8f1a52c3829f4781c321bb43486e44ee8fc94602249d1084e8a6e9269e2ce",
-    "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "9a6b827b4958d412d4f413219458582142d1536f313d14ded54cf666a43946bf",
-    "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "a032c778052e77eb32eef136ca431ce2bfbd6e43ba5a82e90b2ef3dd414b2cd0",
-    "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "cb560e7b3c62bd2598e701360b11a6edb16e730700c4aa5e5d284dd1ceb570c3",
-    "dist/2022-06-29/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "c8e3309f94e8187e41d5de922c7988d610439be3a90e06c9eab76b4a3850343d",
-    "dist/2022-06-29/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "f1388800ff04b85fa549191a5cae8e4964baff89ddadd57fccdef85a1da99e4a",
-    "dist/2022-06-29/rust-std-beta-wasm32-unknown-unknown.tar.gz": "c0a18d66485400b692011d72af2226fc609eddd19fd1e95f370ed6a864f6dd8a",
-    "dist/2022-06-29/rust-std-beta-wasm32-unknown-unknown.tar.xz": "f3772ae732dcc6a63c2143d3530d8253b35c7412b2266ed9583d14f6000b214a",
-    "dist/2022-06-29/rust-std-beta-wasm32-wasi.tar.gz": "aa204e3377e1c4272c18231bcdaa439678fbb1158d794ee8b2699fbad382c828",
-    "dist/2022-06-29/rust-std-beta-wasm32-wasi.tar.xz": "25c90365da9be1307e4aa80f699ed14eec03bd48b8271570d9e9e9d4dd0f701d",
-    "dist/2022-06-29/rust-std-beta-x86_64-apple-darwin.tar.gz": "24754ac282a434638de5bd2a548b3960149b811f03422cf875a5018dfb229441",
-    "dist/2022-06-29/rust-std-beta-x86_64-apple-darwin.tar.xz": "0806c72137fd994acfb304039af85e028999ab941d3d95cd037f298a66377aa5",
-    "dist/2022-06-29/rust-std-beta-x86_64-apple-ios.tar.gz": "588bd3b637531ae3399a91e805d52481c927477d15822636714091d2371e95cf",
-    "dist/2022-06-29/rust-std-beta-x86_64-apple-ios.tar.xz": "27d75a39fec3ead30dca470f0f6c96561a48bffa8d22c283001f7543b0d62f0b",
-    "dist/2022-06-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "b7b32388857ecd8f1f16fdd5354a9411c84c463b8b40a1ec2982d5dee11e2318",
-    "dist/2022-06-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "5ea72074aedac44961823a6a8788bb7aecb905dffe2c25d52c417275be39676d",
-    "dist/2022-06-29/rust-std-beta-x86_64-fuchsia.tar.gz": "5f53ff113fa233161183bd1c79a946aa13770f52f08ab3d8a62a080ee2682163",
-    "dist/2022-06-29/rust-std-beta-x86_64-fuchsia.tar.xz": "5541a85df4ac431a14830b09bcda0d030236ea31419b1ccfdf2e761638a1c484",
-    "dist/2022-06-29/rust-std-beta-x86_64-linux-android.tar.gz": "d17d49d6e416941c1aeed7d145b47d2d61a7bcb563720ed5dd9b867cd0522f05",
-    "dist/2022-06-29/rust-std-beta-x86_64-linux-android.tar.xz": "41aa64b361c17afd7466b621923a44e80d61edefd7052e06df1eb96ee0cad3b1",
-    "dist/2022-06-29/rust-std-beta-x86_64-pc-solaris.tar.gz": "2527ecd6465989f54570e7ed61b51c8a00bc5e1c613e972c93b028df0ad60ec5",
-    "dist/2022-06-29/rust-std-beta-x86_64-pc-solaris.tar.xz": "91f243a73494de90c5250a663f111b3a999925a923cb92220d1853428e2b1aea",
-    "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "e41010c4f7bec5b06205085fba4e538cec40222c18c5d560c2a1a2f5c2d4b859",
-    "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "af8185b065f2ab37f92ec671eae1652368b26b6917e34c24f2a15779f1e447c7",
-    "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "1fc3c51f18174e07ba21bd8bb4da495540273ac3f89d2e106172bd6cbfd08ae3",
-    "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "b5ffbbda960fd38bc11bf56e154990b385940fa6fd95563feed0a403317aeca4",
-    "dist/2022-06-29/rust-std-beta-x86_64-sun-solaris.tar.gz": "8bc7de9a99c3eb1954a1dfd17a39629449e41d743ee85437dcc67f37ccfa9cfa",
-    "dist/2022-06-29/rust-std-beta-x86_64-sun-solaris.tar.xz": "919ffd2e0221c6e6125cecf5f1c21c4b03d3e98c4e1322e5ec664e4079d37fce",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "fbcdbf0d7a8dc6970fadc835455a6fce455ecbdb16ec435957e19477efe94af6",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "09bb9ef104f7eeaf6fae591d908a0f8cbaaf98f1a14e788f468cf99dcbecd8ce",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-illumos.tar.gz": "9b0176f89bbff3c2fef94ca3731dbf9e3c079288aee88827efb42a6296ff8168",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-illumos.tar.xz": "d84e40868ce185b39a0ad9a6dfc118b31cc0742b9e4e80b59944572043088f24",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "69cb1a75f109f1bc3ef55eacb2bf8f3ad4e4f74fbe7fd2b92ee448082b15292f",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "de2bff6b876d38a20c944b9ef1ca296061e6882080316cb6ad4f346b3f25543d",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "1e7803d70fd4965da58e0949f1de2ed9624852b48a6afc43fa7f007940e1ad61",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "cff451b8636469879061f9d0a2e2403d3bece99ea61e4ce8992095dcc5d57429",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "42654d72fc9816827ee0e0fba553f672eeacf7af2f828dcced42b3603ea7b244",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "d8b40b941b95d888af07649aece54b51fe419f129957a3c1ea00bb707092fba9",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "9e168ccc151b0320feac61a46f69e5287ebe61d5cda4fd096c2a6e4c1bc4630e",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "1fa18c0e9d352188505f1dcf21b132863cf531f3a5d1cec512baaa135dae071b",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-none.tar.gz": "221da3b26cafafb2f1db1bcb69529424df021e149983ddd07cae15f9e7bd3b05",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-none.tar.xz": "401b277ab48e8b5dd30da993a68b2318b9f5c3f6a1cd69c244dfa62212b77dc1",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-redox.tar.gz": "0a67ac955769e71b677af6647233bea61f2bc61db0eda5b3a2d70fe52c094806",
-    "dist/2022-06-29/rust-std-beta-x86_64-unknown-redox.tar.xz": "96d52cf2a502adbb3cc37f1c46fba79ec7dc2ffdfaa369e58ba60a2e9b7a6efb",
-    "dist/2022-06-29/rustc-beta-aarch64-apple-darwin.tar.gz": "13c5bf14af21282b302efc63285b2c683f24853d510319aa43d150fd127255d1",
-    "dist/2022-06-29/rustc-beta-aarch64-apple-darwin.tar.xz": "3afc8778d32d04b8137552ca651237b5573149bfb7c4b3797e73746af8636612",
-    "dist/2022-06-29/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "84f95488f8540020efc1f59d3112805b7b16517fcf0e991fac45757f7f88d09b",
-    "dist/2022-06-29/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "818479235bdc06809c89728ba7c449f2187c159aeb45ffce62250a1e40202921",
-    "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "1a8acf7bd5d81b0cce741669aa76170c595525bfd981f327199a014d8f96cf29",
-    "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "eaecede917a4994772b1043c42c1a0a88bbf0efe5b9830e5be4fa039c13152a6",
-    "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "f38e0aefff50338ec442a8a915aef83bb89a445c2535840a74cc1cd3ccd0ec1a",
-    "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f4c7ff3f19303bf82b0a7e3adff2f1d76be75487b78a53a23b5a564567c418b8",
-    "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "473936c8d1c6fb7de9da593185d6d3dcf32b3cd833e9a7b96a721ce6ad587628",
-    "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "72787fe6ae27c684c166acf178556ff570a923db89b5e4576b97b528b991b6db",
-    "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "f641842f5b298ba11d7143d4e24f03b8adf20363e25c459a9b98e9903fd48a16",
-    "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "3ef2c162e55a62024e4cbb079f03a38d40529d864ce4f8d28c12843b38568802",
-    "dist/2022-06-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "e3e714078092863a7cd3a6d9c8b8d8a8c05da97debff0545f45593163bd51e4e",
-    "dist/2022-06-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "dc9ae664ffa5b61d576182ddb79234331e1227302fe9cd6db0926011522582c8",
-    "dist/2022-06-29/rustc-beta-i686-pc-windows-gnu.tar.gz": "9bc6578d355c1fee74e8104331cdad4f3c9c94bf1713e989de5d52c1f5291528",
-    "dist/2022-06-29/rustc-beta-i686-pc-windows-gnu.tar.xz": "412a2ee2a94ecec20c1c54934b72d84b46e29f35f6520b8e654ef518b9a7e511",
-    "dist/2022-06-29/rustc-beta-i686-pc-windows-msvc.tar.gz": "f8fc7fbcd82398964ec562f0750f33fa1af55268e053d416d0729b466fc7fb3f",
-    "dist/2022-06-29/rustc-beta-i686-pc-windows-msvc.tar.xz": "eaa66c5680987aaea99d7cd38a5245c832698f4a53443eeeb06880a8ec915497",
-    "dist/2022-06-29/rustc-beta-i686-unknown-linux-gnu.tar.gz": "8748755c8c72ede71310f998c38ea0ba80e2065da5f53f8ac61bfe8e4c94ea1a",
-    "dist/2022-06-29/rustc-beta-i686-unknown-linux-gnu.tar.xz": "fac18aa72b3c801230dd3a653bab76521618be5fe48de2f79dc1890dacbc7a9c",
-    "dist/2022-06-29/rustc-beta-mips-unknown-linux-gnu.tar.gz": "e22c7209d77b1fdce3439225c2e7d659a61cdaced9387fccaef5370cb25baef1",
-    "dist/2022-06-29/rustc-beta-mips-unknown-linux-gnu.tar.xz": "cea1aa2447e02cc6a4be215f0bb4b658560f641389e314c0cc6814c2e1cb5c18",
-    "dist/2022-06-29/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e57c23dd8981d77b81b27af2879c4a2bf9e6619b5a638d8ba9dac790bf9316a0",
-    "dist/2022-06-29/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "0dafb1d812358f5275ff272d247573ac0799dac64a446f7ad08543d6f4334088",
-    "dist/2022-06-29/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "bf6be111afb4ea7ecdbc611e94aedce8e5ebf255f1e52cc61da65913a6963471",
-    "dist/2022-06-29/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "7d169795f5ef7c09b7e3a9b40d8669c0b2fc6449247551b426286ebe3f6e258f",
-    "dist/2022-06-29/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "0e76f229b0dbeb14497cfda0f4d717c369b8bc59c7bce1fbad059220562c0814",
-    "dist/2022-06-29/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "d6870a46ab49264498b18a4cd2d2400f0df8b02514e92c1bd6396c732f869035",
-    "dist/2022-06-29/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "547269aa65cbfe33ef5457ac969399fcf90384f57523a91e9c61306fb9e464da",
-    "dist/2022-06-29/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "fe75b0ae3a9338f1e48e72e6d6f51edba25f5fd7ab0544d3feae6b69105f160c",
-    "dist/2022-06-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "b445b6ec414be5c580a19717125858ed4c8e0c90828e085f2ab47a3b44a0863e",
-    "dist/2022-06-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "a915c1da4a45cd286c0b8978999d5ef2ab96b24185793ee1dc043e094cf6c51c",
-    "dist/2022-06-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "72b6014c14f12f5e5848924e20342d993903d16e883ea8473ca8cf9d188f68d5",
-    "dist/2022-06-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "ee707cf657c9991eca8a9b722fb58b420b2c9fe9bc9e32c4042a4af2bc37e8cb",
-    "dist/2022-06-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "8e1fc4091115f93f13d88dd7a9b05492ffbcf72f12fc8bdeac28dd6f3c78c3ac",
-    "dist/2022-06-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "ae52c2a0c43871c658d63c101a192dd5fea65931e0d45855bd8dd40a58a7e688",
-    "dist/2022-06-29/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "fe45b4d1d509a7a0c317888b575d3dcf1dfb7c0b8306ec54e2d09245c906e276",
-    "dist/2022-06-29/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "0c06412d27669429ff1c0e5855c3a3ac923b40a93b2fdcb8fbccb4033476b5d1",
-    "dist/2022-06-29/rustc-beta-x86_64-apple-darwin.tar.gz": "a3c33e87a6b12049fcd7cbb0f53ea74c8411c91c262b6f352a1024221d3457c4",
-    "dist/2022-06-29/rustc-beta-x86_64-apple-darwin.tar.xz": "3256ad9fdca2506b06962b4e88c9a41daa8f094a5c1c80530fbce4dbdd6e1c32",
-    "dist/2022-06-29/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "e2881ef537ec43fc012307cdac5291e4733b322e92a3b056a6f2820c883653b8",
-    "dist/2022-06-29/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5a8a36ca5f01ffc8a2dff21c6fbf99652444c6d3731c650fb91cce1fe79c3ebc",
-    "dist/2022-06-29/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "6ee9a6511fc5342b4f07102f874822553c928ed75f09c4e34952db1c248604f1",
-    "dist/2022-06-29/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "830d24aff7aac91a61143878969632a47eb8392c539fabdd25826792c7125509",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-freebsd.tar.gz": "1fb6dc34083e95e193c39bfb4edca99f42713f5cfe3bda8e368e977f61c82110",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-freebsd.tar.xz": "c3b9ba1586bb6152596aeb01997b40ab65ab7140525b1b0bc22f2a84baf5c44b",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-illumos.tar.gz": "584b8ee47755982a6b0f0d0d5a12af35ad740e2df8b1ec1d3084509ea940c2b6",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-illumos.tar.xz": "a4532b97743b8a90f4f492513c7cd51600426c08454be2e24a49cf867ca0e30b",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "f3fb7f949724bf9b8b77cc562d9d53eb067872bc312ceeb2b5541c6667f70da2",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "10912b2783699d9e155b4f59dd762fe012e4ea4410b56d83b36d1df769a8cd49",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f548bad660bce1513081be0767305a523fd129a0b13aa368e8c86a36d1ec3b23",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "fd52405c614d6932d9e5948e851be7315f1f9d21bbfc3e6d142d6d3196464fe7",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-netbsd.tar.gz": "1b816d0bf6d4138bd557094f922e7aa9b2e7d0ea27464cadbb117eac8a42f3fc",
-    "dist/2022-06-29/rustc-beta-x86_64-unknown-netbsd.tar.xz": "b869ba4ab920cd08bd063cedba08614d5c6199f643d277d59f44af513925c16b",
-    "dist/2022-06-29/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "3ac81b63371115875eec194eb4d0c3e9aeb624c7f7ce3ee85b197b8e3f1cd599",
-    "dist/2022-06-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "8eda09837e39a0847b79803645f810d87be7208465deb7f5b0952fa7e39c2113",
-    "dist/2022-06-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "353d2f523a3a1bc2ca478b6facea40363d2d18ca6b48d8f4be18626c7cdb3142",
-    "dist/2022-06-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "ade013031c8c72eae5717c248cb20f36107d326c497b4f3c8e90dc2912d11975",
-    "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "64b5f8f97781bd4eca5554f28688a58831162fafaebac31b0f04610e16f09a48",
-    "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "feb458ae9a30773519b8be69557d0bd4c3d924aa22eb4a4fdf331e0d620f1e90",
-    "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "cb2698b870f2c56554996f2e651ae53b11241c06da6ebab4b40a460f6826d91f",
-    "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "b0be127f8c04dc4ac2d77b2f9ec7e74a793b65bcd591c0c6a7208b1f4b445df3",
-    "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "596b02cf564a03c69a29f61ca6bba4758152d64775eff62b767bf77cce3b00bf",
-    "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "f819a48640599ea06bcc4a3f3630bd0a12c9e698cf8f62f61b36813830a54d55",
-    "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "19df36c566a4cf5d440011a1c0e94a4cc70e5b66e29b36a268872d4e2def8e78",
-    "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "dade13d688c6ba9b291b403d4d61bfd8973d3284b9bc7a92ed6de47665411f07",
-    "dist/2022-06-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "5ba3a696872e02cb2a4b2e191262d61ecbe6f289345373ee06c542a2d2580527",
-    "dist/2022-06-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "8ff08027f040bdf0de0496d6a408796fcca44540b097414255f776704e6f4966",
-    "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "15a36d3a798d2fa027d05229ab42baa4cadb6faa8edfd8c13260ea4756031194",
-    "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "438ea44472607752d205d9d2f14056a4c66fd9a84f728110792aadd22929b9fd",
-    "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "734aa5ce2105134c34301e44f7d8f0ea3bc94587df3e27793530f3a722eb9b26",
-    "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "02a7401369a03caec796deb2d3a0b3c1a46bad79bbe6e654d9e721cd95bfcb0a",
-    "dist/2022-06-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "17a8c573eaaf5033b15ef14ff221848e3100332b6f01b30b249c9e854bcc21d9",
-    "dist/2022-06-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "bca6959f1e6977cccd0571bc61a37928f559eee8e10395d7eb033cec9a8e0dae",
-    "dist/2022-06-29/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "6a4cd4b13e877b7f8ba712cab0e804edefd432d78cd46970bd44384ce94e7faa",
-    "dist/2022-06-29/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "43adf44181bee2b295584c36c35041ff97465fa3fe46b358e142a1d10c224a40",
-    "dist/2022-06-29/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "376abf3aa462c0e1271044761af0c9f3c63442731c6d04accd32a0ca0221eee6",
-    "dist/2022-06-29/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "f8a5f3d01e06f46a6d85fa7f74b1a494fcb55a6d5dc8113eb96d6a46d0d37050",
-    "dist/2022-06-29/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "158573b8e9da4e8a464bd3c692e54084cd0b9097596d41c21646091883d15b48",
-    "dist/2022-06-29/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "bdae49f025be97fbf37c9ca7ef1f4331ec4ebf8a5fb429a4c20f09619069e655",
-    "dist/2022-06-29/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "6ed1ea2364c8b645c6d899cada76cf161222fae9b4693ee71fb98721409f73a8",
-    "dist/2022-06-29/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "beaa6383696385769cd885b3314ccb6f69a7a5557bb1af7214c2c8b2d03d64c7",
-    "dist/2022-06-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "0f0ad140d47b4477e9ff0a925468b36aaaca0063eed018022624ee15cd0fcd7e",
-    "dist/2022-06-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "23d3bcf9d9a22bd869b3857c7c8bbf25c168ab60677a958c8b48d8b04319beae",
-    "dist/2022-06-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "fbd1655d0399a3e8728710dc0c234ebca2ce8669fc42eadbbb075baabaee740f",
-    "dist/2022-06-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "1d0c70f5ec38542f2d5b125d59d93ffa1a984a7a2e2353503f8b8554604daa8a",
-    "dist/2022-06-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "34acce36d8aecd8f4414fae766c2ad7c7942eaa8b422075017ce28e84f08fb08",
-    "dist/2022-06-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "8984ea923bf93c394ca50b41f58df0d750bc522c481de2a0468afafef052f343",
-    "dist/2022-06-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "a9064c4ecfe40a2b3cdbabe12b6063f13680f2a6eb36d58f02fa6207af988a13",
-    "dist/2022-06-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "3576cfd24cb1b53d96145651810c532a5b1c424dfcc39b2c78d5688d7f0791ca",
-    "dist/2022-06-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "2b921dbf7f8c2931bc531665087ffa05efe8bb4270902a311789409994844cd0",
-    "dist/2022-06-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "f6a4134ffb2c4616606b5d9d3ba63b9dda1ec49c2c0af2290a915c08d80ef301",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "468bc3d0d587b37993cda14fbaf07ab4edc05627126d96d9ccaf58b1df55178f",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "e6262f053b2e456d09ce6617e8209e229d2b9ced144a9eff12de830b6f0cbcfe",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "34a9cf74d9076c49c6266d718fad9a78ea1ede268f9b7978b508b76a4c6e3f8c",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "3d0e544dbb280e4cafebc05dcc68b3cda8a742f9909f59de93c8791721c3f2c8",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "d7119b250b1b31fcba6b3d34cb8deafa32fe20f547ad1bc1e931c58e7059f65f",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "ebc31e9118112e64fced1ad94e4e903e7ac0ff8dd771d85a55c1589a6b838c38",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "a940ea208faa9882808cc56a8e96cadf79f954844ede160b2b8971238bc84f4a",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "e699ef1a7a7f5e4bd40cbb3daff754e9214cbe71c28b1436a893a5edbca8c876",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "2a53b4b5e57fd9e1d9014d46576e6b47b51d0dbaaf55c4e84964390c2b2065cf",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "e4491027e20ac563ea8a0906d8941f80274890d4d1b4b3728e26e5926f2c77cf",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "b7ba70b0ca5ece6b14cb1034e7226a83435f8b71c77a864b4ad949db11ab75b1",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "ce07cc2010a424e83672095d89b4592485a7c94a3f450e609ed62237c86909ca",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "bd653ae8f104872e5a2f937fabdff09d41691c28d512fb7f08562fb21ab64e89",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "d374ef3fcfaf21c13813cab8953c42c9c965c02549d18e95fca903b923ef5e6b",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "f0fe5175ea73034b1b789db8d31214ca561af0f4be21c52895b47baf103e5952",
-    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "6bc6231ebba38ec47fc1de646aa7d8a9855d2dbfb61595fad299656e39acd0d5"
+    "dist/2022-07-16/cargo-beta-aarch64-apple-darwin.tar.gz": "d114c9c7d39fa092e291d39eeed2cac5ec67a9d7f1e392014f83629dffd500f6",
+    "dist/2022-07-16/cargo-beta-aarch64-apple-darwin.tar.xz": "d3d0090e4afb944da8ae9b6b5441486e03066e83de69a2a9606a51444e601196",
+    "dist/2022-07-16/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "99d64f68bdbeff55552efe0860a2170db6c0cda155a7a955322d4ccfced2a2e7",
+    "dist/2022-07-16/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "209b0514a99341bdcaf62ad4785b807383aff2572105f143e89fc89f67bea0d4",
+    "dist/2022-07-16/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "6dc3c9f6739418e14d5d505b1f215c12768d9db2cc26912cae09ec75d6a5b336",
+    "dist/2022-07-16/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "741f7d7a55fcab360d6e0d91e0f83bf8ee6aaf19b0e880a7c3e91af22a4d7ca9",
+    "dist/2022-07-16/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "15185b7f4b806cf8dd5e785625df73efa27a5653e8c38476040372f372a11b1f",
+    "dist/2022-07-16/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "0122b5d493383d97d39d6593bd9cc709a1809f29f1713d3553ae242b78047e34",
+    "dist/2022-07-16/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "e3e2b281ff1233f6596b27db8b593252867d7f26c1ce91b779a164234d2cfd86",
+    "dist/2022-07-16/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "0c71da4b8daeab00da01bca07eef363c5a17a03c1eaf48014d3508c7f228e24b",
+    "dist/2022-07-16/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "6bce124d863189178f06cf430466c18d9ba0cd0e42851e18bb38254d00bdad64",
+    "dist/2022-07-16/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "0ae2a35e0e4f2946dd78420b11f17a54a370e15e12367ba29b63e3f087fb0c71",
+    "dist/2022-07-16/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "eee82cd57578eade5cbc07cf3d48be243a4789e6fba6d7db5772038f87e243f9",
+    "dist/2022-07-16/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "e27b8fe73df64a2733002007503995d9f914d16f852d5e643ac539408086435d",
+    "dist/2022-07-16/cargo-beta-i686-pc-windows-gnu.tar.gz": "0aa99ee73efa4940ffd6789f98d3774bf33a3a54c579759b1f9f0e92cb403134",
+    "dist/2022-07-16/cargo-beta-i686-pc-windows-gnu.tar.xz": "244a98bc858d800a1a36018d7b9fbb77471842b9a130301f9dc19e427c336fb2",
+    "dist/2022-07-16/cargo-beta-i686-pc-windows-msvc.tar.gz": "6b19412e037eb918b05e993ab1c62d96da8cbf92b0a9fc1480a76ad2dc331f0f",
+    "dist/2022-07-16/cargo-beta-i686-pc-windows-msvc.tar.xz": "0420980cc9381249bb187c274f42472997e6283acf95bebf1f93b50d5c138942",
+    "dist/2022-07-16/cargo-beta-i686-unknown-linux-gnu.tar.gz": "95d0e17823ee02ebc3d73982e54b96a110afbf97656ed581da0e71e2635cfb51",
+    "dist/2022-07-16/cargo-beta-i686-unknown-linux-gnu.tar.xz": "75a65a917ad25c1927c9c8306e76d13989f1ea42c6ca063269685e33811e1fb1",
+    "dist/2022-07-16/cargo-beta-mips-unknown-linux-gnu.tar.gz": "ac12e969fc6a892621ce9ffa2108a21381033800526d3b0dc6c1dd343b10af09",
+    "dist/2022-07-16/cargo-beta-mips-unknown-linux-gnu.tar.xz": "3be48fe74c14e48c084fe395b9eef153d97fca57dfc12b5a07f2de143c5df4fc",
+    "dist/2022-07-16/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "1727662c7307c3fec52663d356ccc147dd0c2608cd5607f83057a3f2f315e578",
+    "dist/2022-07-16/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "47b32153e287a972d6b7278a7d9b2339d16e8d9a938a42221536d12762d0df92",
+    "dist/2022-07-16/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "14d56231996a7c20e91c204658412142b8288668109d46f3ed9771186937fff5",
+    "dist/2022-07-16/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "83410621415f07b345d6989fd146303594c811449fd5e3c7609158a9404ba236",
+    "dist/2022-07-16/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "5362caf0bd6af50fc4bd89864beddcc909d1d53d0ce2b4049eca4b9019b9d922",
+    "dist/2022-07-16/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "6b5007890a41aead77f919ad7ff0fc29c32e460ab3402837ea0e6ded21f2e4c0",
+    "dist/2022-07-16/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "e4c914ef7b6e97aeb437d0fb2100f0fe621519ef8f6bdee98a4b3e731d5626d6",
+    "dist/2022-07-16/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "33a77edf6f85fc2ea790a10c3108811c0ccb22a0c4c0d1e3a6c3ba27c43ab6d9",
+    "dist/2022-07-16/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "85969807dc0d2999fe4dffdb0f8290bfeaf65646cf333924a933adaa4b045d05",
+    "dist/2022-07-16/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "b36b74e1032d6f83da8b18847df80d52fdf3375b2d45140020452e35c2b9af00",
+    "dist/2022-07-16/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "203402c33bb81ed9c176ee7579fde97671b2f32ad5e7fb3200cd1b77f434d52b",
+    "dist/2022-07-16/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "1bf1daa9660d4fe96e7b9d35fde4995e0e12efcdcb0247cb574495d20de080a1",
+    "dist/2022-07-16/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "a5aec71139c49fb950c03bb4b6af19bac0eec2d6ba2520e49c2d1a08eeae36ee",
+    "dist/2022-07-16/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f0c5b7813073502316e25b71ab41eb600baffd8e51d6ad8134bf14aee53820ac",
+    "dist/2022-07-16/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "b64be7c8c471c9b4a2d9380ecf7d23431b1ea255bd080635ba58380a820cbe23",
+    "dist/2022-07-16/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "a0a6f204ce1f38482939caeb2efe645b60760e8b4c7a68ee4edcf51fc93409d7",
+    "dist/2022-07-16/cargo-beta-x86_64-apple-darwin.tar.gz": "9ab770b4d43ca4020c40b2c234867b67d99794945bb274382f69f9d1e4b0d042",
+    "dist/2022-07-16/cargo-beta-x86_64-apple-darwin.tar.xz": "66201509e2d1eb5b447f85b019467a2193fb9d3eaa12df025aff6746a47f49a7",
+    "dist/2022-07-16/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "295bfb182c85aad35fa5c25691acb03c037a28a8178b9b049df88d40176e418b",
+    "dist/2022-07-16/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "c1d4578521feb07b04c38b5431eb93830d518bbee47bb458e8f745a7bbd4b312",
+    "dist/2022-07-16/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "7eda4ebd7d8ade6e62772604bd6fe1a64f7123da1002c22810a752906893429d",
+    "dist/2022-07-16/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "7eb53b58d63c3f11faf58c819da9bf828f47b579904f9cc801a97b044bb7814c",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-freebsd.tar.gz": "cce8a7f5d0e561ab9ede68e535b601396a7a46c2737d01b9c9f008b6cf4b510f",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-freebsd.tar.xz": "c1989f0a6bb75c8ae4fb56fac60c880a62e92dbb225fa86b5383242573e62e9a",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-illumos.tar.gz": "eb5a4e9bd6a2216e4b72afb5bc542d49583a23a3bb3146ef2c02aa9f15887d24",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-illumos.tar.xz": "42c5330ba2ce1b8e4045e7b8671ad1254bc2d6119bc34996467c5956108897f9",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "35fcf80d8cb8bcc5ab413128575bc6a843c145b4b748df2de9cc9697d535fb6b",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "4070423142b86fac1ad312ea74880456343fbfe2f5f73e465993b21f4f019b93",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "4d3adc8d1cc15d45a4e7498965b92b9313cce8fa9a8f1391000d4dbe0258603a",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "2a39a68b74b7a62fb89f4ccbd202679fed65b425c1678451ac268b94c8294228",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-netbsd.tar.gz": "8508973b3595a0b0a65050d761c108119251a57ba3013d4942f65d0f4f634a7a",
+    "dist/2022-07-16/cargo-beta-x86_64-unknown-netbsd.tar.xz": "4309d7b2c2c26e454fee473e0345947b7447b6e107f795ce9d4cedfca3baa199",
+    "dist/2022-07-16/rust-std-beta-aarch64-apple-darwin.tar.gz": "2168776e63da0bb2b6d09e90510f0d481c68d4aaaa1e1cfc79317add45a01d5a",
+    "dist/2022-07-16/rust-std-beta-aarch64-apple-darwin.tar.xz": "bb9a83c1b5468e740a9b444052afe91a3d8d3223acdf1626e4302475f864acdd",
+    "dist/2022-07-16/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "44f00f44ee97a5f05b156a0be66151fefb79452b94b5d764564702194fb84ba1",
+    "dist/2022-07-16/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "b06f7599e3024cea98f90ea4a9dc0fac9d458dcce63aecc2497e2ec15a00eda8",
+    "dist/2022-07-16/rust-std-beta-aarch64-apple-ios.tar.gz": "35d7c8d11aac14f2e4ce3a1e236a8e59642a6be1e474be7d741c0e38ffcb9d5d",
+    "dist/2022-07-16/rust-std-beta-aarch64-apple-ios.tar.xz": "7fef57b2788303b10b267c228b80f6347c437a10dd2b77bea71e7280a11db008",
+    "dist/2022-07-16/rust-std-beta-aarch64-fuchsia.tar.gz": "d83d4186e499853f337513b5603c4cdf287012bc121a33537eb514b2d47e8963",
+    "dist/2022-07-16/rust-std-beta-aarch64-fuchsia.tar.xz": "92d3caab76907cea85fe78c10f902661ea0887c6689888f6eb9fffa2f443339f",
+    "dist/2022-07-16/rust-std-beta-aarch64-linux-android.tar.gz": "82ca00fd9913e2d55bc0ecf06313a2f9004f71c40c44f01b3d7d9cd8d1799fb0",
+    "dist/2022-07-16/rust-std-beta-aarch64-linux-android.tar.xz": "dc7c287887bba704fe988e7f5f7d080aff576de7a214f1dc63ded4fc784eba0b",
+    "dist/2022-07-16/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "fe47ed76b388f7b01d5e3d1d51918beb0f04ca7e015353479f7eff78e49b9794",
+    "dist/2022-07-16/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "0bcece81cf9b81c5ace02459f945b97be181f81704cade21687460f1db00343a",
+    "dist/2022-07-16/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "9f28057d4828f7a07eeefd8eb03c9e807babd86e67443099491421f7c5afa67f",
+    "dist/2022-07-16/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "b21f0deee74041385b7018979e7db1dfd071530f064b1bc500f9281cfafc38cc",
+    "dist/2022-07-16/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "588d6952722ec461de5d0c10c5f01c6d6735740a74b8162e2e2ebb848f9175d4",
+    "dist/2022-07-16/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "c6731bcd0e4e15d79dcdc6f974b5a4f7a379692ad2183c0bfd56e6619d9f0fe1",
+    "dist/2022-07-16/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "588585fd26813de3ae2a8a49c6e6fea5f0f7311911a54c015372010883cf5938",
+    "dist/2022-07-16/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "a5e820bbbf113250c4f814dd0f4aaa9b20b1a7d61613b7157993d25fb0ff3518",
+    "dist/2022-07-16/rust-std-beta-aarch64-unknown-none.tar.gz": "69ec1ef2f456a8cd294ec3f7c485f45401e6f200df9f525419726cf9da60dc60",
+    "dist/2022-07-16/rust-std-beta-aarch64-unknown-none.tar.xz": "b13d0099a55a928dfbfe07d80426e9bd53b6e35cfc6b634ad2ee02174ce42f7a",
+    "dist/2022-07-16/rust-std-beta-arm-linux-androideabi.tar.gz": "a90a4cc72263b96ada453dd3c8443d076ec150ed910ad30f26f825cd668516e9",
+    "dist/2022-07-16/rust-std-beta-arm-linux-androideabi.tar.xz": "0d7c8c13a18888cd7e9613c7d88ef227d9b2034739d0d16507aca28403328b42",
+    "dist/2022-07-16/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "9fcd72dfd5568a3e7023c416720ba4d5e42aa6d425c7ce6feb2ebf1b650d7591",
+    "dist/2022-07-16/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "43efd4e1ca95f54fef097f14483a4f4d96d499c38c5ad3d3a290e02f7c4c4637",
+    "dist/2022-07-16/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "7d2c708aaeb01014856ee7d2c6c4c85883f17fd00fca912aabb93d84170e3e61",
+    "dist/2022-07-16/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "97d3c092fd702dc7df0df83722046371b4d418aabc60fbbf0807ddddf3e7dcda",
+    "dist/2022-07-16/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "74e8fe4152eb12ee8b9d4fd4e3cfe5d506329c94ab515319fb2aaf013bacea5f",
+    "dist/2022-07-16/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "a207d79cf57f3e13b6f85761373a00fa8afde8f513e14a3e0c0a70f40d89e890",
+    "dist/2022-07-16/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "4660ec4d1fe1960e70b54bce58cae6775b8df86c3ecbc96f4df0067dcd90a3cf",
+    "dist/2022-07-16/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "c86a999f7affd8f4d2e0d509cf3e2229a3cd40768ef86b1ac36b5dccbbe56bdf",
+    "dist/2022-07-16/rust-std-beta-armebv7r-none-eabi.tar.gz": "5ecc032c10a8f8d3e1e40256ca7c7e03cc98ae35d56105f70df94a4519412dbb",
+    "dist/2022-07-16/rust-std-beta-armebv7r-none-eabi.tar.xz": "8e2c1c97083aa141d3b31476903a6325fd11f0ae5350909eb0295b8be19eb1f8",
+    "dist/2022-07-16/rust-std-beta-armebv7r-none-eabihf.tar.gz": "e111491ee2412c8d770b0a93fe402566e46c2faa855c71f24da77a989f36ea2a",
+    "dist/2022-07-16/rust-std-beta-armebv7r-none-eabihf.tar.xz": "7c814fece60ece924f5dffff6ee6f1605965841f4b864cd271c5c4f3b3c18042",
+    "dist/2022-07-16/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "0d4e93aa2f04f1d255d319653b3f4c02bd3557cc8227e6be4e0f1769aeadd2a8",
+    "dist/2022-07-16/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "d60246292f63abeb9eb35ddf93901ea9f75cba358a67589595aa1cfc9d35e6aa",
+    "dist/2022-07-16/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "085e236212a908e0e363d78dd3ce8c676cd2dbc8e817601486502389ba8d0734",
+    "dist/2022-07-16/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "654e655cb257dbed0490ec0c75e0cc0b7e35512d4f6f9f5dddc10bab0cd02098",
+    "dist/2022-07-16/rust-std-beta-armv7-linux-androideabi.tar.gz": "10fb120b0269a65f554a592e05ec26703b0888dbeaf06c15b43522b730c943cd",
+    "dist/2022-07-16/rust-std-beta-armv7-linux-androideabi.tar.xz": "470eec8bd47f66409e28eac2b86b5c6c0644531c91135637f667f54edb7fd6a9",
+    "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "520e83ebeb2dd29fea43087399af6227fe90b5a571572322301cc6d9b76f5027",
+    "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "a7527bcd5ee6017de7fde1a6f1d98db831e7bddf5a64b54ce12cadafaa3d560b",
+    "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "bb0ac318b0a5dd972356f4e94789b68caae1a14e5996493a3bed1a579bb1145d",
+    "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "cc1e65bf50246be9d9578487580038a7015f3a61444dc53afb7c4f2afc8181f8",
+    "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "7ff2051b2324f51bf0b3fe7581e1b5e02c4e2fb4075950c36716e8ba783b1b42",
+    "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "d4e32fcf2da983adc8db7043175cded76e56894f136766c5d9afe08ef6f0e766",
+    "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "6f7b86e7b51ba9d8187c61ff0d7a6d28fe65201bc94b94bd5a845490fbcff3e4",
+    "dist/2022-07-16/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "3ac410ea3f641b578ec1183856306b1eb4e0d02ba58534df114ab45a91fafd1d",
+    "dist/2022-07-16/rust-std-beta-armv7a-none-eabi.tar.gz": "abe93aa78a72eda2735d2f78cc98ea9b7a50752320d83b70464bac86a4a765ee",
+    "dist/2022-07-16/rust-std-beta-armv7a-none-eabi.tar.xz": "059560de23b47a43800319fc968a5dd34d44ab61f486a8f33a075798c66f0528",
+    "dist/2022-07-16/rust-std-beta-armv7r-none-eabi.tar.gz": "b08a4b0b56d86182e735d5dc6f47083a4f8a0101b4a712e02f14c9f3d1720001",
+    "dist/2022-07-16/rust-std-beta-armv7r-none-eabi.tar.xz": "d65cb28ea5f5cb7e5649a85a591609b5f49c0e3b0d02c1ff8d2b1dc10ea3b4a3",
+    "dist/2022-07-16/rust-std-beta-armv7r-none-eabihf.tar.gz": "cb13a879797483d7a7fd2073be2af0c83f98c4226e81ea0333670eddffc4f77e",
+    "dist/2022-07-16/rust-std-beta-armv7r-none-eabihf.tar.xz": "4965ee9c27d6104f572bcfd19944e19a3f70d58a5d0d215059f2cc52f7bc9c1e",
+    "dist/2022-07-16/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "e8437c9df42118b8607723c1e4f04a7b7a302e9894dc52ab8c212f07964ac994",
+    "dist/2022-07-16/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "b05f10cee7b5c8aeea44689c11ddfe6f266a8779dfb0fa9df51c7c784f9f31a6",
+    "dist/2022-07-16/rust-std-beta-i586-pc-windows-msvc.tar.gz": "65f66e8690c742b13c3371c1af4219d701b66f61e4fd984b1d67bb89d6468566",
+    "dist/2022-07-16/rust-std-beta-i586-pc-windows-msvc.tar.xz": "cabea5fef3004aee4c3108a47fba945f434bd29b4c55250236ec009405e41b36",
+    "dist/2022-07-16/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "8349e67b9760f9c257c745c4d87015bd623e1cf073703429f64400f7dc9c1210",
+    "dist/2022-07-16/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ee6473059771a8f49ce5ca8f36913a9ef31be3def32c63c5a31f50a896aa565e",
+    "dist/2022-07-16/rust-std-beta-i586-unknown-linux-musl.tar.gz": "7edb1155a5fab3c123e0a847c0397b6c347cd7b4a6a15996d93f45281c2d8eb1",
+    "dist/2022-07-16/rust-std-beta-i586-unknown-linux-musl.tar.xz": "49360ce15d751ef01403459fe3eaa30061160a79e4454eee7f5c63fc65a3666d",
+    "dist/2022-07-16/rust-std-beta-i686-linux-android.tar.gz": "5d62f8e1b15b44998f7b039b7e6ab7deff85ba13130a11309b2541c70834538a",
+    "dist/2022-07-16/rust-std-beta-i686-linux-android.tar.xz": "4b2e1b2835919299113d28eca09b1e12471054786156da0cb63bc0620d6afe00",
+    "dist/2022-07-16/rust-std-beta-i686-pc-windows-gnu.tar.gz": "39a9c3f2392240b29f52ed525f57d548537e7cc7a57438bd84f7efbd85b49811",
+    "dist/2022-07-16/rust-std-beta-i686-pc-windows-gnu.tar.xz": "d8ae971791693c23260b73c8faf94570a1bddbcecfa9c339fbd23682c8cd2bb5",
+    "dist/2022-07-16/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e57020d959cbe2e7331808f425e8d95e5204f4e9c33cdd301c6809aa06ba6d90",
+    "dist/2022-07-16/rust-std-beta-i686-pc-windows-msvc.tar.xz": "35b4504603903e7c753487585fcc75237f4f8a0ee933c52941abaf2c6913e0f0",
+    "dist/2022-07-16/rust-std-beta-i686-unknown-freebsd.tar.gz": "dd5c6dd4fe4bfb1acdda726ac9f6fa0944f745be946ed175a8e3c62c0d4c46f7",
+    "dist/2022-07-16/rust-std-beta-i686-unknown-freebsd.tar.xz": "95a9f3bcce8780522d678822cac8b06ba662112df51afa312f4c7ed76a3987ed",
+    "dist/2022-07-16/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "52b49a92f66cbc2b250a7272f58acfb9732fdb7073baa430b47ff9ebfe0c98a2",
+    "dist/2022-07-16/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "2f6b5de99c83cdd01c44b388ea059d10ee7f0f62ca17547b7a6d8d66fdf349f4",
+    "dist/2022-07-16/rust-std-beta-i686-unknown-linux-musl.tar.gz": "24d81d4d181c86dc02fe5b3fb54c50f78f72f73c2d9c319710d275fb08a53980",
+    "dist/2022-07-16/rust-std-beta-i686-unknown-linux-musl.tar.xz": "32c99f24396601c8a4afb250cda4718d6d5fae57f9534d5c3c3962e4c076d261",
+    "dist/2022-07-16/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "d476561d571d62d31c03b57fd380591acbb809fd4f26873e2ef2e4b3f583da46",
+    "dist/2022-07-16/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "93d3d0511508351f5e3322a3e4360586c2c2bdb60ca0c4aaea4fe5e7da081e92",
+    "dist/2022-07-16/rust-std-beta-mips-unknown-linux-musl.tar.gz": "d8c354f83a5481508a88fa6ced6fb458458678ddfa7814e47415b5daa66b0470",
+    "dist/2022-07-16/rust-std-beta-mips-unknown-linux-musl.tar.xz": "19f272db8772fa7b77cb9d5e1c56a1a2062a6e087b2980131128ab01b025f571",
+    "dist/2022-07-16/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "775aaac7be36438ce4e8f1cda3926c3540f90fc9b74e387d5e4497227ceaad97",
+    "dist/2022-07-16/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "bc460e80f4fd82492cc8e66f11320ef22c71fe26a4255606c73c325bbd2f8516",
+    "dist/2022-07-16/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "7ebb73739bafa8f412756575f4033b45629b62a92a35460bb37f3f691640bcc9",
+    "dist/2022-07-16/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "1483cde530d3d50116f4dbcb42a3b22cf7bb04559cc9bebd762f82e8b3ebea40",
+    "dist/2022-07-16/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "a7f813851b5a9c67ba16c80da5b80397db1f4c9b5a10f4877f52b6861b856b1d",
+    "dist/2022-07-16/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "3fd132910d46fb9d769d8697e81b89aff7f739d9b197e4a54b00797e217a0a66",
+    "dist/2022-07-16/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "8ddc74476e1023ee58ee5564d7357082cbba2a7d930abd7c704dbdf49439e2cf",
+    "dist/2022-07-16/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "f773cbcfb9010491f92cbeeccff0dfc8109d4407af4c10269766674a51e84b68",
+    "dist/2022-07-16/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "85bebea249c436f016fddef2865850adcb16585cccd6fd4fbd9baf0be971160c",
+    "dist/2022-07-16/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "74a519aa2b595b093510b81b0c65b9a864dc2cb3cb4ff5af8619531afd436b8a",
+    "dist/2022-07-16/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "f8dcb0e03629d23715e7cba213b91753d99a9e0ce8b0111e360a8c6e062b9f41",
+    "dist/2022-07-16/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "e2ad66f17aca663689d80e59b6ab854fe27aabda318c0ae41febf9fff700ac7f",
+    "dist/2022-07-16/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "6351ee40b19c7981f9b4aa2900bda8cf6fec04f5953bca78c0f480f885b78425",
+    "dist/2022-07-16/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "8c8f6ca9717ef1f4168d9ac4c4eb0f771149dcbc77ee4ec179031b10f9de13a2",
+    "dist/2022-07-16/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "706d3e633e8fdbc8f672153f16638ed2ade39321beefde054f63864bfac4e9af",
+    "dist/2022-07-16/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "0b7b37b4eee8fcccad684d606aa5b326f60473ed9f567cd2d17def4cbd8c3b63",
+    "dist/2022-07-16/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "40a2572f1a4297bef43708d1dafd1709373a0258f2bbe7914a9f954ca4dbe2f0",
+    "dist/2022-07-16/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "78ebece93dd1b8e6825d6026444484f0beca982d802651149da32b13d8de69c3",
+    "dist/2022-07-16/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "4a362a752fb6270c75fc24dc7cae00a70d4272972b1f0409a0a32582d1293acd",
+    "dist/2022-07-16/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f1b8eb010818955e3ed21b2b4e3c42180fa817dcc0aa6b75520149fccd2b9d1c",
+    "dist/2022-07-16/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "0eb83977d0fb83eb498ff7858edd3fdfc0a2e40efa859a23b9a03972fd0f0c10",
+    "dist/2022-07-16/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "b39894ecc6fd00b8398b1430285d7876f8955eeae43949e54a45a0e374ad8c37",
+    "dist/2022-07-16/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "402e022a2a7f1eb06e91ba883532b6354e94dbd1314a7ab406f37e56026e6097",
+    "dist/2022-07-16/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "97762f1261461a996626dc922f7d2b9791d38d216e871065d1c9f3fe21dd10e2",
+    "dist/2022-07-16/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "0999c8f23113ed6cdb98f0751779d90fe368d6b322a49506dd5df96e9c00ce0b",
+    "dist/2022-07-16/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "7b289c284b7b53f7f12b05f841be6d6024dc581bbe59abf07402d87f87b78231",
+    "dist/2022-07-16/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "f6a71af82c15e20aa20881fdf0daa5815c2c9589c6fab1a69fade2380c9c740c",
+    "dist/2022-07-16/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "3adc7fd340e08b482259eece4c1abc210ec32f97fe6d5fdf6847ddeebe7e8e10",
+    "dist/2022-07-16/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "2136b39139393e6b9454b0c84a0c25256a444a940b9a6c207fddc7ef2b25a22d",
+    "dist/2022-07-16/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "ec9f3f7c62dd6fcc5339579d5becd5e5542c0eb45b415b91a9a2b6ebde18bd7c",
+    "dist/2022-07-16/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "79e21a41c5400e646f4ff76d8c4c0bea12501338742ce800093ee1e06d0d6932",
+    "dist/2022-07-16/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "f686a014f19efed6d8357d0ff88702779a0132bc412cd1e6eb93b535ebf26686",
+    "dist/2022-07-16/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "45a9dbab6143f10131f702c446768e542180572033811060947d4a1d79a7c2a0",
+    "dist/2022-07-16/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "eefcfb4558b26145aebfafb193420972be8d8e6ca1b8d83a648ab9718cdbf97b",
+    "dist/2022-07-16/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "96e69f7db947588df72b49975b53387a02d102eb1295ecc8712f5cdcf0191ba7",
+    "dist/2022-07-16/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "10c2dfa886225fdcd991db70c0ae077432a9ace7f69c5464222555f1cbe9b51c",
+    "dist/2022-07-16/rust-std-beta-sparcv9-sun-solaris.tar.gz": "254a8a83f480947878a377feb64803e6b396a967e07957513741aa7aa3ef6a07",
+    "dist/2022-07-16/rust-std-beta-sparcv9-sun-solaris.tar.xz": "a18a04dfdcb6fecea8376908114690e0ca5ca54b2aced5e922f463799483d882",
+    "dist/2022-07-16/rust-std-beta-thumbv6m-none-eabi.tar.gz": "643b8d6e5b17aa5ed0696550439039651e178695348dfb11567520e0439091a3",
+    "dist/2022-07-16/rust-std-beta-thumbv6m-none-eabi.tar.xz": "9cb7f0543dfd4f13b6126a6de336a6b11eea9a241cdbbf00290ed0c7a1d331ea",
+    "dist/2022-07-16/rust-std-beta-thumbv7em-none-eabi.tar.gz": "58d094491df31e051e9fc85d4376df165ef103651b676e494beba2b689382254",
+    "dist/2022-07-16/rust-std-beta-thumbv7em-none-eabi.tar.xz": "5e44398411718fb4cd22bc13a5fd091adb23938c2010d45ce63ac0a547435406",
+    "dist/2022-07-16/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "186ac77a1844786df52e5325e9aacd519db8f61ab72cd08376e8af869ce71e22",
+    "dist/2022-07-16/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "737d50c6ad0f0918580b29bdf3cf811f43a49fc5fcfd3b4e5f0cfdfde4acbf15",
+    "dist/2022-07-16/rust-std-beta-thumbv7m-none-eabi.tar.gz": "7e6bb04375764e3c80f2d477b2a982baa170339029a8c3f99caeefb280acd95e",
+    "dist/2022-07-16/rust-std-beta-thumbv7m-none-eabi.tar.xz": "e15af6e720e2b19884a1bfa3b6c2d394082786bf95483b0962ed134d7787161c",
+    "dist/2022-07-16/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "80a32a6988b945861eb834f3bfc0cbbf594a0b2b7cb1594f150e7ac8f2919065",
+    "dist/2022-07-16/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "75f986807dbeb40418b049264334580cf0d324db80e3e86d047d65e6ebb50a2b",
+    "dist/2022-07-16/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "d86a80418c9cc9b883faf2b5e681b530ea09c550fb39b9e558a381ab67d3f43f",
+    "dist/2022-07-16/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "30af6048b67ee64c378250b23227383b799c598aa24e3a09cf50baa4e15a9833",
+    "dist/2022-07-16/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "ed57999629478f3d1efd164249bb471eaf866a95da7c0916572bd0537f40c964",
+    "dist/2022-07-16/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "232f3099d833785dc6e50dadb205ade5440e850ec24821cdd24a534a19b93cb1",
+    "dist/2022-07-16/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "56ea2a0a2ff89efaeb791df36751cd6493161878e281d3dce507f9637044e304",
+    "dist/2022-07-16/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "820b1c2fa96e952a09b32ba0a5a94239bf69ecde2bdcb769d073f35e5ee13383",
+    "dist/2022-07-16/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "a1b9d35ed7346f43025a354c38e5836340c1be3a9b2173845c91afe7bbfadfc4",
+    "dist/2022-07-16/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "e3da59132bdef040b4618037f9d7f0c38511701420a676c9d451544cbfda0ce4",
+    "dist/2022-07-16/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "e92dce094d5c503c3a66c7419f4b2b341a0647678596f6c5ec5ddebaa4107905",
+    "dist/2022-07-16/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "b7a2e4db89f9dde15b51dea0044b57204326898e351fcb45df1da31c5edbe929",
+    "dist/2022-07-16/rust-std-beta-wasm32-unknown-unknown.tar.gz": "608834a5a7d60024e2f7275ac5615d7dc1c1723b2195695eb889dbd633a45e2c",
+    "dist/2022-07-16/rust-std-beta-wasm32-unknown-unknown.tar.xz": "646cbf64202df1f11d829d371810867e12120e12266895125b53600e4d678d26",
+    "dist/2022-07-16/rust-std-beta-wasm32-wasi.tar.gz": "b1802f8dd97e213466bdaaa769ef4b03ea1baf5cd14475edba8b70dd6736b855",
+    "dist/2022-07-16/rust-std-beta-wasm32-wasi.tar.xz": "f47bf0b5aaea9d52deea681b85daab38920db504168fb9a0eeea161996eaf494",
+    "dist/2022-07-16/rust-std-beta-x86_64-apple-darwin.tar.gz": "cd5be7559517ea844335c88e3cd5846990cad18bbb4dd96c1c1add6d873b5ef3",
+    "dist/2022-07-16/rust-std-beta-x86_64-apple-darwin.tar.xz": "3e028523c2a23a5681b6a9f4ed4f4313bbc0295f3f0e986e0c6bffad69454368",
+    "dist/2022-07-16/rust-std-beta-x86_64-apple-ios.tar.gz": "7c18b0d86b4cb7da00139112966e86de05da9286fea72458056dbf1607eab774",
+    "dist/2022-07-16/rust-std-beta-x86_64-apple-ios.tar.xz": "4aeaf6925f7a591a7ff0449d98b1ee5b1fd2fbca93e8bfb7fd2b279ecd2ec2ed",
+    "dist/2022-07-16/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "62ac06824cb70a0b02292ccdca9ae4e2660644fa9a0abb186c73d64e9632c733",
+    "dist/2022-07-16/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "8642bd83f1bf709d38260ee54fbb4de679bbec802d5c72f09e1146e82195577a",
+    "dist/2022-07-16/rust-std-beta-x86_64-fuchsia.tar.gz": "caf561a7b5efb474c9db48dd5ac3ceb32505f60813324b2665fadc639e6103e1",
+    "dist/2022-07-16/rust-std-beta-x86_64-fuchsia.tar.xz": "c6481548b0ef6b9c4a82b1f697842cb7c38176acb06699d559c825243fbbaf4a",
+    "dist/2022-07-16/rust-std-beta-x86_64-linux-android.tar.gz": "be110f47348bc63d27b541af4093167cd48d5f011897482ca7a940abcfeeb1a7",
+    "dist/2022-07-16/rust-std-beta-x86_64-linux-android.tar.xz": "11ccae4e0bfc76df7bd33d858fe47ead9294cd0707aee3f42ac3683a140d583f",
+    "dist/2022-07-16/rust-std-beta-x86_64-pc-solaris.tar.gz": "78d6662fbfb469c7cb0b2f381523ebab1b566edf2dfa676c8a509a6d584e17f2",
+    "dist/2022-07-16/rust-std-beta-x86_64-pc-solaris.tar.xz": "034be03c974835fa0d2747364c8b26f50d83762316d4a266473972622e2627d6",
+    "dist/2022-07-16/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "759eed3f19e2c8203a7b03ab90eedf4b09e0edfff9fea49bcb2fc795aef66a4f",
+    "dist/2022-07-16/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "119c6fbaa021130baa881738164810d7829ee54234e8adb6e82f1f6cba9da876",
+    "dist/2022-07-16/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "b0369c5804ab496b5ae9a2643f5da959e62cf574d394d3a74a06524816bd2fc6",
+    "dist/2022-07-16/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "130b922369beb56a30666dfb6f36881105e5446284f196eef6817939f94f1b02",
+    "dist/2022-07-16/rust-std-beta-x86_64-sun-solaris.tar.gz": "5405406252ab897de56c46023de48c08d03fce7791e7db06c009d10e4c9c03f3",
+    "dist/2022-07-16/rust-std-beta-x86_64-sun-solaris.tar.xz": "b91c6f6dfbe142102a8d72b5c91f8efd1873c20e73e34d9240898a08f63d6be3",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "17526319a486038ef77e7a0f8c1ffbc6e43b4ac3eef4d14c4b70307cbd937c5e",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "8cccb4640373abd1f17418c5b7d5198e8da3af3886206dff559fa2e23c4994e2",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-illumos.tar.gz": "ff3f98720355eede902bc3c12d5ecdfc6e7f53b70133492e26b4cd464ff585f2",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-illumos.tar.xz": "73531fe83d87304fe54adee9ede87e82220afd4dcb5c1a27878a1d9dd7dce9d9",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "936855bb97c47c0978caa65748515e3e7550916beb5d06aa569dab6192738886",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "e8b95205019e5f73e86247da9f5dab22f8ceaa98f6afa8f0eb7c6d92a258b97e",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "2f016727a0d761960923f4a83cce489d2f4d87b354352d109be1e89ad45f99e4",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "16f0829deae2df1fee609dfae7ec51bbcb7da5a9dcfe48f4d517d07934463b42",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "8bb4f4c9bb114cdee7c3d95c78e66f9c574ae47116b3aa0401712eb29c41461f",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "8a4977f3bb54c0f260c4b41f2fc7bf0fb06fd69e6eb9a9c88c438274f7ea993d",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "2b361b36d6a6f917b17a92b68dc9fb80c05e0b90a1987f4761b05ecb970ef4c6",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "5a4069a5ee239d289e13f8071c3fab252dab944706c2e223f763107509730fda",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-none.tar.gz": "d4b0d375705732ac44da55e5272bde7c0756231bed205fabfa5b8b265e0d8e79",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-none.tar.xz": "5d4f05830dc0530d60e0d570e692b0c4d7ee48e68d4bb3838878fead474bc063",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-redox.tar.gz": "c43fb78286169bcdede9e092d84a9f2e7762ad67bdd2ed7a14d6d3234af52b9e",
+    "dist/2022-07-16/rust-std-beta-x86_64-unknown-redox.tar.xz": "905d5a8f6f642a978e55afc45329f6b7b6083a34ec6f51de0bb854685c5e3add",
+    "dist/2022-07-16/rustc-beta-aarch64-apple-darwin.tar.gz": "86afdc287964673c25d3c625b5bf03231d897d46fe8565e1078747e7b85bc627",
+    "dist/2022-07-16/rustc-beta-aarch64-apple-darwin.tar.xz": "8cd87fd24927617793bb06edc581184edfc12de7c961f03a530aee7eb793166f",
+    "dist/2022-07-16/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "6c2858cc584d845ebcb8cc4dbadc5b0bf4e875dd0920b2d9106791b8bb7567e7",
+    "dist/2022-07-16/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "dde2c77b23b8ecedbec8427c3b8f6a889d96b053de74787a73faef366cdb30c1",
+    "dist/2022-07-16/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "5ff5ae57cc7eacf26a3410c499d23e520ed9ef20f7aa50e77a3354a7bbed541f",
+    "dist/2022-07-16/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "850f4456625e7ae545c3036338b5bdcb1982a2fca4d1664efc835630a7e42468",
+    "dist/2022-07-16/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "5409263cbb71867780c8a2bcce126665217632d8eb7e4dab95c199ebfee8755e",
+    "dist/2022-07-16/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "deeeff68790e4857d625fdc1e0ed430e4d31b4e5e87b5534d899cdf7fec2adf5",
+    "dist/2022-07-16/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "0701e5f5d04db2cc677366ec769fa3f6c39351a9527f8493fd54d29086294a00",
+    "dist/2022-07-16/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "a133838e0eb1d9177fe0c052667ba9820a6ba5cbba604a80ad732ca5c1e23846",
+    "dist/2022-07-16/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "9ad3ad6c0c27d50238f83821b526a1d6f598ff293a36381d0a8a28cbd0a7ab4e",
+    "dist/2022-07-16/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "3313866d0d78c82b0b571e889d6ed85fce80dc2ea3dcc495f4738672e8d3b972",
+    "dist/2022-07-16/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "0459cf4a11cc6d41aa95d837b73a339fbf1c50ecfc078a95705c110d03a9c941",
+    "dist/2022-07-16/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "16b092bd7fccc84d6776f8cf3794c302b258fe9b3bf2adcc2ba1551197d3ab92",
+    "dist/2022-07-16/rustc-beta-i686-pc-windows-gnu.tar.gz": "c3c49711e23a87fb78d2a85d4838893963f151918464708f61cbd0a0ef8d6841",
+    "dist/2022-07-16/rustc-beta-i686-pc-windows-gnu.tar.xz": "eac7e88ef96b4eb99d5f15e168c7b782f0c9bfced92e5852559414e4c95a18c4",
+    "dist/2022-07-16/rustc-beta-i686-pc-windows-msvc.tar.gz": "fe6f0c952dccbe7262678615c8a850ce76f510295202427a16755005f3505744",
+    "dist/2022-07-16/rustc-beta-i686-pc-windows-msvc.tar.xz": "bd596d7e1fac9b4e02a036aa1e59819317d210044b3298bf4ec3633817f2ec2b",
+    "dist/2022-07-16/rustc-beta-i686-unknown-linux-gnu.tar.gz": "5dbbdd77e606ad28421a39d9ec95d2254e2658033247d94a733dec05a2368cb5",
+    "dist/2022-07-16/rustc-beta-i686-unknown-linux-gnu.tar.xz": "f9471eb60265b18f755c76dc4786895804fdc2b0ed8c8c8e58a454dbd1eca3b3",
+    "dist/2022-07-16/rustc-beta-mips-unknown-linux-gnu.tar.gz": "e4e8e67a0c4240ccb478631ee3b7a0fcc22d68b2adce26228f5fc9fff34dc03c",
+    "dist/2022-07-16/rustc-beta-mips-unknown-linux-gnu.tar.xz": "c7879912b5b6bfbaea4b424562ac1174bab8e30a4d20b3a82291b606a5a5f09e",
+    "dist/2022-07-16/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "3b437ea0fe1c9f52505cc7e5cfe2b3b103973e3ba3c132ba304d828c210e7eb1",
+    "dist/2022-07-16/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "d1c144f58626f3b0df9a24ffe5db9b2df45a410071df551fec48e0a7097bb17a",
+    "dist/2022-07-16/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "364647a234f7d40095d38cf01fcbdf554128436829d2972cb22f91fde18b346a",
+    "dist/2022-07-16/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "fc2c9200111139a051c8e3bb41f936b2126d24ca91ba175d88de95d59b6e00da",
+    "dist/2022-07-16/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "884a0da049f646196964f6cf93f03d9211e3864b39190432ee2e369c34051717",
+    "dist/2022-07-16/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "d82cd504ff34e741c9cf246fd6d8829f8af74d36670de46daea858a2c282f286",
+    "dist/2022-07-16/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "0fdd190eec39c72972d8d4df7fb59c77ffd9e9fad4d219264b6ceaa301c0250f",
+    "dist/2022-07-16/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "e74704b5c21a77c3d1dd7f265a7f24e9f904405afc3170d5f3836c8d28105ee0",
+    "dist/2022-07-16/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "90c1480f585ad1d9e0c3b564f5eb87667eedf5992ce46f73d6462dbb9a136182",
+    "dist/2022-07-16/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "e5b3e75d5d85e84fbf8c0d4b8e1f4c20421e1d20c18805f413f785d594c14a4c",
+    "dist/2022-07-16/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "5163f545aca9e56edb0510c30eb9343dbdd95ce3704677cdbebcb70947437838",
+    "dist/2022-07-16/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f6c61e0c2bb404f248986287dcf7f4bcf8458fd17e678bbb53c43ce5ef19d5eb",
+    "dist/2022-07-16/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "fce64768b803f67470e093422926f44cf621eca5052eff4d9c6b89b94556b411",
+    "dist/2022-07-16/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "e99f1ae947b812047c4367d87f0f4dde6581c0af02240625500b1ddc9133025e",
+    "dist/2022-07-16/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "c6bb4bd5eaea57d15dd995de614471aeaddd103158e609ecdf43177f1843c25b",
+    "dist/2022-07-16/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "8e54cc288f3bb2a268fe37f2815ce94c3810438aefdfab9dd679ef572dbc127b",
+    "dist/2022-07-16/rustc-beta-x86_64-apple-darwin.tar.gz": "dc06d6cc19934b091cb3894c42debf6189f7b2d54162cc93418cb8851c967154",
+    "dist/2022-07-16/rustc-beta-x86_64-apple-darwin.tar.xz": "2f177aa386c389ce18ec47495d5c48d5512bee00aed0e3dad53809fbdb81f55a",
+    "dist/2022-07-16/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "e6af40fc7d92ddfd3bdab6ed92b8bb614df2ef7158a8f59291593034191d483a",
+    "dist/2022-07-16/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5c51250a55d9e424ced7f91a90a801d53bfcf489be033a06c15adfcd587f5e47",
+    "dist/2022-07-16/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "f4bc463f82baa6681ad7292c512836bde962743b32b28ba118c38622dc3478f4",
+    "dist/2022-07-16/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "a25e397cd228f44c0280f61621bdbab028fb07a20551a3c1b25606d0eefc4745",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-freebsd.tar.gz": "27e0d39b8bdde40899a1486fc39b6bc612068dc4d4db65d52a4b3c85f03675e4",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-freebsd.tar.xz": "74f59446e6e6b031fedd12d10380bd33c119b09d0d1435488008f104a4297a97",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-illumos.tar.gz": "9b49259f9446ffdc510b80b3cb67084f006cbf86bc6c14e6a6a42128657773eb",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-illumos.tar.xz": "2a5b5c0f33dcdf79afce7445d6dd0183ba95f898becfca6eace5858e6836706f",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "b891c82a6acbb2ee5e3b46c4e5ebfc4a215e70415879425125934b7fa8c33329",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "e33bf0cd9e7e50469c9cd98c9404aa7495268192e4be70117c75607a9a18bb95",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f5ed5f80204fa0608e888750866b880575d9eba63bbcd69b71708713a27fe27c",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "3f69e388b687cbdafaf59ca3486eed4dda510652a8ee37fde9efeff096258801",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-netbsd.tar.gz": "57eb4ebf820c11e5d4700f6c3ec414e6d2b70475f71579f854aec66650ab9eb3",
+    "dist/2022-07-16/rustc-beta-x86_64-unknown-netbsd.tar.xz": "979c3d20834c4bdee5b47598fddc26c3e02edd7678ee34faf97ac5f11aa8314b",
+    "dist/2022-07-21/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "9099fe96569cf008c9bb92f86efe1773a1e6f8542e71af037727d411ca3e4c92",
+    "dist/2022-07-21/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "085c6086a977725738ee44c4e0b748be255847c740fbce4aec62519afa91c088",
+    "dist/2022-07-21/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "c829b598f2a7d815ddb1772153aa847e5f1fe844710acc01e18f626d5af1daaf",
+    "dist/2022-07-21/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "50d3336081798cf6dffa615e1217845b51f82017375b4b0cf18167a939de0a5c",
+    "dist/2022-07-21/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "40a86effd1d5b60735d15c33090e31a0ed1cccdcca7cece013176071a90f3c93",
+    "dist/2022-07-21/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "ee29ab772f2f24f7f4f8655cbab2a64ad7fd2253ce04a4a72c497cdd18fd71cc",
+    "dist/2022-07-21/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "d739d788caf9190fccbab1a00e42f75bb7e10d94263b556578175bdd11826468",
+    "dist/2022-07-21/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "9775c98de87876ade2a7896e0df6519334ffb21cca12f60afa1874105b7dc75b",
+    "dist/2022-07-21/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "241d9983b1314829b9311bb7e1743e422b81d22342eed7216ba534788df77016",
+    "dist/2022-07-21/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "df50d81cf63dfea4a17f32318d4b4111944323395641ad9f7c989f9f74dbd383",
+    "dist/2022-07-21/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "1953f4f8c244c81e60a97c9480f78c0a3e0373c44ef7c188306ea26a6ff087e1",
+    "dist/2022-07-21/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "296273dfe9ad0ebf0ef47bb0a566050f90ec235bdb3d7776371b0b249466764e",
+    "dist/2022-07-21/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "da67ad4667d2b39862e21d43b9e0a99ad0bbd36ccc936779ed6dacb9b2fd17c2",
+    "dist/2022-07-21/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "efc5eb6d3c6fabdb03b83c9e9215b13955f82ceec62255aafd78db0e28ba8421",
+    "dist/2022-07-21/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "e603216f64f6fcf3ca21581dcdd283b41a1b6a59779c7760b8aa79b4c593e7e8",
+    "dist/2022-07-21/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "7c5c47faf6f014b63e1193cbf27de51bec82e9811537a17cb9b4922b709618c8",
+    "dist/2022-07-21/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "ac605732e74a1c344ea7c6ef84a6ca1823d3ed51024ef895ec9a181a6f91f8c3",
+    "dist/2022-07-21/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "7044d68341f8ea2fef122600f3995fff681599dc1a545ab2b45d1b2302fd6436",
+    "dist/2022-07-21/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "b7d57d01a9985826333ecac8447e0a1a5a753cf0ed11770de70d47b59050215b",
+    "dist/2022-07-21/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "13076a20f555c18db2d38deaaf33aeaed0f27b8cb5a2962b26661b6989dc3a5f",
+    "dist/2022-07-21/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "c64ab15040368af0c595102a7232b405b1a52164fe39e06ba189b2a26c70fe9d",
+    "dist/2022-07-21/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "a05b3aa95231a7e6631f0da01869d8cb8b6e3a5c184eb411591583cc78cd3aaf",
+    "dist/2022-07-21/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "242650636f9b33adc71a8c1bba1dc3a2928ba7723c976ae5645428b47862c658",
+    "dist/2022-07-21/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "7a2a54f05cac08aa65645e099d2597504477bba269b6f74e99f2df397a660eaf",
+    "dist/2022-07-21/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "2c3f944a0b8a5b06c4a341882934b737a451baf38f7a902f0794b0f41e1102e3",
+    "dist/2022-07-21/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "506e4f89b5243b8c2f6709d69a8b8facad5d7a555b108bed4f689dbd3fe1e46e",
+    "dist/2022-07-21/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "fe3a12786f8eecf26213286045a69bc1046d7138a401511618b86b74a70eb66a",
+    "dist/2022-07-21/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "37409a8573c5d0c9ea1fd0a745990a4e85f325a87a25c9916dd25617b6059783",
+    "dist/2022-07-21/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "e74050fa0288e7368a9e65f2739498f38ca9c91d36c519674e4590c17d86fcd7",
+    "dist/2022-07-21/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "10da2c6d12e14f4a2c6c9a7f1d2c161a62e4f9956ed7ee100ba31fce9446ea78",
+    "dist/2022-07-21/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "a0cf070555fed25a8aa9f20d704149936dca1ccb7c3aa55aabad2be84a7860f7",
+    "dist/2022-07-21/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "f388ba16822251f2dff0d9fd837dc19c5ca181ebabc93ed81759530d07dce72f",
+    "dist/2022-07-21/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "6056b5c1f46807fce83c4c3e2a443beb66b433e678fb090ca253aef5a87d2927",
+    "dist/2022-07-21/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "642046b17142d6e9ecd207243ed82108088c941b04ee5d8f6b1371b07da60601",
+    "dist/2022-07-21/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "600b5e7a11e3cb583fae2ef9f9dc784c2bef08e355da9e3a37204e0c81a63451",
+    "dist/2022-07-21/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "a9019c838270635f2fe383da5b11fdef2c7b23f838bc5edee7ba5882e7102c63",
+    "dist/2022-07-21/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "613539dc9a67c78216d8d11b0d9baf068d48c4067d628c8144bccec2d899afd1",
+    "dist/2022-07-21/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "55d992631c567da8ea082ca6dfcfdbf4774374ec430050a16001def2221adafe",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "9bade75f59be530972a26618f4e283c89bda864cfd162f47c8d1782d31163148",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "39f21c72c31dc0cf945db142cead8aa8f9208769d8f4336905794ec52848e90e",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "3b5cdcc58acad278a1b4eb84dc5aacd8eafe0bd2ac0ab62c5056c918661a9364",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "159dd0daacf54993386b2d1cefab13354d9c7614983745d43c28a1a873fbe498",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "cfef1baac5ef48912a3d30b3ba6513da50e6a35d1ad8687452dfe64e671effc7",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "8c72ca088ae104dd3cd1ce711e083a1816d16876ddd1a07af983d9c22cec1a33",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "fdecac3b5e42523e9f5200080f682e3b557b6820ae0f67a02620e1d1fba6f571",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "cbf56b942479ee95c89e14b060765ab8e21b2152b2c3e02ffb47957e37cec4cf",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "309be4a29a875ba17ed14e351a6aff7a649e0e6897f3d2c3394f2f2ae966a275",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "72e6bfd09cb22f8400dbef4017cd09deb2881cdf67df61d4e4d2d2ed5221a683",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "d40edc2217657dedee45336aad31289190a7da43bc5620b5d36b7dc0fce1f211",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "1df1787f682e9a8bd97a054f76094281fccd4d321c3067e2600860327dd088e3",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "91ed27676b13193eecb93839c0c748e667e869f091de88cea4183c51870efbe8",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "ccb0245ac982c34c9db9f6ffc3c30769e2b62637a18d88dc30a4ed3c1922fa7e",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "54344a42f2fca291c0c10f84386135e2797c9b81519eab0c6db633a95c109f20",
+    "dist/2022-07-21/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "4a276eac1bdace68484b49104b8bb2c48f93a775404f2bd29e9c3d4c6ce7367f"
   }
 }
diff --git a/src/test/assembly/static-relocation-model.rs b/src/test/assembly/static-relocation-model.rs
index 6c41e0b78f1..faa2e395209 100644
--- a/src/test/assembly/static-relocation-model.rs
+++ b/src/test/assembly/static-relocation-model.rs
@@ -36,7 +36,8 @@ extern "C" {
 }
 
 // CHECK-LABEL: banana:
-// x64: movb   chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
+// On the next line LLVM 14 produces a `movb`, whereas LLVM 15+ produces a `movzbl`.
+// x64: {{movb|movzbl}}   chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
 // A64:      adrp    [[REG:[a-z0-9]+]], chaenomeles
 // A64-NEXT: ldrb    {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles]
 #[no_mangle]
@@ -47,7 +48,7 @@ pub fn banana() -> u8 {
 }
 
 // CHECK-LABEL: peach:
-// x64: movb    banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
+// x64: {{movb|movzbl}}    banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
 // A64:      adrp    [[REG2:[a-z0-9]+]], banana
 // A64-NEXT: ldrb    {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana]
 #[no_mangle]
@@ -59,7 +60,7 @@ pub fn peach() -> u8 {
 
 // CHECK-LABEL: mango:
 // x64:      movq    EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]]
-// x64-NEXT: movb    (%[[REG]]), %{{[a-z0-9]+}}
+// x64-NEXT: {{movb|movzbl}}   (%[[REG]]), %{{[a-z0-9]+}}
 // A64:      adrp    [[REG2:[a-z0-9]+]], EXOCHORDA
 // A64-NEXT: ldr     {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA]
 #[no_mangle]
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index ae6abe7a184..dda139be6fc 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -5,6 +5,7 @@
 
 use std::mem::MaybeUninit;
 use std::num::NonZeroU64;
+use std::marker::PhantomPinned;
 
 pub struct S {
   _field: [i32; 8],
@@ -14,6 +15,11 @@ pub struct UnsafeInner {
   _field: std::cell::UnsafeCell<i16>,
 }
 
+pub struct NotUnpin {
+  _field: i32,
+  _marker: PhantomPinned,
+}
+
 pub enum MyBool {
   True,
   False,
@@ -91,7 +97,7 @@ pub fn static_borrow(_: &'static i32) {
 pub fn named_borrow<'r>(_: &'r i32) {
 }
 
-// CHECK: @unsafe_borrow({{i16\*|ptr}} noundef align 2 dereferenceable(2) %_1)
+// CHECK: @unsafe_borrow({{i16\*|ptr}} noundef nonnull align 2 %_1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_borrow(_: &UnsafeInner) {
@@ -109,6 +115,18 @@ pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 pub fn mutable_borrow(_: &mut i32) {
 }
 
+#[no_mangle]
+// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef align 4 dereferenceable(4) %_1)
+// This one is *not* `noalias` because it might be self-referential.
+pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
+}
+
+// CHECK: @notunpin_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
+// But `&NotUnpin` behaves perfectly normal.
+#[no_mangle]
+pub fn notunpin_borrow(_: &NotUnpin) {
+}
+
 // CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {
diff --git a/src/test/codegen/noalias-box-off.rs b/src/test/codegen/noalias-box-off.rs
new file mode 100644
index 00000000000..afd17c7c160
--- /dev/null
+++ b/src/test/codegen/noalias-box-off.rs
@@ -0,0 +1,8 @@
+// compile-flags: -O -Z box-noalias=no
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @box_should_not_have_noalias_if_disabled(
+// CHECK-NOT: noalias
+#[no_mangle]
+pub fn box_should_not_have_noalias_if_disabled(_b: Box<u8>) {}
diff --git a/src/test/codegen/noalias-box.rs b/src/test/codegen/noalias-box.rs
new file mode 100644
index 00000000000..a3d1f093d8b
--- /dev/null
+++ b/src/test/codegen/noalias-box.rs
@@ -0,0 +1,8 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @box_should_have_noalias_by_default(
+// CHECK: noalias
+#[no_mangle]
+pub fn box_should_have_noalias_by_default(_b: Box<u8>) {}
diff --git a/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs b/src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs
index 68f81808861..c42fbba7425 100644
--- a/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs
+++ b/src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs
@@ -1,10 +1,7 @@
 // Verifies that "CFI Canonical Jump Tables" module flag is added.
 //
-// ignore-windows
 // needs-sanitizer-cfi
-// only-aarch64
-// only-x86_64
-// compile-flags: -Clto -Zsanitizer=cfi
+// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
 
 #![crate_type="lib"]
 
diff --git a/src/test/codegen/sanitizer_cfi_emit_type_checks.rs b/src/test/codegen/sanitizer-cfi-emit-type-checks.rs
index 9ed0422ceff..082f0f121ff 100644
--- a/src/test/codegen/sanitizer_cfi_emit_type_checks.rs
+++ b/src/test/codegen/sanitizer-cfi-emit-type-checks.rs
@@ -1,10 +1,7 @@
 // Verifies that pointer type membership tests for indirect calls are emitted.
 //
-// ignore-windows
 // needs-sanitizer-cfi
-// only-aarch64
-// only-x86_64
-// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
+// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
 
 #![crate_type="lib"]
 
diff --git a/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs
new file mode 100644
index 00000000000..ece2adbdf43
--- /dev/null
+++ b/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs
@@ -0,0 +1,575 @@
+// Verifies that type metadata identifiers for functions are emitted correctly.
+//
+// needs-sanitizer-cfi
+// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type="lib"]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+#![allow(unused_must_use)]
+#![feature(adt_const_params, extern_types, inline_const, type_alias_impl_trait)]
+
+extern crate core;
+use core::ffi::c_void;
+use std::marker::PhantomData;
+
+// User-defined type (structure)
+pub struct Struct1<T> {
+    member1: T,
+}
+
+// User-defined type (enum)
+pub enum Enum1<T> {
+    Variant1(T),
+}
+
+// User-defined type (union)
+pub union Union1<T> {
+    member1: std::mem::ManuallyDrop<T>,
+}
+
+// Extern type
+extern {
+    pub type type1;
+}
+
+// Trait
+pub trait Trait1<T> {
+    fn foo(&self) { }
+}
+
+// Trait implementation
+impl<T> Trait1<T> for i32 {
+    fn foo(&self) { }
+}
+
+// Trait implementation
+impl<T> Trait1<T> for Struct1<T> {
+    fn foo(&self) { }
+}
+
+// impl Trait type aliases for helping with defining other types (see below)
+pub type Type1 = impl Send;
+pub type Type2 = impl Send;
+pub type Type3 = impl Send;
+pub type Type4 = impl Send;
+pub type Type5 = impl Send;
+pub type Type6 = impl Send;
+pub type Type7 = impl Send;
+pub type Type8 = impl Send;
+pub type Type9 = impl Send;
+pub type Type10 = impl Send;
+pub type Type11 = impl Send;
+
+pub fn fn1<'a>() {
+    // Closure
+    let closure1 = || { };
+    let _: Type1 = closure1;
+
+    // Constructor
+    pub struct Foo(i32);
+    let _: Type2 = Foo;
+
+    // Type in extern path
+    extern {
+        fn foo();
+    }
+    let _: Type3 = foo;
+
+    // Type in closure path
+    || {
+        pub struct Foo;
+        let _: Type4 = Foo;
+    };
+
+    // Type in const path
+    const {
+        pub struct Foo;
+        fn foo() -> Type5 { Foo }
+    };
+
+    // Type in impl path
+    impl<T> Struct1<T> {
+        fn foo(&self) { }
+    }
+    let _: Type6 = <Struct1<i32>>::foo;
+
+    // Trait method
+    let _: Type7 = <dyn Trait1<i32>>::foo;
+
+    // Trait method
+    let _: Type8 = <i32 as Trait1<i32>>::foo;
+
+    // Trait method
+    let _: Type9 = <Struct1<i32> as Trait1<i32>>::foo;
+
+    // Const generics
+    pub struct Qux<T, const N: usize>([T; N]);
+    let _: Type10 = Qux([0; 32]);
+
+    // Lifetimes/regions
+    pub struct Quux<'a>(&'a i32);
+    pub struct Quuux<'a, 'b>(&'a i32, &'b Quux<'b>);
+    let _: Type11 = Quuux;
+}
+
+// repr(transparent) user-defined type
+struct Foo(i32);
+
+#[repr(transparent)]
+pub struct Type12 {
+    member1: (),
+    member2: PhantomData<i32>,
+    member3: Foo,
+}
+
+// Self-referencing repr(transparent) user-defined type
+#[repr(transparent)]
+pub struct Type13<'a> {
+    member1: (),
+    member2: PhantomData<i32>,
+    member3: &'a Type13<'a>,
+}
+
+pub fn foo0(_: ()) { }
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]]
+pub fn foo1(_: c_void, _: ()) { }
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]]
+pub fn foo2(_: (), _: c_void, _: c_void) { }
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]]
+pub fn foo3(_: *mut c_void) { }
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]]
+pub fn foo4(_: *mut c_void, _: *mut ()) { }
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]]
+pub fn foo5(_: *mut (), _: *mut c_void, _: *mut c_void) { }
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]]
+pub fn foo6(_: *const c_void) { }
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]]
+pub fn foo7(_: *const c_void, _: *const ()) { }
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]]
+pub fn foo8(_: *const (), _: *const c_void, _: *const c_void) { }
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]]
+pub fn foo9(_: bool) { }
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]]
+pub fn foo10(_: bool, _: bool) { }
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]]
+pub fn foo11(_: bool, _: bool, _: bool) { }
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]]
+pub fn foo12(_: i8) { }
+// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]]
+pub fn foo13(_: i8, _: i8) { }
+// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]]
+pub fn foo14(_: i8, _: i8, _: i8) { }
+// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]]
+pub fn foo15(_: i16) { }
+// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]]
+pub fn foo16(_: i16, _: i16) { }
+// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]]
+pub fn foo17(_: i16, _: i16, _: i16) { }
+// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]]
+pub fn foo18(_: i32) { }
+// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]]
+pub fn foo19(_: i32, _: i32) { }
+// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]]
+pub fn foo20(_: i32, _: i32, _: i32) { }
+// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]]
+pub fn foo21(_: i64) { }
+// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]]
+pub fn foo22(_: i64, _: i64) { }
+// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]]
+pub fn foo23(_: i64, _: i64, _: i64) { }
+// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]]
+pub fn foo24(_: i128) { }
+// CHECK: define{{.*}}foo24{{.*}}!type ![[TYPE24:[0-9]+]]
+pub fn foo25(_: i128, _: i128) { }
+// CHECK: define{{.*}}foo25{{.*}}!type ![[TYPE25:[0-9]+]]
+pub fn foo26(_: i128, _: i128, _: i128) { }
+// CHECK: define{{.*}}foo26{{.*}}!type ![[TYPE26:[0-9]+]]
+pub fn foo27(_: isize) { }
+// CHECK: define{{.*}}foo27{{.*}}!type ![[TYPE27:[0-9]+]]
+pub fn foo28(_: isize, _: isize) { }
+// CHECK: define{{.*}}foo28{{.*}}!type ![[TYPE28:[0-9]+]]
+pub fn foo29(_: isize, _: isize, _: isize) { }
+// CHECK: define{{.*}}foo29{{.*}}!type ![[TYPE29:[0-9]+]]
+pub fn foo30(_: u8) { }
+// CHECK: define{{.*}}foo30{{.*}}!type ![[TYPE30:[0-9]+]]
+pub fn foo31(_: u8, _: u8) { }
+// CHECK: define{{.*}}foo31{{.*}}!type ![[TYPE31:[0-9]+]]
+pub fn foo32(_: u8, _: u8, _: u8) { }
+// CHECK: define{{.*}}foo32{{.*}}!type ![[TYPE32:[0-9]+]]
+pub fn foo33(_: u16) { }
+// CHECK: define{{.*}}foo33{{.*}}!type ![[TYPE33:[0-9]+]]
+pub fn foo34(_: u16, _: u16) { }
+// CHECK: define{{.*}}foo34{{.*}}!type ![[TYPE34:[0-9]+]]
+pub fn foo35(_: u16, _: u16, _: u16) { }
+// CHECK: define{{.*}}foo35{{.*}}!type ![[TYPE35:[0-9]+]]
+pub fn foo36(_: u32) { }
+// CHECK: define{{.*}}foo36{{.*}}!type ![[TYPE36:[0-9]+]]
+pub fn foo37(_: u32, _: u32) { }
+// CHECK: define{{.*}}foo37{{.*}}!type ![[TYPE37:[0-9]+]]
+pub fn foo38(_: u32, _: u32, _: u32) { }
+// CHECK: define{{.*}}foo38{{.*}}!type ![[TYPE38:[0-9]+]]
+pub fn foo39(_: u64) { }
+// CHECK: define{{.*}}foo39{{.*}}!type ![[TYPE39:[0-9]+]]
+pub fn foo40(_: u64, _: u64) { }
+// CHECK: define{{.*}}foo40{{.*}}!type ![[TYPE40:[0-9]+]]
+pub fn foo41(_: u64, _: u64, _: u64) { }
+// CHECK: define{{.*}}foo41{{.*}}!type ![[TYPE41:[0-9]+]]
+pub fn foo42(_: u128) { }
+// CHECK: define{{.*}}foo42{{.*}}!type ![[TYPE42:[0-9]+]]
+pub fn foo43(_: u128, _: u128) { }
+// CHECK: define{{.*}}foo43{{.*}}!type ![[TYPE43:[0-9]+]]
+pub fn foo44(_: u128, _: u128, _: u128) { }
+// CHECK: define{{.*}}foo44{{.*}}!type ![[TYPE44:[0-9]+]]
+pub fn foo45(_: usize) { }
+// CHECK: define{{.*}}foo45{{.*}}!type ![[TYPE45:[0-9]+]]
+pub fn foo46(_: usize, _: usize) { }
+// CHECK: define{{.*}}foo46{{.*}}!type ![[TYPE46:[0-9]+]]
+pub fn foo47(_: usize, _: usize, _: usize) { }
+// CHECK: define{{.*}}foo47{{.*}}!type ![[TYPE47:[0-9]+]]
+pub fn foo48(_: f32) { }
+// CHECK: define{{.*}}foo48{{.*}}!type ![[TYPE48:[0-9]+]]
+pub fn foo49(_: f32, _: f32) { }
+// CHECK: define{{.*}}foo49{{.*}}!type ![[TYPE49:[0-9]+]]
+pub fn foo50(_: f32, _: f32, _: f32) { }
+// CHECK: define{{.*}}foo50{{.*}}!type ![[TYPE50:[0-9]+]]
+pub fn foo51(_: f64) { }
+// CHECK: define{{.*}}foo51{{.*}}!type ![[TYPE51:[0-9]+]]
+pub fn foo52(_: f64, _: f64) { }
+// CHECK: define{{.*}}foo52{{.*}}!type ![[TYPE52:[0-9]+]]
+pub fn foo53(_: f64, _: f64, _: f64) { }
+// CHECK: define{{.*}}foo53{{.*}}!type ![[TYPE53:[0-9]+]]
+pub fn foo54(_: char) { }
+// CHECK: define{{.*}}foo54{{.*}}!type ![[TYPE54:[0-9]+]]
+pub fn foo55(_: char, _: char) { }
+// CHECK: define{{.*}}foo55{{.*}}!type ![[TYPE55:[0-9]+]]
+pub fn foo56(_: char, _: char, _: char) { }
+// CHECK: define{{.*}}foo56{{.*}}!type ![[TYPE56:[0-9]+]]
+pub fn foo57(_: &str) { }
+// CHECK: define{{.*}}foo57{{.*}}!type ![[TYPE57:[0-9]+]]
+pub fn foo58(_: &str, _: &str) { }
+// CHECK: define{{.*}}foo58{{.*}}!type ![[TYPE58:[0-9]+]]
+pub fn foo59(_: &str, _: &str, _: &str) { }
+// CHECK: define{{.*}}foo59{{.*}}!type ![[TYPE59:[0-9]+]]
+pub fn foo60(_: (i32, i32)) { }
+// CHECK: define{{.*}}foo60{{.*}}!type ![[TYPE60:[0-9]+]]
+pub fn foo61(_: (i32, i32), _: (i32, i32)) { }
+// CHECK: define{{.*}}foo61{{.*}}!type ![[TYPE61:[0-9]+]]
+pub fn foo62(_: (i32, i32), _: (i32, i32), _: (i32, i32)) { }
+// CHECK: define{{.*}}foo62{{.*}}!type ![[TYPE62:[0-9]+]]
+pub fn foo63(_: [i32; 32]) { }
+// CHECK: define{{.*}}foo63{{.*}}!type ![[TYPE63:[0-9]+]]
+pub fn foo64(_: [i32; 32], _: [i32; 32]) { }
+// CHECK: define{{.*}}foo64{{.*}}!type ![[TYPE64:[0-9]+]]
+pub fn foo65(_: [i32; 32], _: [i32; 32], _: [i32; 32]) { }
+// CHECK: define{{.*}}foo65{{.*}}!type ![[TYPE65:[0-9]+]]
+pub fn foo66(_: &[i32]) { }
+// CHECK: define{{.*}}foo66{{.*}}!type ![[TYPE66:[0-9]+]]
+pub fn foo67(_: &[i32], _: &[i32]) { }
+// CHECK: define{{.*}}foo67{{.*}}!type ![[TYPE67:[0-9]+]]
+pub fn foo68(_: &[i32], _: &[i32], _: &[i32]) { }
+// CHECK: define{{.*}}foo68{{.*}}!type ![[TYPE68:[0-9]+]]
+pub fn foo69(_: &Struct1::<i32>) { }
+// CHECK: define{{.*}}foo69{{.*}}!type ![[TYPE69:[0-9]+]]
+pub fn foo70(_: &Struct1::<i32>, _: &Struct1::<i32>) { }
+// CHECK: define{{.*}}foo70{{.*}}!type ![[TYPE70:[0-9]+]]
+pub fn foo71(_: &Struct1::<i32>, _: &Struct1::<i32>, _: &Struct1::<i32>) { }
+// CHECK: define{{.*}}foo71{{.*}}!type ![[TYPE71:[0-9]+]]
+pub fn foo72(_: &Enum1::<i32>) { }
+// CHECK: define{{.*}}foo72{{.*}}!type ![[TYPE72:[0-9]+]]
+pub fn foo73(_: &Enum1::<i32>, _: &Enum1::<i32>) { }
+// CHECK: define{{.*}}foo73{{.*}}!type ![[TYPE73:[0-9]+]]
+pub fn foo74(_: &Enum1::<i32>, _: &Enum1::<i32>, _: &Enum1::<i32>) { }
+// CHECK: define{{.*}}foo74{{.*}}!type ![[TYPE74:[0-9]+]]
+pub fn foo75(_: &Union1::<i32>) { }
+// CHECK: define{{.*}}foo75{{.*}}!type ![[TYPE75:[0-9]+]]
+pub fn foo76(_: &Union1::<i32>, _: &Union1::<i32>) { }
+// CHECK: define{{.*}}foo76{{.*}}!type ![[TYPE76:[0-9]+]]
+pub fn foo77(_: &Union1::<i32>, _: &Union1::<i32>, _: &Union1::<i32>) { }
+// CHECK: define{{.*}}foo77{{.*}}!type ![[TYPE77:[0-9]+]]
+pub fn foo78(_: *mut type1) { }
+// CHECK: define{{.*}}foo78{{.*}}!type ![[TYPE78:[0-9]+]]
+pub fn foo79(_: *mut type1, _: *mut type1) { }
+// CHECK: define{{.*}}foo79{{.*}}!type ![[TYPE79:[0-9]+]]
+pub fn foo80(_: *mut type1, _: *mut type1, _: *mut type1) { }
+// CHECK: define{{.*}}foo80{{.*}}!type ![[TYPE80:[0-9]+]]
+pub fn foo81(_: &mut i32) { }
+// CHECK: define{{.*}}foo81{{.*}}!type ![[TYPE81:[0-9]+]]
+pub fn foo82(_: &mut i32, _: &i32) { }
+// CHECK: define{{.*}}foo82{{.*}}!type ![[TYPE82:[0-9]+]]
+pub fn foo83(_: &mut i32, _: &i32, _: &i32) { }
+// CHECK: define{{.*}}foo83{{.*}}!type ![[TYPE83:[0-9]+]]
+pub fn foo84(_: &i32) { }
+// CHECK: define{{.*}}foo84{{.*}}!type ![[TYPE84:[0-9]+]]
+pub fn foo85(_: &i32, _: &mut i32) { }
+// CHECK: define{{.*}}foo85{{.*}}!type ![[TYPE85:[0-9]+]]
+pub fn foo86(_: &i32, _: &mut i32, _: &mut i32) { }
+// CHECK: define{{.*}}foo86{{.*}}!type ![[TYPE86:[0-9]+]]
+pub fn foo87(_: *mut i32) { }
+// CHECK: define{{.*}}foo87{{.*}}!type ![[TYPE87:[0-9]+]]
+pub fn foo88(_: *mut i32, _: *const i32) { }
+// CHECK: define{{.*}}foo88{{.*}}!type ![[TYPE88:[0-9]+]]
+pub fn foo89(_: *mut i32, _: *const i32, _: *const i32) { }
+// CHECK: define{{.*}}foo89{{.*}}!type ![[TYPE89:[0-9]+]]
+pub fn foo90(_: *const i32) { }
+// CHECK: define{{.*}}foo90{{.*}}!type ![[TYPE90:[0-9]+]]
+pub fn foo91(_: *const i32, _: *mut i32) { }
+// CHECK: define{{.*}}foo91{{.*}}!type ![[TYPE91:[0-9]+]]
+pub fn foo92(_: *const i32, _: *mut i32, _: *mut i32) { }
+// CHECK: define{{.*}}foo92{{.*}}!type ![[TYPE92:[0-9]+]]
+pub fn foo93(_: fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo93{{.*}}!type ![[TYPE93:[0-9]+]]
+pub fn foo94(_: fn(i32) -> i32, _: fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo94{{.*}}!type ![[TYPE94:[0-9]+]]
+pub fn foo95(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo95{{.*}}!type ![[TYPE95:[0-9]+]]
+pub fn foo96(_: &dyn Fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo96{{.*}}!type ![[TYPE96:[0-9]+]]
+pub fn foo97(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo97{{.*}}!type ![[TYPE97:[0-9]+]]
+pub fn foo98(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo98{{.*}}!type ![[TYPE98:[0-9]+]]
+pub fn foo99(_: &dyn FnMut(i32) -> i32) { }
+// CHECK: define{{.*}}foo99{{.*}}!type ![[TYPE99:[0-9]+]]
+pub fn foo100(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { }
+// CHECK: define{{.*}}foo100{{.*}}!type ![[TYPE100:[0-9]+]]
+pub fn foo101(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { }
+// CHECK: define{{.*}}foo101{{.*}}!type ![[TYPE101:[0-9]+]]
+pub fn foo102(_: &dyn FnOnce(i32) -> i32) { }
+// CHECK: define{{.*}}foo102{{.*}}!type ![[TYPE102:[0-9]+]]
+pub fn foo103(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) { }
+// CHECK: define{{.*}}foo103{{.*}}!type ![[TYPE103:[0-9]+]]
+pub fn foo104(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {}
+// CHECK: define{{.*}}foo104{{.*}}!type ![[TYPE104:[0-9]+]]
+pub fn foo105(_: &dyn Send) { }
+// CHECK: define{{.*}}foo105{{.*}}!type ![[TYPE105:[0-9]+]]
+pub fn foo106(_: &dyn Send, _: &dyn Send) { }
+// CHECK: define{{.*}}foo106{{.*}}!type ![[TYPE106:[0-9]+]]
+pub fn foo107(_: &dyn Send, _: &dyn Send, _: &dyn Send) { }
+// CHECK: define{{.*}}foo107{{.*}}!type ![[TYPE107:[0-9]+]]
+pub fn foo108(_: Type1) { }
+// CHECK: define{{.*}}foo108{{.*}}!type ![[TYPE108:[0-9]+]]
+pub fn foo109(_: Type1, _: Type1) { }
+// CHECK: define{{.*}}foo109{{.*}}!type ![[TYPE109:[0-9]+]]
+pub fn foo110(_: Type1, _: Type1, _: Type1) { }
+// CHECK: define{{.*}}foo110{{.*}}!type ![[TYPE110:[0-9]+]]
+pub fn foo111(_: Type2) { }
+// CHECK: define{{.*}}foo111{{.*}}!type ![[TYPE111:[0-9]+]]
+pub fn foo112(_: Type2, _: Type2) { }
+// CHECK: define{{.*}}foo112{{.*}}!type ![[TYPE112:[0-9]+]]
+pub fn foo113(_: Type2, _: Type2, _: Type2) { }
+// CHECK: define{{.*}}foo113{{.*}}!type ![[TYPE113:[0-9]+]]
+pub fn foo114(_: Type3) { }
+// CHECK: define{{.*}}foo114{{.*}}!type ![[TYPE114:[0-9]+]]
+pub fn foo115(_: Type3, _: Type3) { }
+// CHECK: define{{.*}}foo115{{.*}}!type ![[TYPE115:[0-9]+]]
+pub fn foo116(_: Type3, _: Type3, _: Type3) { }
+// CHECK: define{{.*}}foo116{{.*}}!type ![[TYPE116:[0-9]+]]
+pub fn foo117(_: Type4) { }
+// CHECK: define{{.*}}foo117{{.*}}!type ![[TYPE117:[0-9]+]]
+pub fn foo118(_: Type4, _: Type4) { }
+// CHECK: define{{.*}}foo118{{.*}}!type ![[TYPE118:[0-9]+]]
+pub fn foo119(_: Type4, _: Type4, _: Type4) { }
+// CHECK: define{{.*}}foo119{{.*}}!type ![[TYPE119:[0-9]+]]
+pub fn foo120(_: Type5) { }
+// CHECK: define{{.*}}foo120{{.*}}!type ![[TYPE120:[0-9]+]]
+pub fn foo121(_: Type5, _: Type5) { }
+// CHECK: define{{.*}}foo121{{.*}}!type ![[TYPE121:[0-9]+]]
+pub fn foo122(_: Type5, _: Type5, _: Type5) { }
+// CHECK: define{{.*}}foo122{{.*}}!type ![[TYPE122:[0-9]+]]
+pub fn foo123(_: Type6) { }
+// CHECK: define{{.*}}foo123{{.*}}!type ![[TYPE123:[0-9]+]]
+pub fn foo124(_: Type6, _: Type6) { }
+// CHECK: define{{.*}}foo124{{.*}}!type ![[TYPE124:[0-9]+]]
+pub fn foo125(_: Type6, _: Type6, _: Type6) { }
+// CHECK: define{{.*}}foo125{{.*}}!type ![[TYPE125:[0-9]+]]
+pub fn foo126(_: Type7) { }
+// CHECK: define{{.*}}foo126{{.*}}!type ![[TYPE126:[0-9]+]]
+pub fn foo127(_: Type7, _: Type7) { }
+// CHECK: define{{.*}}foo127{{.*}}!type ![[TYPE127:[0-9]+]]
+pub fn foo128(_: Type7, _: Type7, _: Type7) { }
+// CHECK: define{{.*}}foo128{{.*}}!type ![[TYPE128:[0-9]+]]
+pub fn foo129(_: Type8) { }
+// CHECK: define{{.*}}foo129{{.*}}!type ![[TYPE129:[0-9]+]]
+pub fn foo130(_: Type8, _: Type8) { }
+// CHECK: define{{.*}}foo130{{.*}}!type ![[TYPE130:[0-9]+]]
+pub fn foo131(_: Type8, _: Type8, _: Type8) { }
+// CHECK: define{{.*}}foo131{{.*}}!type ![[TYPE131:[0-9]+]]
+pub fn foo132(_: Type9) { }
+// CHECK: define{{.*}}foo132{{.*}}!type ![[TYPE132:[0-9]+]]
+pub fn foo133(_: Type9, _: Type9) { }
+// CHECK: define{{.*}}foo133{{.*}}!type ![[TYPE133:[0-9]+]]
+pub fn foo134(_: Type9, _: Type9, _: Type9) { }
+// CHECK: define{{.*}}foo134{{.*}}!type ![[TYPE134:[0-9]+]]
+pub fn foo135(_: Type10) { }
+// CHECK: define{{.*}}foo135{{.*}}!type ![[TYPE135:[0-9]+]]
+pub fn foo136(_: Type10, _: Type10) { }
+// CHECK: define{{.*}}foo136{{.*}}!type ![[TYPE136:[0-9]+]]
+pub fn foo137(_: Type10, _: Type10, _: Type10) { }
+// CHECK: define{{.*}}foo137{{.*}}!type ![[TYPE137:[0-9]+]]
+pub fn foo138(_: Type11) { }
+// CHECK: define{{.*}}foo138{{.*}}!type ![[TYPE138:[0-9]+]]
+pub fn foo139(_: Type11, _: Type11) { }
+// CHECK: define{{.*}}foo139{{.*}}!type ![[TYPE139:[0-9]+]]
+pub fn foo140(_: Type11, _: Type11, _: Type11) { }
+// CHECK: define{{.*}}foo140{{.*}}!type ![[TYPE140:[0-9]+]]
+pub fn foo141(_: Type12) { }
+// CHECK: define{{.*}}foo141{{.*}}!type ![[TYPE141:[0-9]+]]
+pub fn foo142(_: Type12, _: Type12) { }
+// CHECK: define{{.*}}foo142{{.*}}!type ![[TYPE142:[0-9]+]]
+pub fn foo143(_: Type12, _: Type12, _: Type12) { }
+// CHECK: define{{.*}}foo143{{.*}}!type ![[TYPE143:[0-9]+]]
+pub fn foo144(_: Type13) { }
+// CHECK: define{{.*}}foo144{{.*}}!type ![[TYPE144:[0-9]+]]
+pub fn foo145(_: Type13, _: Type13) { }
+// CHECK: define{{.*}}foo145{{.*}}!type ![[TYPE145:[0-9]+]]
+pub fn foo146(_: Type13, _: Type13, _: Type13) { }
+// CHECK: define{{.*}}foo146{{.*}}!type ![[TYPE146:[0-9]+]]
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvvE"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvvE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvvvvE"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPvE"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvS_E"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_S_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPKvE"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPKvS0_E"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPKvS0_S0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvbE"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvbbE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvbbbE"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu2i8E"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2i8S_E"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2i8S_S_E"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3i16E"}
+// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16S_E"}
+// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_S_E"}
+// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3i32E"}
+// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3i32S_E"}
+// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3i32S_S_E"}
+// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3i64E"}
+// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3i64S_E"}
+// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3i64S_S_E"}
+// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu4i128E"}
+// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu4i128S_E"}
+// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu4i128S_S_E"}
+// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu5isizeE"}
+// CHECK: ![[TYPE28]] = !{i64 0, !"_ZTSFvu5isizeS_E"}
+// CHECK: ![[TYPE29]] = !{i64 0, !"_ZTSFvu5isizeS_S_E"}
+// CHECK: ![[TYPE30]] = !{i64 0, !"_ZTSFvu2u8E"}
+// CHECK: ![[TYPE31]] = !{i64 0, !"_ZTSFvu2u8S_E"}
+// CHECK: ![[TYPE32]] = !{i64 0, !"_ZTSFvu2u8S_S_E"}
+// CHECK: ![[TYPE33]] = !{i64 0, !"_ZTSFvu3u16E"}
+// CHECK: ![[TYPE34]] = !{i64 0, !"_ZTSFvu3u16S_E"}
+// CHECK: ![[TYPE35]] = !{i64 0, !"_ZTSFvu3u16S_S_E"}
+// CHECK: ![[TYPE36]] = !{i64 0, !"_ZTSFvu3u32E"}
+// CHECK: ![[TYPE37]] = !{i64 0, !"_ZTSFvu3u32S_E"}
+// CHECK: ![[TYPE38]] = !{i64 0, !"_ZTSFvu3u32S_S_E"}
+// CHECK: ![[TYPE39]] = !{i64 0, !"_ZTSFvu3u64E"}
+// CHECK: ![[TYPE40]] = !{i64 0, !"_ZTSFvu3u64S_E"}
+// CHECK: ![[TYPE41]] = !{i64 0, !"_ZTSFvu3u64S_S_E"}
+// CHECK: ![[TYPE42]] = !{i64 0, !"_ZTSFvu4u128E"}
+// CHECK: ![[TYPE43]] = !{i64 0, !"_ZTSFvu4u128S_E"}
+// CHECK: ![[TYPE44]] = !{i64 0, !"_ZTSFvu4u128S_S_E"}
+// CHECK: ![[TYPE45]] = !{i64 0, !"_ZTSFvu5usizeE"}
+// CHECK: ![[TYPE46]] = !{i64 0, !"_ZTSFvu5usizeS_E"}
+// CHECK: ![[TYPE47]] = !{i64 0, !"_ZTSFvu5usizeS_S_E"}
+// CHECK: ![[TYPE48]] = !{i64 0, !"_ZTSFvu3f32E"}
+// CHECK: ![[TYPE49]] = !{i64 0, !"_ZTSFvu3f32S_E"}
+// CHECK: ![[TYPE50]] = !{i64 0, !"_ZTSFvu3f32S_S_E"}
+// CHECK: ![[TYPE51]] = !{i64 0, !"_ZTSFvu3f64E"}
+// CHECK: ![[TYPE52]] = !{i64 0, !"_ZTSFvu3f64S_E"}
+// CHECK: ![[TYPE53]] = !{i64 0, !"_ZTSFvu3f64S_S_E"}
+// CHECK: ![[TYPE54]] = !{i64 0, !"_ZTSFvu4charE"}
+// CHECK: ![[TYPE55]] = !{i64 0, !"_ZTSFvu4charS_E"}
+// CHECK: ![[TYPE56]] = !{i64 0, !"_ZTSFvu4charS_S_E"}
+// CHECK: ![[TYPE57]] = !{i64 0, !"_ZTSFvu3refIu3strEE"}
+// CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"}
+// CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"}
+// CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_EE"}
+// CHECK: ![[TYPE61]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_E"}
+// CHECK: ![[TYPE62]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE63]] = !{i64 0, !"_ZTSFvA32u3i32E"}
+// CHECK: ![[TYPE64]] = !{i64 0, !"_ZTSFvA32u3i32S0_E"}
+// CHECK: ![[TYPE65]] = !{i64 0, !"_ZTSFvA32u3i32S0_S0_E"}
+// CHECK: ![[TYPE66]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"}
+// CHECK: ![[TYPE67]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"}
+// CHECK: ![[TYPE68]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"}
+// CHECK: ![[TYPE69]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EEE"}
+// CHECK: ![[TYPE70]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_E"}
+// CHECK: ![[TYPE71]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE72]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EEE"}
+// CHECK: ![[TYPE73]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_E"}
+// CHECK: ![[TYPE74]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE75]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EEE"}
+// CHECK: ![[TYPE76]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_E"}
+// CHECK: ![[TYPE77]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE78]] = !{i64 0, !"_ZTSFvP5type1E"}
+// CHECK: ![[TYPE79]] = !{i64 0, !"_ZTSFvP5type1S0_E"}
+// CHECK: ![[TYPE80]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"}
+// CHECK: ![[TYPE81]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32EE"}
+// CHECK: ![[TYPE82]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_E"}
+// CHECK: ![[TYPE83]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_S0_E"}
+// CHECK: ![[TYPE84]] = !{i64 0, !"_ZTSFvu3refIu3i32EE"}
+// CHECK: ![[TYPE85]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_E"}
+// CHECK: ![[TYPE86]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_S1_E"}
+// CHECK: ![[TYPE87]] = !{i64 0, !"_ZTSFvPu3i32E"}
+// CHECK: ![[TYPE88]] = !{i64 0, !"_ZTSFvPu3i32PKS_E"}
+// CHECK: ![[TYPE89]] = !{i64 0, !"_ZTSFvPu3i32PKS_S2_E"}
+// CHECK: ![[TYPE90]] = !{i64 0, !"_ZTSFvPKu3i32E"}
+// CHECK: ![[TYPE91]] = !{i64 0, !"_ZTSFvPKu3i32PS_E"}
+// CHECK: ![[TYPE92]] = !{i64 0, !"_ZTSFvPKu3i32PS_S2_E"}
+// CHECK: ![[TYPE93]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"}
+// CHECK: ![[TYPE94]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"}
+// CHECK: ![[TYPE95]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE96]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE97]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE98]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE99]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE100]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE101]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE102]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE103]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE104]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE105]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"}
+// CHECK: ![[TYPE106]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"}
+// CHECK: ![[TYPE107]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"}
+// CHECK: ![[TYPE108]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvEE"}
+// CHECK: ![[TYPE109]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_E"}
+// CHECK: ![[TYPE110]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_S1_E"}
+// CHECK: ![[TYPE111]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}E"}
+// CHECK: ![[TYPE112]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_E"}
+// CHECK: ![[TYPE113]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_S_E"}
+// CHECK: ![[TYPE114]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooE"}
+// CHECK: ![[TYPE115]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_E"}
+// CHECK: ![[TYPE116]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_S_E"}
+// CHECK: ![[TYPE117]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooE"}
+// CHECK: ![[TYPE118]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"}
+// CHECK: ![[TYPE119]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"}
+// CHECK: ![[TYPE120]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooE"}
+// CHECK: ![[TYPE121]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_E"}
+// CHECK: ![[TYPE122]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"}
+// CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"}
+// CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"}
+// CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"}
+// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_EE"}
+// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_E"}
+// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_S3_E"}
+// CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_EE"}
+// CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_E"}
+// CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE132]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_EE"}
+// CHECK: ![[TYPE133]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_E"}
+// CHECK: ![[TYPE134]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_S1_E"}
+// CHECK: ![[TYPE135]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EEE"}
+// CHECK: ![[TYPE136]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_E"}
+// CHECK: ![[TYPE137]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_S2_E"}
+// CHECK: ![[TYPE138]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_EE"}
+// CHECK: ![[TYPE139]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_E"}
+// CHECK: ![[TYPE140]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_S0_E"}
+// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooE"}
+// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_E"}
+// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_S_E"}
+// CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIu3refIvEEE"}
+// CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_E"}
+// CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_S0_E"}
diff --git a/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs
new file mode 100644
index 00000000000..09310ba9f60
--- /dev/null
+++ b/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs
@@ -0,0 +1,31 @@
+// Verifies that type metadata for functions are emitted.
+//
+// needs-sanitizer-cfi
+// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]]
+    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"_ZTSFu3i32S_E")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]]
+    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"_ZTSFu3i32S_S_E")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]]
+    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"_ZTSFu3i32S_S_S_E")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E"}
diff --git a/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs b/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs
deleted file mode 100644
index 96fced47e78..00000000000
--- a/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Verifies that type metadata for functions are emitted.
-//
-// ignore-windows
-// needs-sanitizer-cfi
-// only-aarch64
-// only-x86_64
-// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
-
-#![crate_type="lib"]
-
-pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
-    // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
-    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid1")
-    f(arg)
-}
-
-pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
-    // CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}}
-    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid2")
-    f(arg1, arg2)
-}
-
-pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
-    // CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}}
-    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid3")
-    f(arg1, arg2, arg3)
-}
-
-// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid2"}
-// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid3"}
-// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid4"}
diff --git a/src/test/codegen/sanitizer_scs_attr_check.rs b/src/test/codegen/sanitizer_scs_attr_check.rs
new file mode 100644
index 00000000000..0b53db3b767
--- /dev/null
+++ b/src/test/codegen/sanitizer_scs_attr_check.rs
@@ -0,0 +1,17 @@
+// This tests that the shadowcallstack attribute is
+// applied when enabling the shadow-call-stack sanitizer.
+//
+// needs-sanitizer-shadow-call-stack
+// compile-flags: -Zsanitizer=shadow-call-stack
+
+#![crate_type = "lib"]
+#![feature(no_sanitize)]
+
+// CHECK: ; Function Attrs:{{.*}}shadowcallstack
+// CHECK-NEXT: scs
+pub fn scs() {}
+
+// CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack
+// CHECK-NEXT: no_scs
+#[no_sanitize(shadow_call_stack)]
+pub fn no_scs() {}
diff --git a/src/test/codegen/simd-wide-sum.rs b/src/test/codegen/simd-wide-sum.rs
index 015ac4fe4d1..04314dc291a 100644
--- a/src/test/codegen/simd-wide-sum.rs
+++ b/src/test/codegen/simd-wide-sum.rs
@@ -5,7 +5,7 @@
 #![crate_type = "lib"]
 #![feature(portable_simd)]
 
-use std::simd::Simd;
+use std::simd::{Simd, SimdUint};
 const N: usize = 8;
 
 #[no_mangle]
diff --git a/src/test/debuginfo/basic-types-globals-lto.rs b/src/test/debuginfo/basic-types-globals-lto.rs
deleted file mode 100644
index 1adf278ad32..00000000000
--- a/src/test/debuginfo/basic-types-globals-lto.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// Caveat - gdb doesn't know about UTF-32 character encoding and will print a
-// rust char as only its numerical value.
-
-// min-lldb-version: 310
-// min-gdb-version: 8.0
-
-// no-prefer-dynamic
-// compile-flags:-g -C lto
-// gdb-command:run
-// gdbg-command:print 'basic_types_globals::B'
-// gdbr-command:print B
-// gdb-check:$1 = false
-// gdbg-command:print 'basic_types_globals::I'
-// gdbr-command:print I
-// gdb-check:$2 = -1
-// gdbg-command:print 'basic_types_globals::C'
-// gdbr-command:print/d C
-// gdbg-check:$3 = 97
-// gdbr-check:$3 = 97
-// gdbg-command:print/d 'basic_types_globals::I8'
-// gdbr-command:print I8
-// gdb-check:$4 = 68
-// gdbg-command:print 'basic_types_globals::I16'
-// gdbr-command:print I16
-// gdb-check:$5 = -16
-// gdbg-command:print 'basic_types_globals::I32'
-// gdbr-command:print I32
-// gdb-check:$6 = -32
-// gdbg-command:print 'basic_types_globals::I64'
-// gdbr-command:print I64
-// gdb-check:$7 = -64
-// gdbg-command:print 'basic_types_globals::U'
-// gdbr-command:print U
-// gdb-check:$8 = 1
-// gdbg-command:print/d 'basic_types_globals::U8'
-// gdbr-command:print U8
-// gdb-check:$9 = 100
-// gdbg-command:print 'basic_types_globals::U16'
-// gdbr-command:print U16
-// gdb-check:$10 = 16
-// gdbg-command:print 'basic_types_globals::U32'
-// gdbr-command:print U32
-// gdb-check:$11 = 32
-// gdbg-command:print 'basic_types_globals::U64'
-// gdbr-command:print U64
-// gdb-check:$12 = 64
-// gdbg-command:print 'basic_types_globals::F32'
-// gdbr-command:print F32
-// gdb-check:$13 = 2.5
-// gdbg-command:print 'basic_types_globals::F64'
-// gdbr-command:print F64
-// gdb-check:$14 = 3.5
-// gdb-command:continue
-
-#![allow(unused_variables)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-// N.B. These are `mut` only so they don't constant fold away.
-static mut B: bool = false;
-static mut I: isize = -1;
-static mut C: char = 'a';
-static mut I8: i8 = 68;
-static mut I16: i16 = -16;
-static mut I32: i32 = -32;
-static mut I64: i64 = -64;
-static mut U: usize = 1;
-static mut U8: u8 = 100;
-static mut U16: u16 = 16;
-static mut U32: u32 = 32;
-static mut U64: u64 = 64;
-static mut F32: f32 = 2.5;
-static mut F64: f64 = 3.5;
-
-fn main() {
-    _zzz(); // #break
-
-    let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) };
-}
-
-fn _zzz() {()}
diff --git a/src/test/debuginfo/basic-types-globals.rs b/src/test/debuginfo/basic-types-globals.rs
index 3602db39a4e..8a3df8ba2d1 100644
--- a/src/test/debuginfo/basic-types-globals.rs
+++ b/src/test/debuginfo/basic-types-globals.rs
@@ -4,7 +4,13 @@
 // min-lldb-version: 310
 // min-gdb-version: 8.0
 
+// revisions: lto no-lto
+
 // compile-flags:-g
+
+// [lto] compile-flags:-C lto
+// [lto] no-prefer-dynamic
+
 // gdb-command:run
 // gdbg-command:print 'basic_types_globals::B'
 // gdbr-command:print B
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt
new file mode 100644
index 00000000000..d102d9ecf7d
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt
@@ -0,0 +1,21 @@
+    1|       |// Regression test for issue #98833.
+    2|       |// compile-flags: -Zinline-mir
+    3|       |
+    4|      1|fn main() {
+    5|      1|    println!("{}", live::<false>());
+    6|      1|}
+    7|       |
+    8|       |#[inline]
+    9|      1|fn live<const B: bool>() -> u32 {
+   10|      1|    if B {
+   11|      0|        dead()
+   12|       |    } else {
+   13|      1|        0
+   14|       |    }
+   15|      1|}
+   16|       |
+   17|       |#[inline]
+   18|      0|fn dead() -> u32 {
+   19|      0|    42
+   20|      0|}
+
diff --git a/src/test/run-make-fulldeps/coverage/inline-dead.rs b/src/test/run-make-fulldeps/coverage/inline-dead.rs
new file mode 100644
index 00000000000..cd1ae911a5f
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/inline-dead.rs
@@ -0,0 +1,20 @@
+// Regression test for issue #98833.
+// compile-flags: -Zinline-mir
+
+fn main() {
+    println!("{}", live::<false>());
+}
+
+#[inline]
+fn live<const B: bool>() -> u32 {
+    if B {
+        dead()
+    } else {
+        0
+    }
+}
+
+#[inline]
+fn dead() -> u32 {
+    42
+}
diff --git a/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/Makefile b/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/Makefile
new file mode 100644
index 00000000000..157edb20c30
--- /dev/null
+++ b/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/Makefile
@@ -0,0 +1,11 @@
+# needs-matching-clang
+
+# This test makes sure the embed bitcode in elf created with
+# lto-embed-bitcode=optimized is valid llvm BC module.
+
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+	$(RUSTC) test.rs --target $(TARGET) -Clink-arg=-fuse-ld=lld -Clinker-plugin-lto -Clinker=$(CLANG) -Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized -Zemit-thin-lto=no
+	$(LLVM_BIN_DIR)/objcopy --dump-section .llvmbc=$(TMPDIR)/test.bc $(TMPDIR)/test
+	$(LLVM_BIN_DIR)/llvm-dis $(TMPDIR)/test.bc
diff --git a/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/test.rs b/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/test.rs
new file mode 100644
index 00000000000..47ad8c63411
--- /dev/null
+++ b/src/test/run-make-fulldeps/issue-84395-lto-embed-bitcode/test.rs
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello World!");
+}
diff --git a/src/test/run-make-fulldeps/used-cdylib-macos/Makefile b/src/test/run-make-fulldeps/used-cdylib-macos/Makefile
new file mode 100644
index 00000000000..4828d9c8aad
--- /dev/null
+++ b/src/test/run-make-fulldeps/used-cdylib-macos/Makefile
@@ -0,0 +1,11 @@
+-include ../tools.mk
+
+# only-macos
+#
+# This checks that `#[used]` passes through to the linker on
+# darwin. This is subject to change in the future, see
+# https://github.com/rust-lang/rust/pull/93718 for discussion
+
+all:
+	$(RUSTC) -Copt-level=3 dylib_used.rs
+	nm $(TMPDIR)/libdylib_used.dylib | $(CGREP) VERY_IMPORTANT_SYMBOL
diff --git a/src/test/run-make-fulldeps/used-cdylib-macos/dylib_used.rs b/src/test/run-make-fulldeps/used-cdylib-macos/dylib_used.rs
new file mode 100644
index 00000000000..85f0ff92fe7
--- /dev/null
+++ b/src/test/run-make-fulldeps/used-cdylib-macos/dylib_used.rs
@@ -0,0 +1,4 @@
+#![crate_type = "cdylib"]
+
+#[used]
+static VERY_IMPORTANT_SYMBOL: u32 = 12345;
diff --git a/src/test/rustdoc-gui/search-input.goml b/src/test/rustdoc-gui/search-input.goml
new file mode 100644
index 00000000000..44123b702df
--- /dev/null
+++ b/src/test/rustdoc-gui/search-input.goml
@@ -0,0 +1,23 @@
+// Ensures that the search input border color changes on focus.
+goto: file://|DOC_PATH|/test_docs/index.html
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
+reload:
+
+assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"})
+click: ".search-input"
+focus: ".search-input"
+assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"})
+
+local-storage: {"rustdoc-theme": "light"}
+reload:
+
+assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"})
+click: ".search-input"
+assert-css: (".search-input", {"border-color": "rgb(102, 175, 233)"})
+
+local-storage: {"rustdoc-theme": "ayu"}
+reload:
+
+assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"})
+click: ".search-input"
+assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"})
diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
index 6295d7fae89..8464ba7c23c 100644
--- a/src/test/rustdoc-gui/search-result-display.goml
+++ b/src/test/rustdoc-gui/search-result-display.goml
@@ -18,7 +18,7 @@ assert-css: (".search-results div.desc", {"width": "570px"})
 size: (900, 900)
 
 // First we check the current width and position.
-assert-css: ("#crate-search", {"width": "222px"})
+assert-css: ("#crate-search", {"width": "218px"})
 compare-elements-position-near: (
     "#crate-search",
     "#search-settings .search-results-title",
diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
index 7296b35788a..bcf323e1cab 100644
--- a/src/test/rustdoc-ui/z-help.stdout
+++ b/src/test/rustdoc-ui/z-help.stdout
@@ -4,6 +4,7 @@
     -Z                            asm-comments=val -- generate comments into the assembly (may change behavior) (default: no)
     -Z                       assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`.
     -Z                      binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no)
+    -Z                             box-noalias=val -- emit noalias metadata for box (default: yes)
     -Z                       branch-protection=val -- set options for branch target identification and pointer authentication on AArch64
     -Z                           cf-protection=val -- instrument control-flow architecture protection
     -Z               cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use
@@ -35,6 +36,7 @@
     -Z                       dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
     -Z                           dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
+    -Z                           emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
     -Z                             fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
     -Z              force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
     -Z                                    fuel=val -- set the optimization fuel quota for a crate
diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs
index e54f9a57ae4..59113952345 100644
--- a/src/test/rustdoc/const-generics/add-impl.rs
+++ b/src/test/rustdoc/const-generics/add-impl.rs
@@ -7,7 +7,7 @@ pub struct Simd<T, const WIDTH: usize> {
     inner: T,
 }
 
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16>> for Simd<u8, 16>'
 impl Add for Simd<u8, 16> {
     type Output = Self;
 
diff --git a/src/test/rustdoc/const-generics/const-generic-defaults.rs b/src/test/rustdoc/const-generics/const-generic-defaults.rs
index 8035f826775..2693d9b5969 100644
--- a/src/test/rustdoc/const-generics/const-generic-defaults.rs
+++ b/src/test/rustdoc/const-generics/const-generic-defaults.rs
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
-//      'pub struct Foo<const M: usize = 10_usize, const N: usize = M, T = i32>(_);'
+//      'pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(_);'
 pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T);
diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs
index 61af7de4794..352a8e646bb 100644
--- a/src/test/rustdoc/const-generics/const-generics-docs.rs
+++ b/src/test/rustdoc/const-generics/const-generics-docs.rs
@@ -19,8 +19,8 @@ pub use extern_crate::WTrait;
 
 // @has foo/trait.Trait.html '//pre[@class="rust trait"]' \
 //      'pub trait Trait<const N: usize>'
-// @has - '//*[@id="impl-Trait%3C1_usize%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<1_usize> for u8'
-// @has - '//*[@id="impl-Trait%3C2_usize%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<2_usize> for u8'
+// @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<1> for u8'
+// @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<2> for u8'
 // @has - '//*[@id="impl-Trait%3C{1%20+%202}%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<{1 + 2}> for u8'
 // @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8%3B%20N%5D"]//h3[@class="code-header in-band"]' \
 //      'impl<const N: usize> Trait<N> for [u8; N]'
diff --git a/src/test/ui-fulldeps/gated-plugin.rs b/src/test/ui-fulldeps/gated-plugin.rs
index 445469f8733..85eaf533643 100644
--- a/src/test/ui-fulldeps/gated-plugin.rs
+++ b/src/test/ui-fulldeps/gated-plugin.rs
@@ -1,4 +1,5 @@
 // aux-build:empty-plugin.rs
+// ignore-stage1
 
 #![plugin(empty_plugin)]
 //~^ ERROR compiler plugins are deprecated
diff --git a/src/test/ui-fulldeps/gated-plugin.stderr b/src/test/ui-fulldeps/gated-plugin.stderr
index b8b7dd23c1c..f48f1eab60b 100644
--- a/src/test/ui-fulldeps/gated-plugin.stderr
+++ b/src/test/ui-fulldeps/gated-plugin.stderr
@@ -1,5 +1,5 @@
 error[E0658]: compiler plugins are deprecated
-  --> $DIR/gated-plugin.rs:3:1
+  --> $DIR/gated-plugin.rs:4:1
    |
 LL | #![plugin(empty_plugin)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #![plugin(empty_plugin)]
    = help: add `#![feature(plugin)]` to the crate attributes to enable
 
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/gated-plugin.rs:3:1
+  --> $DIR/gated-plugin.rs:4:1
    |
 LL | #![plugin(empty_plugin)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs
index 2868517774d..6ce67dcaf1d 100644
--- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs
+++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs
@@ -44,11 +44,11 @@ struct WithParameters<T, const N: usize, M = u32> {
 }
 
 impl<T> WithParameters<T, 1> {
-    fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize>` by reference
+    fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1>` by reference
 }
 
 impl<T> WithParameters<T, 1, u8> {
-    fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize, u8>` by reference
+    fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1, u8>` by reference
 }
 
 fn main() {}
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr
index 54a7cf7cab7..fb39ed60b82 100644
--- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr
+++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr
@@ -22,17 +22,17 @@ error: passing `Foo` by reference
 LL |     fn with_ref(&self) {}
    |                 ^^^^^ help: try passing by value: `Foo`
 
-error: passing `WithParameters<T, 1_usize>` by reference
+error: passing `WithParameters<T, 1>` by reference
   --> $DIR/rustc_pass_by_value_self.rs:47:17
    |
 LL |     fn with_ref(&self) {}
-   |                 ^^^^^ help: try passing by value: `WithParameters<T, 1_usize>`
+   |                 ^^^^^ help: try passing by value: `WithParameters<T, 1>`
 
-error: passing `WithParameters<T, 1_usize, u8>` by reference
+error: passing `WithParameters<T, 1, u8>` by reference
   --> $DIR/rustc_pass_by_value_self.rs:51:17
    |
 LL |     fn with_ref(&self) {}
-   |                 ^^^^^ help: try passing by value: `WithParameters<T, 1_usize, u8>`
+   |                 ^^^^^ help: try passing by value: `WithParameters<T, 1, u8>`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui-fulldeps/multiple-plugins.rs b/src/test/ui-fulldeps/multiple-plugins.rs
index 25d2c8bc123..9af3ebd570c 100644
--- a/src/test/ui-fulldeps/multiple-plugins.rs
+++ b/src/test/ui-fulldeps/multiple-plugins.rs
@@ -1,6 +1,7 @@
 // run-pass
 // aux-build:multiple-plugins-1.rs
 // aux-build:multiple-plugins-2.rs
+// ignore-stage1
 
 // Check that the plugin registrar of multiple plugins doesn't conflict
 
diff --git a/src/test/ui-fulldeps/multiple-plugins.stderr b/src/test/ui-fulldeps/multiple-plugins.stderr
index 99151933c4b..878ffabfc7f 100644
--- a/src/test/ui-fulldeps/multiple-plugins.stderr
+++ b/src/test/ui-fulldeps/multiple-plugins.stderr
@@ -1,5 +1,5 @@
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/multiple-plugins.rs:8:1
+  --> $DIR/multiple-plugins.rs:9:1
    |
 LL | #![plugin(multiple_plugins_1)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
@@ -7,7 +7,7 @@ LL | #![plugin(multiple_plugins_1)]
    = note: `#[warn(deprecated)]` on by default
 
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/multiple-plugins.rs:9:1
+  --> $DIR/multiple-plugins.rs:10:1
    |
 LL | #![plugin(multiple_plugins_2)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
diff --git a/src/test/ui/argument-suggestions/issue-98894.rs b/src/test/ui/argument-suggestions/issue-98894.rs
new file mode 100644
index 00000000000..c2618a96716
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-98894.rs
@@ -0,0 +1,4 @@
+fn main() {
+    (|_, ()| ())(if true {} else {return;});
+    //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+}
diff --git a/src/test/ui/argument-suggestions/issue-98894.stderr b/src/test/ui/argument-suggestions/issue-98894.stderr
new file mode 100644
index 00000000000..0c8b94901e1
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-98894.stderr
@@ -0,0 +1,19 @@
+error[E0057]: this function takes 2 arguments but 1 argument was supplied
+  --> $DIR/issue-98894.rs:2:5
+   |
+LL |     (|_, ()| ())(if true {} else {return;});
+   |     ^^^^^^^^^^^^--------------------------- an argument of type `()` is missing
+   |
+note: closure defined here
+  --> $DIR/issue-98894.rs:2:6
+   |
+LL |     (|_, ()| ())(if true {} else {return;});
+   |      ^^^^^^^
+help: provide the argument
+   |
+LL |     (|_, ()| ())(if true {} else {return;}, ());
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0057`.
diff --git a/src/test/ui/argument-suggestions/issue-98897.rs b/src/test/ui/argument-suggestions/issue-98897.rs
new file mode 100644
index 00000000000..c55f495d698
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-98897.rs
@@ -0,0 +1,4 @@
+fn main() {
+    (|_, ()| ())([return, ()]);
+    //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+}
diff --git a/src/test/ui/argument-suggestions/issue-98897.stderr b/src/test/ui/argument-suggestions/issue-98897.stderr
new file mode 100644
index 00000000000..8f0d98d09e8
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-98897.stderr
@@ -0,0 +1,19 @@
+error[E0057]: this function takes 2 arguments but 1 argument was supplied
+  --> $DIR/issue-98897.rs:2:5
+   |
+LL |     (|_, ()| ())([return, ()]);
+   |     ^^^^^^^^^^^^-------------- an argument of type `()` is missing
+   |
+note: closure defined here
+  --> $DIR/issue-98897.rs:2:6
+   |
+LL |     (|_, ()| ())([return, ()]);
+   |      ^^^^^^^
+help: provide the argument
+   |
+LL |     (|_, ()| ())([return, ()], ());
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0057`.
diff --git a/src/test/ui/argument-suggestions/issue-99482.rs b/src/test/ui/argument-suggestions/issue-99482.rs
new file mode 100644
index 00000000000..731b863069b
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-99482.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let f = |_: (), f: fn()| f;
+    let _f = f(main);
+    //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+}
diff --git a/src/test/ui/argument-suggestions/issue-99482.stderr b/src/test/ui/argument-suggestions/issue-99482.stderr
new file mode 100644
index 00000000000..bc005e82a2c
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-99482.stderr
@@ -0,0 +1,19 @@
+error[E0057]: this function takes 2 arguments but 1 argument was supplied
+  --> $DIR/issue-99482.rs:3:14
+   |
+LL |     let _f = f(main);
+   |              ^ ---- an argument of type `()` is missing
+   |
+note: closure defined here
+  --> $DIR/issue-99482.rs:2:13
+   |
+LL |     let f = |_: (), f: fn()| f;
+   |             ^^^^^^^^^^^^^^^^
+help: provide the argument
+   |
+LL |     let _f = f((), main);
+   |              ~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0057`.
diff --git a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
index 1a14ab40b1f..5e531a993c6 100644
--- a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
+++ b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/match_arr_unknown_len.rs:3:9
    |
 LL |         [1, 2] => true,
-   |         ^^^^^^ expected `2_usize`, found `N`
+   |         ^^^^^^ expected `2`, found `N`
    |
    = note: expected array `[u32; 2]`
               found array `[u32; N]`
diff --git a/src/test/ui/asm/x86_64/issue-96797.rs b/src/test/ui/asm/x86_64/issue-96797.rs
new file mode 100644
index 00000000000..d3e0906f37a
--- /dev/null
+++ b/src/test/ui/asm/x86_64/issue-96797.rs
@@ -0,0 +1,26 @@
+// build-pass
+// compile-flags: -O
+// min-llvm-version: 14.0.5
+// needs-asm-support
+// only-x86_64
+// only-linux
+
+// regression test for #96797
+
+#![feature(asm_sym)]
+
+use std::arch::global_asm;
+
+#[no_mangle]
+fn my_func() {}
+
+global_asm!("call_foobar: jmp {}", sym foobar);
+
+fn foobar() {}
+
+fn main() {
+    extern "Rust" {
+        fn call_foobar();
+    }
+    unsafe { call_foobar() };
+}
diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr
index ada6e357aea..e5887689690 100644
--- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr
+++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr
@@ -18,14 +18,6 @@ LL | |             break 0u8;
 LL | |         };
    | |_________- enclosing `async` block
 
-error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
-  --> $DIR/async-block-control-flow-static-semantics.rs:26:39
-   |
-LL |     let _: &dyn Future<Output = ()> = &block;
-   |                                       ^^^^^^ expected `()`, found `u8`
-   |
-   = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
-
 error[E0308]: mismatched types
   --> $DIR/async-block-control-flow-static-semantics.rs:21:58
    |
@@ -40,7 +32,7 @@ LL | | }
    | |_^ expected `u8`, found `()`
 
 error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
-  --> $DIR/async-block-control-flow-static-semantics.rs:17:39
+  --> $DIR/async-block-control-flow-static-semantics.rs:26:39
    |
 LL |     let _: &dyn Future<Output = ()> = &block;
    |                                       ^^^^^^ expected `()`, found `u8`
@@ -55,6 +47,14 @@ LL | fn return_targets_async_block_not_fn() -> u8 {
    |    |
    |    implicitly returns `()` as its body has no tail or `return` expression
 
+error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
+  --> $DIR/async-block-control-flow-static-semantics.rs:17:39
+   |
+LL |     let _: &dyn Future<Output = ()> = &block;
+   |                                       ^^^^^^ expected `()`, found `u8`
+   |
+   = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
+
 error[E0308]: mismatched types
   --> $DIR/async-block-control-flow-static-semantics.rs:47:44
    |
diff --git a/src/test/ui/btreemap/btreemap_dropck.rs b/src/test/ui/btreemap/btreemap_dropck.rs
new file mode 100644
index 00000000000..c58727df30c
--- /dev/null
+++ b/src/test/ui/btreemap/btreemap_dropck.rs
@@ -0,0 +1,16 @@
+struct PrintOnDrop<'a>(&'a str);
+
+impl Drop for PrintOnDrop<'_> {
+    fn drop(&mut self) {
+        println!("printint: {}", self.0);
+    }
+}
+
+use std::collections::BTreeMap;
+use std::iter::FromIterator;
+
+fn main() {
+    let s = String::from("Hello World!");
+    let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]);
+    drop(s); //~ ERROR cannot move out of `s` because it is borrowed
+}
diff --git a/src/test/ui/btreemap/btreemap_dropck.stderr b/src/test/ui/btreemap/btreemap_dropck.stderr
new file mode 100644
index 00000000000..e953e7ae82b
--- /dev/null
+++ b/src/test/ui/btreemap/btreemap_dropck.stderr
@@ -0,0 +1,13 @@
+error[E0505]: cannot move out of `s` because it is borrowed
+  --> $DIR/btreemap_dropck.rs:15:10
+   |
+LL |     let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]);
+   |                                                      -- borrow of `s` occurs here
+LL |     drop(s);
+   |          ^ move out of `s` occurs here
+LL | }
+   | - borrow might be used here, when `_map` is dropped and runs the `Drop` code for type `BTreeMap`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/src/test/ui/closures/issue-99565.rs b/src/test/ui/closures/issue-99565.rs
new file mode 100644
index 00000000000..3a30d2ee034
--- /dev/null
+++ b/src/test/ui/closures/issue-99565.rs
@@ -0,0 +1,7 @@
+#![crate_type = "lib"]
+
+fn foo<T, U>(_: U) {}
+
+fn bar() {
+    foo(|| {}); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/closures/issue-99565.stderr b/src/test/ui/closures/issue-99565.stderr
new file mode 100644
index 00000000000..0d940aa9a2f
--- /dev/null
+++ b/src/test/ui/closures/issue-99565.stderr
@@ -0,0 +1,14 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-99565.rs:6:5
+   |
+LL |     foo(|| {});
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     foo::<T, _>(|| {});
+   |        ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/associated-type-bound-fail.stderr b/src/test/ui/const-generics/associated-type-bound-fail.stderr
index da2558229a7..e5e7ee26e44 100644
--- a/src/test/ui/const-generics/associated-type-bound-fail.stderr
+++ b/src/test/ui/const-generics/associated-type-bound-fail.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `u16: Bar<N>` is not satisfied
 LL |     type Assoc = u16;
    |                  ^^^ the trait `Bar<N>` is not implemented for `u16`
    |
-   = help: the trait `Bar<3_usize>` is implemented for `u16`
+   = help: the trait `Bar<3>` is implemented for `u16`
 note: required by a bound in `Foo::Assoc`
   --> $DIR/associated-type-bound-fail.rs:4:17
    |
diff --git a/src/test/ui/const-generics/defaults/generic-expr-default-concrete.stderr b/src/test/ui/const-generics/defaults/generic-expr-default-concrete.stderr
index 905a285370a..e8826ce4335 100644
--- a/src/test/ui/const-generics/defaults/generic-expr-default-concrete.stderr
+++ b/src/test/ui/const-generics/defaults/generic-expr-default-concrete.stderr
@@ -2,10 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/generic-expr-default-concrete.rs:10:5
    |
 LL |     Foo::<10, 12>
-   |     ^^^^^^^^^^^^^ expected `11_usize`, found `12_usize`
+   |     ^^^^^^^^^^^^^ expected `11`, found `12`
    |
-   = note: expected type `11_usize`
-              found type `12_usize`
+   = note: expected type `11`
+              found type `12`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/defaults/mismatch.rs b/src/test/ui/const-generics/defaults/mismatch.rs
index fce4ec4edda..ec131505ed7 100644
--- a/src/test/ui/const-generics/defaults/mismatch.rs
+++ b/src/test/ui/const-generics/defaults/mismatch.rs
@@ -1,22 +1,22 @@
-pub struct Example<const N: usize=13>;
-pub struct Example2<T=u32, const N: usize=13>(T);
-pub struct Example3<const N: usize=13, T=u32>(T);
-pub struct Example4<const N: usize=13, const M: usize=4>;
+pub struct Example<const N: usize = 13>;
+pub struct Example2<T = u32, const N: usize = 13>(T);
+pub struct Example3<const N: usize = 13, T = u32>(T);
+pub struct Example4<const N: usize = 13, const M: usize = 4>;
 
 fn main() {
-    let e: Example::<13> = ();
+    let e: Example<13> = ();
     //~^ Error: mismatched types
     //~| expected struct `Example`
-    let e: Example2::<u32, 13> = ();
+    let e: Example2<u32, 13> = ();
     //~^ Error: mismatched types
     //~| expected struct `Example2`
-    let e: Example3::<13, u32> = ();
+    let e: Example3<13, u32> = ();
     //~^ Error: mismatched types
     //~| expected struct `Example3`
-    let e: Example3::<7> = ();
+    let e: Example3<7> = ();
     //~^ Error: mismatched types
-    //~| expected struct `Example3<7_usize>`
-    let e: Example4::<7> = ();
+    //~| expected struct `Example3<7>`
+    let e: Example4<7> = ();
     //~^ Error: mismatched types
-    //~| expected struct `Example4<7_usize>`
+    //~| expected struct `Example4<7>`
 }
diff --git a/src/test/ui/const-generics/defaults/mismatch.stderr b/src/test/ui/const-generics/defaults/mismatch.stderr
index 36976819195..52c54aace5f 100644
--- a/src/test/ui/const-generics/defaults/mismatch.stderr
+++ b/src/test/ui/const-generics/defaults/mismatch.stderr
@@ -1,8 +1,8 @@
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:7:28
+  --> $DIR/mismatch.rs:7:26
    |
-LL |     let e: Example::<13> = ();
-   |            -------------   ^^ expected struct `Example`, found `()`
+LL |     let e: Example<13> = ();
+   |            -----------   ^^ expected struct `Example`, found `()`
    |            |
    |            expected due to this
    |
@@ -10,10 +10,10 @@ LL |     let e: Example::<13> = ();
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:10:34
+  --> $DIR/mismatch.rs:10:32
    |
-LL |     let e: Example2::<u32, 13> = ();
-   |            -------------------   ^^ expected struct `Example2`, found `()`
+LL |     let e: Example2<u32, 13> = ();
+   |            -----------------   ^^ expected struct `Example2`, found `()`
    |            |
    |            expected due to this
    |
@@ -21,10 +21,10 @@ LL |     let e: Example2::<u32, 13> = ();
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:13:34
+  --> $DIR/mismatch.rs:13:32
    |
-LL |     let e: Example3::<13, u32> = ();
-   |            -------------------   ^^ expected struct `Example3`, found `()`
+LL |     let e: Example3<13, u32> = ();
+   |            -----------------   ^^ expected struct `Example3`, found `()`
    |            |
    |            expected due to this
    |
@@ -32,25 +32,25 @@ LL |     let e: Example3::<13, u32> = ();
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:16:28
+  --> $DIR/mismatch.rs:16:26
    |
-LL |     let e: Example3::<7> = ();
-   |            -------------   ^^ expected struct `Example3`, found `()`
+LL |     let e: Example3<7> = ();
+   |            -----------   ^^ expected struct `Example3`, found `()`
    |            |
    |            expected due to this
    |
-   = note: expected struct `Example3<7_usize>`
+   = note: expected struct `Example3<7>`
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:19:28
+  --> $DIR/mismatch.rs:19:26
    |
-LL |     let e: Example4::<7> = ();
-   |            -------------   ^^ expected struct `Example4`, found `()`
+LL |     let e: Example4<7> = ();
+   |            -----------   ^^ expected struct `Example4`, found `()`
    |            |
    |            expected due to this
    |
-   = note: expected struct `Example4<7_usize>`
+   = note: expected struct `Example4<7>`
            found unit type `()`
 
 error: aborting due to 5 previous errors
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
index f633e56b0ec..80013e7b4b2 100644
--- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
+++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
@@ -4,16 +4,15 @@ trait Trait {}
 impl<const N: u32> Trait for Uwu<N> {}
 
 fn rawr() -> impl Trait {
-    //~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+    //~^ error: the trait bound `Uwu<10, 12>: Trait` is not satisfied
     Uwu::<10, 12>
 }
 
-trait Traitor<const N: u8 = 1, const M: u8 = N> { }
+trait Traitor<const N: u8 = 1, const M: u8 = N> {}
 
 impl<const N: u8> Traitor<N, 2> for u32 {}
 impl Traitor<1, 2> for u64 {}
 
-
 fn uwu<const N: u8>() -> impl Traitor<N> {
     //~^ error: the trait bound `u32: Traitor<N>` is not satisfied
     1_u32
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
index cbc7b93f3a9..f2e7777ce68 100644
--- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
+++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
@@ -1,16 +1,16 @@
-error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+error[E0277]: the trait bound `Uwu<10, 12>: Trait` is not satisfied
   --> $DIR/rp_impl_trait_fail.rs:6:14
    |
 LL | fn rawr() -> impl Trait {
-   |              ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
+   |              ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10, 12>`
 LL |
 LL |     Uwu::<10, 12>
-   |     ------------- return type was inferred to be `Uwu<10_u32, 12_u32>` here
+   |     ------------- return type was inferred to be `Uwu<10, 12>` here
    |
    = help: the trait `Trait` is implemented for `Uwu<N>`
 
 error[E0277]: the trait bound `u32: Traitor<N>` is not satisfied
-  --> $DIR/rp_impl_trait_fail.rs:17:26
+  --> $DIR/rp_impl_trait_fail.rs:16:26
    |
 LL | fn uwu<const N: u8>() -> impl Traitor<N> {
    |                          ^^^^^^^^^^^^^^^ the trait `Traitor<N>` is not implemented for `u32`
@@ -19,11 +19,11 @@ LL |     1_u32
    |     ----- return type was inferred to be `u32` here
    |
    = help: the following other types implement trait `Traitor<N, M>`:
-             <u32 as Traitor<N, 2_u8>>
-             <u64 as Traitor<1_u8, 2_u8>>
+             <u32 as Traitor<N, 2>>
+             <u64 as Traitor<1, 2>>
 
 error[E0277]: the trait bound `u64: Traitor` is not satisfied
-  --> $DIR/rp_impl_trait_fail.rs:22:13
+  --> $DIR/rp_impl_trait_fail.rs:21:13
    |
 LL | fn owo() -> impl Traitor {
    |             ^^^^^^^^^^^^ the trait `Traitor` is not implemented for `u64`
@@ -32,8 +32,8 @@ LL |     1_u64
    |     ----- return type was inferred to be `u64` here
    |
    = help: the following other types implement trait `Traitor<N, M>`:
-             <u32 as Traitor<N, 2_u8>>
-             <u64 as Traitor<1_u8, 2_u8>>
+             <u32 as Traitor<N, 2>>
+             <u64 as Traitor<1, 2>>
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.rs b/src/test/ui/const-generics/defaults/trait_objects_fail.rs
index 5e779d2e8de..6ab803f9909 100644
--- a/src/test/ui/const-generics/defaults/trait_objects_fail.rs
+++ b/src/test/ui/const-generics/defaults/trait_objects_fail.rs
@@ -16,7 +16,7 @@ trait Traitor<const N: u8 = 1, const M: u8 = N> {
     }
 }
 
-impl Traitor<2, 3> for bool { }
+impl Traitor<2, 3> for bool {}
 
 fn bar<const N: u8>(arg: &dyn Traitor<N>) -> u8 {
     arg.owo()
@@ -26,5 +26,5 @@ fn main() {
     foo(&10_u32);
     //~^ error: the trait bound `u32: Trait` is not satisfied
     bar(&true);
-    //~^ error: the trait bound `bool: Traitor<{_: u8}>` is not satisfied
+    //~^ error: the trait bound `bool: Traitor<_>` is not satisfied
 }
diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr
index da85b2059f0..a9c185e5fcb 100644
--- a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr
+++ b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr
@@ -6,19 +6,19 @@ LL |     foo(&10_u32);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Trait<2_u8>` is implemented for `u32`
+   = help: the trait `Trait<2>` is implemented for `u32`
    = note: required for the cast from `u32` to the object type `dyn Trait`
 
-error[E0277]: the trait bound `bool: Traitor<{_: u8}>` is not satisfied
+error[E0277]: the trait bound `bool: Traitor<_>` is not satisfied
   --> $DIR/trait_objects_fail.rs:28:9
    |
 LL |     bar(&true);
-   |     --- ^^^^^ the trait `Traitor<{_: u8}>` is not implemented for `bool`
+   |     --- ^^^^^ the trait `Traitor<_>` is not implemented for `bool`
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Traitor<2_u8, 3_u8>` is implemented for `bool`
-   = note: required for the cast from `bool` to the object type `dyn Traitor<{_: u8}>`
+   = help: the trait `Traitor<2, 3>` is implemented for `bool`
+   = note: required for the cast from `bool` to the object type `dyn Traitor<_>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/defaults/wfness.rs b/src/test/ui/const-generics/defaults/wfness.rs
index d366040ba3e..a93f670815a 100644
--- a/src/test/ui/const-generics/defaults/wfness.rs
+++ b/src/test/ui/const-generics/defaults/wfness.rs
@@ -3,16 +3,20 @@ struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
 
 trait Trait<const N: u8> {}
 impl Trait<3> for () {}
-struct WhereClause<const N: u8 = 2> where (): Trait<N>;
-//~^ error: the trait bound `(): Trait<2_u8>` is not satisfied
+struct WhereClause<const N: u8 = 2>
+where
+    (): Trait<N>;
+//~^ error: the trait bound `(): Trait<2>` is not satisfied
 
 trait Traitor<T, const N: u8> {}
-struct WhereClauseTooGeneric<T = u32, const N: u8 = 2>(T) where (): Traitor<T, N>;
+struct WhereClauseTooGeneric<T = u32, const N: u8 = 2>(T)
+where
+    (): Traitor<T, N>;
 
 // no error on struct def
 struct DependentDefaultWfness<const N: u8 = 1, T = WhereClause<N>>(T);
 fn foo() -> DependentDefaultWfness {
-    //~^ error: the trait bound `(): Trait<1_u8>` is not satisfied
+    //~^ error: the trait bound `(): Trait<1>` is not satisfied
     loop {}
 }
 
diff --git a/src/test/ui/const-generics/defaults/wfness.stderr b/src/test/ui/const-generics/defaults/wfness.stderr
index 8b405d6753e..25038f830be 100644
--- a/src/test/ui/const-generics/defaults/wfness.stderr
+++ b/src/test/ui/const-generics/defaults/wfness.stderr
@@ -4,26 +4,29 @@ error[E0080]: evaluation of constant value failed
 LL | struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
    |                                 ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
 
-error[E0277]: the trait bound `(): Trait<2_u8>` is not satisfied
-  --> $DIR/wfness.rs:6:47
+error[E0277]: the trait bound `(): Trait<2>` is not satisfied
+  --> $DIR/wfness.rs:8:9
    |
-LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
-   |                                               ^^^^^^^^ the trait `Trait<2_u8>` is not implemented for `()`
+LL |     (): Trait<N>;
+   |         ^^^^^^^^ the trait `Trait<2>` is not implemented for `()`
    |
-   = help: the trait `Trait<3_u8>` is implemented for `()`
+   = help: the trait `Trait<3>` is implemented for `()`
 
-error[E0277]: the trait bound `(): Trait<1_u8>` is not satisfied
-  --> $DIR/wfness.rs:14:13
+error[E0277]: the trait bound `(): Trait<1>` is not satisfied
+  --> $DIR/wfness.rs:18:13
    |
 LL | fn foo() -> DependentDefaultWfness {
-   |             ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1_u8>` is not implemented for `()`
+   |             ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1>` is not implemented for `()`
    |
-   = help: the trait `Trait<3_u8>` is implemented for `()`
+   = help: the trait `Trait<3>` is implemented for `()`
 note: required by a bound in `WhereClause`
-  --> $DIR/wfness.rs:6:47
+  --> $DIR/wfness.rs:8:9
    |
-LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
-   |                                               ^^^^^^^^ required by this bound in `WhereClause`
+LL | struct WhereClause<const N: u8 = 2>
+   |        ----------- required by a bound in this
+LL | where
+LL |     (): Trait<N>;
+   |         ^^^^^^^^ required by this bound in `WhereClause`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/different_generic_args.full.stderr b/src/test/ui/const-generics/different_generic_args.full.stderr
index a2dcc033627..eba1768f7dd 100644
--- a/src/test/ui/const-generics/different_generic_args.full.stderr
+++ b/src/test/ui/const-generics/different_generic_args.full.stderr
@@ -2,10 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/different_generic_args.rs:11:9
    |
 LL |     u = ConstUsize::<4> {};
-   |         ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
+   |         ^^^^^^^^^^^^^^^^^^ expected `3`, found `4`
    |
-   = note: expected struct `ConstUsize<3_usize>`
-              found struct `ConstUsize<4_usize>`
+   = note: expected struct `ConstUsize<3>`
+              found struct `ConstUsize<4>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/different_generic_args.min.stderr b/src/test/ui/const-generics/different_generic_args.min.stderr
index a2dcc033627..eba1768f7dd 100644
--- a/src/test/ui/const-generics/different_generic_args.min.stderr
+++ b/src/test/ui/const-generics/different_generic_args.min.stderr
@@ -2,10 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/different_generic_args.rs:11:9
    |
 LL |     u = ConstUsize::<4> {};
-   |         ^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
+   |         ^^^^^^^^^^^^^^^^^^ expected `3`, found `4`
    |
-   = note: expected struct `ConstUsize<3_usize>`
-              found struct `ConstUsize<4_usize>`
+   = note: expected struct `ConstUsize<3>`
+              found struct `ConstUsize<4>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/different_generic_args_array.stderr b/src/test/ui/const-generics/different_generic_args_array.stderr
index f0b9035357d..4c5b5ada4f1 100644
--- a/src/test/ui/const-generics/different_generic_args_array.stderr
+++ b/src/test/ui/const-generics/different_generic_args_array.stderr
@@ -2,10 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/different_generic_args_array.rs:9:9
    |
 LL |     x = Const::<{ [4] }> {};
-   |         ^^^^^^^^^^^^^^^^^^^ expected `[3_usize]`, found `[4_usize]`
+   |         ^^^^^^^^^^^^^^^^^^^ expected `[3]`, found `[4]`
    |
-   = note: expected struct `Const<[3_usize]>`
-              found struct `Const<[4_usize]>`
+   = note: expected struct `Const<[3]>`
+              found struct `Const<[4]>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/exhaustive-value.stderr b/src/test/ui/const-generics/exhaustive-value.stderr
index 9c1b086f4da..76a83ba67ce 100644
--- a/src/test/ui/const-generics/exhaustive-value.stderr
+++ b/src/test/ui/const-generics/exhaustive-value.stderr
@@ -5,14 +5,14 @@ LL |     <() as Foo<N>>::test()
    |     ^^^^^^^^^^^^^^^^^^^^ the trait `Foo<N>` is not implemented for `()`
    |
    = help: the following other types implement trait `Foo<N>`:
-             <() as Foo<0_u8>>
-             <() as Foo<100_u8>>
-             <() as Foo<101_u8>>
-             <() as Foo<102_u8>>
-             <() as Foo<103_u8>>
-             <() as Foo<104_u8>>
-             <() as Foo<105_u8>>
-             <() as Foo<106_u8>>
+             <() as Foo<0>>
+             <() as Foo<100>>
+             <() as Foo<101>>
+             <() as Foo<102>>
+             <() as Foo<103>>
+             <() as Foo<104>>
+             <() as Foo<105>>
+             <() as Foo<106>>
            and 248 others
 
 error: aborting due to previous error
diff --git a/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr b/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr
index 7581cf4120e..52d1b29f932 100644
--- a/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr
+++ b/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr
@@ -14,7 +14,7 @@ LL | fn ty_fn() -> Bar<i32, _> {
    |               ---------^-
    |               |        |
    |               |        not allowed in type signatures
-   |               help: replace with the correct return type: `Bar<i32, 3_usize>`
+   |               help: replace with the correct return type: `Bar<i32, 3>`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/in-signature.rs:17:25
@@ -24,7 +24,7 @@ LL | fn ty_fn_mixed() -> Bar<_, _> {
    |                     |   |  |
    |                     |   |  not allowed in type signatures
    |                     |   not allowed in type signatures
-   |                     help: replace with the correct return type: `Bar<i32, 3_usize>`
+   |                     help: replace with the correct return type: `Bar<i32, 3>`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/in-signature.rs:22:15
@@ -45,7 +45,7 @@ LL | const TY_CT: Bar<i32, _> = Bar::<i32, 3>(0);
    |              ^^^^^^^^^^^
    |              |
    |              not allowed in type signatures
-   |              help: replace with the correct type: `Bar<i32, 3_usize>`
+   |              help: replace with the correct type: `Bar<i32, 3>`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/in-signature.rs:28:19
@@ -54,7 +54,7 @@ LL | static TY_STATIC: Bar<i32, _> = Bar::<i32, 3>(0);
    |                   ^^^^^^^^^^^
    |                   |
    |                   not allowed in type signatures
-   |                   help: replace with the correct type: `Bar<i32, 3_usize>`
+   |                   help: replace with the correct type: `Bar<i32, 3>`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/in-signature.rs:30:20
@@ -63,7 +63,7 @@ LL | const TY_CT_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
    |                    ^^^^^^^^^
    |                    |
    |                    not allowed in type signatures
-   |                    help: replace with the correct type: `Bar<i32, 3_usize>`
+   |                    help: replace with the correct type: `Bar<i32, 3>`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/in-signature.rs:32:25
@@ -72,7 +72,7 @@ LL | static TY_STATIC_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
    |                         ^^^^^^^^^
    |                         |
    |                         not allowed in type signatures
-   |                         help: replace with the correct type: `Bar<i32, 3_usize>`
+   |                         help: replace with the correct type: `Bar<i32, 3>`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/in-signature.rs:35:21
diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr b/src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr
index f235eb443b8..ababb27a869 100644
--- a/src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr
@@ -56,19 +56,19 @@ error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:23:5
    |
 LL |     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13`
    |
-   = note: expected type `12_u128`
-              found type `13_u128`
+   = note: expected type `12`
+              found type `13`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:25:5
    |
 LL |     assert_impl::<HasCastInTraitImpl<14, 13>>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14`
    |
-   = note: expected type `13_u128`
-              found type `14_u128`
+   = note: expected type `13`
+              found type `14`
 
 error: unconstrained generic constant
   --> $DIR/abstract-const-as-cast-3.rs:35:5
@@ -128,19 +128,19 @@ error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:41:5
    |
 LL |     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13`
    |
-   = note: expected type `12_u128`
-              found type `13_u128`
+   = note: expected type `12`
+              found type `13`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:43:5
    |
 LL |     assert_impl::<HasCastInTraitImpl<14, 13>>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14`
    |
-   = note: expected type `13_u128`
-              found type `14_u128`
+   = note: expected type `13`
+              found type `14`
 
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs
index 90953145944..b8f9827ec91 100644
--- a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs
@@ -2,7 +2,7 @@
 #![allow(incomplete_features)]
 
 fn test<const N: usize>() -> [u8; N - 1] {
-    //~^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
+    //~^ ERROR evaluation of `test::<0>::{constant#0}` failed
     todo!()
 }
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr
index 31ccf979694..bd71b49ee23 100644
--- a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr
@@ -1,4 +1,4 @@
-error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
+error[E0080]: evaluation of `test::<0>::{constant#0}` failed
   --> $DIR/from-sig-fail.rs:4:35
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] {
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr
index 77a3b77ad42..7a083733a2c 100644
--- a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr
@@ -4,14 +4,14 @@ error[E0423]: expected value, found type parameter `T`
 LL | impl<T> Bar<T> for [u8; T] {}
    |                         ^ not a value
 
-error[E0599]: the function or associated item `foo` exists for struct `Foo<{_: usize}>`, but its trait bounds were not satisfied
+error[E0599]: the function or associated item `foo` exists for struct `Foo<_>`, but its trait bounds were not satisfied
   --> $DIR/issue-69654.rs:17:10
    |
 LL | struct Foo<const N: usize> {}
    | -------------------------- function or associated item `foo` not found for this struct
 ...
 LL |     Foo::foo();
-   |          ^^^ function or associated item cannot be called on `Foo<{_: usize}>` due to unsatisfied trait bounds
+   |          ^^^ function or associated item cannot be called on `Foo<_>` due to unsatisfied trait bounds
    |
    = note: the following trait bounds were not satisfied:
            `[u8; _]: Bar<[(); _]>`
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr
index 41afaec86b6..4d0d0253f1b 100644
--- a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr
@@ -34,21 +34,21 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    = help: const parameters may only be used as standalone arguments, i.e. `J`
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
+error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8>: True`
   --> $DIR/issue-72787.rs:21:26
    |
 LL |     IsLessOrEqual<I, 8>: True,
    |                          ^^^^
    |
-   = note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
+   = note: cannot satisfy `IsLessOrEqual<I, 8>: True`
 
-error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
+error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8>: True`
   --> $DIR/issue-72787.rs:21:26
    |
 LL |     IsLessOrEqual<I, 8>: True,
    |                          ^^^^
    |
-   = note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
+   = note: cannot satisfy `IsLessOrEqual<I, 8>: True`
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs b/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs
index c47a350c7fb..cae54df4c12 100644
--- a/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs
@@ -2,10 +2,13 @@
 #![allow(incomplete_features)]
 
 type Arr<const N: usize> = [u8; N - 1];
-//~^ ERROR evaluation of `Arr::<0_usize>::{constant#0}` failed
+//~^ ERROR evaluation of `Arr::<0>::{constant#0}` failed
 
-fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
-//~^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
+fn test<const N: usize>() -> Arr<N>
+where
+    [u8; N - 1]: Sized,
+    //~^ ERROR evaluation of `test::<0>::{constant#0}` failed
+{
     todo!()
 }
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr b/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr
index 99fc92fb4f0..a25fa56b7d4 100644
--- a/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr
@@ -1,10 +1,10 @@
-error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
-  --> $DIR/simple_fail.rs:7:48
+error[E0080]: evaluation of `test::<0>::{constant#0}` failed
+  --> $DIR/simple_fail.rs:9:10
    |
-LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
-   |                                                ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
+LL |     [u8; N - 1]: Sized,
+   |          ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
 
-error[E0080]: evaluation of `Arr::<0_usize>::{constant#0}` failed
+error[E0080]: evaluation of `Arr::<0>::{constant#0}` failed
   --> $DIR/simple_fail.rs:4:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
diff --git a/src/test/ui/const-generics/infer/one-param-uninferred.stderr b/src/test/ui/const-generics/infer/one-param-uninferred.stderr
index 98ea8df8252..cf70c218139 100644
--- a/src/test/ui/const-generics/infer/one-param-uninferred.stderr
+++ b/src/test/ui/const-generics/infer/one-param-uninferred.stderr
@@ -6,8 +6,8 @@ LL |     let _: [u8; 17] = foo();
    |
 help: consider specifying the generic arguments
    |
-LL |     let _: [u8; 17] = foo::<17_usize, M>();
-   |                          +++++++++++++++
+LL |     let _: [u8; 17] = foo::<17, M>();
+   |                          +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issue-66451.stderr b/src/test/ui/const-generics/issue-66451.stderr
index b691eac4f2d..e0cb0b661ff 100644
--- a/src/test/ui/const-generics/issue-66451.stderr
+++ b/src/test/ui/const-generics/issue-66451.stderr
@@ -8,12 +8,12 @@ LL | |             value: 3,
 LL | |             nested: &Bar(5),
 LL | |         }
 LL | |     }> = x;
-   | |      -   ^ expected `Foo { value: 3_i32, nested: &Bar::<i32>(5_i32) }`, found `Foo { value: 3_i32, nested: &Bar::<i32>(4_i32) }`
+   | |      -   ^ expected `Foo { value: 3, nested: &Bar::<i32>(5) }`, found `Foo { value: 3, nested: &Bar::<i32>(4) }`
    | |______|
    |        expected due to this
    |
-   = note: expected struct `Test<Foo { value: 3_i32, nested: &Bar::<i32>(5_i32) }>`
-              found struct `Test<Foo { value: 3_i32, nested: &Bar::<i32>(4_i32) }>`
+   = note: expected struct `Test<Foo { value: 3, nested: &Bar::<i32>(5) }>`
+              found struct `Test<Foo { value: 3, nested: &Bar::<i32>(4) }>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-86530.rs b/src/test/ui/const-generics/issues/issue-86530.rs
index 4a6ffd1f300..b024decd4e1 100644
--- a/src/test/ui/const-generics/issues/issue-86530.rs
+++ b/src/test/ui/const-generics/issues/issue-86530.rs
@@ -15,7 +15,6 @@ where
 fn unit_literals() {
     z(" ");
     //~^ ERROR: the trait bound `&str: X` is not satisfied
-    //~| ERROR: unconstrained generic constant
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-86530.stderr b/src/test/ui/const-generics/issues/issue-86530.stderr
index c688f838dab..c63857b2314 100644
--- a/src/test/ui/const-generics/issues/issue-86530.stderr
+++ b/src/test/ui/const-generics/issues/issue-86530.stderr
@@ -15,22 +15,6 @@ LL | where
 LL |     T: X,
    |        ^ required by this bound in `z`
 
-error: unconstrained generic constant
-  --> $DIR/issue-86530.rs:16:5
-   |
-LL |     z(" ");
-   |     ^
-   |
-   = help: try adding a `where` bound using this expression: `where [(); T::Y]:`
-note: required by a bound in `z`
-  --> $DIR/issue-86530.rs:11:10
-   |
-LL | fn z<T>(t: T)
-   |    - required by a bound in this
-...
-LL |     [(); T::Y]: ,
-   |          ^^^^ required by this bound in `z`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-98629.rs b/src/test/ui/const-generics/issues/issue-98629.rs
new file mode 100644
index 00000000000..fc8666bbcdb
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-98629.rs
@@ -0,0 +1,15 @@
+#![feature(const_trait_impl)]
+
+trait Trait {
+    const N: usize;
+}
+
+impl const Trait for i32 {}
+//~^ ERROR not all trait items implemented, missing: `N`
+
+fn f()
+where
+    [(); <i32 as Trait>::N]:,
+{}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-98629.stderr b/src/test/ui/const-generics/issues/issue-98629.stderr
new file mode 100644
index 00000000000..53570220882
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-98629.stderr
@@ -0,0 +1,12 @@
+error[E0046]: not all trait items implemented, missing: `N`
+  --> $DIR/issue-98629.rs:7:1
+   |
+LL |     const N: usize;
+   |     -------------- `N` from trait
+...
+LL | impl const Trait for i32 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ missing `N` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr
index 52f1c588258..6d9f4406504 100644
--- a/src/test/ui/const-generics/nested-type.full.stderr
+++ b/src/test/ui/const-generics/nested-type.full.stderr
@@ -1,4 +1,4 @@
-error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants
+error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17>::value` in constants
   --> $DIR/nested-type.rs:15:5
    |
 LL |     Foo::<17>::value()
diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr
index 48e12e903b8..a3c011d927b 100644
--- a/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr
+++ b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr
@@ -1,10 +1,10 @@
-error[E0277]: the trait bound `A<{_: usize}>: Bar<{_: usize}>` is not satisfied
+error[E0277]: the trait bound `A<_>: Bar<_>` is not satisfied
   --> $DIR/unused-substs-1.rs:12:13
    |
 LL |     let _ = A;
-   |             ^ the trait `Bar<{_: usize}>` is not implemented for `A<{_: usize}>`
+   |             ^ the trait `Bar<_>` is not implemented for `A<_>`
    |
-   = help: the trait `Bar<N>` is implemented for `A<7_usize>`
+   = help: the trait `Bar<N>` is implemented for `A<7>`
 note: required by a bound in `A`
   --> $DIR/unused-substs-1.rs:9:11
    |
diff --git a/src/test/ui/const-generics/types-mismatch-const-args.full.stderr b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr
index 4d6b752867f..486506239dd 100644
--- a/src/test/ui/const-generics/types-mismatch-const-args.full.stderr
+++ b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr
@@ -2,10 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/types-mismatch-const-args.rs:14:41
    |
 LL |     let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {2u32 + 2u32}, {3u32}> { data: PhantomData };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32`
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `4`
    |
-   = note: expected type `2_u32`
-              found type `4_u32`
+   = note: expected type `2`
+              found type `4`
 
 error[E0308]: mismatched types
   --> $DIR/types-mismatch-const-args.rs:16:41
@@ -26,8 +26,8 @@ LL |     let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data
    |            |
    |            expected due to this
    |
-   = note: expected struct `A<'a, u16, 4_u32, _>`
-              found struct `A<'b, u32, 2_u32, _>`
+   = note: expected struct `A<'a, u16, 4, _>`
+              found struct `A<'b, u32, 2, _>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/types-mismatch-const-args.min.stderr b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr
index 8b60238cb0c..6ac93a08d5d 100644
--- a/src/test/ui/const-generics/types-mismatch-const-args.min.stderr
+++ b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr
@@ -2,12 +2,12 @@ error[E0308]: mismatched types
   --> $DIR/types-mismatch-const-args.rs:14:41
    |
 LL |     let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {2u32 + 2u32}, {3u32}> { data: PhantomData };
-   |            --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32`
+   |            --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `4`
    |            |
    |            expected due to this
    |
-   = note: expected struct `A<'_, _, 2_u32, _>`
-              found struct `A<'_, _, 4_u32, _>`
+   = note: expected struct `A<'_, _, 2, _>`
+              found struct `A<'_, _, 4, _>`
 
 error[E0308]: mismatched types
   --> $DIR/types-mismatch-const-args.rs:16:41
@@ -28,8 +28,8 @@ LL |     let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data
    |            |
    |            expected due to this
    |
-   = note: expected struct `A<'a, u16, 4_u32, _>`
-              found struct `A<'b, u32, 2_u32, _>`
+   = note: expected struct `A<'a, u16, 4, _>`
+              found struct `A<'b, u32, 2, _>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/consts/const-eval/const_transmute.rs b/src/test/ui/consts/const-eval/const_transmute.rs
deleted file mode 100644
index 90a454c75a1..00000000000
--- a/src/test/ui/consts/const-eval/const_transmute.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-
-#[repr(C)]
-union Transmute<T: Copy, U: Copy> {
-    t: T,
-    u: U,
-}
-
-trait Bar {
-    fn bar(&self) -> u32;
-}
-
-struct Foo {
-    foo: u32,
-    bar: bool,
-}
-
-impl Bar for Foo {
-    fn bar(&self) -> u32 {
-        self.foo
-    }
-}
-
-impl Drop for Foo {
-    fn drop(&mut self) {
-        assert!(!self.bar);
-        self.bar = true;
-        println!("dropping Foo");
-    }
-}
-
-#[derive(Copy, Clone)]
-struct Fat<'a>(&'a Foo, &'static VTable);
-
-struct VTable {
-    drop: Option<for<'a> fn(&'a mut Foo)>,
-    size: usize,
-    align: usize,
-    bar: for<'a> fn(&'a Foo) -> u32,
-}
-
-const FOO: &dyn Bar = &Foo { foo: 128, bar: false };
-const G: Fat = unsafe { Transmute { t: FOO }.u };
-const F: Option<for<'a> fn(&'a mut Foo)> = G.1.drop;
-const H: for<'a> fn(&'a Foo) -> u32 = G.1.bar;
-
-fn main() {
-    let mut foo = Foo { foo: 99, bar: false };
-    (F.unwrap())(&mut foo);
-    std::mem::forget(foo); // already ran the drop impl
-    assert_eq!(H(&Foo { foo: 42, bar: false }), 42);
-}
diff --git a/src/test/ui/consts/const-eval/issue-85155.stderr b/src/test/ui/consts/const-eval/issue-85155.stderr
index c36d7c17215..3d2c76b7ed0 100644
--- a/src/test/ui/consts/const-eval/issue-85155.stderr
+++ b/src/test/ui/consts/const-eval/issue-85155.stderr
@@ -1,10 +1,10 @@
-error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2_i32, 0_i32, 1_i32>::VALID` failed
+error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2, 0, 1>::VALID` failed
   --> $DIR/auxiliary/post_monomorphization_error.rs:7:17
    |
 LL |         let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero
 
-note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2_i32>`
+note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2>`
   --> $DIR/issue-85155.rs:19:5
    |
 LL |     post_monomorphization_error::stdarch_intrinsic::<2>();
diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
index c6422447a4b..965256de21a 100644
--- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
@@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-incorrect-vtable.rs:19:14
    |
 LL |     unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: alignment `1000` is not a power of 2
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/ub-incorrect-vtable.rs:24:14
    |
 LL |     unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: size is bigger than largest supported object
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-incorrect-vtable.rs:34:1
+  --> $DIR/ub-incorrect-vtable.rs:33:1
    |
 LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -22,16 +22,38 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-incorrect-vtable.rs:39:1
+  --> $DIR/ub-incorrect-vtable.rs:38:1
    |
 LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾─allocN─╼ ╾─allocN─╼                         │ ╾──╼╾──╼
            }
 
-error: aborting due to 4 previous errors
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:44:1
+   |
+LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─allocN─╼ ╾─allocN─╼                         │ ╾──╼╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:91:1
+   |
+LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
+   | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─allocN─╼ ╾─allocN─╼                         │ ╾──╼╾──╼
+           }
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
index e594ad71b5b..bd542a7a5f2 100644
--- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
@@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-incorrect-vtable.rs:19:14
    |
 LL |     unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: alignment `1000` is not a power of 2
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/ub-incorrect-vtable.rs:24:14
    |
 LL |     unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: size is bigger than largest supported object
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-incorrect-vtable.rs:34:1
+  --> $DIR/ub-incorrect-vtable.rs:33:1
    |
 LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -22,16 +22,38 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-incorrect-vtable.rs:39:1
+  --> $DIR/ub-incorrect-vtable.rs:38:1
    |
 LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
            }
 
-error: aborting due to 4 previous errors
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:44:1
+   |
+LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:91:1
+   |
+LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
+   | ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
+           }
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs b/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs
index 4ec853576c9..4bb30b75bc8 100644
--- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs
+++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs
@@ -18,27 +18,79 @@ trait Trait {}
 const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
     unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
 //~^ ERROR evaluation of constant value failed
-//~| invalid vtable: alignment `1000` is not a power of 2
+//~| does not point to a vtable
 
 const INVALID_VTABLE_SIZE: &dyn Trait =
     unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
 //~^ ERROR evaluation of constant value failed
-//~| invalid vtable: size is bigger than largest supported object
+//~| does not point to a vtable
 
 #[repr(transparent)]
 struct W<T>(T);
 
-// The drop fn is checked before size/align are, so get ourselves a "sufficiently valid" drop fn
 fn drop_me(_: *mut usize) {}
 
 const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
     unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
 //~^^ ERROR it is undefined behavior to use this value
-//~| invalid vtable: alignment `1000` is not a power of 2
+//~| expected a vtable pointer
 
 const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
     unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
 //~^^ ERROR it is undefined behavior to use this value
-//~| invalid vtable: size is bigger than largest supported object
+//~| expected a vtable pointer
+
+// Even if the vtable has a fn ptr and a reasonable size+align, it still does not work.
+const INVALID_VTABLE_UB: W<&dyn Trait> =
+    unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1usize))) };
+//~^^ ERROR it is undefined behavior to use this value
+//~| expected a vtable pointer
+
+// Trying to access the data in a vtable does not work, either.
+
+#[derive(Copy, Clone)]
+struct Wide<'a>(&'a Foo, &'static VTable);
+
+struct VTable {
+    drop: Option<for<'a> fn(&'a mut Foo)>,
+    size: usize,
+    align: usize,
+    bar: for<'a> fn(&'a Foo) -> u32,
+}
+
+trait Bar {
+    fn bar(&self) -> u32;
+}
+
+struct Foo {
+    foo: u32,
+    bar: bool,
+}
+
+impl Bar for Foo {
+    fn bar(&self) -> u32 {
+        self.foo
+    }
+}
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+        assert!(!self.bar);
+        self.bar = true;
+        println!("dropping Foo");
+    }
+}
+
+#[repr(C)]
+union Transmute<T: Copy, U: Copy> {
+    t: T,
+    u: U,
+}
+
+const FOO: &dyn Bar = &Foo { foo: 128, bar: false };
+const G: Wide = unsafe { Transmute { t: FOO }.u };
+//~^ ERROR it is undefined behavior to use this value
+//~| encountered a dangling reference
+// (it is dangling because vtables do not contain memory that can be dereferenced)
 
 fn main() {}
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
index 2cae35bc4d0..ae114233c0f 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
@@ -125,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:56:1
    |
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -147,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:60:1
    |
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x0000000d, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -158,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:62:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
index e2cd0e64db8..1b93a869c0d 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
@@ -125,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:56:1
    |
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -147,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:60:1
    |
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x000000000000000d, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -158,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:62:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
diff --git a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr
index 43f73f6ec7f..f7898e55ee2 100644
--- a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr
@@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─alloc3──╼ ╾─alloc6──╼                         │ ╾──╼╾──╼
+               ╾─alloc3──╼ ╾─alloc4──╼                         │ ╾──╼╾──╼
            }
 
 error: aborting due to previous error
diff --git a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr
index 64185a06362..60432380e13 100644
--- a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr
@@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼
+               ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼
            }
 
 error: aborting due to previous error
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
index 2fd98ea322b..345ead48151 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
@@ -209,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:117:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -217,10 +217,10 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:120:1
+  --> $DIR/ub-wide-ptr.rs:121:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -228,54 +228,39 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:123:1
+  --> $DIR/ub-wide-ptr.rs:125:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾allocN─╼ 04 00 00 00                         │ ╾──╼....
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:125:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:128:57
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
-           }
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:127:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:131:57
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
-           }
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:129:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:134:56
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
-           }
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:131:1
+  --> $DIR/ub-wide-ptr.rs:137:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -283,7 +268,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:135:1
+  --> $DIR/ub-wide-ptr.rs:142:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
@@ -293,39 +278,29 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
                ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:139:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:147:62
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ 00 00 00 00                         │ ╾──╼....
-           }
+   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:141:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:150:65
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾allocN─╼ ╾allocN─╼                         │ ╾──╼╾──╼
-           }
+   |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:147:5
+  --> $DIR/ub-wide-ptr.rs:157:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:151:5
+  --> $DIR/ub-wide-ptr.rs:161:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 12 bytes starting at offset N is out-of-bounds
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error: aborting due to 32 previous errors
 
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
index bae24907659..501932cb95c 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
@@ -209,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:117:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -217,10 +217,10 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:120:1
+  --> $DIR/ub-wide-ptr.rs:121:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -228,54 +228,39 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:123:1
+  --> $DIR/ub-wide-ptr.rs:125:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾──────allocN───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:125:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:128:57
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
-           }
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:127:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:131:57
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
-           }
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:129:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:134:56
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
-           }
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:131:1
+  --> $DIR/ub-wide-ptr.rs:137:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -283,7 +268,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:135:1
+  --> $DIR/ub-wide-ptr.rs:142:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
@@ -293,39 +278,29 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
                ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:139:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:147:62
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
+   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:141:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:150:65
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
-           }
+   |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:147:5
+  --> $DIR/ub-wide-ptr.rs:157:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:151:5
+  --> $DIR/ub-wide-ptr.rs:161:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 24 bytes starting at offset N is out-of-bounds
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
 
 error: aborting due to 32 previous errors
 
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs
index f2e5738f88c..a0377ab1efd 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs
@@ -116,30 +116,40 @@ const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
 // bad trait object
 const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
 //~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
 // bad trait object
 const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
 //~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
 // bad trait object
 const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
 //~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
 const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
-//~^ ERROR it is undefined behavior to use this value
+//~^ ERROR evaluation of constant value failed
+//~| does not point to a vtable
 const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
-//~^ ERROR it is undefined behavior to use this value
+//~^ ERROR evaluation of constant value failed
+//~| does not point to a vtable
 const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
-//~^ ERROR it is undefined behavior to use this value
+//~^ ERROR evaluation of constant value failed
+//~| does not point to a vtable
 const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
 //~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
 
 // bad data *inside* the trait object
 const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
 //~^ ERROR it is undefined behavior to use this value
+//~| expected a boolean
 
 // # raw trait object
 const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-//~^ ERROR it is undefined behavior to use this value
+//~^ ERROR evaluation of constant value failed
+//~| null pointer
 const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-//~^ ERROR it is undefined behavior to use this value
+//~^ ERROR evaluation of constant value failed
+//~| does not point to a vtable
 const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) } as *const dyn Trait; // ok because raw
 
 // Const eval fails for these, so they need to be statics to error.
diff --git a/src/test/ui/consts/issue-79690.64bit.stderr b/src/test/ui/consts/issue-79690.64bit.stderr
index c7aba555370..b8798a9755f 100644
--- a/src/test/ui/consts/issue-79690.64bit.stderr
+++ b/src/test/ui/consts/issue-79690.64bit.stderr
@@ -2,11 +2,11 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/issue-79690.rs:30:1
    |
 LL | const G: Fat = unsafe { Transmute { t: FOO }.u };
-   | ^^^^^^^^^^^^ constructing invalid value at .1.<deref>.size.foo: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼
+               ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼
            }
 
 error: aborting due to previous error
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
index bb8636f1225..7ea35f70d10 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
+++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
@@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─alloc7──╼ ╾─alloc9──╼                         │ ╾──╼╾──╼
+               ╾─alloc7──╼ ╾─alloc8──╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42;
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾─alloc11─╼                                     │ ╾──╼
+               ╾─alloc10─╼                                     │ ╾──╼
            }
 
 warning: skipping const checks
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
index f1652da922a..5ad39893089 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
+++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
@@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────alloc7────────╼ ╾───────alloc9────────╼ │ ╾──────╼╾──────╼
+               ╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42;
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾───────alloc11───────╼                         │ ╾──────╼
+               ╾───────alloc10───────╼                         │ ╾──────╼
            }
 
 warning: skipping const checks
diff --git a/src/test/ui/deriving/deriving-all-codegen.stdout b/src/test/ui/deriving/deriving-all-codegen.stdout
index 542911537be..21fe663f067 100644
--- a/src/test/ui/deriving/deriving-all-codegen.stdout
+++ b/src/test/ui/deriving/deriving-all-codegen.stdout
@@ -25,42 +25,35 @@ extern crate std;
 // Empty struct.
 struct Empty;
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Empty {
     #[inline]
     fn clone(&self) -> Empty { *self }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::marker::Copy for Empty { }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Empty {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         ::core::fmt::Formatter::write_str(f, "Empty")
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::default::Default for Empty {
     #[inline]
     fn default() -> Empty { Empty {} }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Empty {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
 }
 impl ::core::marker::StructuralPartialEq for Empty {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Empty {
     #[inline]
     fn eq(&self, other: &Empty) -> bool { true }
 }
 impl ::core::marker::StructuralEq for Empty {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Empty {
     #[inline]
     #[doc(hidden)]
@@ -68,7 +61,6 @@ impl ::core::cmp::Eq for Empty {
     fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Empty {
     #[inline]
     fn partial_cmp(&self, other: &Empty)
@@ -77,7 +69,6 @@ impl ::core::cmp::PartialOrd for Empty {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Empty {
     #[inline]
     fn cmp(&self, other: &Empty) -> ::core::cmp::Ordering {
@@ -91,7 +82,6 @@ struct Point {
     y: u32,
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Point {
     #[inline]
     fn clone(&self) -> Point {
@@ -100,10 +90,8 @@ impl ::core::clone::Clone for Point {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::marker::Copy for Point { }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Point {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         ::core::fmt::Formatter::debug_struct_field2_finish(f, "Point", "x",
@@ -111,7 +99,6 @@ impl ::core::fmt::Debug for Point {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::default::Default for Point {
     #[inline]
     fn default() -> Point {
@@ -122,7 +109,6 @@ impl ::core::default::Default for Point {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Point {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         ::core::hash::Hash::hash(&self.x, state);
@@ -131,7 +117,6 @@ impl ::core::hash::Hash for Point {
 }
 impl ::core::marker::StructuralPartialEq for Point {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Point {
     #[inline]
     fn eq(&self, other: &Point) -> bool {
@@ -144,7 +129,6 @@ impl ::core::cmp::PartialEq for Point {
 }
 impl ::core::marker::StructuralEq for Point {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Point {
     #[inline]
     #[doc(hidden)]
@@ -154,7 +138,6 @@ impl ::core::cmp::Eq for Point {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Point {
     #[inline]
     fn partial_cmp(&self, other: &Point)
@@ -167,7 +150,6 @@ impl ::core::cmp::PartialOrd for Point {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Point {
     #[inline]
     fn cmp(&self, other: &Point) -> ::core::cmp::Ordering {
@@ -191,7 +173,6 @@ struct Big {
     b8: u32,
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Big {
     #[inline]
     fn clone(&self) -> Big {
@@ -208,7 +189,6 @@ impl ::core::clone::Clone for Big {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Big {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         let names: &'static _ =
@@ -221,7 +201,6 @@ impl ::core::fmt::Debug for Big {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::default::Default for Big {
     #[inline]
     fn default() -> Big {
@@ -238,7 +217,6 @@ impl ::core::default::Default for Big {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Big {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         ::core::hash::Hash::hash(&self.b1, state);
@@ -253,7 +231,6 @@ impl ::core::hash::Hash for Big {
 }
 impl ::core::marker::StructuralPartialEq for Big {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Big {
     #[inline]
     fn eq(&self, other: &Big) -> bool {
@@ -272,7 +249,6 @@ impl ::core::cmp::PartialEq for Big {
 }
 impl ::core::marker::StructuralEq for Big {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Big {
     #[inline]
     #[doc(hidden)]
@@ -282,7 +258,6 @@ impl ::core::cmp::Eq for Big {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Big {
     #[inline]
     fn partial_cmp(&self, other: &Big)
@@ -331,7 +306,6 @@ impl ::core::cmp::PartialOrd for Big {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Big {
     #[inline]
     fn cmp(&self, other: &Big) -> ::core::cmp::Ordering {
@@ -370,7 +344,6 @@ impl ::core::cmp::Ord for Big {
 // A struct with an unsized field. Some derives are not usable in this case.
 struct Unsized([u32]);
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Unsized {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Unsized",
@@ -378,7 +351,6 @@ impl ::core::fmt::Debug for Unsized {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Unsized {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         ::core::hash::Hash::hash(&self.0, state)
@@ -386,7 +358,6 @@ impl ::core::hash::Hash for Unsized {
 }
 impl ::core::marker::StructuralPartialEq for Unsized {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Unsized {
     #[inline]
     fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 }
@@ -395,7 +366,6 @@ impl ::core::cmp::PartialEq for Unsized {
 }
 impl ::core::marker::StructuralEq for Unsized {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Unsized {
     #[inline]
     #[doc(hidden)]
@@ -405,7 +375,6 @@ impl ::core::cmp::Eq for Unsized {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Unsized {
     #[inline]
     fn partial_cmp(&self, other: &Unsized)
@@ -414,7 +383,6 @@ impl ::core::cmp::PartialOrd for Unsized {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Unsized {
     #[inline]
     fn cmp(&self, other: &Unsized) -> ::core::cmp::Ordering {
@@ -426,7 +394,6 @@ impl ::core::cmp::Ord for Unsized {
 #[repr(packed)]
 struct PackedCopy(u32);
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for PackedCopy {
     #[inline]
     fn clone(&self) -> PackedCopy {
@@ -435,10 +402,8 @@ impl ::core::clone::Clone for PackedCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::marker::Copy for PackedCopy { }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for PackedCopy {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy",
@@ -446,7 +411,6 @@ impl ::core::fmt::Debug for PackedCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::default::Default for PackedCopy {
     #[inline]
     fn default() -> PackedCopy {
@@ -454,7 +418,6 @@ impl ::core::default::Default for PackedCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for PackedCopy {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         ::core::hash::Hash::hash(&{ self.0 }, state)
@@ -462,7 +425,6 @@ impl ::core::hash::Hash for PackedCopy {
 }
 impl ::core::marker::StructuralPartialEq for PackedCopy {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for PackedCopy {
     #[inline]
     fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } }
@@ -471,7 +433,6 @@ impl ::core::cmp::PartialEq for PackedCopy {
 }
 impl ::core::marker::StructuralEq for PackedCopy {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for PackedCopy {
     #[inline]
     #[doc(hidden)]
@@ -481,7 +442,6 @@ impl ::core::cmp::Eq for PackedCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for PackedCopy {
     #[inline]
     fn partial_cmp(&self, other: &PackedCopy)
@@ -490,7 +450,6 @@ impl ::core::cmp::PartialOrd for PackedCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for PackedCopy {
     #[inline]
     fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering {
@@ -506,7 +465,6 @@ impl ::core::cmp::Ord for PackedCopy {
 #[repr(packed)]
 struct PackedNonCopy(u8);
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for PackedNonCopy {
     #[inline]
     fn clone(&self) -> PackedNonCopy {
@@ -515,7 +473,6 @@ impl ::core::clone::Clone for PackedNonCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for PackedNonCopy {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         let Self(ref __self_0_0) = *self;
@@ -524,7 +481,6 @@ impl ::core::fmt::Debug for PackedNonCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::default::Default for PackedNonCopy {
     #[inline]
     fn default() -> PackedNonCopy {
@@ -532,7 +488,6 @@ impl ::core::default::Default for PackedNonCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for PackedNonCopy {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         let Self(ref __self_0_0) = *self;
@@ -541,7 +496,6 @@ impl ::core::hash::Hash for PackedNonCopy {
 }
 impl ::core::marker::StructuralPartialEq for PackedNonCopy {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for PackedNonCopy {
     #[inline]
     fn eq(&self, other: &PackedNonCopy) -> bool {
@@ -558,7 +512,6 @@ impl ::core::cmp::PartialEq for PackedNonCopy {
 }
 impl ::core::marker::StructuralEq for PackedNonCopy {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for PackedNonCopy {
     #[inline]
     #[doc(hidden)]
@@ -568,7 +521,6 @@ impl ::core::cmp::Eq for PackedNonCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for PackedNonCopy {
     #[inline]
     fn partial_cmp(&self, other: &PackedNonCopy)
@@ -579,7 +531,6 @@ impl ::core::cmp::PartialOrd for PackedNonCopy {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for PackedNonCopy {
     #[inline]
     fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering {
@@ -592,23 +543,19 @@ impl ::core::cmp::Ord for PackedNonCopy {
 // An empty enum.
 enum Enum0 {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Enum0 {
     #[inline]
     fn clone(&self) -> Enum0 { *self }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::marker::Copy for Enum0 { }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Enum0 {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         unsafe { ::core::intrinsics::unreachable() }
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Enum0 {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         unsafe { ::core::intrinsics::unreachable() }
@@ -616,7 +563,6 @@ impl ::core::hash::Hash for Enum0 {
 }
 impl ::core::marker::StructuralPartialEq for Enum0 {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Enum0 {
     #[inline]
     fn eq(&self, other: &Enum0) -> bool {
@@ -625,7 +571,6 @@ impl ::core::cmp::PartialEq for Enum0 {
 }
 impl ::core::marker::StructuralEq for Enum0 {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Enum0 {
     #[inline]
     #[doc(hidden)]
@@ -633,7 +578,6 @@ impl ::core::cmp::Eq for Enum0 {
     fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Enum0 {
     #[inline]
     fn partial_cmp(&self, other: &Enum0)
@@ -642,7 +586,6 @@ impl ::core::cmp::PartialOrd for Enum0 {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Enum0 {
     #[inline]
     fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering {
@@ -657,7 +600,6 @@ enum Enum1 {
     },
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Enum1 {
     #[inline]
     fn clone(&self) -> Enum1 {
@@ -668,7 +610,6 @@ impl ::core::clone::Clone for Enum1 {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Enum1 {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         match self {
@@ -679,7 +620,6 @@ impl ::core::fmt::Debug for Enum1 {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Enum1 {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         match self {
@@ -690,7 +630,6 @@ impl ::core::hash::Hash for Enum1 {
 }
 impl ::core::marker::StructuralPartialEq for Enum1 {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Enum1 {
     #[inline]
     fn eq(&self, other: &Enum1) -> bool {
@@ -709,7 +648,6 @@ impl ::core::cmp::PartialEq for Enum1 {
 }
 impl ::core::marker::StructuralEq for Enum1 {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Enum1 {
     #[inline]
     #[doc(hidden)]
@@ -719,7 +657,6 @@ impl ::core::cmp::Eq for Enum1 {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Enum1 {
     #[inline]
     fn partial_cmp(&self, other: &Enum1)
@@ -731,7 +668,6 @@ impl ::core::cmp::PartialOrd for Enum1 {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Enum1 {
     #[inline]
     fn cmp(&self, other: &Enum1) -> ::core::cmp::Ordering {
@@ -749,39 +685,33 @@ enum Fieldless1 {
     A,
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Fieldless1 {
     #[inline]
     fn clone(&self) -> Fieldless1 { Fieldless1::A }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Fieldless1 {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         ::core::fmt::Formatter::write_str(f, "A")
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::default::Default for Fieldless1 {
     #[inline]
     fn default() -> Fieldless1 { Self::A }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Fieldless1 {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
 }
 impl ::core::marker::StructuralPartialEq for Fieldless1 {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Fieldless1 {
     #[inline]
     fn eq(&self, other: &Fieldless1) -> bool { true }
 }
 impl ::core::marker::StructuralEq for Fieldless1 {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Fieldless1 {
     #[inline]
     #[doc(hidden)]
@@ -789,7 +719,6 @@ impl ::core::cmp::Eq for Fieldless1 {
     fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Fieldless1 {
     #[inline]
     fn partial_cmp(&self, other: &Fieldless1)
@@ -798,7 +727,6 @@ impl ::core::cmp::PartialOrd for Fieldless1 {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Fieldless1 {
     #[inline]
     fn cmp(&self, other: &Fieldless1) -> ::core::cmp::Ordering {
@@ -815,16 +743,13 @@ enum Fieldless {
     C,
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Fieldless {
     #[inline]
     fn clone(&self) -> Fieldless { *self }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::marker::Copy for Fieldless { }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Fieldless {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         match self {
@@ -835,13 +760,11 @@ impl ::core::fmt::Debug for Fieldless {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::default::Default for Fieldless {
     #[inline]
     fn default() -> Fieldless { Self::A }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Fieldless {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         let __self_tag = ::core::intrinsics::discriminant_value(self);
@@ -850,7 +773,6 @@ impl ::core::hash::Hash for Fieldless {
 }
 impl ::core::marker::StructuralPartialEq for Fieldless {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Fieldless {
     #[inline]
     fn eq(&self, other: &Fieldless) -> bool {
@@ -861,7 +783,6 @@ impl ::core::cmp::PartialEq for Fieldless {
 }
 impl ::core::marker::StructuralEq for Fieldless {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Fieldless {
     #[inline]
     #[doc(hidden)]
@@ -869,7 +790,6 @@ impl ::core::cmp::Eq for Fieldless {
     fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Fieldless {
     #[inline]
     fn partial_cmp(&self, other: &Fieldless)
@@ -880,7 +800,6 @@ impl ::core::cmp::PartialOrd for Fieldless {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Fieldless {
     #[inline]
     fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering {
@@ -903,7 +822,6 @@ enum Mixed {
     },
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Mixed {
     #[inline]
     fn clone(&self) -> Mixed {
@@ -912,10 +830,8 @@ impl ::core::clone::Clone for Mixed {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::marker::Copy for Mixed { }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Mixed {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         match self {
@@ -931,13 +847,11 @@ impl ::core::fmt::Debug for Mixed {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::default::Default for Mixed {
     #[inline]
     fn default() -> Mixed { Self::P }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Mixed {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         let __self_tag = ::core::intrinsics::discriminant_value(self);
@@ -954,7 +868,6 @@ impl ::core::hash::Hash for Mixed {
 }
 impl ::core::marker::StructuralPartialEq for Mixed {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Mixed {
     #[inline]
     fn eq(&self, other: &Mixed) -> bool {
@@ -987,7 +900,6 @@ impl ::core::cmp::PartialEq for Mixed {
 }
 impl ::core::marker::StructuralEq for Mixed {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Mixed {
     #[inline]
     #[doc(hidden)]
@@ -997,7 +909,6 @@ impl ::core::cmp::Eq for Mixed {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Mixed {
     #[inline]
     fn partial_cmp(&self, other: &Mixed)
@@ -1025,7 +936,6 @@ impl ::core::cmp::PartialOrd for Mixed {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Mixed {
     #[inline]
     fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering {
@@ -1054,7 +964,6 @@ impl ::core::cmp::Ord for Mixed {
 // for this enum.
 enum Fielded { X(u32), Y(bool), Z(Option<i32>), }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Fielded {
     #[inline]
     fn clone(&self) -> Fielded {
@@ -1069,7 +978,6 @@ impl ::core::clone::Clone for Fielded {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Fielded {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         match self {
@@ -1086,7 +994,6 @@ impl ::core::fmt::Debug for Fielded {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::hash::Hash for Fielded {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
         let __self_tag = ::core::intrinsics::discriminant_value(self);
@@ -1100,7 +1007,6 @@ impl ::core::hash::Hash for Fielded {
 }
 impl ::core::marker::StructuralPartialEq for Fielded {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Fielded {
     #[inline]
     fn eq(&self, other: &Fielded) -> bool {
@@ -1135,7 +1041,6 @@ impl ::core::cmp::PartialEq for Fielded {
 }
 impl ::core::marker::StructuralEq for Fielded {}
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Eq for Fielded {
     #[inline]
     #[doc(hidden)]
@@ -1147,7 +1052,6 @@ impl ::core::cmp::Eq for Fielded {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::PartialOrd for Fielded {
     #[inline]
     fn partial_cmp(&self, other: &Fielded)
@@ -1170,7 +1074,6 @@ impl ::core::cmp::PartialOrd for Fielded {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::cmp::Ord for Fielded {
     #[inline]
     fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering {
@@ -1199,7 +1102,6 @@ pub union Union {
     pub i: i32,
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::clone::Clone for Union {
     #[inline]
     fn clone(&self) -> Union {
@@ -1208,5 +1110,4 @@ impl ::core::clone::Clone for Union {
     }
 }
 #[automatically_derived]
-#[allow(unused_qualifications)]
 impl ::core::marker::Copy for Union { }
diff --git a/src/test/ui/dropck/reject-specialized-drops-8142.stderr b/src/test/ui/dropck/reject-specialized-drops-8142.stderr
index ebd484b8800..cb48221c67a 100644
--- a/src/test/ui/dropck/reject-specialized-drops-8142.stderr
+++ b/src/test/ui/dropck/reject-specialized-drops-8142.stderr
@@ -104,7 +104,7 @@ error[E0366]: `Drop` impls cannot be specialized
 LL | impl              Drop for X<3>           { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `3_usize` is not a generic parameter
+   = note: `3` is not a generic parameter
 note: use the same sequence of generic lifetime, type and const parameters as the struct definition
   --> $DIR/reject-specialized-drops-8142.rs:17:1
    |
diff --git a/src/test/ui/extern-flag/empty-extern-arg.stderr b/src/test/ui/extern-flag/empty-extern-arg.stderr
index 39a66c08de0..54b5e66fc21 100644
--- a/src/test/ui/extern-flag/empty-extern-arg.stderr
+++ b/src/test/ui/extern-flag/empty-extern-arg.stderr
@@ -1,11 +1,11 @@
 error: extern location for std does not exist: 
 
+error: `#[panic_handler]` function required, but not found
+
 error: language item required, but not found: `eh_personality`
    |
    = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library
    = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config`
 
-error: `#[panic_handler]` function required, but not found
-
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/fmt/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs
index b3e54ed32aa..84f4cc7f4cc 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.rs
+++ b/src/test/ui/fmt/ifmt-bad-arg.rs
@@ -86,6 +86,9 @@ tenth number: {}",
     println!("{:foo}", 1); //~ ERROR unknown format trait `foo`
     println!("{5} {:4$} {6:7$}", 1);
     //~^ ERROR invalid reference to positional arguments 4, 5, 6 and 7 (there is 1 argument)
+    let foo = 1;
+    println!("{foo:0$}");
+    //~^ ERROR invalid reference to positional argument 0 (no arguments were given)
 
     // We used to ICE here because we tried to unconditionally access the first argument, which
     // doesn't exist.
diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr
index d181fe14107..5439ee17398 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.stderr
+++ b/src/test/ui/fmt/ifmt-bad-arg.stderr
@@ -251,8 +251,19 @@ LL |     println!("{5} {:4$} {6:7$}", 1);
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
+error: invalid reference to positional argument 0 (no arguments were given)
+  --> $DIR/ifmt-bad-arg.rs:90:15
+   |
+LL |     println!("{foo:0$}");
+   |               ^^^^^--^
+   |                    |
+   |                    this width flag expects an `usize` argument at position 0, but no arguments were given
+   |
+   = note: positional arguments are zero-based
+   = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
+
 error: 2 positional arguments in format string, but no arguments were given
-  --> $DIR/ifmt-bad-arg.rs:92:15
+  --> $DIR/ifmt-bad-arg.rs:95:15
    |
 LL |     println!("{:.*}");
    |               ^^--^
@@ -328,7 +339,7 @@ LL |     pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
    |            ^^^^^^^^^^
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 36 previous errors
+error: aborting due to 37 previous errors
 
 Some errors have detailed explanations: E0308, E0425.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generator/issue-52304.rs b/src/test/ui/generator/issue-52304.rs
new file mode 100644
index 00000000000..3e9de765b12
--- /dev/null
+++ b/src/test/ui/generator/issue-52304.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+pub fn example() -> impl Generator {
+    || yield &1
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-99073-2.rs b/src/test/ui/impl-trait/issue-99073-2.rs
new file mode 100644
index 00000000000..bebd8286de9
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-99073-2.rs
@@ -0,0 +1,17 @@
+use std::fmt::Display;
+
+fn main() {
+    test("hi", true);
+}
+
+fn test<T: Display>(t: T, recurse: bool) -> impl Display {
+    let f = || {
+        let i: u32 = test::<i32>(-1, false);
+        //~^ ERROR mismatched types
+        println!("{i}");
+    };
+    if recurse {
+        f();
+    }
+    t
+}
diff --git a/src/test/ui/impl-trait/issue-99073-2.stderr b/src/test/ui/impl-trait/issue-99073-2.stderr
new file mode 100644
index 00000000000..c1e4b823c08
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-99073-2.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-99073-2.rs:9:22
+   |
+LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display {
+   |                                             ------------ the expected opaque type
+LL |     let f = || {
+LL |         let i: u32 = test::<i32>(-1, false);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |
+   = note: expected opaque type `impl std::fmt::Display`
+                     found type `u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/issue-99073.rs b/src/test/ui/impl-trait/issue-99073.rs
new file mode 100644
index 00000000000..1d75f608666
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-99073.rs
@@ -0,0 +1,8 @@
+fn main() {
+    let _ = fix(|_: &dyn Fn()| {});
+}
+
+fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
+    move || f(fix(&f))
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/impl-trait/issue-99073.stderr b/src/test/ui/impl-trait/issue-99073.stderr
new file mode 100644
index 00000000000..b35d58093d5
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-99073.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-99073.rs:6:13
+   |
+LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
+   |                                    --------- the expected opaque type
+LL |     move || f(fix(&f))
+   |             ^^^^^^^^^^ types differ
+   |
+   = note: expected opaque type `impl Fn()`
+           found type parameter `G`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs b/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs
index d29a82f76a7..b05579f2166 100644
--- a/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs
+++ b/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.rs
@@ -6,7 +6,7 @@ type Tait = impl Sized;
 
 impl Foo for Concrete {
     type Item = Concrete;
-    //~^ mismatched types
+    //~^ type mismatch resolving
 }
 
 impl Bar for Concrete {
diff --git a/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr b/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr
index a25f0cd8761..f0dceb1b11a 100644
--- a/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr
+++ b/src/test/ui/impl-trait/issues/issue-99348-impl-compatibility.stderr
@@ -1,15 +1,25 @@
-error[E0308]: mismatched types
+error[E0271]: type mismatch resolving `<Concrete as Bar>::Other == Concrete`
   --> $DIR/issue-99348-impl-compatibility.rs:8:17
    |
 LL | type Tait = impl Sized;
-   |             ---------- the expected opaque type
+   |             ---------- the found opaque type
 ...
 LL |     type Item = Concrete;
-   |                 ^^^^^^^^ types differ
+   |                 ^^^^^^^^ type mismatch resolving `<Concrete as Bar>::Other == Concrete`
    |
-   = note: expected opaque type `Tait`
-                   found struct `Concrete`
+note: expected this to be `Concrete`
+  --> $DIR/issue-99348-impl-compatibility.rs:13:18
+   |
+LL |     type Other = Tait;
+   |                  ^^^^
+   = note:   expected struct `Concrete`
+           found opaque type `Tait`
+note: required by a bound in `Foo::Item`
+  --> $DIR/issue-99348-impl-compatibility.rs:17:20
+   |
+LL |     type Item: Bar<Other = Self>;
+   |                    ^^^^^^^^^^^^ required by this bound in `Foo::Item`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr
index 479b451855d..2eea726a19c 100644
--- a/src/test/ui/impl-trait/negative-reasoning.stderr
+++ b/src/test/ui/impl-trait/negative-reasoning.stderr
@@ -7,7 +7,7 @@ LL | impl<T: std::fmt::Debug> AnotherTrait for T {}
 LL | impl AnotherTrait for D<OpaqueType> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
    |
-   = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
+   = note: downstream crates may implement trait `std::fmt::Debug` for type `OpaqueType`
 
 error: cannot implement trait on type alias impl trait
   --> $DIR/negative-reasoning.rs:19:25
diff --git a/src/test/ui/inference/deref-suggestion.rs b/src/test/ui/inference/deref-suggestion.rs
index 4fd695585ba..0d8e7289dc8 100644
--- a/src/test/ui/inference/deref-suggestion.rs
+++ b/src/test/ui/inference/deref-suggestion.rs
@@ -1,5 +1,5 @@
 macro_rules! borrow {
-    ($x:expr) => { &$x } //~ ERROR mismatched types
+    ($x:expr) => { &$x }
 }
 
 fn foo(_: String) {}
@@ -32,6 +32,7 @@ fn main() {
     foo(&mut "aaa".to_owned());
     //~^ ERROR mismatched types
     foo3(borrow!(0));
+    //~^ ERROR mismatched types
     foo4(&0);
     assert_eq!(3i32, &3i32);
     //~^ ERROR mismatched types
diff --git a/src/test/ui/inference/deref-suggestion.stderr b/src/test/ui/inference/deref-suggestion.stderr
index e763e17e517..d729f2d682a 100644
--- a/src/test/ui/inference/deref-suggestion.stderr
+++ b/src/test/ui/inference/deref-suggestion.stderr
@@ -70,13 +70,10 @@ LL +     foo("aaa".to_owned());
    |
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:2:20
+  --> $DIR/deref-suggestion.rs:34:10
    |
-LL |     ($x:expr) => { &$x }
-   |                    ^^^ expected `u32`, found `&{integer}`
-...
 LL |     foo3(borrow!(0));
-   |     ---- ---------- in this macro invocation
+   |     ---- ^^^^^^^^^^ expected `u32`, found `&{integer}`
    |     |
    |     arguments to this function are incorrect
    |
@@ -85,10 +82,9 @@ note: function defined here
    |
 LL | fn foo3(_: u32) {}
    |    ^^^^ ------
-   = note: this error originates in the macro `borrow` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:36:5
+  --> $DIR/deref-suggestion.rs:37:5
    |
 LL |     assert_eq!(3i32, &3i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `&i32`
@@ -96,7 +92,7 @@ LL |     assert_eq!(3i32, &3i32);
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:39:17
+  --> $DIR/deref-suggestion.rs:40:17
    |
 LL |     let s = S { u };
    |                 ^
@@ -105,7 +101,7 @@ LL |     let s = S { u };
    |                 help: consider borrowing here: `u: &u`
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:41:20
+  --> $DIR/deref-suggestion.rs:42:20
    |
 LL |     let s = S { u: u };
    |                    ^
@@ -114,7 +110,7 @@ LL |     let s = S { u: u };
    |                    help: consider borrowing here: `&u`
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:44:17
+  --> $DIR/deref-suggestion.rs:45:17
    |
 LL |     let r = R { i };
    |                 ^ expected `u32`, found `&{integer}`
@@ -125,7 +121,7 @@ LL |     let r = R { i: *i };
    |                 ++++
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:46:20
+  --> $DIR/deref-suggestion.rs:47:20
    |
 LL |     let r = R { i: i };
    |                    ^ expected `u32`, found `&{integer}`
@@ -136,7 +132,7 @@ LL |     let r = R { i: *i };
    |                    +
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:55:9
+  --> $DIR/deref-suggestion.rs:56:9
    |
 LL |         b
    |         ^ expected `i32`, found `&{integer}`
@@ -147,7 +143,7 @@ LL |         *b
    |         +
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:63:9
+  --> $DIR/deref-suggestion.rs:64:9
    |
 LL |         b
    |         ^ expected `i32`, found `&{integer}`
@@ -158,7 +154,7 @@ LL |         *b
    |         +
 
 error[E0308]: `if` and `else` have incompatible types
-  --> $DIR/deref-suggestion.rs:68:12
+  --> $DIR/deref-suggestion.rs:69:12
    |
 LL |        let val = if true {
    |   _______________-
diff --git a/src/test/ui/inline-const/const-expr-generic-err.stderr b/src/test/ui/inline-const/const-expr-generic-err.stderr
index db0d85a2d4e..fc0b6cc4451 100644
--- a/src/test/ui/inline-const/const-expr-generic-err.stderr
+++ b/src/test/ui/inline-const/const-expr-generic-err.stderr
@@ -12,13 +12,13 @@ note: the above error was encountered while instantiating `fn foo::<i32>`
 LL |     foo::<i32>();
    |     ^^^^^^^^^^^^
 
-error[E0080]: evaluation of `bar::<0_usize>::{constant#0}` failed
+error[E0080]: evaluation of `bar::<0>::{constant#0}` failed
   --> $DIR/const-expr-generic-err.rs:9:13
    |
 LL |     const { N - 1 }
    |             ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
 
-note: the above error was encountered while instantiating `fn bar::<0_usize>`
+note: the above error was encountered while instantiating `fn bar::<0>`
   --> $DIR/const-expr-generic-err.rs:14:5
    |
 LL |     bar::<0>();
diff --git a/src/test/ui/invalid/invalid-no-sanitize.stderr b/src/test/ui/invalid/invalid-no-sanitize.stderr
index 5a92555eb32..d328cafa00b 100644
--- a/src/test/ui/invalid/invalid-no-sanitize.stderr
+++ b/src/test/ui/invalid/invalid-no-sanitize.stderr
@@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize`
 LL | #[no_sanitize(brontosaurus)]
    |               ^^^^^^^^^^^^
    |
-   = note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`
+   = note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-23041.stderr b/src/test/ui/issues/issue-23041.stderr
index 7b9a1634a0d..6592b76a39f 100644
--- a/src/test/ui/issues/issue-23041.stderr
+++ b/src/test/ui/issues/issue-23041.stderr
@@ -4,7 +4,7 @@ error[E0282]: type annotations needed
 LL |     b.downcast_ref::<fn(_)->_>();
    |       ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref`
    |
-help: consider specifying the generic arguments
+help: consider specifying the generic argument
    |
 LL |     b.downcast_ref::<fn(_) -> _>();
    |                   ~~~~~~~~~~~~~~
diff --git a/src/test/ui/issues/issue-24013.stderr b/src/test/ui/issues/issue-24013.stderr
index 863993f4509..995dce552e3 100644
--- a/src/test/ui/issues/issue-24013.stderr
+++ b/src/test/ui/issues/issue-24013.stderr
@@ -4,7 +4,7 @@ error[E0282]: type annotations needed
 LL |     unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
    |             ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap`
    |
-help: consider specifying the generic arguments
+help: consider specifying the generic argument
    |
 LL |     unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
    |                 ~~~~~~~~~~
diff --git a/src/test/ui/issues/issue-59494.stderr b/src/test/ui/issues/issue-59494.stderr
index 8b542bb69de..a9284535e4d 100644
--- a/src/test/ui/issues/issue-59494.stderr
+++ b/src/test/ui/issues/issue-59494.stderr
@@ -7,8 +7,6 @@ LL |     let t8 = t8n(t7, t7p(f, g));
    |              required by a bound introduced by this call
    |
    = help: the trait `Fn<(_,)>` is not implemented for `impl Fn(((_, _), _))`
-   = note: expected a closure with arguments `(((_, _), _),)`
-              found a closure with arguments `(_,)`
 note: required by a bound in `t8n`
   --> $DIR/issue-59494.rs:5:45
    |
diff --git a/src/test/ui/issues/issue-72554.rs b/src/test/ui/issues/issue-72554.rs
index 47aca05d778..7287639c61d 100644
--- a/src/test/ui/issues/issue-72554.rs
+++ b/src/test/ui/issues/issue-72554.rs
@@ -1,10 +1,13 @@
 use std::collections::BTreeSet;
 
 #[derive(Hash)]
-pub enum ElemDerived { //~ ERROR recursive type `ElemDerived` has infinite size
+pub enum ElemDerived {
+    //~^ ERROR recursive type `ElemDerived` has infinite size
+    //~| ERROR cycle detected when computing drop-check constraints for `ElemDerived`
     A(ElemDerived)
 }
 
+
 pub enum Elem {
     Derived(ElemDerived)
 }
diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr
index a6e44be636a..3e5adcae133 100644
--- a/src/test/ui/issues/issue-72554.stderr
+++ b/src/test/ui/issues/issue-72554.stderr
@@ -3,6 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size
    |
 LL | pub enum ElemDerived {
    | ^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size
+...
 LL |     A(ElemDerived)
    |       ----------- recursive without indirection
    |
@@ -11,6 +12,20 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ElemDerived
 LL |     A(Box<ElemDerived>)
    |       ++++           +
 
-error: aborting due to previous error
+error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived`
+  --> $DIR/issue-72554.rs:4:1
+   |
+LL | pub enum ElemDerived {
+   | ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again
+note: cycle used when computing drop-check constraints for `Elem`
+  --> $DIR/issue-72554.rs:11:1
+   |
+LL | pub enum Elem {
+   | ^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0072`.
+Some errors have detailed explanations: E0072, E0391.
+For more information about an error, try `rustc --explain E0072`.
diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs
index 1d5d5930731..966d76d148a 100644
--- a/src/test/ui/issues/issue-77919.rs
+++ b/src/test/ui/issues/issue-77919.rs
@@ -1,6 +1,5 @@
 fn main() {
     [1; <Multiply<Five, Five>>::VAL];
-    //~^ ERROR: constant expression depends on a generic parameter
 }
 trait TypeVal<T> {
     const VAL: T;
diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr
index b4c877a2d74..ca256847b1f 100644
--- a/src/test/ui/issues/issue-77919.stderr
+++ b/src/test/ui/issues/issue-77919.stderr
@@ -1,5 +1,5 @@
 error[E0412]: cannot find type `PhantomData` in this scope
-  --> $DIR/issue-77919.rs:10:9
+  --> $DIR/issue-77919.rs:9:9
    |
 LL |     _n: PhantomData,
    |         ^^^^^^^^^^^ not found in this scope
@@ -10,7 +10,7 @@ LL | use std::marker::PhantomData;
    |
 
 error[E0412]: cannot find type `VAL` in this scope
-  --> $DIR/issue-77919.rs:12:63
+  --> $DIR/issue-77919.rs:11:63
    |
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          -                                                    ^^^ not found in this scope
@@ -18,7 +18,7 @@ LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          help: you might be missing a type parameter: `, VAL`
 
 error[E0046]: not all trait items implemented, missing: `VAL`
-  --> $DIR/issue-77919.rs:12:1
+  --> $DIR/issue-77919.rs:11:1
    |
 LL |     const VAL: T;
    |     ------------ `VAL` from trait
@@ -26,15 +26,7 @@ LL |     const VAL: T;
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
 
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-77919.rs:2:9
-   |
-LL |     [1; <Multiply<Five, Five>>::VAL];
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0046, E0412.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr
index 1c61c85368b..025a5008d0f 100644
--- a/src/test/ui/kindck/kindck-copy.stderr
+++ b/src/test/ui/kindck/kindck-copy.stderr
@@ -91,10 +91,10 @@ LL | fn assert_copy<T:Copy>() { }
    |                  ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:42:5
+  --> $DIR/kindck-copy.rs:42:19
    |
 LL |     assert_copy::<Box<dyn Dummy>>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy>`
+   |                   ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy>`
    |
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
@@ -103,10 +103,10 @@ LL | fn assert_copy<T:Copy>() { }
    |                  ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy + Send>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:43:5
+  --> $DIR/kindck-copy.rs:43:19
    |
 LL |     assert_copy::<Box<dyn Dummy + Send>>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy + Send>`
+   |                   ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy + Send>`
    |
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
diff --git a/src/test/ui/lint/auxiliary/add-impl.rs b/src/test/ui/lint/auxiliary/add-impl.rs
new file mode 100644
index 00000000000..9d0e3068aed
--- /dev/null
+++ b/src/test/ui/lint/auxiliary/add-impl.rs
@@ -0,0 +1,22 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(AddImpl)]
+// Unnecessary qualification `bar::foo`
+// https://github.com/rust-lang/rust/issues/71898
+pub fn derive(input: TokenStream) -> TokenStream {
+    "impl B {
+            fn foo(&self) { use bar::foo; bar::foo() }
+        }
+
+        fn foo() {}
+
+        mod bar { pub fn foo() {} }
+    ".parse().unwrap()
+}
diff --git a/src/test/ui/lint/function-item-references.stderr b/src/test/ui/lint/function-item-references.stderr
index 33db687df31..a9d18bb6a47 100644
--- a/src/test/ui/lint/function-item-references.stderr
+++ b/src/test/ui/lint/function-item-references.stderr
@@ -116,7 +116,7 @@ warning: taking a reference to a function item does not give a function pointer
   --> $DIR/function-item-references.rs:118:22
    |
 LL |     println!("{:p}", &take_generic_array::<u32, 4>);
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `take_generic_array` to obtain a function pointer: `take_generic_array::<u32, 4_usize> as fn(_)`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `take_generic_array` to obtain a function pointer: `take_generic_array::<u32, 4> as fn(_)`
 
 warning: taking a reference to a function item does not give a function pointer
   --> $DIR/function-item-references.rs:120:22
@@ -128,7 +128,7 @@ warning: taking a reference to a function item does not give a function pointer
   --> $DIR/function-item-references.rs:122:22
    |
 LL |     println!("{:p}", &multiple_generic_arrays::<u32, f32, 4, 8>);
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `multiple_generic_arrays` to obtain a function pointer: `multiple_generic_arrays::<u32, f32, 4_usize, 8_usize> as fn(_, _)`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `multiple_generic_arrays` to obtain a function pointer: `multiple_generic_arrays::<u32, f32, 4, 8> as fn(_, _)`
 
 warning: taking a reference to a function item does not give a function pointer
   --> $DIR/function-item-references.rs:124:22
diff --git a/src/test/ui/lint/unused-qualification-in-derive-expansion.rs b/src/test/ui/lint/unused-qualification-in-derive-expansion.rs
new file mode 100644
index 00000000000..c2efbf507fe
--- /dev/null
+++ b/src/test/ui/lint/unused-qualification-in-derive-expansion.rs
@@ -0,0 +1,16 @@
+// run-pass
+// aux-build:add-impl.rs
+
+#![forbid(unused_qualifications)]
+
+#[macro_use]
+extern crate add_impl;
+
+#[derive(AddImpl)]
+struct B;
+
+fn main() {
+    B.foo();
+    foo();
+    bar::foo();
+}
diff --git a/src/test/ui/macros/meta-variable-depth-outside-repeat.rs b/src/test/ui/macros/meta-variable-depth-outside-repeat.rs
new file mode 100644
index 00000000000..b7fb947854f
--- /dev/null
+++ b/src/test/ui/macros/meta-variable-depth-outside-repeat.rs
@@ -0,0 +1,12 @@
+#![feature(macro_metavar_expr)]
+
+macro_rules! metavar {
+    ( $i:expr ) => {
+        ${length(0)}
+        //~^ ERROR meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+    };
+}
+
+const _: i32 = metavar!(0);
+
+fn main() {}
diff --git a/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr b/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr
new file mode 100644
index 00000000000..fad150cadfc
--- /dev/null
+++ b/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr
@@ -0,0 +1,8 @@
+error: meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+  --> $DIR/meta-variable-depth-outside-repeat.rs:5:10
+   |
+LL |         ${length(0)}
+   |          ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
index d81c8628bab..6a0d68bd6b1 100644
--- a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
@@ -5,7 +5,7 @@ macro_rules! a {
         (
             ${count(foo, 0)},
             ${count(foo, 10)},
-            //~^ ERROR count depth must be less than 4
+            //~^ ERROR depth parameter on meta-variable expression `count` must be less than 4
         )
     };
 }
@@ -17,7 +17,7 @@ macro_rules! b {
                 ${ignore(foo)}
                 ${index(0)},
                 ${index(10)},
-                //~^ ERROR index depth must be less than 3
+                //~^ ERROR depth parameter on meta-variable expression `index` must be less than 3
             )* )* )*
         )
     };
@@ -30,15 +30,14 @@ macro_rules! c {
                 ${ignore(foo)}
                 ${length(0)}
                 ${length(10)}
-                //~^ ERROR length depth must be less than 2
+                //~^ ERROR depth parameter on meta-variable expression `length` must be less than 2
             )* )*
         )
     };
 }
 
-
 fn main() {
     a!( { [ (a) ] [ (b c) ] } );
     b!( { [ a b ] } );
-    c!( { a } );
+    c!({ a });
 }
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
index 7474c03c0f9..236122b6465 100644
--- a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
@@ -1,16 +1,16 @@
-error: count depth must be less than 4
+error: depth parameter on meta-variable expression `count` must be less than 4
   --> $DIR/out-of-bounds-arguments.rs:7:14
    |
 LL |             ${count(foo, 10)},
    |              ^^^^^^^^^^^^^^^^
 
-error: index depth must be less than 3
+error: depth parameter on meta-variable expression `index` must be less than 3
   --> $DIR/out-of-bounds-arguments.rs:19:18
    |
 LL |                 ${index(10)},
    |                  ^^^^^^^^^^^
 
-error: length depth must be less than 2
+error: depth parameter on meta-variable expression `length` must be less than 2
   --> $DIR/out-of-bounds-arguments.rs:32:18
    |
 LL |                 ${length(10)}
diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.rs b/src/test/ui/methods/method-not-found-generic-arg-elision.rs
index 3df928b5d80..799ced5e9c4 100644
--- a/src/test/ui/methods/method-not-found-generic-arg-elision.rs
+++ b/src/test/ui/methods/method-not-found-generic-arg-elision.rs
@@ -61,13 +61,13 @@ impl Other {
     fn other(&self) {}
 }
 
-struct Struct<T>{
-    _phatom: PhantomData<T>
+struct Struct<T> {
+    _phatom: PhantomData<T>,
 }
 
 impl<T> Default for Struct<T> {
     fn default() -> Self {
-        Self{ _phatom: PhantomData }
+        Self { _phatom: PhantomData }
     }
 }
 
@@ -76,9 +76,9 @@ impl<T: Clone + Copy + PartialEq + Eq + PartialOrd + Ord> Struct<T> {
 }
 
 fn main() {
-    let point_f64 = Point{ x: 1_f64, y: 1_f64};
+    let point_f64 = Point { x: 1_f64, y: 1_f64 };
     let d = point_f64.distance();
-    let point_i32 = Point{ x: 1_i32, y: 1_i32};
+    let point_i32 = Point { x: 1_i32, y: 1_i32 };
     let d = point_i32.distance();
     //~^ ERROR no method named `distance` found for struct `Point<i32>
     let d = point_i32.other();
@@ -92,9 +92,9 @@ fn main() {
     wrapper.other();
     //~^ ERROR no method named `other` found for struct `Wrapper
     let boolean = true;
-    let wrapper = Wrapper2::<'_, _, 3> {x: &boolean};
+    let wrapper = Wrapper2::<'_, _, 3> { x: &boolean };
     wrapper.method();
-    //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>
+    //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3>
     wrapper.other();
     //~^ ERROR no method named `other` found for struct `Wrapper2
     let a = vec![1, 2, 3];
diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr
index 56e1b5a0f44..fc42d1a4dcd 100644
--- a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr
+++ b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr
@@ -50,14 +50,14 @@ LL | struct Wrapper<T>(T);
 LL |     wrapper.other();
    |             ^^^^^ method not found in `Wrapper<bool>`
 
-error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>` in the current scope
+error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3>` in the current scope
   --> $DIR/method-not-found-generic-arg-elision.rs:96:13
    |
 LL | struct Wrapper2<'a, T, const C: usize> {
    | -------------------------------------- method `method` not found for this struct
 ...
 LL |     wrapper.method();
-   |             ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+   |             ^^^^^^ method not found in `Wrapper2<'_, bool, 3>`
    |
    = note: the method was found for
            - `Wrapper2<'a, i8, C>`
@@ -71,7 +71,7 @@ LL | struct Wrapper2<'a, T, const C: usize> {
    | -------------------------------------- method `other` not found for this struct
 ...
 LL |     wrapper.other();
-   |             ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+   |             ^^^^^ method not found in `Wrapper2<'_, bool, 3>`
 
 error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope
   --> $DIR/method-not-found-generic-arg-elision.rs:101:7
@@ -82,7 +82,7 @@ LL |     a.not_found();
 error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
   --> $DIR/method-not-found-generic-arg-elision.rs:104:7
    |
-LL | struct Struct<T>{
+LL | struct Struct<T> {
    | ---------------- method `method` not found for this struct
 ...
 LL |     s.method();
diff --git a/src/test/ui/not-panic/not-panic-safe.stderr b/src/test/ui/not-panic/not-panic-safe.stderr
index 3e54df12376..2cd51a43998 100644
--- a/src/test/ui/not-panic/not-panic-safe.stderr
+++ b/src/test/ui/not-panic/not-panic-safe.stderr
@@ -1,8 +1,11 @@
 error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary
-  --> $DIR/not-panic-safe.rs:8:5
+  --> $DIR/not-panic-safe.rs:8:14
    |
 LL |     assert::<&mut i32>();
-   |     ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary
+   |              -^^^^^^^
+   |              |
+   |              `&mut i32` may not be safely transferred across an unwind boundary
+   |              help: consider removing the leading `&`-reference
    |
    = help: the trait `UnwindSafe` is not implemented for `&mut i32`
    = note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32`
diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr
index cc25f08e33a..202f3309d03 100644
--- a/src/test/ui/panic-handler/weak-lang-item.stderr
+++ b/src/test/ui/panic-handler/weak-lang-item.stderr
@@ -10,13 +10,13 @@ help: you can use `as` to change the binding name of the import
 LL | extern crate core as other_core;
    |
 
+error: `#[panic_handler]` function required, but not found
+
 error: language item required, but not found: `eh_personality`
    |
    = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library
    = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config`
 
-error: `#[panic_handler]` function required, but not found
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0259`.
diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
index c2954868f78..8ff14fb1f30 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -27,7 +27,7 @@ fn main() {
     struct Y;
     impl X for Y {
         async fn ft1() {} //~ ERROR functions in traits cannot be declared `async`
-        //~^ ERROR impl has stricter requirements than trait
+        //~^ ERROR has an incompatible type for trait
         unsafe fn ft2() {} // OK.
         const fn ft3() {} //~ ERROR functions in traits cannot be declared const
         extern "C" fn ft4() {}
@@ -36,7 +36,7 @@ fn main() {
         //~| ERROR functions in traits cannot be declared const
         //~| ERROR functions cannot be both `const` and `async`
         //~| ERROR cycle detected
-        //~| ERROR impl has stricter requirements than trait
+        //~| ERROR has an incompatible type for trait
     }
 
     impl Y {
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index 75d27c614e2..bc51ba8b8c5 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -216,23 +216,41 @@ LL | |     }
 LL | | }
    | |_^
 
-error[E0276]: impl has stricter requirements than trait
-  --> $DIR/fn-header-semantic-fail.rs:29:9
+error[E0053]: method `ft1` has an incompatible type for trait
+  --> $DIR/fn-header-semantic-fail.rs:29:24
    |
-LL |         async fn ft1();
-   |         --------------- definition of `ft1` from trait
-...
 LL |         async fn ft1() {}
-   |         ^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+   |                        ^
+   |                        |
+   |                        checked the `Output` of this `async fn`, found opaque type
+   |                        expected `()`, found opaque type
+   |
+   = note: while checking the return type of the `async fn`
+note: type in trait
+  --> $DIR/fn-header-semantic-fail.rs:17:23
+   |
+LL |         async fn ft1();
+   |                       ^
+   = note: expected fn pointer `fn()`
+              found fn pointer `fn() -> impl Future<Output = ()>`
 
-error[E0276]: impl has stricter requirements than trait
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+error[E0053]: method `ft5` has an incompatible type for trait
+  --> $DIR/fn-header-semantic-fail.rs:34:48
    |
-LL |         const async unsafe extern "C" fn ft5();
-   |         --------------------------------------- definition of `ft5` from trait
-...
 LL |         const async unsafe extern "C" fn ft5() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+   |                                                ^
+   |                                                |
+   |                                                checked the `Output` of this `async fn`, found opaque type
+   |                                                expected `()`, found opaque type
+   |
+   = note: while checking the return type of the `async fn`
+note: type in trait
+  --> $DIR/fn-header-semantic-fail.rs:21:47
+   |
+LL |         const async unsafe extern "C" fn ft5();
+   |                                               ^
+   = note: expected fn pointer `unsafe extern "C" fn()`
+              found fn pointer `unsafe extern "C" fn() -> impl Future<Output = ()>`
 
 error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`
   --> $DIR/fn-header-semantic-fail.rs:34:48
@@ -308,5 +326,5 @@ LL | | }
 
 error: aborting due to 23 previous errors
 
-Some errors have detailed explanations: E0276, E0379, E0391, E0706.
-For more information about an error, try `rustc --explain E0276`.
+Some errors have detailed explanations: E0053, E0379, E0391, E0706.
+For more information about an error, try `rustc --explain E0053`.
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
index 6facc467f7a..aaf0f7eaef0 100644
--- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
@@ -14,7 +14,7 @@ trait B {
 impl B for A {
     async fn associated(); //~ ERROR without body
     //~^ ERROR cannot be declared `async`
-    //~| ERROR impl has stricter requirements than trait
+    //~| ERROR has an incompatible type for trait
 }
 
 fn main() {}
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
index c144060a859..d3214458eac 100644
--- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
@@ -44,16 +44,25 @@ LL |     async fn associated();
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
-error[E0276]: impl has stricter requirements than trait
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
+error[E0053]: method `associated` has an incompatible type for trait
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26
    |
 LL |     async fn associated();
-   |     ---------------------- definition of `associated` from trait
-...
+   |                          ^
+   |                          |
+   |                          checked the `Output` of this `async fn`, found opaque type
+   |                          expected `()`, found opaque type
+   |
+   = note: while checking the return type of the `async fn`
+note: type in trait
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:26
+   |
 LL |     async fn associated();
-   |     ^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+   |                          ^
+   = note: expected fn pointer `fn()`
+              found fn pointer `fn() -> impl Future<Output = ()>`
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0276, E0706.
-For more information about an error, try `rustc --explain E0276`.
+Some errors have detailed explanations: E0053, E0706.
+For more information about an error, try `rustc --explain E0053`.
diff --git a/src/test/ui/simd/intrinsic/generic-shuffle.stderr b/src/test/ui/simd/intrinsic/generic-shuffle.stderr
index 44c57cd7c47..81e641612ce 100644
--- a/src/test/ui/simd/intrinsic/generic-shuffle.stderr
+++ b/src/test/ui/simd/intrinsic/generic-shuffle.stderr
@@ -1,10 +1,10 @@
-error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd<u32, 4_usize>` with length 4
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd<u32, 4>` with length 4
   --> $DIR/generic-shuffle.rs:24:31
    |
 LL |         let _: Simd<u32, 4> = simd_shuffle(v, v, I);
    |                               ^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd<u32, 4_usize>`), found `Simd<f32, 2_usize>` with element type `f32`
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd<u32, 4>`), found `Simd<f32, 2>` with element type `f32`
   --> $DIR/generic-shuffle.rs:27:31
    |
 LL |         let _: Simd<f32, 2> = simd_shuffle(v, v, I);
diff --git a/src/test/ui/simd/libm_no_std_cant_float.rs b/src/test/ui/simd/libm_no_std_cant_float.rs
index abe460a326b..50ac8e20839 100644
--- a/src/test/ui/simd/libm_no_std_cant_float.rs
+++ b/src/test/ui/simd/libm_no_std_cant_float.rs
@@ -2,6 +2,7 @@
 #![no_std]
 #![feature(portable_simd)]
 use core::simd::f32x4;
+use core::simd::SimdFloat;
 
 // For SIMD float ops, the LLIR version which is used to implement the portable
 // forms of them may become calls to math.h AKA libm. So, we can't guarantee
diff --git a/src/test/ui/simd/libm_no_std_cant_float.stderr b/src/test/ui/simd/libm_no_std_cant_float.stderr
index dc8638f6ab7..97e0b7efe2a 100644
--- a/src/test/ui/simd/libm_no_std_cant_float.stderr
+++ b/src/test/ui/simd/libm_no_std_cant_float.stderr
@@ -1,38 +1,38 @@
 error[E0599]: no method named `ceil` found for struct `Simd` in the current scope
-  --> $DIR/libm_no_std_cant_float.rs:14:17
+  --> $DIR/libm_no_std_cant_float.rs:15:17
    |
 LL |     let _xc = x.ceil();
-   |                 ^^^^ method not found in `Simd<f32, 4_usize>`
+   |                 ^^^^ method not found in `Simd<f32, 4>`
 
 error[E0599]: no method named `floor` found for struct `Simd` in the current scope
-  --> $DIR/libm_no_std_cant_float.rs:15:17
+  --> $DIR/libm_no_std_cant_float.rs:16:17
    |
 LL |     let _xf = x.floor();
-   |                 ^^^^^ method not found in `Simd<f32, 4_usize>`
+   |                 ^^^^^ method not found in `Simd<f32, 4>`
 
 error[E0599]: no method named `round` found for struct `Simd` in the current scope
-  --> $DIR/libm_no_std_cant_float.rs:16:17
+  --> $DIR/libm_no_std_cant_float.rs:17:17
    |
 LL |     let _xr = x.round();
-   |                 ^^^^^ method not found in `Simd<f32, 4_usize>`
+   |                 ^^^^^ method not found in `Simd<f32, 4>`
 
 error[E0599]: no method named `trunc` found for struct `Simd` in the current scope
-  --> $DIR/libm_no_std_cant_float.rs:17:17
+  --> $DIR/libm_no_std_cant_float.rs:18:17
    |
 LL |     let _xt = x.trunc();
-   |                 ^^^^^ method not found in `Simd<f32, 4_usize>`
+   |                 ^^^^^ method not found in `Simd<f32, 4>`
 
 error[E0599]: no method named `mul_add` found for struct `Simd` in the current scope
-  --> $DIR/libm_no_std_cant_float.rs:18:19
+  --> $DIR/libm_no_std_cant_float.rs:19:19
    |
 LL |     let _xfma = x.mul_add(x, x);
-   |                   ^^^^^^^ method not found in `Simd<f32, 4_usize>`
+   |                   ^^^^^^^ method not found in `Simd<f32, 4>`
 
 error[E0599]: no method named `sqrt` found for struct `Simd` in the current scope
-  --> $DIR/libm_no_std_cant_float.rs:19:20
+  --> $DIR/libm_no_std_cant_float.rs:20:20
    |
 LL |     let _xsqrt = x.sqrt();
-   |                    ^^^^ method not found in `Simd<f32, 4_usize>`
+   |                    ^^^^ method not found in `Simd<f32, 4>`
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/simd/libm_std_can_float.rs b/src/test/ui/simd/libm_std_can_float.rs
index 6a844e7120e..1c520856e98 100644
--- a/src/test/ui/simd/libm_std_can_float.rs
+++ b/src/test/ui/simd/libm_std_can_float.rs
@@ -3,7 +3,7 @@
 // This is the converse of the other libm test.
 #![feature(portable_simd)]
 use std::simd::f32x4;
-use std::simd::StdFloat;
+use std::simd::{SimdFloat, StdFloat};
 
 // For SIMD float ops, the LLIR version which is used to implement the portable
 // forms of them may become calls to math.h AKA libm. So, we can't guarantee
diff --git a/src/test/ui/simd/type-generic-monomorphisation-empty.rs b/src/test/ui/simd/type-generic-monomorphisation-empty.rs
index 0121404c749..2bf6641e9c9 100644
--- a/src/test/ui/simd/type-generic-monomorphisation-empty.rs
+++ b/src/test/ui/simd/type-generic-monomorphisation-empty.rs
@@ -2,7 +2,7 @@
 
 #![feature(repr_simd, platform_intrinsics)]
 
-// error-pattern:monomorphising SIMD type `Simd<0_usize>` of zero length
+// error-pattern:monomorphising SIMD type `Simd<0>` of zero length
 
 #[repr(simd)]
 struct Simd<const N: usize>([f32; N]);
diff --git a/src/test/ui/simd/type-generic-monomorphisation-empty.stderr b/src/test/ui/simd/type-generic-monomorphisation-empty.stderr
index 00fde199b12..b334b1f4b58 100644
--- a/src/test/ui/simd/type-generic-monomorphisation-empty.stderr
+++ b/src/test/ui/simd/type-generic-monomorphisation-empty.stderr
@@ -1,4 +1,4 @@
-error: monomorphising SIMD type `Simd<0_usize>` of zero length
+error: monomorphising SIMD type `Simd<0>` of zero length
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/simd/type-generic-monomorphisation-oversized.rs b/src/test/ui/simd/type-generic-monomorphisation-oversized.rs
index bd0d457b35e..a7dc482f3cb 100644
--- a/src/test/ui/simd/type-generic-monomorphisation-oversized.rs
+++ b/src/test/ui/simd/type-generic-monomorphisation-oversized.rs
@@ -2,7 +2,7 @@
 
 #![feature(repr_simd, platform_intrinsics)]
 
-// error-pattern:monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768
+// error-pattern:monomorphising SIMD type `Simd<65536>` of length greater than 32768
 
 #[repr(simd)]
 struct Simd<const N: usize>([f32; N]);
diff --git a/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr b/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr
index f4418350115..a2dba1222ee 100644
--- a/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr
+++ b/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr
@@ -1,4 +1,4 @@
-error: monomorphising SIMD type `Simd<65536_usize>` of length greater than 32768
+error: monomorphising SIMD type `Simd<65536>` of length greater than 32768
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs b/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs
new file mode 100644
index 00000000000..468be1bc144
--- /dev/null
+++ b/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs
@@ -0,0 +1,8 @@
+#![feature(staged_api)]
+#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
+
+#[stable(feature = "foo", since = "1.62.0")]
+pub fn foo() {}
+
+#[unstable(feature = "foobar", issue = "1", implied_by = "foo")]
+pub fn foobar() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-missing.rs b/src/test/ui/stability-attribute/stability-attribute-implies-missing.rs
new file mode 100644
index 00000000000..61387853672
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-missing.rs
@@ -0,0 +1,10 @@
+#![feature(staged_api)]
+#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
+
+// Tests that `implied_by = "bar"` results in an error being emitted if `bar` does not exist.
+
+#[unstable(feature = "foobar", issue = "1", implied_by = "bar")]
+//~^ ERROR feature `bar` implying `foobar` does not exist
+pub fn foobar() {}
+
+fn main() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr
new file mode 100644
index 00000000000..ff1856f1763
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr
@@ -0,0 +1,8 @@
+error: feature `bar` implying `foobar` does not exist
+  --> $DIR/stability-attribute-implies-missing.rs:6:1
+   |
+LL | #[unstable(feature = "foobar", issue = "1", implied_by = "bar")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs
new file mode 100644
index 00000000000..947f9f73eff
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs
@@ -0,0 +1,13 @@
+// aux-build:stability-attribute-implies.rs
+
+// Tests that despite the `foobar` feature being implied by now-stable feature `foo`, if `foobar`
+// isn't allowed in this crate then an error will be emitted.
+
+extern crate stability_attribute_implies;
+use stability_attribute_implies::{foo, foobar};
+//~^ ERROR use of unstable library feature 'foobar'
+
+fn main() {
+    foo(); // no error - stable
+    foobar(); //~ ERROR use of unstable library feature 'foobar'
+}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr
new file mode 100644
index 00000000000..c2331f6766c
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr
@@ -0,0 +1,21 @@
+error[E0658]: use of unstable library feature 'foobar'
+  --> $DIR/stability-attribute-implies-no-feature.rs:7:40
+   |
+LL | use stability_attribute_implies::{foo, foobar};
+   |                                        ^^^^^^
+   |
+   = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+   = help: add `#![feature(foobar)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'foobar'
+  --> $DIR/stability-attribute-implies-no-feature.rs:12:5
+   |
+LL |     foobar();
+   |     ^^^^^^
+   |
+   = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+   = help: add `#![feature(foobar)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs
new file mode 100644
index 00000000000..1a2d8e271de
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs
@@ -0,0 +1,15 @@
+// aux-build:stability-attribute-implies.rs
+#![deny(stable_features)]
+#![feature(foo)]
+//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+
+// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic
+// mentioning partial stabilization, and that given the implied unstable feature is unused (there
+// is no `foobar` call), that the compiler suggests removing the flag.
+
+extern crate stability_attribute_implies;
+use stability_attribute_implies::foo;
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr
new file mode 100644
index 00000000000..c9b3f07cc70
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr
@@ -0,0 +1,22 @@
+error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+  --> $DIR/stability-attribute-implies-using-stable.rs:3:12
+   |
+LL | #![feature(foo)]
+   |            ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/stability-attribute-implies-using-stable.rs:2:9
+   |
+LL | #![deny(stable_features)]
+   |         ^^^^^^^^^^^^^^^
+help: if you are using features which are still unstable, change to using `foobar`
+   |
+LL | #![feature(foobar)]
+   |            ~~~~~~
+help: if you are using features which are now stable, remove this line
+   |
+LL - #![feature(foo)]
+   |
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs
new file mode 100644
index 00000000000..3c73c5abf3b
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs
@@ -0,0 +1,17 @@
+// aux-build:stability-attribute-implies.rs
+#![deny(stable_features)]
+#![feature(foo)]
+//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+
+// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic
+// mentioning partial stabilization and that given the implied unstable feature is used (there is a
+// `foobar` call), that the compiler suggests changing to that feature and doesn't error about its
+// use.
+
+extern crate stability_attribute_implies;
+use stability_attribute_implies::{foo, foobar};
+
+fn main() {
+    foo();
+    foobar(); // no error!
+}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr
new file mode 100644
index 00000000000..9a5c7ef5a47
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr
@@ -0,0 +1,22 @@
+error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+  --> $DIR/stability-attribute-implies-using-unstable.rs:3:12
+   |
+LL | #![feature(foo)]
+   |            ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/stability-attribute-implies-using-unstable.rs:2:9
+   |
+LL | #![deny(stable_features)]
+   |         ^^^^^^^^^^^^^^^
+help: if you are using features which are still unstable, change to using `foobar`
+   |
+LL | #![feature(foobar)]
+   |            ~~~~~~
+help: if you are using features which are now stable, remove this line
+   |
+LL - #![feature(foo)]
+   |
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
index bd7b88da158..8dbcc6c97ef 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
@@ -8,7 +8,7 @@ error[E0541]: unknown meta item 'sinse'
   --> $DIR/stability-attribute-sanity-2.rs:10:25
    |
 LL | #[stable(feature = "a", sinse = "1.0.0")]
-   |                         ^^^^^^^^^^^^^^^ expected one of `since`, `note`
+   |                         ^^^^^^^^^^^^^^^ expected one of `feature`, `since`
 
 error[E0545]: `issue` must be a non-zero numeric string or "none"
   --> $DIR/stability-attribute-sanity-2.rs:13:27
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
index fcb1eefddbc..079230b2a31 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -14,7 +14,7 @@ error[E0541]: unknown meta item 'reason'
   --> $DIR/stability-attribute-sanity.rs:8:42
    |
 LL |     #[stable(feature = "a", since = "b", reason)]
-   |                                          ^^^^^^ expected one of `since`, `note`
+   |                                          ^^^^^^ expected one of `feature`, `since`
 
 error[E0539]: incorrect meta item
   --> $DIR/stability-attribute-sanity.rs:11:29
diff --git a/src/test/ui/suggestions/return-bindings.fixed b/src/test/ui/suggestions/return-bindings.fixed
deleted file mode 100644
index 4fabc411abc..00000000000
--- a/src/test/ui/suggestions/return-bindings.fixed
+++ /dev/null
@@ -1,23 +0,0 @@
-// run-rustfix
-
-#![allow(unused)]
-
-fn a(i: i32) -> i32 { i }
-//~^ ERROR mismatched types
-
-fn b(opt_str: Option<String>) {
-    let s: String = if let Some(s) = opt_str {
-        s
-    //~^ ERROR mismatched types
-    } else {
-        String::new()
-    };
-}
-
-fn c() -> Option<i32> {
-    //~^ ERROR mismatched types
-    let x = Some(1);
-    x
-}
-
-fn main() {}
diff --git a/src/test/ui/suggestions/return-bindings.rs b/src/test/ui/suggestions/return-bindings.rs
index d05b4ba27d6..fa1bad37699 100644
--- a/src/test/ui/suggestions/return-bindings.rs
+++ b/src/test/ui/suggestions/return-bindings.rs
@@ -1,5 +1,3 @@
-// run-rustfix
-
 #![allow(unused)]
 
 fn a(i: i32) -> i32 {}
@@ -18,4 +16,36 @@ fn c() -> Option<i32> {
     let x = Some(1);
 }
 
+fn d(opt_str: Option<String>) {
+    let s: String = if let Some(s) = opt_str {
+        //~^ ERROR mismatched types
+    } else {
+        String::new()
+    };
+}
+
+fn d2(opt_str: Option<String>) {
+    let s = if let Some(s) = opt_str {
+    } else {
+        String::new()
+        //~^ ERROR `if` and `else` have incompatible types
+    };
+}
+
+fn e(opt_str: Option<String>) {
+    let s: String = match opt_str {
+        Some(s) => {}
+        //~^ ERROR mismatched types
+        None => String::new(),
+    };
+}
+
+fn e2(opt_str: Option<String>) {
+    let s = match opt_str {
+        Some(s) => {}
+        None => String::new(),
+        //~^ ERROR `match` arms have incompatible types
+    };
+}
+
 fn main() {}
diff --git a/src/test/ui/suggestions/return-bindings.stderr b/src/test/ui/suggestions/return-bindings.stderr
index e5d49255005..c14fb336773 100644
--- a/src/test/ui/suggestions/return-bindings.stderr
+++ b/src/test/ui/suggestions/return-bindings.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/return-bindings.rs:5:17
+  --> $DIR/return-bindings.rs:3:17
    |
 LL | fn a(i: i32) -> i32 {}
    |    -            ^^^ expected `i32`, found `()`
@@ -12,7 +12,7 @@ LL | fn a(i: i32) -> i32 { i }
    |                       +
 
 error[E0308]: mismatched types
-  --> $DIR/return-bindings.rs:9:46
+  --> $DIR/return-bindings.rs:7:46
    |
 LL |       let s: String = if let Some(s) = opt_str {
    |  ______________________________________________^
@@ -28,7 +28,7 @@ LL ~
    |
 
 error[E0308]: mismatched types
-  --> $DIR/return-bindings.rs:16:11
+  --> $DIR/return-bindings.rs:14:11
    |
 LL | fn c() -> Option<i32> {
    |    -      ^^^^^^^^^^^ expected enum `Option`, found `()`
@@ -43,6 +43,68 @@ LL ~     let x = Some(1);
 LL +     x
    |
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/return-bindings.rs:20:46
+   |
+LL |       let s: String = if let Some(s) = opt_str {
+   |  ______________________________________________^
+LL | |
+LL | |     } else {
+   | |_____^ expected struct `String`, found `()`
+   |
+help: consider returning the local binding `s`
+   |
+LL ~     let s: String = if let Some(s) = opt_str {
+LL +         s
+LL ~
+   |
+
+error[E0308]: `if` and `else` have incompatible types
+  --> $DIR/return-bindings.rs:30:9
+   |
+LL |       let s = if let Some(s) = opt_str {
+   |  ______________________________________-
+LL | |     } else {
+   | |_____- expected because of this
+LL |           String::new()
+   |           ^^^^^^^^^^^^^ expected `()`, found struct `String`
+   |
+help: consider returning the local binding `s`
+   |
+LL ~     let s = if let Some(s) = opt_str {
+LL +         s
+LL ~     } else {
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/return-bindings.rs:37:20
+   |
+LL |         Some(s) => {}
+   |                    ^^ expected struct `String`, found `()`
+   |
+help: consider returning the local binding `s`
+   |
+LL |         Some(s) => { s }
+   |                      +
+
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/return-bindings.rs:46:17
+   |
+LL |       let s = match opt_str {
+   |  _____________-
+LL | |         Some(s) => {}
+   | |                    -- this is found to be of type `()`
+LL | |         None => String::new(),
+   | |                 ^^^^^^^^^^^^^ expected `()`, found struct `String`
+LL | |
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+help: consider returning the local binding `s`
+   |
+LL |         Some(s) => { s }
+   |                      +
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/traits/issue-32963.rs b/src/test/ui/traits/issue-32963.rs
index 58055cd5456..56a68f3a231 100644
--- a/src/test/ui/traits/issue-32963.rs
+++ b/src/test/ui/traits/issue-32963.rs
@@ -7,6 +7,5 @@ fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
 fn main() {
     size_of_copy::<dyn Misc + Copy>();
     //~^ ERROR only auto traits can be used as additional traits in a trait object
-    //~| ERROR only auto traits can be used as additional traits in a trait object
     //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied
 }
diff --git a/src/test/ui/traits/issue-32963.stderr b/src/test/ui/traits/issue-32963.stderr
index 5e7762b3220..bad45e54d64 100644
--- a/src/test/ui/traits/issue-32963.stderr
+++ b/src/test/ui/traits/issue-32963.stderr
@@ -9,22 +9,11 @@ LL |     size_of_copy::<dyn Misc + Copy>();
    = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
-error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/issue-32963.rs:8:31
-   |
-LL |     size_of_copy::<dyn Misc + Copy>();
-   |                        ----   ^^^^ additional non-auto trait
-   |                        |
-   |                        first non-auto trait
-   |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
-   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-
 error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied
-  --> $DIR/issue-32963.rs:8:5
+  --> $DIR/issue-32963.rs:8:20
    |
 LL |     size_of_copy::<dyn Misc + Copy>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
+   |                    ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
    |
 note: required by a bound in `size_of_copy`
   --> $DIR/issue-32963.rs:5:20
@@ -32,7 +21,7 @@ note: required by a bound in `size_of_copy`
 LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
    |                    ^^^^ required by this bound in `size_of_copy`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0225, E0277.
 For more information about an error, try `rustc --explain E0225`.
diff --git a/src/test/ui/traits/suggest-where-clause.stderr b/src/test/ui/traits/suggest-where-clause.stderr
index 21b339d12a8..d4d9b496747 100644
--- a/src/test/ui/traits/suggest-where-clause.stderr
+++ b/src/test/ui/traits/suggest-where-clause.stderr
@@ -85,10 +85,10 @@ LL | pub const fn size_of<T>() -> usize {
    |                      ^ required by this bound in `std::mem::size_of`
 
 error[E0277]: the size for values of type `[&U]` cannot be known at compilation time
-  --> $DIR/suggest-where-clause.rs:31:5
+  --> $DIR/suggest-where-clause.rs:31:20
    |
 LL |     mem::size_of::<[&U]>();
-   |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                    ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[&U]`
 note: required by a bound in `std::mem::size_of`
diff --git a/src/test/ui/traits/vtable/vtable-diamond.rs b/src/test/ui/traits/vtable/vtable-diamond.rs
index ec25e8a7071..dc3c17ac314 100644
--- a/src/test/ui/traits/vtable/vtable-diamond.rs
+++ b/src/test/ui/traits/vtable/vtable-diamond.rs
@@ -34,6 +34,11 @@ fn foo(d: &dyn D) {
     d.foo_d();
 }
 
+fn bar(d: &dyn C) {
+    d.foo_c();
+}
+
 fn main() {
     foo(&S);
+    bar(&S);
 }
diff --git a/src/test/ui/traits/vtable/vtable-multi-level.rs b/src/test/ui/traits/vtable/vtable-multi-level.rs
index fcb5fd5274b..ebd55bcf39b 100644
--- a/src/test/ui/traits/vtable/vtable-multi-level.rs
+++ b/src/test/ui/traits/vtable/vtable-multi-level.rs
@@ -12,6 +12,7 @@
 
 #[rustc_dump_vtable]
 trait A {
+    //~^ error vtable
     fn foo_a(&self) {}
 }
 
@@ -23,6 +24,7 @@ trait B {
 
 #[rustc_dump_vtable]
 trait C: A + B {
+    //~^ error vtable
     fn foo_c(&self) {}
 }
 
@@ -115,8 +117,27 @@ impl M for S {}
 impl N for S {}
 impl O for S {}
 
-fn foo(_: &dyn O) {}
+macro_rules! monomorphize_vtable {
+    ($trait:ident) => {{
+        fn foo(_ : &dyn $trait) {}
+        foo(&S);
+    }}
+}
 
 fn main() {
-    foo(&S);
+    monomorphize_vtable!(O);
+
+    monomorphize_vtable!(A);
+    monomorphize_vtable!(B);
+    monomorphize_vtable!(C);
+    monomorphize_vtable!(D);
+    monomorphize_vtable!(E);
+    monomorphize_vtable!(F);
+    monomorphize_vtable!(H);
+    monomorphize_vtable!(I);
+    monomorphize_vtable!(J);
+    monomorphize_vtable!(K);
+    monomorphize_vtable!(L);
+    monomorphize_vtable!(M);
+    monomorphize_vtable!(N);
 }
diff --git a/src/test/ui/traits/vtable/vtable-multi-level.stderr b/src/test/ui/traits/vtable/vtable-multi-level.stderr
index d4d7a8fa3a4..c4389e23fc1 100644
--- a/src/test/ui/traits/vtable/vtable-multi-level.stderr
+++ b/src/test/ui/traits/vtable/vtable-multi-level.stderr
@@ -29,29 +29,54 @@ error: vtable entries for `<S as O>`: [
            TraitVPtr(<S as N>),
            Method(<S as O>::foo_o),
        ]
-  --> $DIR/vtable-multi-level.rs:95:1
+  --> $DIR/vtable-multi-level.rs:97:1
    |
 LL | trait O: G + N {
    | ^^^^^^^^^^^^^^
 
+error: vtable entries for `<S as A>`: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as A>::foo_a),
+       ]
+  --> $DIR/vtable-multi-level.rs:14:1
+   |
+LL | trait A {
+   | ^^^^^^^
+
 error: vtable entries for `<S as B>`: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as B>::foo_b),
        ]
-  --> $DIR/vtable-multi-level.rs:19:1
+  --> $DIR/vtable-multi-level.rs:20:1
    |
 LL | trait B {
    | ^^^^^^^
 
+error: vtable entries for `<S as C>`: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as A>::foo_a),
+           Method(<S as B>::foo_b),
+           TraitVPtr(<S as B>),
+           Method(<S as C>::foo_c),
+       ]
+  --> $DIR/vtable-multi-level.rs:26:1
+   |
+LL | trait C: A + B {
+   | ^^^^^^^^^^^^^^
+
 error: vtable entries for `<S as D>`: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as D>::foo_d),
        ]
-  --> $DIR/vtable-multi-level.rs:30:1
+  --> $DIR/vtable-multi-level.rs:32:1
    |
 LL | trait D {
    | ^^^^^^^
@@ -62,7 +87,7 @@ error: vtable entries for `<S as E>`: [
            MetadataAlign,
            Method(<S as E>::foo_e),
        ]
-  --> $DIR/vtable-multi-level.rs:36:1
+  --> $DIR/vtable-multi-level.rs:38:1
    |
 LL | trait E {
    | ^^^^^^^
@@ -76,7 +101,7 @@ error: vtable entries for `<S as F>`: [
            TraitVPtr(<S as E>),
            Method(<S as F>::foo_f),
        ]
-  --> $DIR/vtable-multi-level.rs:42:1
+  --> $DIR/vtable-multi-level.rs:44:1
    |
 LL | trait F: D + E {
    | ^^^^^^^^^^^^^^
@@ -87,7 +112,7 @@ error: vtable entries for `<S as H>`: [
            MetadataAlign,
            Method(<S as H>::foo_h),
        ]
-  --> $DIR/vtable-multi-level.rs:53:1
+  --> $DIR/vtable-multi-level.rs:55:1
    |
 LL | trait H {
    | ^^^^^^^
@@ -98,7 +123,7 @@ error: vtable entries for `<S as I>`: [
            MetadataAlign,
            Method(<S as I>::foo_i),
        ]
-  --> $DIR/vtable-multi-level.rs:59:1
+  --> $DIR/vtable-multi-level.rs:61:1
    |
 LL | trait I {
    | ^^^^^^^
@@ -112,7 +137,7 @@ error: vtable entries for `<S as J>`: [
            TraitVPtr(<S as I>),
            Method(<S as J>::foo_j),
        ]
-  --> $DIR/vtable-multi-level.rs:65:1
+  --> $DIR/vtable-multi-level.rs:67:1
    |
 LL | trait J: H + I {
    | ^^^^^^^^^^^^^^
@@ -123,7 +148,7 @@ error: vtable entries for `<S as K>`: [
            MetadataAlign,
            Method(<S as K>::foo_k),
        ]
-  --> $DIR/vtable-multi-level.rs:71:1
+  --> $DIR/vtable-multi-level.rs:73:1
    |
 LL | trait K {
    | ^^^^^^^
@@ -134,7 +159,7 @@ error: vtable entries for `<S as L>`: [
            MetadataAlign,
            Method(<S as L>::foo_l),
        ]
-  --> $DIR/vtable-multi-level.rs:77:1
+  --> $DIR/vtable-multi-level.rs:79:1
    |
 LL | trait L {
    | ^^^^^^^
@@ -148,7 +173,7 @@ error: vtable entries for `<S as M>`: [
            TraitVPtr(<S as L>),
            Method(<S as M>::foo_m),
        ]
-  --> $DIR/vtable-multi-level.rs:83:1
+  --> $DIR/vtable-multi-level.rs:85:1
    |
 LL | trait M: K + L {
    | ^^^^^^^^^^^^^^
@@ -169,10 +194,10 @@ error: vtable entries for `<S as N>`: [
            TraitVPtr(<S as M>),
            Method(<S as N>::foo_n),
        ]
-  --> $DIR/vtable-multi-level.rs:89:1
+  --> $DIR/vtable-multi-level.rs:91:1
    |
 LL | trait N: J + M {
    | ^^^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors
+error: aborting due to 14 previous errors
 
diff --git a/src/test/ui/traits/vtable/vtable-multiple.rs b/src/test/ui/traits/vtable/vtable-multiple.rs
index 8e7098a495e..7a0111c5ef2 100644
--- a/src/test/ui/traits/vtable/vtable-multiple.rs
+++ b/src/test/ui/traits/vtable/vtable-multiple.rs
@@ -25,7 +25,9 @@ impl B for S {}
 impl C for S {}
 
 fn foo(c: &dyn C) {}
+fn bar(c: &dyn B) {}
 
 fn main() {
     foo(&S);
+    bar(&S);
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr
index 6c82d31e18d..e7565525ad3 100644
--- a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr
@@ -25,7 +25,7 @@ error: non-defining opaque type use in defining scope
 LL |     7u32
    |     ^^^^
    |
-note: used non-generic constant `123_usize` for generic parameter
+note: used non-generic constant `123` for generic parameter
   --> $DIR/generic_nondefining_use.rs:11:15
    |
 LL | type OneConst<const X: usize> = impl Debug;
diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
index 377ce85e8b2..4a11bb5020e 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
@@ -3,7 +3,7 @@
 type Foo = impl Fn() -> Foo;
 
 fn foo() -> Foo {
-//~^ ERROR: overflow evaluating the requirement `fn() -> Foo {foo}: Sized`
+//~^ ERROR: overflow evaluating the requirement
     foo
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr
index d20b1cc6d85..00c682b2193 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr
@@ -1,10 +1,8 @@
-error[E0275]: overflow evaluating the requirement `fn() -> Foo {foo}: Sized`
+error[E0275]: overflow evaluating the requirement `<fn() -> Foo {foo} as FnOnce<()>>::Output == fn() -> Foo {foo}`
   --> $DIR/issue-53398-cyclic-types.rs:5:13
    |
 LL | fn foo() -> Foo {
    |             ^^^
-   |
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_53398_cyclic_types`)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.rs b/src/test/ui/type-alias-impl-trait/issue-57961.rs
new file mode 100644
index 00000000000..472886c9caa
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-57961.rs
@@ -0,0 +1,18 @@
+#![feature(type_alias_impl_trait)]
+
+type X = impl Sized;
+
+trait Foo {
+    type Bar: Iterator<Item = X>;
+}
+
+impl Foo for () {
+    type Bar = std::vec::IntoIter<u32>;
+    //~^ ERROR type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X
+}
+
+fn incoherent() {
+    let f: X = 22_i32;
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.stderr b/src/test/ui/type-alias-impl-trait/issue-57961.stderr
new file mode 100644
index 00000000000..ed4caf6ce68
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-57961.stderr
@@ -0,0 +1,20 @@
+error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X`
+  --> $DIR/issue-57961.rs:10:16
+   |
+LL | type X = impl Sized;
+   |          ---------- the expected opaque type
+...
+LL |     type Bar = std::vec::IntoIter<u32>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found `u32`
+   |
+   = note: expected opaque type `X`
+                     found type `u32`
+note: required by a bound in `Foo::Bar`
+  --> $DIR/issue-57961.rs:6:24
+   |
+LL |     type Bar: Iterator<Item = X>;
+   |                        ^^^^^^^^ required by this bound in `Foo::Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
index 7aefa064611..468a14762c0 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
@@ -1,8 +1,8 @@
 error[E0277]: `<T as Trait>::AssocType` cannot be sent between threads safely
-  --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5
+  --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:15
    |
 LL |     is_send::<T::AssocType>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely
+   |               ^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely
    |
    = help: the trait `Send` is not implemented for `<T as Trait>::AssocType`
 note: required by a bound in `is_send`
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr
index 09d3eec6b21..a3b32d2c1c8 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `dyn Foo<(isize,), isize, Output = ()>: Eq<dyn Foo<(isize,), Output = ()>>` is not satisfied
-  --> $DIR/unboxed-closure-sugar-default.rs:21:5
+  --> $DIR/unboxed-closure-sugar-default.rs:21:10
    |
 LL |     eq::<dyn Foo<(isize,), isize, Output=()>, dyn Foo(isize)>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(isize,), Output = ()>>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(isize,), Output = ()>>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>`
    |
 note: required by a bound in `eq`
   --> $DIR/unboxed-closure-sugar-default.rs:14:40
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs
index 0fc3e23ec73..acf0227a79b 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs
@@ -42,7 +42,7 @@ fn test<'a,'b>() {
     // Errors expected:
     eq::< dyn Foo<(),Output=()>,
           dyn Foo(char)                                               >();
-    //~^^ ERROR E0277
+    //~^ ERROR E0277
 }
 
 fn main() { }
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr
index a1cbf842a68..bccbf307ae1 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr
@@ -1,9 +1,8 @@
 error[E0277]: the trait bound `dyn Foo<(char,), Output = ()>: Eq<dyn Foo<(), Output = ()>>` is not satisfied
-  --> $DIR/unboxed-closure-sugar-equiv.rs:43:5
+  --> $DIR/unboxed-closure-sugar-equiv.rs:44:11
    |
-LL | /     eq::< dyn Foo<(),Output=()>,
-LL | |           dyn Foo(char)                                               >();
-   | |_______________________________________________________________________^ the trait `Eq<dyn Foo<(), Output = ()>>` is not implemented for `dyn Foo<(char,), Output = ()>`
+LL |           dyn Foo(char)                                               >();
+   |           ^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(), Output = ()>>` is not implemented for `dyn Foo<(char,), Output = ()>`
    |
 note: required by a bound in `eq`
   --> $DIR/unboxed-closure-sugar-equiv.rs:16:28
diff --git a/src/test/ui/unsized/issue-30355.rs b/src/test/ui/unsized/issue-30355.rs
index 01811090503..6ff5b37f6e5 100644
--- a/src/test/ui/unsized/issue-30355.rs
+++ b/src/test/ui/unsized/issue-30355.rs
@@ -4,7 +4,6 @@ pub static Y: &'static X = {
     const Y: &'static [u8] = b"";
     &X(*Y)
     //~^ ERROR E0277
-    //~| ERROR E0277
 };
 
 fn main() {}
diff --git a/src/test/ui/unsized/issue-30355.stderr b/src/test/ui/unsized/issue-30355.stderr
index 62b6007a15a..71bbdf5dec7 100644
--- a/src/test/ui/unsized/issue-30355.stderr
+++ b/src/test/ui/unsized/issue-30355.stderr
@@ -8,20 +8,6 @@ LL |     &X(*Y)
    = note: all function arguments must have a statically known size
    = help: unsized fn params are gated as an unstable feature
 
-error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/issue-30355.rs:5:6
-   |
-LL |     &X(*Y)
-   |      ^ doesn't have a size known at compile-time
-   |
-   = help: within `X`, the trait `Sized` is not implemented for `[u8]`
-note: required because it appears within the type `X`
-  --> $DIR/issue-30355.rs:1:12
-   |
-LL | pub struct X([u8]);
-   |            ^
-   = note: the return type of a function must have a statically known size
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml
index 352a8555614..758b1b139ad 100644
--- a/src/tools/bump-stage0/Cargo.toml
+++ b/src/tools/bump-stage0/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2021"
 [dependencies]
 anyhow = "1.0.34"
 curl = "0.4.38"
-indexmap = { version = "1.7.0", features = ["serde"] }
+indexmap = { version = "1.9.1", features = ["serde"] }
 serde = { version = "1.0.125", features = ["derive"] }
 serde_json = { version = "1.0.59", features = ["preserve_order"] }
 toml = "0.5.7"
diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs
index 908cfc15c0d..95fe98a683f 100644
--- a/src/tools/cargotest/main.rs
+++ b/src/tools/cargotest/main.rs
@@ -11,6 +11,8 @@ struct Test {
     packages: &'static [&'static str],
     features: Option<&'static [&'static str]>,
     manifest_path: Option<&'static str>,
+    /// `filters` are passed to libtest (i.e., after a `--` in the `cargo test` invocation).
+    filters: &'static [&'static str],
 }
 
 const TEST_REPOS: &[Test] = &[
@@ -22,6 +24,7 @@ const TEST_REPOS: &[Test] = &[
         packages: &[],
         features: None,
         manifest_path: None,
+        filters: &[],
     },
     Test {
         name: "ripgrep",
@@ -31,6 +34,7 @@ const TEST_REPOS: &[Test] = &[
         packages: &[],
         features: None,
         manifest_path: None,
+        filters: &[],
     },
     Test {
         name: "tokei",
@@ -40,6 +44,7 @@ const TEST_REPOS: &[Test] = &[
         packages: &[],
         features: None,
         manifest_path: None,
+        filters: &[],
     },
     Test {
         name: "xsv",
@@ -49,6 +54,21 @@ const TEST_REPOS: &[Test] = &[
         packages: &[],
         features: None,
         manifest_path: None,
+        // Many tests here use quickcheck and some of them can fail randomly, so only run deterministic tests.
+        filters: &[
+            "test_flatten::",
+            "test_fmt::",
+            "test_headers::",
+            "test_index::",
+            "test_join::",
+            "test_partition::",
+            "test_search::",
+            "test_select::",
+            "test_slice::",
+            "test_split::",
+            "test_stats::",
+            "test_table::",
+        ],
     },
     Test {
         name: "servo",
@@ -60,6 +80,7 @@ const TEST_REPOS: &[Test] = &[
         packages: &["selectors"],
         features: None,
         manifest_path: None,
+        filters: &[],
     },
     Test {
         name: "diesel",
@@ -75,6 +96,7 @@ const TEST_REPOS: &[Test] = &[
         // not any other crate present in the diesel workspace
         // (This is required to set the feature flags above)
         manifest_path: Some("diesel/Cargo.toml"),
+        filters: &[],
     },
 ];
 
@@ -97,7 +119,8 @@ fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
     if let Some(lockfile) = test.lock {
         fs::write(&dir.join("Cargo.lock"), lockfile).unwrap();
     }
-    if !run_cargo_test(cargo, &dir, test.packages, test.features, test.manifest_path) {
+    if !run_cargo_test(cargo, &dir, test.packages, test.features, test.manifest_path, test.filters)
+    {
         panic!("tests failed for {}", test.repo);
     }
 }
@@ -155,6 +178,7 @@ fn run_cargo_test(
     packages: &[&str],
     features: Option<&[&str]>,
     manifest_path: Option<&str>,
+    filters: &[&str],
 ) -> bool {
     let mut command = Command::new(cargo_path);
     command.arg("test");
@@ -174,6 +198,9 @@ fn run_cargo_test(
         command.arg("-p").arg(name);
     }
 
+    command.arg("--");
+    command.args(filters);
+
     let status = command
         // Disable rust-lang/cargo's cross-compile tests
         .env("CFG_DISABLE_CROSS_TESTS", "1")
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
index a1e37e7317b..638e4a54849 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
@@ -30,15 +30,7 @@ LL |     const VAL: T;
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
 
-error: constant expression depends on a generic parameter
-  --> $DIR/ice-6252.rs:13:9
-   |
-LL |     [1; <Multiply<Five, Five>>::VAL];
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0046, E0412.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 17f2b77dab0..f8f193ddf83 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -535,6 +535,29 @@ impl TestProps {
     }
 }
 
+pub fn line_directive<'line>(
+    comment: &str,
+    ln: &'line str,
+) -> Option<(Option<&'line str>, &'line str)> {
+    if ln.starts_with(comment) {
+        let ln = ln[comment.len()..].trim_start();
+        if ln.starts_with('[') {
+            // A comment like `//[foo]` is specific to revision `foo`
+            if let Some(close_brace) = ln.find(']') {
+                let lncfg = &ln[1..close_brace];
+
+                Some((Some(lncfg), ln[(close_brace + 1)..].trim_start()))
+            } else {
+                panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln)
+            }
+        } else {
+            Some((None, ln))
+        }
+    } else {
+        None
+    }
+}
+
 fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>, &str)) {
     if testfile.is_dir() {
         return;
@@ -557,17 +580,8 @@ fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>
         let ln = ln.trim();
         if ln.starts_with("fn") || ln.starts_with("mod") {
             return;
-        } else if ln.starts_with(comment) && ln[comment.len()..].trim_start().starts_with('[') {
-            // A comment like `//[foo]` is specific to revision `foo`
-            if let Some(close_brace) = ln.find(']') {
-                let open_brace = ln.find('[').unwrap();
-                let lncfg = &ln[open_brace + 1..close_brace];
-                it(Some(lncfg), ln[(close_brace + 1)..].trim_start());
-            } else {
-                panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln)
-            }
-        } else if ln.starts_with(comment) {
-            it(None, ln[comment.len()..].trim_start());
+        } else if let Some((lncfg, ln)) = line_directive(comment, ln) {
+            it(lncfg, ln);
         }
     }
 }
@@ -857,11 +871,13 @@ pub fn make_test_description<R: Read>(
     let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
     let has_asm_support = util::has_asm_support(&config.target);
     let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
+    let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target);
+    let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target);
     // for `-Z gcc-ld=lld`
     let has_rust_lld = config
         .compile_lib_path
@@ -894,11 +910,14 @@ pub fn make_test_description<R: Read>(
         ignore |= !rustc_has_sanitizer_support
             && config.parse_name_directive(ln, "needs-sanitizer-support");
         ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address");
+        ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi");
         ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak");
         ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory");
         ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread");
         ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress");
         ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag");
+        ignore |= !has_shadow_call_stack
+            && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack");
         ignore |= config.target_panic == PanicStrategy::Abort
             && config.parse_name_directive(ln, "needs-unwind");
         ignore |= config.target == "wasm32-unknown-unknown"
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 5517b5a12c3..26730fcec4c 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -648,8 +648,6 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_debuginfo_cdb_test(&self) {
-        assert!(self.revision.is_none(), "revisions not relevant here");
-
         let config = Config {
             target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
             host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
@@ -695,7 +693,12 @@ impl<'test> TestCx<'test> {
 
         // Parse debugger commands etc from test files
         let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
-            match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
+            match DebuggerCommands::parse_from(
+                &self.testpaths.file,
+                self.config,
+                prefixes,
+                self.revision,
+            ) {
                 Ok(cmds) => cmds,
                 Err(e) => self.fatal(&e),
             };
@@ -756,8 +759,6 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_debuginfo_gdb_test(&self) {
-        assert!(self.revision.is_none(), "revisions not relevant here");
-
         let config = Config {
             target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
             host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
@@ -783,7 +784,12 @@ impl<'test> TestCx<'test> {
         };
 
         let DebuggerCommands { commands, check_lines, breakpoint_lines } =
-            match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
+            match DebuggerCommands::parse_from(
+                &self.testpaths.file,
+                self.config,
+                prefixes,
+                self.revision,
+            ) {
                 Ok(cmds) => cmds,
                 Err(e) => self.fatal(&e),
             };
@@ -1005,8 +1011,6 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_debuginfo_lldb_test(&self) {
-        assert!(self.revision.is_none(), "revisions not relevant here");
-
         if self.config.lldb_python_dir.is_none() {
             self.fatal("Can't run LLDB test because LLDB's python path is not set.");
         }
@@ -1059,7 +1063,12 @@ impl<'test> TestCx<'test> {
 
         // Parse debugger commands etc from test files
         let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
-            match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
+            match DebuggerCommands::parse_from(
+                &self.testpaths.file,
+                self.config,
+                prefixes,
+                self.revision,
+            ) {
                 Ok(cmds) => cmds,
                 Err(e) => self.fatal(&e),
             };
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index cbd5e4c431f..379ff0bab40 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -1,4 +1,5 @@
 use crate::common::Config;
+use crate::header::line_directive;
 use crate::runtest::ProcRes;
 
 use std::fs::File;
@@ -16,6 +17,7 @@ impl DebuggerCommands {
         file: &Path,
         config: &Config,
         debugger_prefixes: &[&str],
+        rev: Option<&str>,
     ) -> Result<Self, String> {
         let directives = debugger_prefixes
             .iter()
@@ -25,13 +27,19 @@ impl DebuggerCommands {
         let mut breakpoint_lines = vec![];
         let mut commands = vec![];
         let mut check_lines = vec![];
-        let mut counter = 1;
+        let mut counter = 0;
         let reader = BufReader::new(File::open(file).unwrap());
         for line in reader.lines() {
+            counter += 1;
             match line {
                 Ok(line) => {
-                    let line =
-                        if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() };
+                    let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line));
+
+                    // Skip any revision specific directive that doesn't match the current
+                    // revision being tested
+                    if lnrev.is_some() && lnrev != rev {
+                        continue;
+                    }
 
                     if line.contains("#break") {
                         breakpoint_lines.push(counter);
@@ -49,7 +57,6 @@ impl DebuggerCommands {
                 }
                 Err(e) => return Err(format!("Error while parsing debugger commands: {}", e)),
             }
-            counter += 1;
         }
 
         Ok(Self { commands, check_lines, breakpoint_lines })
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 215af347f17..22df18ee9fb 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -96,6 +96,23 @@ pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
     "x86_64-unknown-linux-gnu",
 ];
 
+// FIXME(rcvalle): More targets are likely supported.
+pub const CFI_SUPPORTED_TARGETS: &[&str] = &[
+    "aarch64-apple-darwin",
+    "aarch64-fuchsia",
+    "aarch64-linux-android",
+    "aarch64-unknown-freebsd",
+    "aarch64-unknown-linux-gnu",
+    "x86_64-apple-darwin",
+    "x86_64-fuchsia",
+    "x86_64-pc-solaris",
+    "x86_64-unknown-freebsd",
+    "x86_64-unknown-illumos",
+    "x86_64-unknown-linux-gnu",
+    "x86_64-unknown-linux-musl",
+    "x86_64-unknown-netbsd",
+];
+
 pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[
     // FIXME: currently broken, see #88132
     // "aarch64-apple-darwin",
@@ -121,6 +138,8 @@ pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
 pub const MEMTAG_SUPPORTED_TARGETS: &[&str] =
     &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
 
+pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"];
+
 const BIG_ENDIAN: &[&str] = &[
     "aarch64_be",
     "armebv7r",
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 416cddb2516dea056bf6269eaaa5ba4d24ad083
+Subproject 963f08b702caf7a06eed564312933ec50dd07f5
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index bd08e0ede0b..33c05180408 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -9,6 +9,6 @@ clap = "3.1.1"
 env_logger = "0.7.1"
 
 [dependencies.mdbook]
-version = "0.4.18"
+version = "0.4.21"
 default-features = false
 features = ["search"]
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index 4ffa1fa8b28..f0054a1c1c9 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -10,8 +10,8 @@ use regex::Regex;
 
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0279", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0490", "E0514", "E0519",
-    "E0523", "E0554", "E0640", "E0717", "E0729", "E0789",
+    "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0490", "E0514", "E0519", "E0523",
+    "E0554", "E0640", "E0717", "E0729", "E0789",
 ];
 
 // Some error codes don't have any tests apparently...