diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index bbb5daccfd639..b13773ffe1460 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2330,10 +2330,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         match (cast_ty_from, cast_ty_to) {
                             (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
                                 let mut normalize = |t| self.normalize(t, location);
+
+                                // N.B. `struct_tail_with_normalize` only "structurally resolves"
+                                // the type. It is not fully normalized, so we have to normalize it
+                                // afterwards.
                                 let src_tail =
                                     tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
+                                let src_tail = normalize(src_tail);
                                 let dst_tail =
                                     tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
+                                let dst_tail = normalize(dst_tail);
 
                                 // This checks (lifetime part of) vtable validity for pointer casts,
                                 // which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 901149825bfd6..79e8e2127765a 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -458,7 +458,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         _unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
         // Shared intrinsics.
-        if ecx.emulate_intrinsic(instance, args, dest, target)? {
+        if ecx.eval_intrinsic(instance, args, dest, target)? {
             return Ok(None);
         }
         let intrinsic_name = ecx.tcx.item_name(instance.def_id());
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 16a0a76a316e6..9210ec4e16fd0 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -97,7 +97,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Returns `true` if emulation happened.
     /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
     /// intrinsic handling.
-    pub fn emulate_intrinsic(
+    pub fn eval_intrinsic(
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, M::Provenance>],
@@ -447,7 +447,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(true)
     }
 
-    pub(super) fn emulate_nondiverging_intrinsic(
+    pub(super) fn eval_nondiverging_intrinsic(
         &mut self,
         intrinsic: &NonDivergingIntrinsic<'tcx>,
     ) -> InterpResult<'tcx> {
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index fe5869ad7fa7a..2f860f9f942b2 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -1,8 +1,9 @@
 use either::Either;
 use rustc_apfloat::{Float, FloatConvert};
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
+use rustc_middle::mir::NullOp;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
-use rustc_middle::ty::{self, FloatTy, ScalarInt};
+use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::symbol::sym;
 use tracing::trace;
@@ -480,4 +481,38 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         }
     }
+
+    pub fn nullary_op(
+        &self,
+        null_op: NullOp<'tcx>,
+        arg_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
+        use rustc_middle::mir::NullOp::*;
+
+        let layout = self.layout_of(arg_ty)?;
+        let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap();
+
+        Ok(match null_op {
+            SizeOf => {
+                if !layout.abi.is_sized() {
+                    span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`");
+                }
+                let val = layout.size.bytes();
+                ImmTy::from_uint(val, usize_layout())
+            }
+            AlignOf => {
+                if !layout.abi.is_sized() {
+                    span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`");
+                }
+                let val = layout.align.abi.bytes();
+                ImmTy::from_uint(val, usize_layout())
+            }
+            OffsetOf(fields) => {
+                let val =
+                    self.tcx.offset_of_subfield(self.param_env, layout, fields.iter()).bytes();
+                ImmTy::from_uint(val, usize_layout())
+            }
+            UbChecks => ImmTy::from_bool(self.tcx.sess.ub_checks(), *self.tcx),
+        })
+    }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 211a7b2300222..28cf1068f4081 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -4,8 +4,7 @@
 
 use either::Either;
 use rustc_index::IndexSlice;
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::{bug, mir, span_bug};
+use rustc_middle::{bug, mir};
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use tracing::{info, instrument, trace};
 
@@ -94,7 +93,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 M::retag_place_contents(self, *kind, &dest)?;
             }
 
-            Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
+            Intrinsic(box intrinsic) => self.eval_nondiverging_intrinsic(intrinsic)?,
 
             // Evaluate the place expression, without reading from it.
             PlaceMention(box place) => {
@@ -179,6 +178,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.write_immediate(*result, &dest)?;
             }
 
+            NullaryOp(null_op, ty) => {
+                let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
+                let val = self.nullary_op(null_op, ty)?;
+                self.write_immediate(*val, &dest)?;
+            }
+
             Aggregate(box ref kind, ref operands) => {
                 self.write_aggregate(kind, operands, &dest)?;
             }
@@ -230,38 +235,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.write_immediate(*val, &dest)?;
             }
 
-            NullaryOp(ref null_op, ty) => {
-                let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
-                let layout = self.layout_of(ty)?;
-                if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op
-                    && layout.is_unsized()
-                {
-                    span_bug!(
-                        self.frame().current_span(),
-                        "{null_op:?} MIR operator called for unsized type {ty}",
-                    );
-                }
-                let val = match null_op {
-                    mir::NullOp::SizeOf => {
-                        let val = layout.size.bytes();
-                        Scalar::from_target_usize(val, self)
-                    }
-                    mir::NullOp::AlignOf => {
-                        let val = layout.align.abi.bytes();
-                        Scalar::from_target_usize(val, self)
-                    }
-                    mir::NullOp::OffsetOf(fields) => {
-                        let val = self
-                            .tcx
-                            .offset_of_subfield(self.param_env, layout, fields.iter())
-                            .bytes();
-                        Scalar::from_target_usize(val, self)
-                    }
-                    mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.ub_checks()),
-                };
-                self.write_scalar(val, &dest)?;
-            }
-
             ShallowInitBox(ref operand, _) => {
                 let src = self.eval_operand(operand, None)?;
                 let v = self.read_immediate(&src)?;
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 3d4b706aa652b..56896d945e5f3 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -75,6 +75,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
             @call(mir_call, args) => {
                 self.parse_call(args)
             },
+            @call(mir_tail_call, args) => {
+                self.parse_tail_call(args)
+            },
             ExprKind::Match { scrutinee, arms, .. } => {
                 let discr = self.parse_operand(*scrutinee)?;
                 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
@@ -187,6 +190,25 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
         )
     }
 
+    fn parse_tail_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
+        parse_by_kind!(self, args[0], _, "tail call",
+            ExprKind::Call { fun, args, fn_span, .. } => {
+                let fun = self.parse_operand(*fun)?;
+                let args = args
+                    .iter()
+                    .map(|arg|
+                        Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span  } )
+                    )
+                    .collect::<PResult<Box<[_]>>>()?;
+                Ok(TerminatorKind::TailCall {
+                    func: fun,
+                    args,
+                    fn_span: *fn_span,
+                })
+            },
+        )
+    }
+
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
         parse_by_kind!(self, expr_id, expr, "rvalue",
             @call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
index ac664c53f4454..cb15c67b895b8 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
@@ -6,7 +6,7 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::bug;
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_target::abi::call::{Conv, FnAbi, PassMode};
 use tracing::instrument;
 
@@ -112,11 +112,12 @@ pub fn typeid_for_instance<'tcx>(
     instance: Instance<'tcx>,
     options: TypeIdOptions,
 ) -> String {
+    assert!(!instance.has_non_region_param(), "{instance:#?} must be fully monomorphic");
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits()));
     let instance = transform_instance(tcx, instance, transform_ty_options);
     let fn_abi = tcx
-        .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
+        .fn_abi_of_instance(ty::ParamEnv::reveal_all().and((instance, ty::List::empty())))
         .unwrap_or_else(|error| {
             bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
         });
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9977fa7425a3e..94cf21da4efb8 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1216,6 +1216,7 @@ symbols! {
         mir_static_mut,
         mir_storage_dead,
         mir_storage_live,
+        mir_tail_call,
         mir_unreachable,
         mir_unwind_cleanup,
         mir_unwind_continue,
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
index 3e575fdd528de..8b40132986867 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
@@ -21,6 +21,7 @@ pub fn target() -> Target {
             llvm_abiname: "lp64d".into(),
             max_atomic_width: Some(64),
             supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
+            crt_static_default: false,
             ..base::linux_musl::opts()
         },
     }
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index fd49a96eaa049..c7cec396e1f2e 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -247,6 +247,8 @@
 //!       otherwise branch.
 //!  - [`Call`] has an associated function as well, with special syntax:
 //!    `Call(ret_val = function(arg1, arg2, ...), ReturnTo(next_block), UnwindContinue())`.
+//!  - [`TailCall`] does not have a return destination or next block, so its syntax is just
+//!    `TailCall(function(arg1, arg2, ...))`.
 
 #![unstable(
     feature = "custom_mir",
@@ -350,6 +352,12 @@ define!("mir_call",
     /// - [`UnwindCleanup`]
     fn Call(call: (), goto: ReturnToArg, unwind_action: UnwindActionArg)
 );
+define!("mir_tail_call",
+    /// Call a function.
+    ///
+    /// The argument must be of the form `fun(arg1, arg2, ...)`.
+    fn TailCall<T>(call: T)
+);
 define!("mir_unwind_resume",
     /// A terminator that resumes the unwinding.
     fn UnwindResume()
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 2621e9a603185..1b98d54169338 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -24,7 +24,8 @@ RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y --no
   # Needed for apt-key to work:
   dirmngr \
   gpg-agent \
-  g++-9-arm-linux-gnueabi
+  g++-9-arm-linux-gnueabi \
+  g++-11-riscv64-linux-gnu
 
 RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486
 RUN add-apt-repository -y 'deb https://apt.dilos.org/dilos dilos2 main'
@@ -73,6 +74,10 @@ RUN env \
     CC=arm-linux-gnueabi-gcc-9 CFLAGS="-march=armv7-a" \
     CXX=arm-linux-gnueabi-g++-9 CXXFLAGS="-march=armv7-a" \
     bash musl.sh armv7 && \
+    env \
+    CC=riscv64-linux-gnu-gcc-11 \
+    CXX=riscv64-linux-gnu-g++-11 \
+    bash musl.sh riscv64gc && \
     rm -rf /build/*
 
 WORKDIR /tmp
@@ -125,6 +130,7 @@ ENV TARGETS=$TARGETS,x86_64-unknown-none
 ENV TARGETS=$TARGETS,aarch64-unknown-uefi
 ENV TARGETS=$TARGETS,i686-unknown-uefi
 ENV TARGETS=$TARGETS,x86_64-unknown-uefi
+ENV TARGETS=$TARGETS,riscv64gc-unknown-linux-musl
 
 # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
 # we need asm in the search path for gcc-9 (for gnux32) but not in the search path of the
@@ -132,7 +138,11 @@ ENV TARGETS=$TARGETS,x86_64-unknown-uefi
 # Luckily one of the folders is /usr/local/include so symlink /usr/include/x86_64-linux-gnu/asm there
 RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/local/include/asm
 
+# musl-gcc can't find libgcc_s.so.1 since it doesn't use the standard search paths.
+RUN ln -s /usr/riscv64-linux-gnu/lib/libgcc_s.so.1 /usr/lib/gcc-cross/riscv64-linux-gnu/11/
+
 ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-llvm-bitcode-linker --disable-docs \
-  --musl-root-armv7=/musl-armv7
+  --musl-root-armv7=/musl-armv7 \
+  --musl-root-riscv64gc=/musl-riscv64gc
 
 ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index d5141591b97e4..467fd6f43e48f 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -66,6 +66,7 @@
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
     - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
     - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md)
+    - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.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 f3b49a65aad28..7fd1808a1f026 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -98,6 +98,7 @@ target | notes
 `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
 `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
 [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29)
+[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
 `s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
 `x86_64-unknown-freebsd` | 64-bit FreeBSD
 `x86_64-unknown-illumos` | illumos
@@ -354,7 +355,6 @@ target | std | host | notes
 [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ |   | RISC-V Hermit
 `riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
 `riscv64gc-unknown-fuchsia` |   |   | RISC-V Fuchsia
-`riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.3)
 [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
 [`riscv64-linux-android`](platform-support/android.md) |   |   | RISC-V 64-bit Android
diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md
new file mode 100644
index 0000000000000..5b3dc68303803
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md
@@ -0,0 +1,47 @@
+# riscv64gc-unknown-linux-musl
+
+**Tier: 2**
+
+Target for RISC-V Linux programs using musl libc.
+
+## Target maintainers
+
+- [@Amanieu](https://github.com/Amanieu)
+- [@kraj](https://github.com/kraj)
+
+## Requirements
+
+Building the target itself requires a RISC-V compiler that is supported by `cc-rs`.
+
+## Building the target
+
+The target can be built by enabling it for a `rustc` build.
+
+```toml
+[build]
+target = ["riscv64gc-unknown-linux-musl"]
+```
+
+Make sure your C compiler is included in `$PATH`, then add it to the `config.toml`:
+
+```toml
+[target.riscv64gc-unknown-linux-musl]
+cc = "riscv64-linux-gnu-gcc"
+cxx = "riscv64-linux-gnu-g++"
+ar = "riscv64-linux-gnu-ar"
+linker = "riscv64-linux-gnu-gcc"
+```
+
+## Building Rust programs
+
+This target are distributed through `rustup`, and otherwise require no
+special configuration.
+
+## Cross-compilation
+
+This target can be cross-compiled from any host.
+
+## Testing
+
+This target can be tested as normal with `x.py` on a RISC-V host or via QEMU
+emulation.
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index ff475b9571b87..2b263f848e89e 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -141,6 +141,7 @@ static TARGETS: &[&str] = &[
     "riscv64gc-unknown-hermit",
     "riscv64gc-unknown-none-elf",
     "riscv64gc-unknown-linux-gnu",
+    "riscv64gc-unknown-linux-musl",
     "s390x-unknown-linux-gnu",
     "sparc64-unknown-linux-gnu",
     "sparcv9-sun-solaris",
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index d60119e75f16d..18b22827bdb15 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -33,7 +33,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // See if the core engine can handle this intrinsic.
-        if this.emulate_intrinsic(instance, args, dest, ret)? {
+        if this.eval_intrinsic(instance, args, dest, ret)? {
             return Ok(None);
         }
         let intrinsic_name = this.tcx.item_name(instance.def_id());
diff --git a/tests/crashes/128621-2.rs b/tests/crashes/128621-2.rs
deleted file mode 100644
index b1cdaf94984a8..0000000000000
--- a/tests/crashes/128621-2.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ known-bug: rust-lang/rust#128621
-
-#![feature(ptr_metadata)]
-use std::{ops::FnMut, ptr::Pointee};
-
-pub type EmplacerFn<'a, T> = dyn for<'b> FnMut(<T as Pointee>::Metadata) + 'a;
-
-pub struct Emplacer<'a, T>(EmplacerFn<'a, T>);
-
-impl<'a, T> Emplacer<'a, T> {
-    pub unsafe fn from_fn<'b>(emplacer_fn: &'b mut EmplacerFn<'a, T>) -> &'b mut Self {
-        unsafe { &mut *((emplacer_fn as *mut EmplacerFn<'a, T>) as *mut Self) }
-    }
-}
-
-pub fn main() {}
diff --git a/tests/mir-opt/building/custom/terminators.rs b/tests/mir-opt/building/custom/terminators.rs
index a8e0b4b35bf47..ed08040a2a58c 100644
--- a/tests/mir-opt/building/custom/terminators.rs
+++ b/tests/mir-opt/building/custom/terminators.rs
@@ -22,6 +22,18 @@ fn direct_call(x: i32) -> i32 {
     }
 }
 
+// EMIT_MIR terminators.tail_call.built.after.mir
+#[custom_mir(dialect = "built")]
+fn tail_call(x: i32) -> i32 {
+    mir! {
+        let y;
+        {
+            y = x + 42;
+            TailCall(ident(y))
+        }
+    }
+}
+
 // EMIT_MIR terminators.indirect_call.built.after.mir
 #[custom_mir(dialect = "built")]
 fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 {
diff --git a/tests/mir-opt/building/custom/terminators.tail_call.built.after.mir b/tests/mir-opt/building/custom/terminators.tail_call.built.after.mir
new file mode 100644
index 0000000000000..4cf6e459aa820
--- /dev/null
+++ b/tests/mir-opt/building/custom/terminators.tail_call.built.after.mir
@@ -0,0 +1,11 @@
+// MIR for `tail_call` after built
+
+fn tail_call(_1: i32) -> i32 {
+    let mut _0: i32;
+    let mut _2: i32;
+
+    bb0: {
+        _2 = Add(_1, const 42_i32);
+        tailcall ident::<i32>(Spanned { node: _2, span: $DIR/terminators.rs:32:28: 32:29 (#0) });
+    }
+}
diff --git a/tests/crashes/128621.rs b/tests/ui/cast/dyn-tails-need-normalization.rs
similarity index 87%
rename from tests/crashes/128621.rs
rename to tests/ui/cast/dyn-tails-need-normalization.rs
index 0a02352236dbb..719e0e892430d 100644
--- a/tests/crashes/128621.rs
+++ b/tests/ui/cast/dyn-tails-need-normalization.rs
@@ -1,4 +1,4 @@
-//@ known-bug: rust-lang/rust#128621
+//@ check-pass
 
 trait Trait {
     type Associated;
@@ -17,3 +17,5 @@ struct Wrap(TraitObject);
 fn cast(x: *mut TraitObject) {
     x as *mut Wrap;
 }
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
index 8d59235e2f448..01529599d37d0 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
@@ -1,4 +1,4 @@
-error: internal compiler error: compiler/rustc_const_eval/src/interpret/step.rs:LL:CC: SizeOf MIR operator called for unsized type dyn Debug
+error: internal compiler error: compiler/rustc_const_eval/src/interpret/operator.rs:LL:CC: unsized type for `NullaryOp::SizeOf`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 
 Box<dyn Any>
diff --git a/tests/ui/sanitizer/cfi-can-reveal-opaques.rs b/tests/ui/sanitizer/cfi-can-reveal-opaques.rs
new file mode 100644
index 0000000000000..55988a62a8cdf
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-can-reveal-opaques.rs
@@ -0,0 +1,44 @@
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ no-prefer-dynamic
+//@ only-x86_64-unknown-linux-gnu
+//@ build-pass
+
+// See comment below for why this test exists.
+
+trait Tr<U> {
+    type Projection;
+}
+
+impl<F, U> Tr<U> for F
+where
+    F: Fn() -> U
+{
+    type Projection = U;
+}
+
+fn test<B: Tr<U>, U>(b: B) -> B::Projection
+{
+    todo!()
+}
+
+fn main() {
+    fn rpit_fn() -> impl Sized {}
+
+    // When CFI runs, it tries to compute the signature of the call. This
+    // ends up giving us a signature of:
+    //     `fn test::<rpit_fn, ()>() -> <rpit_fn as Tr<()>>::Projection`,
+    // where `rpit_fn` is the ZST FnDef for the function. However, we were
+    // previously using a Reveal::UserFacing param-env. This means that the
+    // `<rpit_fn as Tr<()>>::Projection` return type is impossible to normalize,
+    // since it would require proving `rpit_fn: Fn() -> ()`, but we cannot
+    // prove that the `impl Sized` opaque is `()` with a user-facing param-env.
+    // This leads to a normalization error, and then an ICE.
+    //
+    // Side-note:
+    // So why is the second generic of `test` "`()`", and not the
+    // `impl Sized` since we inferred it from the return type of `rpit_fn`
+    // during typeck? Well, that's because we're using the generics from the
+    // terminator of the MIR, which has had the RevealAll pass performed on it.
+    let _ = test(rpit_fn);
+}