about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--RELEASES.md1
-rw-r--r--compiler/rustc_arena/src/lib.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs6
-rw-r--r--compiler/rustc_codegen_gcc/Cargo.lock4
-rw-r--r--compiler/rustc_codegen_gcc/example/std_example.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/consts.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs2
-rw-r--r--compiler/rustc_const_eval/messages.ftl3
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs44
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs14
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs75
-rw-r--r--compiler/rustc_const_eval/src/errors.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs24
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs34
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs22
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs39
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs20
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs6
-rw-r--r--compiler/rustc_interface/src/interface.rs280
-rw-r--r--compiler/rustc_interface/src/tests.rs24
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs302
-rw-r--r--compiler/rustc_llvm/build.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/Linker.cpp1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h13
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp1
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs6
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs16
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs21
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs10
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs99
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs10
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs2
-rw-r--r--compiler/rustc_middle/src/query/erase.rs1
-rw-r--r--compiler/rustc_middle/src/traits/select.rs20
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs17
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts/valtree.rs4
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs9
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs3
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs12
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs8
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs7
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs14
-rw-r--r--compiler/rustc_parse/src/errors.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs41
-rw-r--r--compiler/rustc_resolve/messages.ftl2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs13
-rw-r--r--compiler/rustc_resolve/src/errors.rs7
-rw-r--r--compiler/rustc_resolve/src/imports.rs3
-rw-r--r--compiler/rustc_session/messages.ftl3
-rw-r--r--compiler/rustc_session/src/errors.rs6
-rw-r--r--compiler/rustc_session/src/session.rs37
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs213
-rw-r--r--compiler/rustc_smir/src/rustc_smir/alloc.rs7
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs30
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mod.rs19
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs11
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs21
-rw-r--r--compiler/rustc_span/src/symbol.rs8
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs24
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs235
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs77
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs20
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs9
-rw-r--r--compiler/stable_mir/src/compiler_interface.rs16
-rw-r--r--compiler/stable_mir/src/error.rs2
-rw-r--r--compiler/stable_mir/src/lib.rs2
-rw-r--r--compiler/stable_mir/src/mir/body.rs57
-rw-r--r--compiler/stable_mir/src/mir/mono.rs11
-rw-r--r--compiler/stable_mir/src/mir/visit.rs2
-rw-r--r--compiler/stable_mir/src/ty.rs116
-rw-r--r--library/alloc/src/boxed.rs14
-rw-r--r--library/alloc/src/sync.rs8
-rw-r--r--library/panic_abort/src/lib.rs10
-rw-r--r--library/std/build.rs1
-rw-r--r--library/std/src/sys/mod.rs3
-rw-r--r--library/std/src/sys/teeos/alloc.rs57
-rw-r--r--library/std/src/sys/teeos/locks/condvar.rs100
-rw-r--r--library/std/src/sys/teeos/locks/mod.rs8
-rw-r--r--library/std/src/sys/teeos/locks/rwlock.rs44
-rw-r--r--library/std/src/sys/teeos/mod.rs167
-rw-r--r--library/std/src/sys/teeos/net.rs372
-rw-r--r--library/std/src/sys/teeos/os.rs134
-rw-r--r--library/std/src/sys/teeos/rand.rs21
-rw-r--r--library/std/src/sys/teeos/stdio.rs88
-rw-r--r--library/std/src/sys/teeos/thread.rs164
-rw-r--r--library/std/src/sys/teeos/thread_local_dtor.rs4
-rw-r--r--library/std/src/sys/unix/time.rs12
-rw-r--r--library/std/src/sys/windows/api.rs2
-rw-r--r--library/std/src/thread/mod.rs1
-rw-r--r--src/bootstrap/Cargo.lock4
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/bootstrap.py2
-rw-r--r--src/ci/docker/host-x86_64/dist-various-1/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile3
-rwxr-xr-xsrc/ci/docker/run.sh9
-rwxr-xr-xsrc/ci/run.sh8
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md9
-rw-r--r--src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md13
-rw-r--r--src/doc/rustc/src/platform-support/riscv32i-unknown-none-elf.md1
-rw-r--r--src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md1
-rw-r--r--src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md34
-rw-r--r--src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md1
-rw-r--r--src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md1
-rw-r--r--src/doc/unstable-book/src/compiler-flags/check-cfg.md67
-rw-r--r--src/tools/build-manifest/src/main.rs1
-rw-r--r--src/tools/compiletest/src/runtest.rs7
-rw-r--r--src/tools/miri/src/diagnostics.rs2
-rw-r--r--src/tools/miri/src/intptrcast.rs5
-rw-r--r--src/tools/miri/src/machine.rs25
-rw-r--r--tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir14
-rw-r--r--tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir18
-rw-r--r--tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir12
-rw-r--r--tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir14
-rw-r--r--tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir6
-rw-r--r--tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir6
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff8
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff8
-rw-r--r--tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff2
-rw-r--r--tests/run-make/jobserver-error/cannot_open_fd.stderr2
-rw-r--r--tests/run-make/jobserver-error/not_a_pipe.stderr2
-rw-r--r--tests/ui-fulldeps/stable-mir/check_instance.rs8
-rw-r--r--tests/ui-fulldeps/stable-mir/check_ty_fold.rs115
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr8
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.feature.stderr6
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.full.stderr6
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.rs3
-rw-r--r--tests/ui/check-cfg/exhaustive-names.rs4
-rw-r--r--tests/ui/check-cfg/exhaustive-names.stderr (renamed from tests/ui/check-cfg/exhaustive-names.empty_names.stderr)2
-rw-r--r--tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr2
-rw-r--r--tests/ui/check-cfg/exhaustive-values.empty_values.stderr13
-rw-r--r--tests/ui/check-cfg/exhaustive-values.rs3
-rw-r--r--tests/ui/check-cfg/exhaustive-values.without_names.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.names_simple_ident.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.rs5
-rw-r--r--tests/ui/check-cfg/invalid-arguments.values_simple_ident.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-arguments.values_string_literals.stderr2
-rw-r--r--tests/ui/check-cfg/mix.rs9
-rw-r--r--tests/ui/check-cfg/mix.stderr (renamed from tests/ui/check-cfg/mix.names_values.stderr)54
-rw-r--r--tests/ui/check-cfg/no-expected-values.empty.stderr4
-rw-r--r--tests/ui/check-cfg/no-expected-values.mixed.stderr4
-rw-r--r--tests/ui/check-cfg/no-expected-values.rs3
-rw-r--r--tests/ui/check-cfg/no-expected-values.simple.stderr4
-rw-r--r--tests/ui/check-cfg/no-expected-values.values.stderr23
-rw-r--r--tests/ui/check-cfg/order-independant.names_after.stderr19
-rw-r--r--tests/ui/check-cfg/order-independant.names_before.stderr19
-rw-r--r--tests/ui/check-cfg/order-independant.rs11
-rw-r--r--tests/ui/check-cfg/order-independant.values_after.stderr11
-rw-r--r--tests/ui/check-cfg/order-independant.values_before.stderr11
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr10
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-name.rs5
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-name.stderr (renamed from tests/ui/check-cfg/unexpected-cfg-name.names.stderr)2
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-value.rs6
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-value.stderr (renamed from tests/ui/check-cfg/unexpected-cfg-value.values.stderr)4
-rw-r--r--tests/ui/check-cfg/values-target-json.rs2
-rw-r--r--tests/ui/const-ptr/forbidden_slices.rs2
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.32bit.stderr10
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.64bit.stderr10
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.rs2
-rw-r--r--tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr22
-rw-r--r--tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr22
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.rs2
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.stderr2
-rw-r--r--tests/ui/consts/const-eval/ub-upvars.32bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/ub-upvars.64bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/ub-wide-ptr.rs2
-rw-r--r--tests/ui/consts/const-eval/ub-wide-ptr.stderr16
-rw-r--r--tests/ui/consts/const-eval/ub-write-through-immutable.rs30
-rw-r--r--tests/ui/consts/const-eval/ub-write-through-immutable.stderr55
-rw-r--r--tests/ui/consts/const-points-to-static.32bit.stderr2
-rw-r--r--tests/ui/consts/const-points-to-static.64bit.stderr2
-rw-r--r--tests/ui/consts/invalid-union.32bit.stderr6
-rw-r--r--tests/ui/consts/invalid-union.64bit.stderr6
-rw-r--r--tests/ui/consts/invalid-union.rs12
-rw-r--r--tests/ui/consts/issue-63952.32bit.stderr2
-rw-r--r--tests/ui/consts/issue-63952.64bit.stderr2
-rw-r--r--tests/ui/consts/issue-79690.64bit.stderr2
-rw-r--r--tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr4
-rw-r--r--tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr4
-rw-r--r--tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr4
-rw-r--r--tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr4
-rw-r--r--tests/ui/extern/issue-116203.rs21
-rw-r--r--tests/ui/extern/issue-116203.stderr46
-rw-r--r--tests/ui/feature-gates/feature-gate-check-cfg.rs2
-rw-r--r--tests/ui/lint/unused/assoc-types.assoc_ty.stderr15
-rw-r--r--tests/ui/lint/unused/assoc-types.rpitit.stderr15
-rw-r--r--tests/ui/lint/unused/assoc-types.rs23
-rw-r--r--tests/ui/resolve/issue-117920.rs11
-rw-r--r--tests/ui/resolve/issue-117920.stderr9
-rw-r--r--tests/ui/resolve/issue-118295.rs5
-rw-r--r--tests/ui/resolve/issue-118295.stderr14
-rw-r--r--tests/ui/traits/question-mark-result-err-mismatch.rs59
-rw-r--r--tests/ui/traits/question-mark-result-err-mismatch.stderr62
-rw-r--r--tests/ui/try-block/try-block-bad-type.stderr4
-rw-r--r--tests/ui/try-trait/bad-interconversion.stderr4
-rw-r--r--tests/ui/try-trait/issue-32709.stderr4
223 files changed, 3572 insertions, 1162 deletions
diff --git a/RELEASES.md b/RELEASES.md
index 5bc302305c7..9eb8755dad9 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -89,7 +89,6 @@ Rustdoc
 -------
 
 - [Add warning block support in rustdoc](https://github.com/rust-lang/rust/pull/106561/)
-- [Accept additional user-defined syntax classes in fenced code blocks](https://github.com/rust-lang/rust/pull/110800/)
 - [rustdoc-search: add support for type parameters](https://github.com/rust-lang/rust/pull/112725/)
 - [rustdoc: show inner enum and struct in type definition for concrete type](https://github.com/rust-lang/rust/pull/114855/)
 
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 756af7269f2..621516af9c0 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -484,6 +484,20 @@ impl DroplessArena {
         }
     }
 
+    /// Allocates a string slice that is copied into the `DroplessArena`, returning a
+    /// reference to it. Will panic if passed an empty string.
+    ///
+    /// Panics:
+    ///
+    ///  - Zero-length string
+    #[inline]
+    pub fn alloc_str(&self, string: &str) -> &str {
+        let slice = self.alloc_slice(string.as_bytes());
+
+        // SAFETY: the result has a copy of the same valid UTF-8 bytes.
+        unsafe { std::str::from_utf8_unchecked(slice) }
+    }
+
     /// # Safety
     ///
     /// The caller must ensure that `mem` is valid for writes up to `size_of::<T>() * len`, and that
@@ -655,6 +669,14 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
             self.dropless.alloc_slice(value)
         }
 
+        #[inline]
+        pub fn alloc_str(&self, string: &str) -> &str {
+            if string.is_empty() {
+                return "";
+            }
+            self.dropless.alloc_str(string)
+        }
+
         #[allow(clippy::mut_from_ref)]
         pub fn alloc_from_iter<T: ArenaAllocatable<'tcx, C>, C>(
             &self,
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index cf68a3857c5..65f7ee6999a 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -126,7 +126,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 (prov, offset) = ptr.into_parts(); // we know the `offset` is relative
+                let alloc_id = prov.alloc_id();
                 let base_addr = match fx.tcx.global_alloc(alloc_id) {
                     GlobalAlloc::Memory(alloc) => {
                         let data_id = data_id_for_alloc_id(
@@ -374,7 +375,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
         let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
         data.define(bytes.into_boxed_slice());
 
-        for &(offset, alloc_id) in alloc.provenance().ptrs().iter() {
+        for &(offset, prov) in alloc.provenance().ptrs().iter() {
+            let alloc_id = prov.alloc_id();
             let addend = {
                 let endianness = tcx.data_layout.endian;
                 let offset = offset.bytes() as usize;
diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock
index 7c186336927..ddfce5d59bd 100644
--- a/compiler/rustc_codegen_gcc/Cargo.lock
+++ b/compiler/rustc_codegen_gcc/Cargo.lock
@@ -120,9 +120,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.147"
+version = "0.2.150"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
 
 [[package]]
 name = "linux-raw-sys"
diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs
index 0f6325c8980..ad69409eb65 100644
--- a/compiler/rustc_codegen_gcc/example/std_example.rs
+++ b/compiler/rustc_codegen_gcc/example/std_example.rs
@@ -1,3 +1,4 @@
+#![allow(internal_features)]
 #![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted)]
 
 #[cfg(feature="master")]
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index 93fe27e547a..b7ddc410315 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -199,7 +199,8 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                 }
             }
             Scalar::Ptr(ptr, _size) => {
-                let (alloc_id, offset) = ptr.into_parts();
+                let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative
+                let alloc_id = prov.alloc_id();
                 let base_addr =
                     match self.tcx.global_alloc(alloc_id) {
                         GlobalAlloc::Memory(alloc) => {
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index d8a1fd315c0..f06416b9bb5 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -285,7 +285,8 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
     let pointer_size = dl.pointer_size.bytes() as usize;
 
     let mut next_offset = 0;
-    for &(offset, alloc_id) in alloc.provenance().ptrs().iter() {
+    for &(offset, prov) in alloc.provenance().ptrs().iter() {
+        let alloc_id = prov.alloc_id();
         let offset = offset.bytes();
         assert_eq!(offset as usize as u64, offset);
         let offset = offset as usize;
@@ -313,7 +314,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
 
         llvals.push(cx.scalar_to_backend(
             InterpScalar::from_pointer(
-                interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
+                interpret::Pointer::new(prov, Size::from_bytes(ptr_offset)),
                 &cx.tcx,
             ),
             abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) },
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index d1b643f4967..8173e41aff4 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -246,8 +246,8 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 }
             }
             Scalar::Ptr(ptr, _size) => {
-                let (alloc_id, offset) = ptr.into_parts();
-                let (base_addr, base_addr_space) = match self.tcx.global_alloc(alloc_id) {
+                let (prov, offset) = ptr.into_parts();
+                let (base_addr, base_addr_space) = match self.tcx.global_alloc(prov.alloc_id()) {
                     GlobalAlloc::Memory(alloc) => {
                         let init = const_alloc_to_llvm(self, alloc);
                         let alloc = alloc.inner();
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index b6bc5395bf6..21ff267ca67 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -72,7 +72,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
     }
 
     let mut next_offset = 0;
-    for &(offset, alloc_id) in alloc.provenance().ptrs().iter() {
+    for &(offset, prov) in alloc.provenance().ptrs().iter() {
         let offset = offset.bytes();
         assert_eq!(offset as usize as u64, offset);
         let offset = offset as usize;
@@ -92,13 +92,10 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
         .expect("const_alloc_to_llvm: could not read relocation pointer")
             as u64;
 
-        let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
+        let address_space = cx.tcx.global_alloc(prov.alloc_id()).address_space(cx);
 
         llvals.push(cx.scalar_to_backend(
-            InterpScalar::from_pointer(
-                Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
-                &cx.tcx,
-            ),
+            InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx),
             Scalar::Initialized {
                 value: Primitive::Pointer(address_space),
                 valid_range: WrappingRange::full(dl.pointer_size),
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 6661f1f81e6..d724f9503bb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -105,7 +105,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                     bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
                 };
                 let a = Scalar::from_pointer(
-                    Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data), Size::ZERO),
+                    Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data).into(), Size::ZERO),
                     &bx.tcx(),
                 );
                 let a_llval = bx.scalar_to_backend(
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index f926da464e1..4a426ed16e5 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -461,6 +461,9 @@ const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of
 const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected}
 const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const`
 
+const_eval_write_through_immutable_pointer =
+    writing through a pointer that was derived from a shared (immutable) reference
+
 const_eval_write_to_read_only =
     writing to {$allocation} which is read-only
 const_eval_zst_pointer_out_of_bounds =
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 4934fcc75ec..26cf3b3f2b0 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -1,14 +1,16 @@
 use std::mem;
 
 use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg};
+use rustc_hir::CRATE_HIR_ID;
 use rustc_middle::mir::AssertKind;
+use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{layout::LayoutError, ConstInt};
 use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
 
-use super::InterpCx;
+use super::{CompileTimeInterpreter, InterpCx};
 use crate::errors::{self, FrameNote, ReportErrorExt};
-use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, Machine, MachineStopType};
+use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, MachineStopType};
 
 /// The CTFE machine has some custom error kinds.
 #[derive(Clone, Debug)]
@@ -57,16 +59,20 @@ impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
     }
 }
 
-pub fn get_span_and_frames<'tcx, 'mir, M: Machine<'mir, 'tcx>>(
-    ecx: &InterpCx<'mir, 'tcx, M>,
+pub fn get_span_and_frames<'tcx, 'mir>(
+    tcx: TyCtxtAt<'tcx>,
+    machine: &CompileTimeInterpreter<'mir, 'tcx>,
 ) -> (Span, Vec<errors::FrameNote>)
 where
     'tcx: 'mir,
 {
-    let mut stacktrace = ecx.generate_stacktrace();
+    let mut stacktrace =
+        InterpCx::<CompileTimeInterpreter<'mir, 'tcx>>::generate_stacktrace_from_stack(
+            &machine.stack,
+        );
     // Filter out `requires_caller_location` frames.
-    stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx));
-    let span = stacktrace.first().map(|f| f.span).unwrap_or(ecx.tcx.span);
+    stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx));
+    let span = stacktrace.first().map(|f| f.span).unwrap_or(tcx.span);
 
     let mut frames = Vec::new();
 
@@ -87,7 +93,7 @@ where
 
         let mut last_frame: Option<errors::FrameNote> = None;
         for frame_info in &stacktrace {
-            let frame = frame_info.as_note(*ecx.tcx);
+            let frame = frame_info.as_note(*tcx);
             match last_frame.as_mut() {
                 Some(last_frame)
                     if last_frame.span == frame.span
@@ -156,3 +162,25 @@ where
         }
     }
 }
+
+/// Emit a lint from a const-eval situation.
+// Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future!
+pub(super) fn lint<'tcx, 'mir, L>(
+    tcx: TyCtxtAt<'tcx>,
+    machine: &CompileTimeInterpreter<'mir, 'tcx>,
+    lint: &'static rustc_session::lint::Lint,
+    decorator: impl FnOnce(Vec<errors::FrameNote>) -> L,
+) where
+    L: for<'a> rustc_errors::DecorateLint<'a, ()>,
+{
+    let (span, frames) = get_span_and_frames(tcx, machine);
+
+    tcx.emit_spanned_lint(
+        lint,
+        // We use the root frame for this so the crate that defines the const defines whether the
+        // lint is emitted.
+        machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
+        span,
+        decorator(frames),
+    );
+}
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index edfece07d19..9d22df50d4f 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -155,8 +155,8 @@ pub(super) fn op_to_const<'tcx>(
     match immediate {
         Left(ref mplace) => {
             // We know `offset` is relative to the allocation, so we can use `into_parts`.
-            let (alloc_id, offset) = mplace.ptr().into_parts();
-            let alloc_id = alloc_id.expect("cannot have `fake` place fot non-ZST type");
+            let (prov, offset) = mplace.ptr().into_parts();
+            let alloc_id = prov.expect("cannot have `fake` place for non-ZST type").alloc_id();
             ConstValue::Indirect { alloc_id, offset }
         }
         // see comment on `let force_as_immediate` above
@@ -178,8 +178,8 @@ pub(super) fn op_to_const<'tcx>(
                 );
                 let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation";
                 // We know `offset` is relative to the allocation, so we can use `into_parts`.
-                let (alloc_id, offset) = a.to_pointer(ecx).expect(msg).into_parts();
-                let alloc_id = alloc_id.expect(msg);
+                let (prov, offset) = a.to_pointer(ecx).expect(msg).into_parts();
+                let alloc_id = prov.expect(msg).alloc_id();
                 let data = ecx.tcx.global_alloc(alloc_id).unwrap_memory();
                 assert!(offset == abi::Size::ZERO, "{}", msg);
                 let meta = b.to_target_usize(ecx).expect(msg);
@@ -338,7 +338,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
                 *ecx.tcx,
                 error,
                 None,
-                || super::get_span_and_frames(&ecx),
+                || super::get_span_and_frames(ecx.tcx, &ecx.machine),
                 |span, frames| ConstEvalError {
                     span,
                     error_kind: kind,
@@ -353,7 +353,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
             let validation =
                 const_validate_mplace(&ecx, &mplace, is_static, cid.promoted.is_some());
 
-            let alloc_id = mplace.ptr().provenance.unwrap();
+            let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
 
             // Validation failed, report an error.
             if let Err(error) = validation {
@@ -419,7 +419,7 @@ pub fn const_report_error<'mir, 'tcx>(
         *ecx.tcx,
         error,
         None,
-        || crate::const_eval::get_span_and_frames(ecx),
+        || crate::const_eval::get_span_and_frames(ecx.tcx, &ecx.machine),
         move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes },
     )
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 2d8ca67c3a5..9aaf6c510d5 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -1,30 +1,30 @@
-use rustc_hir::def::DefKind;
-use rustc_hir::LangItem;
-use rustc_middle::mir;
-use rustc_middle::mir::interpret::PointerArithmetic;
-use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::Span;
 use std::borrow::Borrow;
+use std::fmt;
 use std::hash::Hash;
 use std::ops::ControlFlow;
 
+use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::fx::IndexEntry;
-use std::fmt;
-
-use rustc_ast::Mutability;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
+use rustc_hir::LangItem;
+use rustc_middle::mir;
 use rustc_middle::mir::AssertMessage;
+use rustc_middle::query::TyCtxtAt;
+use rustc_middle::ty;
+use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
+use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER;
 use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
 use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi as CallAbi;
 
 use crate::errors::{LongRunning, LongRunningWarn};
 use crate::fluent_generated as fluent;
 use crate::interpret::{
-    self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx,
-    InterpResult, OpTy, PlaceTy, Pointer, Scalar,
+    self, compile_time_machine, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal,
+    Frame, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, PointerArithmetic, Scalar,
 };
 
 use super::error::*;
@@ -49,7 +49,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
     pub(super) num_evaluated_steps: usize,
 
     /// The virtual call stack.
-    pub(super) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>,
+    pub(super) stack: Vec<Frame<'mir, 'tcx>>,
 
     /// We need to make sure consts never point to anything mutable, even recursively. That is
     /// relied on for pattern matching on consts with references.
@@ -638,10 +638,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     }
 
     #[inline(always)]
-    fn expose_ptr(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _ptr: Pointer<AllocId>,
-    ) -> InterpResult<'tcx> {
+    fn expose_ptr(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> {
         // This is only reachable with -Zunleash-the-miri-inside-of-you.
         throw_unsup_format!("exposing pointers is not possible at compile-time")
     }
@@ -674,7 +671,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     }
 
     fn before_access_global(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         machine: &Self,
         alloc_id: AllocId,
         alloc: ConstAllocation<'tcx>,
@@ -711,6 +708,48 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
             }
         }
     }
+
+    fn retag_ptr_value(
+        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _kind: mir::RetagKind,
+        val: &ImmTy<'tcx, CtfeProvenance>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, CtfeProvenance>> {
+        // If it's a frozen shared reference that's not already immutable, make it immutable.
+        // (Do nothing on `None` provenance, that cannot store immutability anyway.)
+        if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind()
+            && *mutbl == Mutability::Not
+            && val.to_scalar_and_meta().0.to_pointer(ecx)?.provenance.is_some_and(|p| !p.immutable())
+            // That next check is expensive, that's why we have all the guards above.
+            && ty.is_freeze(*ecx.tcx, ecx.param_env)
+        {
+            let place = ecx.ref_to_mplace(val)?;
+            let new_place = place.map_provenance(|p| p.map(CtfeProvenance::as_immutable));
+            Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout))
+        } else {
+            Ok(val.clone())
+        }
+    }
+
+    fn before_memory_write(
+        tcx: TyCtxtAt<'tcx>,
+        machine: &mut Self,
+        _alloc_extra: &mut Self::AllocExtra,
+        (_alloc_id, immutable): (AllocId, bool),
+        range: AllocRange,
+    ) -> InterpResult<'tcx> {
+        if range.size == Size::ZERO {
+            // Nothing to check.
+            return Ok(());
+        }
+        // Reject writes through immutable pointers.
+        if immutable {
+            super::lint(tcx, machine, WRITES_THROUGH_IMMUTABLE_POINTER, |frames| {
+                crate::errors::WriteThroughImmutablePointer { frames }
+            });
+        }
+        // Everything else is fine.
+        Ok(())
+    }
 }
 
 // Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 8343dc2dd35..46fb64fd5b3 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -402,6 +402,13 @@ pub struct ConstEvalError {
     pub frame_notes: Vec<FrameNote>,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(const_eval_write_through_immutable_pointer)]
+pub struct WriteThroughImmutablePointer {
+    #[subdiagnostic]
+    pub frames: Vec<FrameNote>,
+}
+
 #[derive(Diagnostic)]
 #[diag(const_eval_nullary_intrinsic_fail)]
 pub struct NullaryIntrinsicError {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 04e5b550d6d..bbebf329d26 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -7,7 +7,9 @@ use hir::CRATE_HIR_ID;
 use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
 use rustc_index::IndexVec;
 use rustc_middle::mir;
-use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
+use rustc_middle::mir::interpret::{
+    CtfeProvenance, ErrorHandled, InvalidMetaKind, ReportedErrorInfo,
+};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
     self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
@@ -20,9 +22,9 @@ use rustc_span::Span;
 use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
 
 use super::{
-    AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
-    MemPlaceMeta, Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic,
-    Projectable, Provenance, Scalar, StackPopJump,
+    GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta,
+    Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable,
+    Provenance, Scalar, StackPopJump,
 };
 use crate::errors;
 use crate::util;
@@ -84,7 +86,7 @@ impl Drop for SpanGuard {
 }
 
 /// A stack frame.
-pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> {
+pub struct Frame<'mir, 'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
     ////////////////////////////////////////////////////////////////////////////////
     // Function and callsite information
     ////////////////////////////////////////////////////////////////////////////////
@@ -156,7 +158,7 @@ pub enum StackPopCleanup {
 
 /// State of a local variable including a memoized layout
 #[derive(Clone)]
-pub struct LocalState<'tcx, Prov: Provenance = AllocId> {
+pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
     value: LocalValue<Prov>,
     /// Don't modify if `Some`, this is only used to prevent computing the layout twice.
     /// Avoids computing the layout of locals that are never actually initialized.
@@ -177,7 +179,7 @@ impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> {
 /// This does not store the type of the local; the type is given by `body.local_decls` and can never
 /// change, so by not storing here we avoid having to maintain that as an invariant.
 #[derive(Copy, Clone, Debug)] // Miri debug-prints these
-pub(super) enum LocalValue<Prov: Provenance = AllocId> {
+pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> {
     /// This local is not currently alive, and cannot be used at all.
     Dead,
     /// A normal, live local.
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 881df9b04ab..7931789e436 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -18,7 +18,7 @@ use super::validity::RefTracking;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
-use rustc_middle::mir::interpret::InterpResult;
+use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult};
 use rustc_middle::ty::{self, layout::TyAndLayout, Ty};
 
 use rustc_ast::Mutability;
@@ -34,7 +34,7 @@ pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
         'mir,
         'tcx,
         MemoryKind = T,
-        Provenance = AllocId,
+        Provenance = CtfeProvenance,
         ExtraFnVal = !,
         FrameExtra = (),
         AllocExtra = (),
@@ -135,7 +135,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
         alloc.mutability = Mutability::Not;
     };
     // link the alloc id to the actual allocation
-    leftover_allocations.extend(alloc.provenance().ptrs().iter().map(|&(_, alloc_id)| alloc_id));
+    leftover_allocations.extend(alloc.provenance().ptrs().iter().map(|&(_, prov)| prov.alloc_id()));
     let alloc = tcx.mk_const_alloc(alloc);
     tcx.set_alloc_id_memory(alloc_id, alloc);
     None
@@ -178,10 +178,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
                 tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind()
             {
                 let ptr = mplace.meta().unwrap_meta().to_pointer(&tcx)?;
-                if let Some(alloc_id) = ptr.provenance {
+                if let Some(prov) = ptr.provenance {
                     // Explicitly choose const mode here, since vtables are immutable, even
                     // if the reference of the fat pointer is mutable.
-                    self.intern_shallow(alloc_id, InternMode::Const, None);
+                    self.intern_shallow(prov.alloc_id(), InternMode::Const, None);
                 } else {
                     // Validation will error (with a better message) on an invalid vtable pointer.
                     // Let validation show the error message, but make sure it *does* error.
@@ -191,7 +191,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
             }
             // Check if we have encountered this pointer+layout combination before.
             // Only recurse for allocation-backed pointers.
-            if let Some(alloc_id) = mplace.ptr().provenance {
+            if let Some(prov) = mplace.ptr().provenance {
                 // Compute the mode with which we intern this. Our goal here is to make as many
                 // statics as we can immutable so they can be placed in read-only memory by LLVM.
                 let ref_mode = match self.mode {
@@ -234,7 +234,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
                         InternMode::Const
                     }
                 };
-                match self.intern_shallow(alloc_id, ref_mode, Some(referenced_ty)) {
+                match self.intern_shallow(prov.alloc_id(), ref_mode, Some(referenced_ty)) {
                     // No need to recurse, these are interned already and statics may have
                     // cycles, so we don't want to recurse there
                     Some(IsStaticOrFn) => {}
@@ -353,7 +353,7 @@ pub fn intern_const_alloc_recursive<
         leftover_allocations,
         // The outermost allocation must exist, because we allocated it with
         // `Memory::allocate`.
-        ret.ptr().provenance.unwrap(),
+        ret.ptr().provenance.unwrap().alloc_id(),
         base_intern_mode,
         Some(ret.layout.ty),
     );
@@ -431,7 +431,8 @@ pub fn intern_const_alloc_recursive<
             }
             let alloc = tcx.mk_const_alloc(alloc);
             tcx.set_alloc_id_memory(alloc_id, alloc);
-            for &(_, alloc_id) in alloc.inner().provenance().ptrs().iter() {
+            for &(_, prov) in alloc.inner().provenance().ptrs().iter() {
+                let alloc_id = prov.alloc_id();
                 if leftover_allocations.insert(alloc_id) {
                     todo.push(alloc_id);
                 }
@@ -503,10 +504,11 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
         // `allocate` picks a fresh AllocId that we will associate with its data below.
         let dest = self.allocate(layout, MemoryKind::Stack)?;
         f(self, &dest.clone().into())?;
-        let mut alloc = self.memory.alloc_map.remove(&dest.ptr().provenance.unwrap()).unwrap().1;
+        let mut alloc =
+            self.memory.alloc_map.remove(&dest.ptr().provenance.unwrap().alloc_id()).unwrap().1;
         alloc.mutability = Mutability::Not;
         let alloc = self.tcx.mk_const_alloc(alloc);
-        let alloc_id = dest.ptr().provenance.unwrap(); // this was just allocated, it must have provenance
+        let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance
         self.tcx.set_alloc_id_memory(alloc_id, alloc);
         Ok(alloc_id)
     }
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 221ff2b60e9..5e69965512b 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -9,15 +9,17 @@ use std::hash::Hash;
 use rustc_apfloat::{Float, FloatConvert};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_middle::mir;
+use rustc_middle::query::TyCtxtAt;
+use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi as CallAbi;
 
 use super::{
-    AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy,
-    InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance,
+    AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, CtfeProvenance, FnArg,
+    Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy,
+    Pointer, Provenance,
 };
 
 /// Data returned by Machine::stack_pop,
@@ -292,7 +294,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
     /// `def_id` is `Some` if this is the "lazy" allocation of a static.
     #[inline]
     fn before_access_global(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         _machine: &Self,
         _alloc_id: AllocId,
         _allocation: ConstAllocation<'tcx>,
@@ -387,7 +389,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
     /// need to mutate.
     #[inline(always)]
     fn before_memory_read(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         _machine: &Self,
         _alloc_extra: &Self::AllocExtra,
         _prov: (AllocId, Self::ProvenanceExtra),
@@ -399,7 +401,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
     /// Hook for performing extra checks on a memory write access.
     #[inline(always)]
     fn before_memory_write(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         _machine: &mut Self,
         _alloc_extra: &mut Self::AllocExtra,
         _prov: (AllocId, Self::ProvenanceExtra),
@@ -411,7 +413,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
     /// Hook for performing extra operations on a memory deallocation.
     #[inline(always)]
     fn before_memory_deallocation(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         _machine: &mut Self,
         _alloc_extra: &mut Self::AllocExtra,
         _prov: (AllocId, Self::ProvenanceExtra),
@@ -513,8 +515,8 @@ pub trait Machine<'mir, 'tcx: 'mir>: 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 Provenance = AllocId;
-    type ProvenanceExtra = ();
+    type Provenance = CtfeProvenance;
+    type ProvenanceExtra = bool; // the "immutable" flag
 
     type ExtraFnVal = !;
 
@@ -567,14 +569,14 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
         def_id: DefId,
     ) -> InterpResult<$tcx, Pointer> {
         // Use the `AllocId` associated with the `DefId`. Any actual *access* will fail.
-        Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id), Size::ZERO))
+        Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO))
     }
 
     #[inline(always)]
     fn adjust_alloc_base_pointer(
         _ecx: &InterpCx<$mir, $tcx, Self>,
-        ptr: Pointer<AllocId>,
-    ) -> InterpResult<$tcx, Pointer<AllocId>> {
+        ptr: Pointer<CtfeProvenance>,
+    ) -> InterpResult<$tcx, Pointer<CtfeProvenance>> {
         Ok(ptr)
     }
 
@@ -582,7 +584,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     fn ptr_from_addr_cast(
         _ecx: &InterpCx<$mir, $tcx, Self>,
         addr: u64,
-    ) -> InterpResult<$tcx, Pointer<Option<AllocId>>> {
+    ) -> InterpResult<$tcx, Pointer<Option<CtfeProvenance>>> {
         // Allow these casts, but make the pointer not dereferenceable.
         // (I.e., they behave like transmutation.)
         // This is correct because no pointers can ever be exposed in compile-time evaluation.
@@ -592,10 +594,10 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     #[inline(always)]
     fn ptr_get_alloc(
         _ecx: &InterpCx<$mir, $tcx, Self>,
-        ptr: Pointer<AllocId>,
+        ptr: Pointer<CtfeProvenance>,
     ) -> 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, ()))
+        let (prov, offset) = ptr.into_parts();
+        Some((prov.alloc_id(), offset, prov.immutable()))
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index f865c0cc5fa..3fde6ae9b8e 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -22,8 +22,8 @@ use crate::fluent_generated as fluent;
 
 use super::{
     alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg,
-    CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
-    PointerArithmetic, Provenance, Scalar,
+    CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak,
+    Misalignment, Pointer, PointerArithmetic, Provenance, Scalar,
 };
 
 #[derive(Debug, PartialEq, Copy, Clone)]
@@ -159,9 +159,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline]
     pub fn global_base_pointer(
         &self,
-        ptr: Pointer<AllocId>,
+        ptr: Pointer<CtfeProvenance>,
     ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
-        let alloc_id = ptr.provenance;
+        let alloc_id = ptr.provenance.alloc_id();
         // We need to handle `extern static`.
         match self.tcx.try_get_global_alloc(alloc_id) {
             Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => {
@@ -339,7 +339,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Let the machine take some extra action
         let size = alloc.size();
         M::before_memory_deallocation(
-            *self.tcx,
+            self.tcx,
             &mut self.machine,
             &mut alloc.extra,
             (alloc_id, prov),
@@ -561,7 +561,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 (val, Some(def_id))
             }
         };
-        M::before_access_global(*self.tcx, &self.machine, id, alloc, def_id, is_write)?;
+        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::adjust_allocation(
             self,
@@ -626,7 +626,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         )?;
         if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc {
             let range = alloc_range(offset, size);
-            M::before_memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?;
+            M::before_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
@@ -687,13 +687,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     {
         let parts = self.get_ptr_access(ptr, size)?;
         if let Some((alloc_id, offset, prov)) = parts {
-            let tcx = *self.tcx;
+            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::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?;
-            Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id }))
+            Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id }))
         } else {
             Ok(None)
         }
@@ -1133,7 +1133,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let src_alloc = self.get_alloc_raw(src_alloc_id)?;
         let src_range = alloc_range(src_offset, size);
         M::before_memory_read(
-            *tcx,
+            tcx,
             &self.machine,
             &src_alloc.extra,
             (src_alloc_id, src_prov),
@@ -1163,7 +1163,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
         let dest_range = alloc_range(dest_offset, size * num_copies);
         M::before_memory_write(
-            *tcx,
+            tcx,
             extra,
             &mut dest_alloc.extra,
             (dest_alloc_id, dest_prov),
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 255dd1eba97..b39b219b46a 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -13,9 +13,9 @@ use rustc_middle::{mir, ty};
 use rustc_target::abi::{self, Abi, HasDataLayout, Size};
 
 use super::{
-    alloc_range, from_known_layout, mir_assign_valid_types, AllocId, Frame, InterpCx, InterpResult,
-    MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable,
-    Provenance, Scalar,
+    alloc_range, from_known_layout, mir_assign_valid_types, CtfeProvenance, Frame, InterpCx,
+    InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer,
+    Projectable, Provenance, Scalar,
 };
 
 /// An `Immediate` represents a single immediate self-contained Rust value.
@@ -26,7 +26,7 @@ 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<Prov: Provenance = AllocId> {
+pub enum Immediate<Prov: Provenance = CtfeProvenance> {
     /// A single scalar value (must have *initialized* `Scalar` ABI).
     Scalar(Scalar<Prov>),
     /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are
@@ -93,12 +93,23 @@ impl<Prov: Provenance> Immediate<Prov> {
             Immediate::Uninit => bug!("Got uninit where a scalar pair was expected"),
         }
     }
+
+    /// Returns the scalar from the first component and optionally the 2nd component as metadata.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
+    pub fn to_scalar_and_meta(self) -> (Scalar<Prov>, MemPlaceMeta<Prov>) {
+        match self {
+            Immediate::ScalarPair(val1, val2) => (val1, MemPlaceMeta::Meta(val2)),
+            Immediate::Scalar(val) => (val, MemPlaceMeta::None),
+            Immediate::Uninit => bug!("Got uninit where a scalar or scalar pair was expected"),
+        }
+    }
 }
 
 // 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)]
-pub struct ImmTy<'tcx, Prov: Provenance = AllocId> {
+pub struct ImmTy<'tcx, Prov: Provenance = CtfeProvenance> {
     imm: Immediate<Prov>,
     pub layout: TyAndLayout<'tcx>,
 }
@@ -334,13 +345,13 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
 /// 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(super) enum Operand<Prov: Provenance = AllocId> {
+pub(super) enum Operand<Prov: Provenance = CtfeProvenance> {
     Immediate(Immediate<Prov>),
     Indirect(MemPlace<Prov>),
 }
 
 #[derive(Clone)]
-pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
+pub struct OpTy<'tcx, Prov: Provenance = CtfeProvenance> {
     op: Operand<Prov>, // Keep this private; it helps enforce invariants.
     pub layout: TyAndLayout<'tcx>,
 }
@@ -750,17 +761,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?;
         let imm = match val_val {
             mir::ConstValue::Indirect { alloc_id, offset } => {
-                // We rely on mutability being set correctly in that allocation to prevent writes
-                // where none should happen.
-                let ptr = self.global_base_pointer(Pointer::new(alloc_id, offset))?;
+                // This is const data, no mutation allowed.
+                let ptr = self.global_base_pointer(Pointer::new(
+                    CtfeProvenance::from(alloc_id).as_immutable(),
+                    offset,
+                ))?;
                 return Ok(self.ptr_to_mplace(ptr.into(), layout).into());
             }
             mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(),
             mir::ConstValue::ZeroSized => Immediate::Uninit,
             mir::ConstValue::Slice { data, meta } => {
-                // We rely on mutability being set correctly in `data` to prevent writes
-                // where none should happen.
-                let ptr = Pointer::new(self.tcx.reserve_and_set_memory_alloc(data), Size::ZERO);
+                // This is const data, no mutation allowed.
+                let alloc_id = self.tcx.reserve_and_set_memory_alloc(data);
+                let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO);
                 Immediate::new_slice(self.global_base_pointer(ptr)?.into(), meta, self)
             }
         };
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 04f0cdb326e..639b269ac25 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -14,14 +14,14 @@ use rustc_middle::ty::Ty;
 use rustc_target::abi::{Abi, Align, HasDataLayout, Size};
 
 use super::{
-    alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckAlignMsg, ImmTy,
-    Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy,
+    alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance,
+    ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy,
     Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable, Scalar,
 };
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
 /// Information required for the sound usage of a `MemPlace`.
-pub enum MemPlaceMeta<Prov: Provenance = AllocId> {
+pub enum MemPlaceMeta<Prov: Provenance = CtfeProvenance> {
     /// The unsized payload (e.g. length for slices or vtable pointer for trait objects).
     Meta(Scalar<Prov>),
     /// `Sized` types or unsized `extern type`
@@ -49,7 +49,7 @@ impl<Prov: Provenance> MemPlaceMeta<Prov> {
 }
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
-pub(super) struct MemPlace<Prov: Provenance = AllocId> {
+pub(super) struct MemPlace<Prov: Provenance = CtfeProvenance> {
     /// 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.
@@ -100,7 +100,7 @@ impl<Prov: Provenance> MemPlace<Prov> {
 
 /// A MemPlace with its layout. Constructing it is only possible in this module.
 #[derive(Clone, Hash, Eq, PartialEq)]
-pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
+pub struct MPlaceTy<'tcx, Prov: Provenance = CtfeProvenance> {
     mplace: MemPlace<Prov>,
     pub layout: TyAndLayout<'tcx>,
 }
@@ -179,7 +179,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub(super) enum Place<Prov: Provenance = AllocId> {
+pub(super) enum Place<Prov: Provenance = CtfeProvenance> {
     /// A place referring to a value allocated in the `Memory` system.
     Ptr(MemPlace<Prov>),
 
@@ -195,7 +195,7 @@ pub(super) enum Place<Prov: Provenance = AllocId> {
 }
 
 #[derive(Clone)]
-pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
+pub struct PlaceTy<'tcx, Prov: Provenance = CtfeProvenance> {
     place: Place<Prov>, // Keep this private; it helps enforce invariants.
     pub layout: TyAndLayout<'tcx>,
 }
@@ -406,11 +406,7 @@ where
         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)?;
-        let (ptr, meta) = match **val {
-            Immediate::Scalar(ptr) => (ptr, MemPlaceMeta::None),
-            Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta)),
-            Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
-        };
+        let (ptr, meta) = val.to_scalar_and_meta();
 
         // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced;
         // we hence can't call `size_and_align_of` since that asserts more validity than we want.
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index debae6c8902..e48506bd083 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -18,14 +18,14 @@ use rustc_target::abi::{
 use rustc_target::spec::abi::Abi;
 
 use super::{
-    AllocId, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable,
-    Provenance, Scalar, StackPopCleanup,
+    CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
+    Projectable, Provenance, Scalar, StackPopCleanup,
 };
 use crate::fluent_generated as fluent;
 
 /// An argment passed to a function.
 #[derive(Clone, Debug)]
-pub enum FnArg<'tcx, Prov: Provenance = AllocId> {
+pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
     /// Pass a copy of the given operand.
     Copy(OpTy<'tcx, Prov>),
     /// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 8a6d8d3d42e..7831b251db4 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -10,8 +10,8 @@ use rustc_data_structures::sync::Lrc;
 use rustc_errors::registry::Registry;
 use rustc_errors::{ErrorGuaranteed, Handler};
 use rustc_lint::LintStore;
+use rustc_middle::ty;
 use rustc_middle::util::Providers;
-use rustc_middle::{bug, ty};
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_query_impl::QueryCtxt;
 use rustc_query_system::query::print_query_stack;
@@ -42,7 +42,7 @@ pub struct Compiler {
 }
 
 /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`.
-pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg {
+pub(crate) fn parse_cfg(handler: &Handler, cfgs: Vec<String>) -> Cfg {
     cfgs.into_iter()
         .map(|s| {
             let sess = ParseSess::with_silent_emitter(Some(format!(
@@ -52,10 +52,14 @@ pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg {
 
             macro_rules! error {
                 ($reason: expr) => {
-                    handler.early_error(format!(
-                        concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
-                        s
-                    ));
+                    #[allow(rustc::untranslatable_diagnostic)]
+                    #[allow(rustc::diagnostic_outside_of_impl)]
+                    handler
+                        .struct_fatal(format!(
+                            concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
+                            s
+                        ))
+                        .emit();
                 };
             }
 
@@ -97,14 +101,13 @@ pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg {
 }
 
 /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
-pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg {
+pub(crate) fn parse_check_cfg(handler: &Handler, specs: Vec<String>) -> CheckCfg {
     // If any --check-cfg is passed then exhaustive_values and exhaustive_names
     // are enabled by default.
     let exhaustive_names = !specs.is_empty();
     let exhaustive_values = !specs.is_empty();
     let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
 
-    let mut old_syntax = None;
     for s in specs {
         let sess = ParseSess::with_silent_emitter(Some(format!(
             "this error occurred on the command line: `--check-cfg={s}`"
@@ -113,10 +116,14 @@ pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -
 
         macro_rules! error {
             ($reason:expr) => {
-                handler.early_error(format!(
-                    concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
-                    s
-                ))
+                #[allow(rustc::untranslatable_diagnostic)]
+                #[allow(rustc::diagnostic_outside_of_impl)]
+                handler
+                    .struct_fatal(format!(
+                        concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
+                        s
+                    ))
+                    .emit()
             };
         }
 
@@ -142,174 +149,101 @@ pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -
             expected_error();
         };
 
-        let mut set_old_syntax = || {
-            // defaults are flipped for the old syntax
-            if old_syntax == None {
-                check_cfg.exhaustive_names = false;
-                check_cfg.exhaustive_values = false;
-            }
-            old_syntax = Some(true);
-        };
+        if !meta_item.has_name(sym::cfg) {
+            expected_error();
+        }
 
-        if meta_item.has_name(sym::names) {
-            set_old_syntax();
-
-            check_cfg.exhaustive_names = true;
-            for arg in args {
-                if arg.is_word()
-                    && let Some(ident) = arg.ident()
-                {
-                    check_cfg.expecteds.entry(ident.name).or_insert(ExpectedValues::Any);
-                } else {
-                    error!("`names()` arguments must be simple identifiers");
-                }
-            }
-        } else if meta_item.has_name(sym::values) {
-            set_old_syntax();
-
-            if let Some((name, values)) = args.split_first() {
-                if name.is_word()
-                    && let Some(ident) = name.ident()
-                {
-                    let expected_values = check_cfg
-                        .expecteds
-                        .entry(ident.name)
-                        .and_modify(|expected_values| match expected_values {
-                            ExpectedValues::Some(_) => {}
-                            ExpectedValues::Any => {
-                                // handle the case where names(...) was done
-                                // before values by changing to a list
-                                *expected_values = ExpectedValues::Some(FxHashSet::default());
-                            }
-                        })
-                        .or_insert_with(|| ExpectedValues::Some(FxHashSet::default()));
+        let mut names = Vec::new();
+        let mut values: FxHashSet<_> = Default::default();
 
-                    let ExpectedValues::Some(expected_values) = expected_values else {
-                        bug!("`expected_values` should be a list a values")
-                    };
+        let mut any_specified = false;
+        let mut values_specified = false;
+        let mut values_any_specified = false;
 
-                    for val in values {
-                        if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) {
-                            expected_values.insert(Some(*s));
-                        } else {
-                            error!("`values()` arguments must be string literals");
-                        }
-                    }
-
-                    if values.is_empty() {
-                        expected_values.insert(None);
-                    }
-                } else {
-                    error!("`values()` first argument must be a simple identifier");
+        for arg in args {
+            if arg.is_word()
+                && let Some(ident) = arg.ident()
+            {
+                if values_specified {
+                    error!("`cfg()` names cannot be after values");
                 }
-            } else if args.is_empty() {
-                check_cfg.exhaustive_values = true;
-            } else {
-                expected_error();
-            }
-        } else if meta_item.has_name(sym::cfg) {
-            old_syntax = Some(false);
-
-            let mut names = Vec::new();
-            let mut values: FxHashSet<_> = Default::default();
-
-            let mut any_specified = false;
-            let mut values_specified = false;
-            let mut values_any_specified = false;
-
-            for arg in args {
-                if arg.is_word()
-                    && let Some(ident) = arg.ident()
-                {
-                    if values_specified {
-                        error!("`cfg()` names cannot be after values");
-                    }
-                    names.push(ident);
-                } else if arg.has_name(sym::any)
-                    && let Some(args) = arg.meta_item_list()
-                {
-                    if any_specified {
-                        error!("`any()` cannot be specified multiple times");
-                    }
-                    any_specified = true;
-                    if !args.is_empty() {
-                        error!("`any()` must be empty");
-                    }
-                } else if arg.has_name(sym::values)
-                    && let Some(args) = arg.meta_item_list()
-                {
-                    if names.is_empty() {
-                        error!("`values()` cannot be specified before the names");
-                    } else if values_specified {
-                        error!("`values()` cannot be specified multiple times");
-                    }
-                    values_specified = true;
-
-                    for arg in args {
-                        if let Some(LitKind::Str(s, _)) = arg.lit().map(|lit| &lit.kind) {
-                            values.insert(Some(*s));
-                        } else if arg.has_name(sym::any)
-                            && let Some(args) = arg.meta_item_list()
-                        {
-                            if values_any_specified {
-                                error!("`any()` in `values()` cannot be specified multiple times");
-                            }
-                            values_any_specified = true;
-                            if !args.is_empty() {
-                                error!("`any()` must be empty");
-                            }
-                        } else {
-                            error!("`values()` arguments must be string literals or `any()`");
+                names.push(ident);
+            } else if arg.has_name(sym::any)
+                && let Some(args) = arg.meta_item_list()
+            {
+                if any_specified {
+                    error!("`any()` cannot be specified multiple times");
+                }
+                any_specified = true;
+                if !args.is_empty() {
+                    error!("`any()` must be empty");
+                }
+            } else if arg.has_name(sym::values)
+                && let Some(args) = arg.meta_item_list()
+            {
+                if names.is_empty() {
+                    error!("`values()` cannot be specified before the names");
+                } else if values_specified {
+                    error!("`values()` cannot be specified multiple times");
+                }
+                values_specified = true;
+
+                for arg in args {
+                    if let Some(LitKind::Str(s, _)) = arg.lit().map(|lit| &lit.kind) {
+                        values.insert(Some(*s));
+                    } else if arg.has_name(sym::any)
+                        && let Some(args) = arg.meta_item_list()
+                    {
+                        if values_any_specified {
+                            error!("`any()` in `values()` cannot be specified multiple times");
+                        }
+                        values_any_specified = true;
+                        if !args.is_empty() {
+                            error!("`any()` must be empty");
                         }
+                    } else {
+                        error!("`values()` arguments must be string literals or `any()`");
                     }
-                } else {
-                    error!(
-                        "`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"
-                    );
                 }
+            } else {
+                error!("`cfg()` arguments must be simple identifiers, `any()` or `values(...)`");
             }
+        }
 
-            if values.is_empty() && !values_any_specified && !any_specified {
-                values.insert(None);
-            } else if !values.is_empty() && values_any_specified {
-                error!(
-                    "`values()` arguments cannot specify string literals and `any()` at the same time"
-                );
-            }
+        if values.is_empty() && !values_any_specified && !any_specified {
+            values.insert(None);
+        } else if !values.is_empty() && values_any_specified {
+            error!(
+                "`values()` arguments cannot specify string literals and `any()` at the same time"
+            );
+        }
 
-            if any_specified {
-                if names.is_empty()
-                    && values.is_empty()
-                    && !values_specified
-                    && !values_any_specified
-                {
-                    check_cfg.exhaustive_names = false;
-                } else {
-                    error!("`cfg(any())` can only be provided in isolation");
-                }
+        if any_specified {
+            if names.is_empty() && values.is_empty() && !values_specified && !values_any_specified {
+                check_cfg.exhaustive_names = false;
             } else {
-                for name in names {
-                    check_cfg
-                        .expecteds
-                        .entry(name.name)
-                        .and_modify(|v| match v {
-                            ExpectedValues::Some(v) if !values_any_specified => {
-                                v.extend(values.clone())
-                            }
-                            ExpectedValues::Some(_) => *v = ExpectedValues::Any,
-                            ExpectedValues::Any => {}
-                        })
-                        .or_insert_with(|| {
-                            if values_any_specified {
-                                ExpectedValues::Any
-                            } else {
-                                ExpectedValues::Some(values.clone())
-                            }
-                        });
-                }
+                error!("`cfg(any())` can only be provided in isolation");
             }
         } else {
-            expected_error();
+            for name in names {
+                check_cfg
+                    .expecteds
+                    .entry(name.name)
+                    .and_modify(|v| match v {
+                        ExpectedValues::Some(v) if !values_any_specified => {
+                            v.extend(values.clone())
+                        }
+                        ExpectedValues::Some(_) => *v = ExpectedValues::Any,
+                        ExpectedValues::Any => {}
+                    })
+                    .or_insert_with(|| {
+                        if values_any_specified {
+                            ExpectedValues::Any
+                        } else {
+                            ExpectedValues::Some(values.clone())
+                        }
+                    });
+            }
         }
     }
 
@@ -388,13 +322,13 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
         || {
             crate::callbacks::setup_callbacks();
 
-            let handler = EarlyErrorHandler::new(config.opts.error_format);
+            let early_handler = EarlyErrorHandler::new(config.opts.error_format);
 
             let codegen_backend = if let Some(make_codegen_backend) = config.make_codegen_backend {
                 make_codegen_backend(&config.opts)
             } else {
                 util::get_codegen_backend(
-                    &handler,
+                    &early_handler,
                     &config.opts.maybe_sysroot,
                     config.opts.unstable_opts.codegen_backend.as_deref(),
                 )
@@ -411,7 +345,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             ) {
                 Ok(bundle) => bundle,
                 Err(e) => {
-                    handler.early_error(format!("failed to load fluent bundle: {e}"));
+                    early_handler.early_error(format!("failed to load fluent bundle: {e}"));
                 }
             };
 
@@ -422,7 +356,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             let target_override = codegen_backend.target_override(&config.opts);
 
             let mut sess = rustc_session::build_session(
-                &handler,
+                early_handler,
                 config.opts,
                 CompilerIO {
                     input: config.input,
@@ -444,12 +378,12 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
             codegen_backend.init(&sess);
 
-            let cfg = parse_cfg(&handler, config.crate_cfg);
+            let cfg = parse_cfg(&sess.diagnostic(), config.crate_cfg);
             let mut cfg = config::build_configuration(&sess, cfg);
             util::add_configuration(&mut cfg, &mut sess, &*codegen_backend);
             sess.parse_sess.config = cfg;
 
-            let mut check_cfg = parse_check_cfg(&handler, config.crate_check_cfg);
+            let mut check_cfg = parse_check_cfg(&sess.diagnostic(), config.crate_check_cfg);
             check_cfg.fill_well_known(&sess.target);
             sess.parse_sess.check_config = check_cfg;
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 714af977fb5..f7b6ab331a5 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -25,10 +25,10 @@ use std::num::NonZeroUsize;
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
 
-fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, Cfg) {
+fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
+    let mut early_handler = EarlyErrorHandler::new(ErrorOutputType::default());
     let registry = registry::Registry::new(&[]);
-    let sessopts = build_session_options(handler, &matches);
-    let cfg = parse_cfg(handler, matches.opt_strs("cfg"));
+    let sessopts = build_session_options(&mut early_handler, &matches);
     let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
     let io = CompilerIO {
         input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
@@ -37,7 +37,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se
         temps_dir,
     };
     let sess = build_session(
-        handler,
+        early_handler,
         sessopts,
         io,
         None,
@@ -51,6 +51,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se
         Arc::default(),
         Default::default(),
     );
+    let cfg = parse_cfg(&sess.diagnostic(), matches.opt_strs("cfg"));
     (sess, cfg)
 }
 
@@ -117,8 +118,7 @@ fn assert_non_crate_hash_different(x: &Options, y: &Options) {
 fn test_switch_implies_cfg_test() {
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["--test".to_string()]).unwrap();
-        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
-        let (sess, cfg) = mk_session(&mut handler, matches);
+        let (sess, cfg) = mk_session(matches);
         let cfg = build_configuration(&sess, cfg);
         assert!(cfg.contains(&(sym::test, None)));
     });
@@ -129,8 +129,7 @@ fn test_switch_implies_cfg_test() {
 fn test_switch_implies_cfg_test_unless_cfg_test() {
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
-        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
-        let (sess, cfg) = mk_session(&mut handler, matches);
+        let (sess, cfg) = mk_session(matches);
         let cfg = build_configuration(&sess, cfg);
         let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
         assert!(test_items.next().is_some());
@@ -142,23 +141,20 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
 fn test_can_print_warnings() {
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
-        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
-        let (sess, _) = mk_session(&mut handler, matches);
+        let (sess, _) = mk_session(matches);
         assert!(!sess.diagnostic().can_emit_warnings());
     });
 
     rustc_span::create_default_session_globals_then(|| {
         let matches =
             optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
-        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
-        let (sess, _) = mk_session(&mut handler, matches);
+        let (sess, _) = mk_session(matches);
         assert!(sess.diagnostic().can_emit_warnings());
     });
 
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
-        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
-        let (sess, _) = mk_session(&mut handler, matches);
+        let (sess, _) = mk_session(matches);
         assert!(sess.diagnostic().can_emit_warnings());
     });
 }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 0a167b0893c..c492e7c6fbf 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -291,7 +291,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                         .map(|inner| MustUsePath::Pinned(Box::new(inner)))
                 }
                 ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
+                ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
                     elaborate(
                         cx.tcx,
                         cx.tcx.explicit_item_bounds(def).instantiate_identity_iter_copied(),
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a2243817df9..e6e445c54b1 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -8,6 +8,135 @@ use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::sym;
 
+declare_lint_pass! {
+    /// Does nothing as a lint pass, but registers some `Lint`s
+    /// that are used by other parts of the compiler.
+    HardwiredLints => [
+        // tidy-alphabetical-start
+        ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
+        AMBIGUOUS_ASSOCIATED_ITEMS,
+        AMBIGUOUS_GLOB_IMPORTS,
+        AMBIGUOUS_GLOB_REEXPORTS,
+        ARITHMETIC_OVERFLOW,
+        ASM_SUB_REGISTER,
+        BAD_ASM_STYLE,
+        BARE_TRAIT_OBJECTS,
+        BINDINGS_WITH_VARIANT_NAME,
+        BREAK_WITH_LABEL_AND_LOOP,
+        BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
+        CENUM_IMPL_DROP_CAST,
+        COHERENCE_LEAK_CHECK,
+        COINDUCTIVE_OVERLAP_IN_COHERENCE,
+        CONFLICTING_REPR_HINTS,
+        CONST_EVALUATABLE_UNCHECKED,
+        CONST_ITEM_MUTATION,
+        CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
+        DEAD_CODE,
+        DEPRECATED,
+        DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+        DEPRECATED_IN_FUTURE,
+        DEPRECATED_WHERE_CLAUSE_LOCATION,
+        DUPLICATE_MACRO_ATTRIBUTES,
+        ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
+        ELIDED_LIFETIMES_IN_PATHS,
+        EXPORTED_PRIVATE_DEPENDENCIES,
+        FFI_UNWIND_CALLS,
+        FORBIDDEN_LINT_GROUPS,
+        FUNCTION_ITEM_REFERENCES,
+        FUZZY_PROVENANCE_CASTS,
+        HIDDEN_GLOB_REEXPORTS,
+        ILL_FORMED_ATTRIBUTE_INPUT,
+        ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+        IMPLIED_BOUNDS_ENTAILMENT,
+        INCOMPLETE_INCLUDE,
+        INDIRECT_STRUCTURAL_MATCH,
+        INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
+        INLINE_NO_SANITIZE,
+        INVALID_DOC_ATTRIBUTES,
+        INVALID_MACRO_EXPORT_ARGUMENTS,
+        INVALID_TYPE_PARAM_DEFAULT,
+        IRREFUTABLE_LET_PATTERNS,
+        LARGE_ASSIGNMENTS,
+        LATE_BOUND_LIFETIME_ARGUMENTS,
+        LEGACY_DERIVE_HELPERS,
+        LONG_RUNNING_CONST_EVAL,
+        LOSSY_PROVENANCE_CASTS,
+        MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
+        MACRO_USE_EXTERN_CRATE,
+        META_VARIABLE_MISUSE,
+        MISSING_ABI,
+        MISSING_FRAGMENT_SPECIFIER,
+        MUST_NOT_SUSPEND,
+        NAMED_ARGUMENTS_USED_POSITIONALLY,
+        NON_EXHAUSTIVE_OMITTED_PATTERNS,
+        NONTRIVIAL_STRUCTURAL_MATCH,
+        ORDER_DEPENDENT_TRAIT_OBJECTS,
+        OVERLAPPING_RANGE_ENDPOINTS,
+        PATTERNS_IN_FNS_WITHOUT_BODY,
+        POINTER_STRUCTURAL_MATCH,
+        PRIVATE_BOUNDS,
+        PRIVATE_INTERFACES,
+        PROC_MACRO_BACK_COMPAT,
+        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+        PUB_USE_OF_PRIVATE_EXTERN_CRATE,
+        REFINING_IMPL_TRAIT,
+        RENAMED_AND_REMOVED_LINTS,
+        REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
+        RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
+        RUST_2021_INCOMPATIBLE_OR_PATTERNS,
+        RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
+        RUST_2021_PRELUDE_COLLISIONS,
+        SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
+        SINGLE_USE_LIFETIMES,
+        SOFT_UNSTABLE,
+        STABLE_FEATURES,
+        SUSPICIOUS_AUTO_TRAIT_IMPLS,
+        TEST_UNSTABLE_LINT,
+        TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+        TRIVIAL_CASTS,
+        TRIVIAL_NUMERIC_CASTS,
+        TYVAR_BEHIND_RAW_POINTER,
+        UNCONDITIONAL_PANIC,
+        UNCONDITIONAL_RECURSION,
+        UNDEFINED_NAKED_FUNCTION_ABI,
+        UNEXPECTED_CFGS,
+        UNFULFILLED_LINT_EXPECTATIONS,
+        UNINHABITED_STATIC,
+        UNKNOWN_CRATE_TYPES,
+        UNKNOWN_LINTS,
+        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+        UNNAMEABLE_TEST_ITEMS,
+        UNNAMEABLE_TYPES,
+        UNREACHABLE_CODE,
+        UNREACHABLE_PATTERNS,
+        UNSAFE_OP_IN_UNSAFE_FN,
+        UNSTABLE_NAME_COLLISIONS,
+        UNSTABLE_SYNTAX_PRE_EXPANSION,
+        UNSUPPORTED_CALLING_CONVENTIONS,
+        UNUSED_ASSIGNMENTS,
+        UNUSED_ASSOCIATED_TYPE_BOUNDS,
+        UNUSED_ATTRIBUTES,
+        UNUSED_CRATE_DEPENDENCIES,
+        UNUSED_EXTERN_CRATES,
+        UNUSED_FEATURES,
+        UNUSED_IMPORTS,
+        UNUSED_LABELS,
+        UNUSED_LIFETIMES,
+        UNUSED_MACRO_RULES,
+        UNUSED_MACROS,
+        UNUSED_MUT,
+        UNUSED_QUALIFICATIONS,
+        UNUSED_TUPLE_STRUCT_FIELDS,
+        UNUSED_UNSAFE,
+        UNUSED_VARIABLES,
+        USELESS_DEPRECATED,
+        WARNINGS,
+        WHERE_CLAUSES_OBJECT_SAFETY,
+        WRITES_THROUGH_IMMUTABLE_POINTER,
+        // tidy-alphabetical-end
+    ]
+}
+
 declare_lint! {
     /// The `forbidden_lint_groups` lint detects violations of
     /// `forbid` applied to a lint group. Due to a bug in the compiler,
@@ -3135,7 +3264,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```text
-    /// rustc --check-cfg 'names()'
+    /// rustc --check-cfg 'cfg()'
     /// ```
     ///
     /// ```rust,ignore (needs command line option)
@@ -3146,7 +3275,7 @@ declare_lint! {
     /// This will produce:
     ///
     /// ```text
-    /// warning: unknown condition name used
+    /// warning: unexpected `cfg` condition name: `widnows`
     ///  --> lint_example.rs:1:7
     ///   |
     /// 1 | #[cfg(widnows)]
@@ -3157,9 +3286,10 @@ declare_lint! {
     ///
     /// ### Explanation
     ///
-    /// This lint is only active when a `--check-cfg='names(...)'` option has been passed
-    /// to the compiler and triggers whenever an unknown condition name or value is used.
-    /// The known condition include names or values passed in `--check-cfg`, `--cfg`, and some
+    /// This lint is only active when `--check-cfg` arguments are being passed
+    /// to the compiler and triggers whenever an unexpected condition name or value is used.
+    ///
+    /// The known condition include names or values passed in `--check-cfg`, and some
     /// well-knows names and values built into the compiler.
     pub UNEXPECTED_CFGS,
     Warn,
@@ -3348,134 +3478,6 @@ declare_lint! {
     "name introduced by a private item shadows a name introduced by a public glob re-export",
 }
 
-declare_lint_pass! {
-    /// Does nothing as a lint pass, but registers some `Lint`s
-    /// that are used by other parts of the compiler.
-    HardwiredLints => [
-        // tidy-alphabetical-start
-        ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
-        AMBIGUOUS_ASSOCIATED_ITEMS,
-        AMBIGUOUS_GLOB_IMPORTS,
-        AMBIGUOUS_GLOB_REEXPORTS,
-        ARITHMETIC_OVERFLOW,
-        ASM_SUB_REGISTER,
-        BAD_ASM_STYLE,
-        BARE_TRAIT_OBJECTS,
-        BINDINGS_WITH_VARIANT_NAME,
-        BREAK_WITH_LABEL_AND_LOOP,
-        BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
-        CENUM_IMPL_DROP_CAST,
-        COHERENCE_LEAK_CHECK,
-        COINDUCTIVE_OVERLAP_IN_COHERENCE,
-        CONFLICTING_REPR_HINTS,
-        CONST_EVALUATABLE_UNCHECKED,
-        CONST_ITEM_MUTATION,
-        CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
-        DEAD_CODE,
-        DEPRECATED,
-        DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
-        DEPRECATED_IN_FUTURE,
-        DEPRECATED_WHERE_CLAUSE_LOCATION,
-        DUPLICATE_MACRO_ATTRIBUTES,
-        ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
-        ELIDED_LIFETIMES_IN_PATHS,
-        EXPORTED_PRIVATE_DEPENDENCIES,
-        FFI_UNWIND_CALLS,
-        FORBIDDEN_LINT_GROUPS,
-        FUNCTION_ITEM_REFERENCES,
-        FUZZY_PROVENANCE_CASTS,
-        HIDDEN_GLOB_REEXPORTS,
-        ILL_FORMED_ATTRIBUTE_INPUT,
-        ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-        IMPLIED_BOUNDS_ENTAILMENT,
-        INCOMPLETE_INCLUDE,
-        INDIRECT_STRUCTURAL_MATCH,
-        INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
-        INLINE_NO_SANITIZE,
-        INVALID_DOC_ATTRIBUTES,
-        INVALID_MACRO_EXPORT_ARGUMENTS,
-        INVALID_TYPE_PARAM_DEFAULT,
-        IRREFUTABLE_LET_PATTERNS,
-        LARGE_ASSIGNMENTS,
-        LATE_BOUND_LIFETIME_ARGUMENTS,
-        LEGACY_DERIVE_HELPERS,
-        LONG_RUNNING_CONST_EVAL,
-        LOSSY_PROVENANCE_CASTS,
-        MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
-        MACRO_USE_EXTERN_CRATE,
-        META_VARIABLE_MISUSE,
-        MISSING_ABI,
-        MISSING_FRAGMENT_SPECIFIER,
-        MUST_NOT_SUSPEND,
-        NAMED_ARGUMENTS_USED_POSITIONALLY,
-        NON_EXHAUSTIVE_OMITTED_PATTERNS,
-        NONTRIVIAL_STRUCTURAL_MATCH,
-        ORDER_DEPENDENT_TRAIT_OBJECTS,
-        OVERLAPPING_RANGE_ENDPOINTS,
-        PATTERNS_IN_FNS_WITHOUT_BODY,
-        POINTER_STRUCTURAL_MATCH,
-        PRIVATE_BOUNDS,
-        PRIVATE_INTERFACES,
-        PROC_MACRO_BACK_COMPAT,
-        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-        PUB_USE_OF_PRIVATE_EXTERN_CRATE,
-        REFINING_IMPL_TRAIT,
-        RENAMED_AND_REMOVED_LINTS,
-        REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
-        RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
-        RUST_2021_INCOMPATIBLE_OR_PATTERNS,
-        RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
-        RUST_2021_PRELUDE_COLLISIONS,
-        SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
-        SINGLE_USE_LIFETIMES,
-        SOFT_UNSTABLE,
-        STABLE_FEATURES,
-        SUSPICIOUS_AUTO_TRAIT_IMPLS,
-        TEST_UNSTABLE_LINT,
-        TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
-        TRIVIAL_CASTS,
-        TRIVIAL_NUMERIC_CASTS,
-        TYVAR_BEHIND_RAW_POINTER,
-        UNCONDITIONAL_PANIC,
-        UNCONDITIONAL_RECURSION,
-        UNDEFINED_NAKED_FUNCTION_ABI,
-        UNEXPECTED_CFGS,
-        UNFULFILLED_LINT_EXPECTATIONS,
-        UNINHABITED_STATIC,
-        UNKNOWN_CRATE_TYPES,
-        UNKNOWN_LINTS,
-        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-        UNNAMEABLE_TEST_ITEMS,
-        UNNAMEABLE_TYPES,
-        UNREACHABLE_CODE,
-        UNREACHABLE_PATTERNS,
-        UNSAFE_OP_IN_UNSAFE_FN,
-        UNSTABLE_NAME_COLLISIONS,
-        UNSTABLE_SYNTAX_PRE_EXPANSION,
-        UNSUPPORTED_CALLING_CONVENTIONS,
-        UNUSED_ASSIGNMENTS,
-        UNUSED_ASSOCIATED_TYPE_BOUNDS,
-        UNUSED_ATTRIBUTES,
-        UNUSED_CRATE_DEPENDENCIES,
-        UNUSED_EXTERN_CRATES,
-        UNUSED_FEATURES,
-        UNUSED_IMPORTS,
-        UNUSED_LABELS,
-        UNUSED_LIFETIMES,
-        UNUSED_MACRO_RULES,
-        UNUSED_MACROS,
-        UNUSED_MUT,
-        UNUSED_QUALIFICATIONS,
-        UNUSED_TUPLE_STRUCT_FIELDS,
-        UNUSED_UNSAFE,
-        UNUSED_VARIABLES,
-        USELESS_DEPRECATED,
-        WARNINGS,
-        WHERE_CLAUSES_OBJECT_SAFETY,
-        // tidy-alphabetical-end
-    ]
-}
-
 declare_lint! {
     /// The `long_running_const_eval` lint is emitted when const
     /// eval is running for a long time to ensure rustc terminates
@@ -4620,3 +4622,37 @@ declare_lint! {
         reference: "issue #115010 <https://github.com/rust-lang/rust/issues/115010>",
     };
 }
+
+declare_lint! {
+    /// The `writes_through_immutable_pointer` lint detects writes through pointers derived from
+    /// shared references.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![feature(const_mut_refs)]
+    /// const WRITE_AFTER_CAST: () = unsafe {
+    ///     let mut x = 0;
+    ///     let ptr = &x as *const i32 as *mut i32;
+    ///     *ptr = 0;
+    /// };
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Shared references are immutable (when there is no `UnsafeCell` involved),
+    /// and writing through them or through pointers derived from them is Undefined Behavior.
+    /// The compiler recently learned to detect such Undefined Behavior during compile-time
+    /// evaluation, and in the future this will raise a hard error.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub WRITES_THROUGH_IMMUTABLE_POINTER,
+    Warn,
+    "shared references are immutable, and pointers derived from them must not be written to",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
+        reference: "issue #X <https://github.com/rust-lang/rust/issues/X>",
+    };
+}
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index ed1e8771323..4b0c1229da1 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -102,7 +102,7 @@ fn output(cmd: &mut Command) -> String {
 
 fn main() {
     for component in REQUIRED_COMPONENTS.iter().chain(OPTIONAL_COMPONENTS.iter()) {
-        println!("cargo:rustc-check-cfg=values(llvm_component,\"{component}\")");
+        println!("cargo:rustc-check-cfg=cfg(llvm_component,values(\"{component}\"))");
     }
 
     if tracked_env_var_os("RUST_CHECK").is_some() {
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 834120efa67..5bfffc5d911 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -1,3 +1,5 @@
+#include "SuppressLLVMWarnings.h"
+
 #include "llvm-c/BitReader.h"
 #include "llvm-c/Core.h"
 #include "llvm-c/Object.h"
diff --git a/compiler/rustc_llvm/llvm-wrapper/Linker.cpp b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp
index 8766e96f086..533df0f75f8 100644
--- a/compiler/rustc_llvm/llvm-wrapper/Linker.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp
@@ -1,3 +1,4 @@
+#include "SuppressLLVMWarnings.h"
 #include "llvm/Linker/Linker.h"
 
 #include "LLVMWrapper.h"
diff --git a/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h b/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h
new file mode 100644
index 00000000000..56964e4eaa7
--- /dev/null
+++ b/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h
@@ -0,0 +1,13 @@
+#ifndef _rustc_llvm_SuppressLLVMWarnings_h
+#define _rustc_llvm_SuppressLLVMWarnings_h
+
+// LLVM currently generates many warnings when compiled using MSVC. These warnings make it difficult
+// to diagnose real problems when working on C++ code, so we suppress them.
+
+#ifdef _MSC_VER
+#pragma warning(disable:4530) // C++ exception handler used, but unwind semantics are not enabled.
+#pragma warning(disable:4624) // 'xxx': destructor was implicitly defined as deleted
+#pragma warning(disable:4244) // conversion from 'xxx' to 'yyy', possible loss of data
+#endif
+
+#endif // _rustc_llvm_SuppressLLVMWarnings_h
diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
index bf00d11edf6..91f84692df8 100644
--- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
@@ -7,6 +7,7 @@
 // * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/include/llvm/Object/ArchiveWriter.h
 // * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/lib/Object/ArchiveWriter.cpp
 
+#include "SuppressLLVMWarnings.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/Object/ObjectFile.h"
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index d38df1b7201..26138157b74 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -75,7 +75,7 @@ static_assert_size!(ConstValue<'_>, 24);
 
 impl<'tcx> ConstValue<'tcx> {
     #[inline]
-    pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
+    pub fn try_to_scalar(&self) -> Option<Scalar> {
         match *self {
             ConstValue::Indirect { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
             ConstValue::Scalar(val) => Some(val),
@@ -161,8 +161,8 @@ impl<'tcx> ConstValue<'tcx> {
                     return Some(&[]);
                 }
                 // Non-empty slice, must have memory. We know this is a relative pointer.
-                let (inner_alloc_id, offset) = ptr.into_parts();
-                let data = tcx.global_alloc(inner_alloc_id?).unwrap_memory();
+                let (inner_prov, offset) = ptr.into_parts();
+                let data = tcx.global_alloc(inner_prov?.alloc_id()).unwrap_memory();
                 (data, offset.bytes(), offset.bytes() + len)
             }
         };
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 09e56b2e4a8..2a9e0847f43 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -18,9 +18,9 @@ use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
 use super::{
-    read_target_uint, write_target_uint, AllocId, BadBytesAccess, InterpError, InterpResult,
-    Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch,
-    UndefinedBehaviorInfo, UnsupportedOpInfo,
+    read_target_uint, write_target_uint, AllocId, BadBytesAccess, CtfeProvenance, InterpError,
+    InterpResult, Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar,
+    ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo,
 };
 use crate::ty;
 use init_mask::*;
@@ -63,7 +63,7 @@ impl AllocBytes for Box<[u8]> {
 // hashed. (see the `Hash` impl below for more details), so the impl is not derived.
 #[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
-pub struct Allocation<Prov: Provenance = AllocId, Extra = (), Bytes = Box<[u8]>> {
+pub struct Allocation<Prov: Provenance = CtfeProvenance, Extra = (), Bytes = Box<[u8]>> {
     /// The actual bytes of the allocation.
     /// Note that the bytes of a pointer represent the offset of the pointer.
     bytes: Bytes,
@@ -336,14 +336,14 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
     }
 }
 
-impl<Bytes: AllocBytes> Allocation<AllocId, (), Bytes> {
-    /// Adjust allocation from the ones in tcx to a custom Machine instance
-    /// with a different Provenance and Extra type.
+impl<Bytes: AllocBytes> Allocation<CtfeProvenance, (), Bytes> {
+    /// 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: Provenance, Extra, Err>(
         self,
         cx: &impl HasDataLayout,
         extra: Extra,
-        mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>,
+        mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> Result<Pointer<Prov>, Err>,
     ) -> Result<Allocation<Prov, Extra, Bytes>, Err> {
         let mut bytes = self.bytes;
         // Adjust provenance of pointers stored in this allocation.
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
index d504af6b7ea..9459af490e3 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
@@ -6,14 +6,14 @@ use std::cmp;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_target::abi::{HasDataLayout, Size};
 
-use super::{alloc_range, AllocError, AllocId, AllocRange, AllocResult, Provenance};
+use super::{alloc_range, AllocError, AllocRange, AllocResult, CtfeProvenance, Provenance};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
 /// Stores the provenance information of pointers stored in memory.
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 #[derive(HashStable)]
-pub struct ProvenanceMap<Prov = AllocId> {
-    /// Provenance in this map applies from the given offset for an entire pointer-size worth of
+pub struct ProvenanceMap<Prov = CtfeProvenance> {
+    /// `Provenance` in this map applies from the given offset for an entire pointer-size worth of
     /// bytes. Two entries in this map are always at least a pointer size apart.
     ptrs: SortedMap<Size, Prov>,
     /// Provenance in this map only applies to the given single byte.
@@ -22,18 +22,19 @@ pub struct ProvenanceMap<Prov = AllocId> {
     bytes: Option<Box<SortedMap<Size, Prov>>>,
 }
 
+// These impls are generic over `Prov` since `CtfeProvenance` is only decodable/encodable
+// for some particular `D`/`S`.
 impl<D: Decoder, Prov: Provenance + Decodable<D>> Decodable<D> for ProvenanceMap<Prov> {
     fn decode(d: &mut D) -> Self {
-        assert!(!Prov::OFFSET_IS_ADDR); // only `AllocId` is ever serialized
+        assert!(!Prov::OFFSET_IS_ADDR); // only `CtfeProvenance` is ever serialized
         Self { ptrs: Decodable::decode(d), bytes: None }
     }
 }
-
 impl<S: Encoder, Prov: Provenance + Encodable<S>> Encodable<S> for ProvenanceMap<Prov> {
     fn encode(&self, s: &mut S) {
         let Self { ptrs, bytes } = self;
-        assert!(!Prov::OFFSET_IS_ADDR); // only `AllocId` is ever serialized
-        debug_assert!(bytes.is_none());
+        assert!(!Prov::OFFSET_IS_ADDR); // only `CtfeProvenance` is ever serialized
+        debug_assert!(bytes.is_none()); // without `OFFSET_IS_ADDR`, this is always empty
         ptrs.encode(s)
     }
 }
@@ -54,10 +55,10 @@ impl ProvenanceMap {
     /// Give access to the ptr-sized provenances (which can also be thought of as relocations, and
     /// indeed that is how codegen treats them).
     ///
-    /// Only exposed with `AllocId` provenance, since it panics if there is bytewise provenance.
+    /// Only exposed with `CtfeProvenance` provenance, since it panics if there is bytewise provenance.
     #[inline]
-    pub fn ptrs(&self) -> &SortedMap<Size, AllocId> {
-        debug_assert!(self.bytes.is_none()); // `AllocId::OFFSET_IS_ADDR` is false so this cannot fail
+    pub fn ptrs(&self) -> &SortedMap<Size, CtfeProvenance> {
+        debug_assert!(self.bytes.is_none()); // `CtfeProvenance::OFFSET_IS_ADDR` is false so this cannot fail
         &self.ptrs
     }
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 44b22e2d383..41386793987 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -290,7 +290,7 @@ macro_rules! impl_into_diagnostic_arg_through_debug {
 // These types have nice `Debug` output so we can just use them in diagnostics.
 impl_into_diagnostic_arg_through_debug! {
     AllocId,
-    Pointer,
+    Pointer<AllocId>,
     AllocRange,
 }
 
@@ -323,7 +323,7 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     /// Invalid metadata in a wide pointer
     InvalidMeta(InvalidMetaKind),
     /// Reading a C string that does not end within its allocation.
-    UnterminatedCString(Pointer),
+    UnterminatedCString(Pointer<AllocId>),
     /// Using a pointer after it got freed.
     PointerUseAfterFree(AllocId, CheckInAllocMsg),
     /// Used a pointer outside the bounds it is valid for.
@@ -350,11 +350,11 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     /// Using a non-character `u32` as character.
     InvalidChar(u32),
     /// The tag of an enum does not encode an actual discriminant.
-    InvalidTag(Scalar),
+    InvalidTag(Scalar<AllocId>),
     /// Using a pointer-not-to-a-function as function pointer.
-    InvalidFunctionPointer(Pointer),
+    InvalidFunctionPointer(Pointer<AllocId>),
     /// Using a pointer-not-to-a-vtable as vtable pointer.
-    InvalidVTablePointer(Pointer),
+    InvalidVTablePointer(Pointer<AllocId>),
     /// Using a string that is not valid UTF-8,
     InvalidStr(std::str::Utf8Error),
     /// Using uninitialized data where it is not allowed.
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index e5f891fcc91..2db56008553 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -157,7 +157,7 @@ pub use self::allocation::{
     InitChunk, InitChunkIter,
 };
 
-pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
+pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
 
 /// Uniquely identifies one of the following:
 /// - A constant
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 1c9ce1cb130..6893387736a 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -3,7 +3,7 @@ use super::{AllocId, InterpResult};
 use rustc_macros::HashStable;
 use rustc_target::abi::{HasDataLayout, Size};
 
-use std::fmt;
+use std::{fmt, num::NonZeroU64};
 
 ////////////////////////////////////////////////////////////////////////////////
 // Pointer arithmetic
@@ -114,22 +114,7 @@ pub trait Provenance: Copy + fmt::Debug + 'static {
     const OFFSET_IS_ADDR: bool;
 
     /// Determines how a pointer should be printed.
-    ///
-    /// Default impl is only good for when `OFFSET_IS_ADDR == true`.
-    fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
-    where
-        Self: Sized,
-    {
-        assert!(Self::OFFSET_IS_ADDR);
-        let (prov, addr) = ptr.into_parts(); // address is absolute
-        write!(f, "{:#x}", addr.bytes())?;
-        if f.alternate() {
-            write!(f, "{prov:#?}")?;
-        } else {
-            write!(f, "{prov:?}")?;
-        }
-        Ok(())
-    }
+    fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
 
     /// If `OFFSET_IS_ADDR == false`, provenance must always be able to
     /// identify the allocation this ptr points to (i.e., this must return `Some`).
@@ -141,6 +126,80 @@ pub trait Provenance: Copy + fmt::Debug + 'static {
     fn join(left: Option<Self>, right: Option<Self>) -> Option<Self>;
 }
 
+/// The type of provenance in the compile-time interpreter.
+/// This is a packed representation of an `AllocId` and an `immutable: bool`.
+#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct CtfeProvenance(NonZeroU64);
+
+impl From<AllocId> for CtfeProvenance {
+    fn from(value: AllocId) -> Self {
+        let prov = CtfeProvenance(value.0);
+        assert!(!prov.immutable(), "`AllocId` with the highest bit set cannot be used in CTFE");
+        prov
+    }
+}
+
+impl fmt::Debug for CtfeProvenance {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&self.alloc_id(), f)?; // propagates `alternate` flag
+        if self.immutable() {
+            write!(f, "<imm>")?;
+        }
+        Ok(())
+    }
+}
+
+const IMMUTABLE_MASK: u64 = 1 << 63; // the highest bit
+
+impl CtfeProvenance {
+    /// Returns the `AllocId` of this provenance.
+    #[inline(always)]
+    pub fn alloc_id(self) -> AllocId {
+        AllocId(NonZeroU64::new(self.0.get() & !IMMUTABLE_MASK).unwrap())
+    }
+
+    /// Returns whether this provenance is immutable.
+    #[inline]
+    pub fn immutable(self) -> bool {
+        self.0.get() & IMMUTABLE_MASK != 0
+    }
+
+    /// Returns an immutable version of this provenance.
+    #[inline]
+    pub fn as_immutable(self) -> Self {
+        CtfeProvenance(self.0 | IMMUTABLE_MASK)
+    }
+}
+
+impl Provenance for CtfeProvenance {
+    // With the `AllocId` as provenance, the `offset` is interpreted *relative to the allocation*,
+    // so ptr-to-int casts are not possible (since we do not know the global physical offset).
+    const OFFSET_IS_ADDR: bool = false;
+
+    fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Print AllocId.
+        fmt::Debug::fmt(&ptr.provenance.alloc_id(), f)?; // propagates `alternate` flag
+        // Print offset only if it is non-zero.
+        if ptr.offset.bytes() > 0 {
+            write!(f, "+{:#x}", ptr.offset.bytes())?;
+        }
+        // Print immutable status.
+        if ptr.provenance.immutable() {
+            write!(f, "<imm>")?;
+        }
+        Ok(())
+    }
+
+    fn get_alloc_id(self) -> Option<AllocId> {
+        Some(self.alloc_id())
+    }
+
+    fn join(_left: Option<Self>, _right: Option<Self>) -> Option<Self> {
+        panic!("merging provenance is not supported when `OFFSET_IS_ADDR` is false")
+    }
+}
+
+// We also need this impl so that one can debug-print `Pointer<AllocId>`
 impl Provenance for AllocId {
     // With the `AllocId` as provenance, the `offset` is interpreted *relative to the allocation*,
     // so ptr-to-int casts are not possible (since we do not know the global physical offset).
@@ -174,7 +233,7 @@ impl Provenance for AllocId {
 /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
 #[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
-pub struct Pointer<Prov = AllocId> {
+pub struct Pointer<Prov = CtfeProvenance> {
     pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Prov` type)
     pub provenance: Prov,
 }
@@ -182,7 +241,7 @@ pub struct Pointer<Prov = AllocId> {
 static_assert_size!(Pointer, 16);
 // `Option<Prov>` pointers are also passed around quite a bit
 // (but not stored in permanent machine state).
-static_assert_size!(Pointer<Option<AllocId>>, 16);
+static_assert_size!(Pointer<Option<CtfeProvenance>>, 16);
 
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
 // all the Miri types.
@@ -215,7 +274,7 @@ impl<Prov: Provenance> fmt::Display for Pointer<Option<Prov>> {
 impl From<AllocId> for Pointer {
     #[inline(always)]
     fn from(alloc_id: AllocId) -> Self {
-        Pointer::new(alloc_id, Size::ZERO)
+        Pointer::new(alloc_id.into(), Size::ZERO)
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 0d548f88636..5ecff04f3ae 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -11,7 +11,10 @@ use rustc_target::abi::{HasDataLayout, Size};
 
 use crate::ty::ScalarInt;
 
-use super::{AllocId, InterpResult, Pointer, PointerArithmetic, Provenance, ScalarSizeMismatch};
+use super::{
+    AllocId, CtfeProvenance, InterpResult, Pointer, PointerArithmetic, Provenance,
+    ScalarSizeMismatch,
+};
 
 /// A `Scalar` represents an immediate, primitive value existing outside of a
 /// `memory::Allocation`. It is in many ways like a small chunk of an `Allocation`, up to 16 bytes in
@@ -22,7 +25,7 @@ use super::{AllocId, InterpResult, Pointer, PointerArithmetic, Provenance, Scala
 /// Do *not* match on a `Scalar`! Use the various `to_*` methods instead.
 #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
-pub enum Scalar<Prov = AllocId> {
+pub enum Scalar<Prov = CtfeProvenance> {
     /// The raw bytes of a simple value.
     Int(ScalarInt),
 
@@ -267,6 +270,9 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
     /// Will perform ptr-to-int casts if needed and possible.
     /// If that fails, we know the offset is relative, so we return an "erased" Scalar
     /// (which is useful for error messages but not much else).
+    ///
+    /// The error type is `AllocId`, not `CtfeProvenance`, since `AllocId` is the "minimal"
+    /// component all provenance types must have.
     #[inline]
     pub fn try_to_int(self) -> Result<ScalarInt, Scalar<AllocId>> {
         match self {
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 1974a35cb85..bfaa0d88fc0 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1337,13 +1337,13 @@ pub fn write_allocations<'tcx>(
     fn alloc_ids_from_alloc(
         alloc: ConstAllocation<'_>,
     ) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
-        alloc.inner().provenance().ptrs().values().copied()
+        alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id())
     }
 
     fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
         match val {
             ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
-                Either::Left(std::iter::once(ptr.provenance))
+                Either::Left(std::iter::once(ptr.provenance.alloc_id()))
             }
             ConstValue::Scalar(interpret::Scalar::Int { .. }) => Either::Right(std::iter::empty()),
             ConstValue::ZeroSized => Either::Right(std::iter::empty()),
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index be35a54be58..f929a5cec25 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -381,7 +381,7 @@ impl<'tcx> Operand<'tcx> {
 impl<'tcx> ConstOperand<'tcx> {
     pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
         match self.const_.try_to_scalar() {
-            Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
+            Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance.alloc_id()) {
                 GlobalAlloc::Static(def_id) => {
                     assert!(!tcx.is_thread_local_static(def_id));
                     Some(def_id)
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index cdde6a596a8..b9200f1abf1 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -264,6 +264,7 @@ trivial! {
     rustc_middle::middle::stability::DeprecationEntry,
     rustc_middle::mir::ConstQualifs,
     rustc_middle::mir::interpret::AllocId,
+    rustc_middle::mir::interpret::CtfeProvenance,
     rustc_middle::mir::interpret::ErrorHandled,
     rustc_middle::mir::interpret::LitToConstError,
     rustc_middle::thir::ExprId,
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index f33421bbaa6..96ed1a4d0be 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -180,8 +180,8 @@ pub enum SelectionCandidate<'tcx> {
 ///
 /// The evaluation results are ordered:
 ///     - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
-///       implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
-///     - `EvaluatedToErr` implies `EvaluatedToRecur`
+///       implies `EvaluatedToAmbig` implies `EvaluatedToAmbigStackDependent`
+///     - `EvaluatedToErr` implies `EvaluatedToErrStackDependent`
 ///     - the "union" of evaluation results is equal to their maximum -
 ///     all the "potential success" candidates can potentially succeed,
 ///     so they are noops when unioned with a definite error, and within
@@ -199,7 +199,7 @@ pub enum EvaluationResult {
     /// Evaluation is known to be ambiguous -- it *might* hold for some
     /// assignment of inference variables, but it might not.
     ///
-    /// While this has the same meaning as `EvaluatedToUnknown` -- we can't
+    /// While this has the same meaning as `EvaluatedToAmbigStackDependent` -- we can't
     /// know whether this obligation holds or not -- it is the result we
     /// would get with an empty stack, and therefore is cacheable.
     EvaluatedToAmbig,
@@ -207,8 +207,8 @@ pub enum EvaluationResult {
     /// variables. We are somewhat imprecise there, so we don't actually
     /// know the real result.
     ///
-    /// This can't be trivially cached for the same reason as `EvaluatedToRecur`.
-    EvaluatedToUnknown,
+    /// This can't be trivially cached for the same reason as `EvaluatedToErrStackDependent`.
+    EvaluatedToAmbigStackDependent,
     /// Evaluation failed because we encountered an obligation we are already
     /// trying to prove on this branch.
     ///
@@ -247,12 +247,12 @@ pub enum EvaluationResult {
     /// does not hold, because of the bound (which can indeed be satisfied
     /// by `SomeUnsizedType` from another crate).
     //
-    // FIXME: when an `EvaluatedToRecur` goes past its parent root, we
+    // FIXME: when an `EvaluatedToErrStackDependent` goes past its parent root, we
     // ought to convert it to an `EvaluatedToErr`, because we know
     // there definitely isn't a proof tree for that obligation. Not
     // doing so is still sound -- there isn't any proof tree, so the
     // branch still can't be a part of a minimal one -- but does not re-enable caching.
-    EvaluatedToRecur,
+    EvaluatedToErrStackDependent,
     /// Evaluation failed.
     EvaluatedToErr,
 }
@@ -276,15 +276,15 @@ impl EvaluationResult {
             | EvaluatedToOk
             | EvaluatedToOkModuloRegions
             | EvaluatedToAmbig
-            | EvaluatedToUnknown => true,
+            | EvaluatedToAmbigStackDependent => true,
 
-            EvaluatedToErr | EvaluatedToRecur => false,
+            EvaluatedToErr | EvaluatedToErrStackDependent => false,
         }
     }
 
     pub fn is_stack_dependent(self) -> bool {
         match self {
-            EvaluatedToUnknown | EvaluatedToRecur => true,
+            EvaluatedToAmbigStackDependent | EvaluatedToErrStackDependent => true,
 
             EvaluatedToOkModuloOpaqueTypes
             | EvaluatedToOk
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 81cf41889d4..69ae05ca820 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -8,6 +8,7 @@
 
 use crate::arena::ArenaAllocatable;
 use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
+use crate::mir::interpret::CtfeProvenance;
 use crate::mir::{
     self,
     interpret::{AllocId, ConstAllocation},
@@ -164,6 +165,13 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId {
     }
 }
 
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for CtfeProvenance {
+    fn encode(&self, e: &mut E) {
+        self.alloc_id().encode(e);
+        self.immutable().encode(e);
+    }
+}
+
 impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::ParamEnv<'tcx> {
     fn encode(&self, e: &mut E) {
         self.caller_bounds().encode(e);
@@ -295,6 +303,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AllocId {
     }
 }
 
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for CtfeProvenance {
+    fn decode(decoder: &mut D) -> Self {
+        let alloc_id: AllocId = Decodable::decode(decoder);
+        let prov = CtfeProvenance::from(alloc_id);
+        let immutable: bool = Decodable::decode(decoder);
+        if immutable { prov.as_immutable() } else { prov }
+    }
+}
+
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::SymbolName<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         ty::SymbolName::new(decoder.interner(), decoder.read_str())
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index a216cc28c8a..e48840fac20 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,5 +1,5 @@
 use crate::middle::resolve_bound_vars as rbv;
-use crate::mir::interpret::{AllocId, ErrorHandled, LitToConstInput, Scalar};
+use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
 use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
@@ -413,7 +413,7 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
+    pub fn try_to_scalar(self) -> Option<Scalar> {
         self.try_to_valtree()?.try_to_scalar()
     }
 
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index fb7bf78bafe..ffa0e89c473 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -1,5 +1,5 @@
 use super::ScalarInt;
-use crate::mir::interpret::{AllocId, Scalar};
+use crate::mir::interpret::Scalar;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 
@@ -67,7 +67,7 @@ impl<'tcx> ValTree<'tcx> {
         Self::Leaf(i)
     }
 
-    pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
+    pub fn try_to_scalar(self) -> Option<Scalar> {
         self.try_to_scalar_int().map(Scalar::Int)
     }
 
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index 59c0639fea2..129d947697e 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -84,6 +84,14 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
     }
 }
 
+// CtfeProvenance is an AllocId and a bool.
+impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::CtfeProvenance {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        self.alloc_id().hash_stable(hcx, hasher);
+        self.immutable().hash_stable(hcx, hasher);
+    }
+}
+
 impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope {
     type KeyType = region::Scope;
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 9feda4d205e..77196486ac1 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -98,9 +98,8 @@ pub use self::sty::{
     CoroutineArgs, CoroutineArgsParts, EarlyParamRegion, ExistentialPredicate,
     ExistentialProjection, ExistentialTraitRef, FnSig, GenSig, InlineConstArgs,
     InlineConstArgsParts, LateParamRegion, ParamConst, ParamTy, PolyExistentialPredicate,
-    PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef,
-    PredicateKind, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs,
-    VarianceDiagInfo,
+    PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyTraitRef, PredicateKind,
+    Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
@@ -2614,9 +2613,7 @@ pub struct SymbolName<'tcx> {
 
 impl<'tcx> SymbolName<'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, name: &str) -> SymbolName<'tcx> {
-        SymbolName {
-            name: unsafe { str::from_utf8_unchecked(tcx.arena.alloc_slice(name.as_bytes())) },
-        }
+        SymbolName { name: tcx.arena.alloc_str(name) }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 63b706e6b3d..1592d852bc7 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1410,14 +1410,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
     ) -> Result<(), PrintError> {
         define_scoped_cx!(self);
 
-        let (alloc_id, offset) = ptr.into_parts();
+        let (prov, offset) = ptr.into_parts();
         match ty.kind() {
             // Byte strings (&[u8; N])
             ty::Ref(_, inner, _) => {
                 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().try_get_global_alloc(alloc_id) {
+                            match self.tcx().try_get_global_alloc(prov.alloc_id()) {
                                 Some(GlobalAlloc::Memory(alloc)) => {
                                     let len = int.assert_bits(self.tcx().data_layout.pointer_size);
                                     let range =
@@ -1447,7 +1447,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 // 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().try_get_global_alloc(alloc_id)
+                    self.tcx().try_get_global_alloc(prov.alloc_id())
                 {
                     self.typed_value(
                         |this| this.print_value_path(instance.def_id(), instance.args),
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 971acda33e2..0f19a2fd822 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -440,8 +440,9 @@ TrivialTypeTraversalAndLiftImpls! {
     crate::ty::ClosureKind,
     crate::ty::ParamConst,
     crate::ty::ParamTy,
-    interpret::Scalar,
     interpret::AllocId,
+    interpret::CtfeProvenance,
+    interpret::Scalar,
     rustc_target::abi::Size,
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index e10b5706b48..e221b4e8bec 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -468,16 +468,6 @@ impl<'tcx> CoroutineArgs<'tcx> {
         self.split().return_ty.expect_ty()
     }
 
-    /// Returns the "coroutine signature", which consists of its yield
-    /// and return types.
-    ///
-    /// N.B., some bits of the code prefers to see this wrapped in a
-    /// binder, but it never contains bound regions. Probably this
-    /// function should be removed.
-    pub fn poly_sig(self) -> PolyGenSig<'tcx> {
-        ty::Binder::dummy(self.sig())
-    }
-
     /// Returns the "coroutine signature", which consists of its resume, yield
     /// and return types.
     pub fn sig(self) -> GenSig<'tcx> {
@@ -1352,8 +1342,6 @@ pub struct GenSig<'tcx> {
     pub return_ty: Ty<'tcx>,
 }
 
-pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>;
-
 /// Signature of a function type, which we have arbitrarily
 /// decided to use to refer to the input/output types.
 ///
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index b96125de95e..d88b33cc973 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -11,6 +11,7 @@ use rustc_middle::mir::visit::{
     MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
 };
 use rustc_middle::mir::*;
+use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::{def_id::DefId, Span};
@@ -220,7 +221,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     }
 
     fn before_access_global(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         _machine: &Self,
         _alloc_id: AllocId,
         alloc: ConstAllocation<'tcx>,
@@ -240,10 +241,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     }
 
     #[inline(always)]
-    fn expose_ptr(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _ptr: Pointer<AllocId>,
-    ) -> InterpResult<'tcx> {
+    fn expose_ptr(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> {
         throw_machine_stop_str!("exposing pointers isn't supported in ConstProp")
     }
 
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 21b92e6d77c..e9949ebbc87 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -8,6 +8,7 @@ use rustc_hir::def::DefKind;
 use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
+use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::value_analysis::{
@@ -876,7 +877,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
     }
 
     fn before_access_global(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         _machine: &Self,
         _alloc_id: AllocId,
         alloc: ConstAllocation<'tcx>,
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 735960f31b3..1a5979ef714 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -388,7 +388,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                         self.ecx.copy_op(op, &field_dest, /*allow_transmute*/ false).ok()?;
                     }
                     self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?;
-                    self.ecx.alloc_mark_immutable(dest.ptr().provenance.unwrap()).ok()?;
+                    self.ecx
+                        .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
+                        .ok()?;
                     dest.into()
                 } else {
                     return None;
@@ -928,7 +930,8 @@ fn op_to_prop_const<'tcx>(
         }
 
         let pointer = mplace.ptr().into_pointer_or_addr().ok()?;
-        let (alloc_id, offset) = pointer.into_parts();
+        let (prov, offset) = pointer.into_parts();
+        let alloc_id = prov.alloc_id();
         intern_const_alloc_for_constprop(ecx, alloc_id).ok()?;
         if matches!(ecx.tcx.global_alloc(alloc_id), GlobalAlloc::Memory(_)) {
             // `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index b882a038711..3a7cc405ca7 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -385,8 +385,8 @@ fn collect_items_rec<'tcx>(
             recursion_depth_reset = None;
 
             if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
-                for &id in alloc.inner().provenance().ptrs().values() {
-                    collect_alloc(tcx, id, &mut used_items);
+                for &prov in alloc.inner().provenance().ptrs().values() {
+                    collect_alloc(tcx, prov.alloc_id(), &mut used_items);
                 }
             }
 
@@ -1363,9 +1363,9 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
         }
         GlobalAlloc::Memory(alloc) => {
             trace!("collecting {:?} with {:#?}", alloc_id, alloc);
-            for &inner in alloc.inner().provenance().ptrs().values() {
+            for &prov in alloc.inner().provenance().ptrs().values() {
                 rustc_data_structures::stack::ensure_sufficient_stack(|| {
-                    collect_alloc(tcx, inner, output);
+                    collect_alloc(tcx, prov.alloc_id(), output);
                 });
             }
         }
@@ -1440,12 +1440,12 @@ fn collect_const_value<'tcx>(
 ) {
     match value {
         mir::ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => {
-            collect_alloc(tcx, ptr.provenance, output)
+            collect_alloc(tcx, ptr.provenance.alloc_id(), output)
         }
         mir::ConstValue::Indirect { alloc_id, .. } => collect_alloc(tcx, alloc_id, output),
         mir::ConstValue::Slice { data, meta: _ } => {
-            for &id in data.inner().provenance().ptrs().values() {
-                collect_alloc(tcx, id, output);
+            for &prov in data.inner().provenance().ptrs().values() {
+                collect_alloc(tcx, prov.alloc_id(), output);
             }
         }
         _ => {}
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 72e5ca41c78..45f950db5c3 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1733,7 +1733,7 @@ pub(crate) struct ExternItemCannotBeConst {
     #[primary_span]
     pub ident_span: Span,
     #[suggestion(code = "static ", applicability = "machine-applicable")]
-    pub const_span: Span,
+    pub const_span: Option<Span>,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 8a987767dc4..086e8d5cf9b 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1139,9 +1139,11 @@ impl<'a> Parser<'a> {
                     Ok(kind) => kind,
                     Err(kind) => match kind {
                         ItemKind::Const(box ConstItem { ty, expr, .. }) => {
+                            let const_span = Some(span.with_hi(ident.span.lo()))
+                                .filter(|span| span.can_be_used_for_suggestions());
                             self.sess.emit_err(errors::ExternItemCannotBeConst {
                                 ident_span: ident.span,
-                                const_span: span.with_hi(ident.span.lo()),
+                                const_span,
                             });
                             ForeignItemKind::Static(ty, Mutability::Not, expr)
                         }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index e7ec4749efe..9064cb6e875 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -531,44 +531,21 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         macro_ev: EffectiveVisibility,
     ) -> bool {
         if self.macro_reachable.insert((module_def_id, defining_mod)) {
-            self.update_macro_reachable_mod(module_def_id, defining_mod, macro_ev);
+            for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) {
+                if let Res::Def(def_kind, def_id) = child.res
+                    && let Some(def_id) = def_id.as_local()
+                    && child.vis.is_accessible_from(defining_mod, self.tcx)
+                {
+                    let vis = self.tcx.local_visibility(def_id);
+                    self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
+                }
+            }
             true
         } else {
             false
         }
     }
 
-    fn update_macro_reachable_mod(
-        &mut self,
-        module_def_id: LocalModDefId,
-        defining_mod: LocalModDefId,
-        macro_ev: EffectiveVisibility,
-    ) {
-        let module = self.tcx.hir().get_module(module_def_id).0;
-        for item_id in module.item_ids {
-            let def_kind = self.tcx.def_kind(item_id.owner_id);
-            let vis = self.tcx.local_visibility(item_id.owner_id.def_id);
-            self.update_macro_reachable_def(
-                item_id.owner_id.def_id,
-                def_kind,
-                vis,
-                defining_mod,
-                macro_ev,
-            );
-        }
-        for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) {
-            // FIXME: Use module children for the logic above too.
-            if !child.reexport_chain.is_empty()
-                && child.vis.is_accessible_from(defining_mod, self.tcx)
-                && let Res::Def(def_kind, def_id) = child.res
-                && let Some(def_id) = def_id.as_local()
-            {
-                let vis = self.tcx.local_visibility(def_id);
-                self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
-            }
-        }
-    }
-
     fn update_macro_reachable_def(
         &mut self,
         def_id: LocalDefId,
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index a5faaaab639..3f8df16e03f 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -181,6 +181,8 @@ resolve_method_not_member_of_trait =
     method `{$method}` is not a member of trait `{$trait_}`
     .label = not a member of trait `{$trait_}`
 
+resolve_missing_macro_rules_name = maybe you have forgotten to define a name for this `macro_rules!`
+
 resolve_module_only =
     visibility must resolve to a module
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 444110c7e7e..542aff69e34 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -27,10 +27,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
 use thin_vec::{thin_vec, ThinVec};
 
-use crate::errors::{
-    AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
-    ExplicitUnsafeTraits,
-};
+use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion};
+use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName};
 use crate::imports::{Import, ImportKind};
 use crate::late::{PatternSource, Rib};
 use crate::path_names_to_string;
@@ -1421,14 +1419,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             "",
         );
 
+        if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
+            err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span });
+            return;
+        }
+
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
             err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
             return;
         }
+
         if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
             err.subdiagnostic(AddedMacroUse);
             return;
         }
+
         if ident.name == kw::Default
             && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
         {
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 72ff959bbd6..1fdb193e571 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -666,6 +666,13 @@ pub(crate) struct ExplicitUnsafeTraits {
 }
 
 #[derive(Subdiagnostic)]
+#[note(resolve_missing_macro_rules_name)]
+pub(crate) struct MaybeMissingMacroRulesName {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Subdiagnostic)]
 #[help(resolve_added_macro_use)]
 pub(crate) struct AddedMacroUse;
 
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index b28ad671f12..c2306e3ea7d 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -477,6 +477,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             self.per_ns(|this, ns| {
                 let key = BindingKey::new(target, ns);
                 let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false);
+                this.update_resolution(import.parent_scope.module, key, false, |_, resolution| {
+                    resolution.single_imports.remove(&import);
+                })
             });
             self.record_use(target, dummy_binding, false);
         } else if import.imported_module.get().is_none() {
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index 3a7959c332e..f2e646c70f5 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -16,6 +16,8 @@ session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has
 
 session_expr_parentheses_needed = parentheses are required to parse this as an expression
 
+session_failed_to_create_profiler = failed to create profiler: {$err}
+
 session_feature_diagnostic_for_issue =
     see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
 
@@ -73,6 +75,7 @@ session_not_supported = not supported
 session_nul_in_c_str = null characters in C string literals are not supported
 
 session_octal_float_literal_not_supported = octal float literal is not supported
+
 session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
 
 session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist.
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 72c013eb549..7eed59709c8 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -444,3 +444,9 @@ pub(crate) struct FunctionReturnRequiresX86OrX8664;
 #[derive(Diagnostic)]
 #[diag(session_function_return_thunk_extern_requires_non_large_code_model)]
 pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel;
+
+#[derive(Diagnostic)]
+#[diag(session_failed_to_create_profiler)]
+pub struct FailedToCreateProfiler {
+    pub err: String,
+}
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index e9648d0d622..123e9c788f5 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -24,7 +24,7 @@ use rustc_errors::registry::Registry;
 use rustc_errors::{
     error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
     ErrorGuaranteed, FluentBundle, Handler, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
-    SubdiagnosticMessage, TerminalUrl,
+    TerminalUrl,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
@@ -1349,7 +1349,7 @@ fn default_emitter(
 // JUSTIFICATION: literally session construction
 #[allow(rustc::bad_opt_access)]
 pub fn build_session(
-    handler: &EarlyErrorHandler,
+    early_handler: EarlyErrorHandler,
     sopts: config::Options,
     io: CompilerIO,
     bundle: Option<Lrc<rustc_errors::FluentBundle>>,
@@ -1379,12 +1379,13 @@ pub fn build_session(
         None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"),
     };
 
-    let target_cfg = config::build_target_config(handler, &sopts, target_override, &sysroot);
+    let target_cfg = config::build_target_config(&early_handler, &sopts, target_override, &sysroot);
     let host_triple = TargetTriple::from_triple(config::host_triple());
-    let (host, target_warnings) = Target::search(&host_triple, &sysroot)
-        .unwrap_or_else(|e| handler.early_error(format!("Error loading host specification: {e}")));
+    let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| {
+        early_handler.early_error(format!("Error loading host specification: {e}"))
+    });
     for warning in target_warnings.warning_messages() {
-        handler.early_warn(warning)
+        early_handler.early_warn(warning)
     }
 
     let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
@@ -1413,6 +1414,10 @@ pub fn build_session(
         span_diagnostic = span_diagnostic.with_ice_file(ice_file);
     }
 
+    // Now that the proper handler has been constructed, drop the early handler
+    // to prevent accidental use.
+    drop(early_handler);
+
     let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile
     {
         let directory =
@@ -1427,7 +1432,7 @@ pub fn build_session(
         match profiler {
             Ok(profiler) => Some(Arc::new(profiler)),
             Err(e) => {
-                handler.early_warn(format!("failed to create profiler: {e}"));
+                span_diagnostic.emit_warning(errors::FailedToCreateProfiler { err: e.to_string() });
                 None
             }
         }
@@ -1471,7 +1476,13 @@ pub fn build_session(
 
     // Check jobserver before getting `jobserver::client`.
     jobserver::check(|err| {
-        handler.early_warn_with_note(err, "the build environment is likely misconfigured")
+        #[allow(rustc::untranslatable_diagnostic)]
+        #[allow(rustc::diagnostic_outside_of_impl)]
+        parse_sess
+            .span_diagnostic
+            .struct_warn(err)
+            .note("the build environment is likely misconfigured")
+            .emit()
     });
 
     let sess = Session {
@@ -1781,16 +1792,6 @@ impl EarlyErrorHandler {
     pub fn early_warn(&self, msg: impl Into<DiagnosticMessage>) {
         self.handler.struct_warn(msg).emit()
     }
-
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    pub fn early_warn_with_note(
-        &self,
-        msg: impl Into<DiagnosticMessage>,
-        note: impl Into<SubdiagnosticMessage>,
-    ) {
-        self.handler.struct_warn(msg).note(note).emit()
-    }
 }
 
 fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 202ca1b156a..63207200353 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -9,10 +9,12 @@ use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
 use rustc_span::Symbol;
 use stable_mir::mir::alloc::AllocId;
 use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
+use stable_mir::mir::{Mutability, Safety};
 use stable_mir::ty::{
-    AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
-    ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, Span,
-    TraitRef, Ty, UintTy,
+    Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
+    DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
+    GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind,
+    TraitRef, Ty, UintTy, VariantDef, VariantIdx,
 };
 use stable_mir::{CrateItem, DefId};
 
@@ -84,17 +86,38 @@ impl<'tcx> RustcInternal<'tcx> for RigidTy {
             }
             RigidTy::Str => rustc_ty::TyKind::Str,
             RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables)),
-            RigidTy::RawPtr(..)
-            | RigidTy::Ref(..)
-            | RigidTy::Foreign(_)
-            | RigidTy::FnDef(_, _)
-            | RigidTy::FnPtr(_)
-            | RigidTy::Closure(..)
-            | RigidTy::Coroutine(..)
-            | RigidTy::CoroutineWitness(..)
-            | RigidTy::Dynamic(..)
-            | RigidTy::Tuple(..) => {
-                todo!()
+            RigidTy::RawPtr(ty, mutability) => rustc_ty::TyKind::RawPtr(rustc_ty::TypeAndMut {
+                ty: ty.internal(tables),
+                mutbl: mutability.internal(tables),
+            }),
+            RigidTy::Ref(region, ty, mutability) => rustc_ty::TyKind::Ref(
+                region.internal(tables),
+                ty.internal(tables),
+                mutability.internal(tables),
+            ),
+            RigidTy::Foreign(def) => rustc_ty::TyKind::Foreign(def.0.internal(tables)),
+            RigidTy::FnDef(def, args) => {
+                rustc_ty::TyKind::FnDef(def.0.internal(tables), args.internal(tables))
+            }
+            RigidTy::FnPtr(sig) => rustc_ty::TyKind::FnPtr(sig.internal(tables)),
+            RigidTy::Closure(def, args) => {
+                rustc_ty::TyKind::Closure(def.0.internal(tables), args.internal(tables))
+            }
+            RigidTy::Coroutine(def, args, mov) => rustc_ty::TyKind::Coroutine(
+                def.0.internal(tables),
+                args.internal(tables),
+                mov.internal(tables),
+            ),
+            RigidTy::CoroutineWitness(def, args) => {
+                rustc_ty::TyKind::CoroutineWitness(def.0.internal(tables), args.internal(tables))
+            }
+            RigidTy::Dynamic(predicate, region, dyn_kind) => rustc_ty::TyKind::Dynamic(
+                tables.tcx.mk_poly_existential_predicates(&predicate.internal(tables)),
+                region.internal(tables),
+                dyn_kind.internal(tables),
+            ),
+            RigidTy::Tuple(tys) => {
+                rustc_ty::TyKind::Tuple(tables.tcx.mk_type_list(&tys.internal(tables)))
             }
         }
     }
@@ -141,6 +164,57 @@ impl<'tcx> RustcInternal<'tcx> for FloatTy {
     }
 }
 
+impl<'tcx> RustcInternal<'tcx> for Mutability {
+    type T = rustc_ty::Mutability;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            Mutability::Not => rustc_ty::Mutability::Not,
+            Mutability::Mut => rustc_ty::Mutability::Mut,
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for Movability {
+    type T = rustc_ty::Movability;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            Movability::Static => rustc_ty::Movability::Static,
+            Movability::Movable => rustc_ty::Movability::Movable,
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for FnSig {
+    type T = rustc_ty::FnSig<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        rustc_ty::FnSig {
+            inputs_and_output: tables.tcx.mk_type_list(&self.inputs_and_output.internal(tables)),
+            c_variadic: self.c_variadic,
+            unsafety: self.unsafety.internal(tables),
+            abi: self.abi.internal(tables),
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for VariantIdx {
+    type T = rustc_target::abi::VariantIdx;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        rustc_target::abi::VariantIdx::from(self.to_index())
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for VariantDef {
+    type T = &'tcx rustc_ty::VariantDef;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        self.adt_def.internal(tables).variant(self.idx.internal(tables))
+    }
+}
+
 fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Const<'tcx> {
     match constant.internal(tables) {
         rustc_middle::mir::Const::Ty(c) => c,
@@ -230,6 +304,58 @@ impl<'tcx> RustcInternal<'tcx> for BoundVariableKind {
     }
 }
 
+impl<'tcx> RustcInternal<'tcx> for DynKind {
+    type T = rustc_ty::DynKind;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            DynKind::Dyn => rustc_ty::DynKind::Dyn,
+            DynKind::DynStar => rustc_ty::DynKind::DynStar,
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for ExistentialPredicate {
+    type T = rustc_ty::ExistentialPredicate<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            ExistentialPredicate::Trait(trait_ref) => {
+                rustc_ty::ExistentialPredicate::Trait(trait_ref.internal(tables))
+            }
+            ExistentialPredicate::Projection(proj) => {
+                rustc_ty::ExistentialPredicate::Projection(proj.internal(tables))
+            }
+            ExistentialPredicate::AutoTrait(trait_def) => {
+                rustc_ty::ExistentialPredicate::AutoTrait(trait_def.0.internal(tables))
+            }
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for ExistentialProjection {
+    type T = rustc_ty::ExistentialProjection<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        rustc_ty::ExistentialProjection {
+            def_id: self.def_id.0.internal(tables),
+            args: self.generic_args.internal(tables),
+            term: self.term.internal(tables),
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for TermKind {
+    type T = rustc_ty::Term<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            TermKind::Type(ty) => ty.internal(tables).into(),
+            TermKind::Const(const_) => ty_const(const_, tables).into(),
+        }
+    }
+}
+
 impl<'tcx> RustcInternal<'tcx> for ExistentialTraitRef {
     type T = rustc_ty::ExistentialTraitRef<'tcx>;
 
@@ -279,6 +405,53 @@ impl<'tcx> RustcInternal<'tcx> for AdtDef {
     }
 }
 
+impl<'tcx> RustcInternal<'tcx> for Abi {
+    type T = rustc_target::spec::abi::Abi;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match *self {
+            Abi::Rust => rustc_target::spec::abi::Abi::Rust,
+            Abi::C { unwind } => rustc_target::spec::abi::Abi::C { unwind },
+            Abi::Cdecl { unwind } => rustc_target::spec::abi::Abi::Cdecl { unwind },
+            Abi::Stdcall { unwind } => rustc_target::spec::abi::Abi::Stdcall { unwind },
+            Abi::Fastcall { unwind } => rustc_target::spec::abi::Abi::Fastcall { unwind },
+            Abi::Vectorcall { unwind } => rustc_target::spec::abi::Abi::Vectorcall { unwind },
+            Abi::Thiscall { unwind } => rustc_target::spec::abi::Abi::Thiscall { unwind },
+            Abi::Aapcs { unwind } => rustc_target::spec::abi::Abi::Aapcs { unwind },
+            Abi::Win64 { unwind } => rustc_target::spec::abi::Abi::Win64 { unwind },
+            Abi::SysV64 { unwind } => rustc_target::spec::abi::Abi::SysV64 { unwind },
+            Abi::PtxKernel => rustc_target::spec::abi::Abi::PtxKernel,
+            Abi::Msp430Interrupt => rustc_target::spec::abi::Abi::Msp430Interrupt,
+            Abi::X86Interrupt => rustc_target::spec::abi::Abi::X86Interrupt,
+            Abi::AmdGpuKernel => rustc_target::spec::abi::Abi::AmdGpuKernel,
+            Abi::EfiApi => rustc_target::spec::abi::Abi::EfiApi,
+            Abi::AvrInterrupt => rustc_target::spec::abi::Abi::AvrInterrupt,
+            Abi::AvrNonBlockingInterrupt => rustc_target::spec::abi::Abi::AvrNonBlockingInterrupt,
+            Abi::CCmseNonSecureCall => rustc_target::spec::abi::Abi::CCmseNonSecureCall,
+            Abi::Wasm => rustc_target::spec::abi::Abi::Wasm,
+            Abi::System { unwind } => rustc_target::spec::abi::Abi::System { unwind },
+            Abi::RustIntrinsic => rustc_target::spec::abi::Abi::RustIntrinsic,
+            Abi::RustCall => rustc_target::spec::abi::Abi::RustCall,
+            Abi::PlatformIntrinsic => rustc_target::spec::abi::Abi::PlatformIntrinsic,
+            Abi::Unadjusted => rustc_target::spec::abi::Abi::Unadjusted,
+            Abi::RustCold => rustc_target::spec::abi::Abi::RustCold,
+            Abi::RiscvInterruptM => rustc_target::spec::abi::Abi::RiscvInterruptM,
+            Abi::RiscvInterruptS => rustc_target::spec::abi::Abi::RiscvInterruptS,
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for Safety {
+    type T = rustc_hir::Unsafety;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            Safety::Unsafe => rustc_hir::Unsafety::Unsafe,
+            Safety::Normal => rustc_hir::Unsafety::Normal,
+        }
+    }
+}
+
 impl<'tcx> RustcInternal<'tcx> for Span {
     type T = rustc_span::Span;
 
@@ -297,6 +470,7 @@ where
         (*self).internal(tables)
     }
 }
+
 impl<'tcx, T> RustcInternal<'tcx> for Option<T>
 where
     T: RustcInternal<'tcx>,
@@ -307,3 +481,14 @@ where
         self.as_ref().map(|inner| inner.internal(tables))
     }
 }
+
+impl<'tcx, T> RustcInternal<'tcx> for Vec<T>
+where
+    T: RustcInternal<'tcx>,
+{
+    type T = Vec<T::T>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        self.iter().map(|e| e.internal(tables)).collect()
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs
index 63a2a145069..850a52ce275 100644
--- a/compiler/rustc_smir/src/rustc_smir/alloc.rs
+++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs
@@ -47,7 +47,7 @@ pub fn new_allocation<'tcx>(
         }
         ConstValue::Slice { data, meta } => {
             let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data);
-            let ptr = Pointer::new(alloc_id, rustc_target::abi::Size::ZERO);
+            let ptr = Pointer::new(alloc_id.into(), rustc_target::abi::Size::ZERO);
             let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
             let scalar_meta =
                 rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
@@ -112,7 +112,10 @@ pub(super) fn allocation_filter<'tcx>(
         .iter()
         .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end())
     {
-        ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), tables.prov(*prov)));
+        ptrs.push((
+            offset.bytes_usize() - alloc_range.start.bytes_usize(),
+            tables.prov(prov.alloc_id()),
+        ));
     }
     Allocation {
         bytes: bytes,
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 0bd640ee1e3..6dc569b8f6a 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -12,8 +12,8 @@ use stable_mir::mir::alloc::GlobalAlloc;
 use stable_mir::mir::mono::{InstanceDef, StaticDef};
 use stable_mir::mir::Body;
 use stable_mir::ty::{
-    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs, LineInfo,
-    PolyFnSig, RigidTy, Span, TyKind,
+    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
+    LineInfo, PolyFnSig, RigidTy, Span, TyKind, VariantDef,
 };
 use stable_mir::{self, Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol};
 use std::cell::RefCell;
@@ -187,9 +187,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         new_item_kind(tables.tcx.def_kind(tables[item.0]))
     }
 
-    fn is_foreign_item(&self, item: CrateItem) -> bool {
+    fn is_foreign_item(&self, item: DefId) -> bool {
         let tables = self.0.borrow();
-        tables.tcx.is_foreign_item(tables[item.0])
+        tables.tcx.is_foreign_item(tables[item])
     }
 
     fn adt_kind(&self, def: AdtDef) -> AdtKind {
@@ -209,6 +209,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         sig.stable(&mut *tables)
     }
 
+    fn adt_variants_len(&self, def: AdtDef) -> usize {
+        let mut tables = self.0.borrow_mut();
+        def.internal(&mut *tables).variants().len()
+    }
+
+    fn variant_name(&self, def: VariantDef) -> Symbol {
+        let mut tables = self.0.borrow_mut();
+        def.internal(&mut *tables).name.to_string()
+    }
+
+    fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
+        let mut tables = self.0.borrow_mut();
+        def.internal(&mut *tables).fields.iter().map(|f| f.stable(&mut *tables)).collect()
+    }
+
     fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error> {
         let mut tables = self.0.borrow_mut();
         let mir_const = cnst.internal(&mut *tables);
@@ -240,6 +255,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         tables.tcx.type_of(item.internal(&mut *tables)).instantiate_identity().stable(&mut *tables)
     }
 
+    fn def_ty_with_args(&self, item: stable_mir::DefId, args: &GenericArgs) -> stable_mir::ty::Ty {
+        let mut tables = self.0.borrow_mut();
+        let args = args.internal(&mut *tables);
+        let def_ty = tables.tcx.type_of(item.internal(&mut *tables));
+        def_ty.instantiate(tables.tcx, args).stable(&mut *tables)
+    }
+
     fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String {
         internal(cnst).to_string()
     }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 165b8c50e70..0cea3fcc7f7 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -517,7 +517,7 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
             mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => {
                 stable_mir::mir::AggregateKind::Adt(
                     tables.adt_def(*def_id),
-                    var_idx.index(),
+                    var_idx.stable(tables),
                     generic_arg.stable(tables),
                     user_ty_index.map(|idx| idx.index()),
                     field_idx.map(|idx| idx.index()),
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
index edb32df305c..9c0b2b29bca 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
@@ -1,7 +1,7 @@
 //! Conversion of internal Rust compiler items to stable ones.
 
 use rustc_target::abi::FieldIdx;
-use stable_mir::mir::VariantIdx;
+use stable_mir::ty::{IndexedVal, VariantIdx};
 
 use crate::rustc_smir::{Stable, Tables};
 
@@ -25,17 +25,10 @@ impl<'tcx> Stable<'tcx> for FieldIdx {
     }
 }
 
-impl<'tcx> Stable<'tcx> for (rustc_target::abi::VariantIdx, FieldIdx) {
-    type T = (usize, usize);
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        (self.0.as_usize(), self.1.as_usize())
-    }
-}
-
 impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
     type T = VariantIdx;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        self.as_usize()
+        VariantIdx::to_val(self.as_usize())
     }
 }
 
@@ -67,6 +60,14 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
     }
 }
 
+impl<'tcx> Stable<'tcx> for rustc_span::Symbol {
+    type T = stable_mir::Symbol;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        self.to_string()
+    }
+}
+
 impl<'tcx> Stable<'tcx> for rustc_span::Span {
     type T = stable_mir::ty::Span;
 
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index f837f28e11e..4fe847c291c 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -137,6 +137,17 @@ impl<'tcx> Stable<'tcx> for ty::AdtKind {
     }
 }
 
+impl<'tcx> Stable<'tcx> for ty::FieldDef {
+    type T = stable_mir::ty::FieldDef;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        stable_mir::ty::FieldDef {
+            def: tables.create_def_id(self.did),
+            name: self.name.stable(tables),
+        }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> {
     type T = stable_mir::ty::GenericArgs;
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index eee587f3b2a..4cb48a12c96 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -141,3 +141,24 @@ where
         }
     }
 }
+
+impl<'tcx, T> Stable<'tcx> for &[T]
+where
+    T: Stable<'tcx>,
+{
+    type T = Vec<T::T>;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        self.iter().map(|e| e.stable(tables)).collect()
+    }
+}
+
+impl<'tcx, T, U> Stable<'tcx> for (T, U)
+where
+    T: Stable<'tcx>,
+    U: Stable<'tcx>,
+{
+    type T = (T::T, U::T);
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        (self.0.stable(tables), self.1.stable(tables))
+    }
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 2809aaed43c..5c1e703837a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -973,6 +973,7 @@ symbols! {
         managed_boxes,
         manually_drop,
         map,
+        map_err,
         marker,
         marker_trait_attr,
         masked,
@@ -1137,6 +1138,7 @@ symbols! {
         offset,
         offset_of,
         offset_of_enum,
+        ok_or_else,
         omit_gdb_pretty_printer_section,
         on,
         on_unimplemented,
@@ -2117,11 +2119,7 @@ impl Interner {
             return Symbol::new(idx as u32);
         }
 
-        // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena,
-        // and immediately convert the clone back to `&[u8]`, all because there
-        // is no `inner.arena.alloc_str()` method. This is clearly safe.
-        let string: &str =
-            unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) };
+        let string: &str = inner.arena.alloc_str(string);
 
         // SAFETY: we can extend the arena allocation to `'static` because we
         // only access these while the arena is still alive.
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index dbce2f30f93..63002aa4aa4 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1637,6 +1637,7 @@ supported_targets! {
     ("riscv32imc-esp-espidf", riscv32imc_esp_espidf),
     ("riscv32imac-esp-espidf", riscv32imac_esp_espidf),
     ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
+    ("riscv32imafc-unknown-none-elf", riscv32imafc_unknown_none_elf),
     ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf),
     ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
     ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs
index eec2668d487..b490e80258c 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs
@@ -4,7 +4,6 @@ pub fn target() -> Target {
     let mut base = base::teeos::opts();
     base.features = "+strict-align,+neon,+fp-armv8".into();
     base.max_atomic_width = Some(128);
-    base.linker = Some("aarch64-linux-gnu-ld".into());
 
     Target {
         llvm_target: "aarch64-unknown-none".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs
new file mode 100644
index 00000000000..9fb68874ac8
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs
@@ -0,0 +1,24 @@
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
+        llvm_target: "riscv32".into(),
+        pointer_width: 32,
+        arch: "riscv32".into(),
+
+        options: TargetOptions {
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            cpu: "generic-rv32".into(),
+            max_atomic_width: Some(32),
+            llvm_abiname: "ilp32f".into(),
+            features: "+m,+a,+c,+f".into(),
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 992bfd97e0e..4b11cc3ace9 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -29,7 +29,7 @@ pub trait InferCtxtExt<'tcx> {
     /// - the parameter environment
     ///
     /// Invokes `evaluate_obligation`, so in the event that evaluating
-    /// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToUnknown)
+    /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent (or EvaluatedToAmbigStackDependent)
     /// will be returned.
     fn type_implements_trait(
         &self,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 85774013062..090706070eb 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -3,6 +3,7 @@ use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as
 use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch};
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::InferCtxtExt as _;
 use crate::infer::{self, InferCtxt};
 use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt;
 use crate::traits::error_reporting::{ambiguity, ambiguity::Ambiguity::*};
@@ -40,7 +41,7 @@ use rustc_session::config::{DumpSolverProofTree, TraitSolver};
 use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::sym;
-use rustc_span::{ExpnKind, Span, DUMMY_SP};
+use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP};
 use std::borrow::Cow;
 use std::fmt;
 use std::iter;
@@ -106,6 +107,13 @@ pub trait TypeErrCtxtExt<'tcx> {
 
     fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool;
 
+    fn try_conversion_context(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::TraitRef<'tcx>,
+        err: &mut Diagnostic,
+    ) -> bool;
+
     fn report_const_param_not_wf(
         &self,
         ty: Ty<'tcx>,
@@ -509,6 +517,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
                         let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg);
 
+                        let mut suggested = false;
+                        if is_try_conversion {
+                            suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err);
+                        }
+
                         if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
                             err.span_label(
                                 ret_span,
@@ -609,8 +622,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
                         self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref);
                         self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate);
-                        let mut suggested =
-                            self.suggest_dereferences(&obligation, &mut err, trait_predicate);
+                        suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate);
                         suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
                         let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
                         suggested = if let &[cand] = &impl_candidates[..] {
@@ -982,6 +994,223 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         false
     }
 
+    /// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,
+    /// identify thoe method chain sub-expressions that could or could not have been annotated
+    /// with `?`.
+    fn try_conversion_context(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::TraitRef<'tcx>,
+        err: &mut Diagnostic,
+    ) -> bool {
+        let span = obligation.cause.span;
+        struct V<'v> {
+            search_span: Span,
+            found: Option<&'v hir::Expr<'v>>,
+        }
+        impl<'v> Visitor<'v> for V<'v> {
+            fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+                if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind
+                {
+                    if ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span) {
+                        if let hir::ExprKind::Call(_, [expr, ..]) = expr.kind {
+                            self.found = Some(expr);
+                            return;
+                        }
+                    }
+                }
+                hir::intravisit::walk_expr(self, ex);
+            }
+        }
+        let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);
+        let body_id = match self.tcx.hir().find(hir_id) {
+            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
+                body_id
+            }
+            _ => return false,
+        };
+        let mut v = V { search_span: span, found: None };
+        v.visit_body(self.tcx.hir().body(*body_id));
+        let Some(expr) = v.found else {
+            return false;
+        };
+        let Some(typeck) = &self.typeck_results else {
+            return false;
+        };
+        let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent()
+        else {
+            return false;
+        };
+        if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) {
+            return false;
+        }
+        let self_ty = trait_ref.self_ty();
+        let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type());
+
+        let mut prev_ty = self.resolve_vars_if_possible(
+            typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
+        );
+
+        // We always look at the `E` type, because that's the only one affected by `?`. If the
+        // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
+        // expression, after the `?` has "unwrapped" the `T`.
+        let get_e_type = |prev_ty: Ty<'tcx>| -> Option<Ty<'tcx>> {
+            let ty::Adt(def, args) = prev_ty.kind() else {
+                return None;
+            };
+            let Some(arg) = args.get(1) else {
+                return None;
+            };
+            if !self.tcx.is_diagnostic_item(sym::Result, def.did()) {
+                return None;
+            }
+            Some(arg.as_type()?)
+        };
+
+        let mut suggested = false;
+        let mut chain = vec![];
+
+        // The following logic is simlar to `point_at_chain`, but that's focused on associated types
+        let mut expr = expr;
+        while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind {
+            // Point at every method call in the chain with the `Result` type.
+            // let foo = bar.iter().map(mapper)?;
+            //               ------ -----------
+            expr = rcvr_expr;
+            chain.push((span, prev_ty));
+
+            let next_ty = self.resolve_vars_if_possible(
+                typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
+            );
+
+            let is_diagnostic_item = |symbol: Symbol, ty: Ty<'tcx>| {
+                let ty::Adt(def, _) = ty.kind() else {
+                    return false;
+                };
+                self.tcx.is_diagnostic_item(symbol, def.did())
+            };
+            // For each method in the chain, see if this is `Result::map_err` or
+            // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect
+            // trailing `;`.
+            if let Some(ty) = get_e_type(prev_ty)
+                && let Some(found_ty) = found_ty
+                // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100%
+                // accurate check, but we are in the wrong stage to do that and looking for
+                // `Result::map_err` by checking the Self type and the path segment is enough.
+                // sym::ok_or_else
+                && (
+                    ( // Result::map_err
+                        path_segment.ident.name == sym::map_err
+                            && is_diagnostic_item(sym::Result, next_ty)
+                    ) || ( // Option::ok_or_else
+                        path_segment.ident.name == sym::ok_or_else
+                            && is_diagnostic_item(sym::Option, next_ty)
+                    )
+                )
+                // Found `Result<_, ()>?`
+                && let ty::Tuple(tys) = found_ty.kind()
+                && tys.is_empty()
+                // The current method call returns `Result<_, ()>`
+                && self.can_eq(obligation.param_env, ty, found_ty)
+                // There's a single argument in the method call and it is a closure
+                && args.len() == 1
+                && let Some(arg) = args.get(0)
+                && let hir::ExprKind::Closure(closure) = arg.kind
+                // The closure has a block for its body with no tail expression
+                && let body = self.tcx.hir().body(closure.body)
+                && let hir::ExprKind::Block(block, _) = body.value.kind
+                && let None = block.expr
+                // The last statement is of a type that can be converted to the return error type
+                && let [.., stmt] = block.stmts
+                && let hir::StmtKind::Semi(expr) = stmt.kind
+                && let expr_ty = self.resolve_vars_if_possible(
+                    typeck.expr_ty_adjusted_opt(expr)
+                        .unwrap_or(Ty::new_misc_error(self.tcx)),
+                )
+                && self
+                    .infcx
+                    .type_implements_trait(
+                        self.tcx.get_diagnostic_item(sym::From).unwrap(),
+                        [self_ty, expr_ty],
+                        obligation.param_env,
+                    )
+                    .must_apply_modulo_regions()
+            {
+                suggested = true;
+                err.span_suggestion_short(
+                    stmt.span.with_lo(expr.span.hi()),
+                    "remove this semicolon",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+            }
+
+            prev_ty = next_ty;
+
+            if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
+                && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
+                && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
+                && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id)
+            {
+                // We've reached the root of the method call chain...
+                if let hir::Node::Local(local) = parent
+                    && let Some(binding_expr) = local.init
+                {
+                    // ...and it is a binding. Get the binding creation and continue the chain.
+                    expr = binding_expr;
+                }
+                if let hir::Node::Param(_param) = parent {
+                    // ...and it is a an fn argument.
+                    break;
+                }
+            }
+        }
+        // `expr` is now the "root" expression of the method call chain, which can be any
+        // expression kind, like a method call or a path. If this expression is `Result<T, E>` as
+        // well, then we also point at it.
+        prev_ty = self.resolve_vars_if_possible(
+            typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
+        );
+        chain.push((expr.span, prev_ty));
+
+        let mut prev = None;
+        for (span, err_ty) in chain.into_iter().rev() {
+            let err_ty = get_e_type(err_ty);
+            let err_ty = match (err_ty, prev) {
+                (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => {
+                    err_ty
+                }
+                (Some(err_ty), None) => err_ty,
+                _ => {
+                    prev = err_ty;
+                    continue;
+                }
+            };
+            if self
+                .infcx
+                .type_implements_trait(
+                    self.tcx.get_diagnostic_item(sym::From).unwrap(),
+                    [self_ty, err_ty],
+                    obligation.param_env,
+                )
+                .must_apply_modulo_regions()
+            {
+                if !suggested {
+                    err.span_label(span, format!("this has type `Result<_, {err_ty}>`"));
+                }
+            } else {
+                err.span_label(
+                    span,
+                    format!(
+                        "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`",
+                    ),
+                );
+            }
+            prev = Some(err_ty);
+        }
+        suggested
+    }
+
     fn report_const_param_not_wf(
         &self,
         ty: Ty<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 45bdff09dee..5b0829b5732 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -2076,7 +2076,7 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
     else {
         unreachable!()
     };
-    let coroutine_sig = args.as_coroutine().poly_sig();
+    let coroutine_sig = args.as_coroutine().sig();
     let Normalized { value: coroutine_sig, obligations } = normalize_with_depth(
         selcx,
         obligation.param_env,
@@ -2091,29 +2091,28 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
 
     let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, None);
 
-    let predicate = super::util::coroutine_trait_ref_and_outputs(
+    let (trait_ref, yield_ty, return_ty) = super::util::coroutine_trait_ref_and_outputs(
         tcx,
         coroutine_def_id,
         obligation.predicate.self_ty(),
         coroutine_sig,
-    )
-    .map_bound(|(trait_ref, yield_ty, return_ty)| {
-        let name = tcx.associated_item(obligation.predicate.def_id).name;
-        let ty = if name == sym::Return {
-            return_ty
-        } else if name == sym::Yield {
-            yield_ty
-        } else {
-            bug!()
-        };
+    );
 
-        ty::ProjectionPredicate {
-            projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
-            term: ty.into(),
-        }
-    });
+    let name = tcx.associated_item(obligation.predicate.def_id).name;
+    let ty = if name == sym::Return {
+        return_ty
+    } else if name == sym::Yield {
+        yield_ty
+    } else {
+        bug!()
+    };
+
+    let predicate = ty::ProjectionPredicate {
+        projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+        term: ty.into(),
+    };
 
-    confirm_param_env_candidate(selcx, obligation, predicate, false)
+    confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
         .with_addl_obligations(nested)
         .with_addl_obligations(obligations)
 }
@@ -2128,7 +2127,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
     else {
         unreachable!()
     };
-    let coroutine_sig = args.as_coroutine().poly_sig();
+    let coroutine_sig = args.as_coroutine().sig();
     let Normalized { value: coroutine_sig, obligations } = normalize_with_depth(
         selcx,
         obligation.param_env,
@@ -2142,22 +2141,21 @@ fn confirm_future_candidate<'cx, 'tcx>(
     let tcx = selcx.tcx();
     let fut_def_id = tcx.require_lang_item(LangItem::Future, None);
 
-    let predicate = super::util::future_trait_ref_and_outputs(
+    let (trait_ref, return_ty) = super::util::future_trait_ref_and_outputs(
         tcx,
         fut_def_id,
         obligation.predicate.self_ty(),
         coroutine_sig,
-    )
-    .map_bound(|(trait_ref, return_ty)| {
-        debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
+    );
 
-        ty::ProjectionPredicate {
-            projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
-            term: return_ty.into(),
-        }
-    });
+    debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
+
+    let predicate = ty::ProjectionPredicate {
+        projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+        term: return_ty.into(),
+    };
 
-    confirm_param_env_candidate(selcx, obligation, predicate, false)
+    confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
         .with_addl_obligations(nested)
         .with_addl_obligations(obligations)
 }
@@ -2172,7 +2170,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
     else {
         unreachable!()
     };
-    let gen_sig = args.as_coroutine().poly_sig();
+    let gen_sig = args.as_coroutine().sig();
     let Normalized { value: gen_sig, obligations } = normalize_with_depth(
         selcx,
         obligation.param_env,
@@ -2186,22 +2184,21 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
     let tcx = selcx.tcx();
     let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None);
 
-    let predicate = super::util::iterator_trait_ref_and_outputs(
+    let (trait_ref, yield_ty) = super::util::iterator_trait_ref_and_outputs(
         tcx,
         iter_def_id,
         obligation.predicate.self_ty(),
         gen_sig,
-    )
-    .map_bound(|(trait_ref, yield_ty)| {
-        debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
+    );
 
-        ty::ProjectionPredicate {
-            projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
-            term: yield_ty.into(),
-        }
-    });
+    debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
 
-    confirm_param_env_candidate(selcx, obligation, predicate, false)
+    let predicate = ty::ProjectionPredicate {
+        projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+        term: yield_ty.into(),
+    };
+
+    confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
         .with_addl_obligations(nested)
         .with_addl_obligations(obligations)
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index a33160b7c43..fc4f6f37621 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -731,7 +731,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         debug!(?obligation, ?coroutine_def_id, ?args, "confirm_coroutine_candidate");
 
-        let coroutine_sig = args.as_coroutine().poly_sig();
+        let coroutine_sig = args.as_coroutine().sig();
 
         // NOTE: The self-type is a coroutine type and hence is
         // in fact unparameterized (or at least does not reference any
@@ -742,15 +742,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .no_bound_vars()
             .expect("unboxed closure type should not capture bound vars from the predicate");
 
-        let trait_ref = super::util::coroutine_trait_ref_and_outputs(
+        let (trait_ref, _, _) = super::util::coroutine_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
             self_ty,
             coroutine_sig,
-        )
-        .map_bound(|(trait_ref, ..)| trait_ref);
+        );
 
-        let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
         debug!(?trait_ref, ?nested, "coroutine candidate obligations");
 
         Ok(nested)
@@ -770,17 +769,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         debug!(?obligation, ?coroutine_def_id, ?args, "confirm_future_candidate");
 
-        let coroutine_sig = args.as_coroutine().poly_sig();
+        let coroutine_sig = args.as_coroutine().sig();
 
-        let trait_ref = super::util::future_trait_ref_and_outputs(
+        let (trait_ref, _) = super::util::future_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
             obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(),
             coroutine_sig,
-        )
-        .map_bound(|(trait_ref, ..)| trait_ref);
+        );
 
-        let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
         debug!(?trait_ref, ?nested, "future candidate obligations");
 
         Ok(nested)
@@ -800,17 +798,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         debug!(?obligation, ?coroutine_def_id, ?args, "confirm_iterator_candidate");
 
-        let gen_sig = args.as_coroutine().poly_sig();
+        let gen_sig = args.as_coroutine().sig();
 
-        let trait_ref = super::util::iterator_trait_ref_and_outputs(
+        let (trait_ref, _) = super::util::iterator_trait_ref_and_outputs(
             self.tcx(),
             obligation.predicate.def_id(),
             obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
             gen_sig,
-        )
-        .map_bound(|(trait_ref, ..)| trait_ref);
+        );
 
-        let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+        let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
         debug!(?trait_ref, ?nested, "iterator candidate obligations");
 
         Ok(nested)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 8e4f7d5d965..0d3ec41f511 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -222,8 +222,8 @@ pub enum TreatInductiveCycleAs {
 impl From<TreatInductiveCycleAs> for EvaluationResult {
     fn from(treat: TreatInductiveCycleAs) -> EvaluationResult {
         match treat {
-            TreatInductiveCycleAs::Ambig => EvaluatedToUnknown,
-            TreatInductiveCycleAs::Recur => EvaluatedToRecur,
+            TreatInductiveCycleAs::Ambig => EvaluatedToAmbigStackDependent,
+            TreatInductiveCycleAs::Recur => EvaluatedToErrStackDependent,
         }
     }
 }
@@ -1231,7 +1231,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             })
         {
             debug!("evaluate_stack --> unbound argument, recursive --> giving up",);
-            return Ok(EvaluatedToUnknown);
+            return Ok(EvaluatedToAmbigStackDependent);
         }
 
         match self.candidate_from_obligation(stack) {
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index bbde0c82743..5574badf238 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -279,33 +279,33 @@ pub fn coroutine_trait_ref_and_outputs<'tcx>(
     tcx: TyCtxt<'tcx>,
     fn_trait_def_id: DefId,
     self_ty: Ty<'tcx>,
-    sig: ty::PolyGenSig<'tcx>,
-) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
+    sig: ty::GenSig<'tcx>,
+) -> (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>) {
     assert!(!self_ty.has_escaping_bound_vars());
-    let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.skip_binder().resume_ty]);
-    sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty))
+    let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.resume_ty]);
+    (trait_ref, sig.yield_ty, sig.return_ty)
 }
 
 pub fn future_trait_ref_and_outputs<'tcx>(
     tcx: TyCtxt<'tcx>,
     fn_trait_def_id: DefId,
     self_ty: Ty<'tcx>,
-    sig: ty::PolyGenSig<'tcx>,
-) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
+    sig: ty::GenSig<'tcx>,
+) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
     assert!(!self_ty.has_escaping_bound_vars());
     let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]);
-    sig.map_bound(|sig| (trait_ref, sig.return_ty))
+    (trait_ref, sig.return_ty)
 }
 
 pub fn iterator_trait_ref_and_outputs<'tcx>(
     tcx: TyCtxt<'tcx>,
     iterator_def_id: DefId,
     self_ty: Ty<'tcx>,
-    sig: ty::PolyGenSig<'tcx>,
-) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
+    sig: ty::GenSig<'tcx>,
+) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
     assert!(!self_ty.has_escaping_bound_vars());
     let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]);
-    sig.map_bound(|sig| (trait_ref, sig.yield_ty))
+    (trait_ref, sig.yield_ty)
 }
 
 pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index b28e3d5c412..a58e98ce99c 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -99,11 +99,11 @@ fn fn_sig_for_fn_abi<'tcx>(
         }
         ty::Coroutine(did, args, _) => {
             let coroutine_kind = tcx.coroutine_kind(did).unwrap();
-            let sig = args.as_coroutine().poly_sig();
+            let sig = args.as_coroutine().sig();
 
-            let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
-                sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
-            );
+            let bound_vars = tcx.mk_bound_variable_kinds_from_iter(iter::once(
+                ty::BoundVariableKind::Region(ty::BrEnv),
+            ));
             let br = ty::BoundRegion {
                 var: ty::BoundVar::from_usize(bound_vars.len() - 1),
                 kind: ty::BoundRegionKind::BrEnv,
@@ -124,7 +124,6 @@ fn fn_sig_for_fn_abi<'tcx>(
                 }
             };
 
-            let sig = sig.skip_binder();
             // The `FnSig` and the `ret_ty` here is for a coroutines main
             // `Coroutine::resume(...) -> CoroutineState` function in case we
             // have an ordinary coroutine, the `Future::poll(...) -> Poll`
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index daf4465963e..5c91ec15455 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -9,9 +9,9 @@ use crate::mir::alloc::{AllocId, GlobalAlloc};
 use crate::mir::mono::{Instance, InstanceDef, StaticDef};
 use crate::mir::Body;
 use crate::ty::{
-    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs,
+    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
     GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl,
-    TraitDef, Ty, TyKind,
+    TraitDef, Ty, TyKind, VariantDef,
 };
 use crate::{
     mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol,
@@ -60,7 +60,7 @@ pub trait Context {
     fn item_kind(&self, item: CrateItem) -> ItemKind;
 
     /// Returns whether this is a foreign item.
-    fn is_foreign_item(&self, item: CrateItem) -> bool;
+    fn is_foreign_item(&self, item: DefId) -> bool;
 
     /// Returns the kind of a given algebraic data type
     fn adt_kind(&self, def: AdtDef) -> AdtKind;
@@ -71,6 +71,13 @@ pub trait Context {
     /// Retrieve the function signature for the given generic arguments.
     fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig;
 
+    /// The number of variants in this ADT.
+    fn adt_variants_len(&self, def: AdtDef) -> usize;
+
+    /// The name of a variant.
+    fn variant_name(&self, def: VariantDef) -> Symbol;
+    fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef>;
+
     /// Evaluate constant as a target usize.
     fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>;
 
@@ -83,6 +90,9 @@ pub trait Context {
     /// Returns the type of given crate item.
     fn def_ty(&self, item: DefId) -> Ty;
 
+    /// Returns the type of given definition instantiated with the given arguments.
+    fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty;
+
     /// Returns literal value of a const as a string.
     fn const_literal(&self, cnst: &Const) -> String;
 
diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs
index 1ff65717e87..bb5e1a34180 100644
--- a/compiler/stable_mir/src/error.rs
+++ b/compiler/stable_mir/src/error.rs
@@ -28,7 +28,7 @@ pub enum CompilerError<T> {
 }
 
 /// A generic error to represent an API request that cannot be fulfilled.
-#[derive(Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
 pub struct Error(pub(crate) String);
 
 impl Error {
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index 2099c485c6f..1e7495009d8 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -120,7 +120,7 @@ impl CrateItem {
     }
 
     pub fn is_foreign_item(&self) -> bool {
-        with(|cx| cx.is_foreign_item(*self))
+        with(|cx| cx.is_foreign_item(self.0))
     }
 
     pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index 3a4f4283562..6f131cc4f03 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -1,6 +1,7 @@
 use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator};
 use crate::ty::{
     AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
+    VariantIdx,
 };
 use crate::{Error, Opaque, Span, Symbol};
 use std::io;
@@ -9,17 +10,17 @@ use std::io;
 pub struct Body {
     pub blocks: Vec<BasicBlock>,
 
-    // Declarations of locals within the function.
-    //
-    // The first local is the return value pointer, followed by `arg_count`
-    // locals for the function arguments, followed by any user-declared
-    // variables and temporaries.
+    /// Declarations of locals within the function.
+    ///
+    /// The first local is the return value pointer, followed by `arg_count`
+    /// locals for the function arguments, followed by any user-declared
+    /// variables and temporaries.
     pub(super) locals: LocalDecls,
 
-    // The number of arguments this function takes.
+    /// The number of arguments this function takes.
     pub(super) arg_count: usize,
 
-    // Debug information pertaining to user variables, including captures.
+    /// Debug information pertaining to user variables, including captures.
     pub(super) var_debug_info: Vec<VarDebugInfo>,
 }
 
@@ -69,6 +70,11 @@ impl Body {
         &self.locals
     }
 
+    /// Get the local declaration for this local.
+    pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> {
+        self.locals.get(local)
+    }
+
     pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
         writeln!(w, "{}", function_body(self))?;
         self.blocks
@@ -492,12 +498,32 @@ pub struct Place {
     pub projection: Vec<ProjectionElem>,
 }
 
+impl From<Local> for Place {
+    fn from(local: Local) -> Self {
+        Place { local, projection: vec![] }
+    }
+}
+
+/// Debug information pertaining to a user variable.
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct VarDebugInfo {
+    /// The variable name.
     pub name: Symbol,
+
+    /// Source info of the user variable, including the scope
+    /// within which the variable is visible (to debuginfo).
     pub source_info: SourceInfo,
+
+    /// The user variable's data is split across several fragments,
+    /// each described by a `VarDebugInfoFragment`.
     pub composite: Option<VarDebugInfoFragment>,
+
+    /// Where the data for this user variable is to be found.
     pub value: VarDebugInfoContents,
+
+    /// When present, indicates what argument number this variable is in the function that it
+    /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the
+    /// argument number in the original function before it was inlined.
     pub argument_index: Option<u16>,
 }
 
@@ -632,22 +658,7 @@ pub const RETURN_LOCAL: Local = 0;
 /// `b`'s `FieldIdx` is `1`,
 /// `c`'s `FieldIdx` is `0`, and
 /// `g`'s `FieldIdx` is `2`.
-type FieldIdx = usize;
-
-/// The source-order index of a variant in a type.
-///
-/// For example, in the following types,
-/// ```ignore(illustrative)
-/// enum Demo1 {
-///    Variant0 { a: bool, b: i32 },
-///    Variant1 { c: u8, d: u64 },
-/// }
-/// struct Demo2 { e: u8, f: u16, g: u8 }
-/// ```
-/// `a` is in the variant with the `VariantIdx` of `0`,
-/// `c` is in the variant with the `VariantIdx` of `1`, and
-/// `g` is in the variant with the `VariantIdx` of `0`.
-pub type VariantIdx = usize;
+pub type FieldIdx = usize;
 
 type UserTypeAnnotationIndex = usize;
 
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index 10270c82e63..11b849868e0 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -39,9 +39,16 @@ impl Instance {
         with(|context| context.instance_body(self.def))
     }
 
+    /// Check whether this instance has a body available.
+    ///
+    /// This call is much cheaper than `instance.body().is_some()`, since it doesn't try to build
+    /// the StableMIR body.
+    pub fn has_body(&self) -> bool {
+        with(|cx| cx.has_body(self.def.def_id()))
+    }
+
     pub fn is_foreign_item(&self) -> bool {
-        let item = CrateItem::try_from(*self);
-        item.as_ref().is_ok_and(CrateItem::is_foreign_item)
+        with(|cx| cx.is_foreign_item(self.def.def_id()))
     }
 
     /// Get the instance type with generic substitutions applied and lifetimes erased.
diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs
index 0c44781c463..d46caad9a01 100644
--- a/compiler/stable_mir/src/mir/visit.rs
+++ b/compiler/stable_mir/src/mir/visit.rs
@@ -452,7 +452,7 @@ impl Location {
 }
 
 /// Information about a place's usage.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct PlaceContext {
     /// Whether the access is mutable or not. Keep this private so we can increment the type in a
     /// backward compatible manner.
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 6c4fb4a7753..f64b1f5f5a3 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -30,6 +30,16 @@ impl Ty {
     pub fn try_new_array(elem_ty: Ty, size: u64) -> Result<Ty, Error> {
         Ok(Ty::from_rigid_kind(RigidTy::Array(elem_ty, Const::try_from_target_usize(size)?)))
     }
+
+    /// Create a new pointer type.
+    pub fn new_ptr(pointee_ty: Ty, mutability: Mutability) -> Ty {
+        Ty::from_rigid_kind(RigidTy::RawPtr(pointee_ty, mutability))
+    }
+
+    /// Create a type representing `usize`.
+    pub fn usize_ty() -> Ty {
+        Ty::from_rigid_kind(RigidTy::Uint(UintTy::Usize))
+    }
 }
 
 impl Ty {
@@ -366,9 +376,97 @@ impl AdtDef {
         with(|cx| cx.adt_kind(*self))
     }
 
+    /// Retrieve the type of this Adt.
+    pub fn ty(&self) -> Ty {
+        with(|cx| cx.def_ty(self.0))
+    }
+
+    /// Retrieve the type of this Adt instantiating the type with the given arguments.
+    ///
+    /// This will assume the type can be instantiated with these arguments.
+    pub fn ty_with_args(&self, args: &GenericArgs) -> Ty {
+        with(|cx| cx.def_ty_with_args(self.0, args))
+    }
+
     pub fn is_box(&self) -> bool {
         with(|cx| cx.adt_is_box(*self))
     }
+
+    /// The number of variants in this ADT.
+    pub fn num_variants(&self) -> usize {
+        with(|cx| cx.adt_variants_len(*self))
+    }
+
+    /// Retrieve the variants in this ADT.
+    pub fn variants(&self) -> Vec<VariantDef> {
+        self.variants_iter().collect()
+    }
+
+    /// Iterate over the variants in this ADT.
+    pub fn variants_iter(&self) -> impl Iterator<Item = VariantDef> + '_ {
+        (0..self.num_variants())
+            .map(|idx| VariantDef { idx: VariantIdx::to_val(idx), adt_def: *self })
+    }
+
+    pub fn variant(&self, idx: VariantIdx) -> Option<VariantDef> {
+        (idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self })
+    }
+}
+
+/// Definition of a variant, which can be either a struct / union field or an enum variant.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct VariantDef {
+    /// The variant index.
+    ///
+    /// ## Warning
+    /// Do not access this field directly!
+    pub idx: VariantIdx,
+    /// The data type where this variant comes from.
+    /// For now, we use this to retrieve information about the variant itself so we don't need to
+    /// cache more information.
+    ///
+    /// ## Warning
+    /// Do not access this field directly!
+    pub adt_def: AdtDef,
+}
+
+impl VariantDef {
+    pub fn name(&self) -> Symbol {
+        with(|cx| cx.variant_name(*self))
+    }
+
+    /// Retrieve all the fields in this variant.
+    // We expect user to cache this and use it directly since today it is expensive to generate all
+    // fields name.
+    pub fn fields(&self) -> Vec<FieldDef> {
+        with(|cx| cx.variant_fields(*self))
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct FieldDef {
+    /// The field definition.
+    ///
+    /// ## Warning
+    /// Do not access this field directly! This is public for the compiler to have access to it.
+    pub def: DefId,
+
+    /// The field name.
+    pub name: Symbol,
+}
+
+impl FieldDef {
+    /// Retrieve the type of this field instantiating the type with the given arguments.
+    ///
+    /// This will assume the type can be instantiated with these arguments.
+    pub fn ty_with_args(&self, args: &GenericArgs) -> Ty {
+        with(|cx| cx.def_ty_with_args(self.def, args))
+    }
+
+    /// Retrieve the type of this field.
+    pub fn ty(&self) -> Ty {
+        with(|cx| cx.def_ty(self.def))
+    }
 }
 
 impl Display for AdtKind {
@@ -906,3 +1004,21 @@ macro_rules! index_impl {
 index_impl!(ConstId);
 index_impl!(Ty);
 index_impl!(Span);
+
+/// The source-order index of a variant in a type.
+///
+/// For example, in the following types,
+/// ```ignore(illustrative)
+/// enum Demo1 {
+///    Variant0 { a: bool, b: i32 },
+///    Variant1 { c: u8, d: u64 },
+/// }
+/// struct Demo2 { e: u8, f: u16, g: u8 }
+/// ```
+/// `a` is in the variant with the `VariantIdx` of `0`,
+/// `c` is in the variant with the `VariantIdx` of `1`, and
+/// `g` is in the variant with the `VariantIdx` of `0`.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct VariantIdx(usize);
+
+index_impl!(VariantIdx);
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 25c63b425ce..fdf5e134f4d 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1038,10 +1038,18 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// use std::ptr;
     ///
     /// let x = Box::new(String::from("Hello"));
-    /// let p = Box::into_raw(x);
+    /// let ptr = Box::into_raw(x);
+    /// unsafe {
+    ///     ptr::drop_in_place(ptr);
+    ///     dealloc(ptr as *mut u8, Layout::new::<String>());
+    /// }
+    /// ```
+    /// Note: This is equivalent to the following:
+    /// ```
+    /// let x = Box::new(String::from("Hello"));
+    /// let ptr = Box::into_raw(x);
     /// unsafe {
-    ///     ptr::drop_in_place(p);
-    ///     dealloc(p as *mut u8, Layout::new::<String>());
+    ///     drop(Box::from_raw(ptr));
     /// }
     /// ```
     ///
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index da0abdc9746..5a4a94d79d8 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -2843,16 +2843,14 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
     /// (i.e., when this `Weak` was created by `Weak::new`).
     #[inline]
     fn inner(&self) -> Option<WeakInner<'_>> {
-        if is_dangling(self.ptr.as_ptr()) {
+        let ptr = self.ptr.as_ptr();
+        if is_dangling(ptr) {
             None
         } else {
             // We are careful to *not* create a reference covering the "data" field, as
             // the field may be mutated concurrently (for example, if the last `Arc`
             // is dropped, the data field will be dropped in-place).
-            Some(unsafe {
-                let ptr = self.ptr.as_ptr();
-                WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak }
-            })
+            Some(unsafe { WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } })
         }
     }
 
diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index 6e097e2caf2..8fd64279ac5 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -81,6 +81,16 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
                 }
                 core::intrinsics::unreachable();
             }
+        } else if #[cfg(target_os = "teeos")] {
+            mod teeos {
+                extern "C" {
+                    pub fn TEE_Panic(code: u32) -> !;
+                }
+            }
+
+            unsafe fn abort() -> ! {
+                teeos::TEE_Panic(1);
+            }
         } else {
             unsafe fn abort() -> ! {
                 core::intrinsics::abort();
diff --git a/library/std/build.rs b/library/std/build.rs
index 11ba29766c1..0f5068b59b7 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -34,6 +34,7 @@ fn main() {
         || target.contains("xous")
         || target.contains("hurd")
         || target.contains("uefi")
+        || target.contains("teeos")
         // See src/bootstrap/synthetic_targets.rs
         || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
     {
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 159ffe7ac96..88420bd3612 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -53,6 +53,9 @@ cfg_if::cfg_if! {
     } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
         mod sgx;
         pub use self::sgx::*;
+    } else if #[cfg(target_os = "teeos")] {
+        mod teeos;
+        pub use self::teeos::*;
     } else {
         mod unsupported;
         pub use self::unsupported::*;
diff --git a/library/std/src/sys/teeos/alloc.rs b/library/std/src/sys/teeos/alloc.rs
new file mode 100644
index 00000000000..e236819aa23
--- /dev/null
+++ b/library/std/src/sys/teeos/alloc.rs
@@ -0,0 +1,57 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::ptr;
+use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // jemalloc provides alignment less than MIN_ALIGN for small allocations.
+        // So only rely on MIN_ALIGN if size >= align.
+        // Also see <https://github.com/rust-lang/rust/issues/45955> and
+        // <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
+        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+            libc::malloc(layout.size()) as *mut u8
+        } else {
+            aligned_malloc(&layout)
+        }
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        // See the comment above in `alloc` for why this check looks the way it does.
+        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+            libc::calloc(layout.size(), 1) as *mut u8
+        } else {
+            let ptr = self.alloc(layout);
+            if !ptr.is_null() {
+                ptr::write_bytes(ptr, 0, layout.size());
+            }
+            ptr
+        }
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        libc::free(ptr as *mut libc::c_void)
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+            libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+        } else {
+            realloc_fallback(self, ptr, layout, new_size)
+        }
+    }
+}
+
+#[inline]
+unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+    let mut out = ptr::null_mut();
+    // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
+    // Since these are all powers of 2, we can just use max.
+    let align = layout.align().max(crate::mem::size_of::<usize>());
+    let ret = libc::posix_memalign(&mut out, align, layout.size());
+    if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
+}
diff --git a/library/std/src/sys/teeos/locks/condvar.rs b/library/std/src/sys/teeos/locks/condvar.rs
new file mode 100644
index 00000000000..c08e8145b8c
--- /dev/null
+++ b/library/std/src/sys/teeos/locks/condvar.rs
@@ -0,0 +1,100 @@
+use crate::cell::UnsafeCell;
+use crate::ptr;
+use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed};
+use crate::sys::locks::mutex::{self, Mutex};
+use crate::sys::time::TIMESPEC_MAX;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
+use crate::time::Duration;
+
+extern "C" {
+    pub fn pthread_cond_timedwait(
+        cond: *mut libc::pthread_cond_t,
+        lock: *mut libc::pthread_mutex_t,
+        adstime: *const libc::timespec,
+    ) -> libc::c_int;
+}
+
+struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>);
+
+pub struct Condvar {
+    inner: LazyBox<AllocatedCondvar>,
+    mutex: AtomicPtr<libc::pthread_mutex_t>,
+}
+
+#[inline]
+fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
+    c.inner.0.get()
+}
+
+unsafe impl Send for AllocatedCondvar {}
+unsafe impl Sync for AllocatedCondvar {}
+
+impl LazyInit for AllocatedCondvar {
+    fn init() -> Box<Self> {
+        let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)));
+
+        let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) };
+        assert_eq!(r, 0);
+
+        condvar
+    }
+}
+
+impl Drop for AllocatedCondvar {
+    #[inline]
+    fn drop(&mut self) {
+        let r = unsafe { libc::pthread_cond_destroy(self.0.get()) };
+        debug_assert_eq!(r, 0);
+    }
+}
+
+impl Condvar {
+    pub const fn new() -> Condvar {
+        Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
+    }
+
+    #[inline]
+    fn verify(&self, mutex: *mut libc::pthread_mutex_t) {
+        match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) {
+            Ok(_) => {}                // Stored the address
+            Err(n) if n == mutex => {} // Lost a race to store the same address
+            _ => panic!("attempted to use a condition variable with two mutexes"),
+        }
+    }
+
+    #[inline]
+    pub fn notify_one(&self) {
+        let r = unsafe { libc::pthread_cond_signal(raw(self)) };
+        debug_assert_eq!(r, 0);
+    }
+
+    #[inline]
+    pub fn notify_all(&self) {
+        let r = unsafe { libc::pthread_cond_broadcast(raw(self)) };
+        debug_assert_eq!(r, 0);
+    }
+
+    #[inline]
+    pub unsafe fn wait(&self, mutex: &Mutex) {
+        let mutex = mutex::raw(mutex);
+        self.verify(mutex);
+        let r = libc::pthread_cond_wait(raw(self), mutex);
+        debug_assert_eq!(r, 0);
+    }
+
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        use crate::sys::time::Timespec;
+
+        let mutex = mutex::raw(mutex);
+        self.verify(mutex);
+
+        let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
+            .checked_add_duration(&dur)
+            .and_then(|t| t.to_timespec())
+            .unwrap_or(TIMESPEC_MAX);
+
+        let r = pthread_cond_timedwait(raw(self), mutex, &timeout);
+        assert!(r == libc::ETIMEDOUT || r == 0);
+        r == 0
+    }
+}
diff --git a/library/std/src/sys/teeos/locks/mod.rs b/library/std/src/sys/teeos/locks/mod.rs
new file mode 100644
index 00000000000..c58e9c7fd45
--- /dev/null
+++ b/library/std/src/sys/teeos/locks/mod.rs
@@ -0,0 +1,8 @@
+pub mod condvar;
+#[path = "../../unix/locks/pthread_mutex.rs"]
+pub mod mutex;
+pub mod rwlock;
+
+pub(crate) use condvar::Condvar;
+pub(crate) use mutex::Mutex;
+pub(crate) use rwlock::RwLock;
diff --git a/library/std/src/sys/teeos/locks/rwlock.rs b/library/std/src/sys/teeos/locks/rwlock.rs
new file mode 100644
index 00000000000..27cdb88788f
--- /dev/null
+++ b/library/std/src/sys/teeos/locks/rwlock.rs
@@ -0,0 +1,44 @@
+use crate::sys::locks::mutex::Mutex;
+
+/// we do not supported rwlock, so use mutex to simulate rwlock.
+/// it's useful because so many code in std will use rwlock.
+pub struct RwLock {
+    inner: Mutex,
+}
+
+impl RwLock {
+    #[inline]
+    pub const fn new() -> RwLock {
+        RwLock { inner: Mutex::new() }
+    }
+
+    #[inline]
+    pub fn read(&self) {
+        unsafe { self.inner.lock() };
+    }
+
+    #[inline]
+    pub fn try_read(&self) -> bool {
+        unsafe { self.inner.try_lock() }
+    }
+
+    #[inline]
+    pub fn write(&self) {
+        unsafe { self.inner.lock() };
+    }
+
+    #[inline]
+    pub unsafe fn try_write(&self) -> bool {
+        unsafe { self.inner.try_lock() }
+    }
+
+    #[inline]
+    pub unsafe fn read_unlock(&self) {
+        unsafe { self.inner.unlock() };
+    }
+
+    #[inline]
+    pub unsafe fn write_unlock(&self) {
+        unsafe { self.inner.unlock() };
+    }
+}
diff --git a/library/std/src/sys/teeos/mod.rs b/library/std/src/sys/teeos/mod.rs
new file mode 100644
index 00000000000..ed8c54b2c36
--- /dev/null
+++ b/library/std/src/sys/teeos/mod.rs
@@ -0,0 +1,167 @@
+//! System bindings for the Teeos platform
+//!
+//! This module contains the facade (aka platform-specific) implementations of
+//! OS level functionality for Teeos.
+#![allow(unsafe_op_in_unsafe_fn)]
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+pub use self::rand::hashmap_random_keys;
+
+pub mod alloc;
+#[path = "../unsupported/args.rs"]
+pub mod args;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+#[path = "../unsupported/env.rs"]
+pub mod env;
+pub mod locks;
+//pub mod fd;
+#[path = "../unsupported/fs.rs"]
+pub mod fs;
+#[path = "../unsupported/io.rs"]
+pub mod io;
+#[path = "../unix/memchr.rs"]
+pub mod memchr;
+pub mod net;
+#[path = "../unsupported/once.rs"]
+pub mod once;
+pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
+#[path = "../unix/path.rs"]
+pub mod path;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+#[path = "../unsupported/process.rs"]
+pub mod process;
+mod rand;
+pub mod stdio;
+pub mod thread;
+pub mod thread_local_dtor;
+#[path = "../unix/thread_local_key.rs"]
+pub mod thread_local_key;
+#[path = "../unsupported/thread_parking.rs"]
+pub mod thread_parking;
+#[allow(non_upper_case_globals)]
+#[path = "../unix/time.rs"]
+pub mod time;
+
+use crate::io::ErrorKind;
+
+pub fn abort_internal() -> ! {
+    unsafe { libc::abort() }
+}
+
+// Trusted Applications are loaded as dynamic libraries on Teeos,
+// so this should never be called.
+pub fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {}
+
+// SAFETY: must be called only once during runtime cleanup.
+// this is not guaranteed to run, for example when the program aborts.
+pub unsafe fn cleanup() {
+    unimplemented!()
+    // We do NOT have stack overflow handler, because TEE OS will kill TA when it happens.
+    // So cleanup is commented
+    // stack_overflow::cleanup();
+}
+
+#[inline]
+pub(crate) fn is_interrupted(errno: i32) -> bool {
+    errno == libc::EINTR
+}
+
+// Note: code below is 1:1 copied from unix/mod.rs
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+    use ErrorKind::*;
+    match errno as libc::c_int {
+        libc::E2BIG => ArgumentListTooLong,
+        libc::EADDRINUSE => AddrInUse,
+        libc::EADDRNOTAVAIL => AddrNotAvailable,
+        libc::EBUSY => ResourceBusy,
+        libc::ECONNABORTED => ConnectionAborted,
+        libc::ECONNREFUSED => ConnectionRefused,
+        libc::ECONNRESET => ConnectionReset,
+        libc::EDEADLK => Deadlock,
+        libc::EDQUOT => FilesystemQuotaExceeded,
+        libc::EEXIST => AlreadyExists,
+        libc::EFBIG => FileTooLarge,
+        libc::EHOSTUNREACH => HostUnreachable,
+        libc::EINTR => Interrupted,
+        libc::EINVAL => InvalidInput,
+        libc::EISDIR => IsADirectory,
+        libc::ELOOP => FilesystemLoop,
+        libc::ENOENT => NotFound,
+        libc::ENOMEM => OutOfMemory,
+        libc::ENOSPC => StorageFull,
+        libc::ENOSYS => Unsupported,
+        libc::EMLINK => TooManyLinks,
+        libc::ENAMETOOLONG => InvalidFilename,
+        libc::ENETDOWN => NetworkDown,
+        libc::ENETUNREACH => NetworkUnreachable,
+        libc::ENOTCONN => NotConnected,
+        libc::ENOTDIR => NotADirectory,
+        libc::ENOTEMPTY => DirectoryNotEmpty,
+        libc::EPIPE => BrokenPipe,
+        libc::EROFS => ReadOnlyFilesystem,
+        libc::ESPIPE => NotSeekable,
+        libc::ESTALE => StaleNetworkFileHandle,
+        libc::ETIMEDOUT => TimedOut,
+        libc::ETXTBSY => ExecutableFileBusy,
+        libc::EXDEV => CrossesDevices,
+
+        libc::EACCES | libc::EPERM => PermissionDenied,
+
+        // These two constants can have the same value on some systems,
+        // but different values on others, so we can't use a match
+        // clause
+        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock,
+
+        _ => Uncategorized,
+    }
+}
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+    fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+    ($($t:ident)*) => ($(impl IsMinusOne for $t {
+        fn is_minus_one(&self) -> bool {
+            *self == -1
+        }
+    })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
+    if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
+}
+
+pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
+where
+    T: IsMinusOne,
+    F: FnMut() -> T,
+{
+    loop {
+        match cvt(f()) {
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+            other => return other,
+        }
+    }
+}
+
+pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
+    if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) }
+}
+
+use crate::io as std_io;
+pub fn unsupported<T>() -> std_io::Result<T> {
+    Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> std_io::Error {
+    std_io::Error::new(std_io::ErrorKind::Unsupported, "operation not supported on this platform")
+}
diff --git a/library/std/src/sys/teeos/net.rs b/library/std/src/sys/teeos/net.rs
new file mode 100644
index 00000000000..0df681dbfa5
--- /dev/null
+++ b/library/std/src/sys/teeos/net.rs
@@ -0,0 +1,372 @@
+use crate::fmt;
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::sys::unsupported;
+use crate::time::Duration;
+
+pub struct TcpStream(!);
+
+impl TcpStream {
+    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn is_read_vectored(&self) -> bool {
+        self.0
+    }
+
+    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        self.0
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpStream> {
+        self.0
+    }
+
+    pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        self.0
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+}
+
+impl fmt::Debug for TcpStream {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0
+    }
+}
+
+pub struct TcpListener(!);
+
+impl TcpListener {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+        unsupported()
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        self.0
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpListener> {
+        self.0
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        self.0
+    }
+
+    pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn only_v6(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+}
+
+impl fmt::Debug for TcpListener {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0
+    }
+}
+
+pub struct UdpSocket(!);
+
+impl UdpSocket {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+        unsupported()
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        self.0
+    }
+
+    pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.0
+    }
+
+    pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.0
+    }
+
+    pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn duplicate(&self) -> io::Result<UdpSocket> {
+        self.0
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
+    pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn broadcast(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+        self.0
+    }
+
+    pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        self.0
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+        self.0
+    }
+
+    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+        self.0
+    }
+}
+
+impl fmt::Debug for UdpSocket {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0
+    }
+}
+
+pub struct LookupHost(!);
+
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        self.0
+    }
+}
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<SocketAddr> {
+        self.0
+    }
+}
+
+impl TryFrom<&str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: &str) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+#[allow(nonstandard_style)]
+pub mod netc {
+    pub const AF_INET: u8 = 0;
+    pub const AF_INET6: u8 = 1;
+    pub type sa_family_t = u8;
+
+    #[derive(Copy, Clone)]
+    pub struct in_addr {
+        pub s_addr: u32,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in {
+        pub sin_family: sa_family_t,
+        pub sin_port: u16,
+        pub sin_addr: in_addr,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct in6_addr {
+        pub s6_addr: [u8; 16],
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in6 {
+        pub sin6_family: sa_family_t,
+        pub sin6_port: u16,
+        pub sin6_addr: in6_addr,
+        pub sin6_flowinfo: u32,
+        pub sin6_scope_id: u32,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr {}
+}
+
+pub type Socket = UdpSocket;
diff --git a/library/std/src/sys/teeos/os.rs b/library/std/src/sys/teeos/os.rs
new file mode 100644
index 00000000000..e54a92f01f8
--- /dev/null
+++ b/library/std/src/sys/teeos/os.rs
@@ -0,0 +1,134 @@
+//! Implementation of `std::os` functionality for teeos
+
+use core::marker::PhantomData;
+
+use crate::error::Error as StdError;
+use crate::ffi::{OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::path;
+use crate::path::PathBuf;
+
+use super::unsupported;
+
+pub fn errno() -> i32 {
+    unsafe { (*libc::__errno_location()) as i32 }
+}
+
+// Hardcoded to return 4096, since `sysconf` is only implemented as a stub.
+pub fn page_size() -> usize {
+    // unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
+    4096
+}
+
+// Everything below are stubs and copied from unsupported.rs
+
+pub fn error_string(_errno: i32) -> String {
+    "error string unimplemented".to_string()
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+    panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> {
+        self.0
+    }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+    I: Iterator<Item = T>,
+    T: AsRef<OsStr>,
+{
+    Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "not supported on this platform yet".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    #[allow(deprecated)]
+    fn description(&self) -> &str {
+        "not supported on this platform yet"
+    }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub struct Env(!);
+
+impl Env {
+    // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
+    pub fn str_debug(&self) -> impl fmt::Debug + '_ {
+        let Self(inner) = self;
+        match *inner {}
+    }
+}
+
+impl fmt::Debug for Env {
+    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Self(inner) = self;
+        match *inner {}
+    }
+}
+
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> {
+        let Self(inner) = self;
+        match *inner {}
+    }
+}
+
+pub fn env() -> Env {
+    panic!("not supported on this platform")
+}
+
+pub fn getenv(_: &OsStr) -> Option<OsString> {
+    None
+}
+
+pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
+    Err(io::Error::new(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
+}
+
+pub fn unsetenv(_: &OsStr) -> io::Result<()> {
+    Err(io::Error::new(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
+}
+
+pub fn temp_dir() -> PathBuf {
+    panic!("no filesystem on this platform")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    None
+}
+
+pub fn exit(_code: i32) -> ! {
+    panic!("TA should not call `exit`")
+}
+
+pub fn getpid() -> u32 {
+    panic!("no pids on this platform")
+}
diff --git a/library/std/src/sys/teeos/rand.rs b/library/std/src/sys/teeos/rand.rs
new file mode 100644
index 00000000000..b45c3bb40e7
--- /dev/null
+++ b/library/std/src/sys/teeos/rand.rs
@@ -0,0 +1,21 @@
+pub fn hashmap_random_keys() -> (u64, u64) {
+    const KEY_LEN: usize = core::mem::size_of::<u64>();
+
+    let mut v = [0u8; KEY_LEN * 2];
+    imp::fill_bytes(&mut v);
+
+    let key1 = v[0..KEY_LEN].try_into().unwrap();
+    let key2 = v[KEY_LEN..].try_into().unwrap();
+
+    (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
+}
+
+mod imp {
+    extern "C" {
+        fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t);
+    }
+
+    pub fn fill_bytes(v: &mut [u8]) {
+        unsafe { TEE_GenerateRandom(v.as_mut_ptr() as _, v.len() * crate::mem::size_of::<u8>()) }
+    }
+}
diff --git a/library/std/src/sys/teeos/stdio.rs b/library/std/src/sys/teeos/stdio.rs
new file mode 100644
index 00000000000..9ca04f29273
--- /dev/null
+++ b/library/std/src/sys/teeos/stdio.rs
@@ -0,0 +1,88 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
+use crate::io;
+use core::arch::asm;
+
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
+
+const KCALL_DEBUG_CMD_PUT_BYTES: i64 = 2;
+
+unsafe fn debug_call(cap_ref: u64, call_no: i64, arg1: u64, arg2: u64) -> i32 {
+    let ret: u64;
+    unsafe {
+        asm!(
+            "svc #99",
+            inout("x0") cap_ref => ret,
+            in("x1") call_no,
+            in("x2") arg1,
+            in("x3") arg2,
+        );
+    }
+
+    ret as i32
+}
+
+fn print_buf(s: &[u8]) -> io::Result<usize> {
+    // Corresponds to `HM_DEBUG_PUT_BYTES_LIMIT`.
+    const MAX_LEN: usize = 512;
+    let len = if s.len() > MAX_LEN { MAX_LEN } else { s.len() };
+    let result = unsafe { debug_call(0, KCALL_DEBUG_CMD_PUT_BYTES, s.as_ptr() as u64, len as u64) };
+
+    if result == 0 { Ok(len) } else { Err(io::Error::from(io::ErrorKind::InvalidInput)) }
+}
+
+impl Stdin {
+    pub const fn new() -> Stdin {
+        Stdin
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+        Ok(0)
+    }
+}
+
+impl Stdout {
+    pub const fn new() -> Stdout {
+        Stdout
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        print_buf(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Stderr {
+    pub const fn new() -> Stderr {
+        Stderr
+    }
+}
+
+impl io::Write for Stderr {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        print_buf(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+    err.raw_os_error() == Some(libc::EBADF as i32)
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+    Some(Stderr::new())
+}
diff --git a/library/std/src/sys/teeos/thread.rs b/library/std/src/sys/teeos/thread.rs
new file mode 100644
index 00000000000..155f333f906
--- /dev/null
+++ b/library/std/src/sys/teeos/thread.rs
@@ -0,0 +1,164 @@
+use core::convert::TryInto;
+
+use crate::cmp;
+use crate::ffi::CStr;
+use crate::io;
+use crate::mem;
+use crate::num::NonZeroUsize;
+use crate::ptr;
+use crate::sys::os;
+use crate::time::Duration;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024;
+
+pub struct Thread {
+    id: libc::pthread_t,
+}
+
+// Some platforms may have pthread_t as a pointer in which case we still want
+// a thread to be Send/Sync
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+extern "C" {
+    pub fn TEE_Wait(timeout: u32) -> u32;
+}
+
+impl Thread {
+    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+        let p = Box::into_raw(Box::new(p));
+        let mut native: libc::pthread_t = mem::zeroed();
+        let mut attr: libc::pthread_attr_t = mem::zeroed();
+        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+        assert_eq!(
+            libc::pthread_attr_settee(
+                &mut attr,
+                libc::TEESMP_THREAD_ATTR_CA_INHERIT,
+                libc::TEESMP_THREAD_ATTR_TASK_ID_INHERIT,
+                libc::TEESMP_THREAD_ATTR_HAS_SHADOW,
+            ),
+            0,
+        );
+
+        let stack_size = cmp::max(stack, min_stack_size(&attr));
+
+        match libc::pthread_attr_setstacksize(&mut attr, stack_size) {
+            0 => {}
+            n => {
+                assert_eq!(n, libc::EINVAL);
+                // EINVAL means |stack_size| is either too small or not a
+                // multiple of the system page size.  Because it's definitely
+                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
+                // Round up to the nearest page and try again.
+                let page_size = os::page_size();
+                let stack_size =
+                    (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
+                assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
+            }
+        };
+
+        let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
+        // Note: if the thread creation fails and this assert fails, then p will
+        // be leaked. However, an alternative design could cause double-free
+        // which is clearly worse.
+        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+
+        return if ret != 0 {
+            // The thread failed to start and as a result p was not consumed. Therefore, it is
+            // safe to reconstruct the box so that it gets deallocated.
+            drop(Box::from_raw(p));
+            Err(io::Error::from_raw_os_error(ret))
+        } else {
+            // The new thread will start running earliest after the next yield.
+            // We add a yield here, so that the user does not have to.
+            Thread::yield_now();
+            Ok(Thread { id: native })
+        };
+
+        extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+            unsafe {
+                // Next, set up our stack overflow handler which may get triggered if we run
+                // out of stack.
+                // this is not necessary in TEE.
+                //let _handler = stack_overflow::Handler::new();
+                // Finally, let's run some code.
+                Box::from_raw(main as *mut Box<dyn FnOnce()>)();
+            }
+            ptr::null_mut()
+        }
+    }
+
+    pub fn yield_now() {
+        let ret = unsafe { libc::sched_yield() };
+        debug_assert_eq!(ret, 0);
+    }
+
+    /// This does not do anything on teeos
+    pub fn set_name(_name: &CStr) {
+        // Both pthread_setname_np and prctl are not available to the TA,
+        // so we can't implement this currently. If the need arises please
+        // contact the teeos rustzone team.
+    }
+
+    /// only main thread could wait for sometime in teeos
+    pub fn sleep(dur: Duration) {
+        let sleep_millis = dur.as_millis();
+        let final_sleep: u32 =
+            if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
+        unsafe {
+            let _ = TEE_Wait(final_sleep);
+        }
+    }
+
+    /// must join, because no pthread_detach supported
+    pub fn join(self) {
+        unsafe {
+            let ret = libc::pthread_join(self.id, ptr::null_mut());
+            mem::forget(self);
+            assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
+        }
+    }
+
+    pub fn id(&self) -> libc::pthread_t {
+        self.id
+    }
+
+    pub fn into_id(self) -> libc::pthread_t {
+        let id = self.id;
+        mem::forget(self);
+        id
+    }
+}
+
+impl Drop for Thread {
+    fn drop(&mut self) {
+        // we can not call detach, so just panic if thread spawn without join
+        panic!("thread must join, detach is not supported!");
+    }
+}
+
+// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
+// teeos, so this function always returns an Error!
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+    Err(io::Error::new(
+        io::ErrorKind::NotFound,
+        "The number of hardware threads is not known for the target platform",
+    ))
+}
+
+// stub
+pub mod guard {
+    use crate::ops::Range;
+    pub type Guard = Range<usize>;
+    pub unsafe fn current() -> Option<Guard> {
+        None
+    }
+    pub unsafe fn init() -> Option<Guard> {
+        None
+    }
+}
+
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+    libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
+}
diff --git a/library/std/src/sys/teeos/thread_local_dtor.rs b/library/std/src/sys/teeos/thread_local_dtor.rs
new file mode 100644
index 00000000000..5c6bc4d6750
--- /dev/null
+++ b/library/std/src/sys/teeos/thread_local_dtor.rs
@@ -0,0 +1,4 @@
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+    use crate::sys_common::thread_local_dtor::register_dtor_fallback;
+    register_dtor_fallback(t, dtor);
+}
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index f2e86a4fb2b..f62eb828ee5 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -23,11 +23,11 @@ struct Nanoseconds(u32);
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct SystemTime {
-    pub(in crate::sys::unix) t: Timespec,
+    pub(crate) t: Timespec,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub(in crate::sys::unix) struct Timespec {
+pub(crate) struct Timespec {
     tv_sec: i64,
     tv_nsec: Nanoseconds,
 }
@@ -239,11 +239,11 @@ impl From<libc::timespec> for Timespec {
     not(target_arch = "riscv32")
 ))]
 #[repr(C)]
-pub(in crate::sys::unix) struct __timespec64 {
-    pub(in crate::sys::unix) tv_sec: i64,
+pub(crate) struct __timespec64 {
+    pub(crate) tv_sec: i64,
     #[cfg(target_endian = "big")]
     _padding: i32,
-    pub(in crate::sys::unix) tv_nsec: i32,
+    pub(crate) tv_nsec: i32,
     #[cfg(target_endian = "little")]
     _padding: i32,
 }
@@ -255,7 +255,7 @@ pub(in crate::sys::unix) struct __timespec64 {
     not(target_arch = "riscv32")
 ))]
 impl __timespec64 {
-    pub(in crate::sys::unix) fn new(tv_sec: i64, tv_nsec: i32) -> Self {
+    pub(crate) fn new(tv_sec: i64, tv_nsec: i32) -> Self {
         Self { tv_sec, tv_nsec, _padding: 0 }
     }
 }
diff --git a/library/std/src/sys/windows/api.rs b/library/std/src/sys/windows/api.rs
index 72ecb950341..a7ea59e85f7 100644
--- a/library/std/src/sys/windows/api.rs
+++ b/library/std/src/sys/windows/api.rs
@@ -48,7 +48,7 @@ use super::c;
 /// converted to a `u32`. Clippy would warn about this but, alas, it's not run
 /// on the standard library.
 const fn win32_size_of<T: Sized>() -> u32 {
-    // Const assert that the size is less than u32::MAX.
+    // Const assert that the size does not exceed u32::MAX.
     // Uses a trait to workaround restriction on using generic types in inner items.
     trait Win32SizeOf: Sized {
         const WIN32_SIZE_OF: u32 = {
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 4b9ddd5aba1..8498937809e 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1581,6 +1581,7 @@ impl<'scope, T> JoinInner<'scope, T> {
 /// [`thread::Builder::spawn`]: Builder::spawn
 /// [`thread::spawn`]: spawn
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(target_os = "teeos", must_use)]
 pub struct JoinHandle<T>(JoinInner<'static, T>);
 
 #[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 57113b0ec62..f452b944e75 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -370,9 +370,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.149"
+version = "0.2.150"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
+checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
 
 [[package]]
 name = "linux-raw-sys"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index e4d359141ce..24951cf20fa 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -42,7 +42,7 @@ filetime = "0.2"
 hex = "0.4"
 home = "0.5.4"
 ignore = "0.4.10"
-libc = "0.2"
+libc = "0.2.150"
 object = { version = "0.32.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
 once_cell = "1.7.2"
 opener = "0.5"
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 4691fb3ad6f..2328dd822af 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -946,6 +946,8 @@ class RustBuild(object):
         target_linker = self.get_toml("linker", build_section)
         if target_linker is not None:
             env["RUSTFLAGS"] += " -C linker=" + target_linker
+        # When changing this list, also update the corresponding list in `Builder::cargo`
+        # in `src/bootstrap/src/core/builder.rs`.
         env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes"
         if self.warnings == "default":
             deny_warnings = self.get_toml("deny-warnings", "rust") != "false"
diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
index 341e2de223a..adf3c67479b 100644
--- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
@@ -95,6 +95,7 @@ ENV TARGETS=$TARGETS,thumbv8m.main-none-eabihf
 ENV TARGETS=$TARGETS,riscv32i-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf
+ENV TARGETS=$TARGETS,riscv32imafc-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv64gc-unknown-none-elf
 ENV TARGETS=$TARGETS,armebv7r-none-eabi
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
index 4757c3e7329..f4850715e82 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
@@ -24,8 +24,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   nodejs \
   mingw-w64 \
+  libgccjit-12-dev \
   && rm -rf /var/lib/apt/lists/*
 
+# Note: libgccjit needs to match the default gcc version for the linker to find it.
+
 # Install powershell (universal package) so we can test x.ps1 on Linux
 RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
     dpkg -i powershell.deb && \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
index dc5a04d4e06..f1d6b9a4ef2 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
@@ -24,8 +24,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   nodejs \
   mingw-w64 \
+  libgccjit-13-dev \
   && rm -rf /var/lib/apt/lists/*
 
+# Note: libgccjit needs to match the default gcc version for the linker to find it.
+
 # Install powershell (universal package) so we can test x.ps1 on Linux
 RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
     dpkg -i powershell.deb && \
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index cedbc0390f8..636692a0954 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -269,14 +269,9 @@ touch $objdir/${SUMMARY_FILE}
 
 extra_env=""
 if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then
-  extra_env="$EXTRA_ENV --env ENABLE_GCC_CODEGEN=1"
-  # If `ENABLE_GCC_CODEGEN` is set and not empty, we add the `--enable-new-symbol-mangling`
-  # argument to `RUST_CONFIGURE_ARGS` and set the `GCC_EXEC_PREFIX` environment variable.
-  # `cg_gcc` doesn't support the legacy mangling so we need to enforce the new one
-  # if we run `cg_gcc` tests.
-  extra_env="$EXTRA_ENV --env USE_NEW_MANGLING=--enable-new-symbol-mangling"
+  extra_env="$extra_env --env ENABLE_GCC_CODEGEN=1"
   # Fix rustc_codegen_gcc lto issues.
-  extra_env="$EXTRA_ENV --env GCC_EXEC_PREFIX=/usr/lib/gcc/"
+  extra_env="$extra_env --env GCC_EXEC_PREFIX=/usr/lib/gcc/"
   echo "Setting extra environment values for docker: $extra_env"
 fi
 
diff --git a/src/ci/run.sh b/src/ci/run.sh
index fa786c6c7e7..5700172fd3e 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -163,6 +163,14 @@ if [ "$IS_NOT_LATEST_LLVM" = "" ]; then
   export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1
 fi
 
+if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then
+  # If `ENABLE_GCC_CODEGEN` is set and not empty, we add the `--enable-new-symbol-mangling`
+  # argument to `RUST_CONFIGURE_ARGS` and set the `GCC_EXEC_PREFIX` environment variable.
+  # `cg_gcc` doesn't support the legacy mangling so we need to enforce the new one
+  # if we run `cg_gcc` tests.
+  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-new-symbol-mangling"
+fi
+
 # Print the date from the local machine and the date from an external source to
 # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure
 # Pipelines it happened that the certificates were marked as expired.
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 3bd90f7062d..ad335389514 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -45,6 +45,7 @@
     - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md)
     - [powerpc64-ibm-aix](platform-support/aix.md)
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
+    - [riscv32*-unknown-none-elf](platform-support/riscv32imac-unknown-none-elf.md)
     - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
     - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
     - [\*-nto-qnx-\*](platform-support/nto-qnx.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 3671fdd3fd2..457e8d90a43 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -159,9 +159,9 @@ target | std | notes
 [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * |  | LoongArch64 Bare-metal (LP64D ABI)
 [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * |  | LoongArch64 Bare-metal (LP64S ABI)
 [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
-`riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA)
-`riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA)
-`riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA)
+[`riscv32imac-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA)
+[`riscv32i-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32I ISA)
+[`riscv32imc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA)
 `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
 `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
 `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
@@ -314,7 +314,8 @@ target | std | host | notes
 [`powerpc64-ibm-aix`](platform-support/aix.md) | ? |  | 64-bit AIX (7.2 and newer)
 `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
-`riscv32im-unknown-none-elf` | * |  | Bare RISC-V (RV32IM ISA)
+[`riscv32imafc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA)
+[`riscv32im-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * |  | Bare RISC-V (RV32IM ISA)
 [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? |  | RISC-V Xous (RV32IMAC ISA)
 [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
 [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md b/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md
index 9233a36db3d..7a6609b2d76 100644
--- a/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md
+++ b/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md
@@ -39,7 +39,7 @@ Create the following shell scripts that wrap Clang from the OpenHarmony SDK:
 ```sh
 #!/bin/sh
 exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \
-  --target aarch64-linux-gnu \
+  -target aarch64-linux-gnu \
   "$@"
 ```
 
@@ -48,7 +48,7 @@ exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \
 ```sh
 #!/bin/sh
 exec /path/to/ohos-sdk/linux/native/llvm/bin/clang++ \
-  --target aarch64-linux-gnu \
+  -target aarch64-linux-gnu \
   "$@"
 ```
 
@@ -81,6 +81,13 @@ ranlib = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ranlib"
 llvm-config = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-config"
 ```
 
+```text
+note: You need to insert "/usr/include/x86_64-linux-gnu/" into environment variable: $C_INCLUDE_PATH
+ if some header files like bits/xxx.h not found.
+note: You can install gcc-aarch64-linux-gnu,g++-aarch64-linux-gnu if some files like crti.o not found.
+note: You may need to install libc6-dev-i386 libc6-dev if "gnu/stubs-32.h" not found.
+```
+
 ## Building Rust programs
 
 Rust does not yet ship pre-compiled artifacts for this target. To compile for
@@ -91,7 +98,7 @@ this target, you will either need to build Rust with the target enabled (see
 You will need to configure the linker to use in `~/.cargo/config`:
 ```toml
 [target.aarch64-unknown-teeos]
-linker = "/path/to/aarch64-unknown-teeos-clang.sh"
+linker = "/path/to/aarch64-unknown-teeos-clang.sh" # or aarch64-linux-gnu-ld
 ```
 
 ## Testing
diff --git a/src/doc/rustc/src/platform-support/riscv32i-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32i-unknown-none-elf.md
new file mode 100644
index 00000000000..edfe07fc053
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv32i-unknown-none-elf.md
@@ -0,0 +1 @@
+riscv32imac-unknown-none-elf.md
diff --git a/src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md
new file mode 100644
index 00000000000..edfe07fc053
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md
@@ -0,0 +1 @@
+riscv32imac-unknown-none-elf.md
diff --git a/src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md
new file mode 100644
index 00000000000..a069f3d3aa9
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md
@@ -0,0 +1,34 @@
+# `riscv32{i,im,imc,imac,imafc}-unknown-none-elf`
+
+**Tier: 2/3**
+
+Bare-metal target for RISC-V CPUs with the RV32I, RV32IM, RV32IMC, RV32IMAFC and RV32IMAC ISAs.
+
+## Target maintainers
+
+* Rust Embedded Working Group, [RISC-V team](https://github.com/rust-embedded/wg#the-risc-v-team)
+
+## Requirements
+
+The target is cross-compiled, and uses static linking. No external toolchain
+is required and the default `rust-lld` linker works, but you must specify
+a linker script. The [`riscv-rt`] crate provides a suitable one. The
+[`riscv-rust-quickstart`] repository gives an example of an RV32 project.
+
+[`riscv-rt`]: https://crates.io/crates/riscv-rt
+[`riscv-rust-quickstart`]: https://github.com/riscv-rust/riscv-rust-quickstart
+
+## Building the target
+
+This target is included in Rust and can be installed via `rustup`.
+
+## Testing
+
+This is a cross-compiled no-std target, which must be run either in a simulator
+or by programming them onto suitable hardware. It is not possible to run the
+Rust testsuite on this target.
+
+## Cross-compilation toolchains and C code
+
+This target supports C code. If interlinking with C or C++, you may need to use
+riscv64-unknown-elf-gcc as a linker instead of rust-lld.
diff --git a/src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md
new file mode 100644
index 00000000000..edfe07fc053
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md
@@ -0,0 +1 @@
+riscv32imac-unknown-none-elf.md
diff --git a/src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md
new file mode 100644
index 00000000000..edfe07fc053
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md
@@ -0,0 +1 @@
+riscv32imac-unknown-none-elf.md
diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
index bcfab790478..a5b9169c9f3 100644
--- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md
+++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
@@ -190,70 +190,3 @@ fn shoot_lasers() {}
                             // the cfg(feature) list
 fn write_shakespeare() {}
 ```
-
-## The deprecated `names(...)` form
-
-The `names(...)` form enables checking the names. This form uses a named list:
-
-```bash
-rustc --check-cfg 'names(name1, name2, ... nameN)'
-```
-
-where each `name` is a bare identifier (has no quotes). The order of the names is not significant.
-
-If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to
-condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause
-inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition
-names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint
-diagnostic. The default diagnostic level for this lint is `Warn`.
-
-If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition
-names.
-
-`--check-cfg names(...)` may be specified more than once. The result is that the list of valid
-condition names is merged across all options. It is legal for a condition name to be specified
-more than once; redundantly specifying a condition name has no effect.
-
-To enable checking condition names with an empty set of valid condition names, use the following
-form. The parentheses are required.
-
-```bash
-rustc --check-cfg 'names()'
-```
-
-Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely.
-The first form enables checking condition names, while specifying that there are no valid
-condition names (outside of the set of well-known names defined by `rustc`). Omitting the
-`--check-cfg 'names(...)'` option does not enable checking condition names.
-
-## The deprecated `values(...)` form
-
-The `values(...)` form enables checking the values within list-valued conditions. It has this
-form:
-
-```bash
-rustc --check-cfg `values(name, "value1", "value2", ... "valueN")'
-```
-
-where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal
-string. `name` specifies the name of the condition, such as `feature` or `target_os`.
-
-When the `values(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]`
-attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]`
-and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the
-list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs`
-lint diagnostic. The default diagnostic level for this lint is `Warn`.
-
-To enable checking of values, but to provide an empty set of valid values, use this form:
-
-```bash
-rustc --check-cfg `values(name)`
-```
-
-The `--check-cfg values(...)` option can be repeated, both for the same condition name and for
-different names. If it is repeated for the same condition name, then the sets of values for that
-condition are merged together.
-
-If `values()` is specified, then `rustc` will enable the checking of well-known values defined
-by itself. Note that it's necessary to specify the `values()` form to enable the checking of
-well known values, specifying the other forms doesn't implicitly enable it.
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 83c7ccc9ede..9ac97236f19 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -124,6 +124,7 @@ static TARGETS: &[&str] = &[
     "riscv32im-unknown-none-elf",
     "riscv32imc-unknown-none-elf",
     "riscv32imac-unknown-none-elf",
+    "riscv32imafc-unknown-none-elf",
     "riscv32gc-unknown-linux-gnu",
     "riscv64imac-unknown-none-elf",
     "riscv64gc-unknown-hermit",
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index af224360319..055671afd14 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -4288,15 +4288,18 @@ impl<'test> TestCx<'test> {
             let mut seen_allocs = indexmap::IndexSet::new();
 
             // The alloc-id appears in pretty-printed allocations.
-            let re = Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?─*╼").unwrap();
+            let re =
+                Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?(<imm>)?( \([0-9]+ ptr bytes\))?─*╼")
+                    .unwrap();
             normalized = re
                 .replace_all(&normalized, |caps: &Captures<'_>| {
                     // Renumber the captured index.
                     let index = caps.get(2).unwrap().as_str().to_string();
                     let (index, _) = seen_allocs.insert_full(index);
                     let offset = caps.get(3).map_or("", |c| c.as_str());
+                    let imm = caps.get(4).map_or("", |c| c.as_str());
                     // Do not bother keeping it pretty, just make it deterministic.
-                    format!("╾ALLOC{index}{offset}╼")
+                    format!("╾ALLOC{index}{offset}{imm}╼")
                 })
                 .into_owned();
 
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index fb90559f3d1..ef394b16310 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -44,7 +44,7 @@ pub enum TerminationInfo {
     },
     DataRace {
         involves_non_atomic: bool,
-        ptr: Pointer,
+        ptr: Pointer<AllocId>,
         op1: RacingOp,
         op2: RacingOp,
         extra: Option<&'static str>,
diff --git a/src/tools/miri/src/intptrcast.rs b/src/tools/miri/src/intptrcast.rs
index cd4d1bcc464..68c9a7660eb 100644
--- a/src/tools/miri/src/intptrcast.rs
+++ b/src/tools/miri/src/intptrcast.rs
@@ -256,12 +256,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     /// Convert a relative (tcx) pointer to a Miri pointer.
     fn ptr_from_rel_ptr(
         &self,
-        ptr: Pointer<AllocId>,
+        ptr: Pointer<CtfeProvenance>,
         tag: BorTag,
     ) -> InterpResult<'tcx, Pointer<Provenance>> {
         let ecx = self.eval_context_ref();
 
-        let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
+        let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
+        let alloc_id = prov.alloc_id();
         let base_addr = ecx.addr_from_alloc_id(alloc_id)?;
 
         // Add offset with the right kind of pointer-overflowing arithmetic.
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 243dc5e779b..4a878f4a36e 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -17,6 +17,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::static_assert_size;
 use rustc_middle::{
     mir,
+    query::TyCtxtAt,
     ty::{
         self,
         layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout},
@@ -259,6 +260,17 @@ impl interpret::Provenance for Provenance {
         }
     }
 
+    fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let (prov, addr) = ptr.into_parts(); // address is absolute
+        write!(f, "{:#x}", addr.bytes())?;
+        if f.alternate() {
+            write!(f, "{prov:#?}")?;
+        } else {
+            write!(f, "{prov:?}")?;
+        }
+        Ok(())
+    }
+
     fn join(left: Option<Self>, right: Option<Self>) -> Option<Self> {
         match (left, right) {
             // If both are the *same* concrete tag, that is the result.
@@ -1170,11 +1182,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
 
     fn adjust_alloc_base_pointer(
         ecx: &MiriInterpCx<'mir, 'tcx>,
-        ptr: Pointer<AllocId>,
+        ptr: Pointer<CtfeProvenance>,
     ) -> InterpResult<'tcx, Pointer<Provenance>> {
+        let alloc_id = ptr.provenance.alloc_id();
         if cfg!(debug_assertions) {
             // The machine promises to never call us on thread-local or extern statics.
-            let alloc_id = ptr.provenance;
             match ecx.tcx.try_get_global_alloc(alloc_id) {
                 Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => {
                     panic!("adjust_alloc_base_pointer called on thread-local static")
@@ -1185,8 +1197,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
                 _ => {}
             }
         }
+        // FIXME: can we somehow preserve the immutability of `ptr`?
         let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
-            borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine)
+            borrow_tracker.borrow_mut().base_ptr_tag(alloc_id, &ecx.machine)
         } else {
             // Value does not matter, SB is disabled
             BorTag::default()
@@ -1245,7 +1258,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
 
     #[inline(always)]
     fn before_memory_read(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         machine: &Self,
         alloc_extra: &AllocExtra<'tcx>,
         (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
@@ -1265,7 +1278,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
 
     #[inline(always)]
     fn before_memory_write(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         machine: &mut Self,
         alloc_extra: &mut AllocExtra<'tcx>,
         (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
@@ -1285,7 +1298,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
 
     #[inline(always)]
     fn before_memory_deallocation(
-        _tcx: TyCtxt<'tcx>,
+        _tcx: TyCtxtAt<'tcx>,
         machine: &mut Self,
         alloc_extra: &mut AllocExtra<'tcx>,
         (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra),
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
index f20bfef8c79..9cc4c7c4d76 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
@@ -18,19 +18,19 @@ fn main() -> () {
 }
 
 ALLOC9 (static: FOO, size: 8, align: 4) {
-    ╾ALLOC0╼ 03 00 00 00                         │ ╾──╼....
+    ╾ALLOC0<imm>╼ 03 00 00 00                         │ ╾──╼....
 }
 
 ALLOC0 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ 03 00 00 00 │ ....*...╾──╼....
+    0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1<imm>╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2<imm>╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3<imm>╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
 ALLOC1 (size: 0, align: 4) {}
 
 ALLOC2 (size: 16, align: 4) {
-    ╾ALLOC4╼ 03 00 00 00 ╾ALLOC5╼ 03 00 00 00 │ ╾──╼....╾──╼....
+    ╾ALLOC4<imm>╼ 03 00 00 00 ╾ALLOC5<imm>╼ 03 00 00 00 │ ╾──╼....╾──╼....
 }
 
 ALLOC4 (size: 3, align: 1) {
@@ -42,8 +42,8 @@ ALLOC5 (size: 3, align: 1) {
 }
 
 ALLOC3 (size: 24, align: 4) {
-    0x00 │ ╾ALLOC6╼ 03 00 00 00 ╾ALLOC7╼ 03 00 00 00 │ ╾──╼....╾──╼....
-    0x10 │ ╾ALLOC8╼ 04 00 00 00                         │ ╾──╼....
+    0x00 │ ╾ALLOC6<imm>╼ 03 00 00 00 ╾ALLOC7<imm>╼ 03 00 00 00 │ ╾──╼....╾──╼....
+    0x10 │ ╾ALLOC8<imm>╼ 04 00 00 00                         │ ╾──╼....
 }
 
 ALLOC6 (size: 3, align: 1) {
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
index 263cae2f3ea..faa9d20f2d5 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
@@ -18,22 +18,22 @@ fn main() -> () {
 }
 
 ALLOC9 (static: FOO, size: 16, align: 8) {
-    ╾ALLOC0╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾ALLOC0<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 ALLOC0 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ │ ....░░░░╾──────╼
+    0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1<imm>╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾ALLOC2╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ │ ....*...╾──────╼
+    0x20 │ ╾ALLOC2<imm>╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3<imm>╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
 ALLOC1 (size: 0, align: 8) {}
 
 ALLOC2 (size: 32, align: 8) {
-    0x00 │ ╾ALLOC4╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾ALLOC5╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x00 │ ╾ALLOC4<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾ALLOC5<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 ALLOC4 (size: 3, align: 1) {
@@ -45,9 +45,9 @@ ALLOC5 (size: 3, align: 1) {
 }
 
 ALLOC3 (size: 48, align: 8) {
-    0x00 │ ╾ALLOC6╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾ALLOC7╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x20 │ ╾ALLOC8╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x00 │ ╾ALLOC6<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾ALLOC7<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x20 │ ╾ALLOC8<imm>╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 ALLOC6 (size: 3, align: 1) {
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
index 713abb264a7..898835b46e4 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
@@ -18,19 +18,19 @@ fn main() -> () {
 }
 
 ALLOC9 (static: FOO, size: 8, align: 4) {
-    ╾ALLOC0╼ 03 00 00 00                         │ ╾──╼....
+    ╾ALLOC0<imm>╼ 03 00 00 00                         │ ╾──╼....
 }
 
 ALLOC0 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ 03 00 00 00 │ ....*...╾──╼....
+    0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1<imm>╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2<imm>╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3<imm>╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
 ALLOC1 (size: 0, align: 4) {}
 
 ALLOC2 (size: 8, align: 4) {
-    ╾ALLOC4╼ ╾ALLOC5╼                         │ ╾──╼╾──╼
+    ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼                         │ ╾──╼╾──╼
 }
 
 ALLOC4 (size: 1, align: 1) {
@@ -42,7 +42,7 @@ ALLOC5 (size: 1, align: 1) {
 }
 
 ALLOC3 (size: 12, align: 4) {
-    ╾ALLOC6+0x3╼ ╾ALLOC7╼ ╾ALLOC8+0x2╼             │ ╾──╼╾──╼╾──╼
+    ╾ALLOC6+0x3<imm>╼ ╾ALLOC7<imm>╼ ╾ALLOC8+0x2<imm>╼             │ ╾──╼╾──╼╾──╼
 }
 
 ALLOC6 (size: 4, align: 1) {
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
index e9d61ef120c..f5352c2aebb 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
@@ -18,21 +18,21 @@ fn main() -> () {
 }
 
 ALLOC9 (static: FOO, size: 16, align: 8) {
-    ╾ALLOC0╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾ALLOC0<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 ALLOC0 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ │ ....░░░░╾──────╼
+    0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1<imm>╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾ALLOC2╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ │ ....*...╾──────╼
+    0x20 │ ╾ALLOC2<imm>╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3<imm>╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
 ALLOC1 (size: 0, align: 8) {}
 
 ALLOC2 (size: 16, align: 8) {
-    ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼
+    ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼
 }
 
 ALLOC4 (size: 1, align: 1) {
@@ -44,8 +44,8 @@ ALLOC5 (size: 1, align: 1) {
 }
 
 ALLOC3 (size: 24, align: 8) {
-    0x00 │ ╾ALLOC6+0x3╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼
-    0x10 │ ╾ALLOC8+0x2╼                         │ ╾──────╼
+    0x00 │ ╾ALLOC6+0x3<imm>╼ ╾ALLOC7<imm>╼ │ ╾──────╼╾──────╼
+    0x10 │ ╾ALLOC8+0x2<imm>╼                         │ ╾──────╼
 }
 
 ALLOC6 (size: 4, align: 1) {
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
index c18c067c72e..624047f5b6f 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
@@ -18,12 +18,12 @@ fn main() -> () {
 }
 
 ALLOC4 (static: FOO, size: 4, align: 4) {
-    ╾ALLOC0╼                                     │ ╾──╼
+    ╾ALLOC0<imm>╼                                     │ ╾──╼
 }
 
 ALLOC0 (size: 168, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾ALLOC1╼ │ ............╾──╼
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾ALLOC1<imm>╼ │ ............╾──╼
     0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
@@ -31,7 +31,7 @@ ALLOC0 (size: 168, align: 1) {
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾ALLOC2╼ 00 00 │ ..........╾──╼..
-    0x90 │ ╾ALLOC3+0x63╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
+    0x90 │ ╾ALLOC3+0x63<imm>╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
     0xa0 │ 00 00 00 00 00 00 00 00                         │ ........
 }
 
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
index 6af0e3cbd94..cdd4758e153 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
@@ -18,12 +18,12 @@ fn main() -> () {
 }
 
 ALLOC2 (static: FOO, size: 8, align: 8) {
-    ╾ALLOC0╼                         │ ╾──────╼
+    ╾ALLOC0<imm>╼                         │ ╾──────╼
 }
 
 ALLOC0 (size: 180, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──ALLOC3── │ ............╾───
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾ALLOC3<imm> (8 ptr bytes) │ ............╾───
     0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
@@ -31,7 +31,7 @@ ALLOC0 (size: 180, align: 1) {
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─
-    0x90 │ ─────ALLOC4─────╼ 00 00 ╾ALLOC1+0x63╼ │ ─────╼..╾──────╼
+    0x90 │ ─────ALLOC4─────╼ 00 00 ╾ALLOC1+0x63<imm>╼ │ ─────╼..╾──────╼
     0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0xb0 │ 00 00 00 00                                     │ ....
 }
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
index d502b198239..053981abea3 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
@@ -118,7 +118,7 @@
   }
   
   ALLOC2 (static: RC, size: 4, align: 4) {
-      ╾ALLOC0╼                                     │ ╾──╼
+      ╾ALLOC0<imm>╼                                     │ ╾──╼
   }
   
   ALLOC0 (size: 8, align: 4) {
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
index 5d69572b507..d862bd93ff5 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
@@ -118,7 +118,7 @@
   }
   
   ALLOC2 (static: RC, size: 8, align: 8) {
-      ╾ALLOC0╼                         │ ╾──────╼
+      ╾ALLOC0<imm>╼                         │ ╾──────╼
   }
   
   ALLOC0 (size: 8, align: 4) {
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
index 8499d0a89c3..0f461f515fd 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
@@ -220,11 +220,11 @@
   }
   
   ALLOC5 (static: BIG_STAT, size: 4, align: 4) {
-      ╾ALLOC0╼                                     │ ╾──╼
+      ╾ALLOC0<imm>╼                                     │ ╾──╼
   }
   
   ALLOC0 (size: 20, align: 4) {
-      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ 02 00 00 00 │ ....#...╾──╼....
+      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1<imm>╼ 02 00 00 00 │ ....#...╾──╼....
       0x10 │ 00 00 a4 42                                     │ ...B
   }
   
@@ -233,11 +233,11 @@
   }
   
   ALLOC4 (static: SMALL_STAT, size: 4, align: 4) {
-      ╾ALLOC2╼                                     │ ╾──╼
+      ╾ALLOC2<imm>╼                                     │ ╾──╼
   }
   
   ALLOC2 (size: 20, align: 4) {
-      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ 01 00 00 00 │ ....░░░░╾──╼....
+      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3<imm>╼ 01 00 00 00 │ ....░░░░╾──╼....
       0x10 │ 00 00 10 41                                     │ ...A
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
index 01ec3f623d1..3c40ec8bfb4 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
@@ -220,11 +220,11 @@
   }
   
   ALLOC5 (static: BIG_STAT, size: 8, align: 8) {
-      ╾ALLOC0╼                         │ ╾──────╼
+      ╾ALLOC0<imm>╼                         │ ╾──────╼
   }
   
   ALLOC0 (size: 32, align: 8) {
-      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ │ ....#...╾──────╼
+      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1<imm>╼ │ ....#...╾──────╼
       0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........B░░░░
   }
   
@@ -233,11 +233,11 @@
   }
   
   ALLOC4 (static: SMALL_STAT, size: 8, align: 8) {
-      ╾ALLOC2╼                         │ ╾──────╼
+      ╾ALLOC2<imm>╼                         │ ╾──────╼
   }
   
   ALLOC2 (size: 32, align: 8) {
-      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ │ ....░░░░╾──────╼
+      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3<imm>╼ │ ....░░░░╾──────╼
       0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........A░░░░
   }
   
diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff
index eaea5db77c9..d5628dc7a6e 100644
--- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff
@@ -78,7 +78,7 @@
           StorageLive(_6);
           _9 = const _;
 -         _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable];
-+         _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable];
++         _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff
index f2c2504f802..d28059458ae 100644
--- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff
@@ -76,7 +76,7 @@
           StorageLive(_6);
           _9 = const _;
 -         _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue];
-+         _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue];
++         _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue];
       }
   
       bb5: {
diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff
index d31a9a5c079..d139fc73e21 100644
--- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff
@@ -78,7 +78,7 @@
           StorageLive(_6);
           _9 = const _;
 -         _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable];
-+         _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable];
++         _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff
index 62e05a68955..63db9553b37 100644
--- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff
@@ -76,7 +76,7 @@
           StorageLive(_6);
           _9 = const _;
 -         _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue];
-+         _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue];
++         _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue];
       }
   
       bb5: {
diff --git a/tests/run-make/jobserver-error/cannot_open_fd.stderr b/tests/run-make/jobserver-error/cannot_open_fd.stderr
index 343de5cd52c..a2f77a94e4f 100644
--- a/tests/run-make/jobserver-error/cannot_open_fd.stderr
+++ b/tests/run-make/jobserver-error/cannot_open_fd.stderr
@@ -4,3 +4,5 @@ warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--
 
 error: no input filename given
 
+warning: 1 warning emitted
+
diff --git a/tests/run-make/jobserver-error/not_a_pipe.stderr b/tests/run-make/jobserver-error/not_a_pipe.stderr
index 536c04576b9..9158fda6e47 100644
--- a/tests/run-make/jobserver-error/not_a_pipe.stderr
+++ b/tests/run-make/jobserver-error/not_a_pipe.stderr
@@ -2,3 +2,5 @@ warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--
   |
   = note: the build environment is likely misconfigured
 
+warning: 1 warning emitted
+
diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs
index 976dfee774b..5cb07eabf41 100644
--- a/tests/ui-fulldeps/stable-mir/check_instance.rs
+++ b/tests/ui-fulldeps/stable-mir/check_instance.rs
@@ -64,8 +64,12 @@ fn test_body(body: mir::Body) {
                 let RigidTy::FnDef(def, args) = ty else { unreachable!() };
                 let instance = Instance::resolve(def, &args).unwrap();
                 let mangled_name = instance.mangled_name();
-                let body = instance.body();
-                assert!(body.is_some() || mangled_name == "setpwent", "Failed: {func:?}");
+                assert!(instance.has_body() || (mangled_name == "setpwent"), "Failed: {func:?}");
+                assert!(instance.has_body() ^ instance.is_foreign_item());
+                if instance.has_body() {
+                    let body = instance.body().unwrap();
+                    assert!(!body.locals().is_empty(), "Body must at least have a return local");
+                }
             }
             Goto { .. } | Assert { .. } | SwitchInt { .. } | Return | Drop { .. } => {
                 /* Do nothing */
diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
new file mode 100644
index 00000000000..b90d47d4540
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
@@ -0,0 +1,115 @@
+// run-pass
+//! Test that users are able to use stable mir APIs to retrieve monomorphized types, and that
+//! we have an error handling for trying to instantiate types with incorrect arguments.
+
+// ignore-stage1
+// ignore-cross-compile
+// ignore-remote
+// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+// edition: 2021
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+#![feature(control_flow_enum)]
+
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use rustc_middle::ty::TyCtxt;
+use rustc_smir::rustc_internal;
+use stable_mir::ty::{RigidTy, TyKind, Ty, };
+use stable_mir::mir::{Body, MirVisitor, FieldIdx, Place, ProjectionElem, visit::{Location,
+                                                                            PlaceContext}};
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "input";
+
+/// This function uses the Stable MIR APIs to get information about the test crate.
+fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+    let main_fn = stable_mir::entry_fn();
+    let body = main_fn.unwrap().body();
+    let mut visitor = PlaceVisitor{ body: &body, tested: false};
+    visitor.visit_body(&body);
+    assert!(visitor.tested);
+    ControlFlow::Continue(())
+}
+
+struct PlaceVisitor<'a> {
+    body: &'a Body,
+    /// Used to ensure that the test was reachable. Otherwise this test would vacuously succeed.
+    tested: bool,
+}
+
+/// Check that `wrapper.inner` place projection can be correctly interpreted.
+/// Ensure that instantiation is correct.
+fn check_tys(local_ty: Ty, idx: FieldIdx, expected_ty: Ty) {
+    let TyKind::RigidTy(RigidTy::Adt(def, args)) = local_ty.kind() else { unreachable!() };
+    assert_eq!(def.ty_with_args(&args), local_ty);
+
+    let field_def = &def.variants_iter().next().unwrap().fields()[idx];
+    let field_ty = field_def.ty_with_args(&args);
+    assert_eq!(field_ty, expected_ty);
+
+    // Check that the generic version is different than the instantiated one.
+    let field_ty_gen = field_def.ty();
+    assert_ne!(field_ty_gen, field_ty);
+}
+
+impl<'a> MirVisitor for PlaceVisitor<'a> {
+    fn visit_place(&mut self, place: &Place, _ptx: PlaceContext, _loc: Location) {
+        let start_ty = self.body.locals()[place.local].ty;
+        match place.projection.as_slice() {
+            [ProjectionElem::Field(idx, ty)] => {
+                check_tys(start_ty, *idx, *ty);
+                self.tested = true;
+            }
+            _ => {}
+        }
+    }
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "ty_fold_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "-Cpanic=abort".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, tcx, test_stable_mir(tcx)).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        struct Wrapper<T: Default> {{
+            pub inner: T
+        }}
+
+        impl<T: Default> Wrapper<T> {{
+            pub fn new() -> Wrapper<T> {{
+                Wrapper {{ inner: T::default() }}
+            }}
+        }}
+
+        fn main() {{
+            let wrapper = Wrapper::<u8>::new();
+            let _inner = wrapper.inner;
+        }}
+    "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
index 971abb1a21a..9efc77fb43f 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `unknown_key`
-  --> $DIR/exhaustive-names-values.rs:11:7
+  --> $DIR/exhaustive-names-values.rs:10:7
    |
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #[cfg(unknown_key = "value")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `value`
-  --> $DIR/exhaustive-names-values.rs:15:7
+  --> $DIR/exhaustive-names-values.rs:14:7
    |
 LL | #[cfg(test = "value")]
    |       ^^^^----------
@@ -18,13 +18,13 @@ LL | #[cfg(test = "value")]
    = note: no expected value for `test`
 
 warning: unexpected `cfg` condition name: `feature`
-  --> $DIR/exhaustive-names-values.rs:19:7
+  --> $DIR/exhaustive-names-values.rs:18:7
    |
 LL | #[cfg(feature = "unk")]
    |       ^^^^^^^^^^^^^^^
 
 warning: unexpected `cfg` condition name: `feature`
-  --> $DIR/exhaustive-names-values.rs:26:7
+  --> $DIR/exhaustive-names-values.rs:25:7
    |
 LL | #[cfg(feature = "std")]
    |       ^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
index d71ca095894..4549482abcb 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `unknown_key`
-  --> $DIR/exhaustive-names-values.rs:11:7
+  --> $DIR/exhaustive-names-values.rs:10:7
    |
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #[cfg(unknown_key = "value")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `value`
-  --> $DIR/exhaustive-names-values.rs:15:7
+  --> $DIR/exhaustive-names-values.rs:14:7
    |
 LL | #[cfg(test = "value")]
    |       ^^^^----------
@@ -18,7 +18,7 @@ LL | #[cfg(test = "value")]
    = note: no expected value for `test`
 
 warning: unexpected `cfg` condition value: `unk`
-  --> $DIR/exhaustive-names-values.rs:19:7
+  --> $DIR/exhaustive-names-values.rs:18:7
    |
 LL | #[cfg(feature = "unk")]
    |       ^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
index d71ca095894..4549482abcb 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `unknown_key`
-  --> $DIR/exhaustive-names-values.rs:11:7
+  --> $DIR/exhaustive-names-values.rs:10:7
    |
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #[cfg(unknown_key = "value")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `value`
-  --> $DIR/exhaustive-names-values.rs:15:7
+  --> $DIR/exhaustive-names-values.rs:14:7
    |
 LL | #[cfg(test = "value")]
    |       ^^^^----------
@@ -18,7 +18,7 @@ LL | #[cfg(test = "value")]
    = note: no expected value for `test`
 
 warning: unexpected `cfg` condition value: `unk`
-  --> $DIR/exhaustive-names-values.rs:19:7
+  --> $DIR/exhaustive-names-values.rs:18:7
    |
 LL | #[cfg(feature = "unk")]
    |       ^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/exhaustive-names-values.rs b/tests/ui/check-cfg/exhaustive-names-values.rs
index ceb4831e22d..956992a1e77 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.rs
+++ b/tests/ui/check-cfg/exhaustive-names-values.rs
@@ -1,9 +1,8 @@
 // Check warning for unexpected cfg in the code.
 //
 // check-pass
-// revisions: empty_names_values empty_cfg feature full
+// revisions: empty_cfg feature full
 // compile-flags: -Z unstable-options
-// [empty_names_values]compile-flags: --check-cfg=names() --check-cfg=values()
 // [empty_cfg]compile-flags: --check-cfg=cfg()
 // [feature]compile-flags: --check-cfg=cfg(feature,values("std"))
 // [full]compile-flags: --check-cfg=cfg(feature,values("std")) --check-cfg=cfg()
diff --git a/tests/ui/check-cfg/exhaustive-names.rs b/tests/ui/check-cfg/exhaustive-names.rs
index b86a7f84eb4..80668020699 100644
--- a/tests/ui/check-cfg/exhaustive-names.rs
+++ b/tests/ui/check-cfg/exhaustive-names.rs
@@ -1,9 +1,7 @@
 // Check warning for unexpected cfg
 //
 // check-pass
-// revisions: empty_names exhaustive_names
-// [empty_names]compile-flags: --check-cfg=names() -Z unstable-options
-// [exhaustive_names]compile-flags: --check-cfg=cfg() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[cfg(unknown_key = "value")]
 //~^ WARNING unexpected `cfg` condition name
diff --git a/tests/ui/check-cfg/exhaustive-names.empty_names.stderr b/tests/ui/check-cfg/exhaustive-names.stderr
index 7d01c73cc09..866595b1213 100644
--- a/tests/ui/check-cfg/exhaustive-names.empty_names.stderr
+++ b/tests/ui/check-cfg/exhaustive-names.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `unknown_key`
-  --> $DIR/exhaustive-names.rs:8:7
+  --> $DIR/exhaustive-names.rs:6:7
    |
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr
index 77ddc35100a..745646bda1c 100644
--- a/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr
+++ b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `value`
-  --> $DIR/exhaustive-values.rs:9:7
+  --> $DIR/exhaustive-values.rs:8:7
    |
 LL | #[cfg(test = "value")]
    |       ^^^^----------
diff --git a/tests/ui/check-cfg/exhaustive-values.empty_values.stderr b/tests/ui/check-cfg/exhaustive-values.empty_values.stderr
deleted file mode 100644
index 77ddc35100a..00000000000
--- a/tests/ui/check-cfg/exhaustive-values.empty_values.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-warning: unexpected `cfg` condition value: `value`
-  --> $DIR/exhaustive-values.rs:9:7
-   |
-LL | #[cfg(test = "value")]
-   |       ^^^^----------
-   |           |
-   |           help: remove the value
-   |
-   = note: no expected value for `test`
-   = note: `#[warn(unexpected_cfgs)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/check-cfg/exhaustive-values.rs b/tests/ui/check-cfg/exhaustive-values.rs
index 8a1689ba86b..430d3b89e7a 100644
--- a/tests/ui/check-cfg/exhaustive-values.rs
+++ b/tests/ui/check-cfg/exhaustive-values.rs
@@ -1,8 +1,7 @@
 // Check warning for unexpected cfg value
 //
 // check-pass
-// revisions: empty_values empty_cfg without_names
-// [empty_values]compile-flags: --check-cfg=values() -Z unstable-options
+// revisions: empty_cfg without_names
 // [empty_cfg]compile-flags: --check-cfg=cfg() -Z unstable-options
 // [without_names]compile-flags: --check-cfg=cfg(any()) -Z unstable-options
 
diff --git a/tests/ui/check-cfg/exhaustive-values.without_names.stderr b/tests/ui/check-cfg/exhaustive-values.without_names.stderr
index 77ddc35100a..745646bda1c 100644
--- a/tests/ui/check-cfg/exhaustive-values.without_names.stderr
+++ b/tests/ui/check-cfg/exhaustive-values.without_names.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `value`
-  --> $DIR/exhaustive-values.rs:9:7
+  --> $DIR/exhaustive-values.rs:8:7
    |
 LL | #[cfg(test = "value")]
    |       ^^^^----------
diff --git a/tests/ui/check-cfg/invalid-arguments.names_simple_ident.stderr b/tests/ui/check-cfg/invalid-arguments.names_simple_ident.stderr
deleted file mode 100644
index 8fadcc1f9f0..00000000000
--- a/tests/ui/check-cfg/invalid-arguments.names_simple_ident.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error: invalid `--check-cfg` argument: `names("NOT_IDENT")` (`names()` arguments must be simple identifiers)
-
diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs
index a56f48e0af9..90c62fa3807 100644
--- a/tests/ui/check-cfg/invalid-arguments.rs
+++ b/tests/ui/check-cfg/invalid-arguments.rs
@@ -1,7 +1,7 @@
 // Check that invalid --check-cfg are rejected
 //
 // check-fail
-// revisions: anything_else names_simple_ident values_simple_ident values_string_literals
+// revisions: anything_else
 // revisions: string_for_name_1 string_for_name_2 multiple_any multiple_values
 // revisions: multiple_values_any not_empty_any not_empty_values_any
 // revisions: values_any_missing_values values_any_before_ident ident_in_values_1
@@ -10,9 +10,6 @@
 //
 // compile-flags: -Z unstable-options
 // [anything_else]compile-flags: --check-cfg=anything_else(...)
-// [names_simple_ident]compile-flags: --check-cfg=names("NOT_IDENT")
-// [values_simple_ident]compile-flags: --check-cfg=values("NOT_IDENT")
-// [values_string_literals]compile-flags: --check-cfg=values(test,12)
 // [string_for_name_1]compile-flags: --check-cfg=cfg("NOT_IDENT")
 // [string_for_name_2]compile-flags: --check-cfg=cfg(foo,"NOT_IDENT",bar)
 // [multiple_any]compile-flags: --check-cfg=cfg(any(),any())
diff --git a/tests/ui/check-cfg/invalid-arguments.values_simple_ident.stderr b/tests/ui/check-cfg/invalid-arguments.values_simple_ident.stderr
deleted file mode 100644
index 061d3f0e971..00000000000
--- a/tests/ui/check-cfg/invalid-arguments.values_simple_ident.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error: invalid `--check-cfg` argument: `values("NOT_IDENT")` (`values()` first argument must be a simple identifier)
-
diff --git a/tests/ui/check-cfg/invalid-arguments.values_string_literals.stderr b/tests/ui/check-cfg/invalid-arguments.values_string_literals.stderr
deleted file mode 100644
index 5853b4741a6..00000000000
--- a/tests/ui/check-cfg/invalid-arguments.values_string_literals.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error: invalid `--check-cfg` argument: `values(test,12)` (`values()` arguments must be string literals)
-
diff --git a/tests/ui/check-cfg/mix.rs b/tests/ui/check-cfg/mix.rs
index d7b3b4953b7..a6c3efee611 100644
--- a/tests/ui/check-cfg/mix.rs
+++ b/tests/ui/check-cfg/mix.rs
@@ -1,13 +1,10 @@
-// This test checks the combination of well known names, their activation via names(),
-// the usage of values(), and that no implicit is done with --cfg while also testing that
+// This test checks the combination of well known names, the usage of cfg(),
+// and that no implicit cfgs is added from --cfg while also testing that
 // we correctly lint on the `cfg!` macro and `cfg_attr` attribute.
 //
 // check-pass
-// revisions: names_values cfg
 // compile-flags: --cfg feature="bar" --cfg unknown_name -Z unstable-options
-// compile-flags: --check-cfg=cfg(names_values,cfg)
-// [names_values]compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo")
-// [cfg]compile-flags: --check-cfg=cfg(feature,values("foo"))
+// compile-flags: --check-cfg=cfg(feature,values("foo"))
 
 #[cfg(windows)]
 fn do_windows_stuff() {}
diff --git a/tests/ui/check-cfg/mix.names_values.stderr b/tests/ui/check-cfg/mix.stderr
index 21c0c7da1dd..eefdbd6af30 100644
--- a/tests/ui/check-cfg/mix.names_values.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/mix.rs:15:7
+  --> $DIR/mix.rs:12:7
    |
 LL | #[cfg(widnows)]
    |       ^^^^^^^ help: there is a config with a similar name: `windows`
@@ -7,7 +7,7 @@ LL | #[cfg(widnows)]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: (none)
-  --> $DIR/mix.rs:19:7
+  --> $DIR/mix.rs:16:7
    |
 LL | #[cfg(feature)]
    |       ^^^^^^^- help: specify a config value: `= "foo"`
@@ -15,7 +15,7 @@ LL | #[cfg(feature)]
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/mix.rs:26:7
+  --> $DIR/mix.rs:23:7
    |
 LL | #[cfg(feature = "bar")]
    |       ^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | #[cfg(feature = "bar")]
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:30:7
+  --> $DIR/mix.rs:27:7
    |
 LL | #[cfg(feature = "zebra")]
    |       ^^^^^^^^^^^^^^^^^
@@ -31,21 +31,21 @@ LL | #[cfg(feature = "zebra")]
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `uu`
-  --> $DIR/mix.rs:34:12
+  --> $DIR/mix.rs:31:12
    |
 LL | #[cfg_attr(uu, test)]
    |            ^^
    |
-   = help: expected names are: `cfg`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `names_values`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
 
 warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/mix.rs:43:10
+  --> $DIR/mix.rs:40:10
    |
 LL |     cfg!(widnows);
    |          ^^^^^^^ help: there is a config with a similar name: `windows`
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/mix.rs:46:10
+  --> $DIR/mix.rs:43:10
    |
 LL |     cfg!(feature = "bar");
    |          ^^^^^^^^^^^^^^^
@@ -53,7 +53,7 @@ LL |     cfg!(feature = "bar");
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:48:10
+  --> $DIR/mix.rs:45:10
    |
 LL |     cfg!(feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^
@@ -61,25 +61,25 @@ LL |     cfg!(feature = "zebra");
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:50:10
+  --> $DIR/mix.rs:47:10
    |
 LL |     cfg!(xxx = "foo");
    |          ^^^^^^^^^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:52:10
+  --> $DIR/mix.rs:49:10
    |
 LL |     cfg!(xxx);
    |          ^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:54:14
+  --> $DIR/mix.rs:51:14
    |
 LL |     cfg!(any(xxx, windows));
    |              ^^^
 
 warning: unexpected `cfg` condition value: `bad`
-  --> $DIR/mix.rs:56:14
+  --> $DIR/mix.rs:53:14
    |
 LL |     cfg!(any(feature = "bad", windows));
    |              ^^^^^^^^^^^^^^^
@@ -87,43 +87,43 @@ LL |     cfg!(any(feature = "bad", windows));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:58:23
+  --> $DIR/mix.rs:55:23
    |
 LL |     cfg!(any(windows, xxx));
    |                       ^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:60:20
+  --> $DIR/mix.rs:57:20
    |
 LL |     cfg!(all(unix, xxx));
    |                    ^^^
 
 warning: unexpected `cfg` condition name: `aa`
-  --> $DIR/mix.rs:62:14
+  --> $DIR/mix.rs:59:14
    |
 LL |     cfg!(all(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name: `bb`
-  --> $DIR/mix.rs:62:18
+  --> $DIR/mix.rs:59:18
    |
 LL |     cfg!(all(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition name: `aa`
-  --> $DIR/mix.rs:65:14
+  --> $DIR/mix.rs:62:14
    |
 LL |     cfg!(any(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name: `bb`
-  --> $DIR/mix.rs:65:18
+  --> $DIR/mix.rs:62:18
    |
 LL |     cfg!(any(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:68:20
+  --> $DIR/mix.rs:65:20
    |
 LL |     cfg!(any(unix, feature = "zebra"));
    |                    ^^^^^^^^^^^^^^^^^
@@ -131,13 +131,13 @@ LL |     cfg!(any(unix, feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:70:14
+  --> $DIR/mix.rs:67:14
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |              ^^^
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:70:19
+  --> $DIR/mix.rs:67:19
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |                   ^^^^^^^^^^^^^^^^^
@@ -145,19 +145,19 @@ LL |     cfg!(any(xxx, feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:73:14
+  --> $DIR/mix.rs:70:14
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |              ^^^
 
 warning: unexpected `cfg` condition name: `xxx`
-  --> $DIR/mix.rs:73:25
+  --> $DIR/mix.rs:70:25
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |                         ^^^
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:76:14
+  --> $DIR/mix.rs:73:14
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |              ^^^^^^^^^^^^^^^^^
@@ -165,7 +165,7 @@ LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:76:33
+  --> $DIR/mix.rs:73:33
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                 ^^^^^^^^^^^^^^^^^
@@ -173,7 +173,7 @@ LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value: `zebra`
-  --> $DIR/mix.rs:76:52
+  --> $DIR/mix.rs:73:52
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                                    ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/no-expected-values.empty.stderr b/tests/ui/check-cfg/no-expected-values.empty.stderr
index 5d261b2a5e6..0969d61dd40 100644
--- a/tests/ui/check-cfg/no-expected-values.empty.stderr
+++ b/tests/ui/check-cfg/no-expected-values.empty.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-expected-values.rs:12:7
+  --> $DIR/no-expected-values.rs:11:7
    |
 LL | #[cfg(feature = "foo")]
    |       ^^^^^^^--------
@@ -10,7 +10,7 @@ LL | #[cfg(feature = "foo")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-expected-values.rs:16:7
+  --> $DIR/no-expected-values.rs:15:7
    |
 LL | #[cfg(test = "foo")]
    |       ^^^^--------
diff --git a/tests/ui/check-cfg/no-expected-values.mixed.stderr b/tests/ui/check-cfg/no-expected-values.mixed.stderr
index 5d261b2a5e6..0969d61dd40 100644
--- a/tests/ui/check-cfg/no-expected-values.mixed.stderr
+++ b/tests/ui/check-cfg/no-expected-values.mixed.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-expected-values.rs:12:7
+  --> $DIR/no-expected-values.rs:11:7
    |
 LL | #[cfg(feature = "foo")]
    |       ^^^^^^^--------
@@ -10,7 +10,7 @@ LL | #[cfg(feature = "foo")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-expected-values.rs:16:7
+  --> $DIR/no-expected-values.rs:15:7
    |
 LL | #[cfg(test = "foo")]
    |       ^^^^--------
diff --git a/tests/ui/check-cfg/no-expected-values.rs b/tests/ui/check-cfg/no-expected-values.rs
index 9e2a9f09aed..9f34c019ea5 100644
--- a/tests/ui/check-cfg/no-expected-values.rs
+++ b/tests/ui/check-cfg/no-expected-values.rs
@@ -1,10 +1,9 @@
 // Check that we detect unexpected value when none are allowed
 //
 // check-pass
-// revisions: values simple mixed empty
+// revisions: simple mixed empty
 // compile-flags: -Z unstable-options
 // compile-flags: --check-cfg=cfg(values,simple,mixed,empty)
-// [values]compile-flags: --check-cfg=values(test) --check-cfg=values(feature)
 // [simple]compile-flags: --check-cfg=cfg(test) --check-cfg=cfg(feature)
 // [mixed]compile-flags: --check-cfg=cfg(test,feature)
 // [empty]compile-flags: --check-cfg=cfg(test,feature,values())
diff --git a/tests/ui/check-cfg/no-expected-values.simple.stderr b/tests/ui/check-cfg/no-expected-values.simple.stderr
index 5d261b2a5e6..0969d61dd40 100644
--- a/tests/ui/check-cfg/no-expected-values.simple.stderr
+++ b/tests/ui/check-cfg/no-expected-values.simple.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-expected-values.rs:12:7
+  --> $DIR/no-expected-values.rs:11:7
    |
 LL | #[cfg(feature = "foo")]
    |       ^^^^^^^--------
@@ -10,7 +10,7 @@ LL | #[cfg(feature = "foo")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-expected-values.rs:16:7
+  --> $DIR/no-expected-values.rs:15:7
    |
 LL | #[cfg(test = "foo")]
    |       ^^^^--------
diff --git a/tests/ui/check-cfg/no-expected-values.values.stderr b/tests/ui/check-cfg/no-expected-values.values.stderr
deleted file mode 100644
index 5d261b2a5e6..00000000000
--- a/tests/ui/check-cfg/no-expected-values.values.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-expected-values.rs:12:7
-   |
-LL | #[cfg(feature = "foo")]
-   |       ^^^^^^^--------
-   |              |
-   |              help: remove the value
-   |
-   = note: no expected value for `feature`
-   = note: `#[warn(unexpected_cfgs)]` on by default
-
-warning: unexpected `cfg` condition value: `foo`
-  --> $DIR/no-expected-values.rs:16:7
-   |
-LL | #[cfg(test = "foo")]
-   |       ^^^^--------
-   |           |
-   |           help: remove the value
-   |
-   = note: no expected value for `test`
-
-warning: 2 warnings emitted
-
diff --git a/tests/ui/check-cfg/order-independant.names_after.stderr b/tests/ui/check-cfg/order-independant.names_after.stderr
deleted file mode 100644
index a308358e485..00000000000
--- a/tests/ui/check-cfg/order-independant.names_after.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-warning: unexpected `cfg` condition value: (none)
-  --> $DIR/order-independant.rs:8:7
-   |
-LL | #[cfg(a)]
-   |       ^- help: specify a config value: `= "b"`
-   |
-   = note: expected values for `a` are: `b`
-   = note: `#[warn(unexpected_cfgs)]` on by default
-
-warning: unexpected `cfg` condition value: `unk`
-  --> $DIR/order-independant.rs:12:7
-   |
-LL | #[cfg(a = "unk")]
-   |       ^^^^^^^^^
-   |
-   = note: expected values for `a` are: `b`
-
-warning: 2 warnings emitted
-
diff --git a/tests/ui/check-cfg/order-independant.names_before.stderr b/tests/ui/check-cfg/order-independant.names_before.stderr
deleted file mode 100644
index a308358e485..00000000000
--- a/tests/ui/check-cfg/order-independant.names_before.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-warning: unexpected `cfg` condition value: (none)
-  --> $DIR/order-independant.rs:8:7
-   |
-LL | #[cfg(a)]
-   |       ^- help: specify a config value: `= "b"`
-   |
-   = note: expected values for `a` are: `b`
-   = note: `#[warn(unexpected_cfgs)]` on by default
-
-warning: unexpected `cfg` condition value: `unk`
-  --> $DIR/order-independant.rs:12:7
-   |
-LL | #[cfg(a = "unk")]
-   |       ^^^^^^^^^
-   |
-   = note: expected values for `a` are: `b`
-
-warning: 2 warnings emitted
-
diff --git a/tests/ui/check-cfg/order-independant.rs b/tests/ui/check-cfg/order-independant.rs
index ce056b8dcd6..86e3cfa1d9b 100644
--- a/tests/ui/check-cfg/order-independant.rs
+++ b/tests/ui/check-cfg/order-independant.rs
@@ -1,12 +1,13 @@
 // check-pass
-// revisions: names_before names_after
+//
+// revisions: values_before values_after
 // compile-flags: -Z unstable-options
-// compile-flags: --check-cfg=names(names_before,names_after)
-// [names_before]compile-flags: --check-cfg=names(a) --check-cfg=values(a,"b")
-// [names_after]compile-flags: --check-cfg=values(a,"b") --check-cfg=names(a)
+// compile-flags: --check-cfg=cfg(values_before,values_after)
+//
+// [values_before]compile-flags: --check-cfg=cfg(a,values("b")) --check-cfg=cfg(a)
+// [values_after]compile-flags: --check-cfg=cfg(a) --check-cfg=cfg(a,values("b"))
 
 #[cfg(a)]
-//~^ WARNING unexpected `cfg` condition value
 fn my_cfg() {}
 
 #[cfg(a = "unk")]
diff --git a/tests/ui/check-cfg/order-independant.values_after.stderr b/tests/ui/check-cfg/order-independant.values_after.stderr
new file mode 100644
index 00000000000..ed162fb5489
--- /dev/null
+++ b/tests/ui/check-cfg/order-independant.values_after.stderr
@@ -0,0 +1,11 @@
+warning: unexpected `cfg` condition value: `unk`
+  --> $DIR/order-independant.rs:13:7
+   |
+LL | #[cfg(a = "unk")]
+   |       ^^^^^^^^^
+   |
+   = note: expected values for `a` are: (none), `b`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/order-independant.values_before.stderr b/tests/ui/check-cfg/order-independant.values_before.stderr
new file mode 100644
index 00000000000..ed162fb5489
--- /dev/null
+++ b/tests/ui/check-cfg/order-independant.values_before.stderr
@@ -0,0 +1,11 @@
+warning: unexpected `cfg` condition value: `unk`
+  --> $DIR/order-independant.rs:13:7
+   |
+LL | #[cfg(a = "unk")]
+   |       ^^^^^^^^^
+   |
+   = note: expected values for `a` are: (none), `b`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr b/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr
deleted file mode 100644
index 513f7ac7fd1..00000000000
--- a/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/unexpected-cfg-name.rs:9:7
-   |
-LL | #[cfg(widnows)]
-   |       ^^^^^^^ help: there is a config with a similar name: `windows`
-   |
-   = note: `#[warn(unexpected_cfgs)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/check-cfg/unexpected-cfg-name.rs b/tests/ui/check-cfg/unexpected-cfg-name.rs
index 15c3aa6e081..9fc0e28a8fe 100644
--- a/tests/ui/check-cfg/unexpected-cfg-name.rs
+++ b/tests/ui/check-cfg/unexpected-cfg-name.rs
@@ -1,10 +1,7 @@
 // Check warning for unexpected configuration name
 //
 // check-pass
-// revisions: names exhaustive
-// compile-flags: --check-cfg=cfg(names,exhaustive)
-// [names]compile-flags: --check-cfg=names() -Z unstable-options
-// [exhaustive]compile-flags: --check-cfg=cfg() -Z unstable-options
+// compile-flags: --check-cfg=cfg() -Z unstable-options
 
 #[cfg(widnows)]
 //~^ WARNING unexpected `cfg` condition name
diff --git a/tests/ui/check-cfg/unexpected-cfg-name.names.stderr b/tests/ui/check-cfg/unexpected-cfg-name.stderr
index 513f7ac7fd1..0874ccfc461 100644
--- a/tests/ui/check-cfg/unexpected-cfg-name.names.stderr
+++ b/tests/ui/check-cfg/unexpected-cfg-name.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `widnows`
-  --> $DIR/unexpected-cfg-name.rs:9:7
+  --> $DIR/unexpected-cfg-name.rs:6:7
    |
 LL | #[cfg(widnows)]
    |       ^^^^^^^ help: there is a config with a similar name: `windows`
diff --git a/tests/ui/check-cfg/unexpected-cfg-value.rs b/tests/ui/check-cfg/unexpected-cfg-value.rs
index 1b8ead956be..54dce0f0de4 100644
--- a/tests/ui/check-cfg/unexpected-cfg-value.rs
+++ b/tests/ui/check-cfg/unexpected-cfg-value.rs
@@ -1,10 +1,8 @@
 // Check for unexpected configuration value in the code.
 //
 // check-pass
-// revisions: values cfg
-// compile-flags: -Z unstable-options
-// [values]compile-flags: --check-cfg=values(feature,"serde","full")
-// [cfg]compile-flags: --check-cfg=cfg(feature,values("serde","full"))
+// compile-flags: --cfg=feature="rand" -Z unstable-options
+// compile-flags: --check-cfg=cfg(feature,values("serde","full"))
 
 #[cfg(feature = "sedre")]
 //~^ WARNING unexpected `cfg` condition value
diff --git a/tests/ui/check-cfg/unexpected-cfg-value.values.stderr b/tests/ui/check-cfg/unexpected-cfg-value.stderr
index 2855aa75966..31c473a08cb 100644
--- a/tests/ui/check-cfg/unexpected-cfg-value.values.stderr
+++ b/tests/ui/check-cfg/unexpected-cfg-value.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `sedre`
-  --> $DIR/unexpected-cfg-value.rs:9:7
+  --> $DIR/unexpected-cfg-value.rs:7:7
    |
 LL | #[cfg(feature = "sedre")]
    |       ^^^^^^^^^^-------
@@ -10,7 +10,7 @@ LL | #[cfg(feature = "sedre")]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `rand`
-  --> $DIR/unexpected-cfg-value.rs:16:7
+  --> $DIR/unexpected-cfg-value.rs:14:7
    |
 LL | #[cfg(feature = "rand")]
    |       ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/values-target-json.rs b/tests/ui/check-cfg/values-target-json.rs
index 2ef5a44592b..e4c1b54cccc 100644
--- a/tests/ui/check-cfg/values-target-json.rs
+++ b/tests/ui/check-cfg/values-target-json.rs
@@ -2,7 +2,7 @@
 //
 // check-pass
 // needs-llvm-components: x86
-// compile-flags: --crate-type=lib --check-cfg=values() --target={{src-base}}/check-cfg/my-awesome-platform.json -Z unstable-options
+// compile-flags: --crate-type=lib --check-cfg=cfg() --target={{src-base}}/check-cfg/my-awesome-platform.json -Z unstable-options
 
 #![feature(lang_items, no_core, auto_traits)]
 #![no_core]
diff --git a/tests/ui/const-ptr/forbidden_slices.rs b/tests/ui/const-ptr/forbidden_slices.rs
index 0374ac7f714..deab67f725a 100644
--- a/tests/ui/const-ptr/forbidden_slices.rs
+++ b/tests/ui/const-ptr/forbidden_slices.rs
@@ -1,6 +1,6 @@
 // Strip out raw byte dumps to make comparison platform-independent:
 // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
-// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 
 #![feature(
     slice_from_ptr_range,
diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
index 8b941d538a2..383c167d3c0 100644
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
+++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
@@ -6,7 +6,7 @@ LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32)
    |
    = 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) {
-               ╾ALLOC0╼                                     │ ╾──╼
+               ╾ALLOC0<imm>╼                                     │ ╾──╼
            }
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
index 5ef03427093..d0679228326 100644
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
+++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
@@ -6,7 +6,7 @@ LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32)
    |
    = 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) {
-               ╾ALLOC0╼                         │ ╾──────╼
+               ╾ALLOC0<imm>╼                         │ ╾──────╼
            }
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
index 43e664ce413..57815e6af65 100644
--- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
@@ -211,7 +211,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:109:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, 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) {
@@ -385,7 +385,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:178:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17<imm>, 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) {
@@ -396,7 +396,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:182:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19<imm>, 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) {
@@ -418,7 +418,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:189: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 ALLOC22, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22<imm>, 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) {
@@ -451,7 +451,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:199:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, 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) {
diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
index 1427cef7d03..c875d91ccb8 100644
--- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
@@ -211,7 +211,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:109:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, 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) {
@@ -385,7 +385,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:178:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17<imm>, 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) {
@@ -396,7 +396,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:182:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19<imm>, 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) {
@@ -418,7 +418,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:189: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 ALLOC22, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22<imm>, 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) {
@@ -451,7 +451,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:199:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, 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) {
diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs
index ff2a32d5757..ae65a5cb8df 100644
--- a/tests/ui/consts/const-eval/raw-bytes.rs
+++ b/tests/ui/consts/const-eval/raw-bytes.rs
@@ -1,7 +1,7 @@
 // stderr-per-bitwidth
 // ignore-endian-big
 // ignore-tidy-linelength
-// normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$1╼"
+// normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼" -> "╾ALLOC_ID$1╼"
 
 #![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)]
 #![allow(invalid_value)]
diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
index 7b30233c025..5c47cbfdf3b 100644
--- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
+++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
@@ -2,55 +2,55 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:18:1
    |
 LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, 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) {
-               ╾ALLOC0╼ ╾ALLOC1╼                         │ ╾──╼╾──╼
+               ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:23:1
    |
 LL | const INVALID_VTABLE_SIZE: &dyn Trait =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, 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) {
-               ╾ALLOC2╼ ╾ALLOC3╼                         │ ╾──╼╾──╼
+               ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:33:1
    |
 LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, 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) {
-               ╾ALLOC4╼ ╾ALLOC5╼                         │ ╾──╼╾──╼
+               ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:38:1
    |
 LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, 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) {
-               ╾ALLOC6╼ ╾ALLOC7╼                         │ ╾──╼╾──╼
+               ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼                         │ ╾──╼╾──╼
            }
 
 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 ALLOC9, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, 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) {
-               ╾ALLOC8╼ ╾ALLOC9╼                         │ ╾──╼╾──╼
+               ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -61,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
    |
    = 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) {
-               ╾ALLOC10╼ ╾ALLOC11╼                         │ ╾──╼╾──╼
+               ╾ALLOC10<imm>╼ ╾ALLOC11╼                         │ ╾──╼╾──╼
            }
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
index 9330ae3c9a6..f400073aca2 100644
--- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
+++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
@@ -2,55 +2,55 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:18:1
    |
 LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, 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) {
-               ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
+               ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:23:1
    |
 LL | const INVALID_VTABLE_SIZE: &dyn Trait =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, 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) {
-               ╾ALLOC2╼ ╾ALLOC3╼ │ ╾──────╼╾──────╼
+               ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:33:1
    |
 LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, 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) {
-               ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼
+               ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:38:1
    |
 LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, 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) {
-               ╾ALLOC6╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼
+               ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──────╼╾──────╼
            }
 
 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 ALLOC9, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, 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) {
-               ╾ALLOC8╼ ╾ALLOC9╼ │ ╾──────╼╾──────╼
+               ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -61,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
    |
    = 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) {
-               ╾ALLOC10╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼
+               ╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼
            }
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs
index 08d4dce4d17..9e49e3de8bc 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.rs
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs
@@ -1,7 +1,7 @@
 // ignore-tidy-linelength
 // Strip out raw byte dumps to make comparison platform-independent:
 // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
-// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 #![allow(invalid_value)]
 
 use std::mem;
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
index ca7b6645d3f..3bbf2977392 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
@@ -141,7 +141,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:59:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC2, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC2<imm>, 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: $SIZE, align: $ALIGN) {
diff --git a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr
index a6938ca0e90..5342fea66bd 100644
--- a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr
+++ b/tests/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) {
-               ╾ALLOC0╼ ╾ALLOC1╼                         │ ╾──╼╾──╼
+               ╾ALLOC0<imm>╼ ╾ALLOC1╼                         │ ╾──╼╾──╼
            }
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr
index ef2545b43b1..a2496dfc287 100644
--- a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr
+++ b/tests/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) {
-               ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
+               ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
            }
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs
index dc8d4c640c2..3c1baab3e48 100644
--- a/tests/ui/consts/const-eval/ub-wide-ptr.rs
+++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs
@@ -5,7 +5,7 @@ use std::mem;
 
 // Strip out raw byte dumps to make comparison platform-independent:
 // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
-// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 // normalize-stderr-test "offset \d+" -> "offset N"
 // normalize-stderr-test "size \d+" -> "size N"
 
diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
index b203794858a..91ce531c9f7 100644
--- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
@@ -189,7 +189,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:113:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC12<imm>, 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: $SIZE, align: $ALIGN) {
@@ -200,7 +200,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:117:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC14, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC14<imm>, 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: $SIZE, align: $ALIGN) {
@@ -222,7 +222,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:124:1
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17<imm>, 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: $SIZE, align: $ALIGN) {
@@ -233,7 +233,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:127:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19<imm>, 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: $SIZE, align: $ALIGN) {
@@ -244,7 +244,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:130:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21<imm>, 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: $SIZE, align: $ALIGN) {
@@ -255,7 +255,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:133: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 ALLOC23, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC23<imm>, 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: $SIZE, align: $ALIGN) {
@@ -288,7 +288,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:145:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28<imm>, 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: $SIZE, align: $ALIGN) {
@@ -310,7 +310,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:154:1
    |
 LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31<imm>, 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: $SIZE, align: $ALIGN) {
diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.rs b/tests/ui/consts/const-eval/ub-write-through-immutable.rs
new file mode 100644
index 00000000000..945367f1823
--- /dev/null
+++ b/tests/ui/consts/const-eval/ub-write-through-immutable.rs
@@ -0,0 +1,30 @@
+//! Ensure we catch UB due to writing through a shared reference.
+#![feature(const_mut_refs, const_refs_to_cell)]
+#![deny(writes_through_immutable_pointer)]
+#![allow(invalid_reference_casting)]
+
+use std::mem;
+use std::cell::UnsafeCell;
+
+const WRITE_AFTER_CAST: () = unsafe {
+    let mut x = 0;
+    let ptr = &x as *const i32 as *mut i32;
+    *ptr = 0; //~ERROR: writes_through_immutable_pointer
+    //~^ previously accepted
+};
+
+const WRITE_AFTER_TRANSMUTE: () = unsafe {
+    let mut x = 0;
+    let ptr: *mut i32 = mem::transmute(&x);
+    *ptr = 0; //~ERROR: writes_through_immutable_pointer
+    //~^ previously accepted
+};
+
+// it's okay when there is interior mutability;
+const WRITE_INTERIOR_MUT: () = unsafe {
+    let x = UnsafeCell::new(0);
+    let ptr = &x as *const _ as *mut i32;
+    *ptr = 0;
+};
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr
new file mode 100644
index 00000000000..27eb2d2c0d1
--- /dev/null
+++ b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr
@@ -0,0 +1,55 @@
+error: writing through a pointer that was derived from a shared (immutable) reference
+  --> $DIR/ub-write-through-immutable.rs:12:5
+   |
+LL |     *ptr = 0;
+   |     ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
+note: the lint level is defined here
+  --> $DIR/ub-write-through-immutable.rs:3:9
+   |
+LL | #![deny(writes_through_immutable_pointer)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: writing through a pointer that was derived from a shared (immutable) reference
+  --> $DIR/ub-write-through-immutable.rs:19:5
+   |
+LL |     *ptr = 0;
+   |     ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
+
+error: aborting due to 2 previous errors
+
+Future incompatibility report: Future breakage diagnostic:
+error: writing through a pointer that was derived from a shared (immutable) reference
+  --> $DIR/ub-write-through-immutable.rs:12:5
+   |
+LL |     *ptr = 0;
+   |     ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
+note: the lint level is defined here
+  --> $DIR/ub-write-through-immutable.rs:3:9
+   |
+LL | #![deny(writes_through_immutable_pointer)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: writing through a pointer that was derived from a shared (immutable) reference
+  --> $DIR/ub-write-through-immutable.rs:19:5
+   |
+LL |     *ptr = 0;
+   |     ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
+note: the lint level is defined here
+  --> $DIR/ub-write-through-immutable.rs:3:9
+   |
+LL | #![deny(writes_through_immutable_pointer)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/consts/const-points-to-static.32bit.stderr b/tests/ui/consts/const-points-to-static.32bit.stderr
index 452ed6b39d2..73fbf5e1837 100644
--- a/tests/ui/consts/const-points-to-static.32bit.stderr
+++ b/tests/ui/consts/const-points-to-static.32bit.stderr
@@ -6,7 +6,7 @@ LL | const TEST: &u8 = &MY_STATIC;
    |
    = 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) {
-               ╾ALLOC0╼                                     │ ╾──╼
+               ╾ALLOC0<imm>╼                                     │ ╾──╼
            }
 
 warning: skipping const checks
diff --git a/tests/ui/consts/const-points-to-static.64bit.stderr b/tests/ui/consts/const-points-to-static.64bit.stderr
index 2bebfbfda01..42088bbb2c4 100644
--- a/tests/ui/consts/const-points-to-static.64bit.stderr
+++ b/tests/ui/consts/const-points-to-static.64bit.stderr
@@ -6,7 +6,7 @@ LL | const TEST: &u8 = &MY_STATIC;
    |
    = 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) {
-               ╾ALLOC0╼                         │ ╾──────╼
+               ╾ALLOC0<imm>╼                         │ ╾──────╼
            }
 
 warning: skipping const checks
diff --git a/tests/ui/consts/invalid-union.32bit.stderr b/tests/ui/consts/invalid-union.32bit.stderr
index cd7549597c7..177e4f03e83 100644
--- a/tests/ui/consts/invalid-union.32bit.stderr
+++ b/tests/ui/consts/invalid-union.32bit.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/invalid-union.rs:41:1
+  --> $DIR/invalid-union.rs:35:1
    |
 LL | fn main() {
    | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
@@ -10,13 +10,13 @@ LL | fn main() {
            }
 
 note: erroneous constant encountered
-  --> $DIR/invalid-union.rs:43:25
+  --> $DIR/invalid-union.rs:37:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^
 
 note: erroneous constant encountered
-  --> $DIR/invalid-union.rs:43:25
+  --> $DIR/invalid-union.rs:37:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^
diff --git a/tests/ui/consts/invalid-union.64bit.stderr b/tests/ui/consts/invalid-union.64bit.stderr
index e8a0a9955ad..09c648c3cda 100644
--- a/tests/ui/consts/invalid-union.64bit.stderr
+++ b/tests/ui/consts/invalid-union.64bit.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/invalid-union.rs:41:1
+  --> $DIR/invalid-union.rs:35:1
    |
 LL | fn main() {
    | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
@@ -10,13 +10,13 @@ LL | fn main() {
            }
 
 note: erroneous constant encountered
-  --> $DIR/invalid-union.rs:43:25
+  --> $DIR/invalid-union.rs:37:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^
 
 note: erroneous constant encountered
-  --> $DIR/invalid-union.rs:43:25
+  --> $DIR/invalid-union.rs:37:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^
diff --git a/tests/ui/consts/invalid-union.rs b/tests/ui/consts/invalid-union.rs
index 28706b4a923..4f67ec97902 100644
--- a/tests/ui/consts/invalid-union.rs
+++ b/tests/ui/consts/invalid-union.rs
@@ -1,11 +1,6 @@
 // Check that constants with interior mutability inside unions are rejected
 // during validation.
 //
-// Note that this test case relies on undefined behaviour to construct a
-// constant with interior mutability that is "invisible" to the static checks.
-// If for some reason this approach no longer works, it is should be fine to
-// remove the test case.
-//
 // build-fail
 // stderr-per-bitwidth
 #![feature(const_mut_refs)]
@@ -30,10 +25,9 @@ union U {
 }
 
 const C: S = {
-    let s = S { x: 0, y: E::A };
-    // Go through an &u32 reference which is definitely not allowed to mutate anything.
-    let p = &s.x as *const u32 as *mut u32;
-    // Change enum tag to E::B.
+    let mut s = S { x: 0, y: E::A };
+    let p = &mut s.x as *mut u32;
+    // Change enum tag to E::B. Now there's interior mutability here.
     unsafe { *p.add(1) = 1 };
     s
 };
diff --git a/tests/ui/consts/issue-63952.32bit.stderr b/tests/ui/consts/issue-63952.32bit.stderr
index f676d8a7586..f562f9104e3 100644
--- a/tests/ui/consts/issue-63952.32bit.stderr
+++ b/tests/ui/consts/issue-63952.32bit.stderr
@@ -6,7 +6,7 @@ LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe {
    |
    = 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) {
-               ╾ALLOC0╼ ff ff ff ff                         │ ╾──╼....
+               ╾ALLOC0<imm>╼ ff ff ff ff                         │ ╾──╼....
            }
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/issue-63952.64bit.stderr b/tests/ui/consts/issue-63952.64bit.stderr
index c1d7b75af88..fe66bec13a1 100644
--- a/tests/ui/consts/issue-63952.64bit.stderr
+++ b/tests/ui/consts/issue-63952.64bit.stderr
@@ -6,7 +6,7 @@ LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe {
    |
    = 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) {
-               ╾ALLOC0╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+               ╾ALLOC0<imm>╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
            }
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/issue-79690.64bit.stderr b/tests/ui/consts/issue-79690.64bit.stderr
index e99ce078c11..d603a1dc291 100644
--- a/tests/ui/consts/issue-79690.64bit.stderr
+++ b/tests/ui/consts/issue-79690.64bit.stderr
@@ -6,7 +6,7 @@ LL | const G: Fat = unsafe { Transmute { t: FOO }.u };
    |
    = 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) {
-               ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
+               ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼
            }
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr
index 4a3344a5b04..ab33b0c00c9 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr
@@ -24,7 +24,7 @@ LL | const REF_INTERIOR_MUT: &usize = {
    |
    = 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) {
-               ╾ALLOC0╼                                     │ ╾──╼
+               ╾ALLOC0<imm>╼                                     │ ╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -35,7 +35,7 @@ LL | const READ_IMMUT: &usize = {
    |
    = 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) {
-               ╾ALLOC1╼                                     │ ╾──╼
+               ╾ALLOC1<imm>╼                                     │ ╾──╼
            }
 
 warning: skipping const checks
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr
index 7573bfa39ec..f1f58d9ca6d 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr
@@ -24,7 +24,7 @@ LL | const REF_INTERIOR_MUT: &usize = {
    |
    = 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) {
-               ╾ALLOC0╼                         │ ╾──────╼
+               ╾ALLOC0<imm>╼                         │ ╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -35,7 +35,7 @@ LL | const READ_IMMUT: &usize = {
    |
    = 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) {
-               ╾ALLOC1╼                         │ ╾──────╼
+               ╾ALLOC1<imm>╼                         │ ╾──────╼
            }
 
 warning: skipping const checks
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
index 492d8718a13..7960648ce3a 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
@@ -6,7 +6,7 @@ LL | const SLICE_MUT: &[u8; 1] = {
    |
    = 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) {
-               ╾ALLOC0╼                                     │ ╾──╼
+               ╾ALLOC0<imm>╼                                     │ ╾──╼
            }
 
 error: could not evaluate constant pattern
@@ -23,7 +23,7 @@ LL | const U8_MUT: &u8 = {
    |
    = 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) {
-               ╾ALLOC0╼                                     │ ╾──╼
+               ╾ALLOC0<imm>╼                                     │ ╾──╼
            }
 
 error: could not evaluate constant pattern
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
index f6d82d6c0ba..6ae0b2d1bfe 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
@@ -6,7 +6,7 @@ LL | const SLICE_MUT: &[u8; 1] = {
    |
    = 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) {
-               ╾ALLOC0╼                         │ ╾──────╼
+               ╾ALLOC0<imm>╼                         │ ╾──────╼
            }
 
 error: could not evaluate constant pattern
@@ -23,7 +23,7 @@ LL | const U8_MUT: &u8 = {
    |
    = 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) {
-               ╾ALLOC0╼                         │ ╾──────╼
+               ╾ALLOC0<imm>╼                         │ ╾──────╼
            }
 
 error: could not evaluate constant pattern
diff --git a/tests/ui/extern/issue-116203.rs b/tests/ui/extern/issue-116203.rs
new file mode 100644
index 00000000000..f8212841644
--- /dev/null
+++ b/tests/ui/extern/issue-116203.rs
@@ -0,0 +1,21 @@
+extern "C" {
+    thread_local! {
+      static FOO: u32 = 0;
+      //~^ error: extern items cannot be `const`
+      //~| error: incorrect `static` inside `extern` block
+    }
+}
+
+macro_rules! hello {
+    ($name:ident) => {
+        const $name: () = ();
+    };
+}
+
+extern "C" {
+    hello! { yes }
+    //~^ error: extern items cannot be `const`
+    //~| error: incorrect `static` inside `extern` block
+}
+
+fn main() {}
diff --git a/tests/ui/extern/issue-116203.stderr b/tests/ui/extern/issue-116203.stderr
new file mode 100644
index 00000000000..86e4cc763bd
--- /dev/null
+++ b/tests/ui/extern/issue-116203.stderr
@@ -0,0 +1,46 @@
+error: extern items cannot be `const`
+  --> $DIR/issue-116203.rs:3:14
+   |
+LL |       static FOO: u32 = 0;
+   |              ^^^
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: extern items cannot be `const`
+  --> $DIR/issue-116203.rs:16:14
+   |
+LL |     hello! { yes }
+   |              ^^^
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: incorrect `static` inside `extern` block
+  --> $DIR/issue-116203.rs:3:14
+   |
+LL |   extern "C" {
+   |   ---------- `extern` blocks define existing foreign statics and statics inside of them cannot have a body
+LL | /     thread_local! {
+LL | |       static FOO: u32 = 0;
+   | |              ^^^ cannot have a body
+LL | |
+LL | |
+LL | |     }
+   | |_____- the invalid body
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: incorrect `static` inside `extern` block
+  --> $DIR/issue-116203.rs:16:14
+   |
+LL |         const $name: () = ();
+   |                           -- the invalid body
+...
+LL | extern "C" {
+   | ---------- `extern` blocks define existing foreign statics and statics inside of them cannot have a body
+LL |     hello! { yes }
+   |              ^^^ cannot have a body
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/feature-gates/feature-gate-check-cfg.rs b/tests/ui/feature-gates/feature-gate-check-cfg.rs
index 4012a3b04b5..953b8e3ffce 100644
--- a/tests/ui/feature-gates/feature-gate-check-cfg.rs
+++ b/tests/ui/feature-gates/feature-gate-check-cfg.rs
@@ -1,3 +1,3 @@
-// compile-flags: --check-cfg "names()"
+// compile-flags: --check-cfg "cfg()"
 
 fn main() {}
diff --git a/tests/ui/lint/unused/assoc-types.assoc_ty.stderr b/tests/ui/lint/unused/assoc-types.assoc_ty.stderr
new file mode 100644
index 00000000000..190c4ef0cea
--- /dev/null
+++ b/tests/ui/lint/unused/assoc-types.assoc_ty.stderr
@@ -0,0 +1,15 @@
+error: unused implementer of `Future` that must be used
+  --> $DIR/assoc-types.rs:19:5
+   |
+LL |     T::foo();
+   |     ^^^^^^^^
+   |
+   = note: futures do nothing unless you `.await` or poll them
+note: the lint level is defined here
+  --> $DIR/assoc-types.rs:4:9
+   |
+LL | #![deny(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/unused/assoc-types.rpitit.stderr b/tests/ui/lint/unused/assoc-types.rpitit.stderr
new file mode 100644
index 00000000000..190c4ef0cea
--- /dev/null
+++ b/tests/ui/lint/unused/assoc-types.rpitit.stderr
@@ -0,0 +1,15 @@
+error: unused implementer of `Future` that must be used
+  --> $DIR/assoc-types.rs:19:5
+   |
+LL |     T::foo();
+   |     ^^^^^^^^
+   |
+   = note: futures do nothing unless you `.await` or poll them
+note: the lint level is defined here
+  --> $DIR/assoc-types.rs:4:9
+   |
+LL | #![deny(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/unused/assoc-types.rs b/tests/ui/lint/unused/assoc-types.rs
new file mode 100644
index 00000000000..cebb9b4090c
--- /dev/null
+++ b/tests/ui/lint/unused/assoc-types.rs
@@ -0,0 +1,23 @@
+// edition: 2021
+// revisions: rpitit assoc_ty
+
+#![deny(unused_must_use)]
+
+use std::future::Future;
+
+pub trait Tr {
+    type Fut: Future<Output = ()>;
+
+    #[cfg(rpitit)]
+    fn foo() -> impl Future<Output = ()>;
+
+    #[cfg(assoc_ty)]
+    fn foo() -> Self::Fut;
+}
+
+pub async fn bar<T: Tr>() {
+    T::foo();
+    //~^ ERROR unused implementer of `Future` that must be used
+}
+
+fn main() {}
diff --git a/tests/ui/resolve/issue-117920.rs b/tests/ui/resolve/issue-117920.rs
new file mode 100644
index 00000000000..928f194c59c
--- /dev/null
+++ b/tests/ui/resolve/issue-117920.rs
@@ -0,0 +1,11 @@
+#![crate_type = "lib"]
+
+use super::A; //~ ERROR failed to resolve
+
+mod b {
+    pub trait A {}
+    pub trait B {}
+}
+
+/// [`A`]
+pub use b::*;
diff --git a/tests/ui/resolve/issue-117920.stderr b/tests/ui/resolve/issue-117920.stderr
new file mode 100644
index 00000000000..c4528d467e9
--- /dev/null
+++ b/tests/ui/resolve/issue-117920.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: there are too many leading `super` keywords
+  --> $DIR/issue-117920.rs:3:5
+   |
+LL | use super::A;
+   |     ^^^^^ there are too many leading `super` keywords
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/resolve/issue-118295.rs b/tests/ui/resolve/issue-118295.rs
new file mode 100644
index 00000000000..b97681d9563
--- /dev/null
+++ b/tests/ui/resolve/issue-118295.rs
@@ -0,0 +1,5 @@
+macro_rules! {}
+//~^ ERROR cannot find macro `macro_rules` in this scope
+//~| NOTE maybe you have forgotten to define a name for this `macro_rules!`
+
+fn main() {}
diff --git a/tests/ui/resolve/issue-118295.stderr b/tests/ui/resolve/issue-118295.stderr
new file mode 100644
index 00000000000..d60d7d9185d
--- /dev/null
+++ b/tests/ui/resolve/issue-118295.stderr
@@ -0,0 +1,14 @@
+error: cannot find macro `macro_rules` in this scope
+  --> $DIR/issue-118295.rs:1:1
+   |
+LL | macro_rules! {}
+   | ^^^^^^^^^^^
+   |
+note: maybe you have forgotten to define a name for this `macro_rules!`
+  --> $DIR/issue-118295.rs:1:1
+   |
+LL | macro_rules! {}
+   | ^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs
new file mode 100644
index 00000000000..0ca18b5b0dd
--- /dev/null
+++ b/tests/ui/traits/question-mark-result-err-mismatch.rs
@@ -0,0 +1,59 @@
+fn foo() -> Result<String, String> { //~ NOTE expected `String` because of this
+    let test = String::from("one,two");
+    let x = test
+        .split_whitespace()
+        .next()
+        .ok_or_else(|| {
+            "Couldn't split the test string"
+        });
+    let one = x
+        .map(|s| ())
+        .map_err(|e| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>`
+            e; //~ HELP remove this semicolon
+        })
+        .map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String`
+    //~^ NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE the trait `From<()>` is not implemented for `String`
+    //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+    //~| NOTE required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>`
+    Ok(one.to_string())
+}
+
+fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this
+    let x = foo(); //~ NOTE this has type `Result<_, String>`
+    let one = x
+        .map(|s| ())
+        .map_err(|_| ())?; //~ ERROR `?` couldn't convert the error to `String`
+    //~^ NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE this can't be annotated with `?` because it has type `Result<_, ()>`
+    //~| NOTE the trait `From<()>` is not implemented for `String`
+    //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+    //~| NOTE required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>`
+    //~| HELP the following other types implement trait `From<T>`:
+    Ok(one)
+}
+
+fn baz() -> Result<String, String> { //~ NOTE expected `String` because of this
+    let test = String::from("one,two");
+    let one = test
+        .split_whitespace()
+        .next()
+        .ok_or_else(|| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>`
+            "Couldn't split the test string"; //~ HELP remove this semicolon
+        })?;
+    //~^ ERROR `?` couldn't convert the error to `String`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE in this expansion of desugaring of operator `?`
+    //~| NOTE the trait `From<()>` is not implemented for `String`
+    //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+    //~| NOTE required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>`
+    Ok(one.to_string())
+}
+
+fn main() {}
diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr
new file mode 100644
index 00000000000..3059e0beca3
--- /dev/null
+++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr
@@ -0,0 +1,62 @@
+error[E0277]: `?` couldn't convert the error to `String`
+  --> $DIR/question-mark-result-err-mismatch.rs:14:22
+   |
+LL |   fn foo() -> Result<String, String> {
+   |               ---------------------- expected `String` because of this
+...
+LL |           .map_err(|e| {
+   |  __________-
+LL | |             e;
+   | |              - help: remove this semicolon
+LL | |         })
+   | |__________- this can't be annotated with `?` because it has type `Result<_, ()>`
+LL |           .map(|()| "")?;
+   |                        ^ the trait `From<()>` is not implemented for `String`
+   |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+   = note: required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>`
+
+error[E0277]: `?` couldn't convert the error to `String`
+  --> $DIR/question-mark-result-err-mismatch.rs:28:25
+   |
+LL | fn bar() -> Result<(), String> {
+   |             ------------------ expected `String` because of this
+LL |     let x = foo();
+   |             ----- this has type `Result<_, String>`
+...
+LL |         .map_err(|_| ())?;
+   |          ---------------^ the trait `From<()>` is not implemented for `String`
+   |          |
+   |          this can't be annotated with `?` because it has type `Result<_, ()>`
+   |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+   = help: the following other types implement trait `From<T>`:
+             <String as From<char>>
+             <String as From<Box<str>>>
+             <String as From<Cow<'a, str>>>
+             <String as From<&str>>
+             <String as From<&mut str>>
+             <String as From<&String>>
+   = note: required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>`
+
+error[E0277]: `?` couldn't convert the error to `String`
+  --> $DIR/question-mark-result-err-mismatch.rs:48:11
+   |
+LL |   fn baz() -> Result<String, String> {
+   |               ---------------------- expected `String` because of this
+...
+LL |           .ok_or_else(|| {
+   |  __________-
+LL | |             "Couldn't split the test string";
+   | |                                             - help: remove this semicolon
+LL | |         })?;
+   | |          -^ the trait `From<()>` is not implemented for `String`
+   | |__________|
+   |            this can't be annotated with `?` because it has type `Result<_, ()>`
+   |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+   = note: required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr
index b41bf86d3d9..d58a011ff55 100644
--- a/tests/ui/try-block/try-block-bad-type.stderr
+++ b/tests/ui/try-block/try-block-bad-type.stderr
@@ -2,7 +2,9 @@ error[E0277]: `?` couldn't convert the error to `TryFromSliceError`
   --> $DIR/try-block-bad-type.rs:7:16
    |
 LL |         Err("")?;
-   |                ^ the trait `From<&str>` is not implemented for `TryFromSliceError`
+   |         -------^ the trait `From<&str>` is not implemented for `TryFromSliceError`
+   |         |
+   |         this can't be annotated with `?` because it has type `Result<_, &str>`
    |
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = help: the trait `From<Infallible>` is implemented for `TryFromSliceError`
diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr
index d8b9431becc..97fbbdbf8f8 100644
--- a/tests/ui/try-trait/bad-interconversion.stderr
+++ b/tests/ui/try-trait/bad-interconversion.stderr
@@ -4,7 +4,9 @@ error[E0277]: `?` couldn't convert the error to `u8`
 LL | fn result_to_result() -> Result<u64, u8> {
    |                          --------------- expected `u8` because of this
 LL |     Ok(Err(123_i32)?)
-   |                    ^ the trait `From<i32>` is not implemented for `u8`
+   |        ------------^ the trait `From<i32>` is not implemented for `u8`
+   |        |
+   |        this can't be annotated with `?` because it has type `Result<_, i32>`
    |
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = help: the following other types implement trait `From<T>`:
diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr
index 46798f5dcfd..b155b3ff663 100644
--- a/tests/ui/try-trait/issue-32709.stderr
+++ b/tests/ui/try-trait/issue-32709.stderr
@@ -4,7 +4,9 @@ error[E0277]: `?` couldn't convert the error to `()`
 LL | fn a() -> Result<i32, ()> {
    |           --------------- expected `()` because of this
 LL |     Err(5)?;
-   |           ^ the trait `From<{integer}>` is not implemented for `()`
+   |     ------^ the trait `From<{integer}>` is not implemented for `()`
+   |     |
+   |     this can't be annotated with `?` because it has type `Result<_, {integer}>`
    |
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = help: the following other types implement trait `From<T>`: