about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <t.gross35@gmail.com>2024-09-24 19:47:48 -0400
committerGitHub <noreply@github.com>2024-09-24 19:47:48 -0400
commit75296fc72117153c9165f41575c4439087bd40f0 (patch)
treea514b30ead2a155f96eed4f892e40da5b3a1a99e
parent363ae4188316b8b22cf6c1890bc73d84d05f70a4 (diff)
parentb62e72ce8c31bbfd028136570a5e46bee233d4f3 (diff)
downloadrust-75296fc72117153c9165f41575c4439087bd40f0.tar.gz
rust-75296fc72117153c9165f41575c4439087bd40f0.zip
Rollup merge of #130234 - lukas-code:ptr-cast-errors, r=WaffleLapkin
improve compile errors for invalid ptr-to-ptr casts with trait objects

This is a follow-up to https://github.com/rust-lang/rust/pull/120248 to improve some of its error messages.

1. Make the borrowcheck error for "type annotation requires that x must outlive y" actually point at the type annotation, i.e. the type `T` in a `x as T` cast. This makes the error more consistent with other errors caused by type annotation in other places, such as
```text
error: lifetime may not live long enough
 --> src/lib.rs:4:12
  |
3 | fn bar(a: &i32) {
  |           - let's call the lifetime of this reference `'1`
4 |     let b: &'static i32 = a;
  |            ^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
```

2. Don't say "cast" when we actually mean "coercion" and give borrowcheck errors from actual casts (which is currently just the check added in https://github.com/rust-lang/rust/pull/120248) a higher priority than ones from coercions. This can improve the errors for ptr-to-ptr cast between trait objects because they are are lowered as an upcast "unsizing" coercion if possible (which may be the identity upcast) followed by the actual cast.

3. Bring back the old "casting X as Y is invalid" message for type mismatch in the principals and reword the "vtable kinds may not match" message to more accurately describe the pointer metadata and not refer to "vtables" if the metadata is unknown.

fixes https://github.com/rust-lang/rust/issues/130030

r? `@WaffleLapkin` but feel free to reassign
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs3
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs71
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs15
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs14
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs13
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs144
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs7
-rw-r--r--compiler/rustc_middle/src/mir/query.rs4
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs3
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs17
-rw-r--r--compiler/rustc_middle/src/thir.rs6
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs7
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs6
-rw-r--r--compiler/rustc_middle/src/ty/cast.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs40
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs13
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs1
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs10
-rw-r--r--compiler/rustc_mir_transform/src/mentioned_items.rs10
-rw-r--r--compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs9
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs18
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs10
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs5
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs1
-rw-r--r--compiler/stable_mir/src/mir/body.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs8
-rw-r--r--src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr2
-rw-r--r--tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir38
-rw-r--r--tests/mir-opt/build_correct_coerce.main.built.after.mir2
-rw-r--r--tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir4
-rw-r--r--tests/mir-opt/building/storage_live_dead_in_statics.XXX.built.after.mir2
-rw-r--r--tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff2
-rw-r--r--tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff2
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff2
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.rs2
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff4
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff4
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/slice_len.rs2
-rw-r--r--tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff2
-rw-r--r--tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/gvn.array_len.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff12
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff12
-rw-r--r--tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-abort.diff20
-rw-r--r--tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-unwind.diff20
-rw-r--r--tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff20
-rw-r--r--tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff20
-rw-r--r--tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff2
-rw-r--r--tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff2
-rw-r--r--tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff2
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff2
-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.64bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff2
-rw-r--r--tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff2
-rw-r--r--tests/ui/borrowck/two-phase-surprise-no-conflict.stderr4
-rw-r--r--tests/ui/cast/casts-differing-anon.stderr2
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-args.rs8
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-args.stderr41
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr4
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr4
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs5
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr10
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr2
-rw-r--r--tests/ui/dropck/dropck_trait_cycle_checked.stderr12
-rw-r--r--tests/ui/dyn-star/dyn-to-rigid.rs2
-rw-r--r--tests/ui/dyn-star/dyn-to-rigid.stderr6
-rw-r--r--tests/ui/dyn-star/enum-cast.rs18
-rw-r--r--tests/ui/kindck/kindck-impl-type-params.stderr4
-rw-r--r--tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr4
-rw-r--r--tests/ui/mismatched_types/cast-rfc0401.stderr8
-rw-r--r--tests/ui/nll/issue-54779-anon-static-lifetime.stderr2
-rw-r--r--tests/ui/nll/user-annotations/cast_static_lifetime.stderr3
-rw-r--r--tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr7
-rw-r--r--tests/ui/regions/regions-close-object-into-object-4.stderr3
-rw-r--r--tests/ui/regions/regions-close-object-into-object-5.stderr3
-rw-r--r--tests/ui/regions/regions-close-over-type-parameter-1.stderr4
-rw-r--r--tests/ui/suggestions/lifetimes/suggest-using-tick-underscore-lifetime-in-return-trait-object.stderr2
-rw-r--r--tests/ui/traits/trait-object-lifetime-default-note.rs2
-rw-r--r--tests/ui/traits/trait-object-lifetime-default-note.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-3.stderr8
-rw-r--r--tests/ui/traits/trait-upcasting/type-checking-test-4.stderr8
-rw-r--r--tests/ui/traits/upcast_soundness_bug.rs2
-rw-r--r--tests/ui/traits/upcast_soundness_bug.stderr10
122 files changed, 552 insertions, 394 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 7077d78f459..31a5d451ff6 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -333,7 +333,11 @@ impl<'tcx> BorrowExplanation<'tcx> {
                     }
                 }
 
-                if let ConstraintCategory::Cast { unsize_to: Some(unsize_ty) } = category {
+                if let ConstraintCategory::Cast {
+                    is_implicit_coercion: true,
+                    unsize_to: Some(unsize_ty),
+                } = category
+                {
                     self.add_object_lifetime_default_note(tcx, err, unsize_ty);
                 }
                 self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
@@ -740,7 +744,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
                         // If we see an unsized cast, then if it is our data we should check
                         // whether it is being cast to a trait object.
                         Rvalue::Cast(
-                            CastKind::PointerCoercion(PointerCoercion::Unsize),
+                            CastKind::PointerCoercion(PointerCoercion::Unsize, _),
                             operand,
                             ty,
                         ) => {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index ca0a3c66130..39175b406a4 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -47,7 +47,8 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
             ConstraintCategory::Yield => "yielding this value ",
             ConstraintCategory::UseAsConst => "using this value as a constant ",
             ConstraintCategory::UseAsStatic => "using this value as a static ",
-            ConstraintCategory::Cast { .. } => "cast ",
+            ConstraintCategory::Cast { is_implicit_coercion: false, .. } => "cast ",
+            ConstraintCategory::Cast { is_implicit_coercion: true, .. } => "coercion ",
             ConstraintCategory::CallArgument(_) => "argument ",
             ConstraintCategory::TypeAnnotation => "type annotation ",
             ConstraintCategory::ClosureBounds => "closure body ",
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 4056b423548..16e51e82f85 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1975,8 +1975,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             Rvalue::Cast(cast_kind, op, ty) => {
                 self.check_operand(op, location);
 
-                match cast_kind {
-                    CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => {
+                match *cast_kind {
+                    CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, coercion_source) => {
+                        let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
                         let src_sig = op.ty(body, tcx).fn_sig(tcx);
 
                         // HACK: This shouldn't be necessary... We can remove this when we actually
@@ -2007,7 +2008,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             self.prove_predicate(
                                 ty::ClauseKind::WellFormed(src_ty.into()),
                                 location.to_locations(),
-                                ConstraintCategory::Cast { unsize_to: None },
+                                ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                             );
 
                             let src_ty = self.normalize(src_ty, location);
@@ -2015,7 +2016,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 src_ty,
                                 *ty,
                                 location.to_locations(),
-                                ConstraintCategory::Cast { unsize_to: None },
+                                ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                             ) {
                                 span_mirbug!(
                                     self,
@@ -2036,7 +2037,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         self.prove_predicate(
                             ty::ClauseKind::WellFormed(src_ty.into()),
                             location.to_locations(),
-                            ConstraintCategory::Cast { unsize_to: None },
+                            ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                         );
 
                         // The type that we see in the fcx is like
@@ -2049,7 +2050,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             src_ty,
                             *ty,
                             location.to_locations(),
-                            ConstraintCategory::Cast { unsize_to: None },
+                            ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                         ) {
                             span_mirbug!(
                                 self,
@@ -2062,19 +2063,23 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
 
-                    CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(safety)) => {
+                    CastKind::PointerCoercion(
+                        PointerCoercion::ClosureFnPointer(safety),
+                        coercion_source,
+                    ) => {
                         let sig = match op.ty(body, tcx).kind() {
                             ty::Closure(_, args) => args.as_closure().sig(),
                             _ => bug!(),
                         };
                         let ty_fn_ptr_from =
-                            Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *safety));
+                            Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, safety));
 
+                        let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
                         if let Err(terr) = self.sub_types(
                             ty_fn_ptr_from,
                             *ty,
                             location.to_locations(),
-                            ConstraintCategory::Cast { unsize_to: None },
+                            ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                         ) {
                             span_mirbug!(
                                 self,
@@ -2087,7 +2092,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
 
-                    CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => {
+                    CastKind::PointerCoercion(
+                        PointerCoercion::UnsafeFnPointer,
+                        coercion_source,
+                    ) => {
                         let fn_sig = op.ty(body, tcx).fn_sig(tcx);
 
                         // The type that we see in the fcx is like
@@ -2099,11 +2107,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
                         let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
 
+                        let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
                         if let Err(terr) = self.sub_types(
                             ty_fn_ptr_from,
                             *ty,
                             location.to_locations(),
-                            ConstraintCategory::Cast { unsize_to: None },
+                            ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                         ) {
                             span_mirbug!(
                                 self,
@@ -2116,7 +2125,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
 
-                    CastKind::PointerCoercion(PointerCoercion::Unsize) => {
+                    CastKind::PointerCoercion(PointerCoercion::Unsize, coercion_source) => {
                         let &ty = ty;
                         let trait_ref = ty::TraitRef::new(
                             tcx,
@@ -2124,22 +2133,21 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             [op.ty(body, tcx), ty],
                         );
 
+                        let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
+                        let unsize_to = tcx.fold_regions(ty, |r, _| {
+                            if let ty::ReVar(_) = r.kind() { tcx.lifetimes.re_erased } else { r }
+                        });
                         self.prove_trait_ref(
                             trait_ref,
                             location.to_locations(),
                             ConstraintCategory::Cast {
-                                unsize_to: Some(tcx.fold_regions(ty, |r, _| {
-                                    if let ty::ReVar(_) = r.kind() {
-                                        tcx.lifetimes.re_erased
-                                    } else {
-                                        r
-                                    }
-                                })),
+                                is_implicit_coercion,
+                                unsize_to: Some(unsize_to),
                             },
                         );
                     }
 
-                    CastKind::DynStar => {
+                    CastKind::PointerCoercion(PointerCoercion::DynStar, coercion_source) => {
                         // get the constraints from the target type (`dyn* Clone`)
                         //
                         // apply them to prove that the source type `Foo` implements `Clone` etc
@@ -2150,12 +2158,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
                         let self_ty = op.ty(body, tcx);
 
+                        let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
                         self.prove_predicates(
                             existential_predicates
                                 .iter()
                                 .map(|predicate| predicate.with_self_ty(tcx, self_ty)),
                             location.to_locations(),
-                            ConstraintCategory::Cast { unsize_to: None },
+                            ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                         );
 
                         let outlives_predicate = tcx.mk_predicate(Binder::dummy(
@@ -2166,11 +2175,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         self.prove_predicate(
                             outlives_predicate,
                             location.to_locations(),
-                            ConstraintCategory::Cast { unsize_to: None },
+                            ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                         );
                     }
 
-                    CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) => {
+                    CastKind::PointerCoercion(
+                        PointerCoercion::MutToConstPointer,
+                        coercion_source,
+                    ) => {
                         let ty::RawPtr(ty_from, hir::Mutability::Mut) = op.ty(body, tcx).kind()
                         else {
                             span_mirbug!(self, rvalue, "unexpected base type for cast {:?}", ty,);
@@ -2180,11 +2192,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             span_mirbug!(self, rvalue, "unexpected target type for cast {:?}", ty,);
                             return;
                         };
+                        let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
                         if let Err(terr) = self.sub_types(
                             *ty_from,
                             *ty_to,
                             location.to_locations(),
-                            ConstraintCategory::Cast { unsize_to: None },
+                            ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                         ) {
                             span_mirbug!(
                                 self,
@@ -2197,7 +2210,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
 
-                    CastKind::PointerCoercion(PointerCoercion::ArrayToPointer) => {
+                    CastKind::PointerCoercion(PointerCoercion::ArrayToPointer, coercion_source) => {
                         let ty_from = op.ty(body, tcx);
 
                         let opt_ty_elem_mut = match ty_from.kind() {
@@ -2242,11 +2255,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             return;
                         }
 
+                        let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
                         if let Err(terr) = self.sub_types(
                             *ty_elem,
                             *ty_to,
                             location.to_locations(),
-                            ConstraintCategory::Cast { unsize_to: None },
+                            ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
                         ) {
                             span_mirbug!(
                                 self,
@@ -2427,7 +2441,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                         src_obj,
                                         dst_obj,
                                         location.to_locations(),
-                                        ConstraintCategory::Cast { unsize_to: None },
+                                        ConstraintCategory::Cast {
+                                            is_implicit_coercion: false,
+                                            unsize_to: None,
+                                        },
                                     )
                                     .unwrap();
                                 }
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index dc342e151f3..1ce0aacab49 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -652,7 +652,7 @@ fn codegen_stmt<'tcx>(
                     lval.write_cvalue(fx, res);
                 }
                 Rvalue::Cast(
-                    CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer),
+                    CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _),
                     ref operand,
                     to_ty,
                 ) => {
@@ -677,7 +677,7 @@ fn codegen_stmt<'tcx>(
                     }
                 }
                 Rvalue::Cast(
-                    CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer),
+                    CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _),
                     ref operand,
                     to_ty,
                 ) => {
@@ -688,6 +688,7 @@ fn codegen_stmt<'tcx>(
                 Rvalue::Cast(
                     CastKind::PointerCoercion(
                         PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer,
+                        _,
                     ),
                     ..,
                 ) => {
@@ -741,7 +742,7 @@ fn codegen_stmt<'tcx>(
                     }
                 }
                 Rvalue::Cast(
-                    CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
+                    CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _),
                     ref operand,
                     _to_ty,
                 ) => {
@@ -763,14 +764,18 @@ fn codegen_stmt<'tcx>(
                     }
                 }
                 Rvalue::Cast(
-                    CastKind::PointerCoercion(PointerCoercion::Unsize),
+                    CastKind::PointerCoercion(PointerCoercion::Unsize, _),
                     ref operand,
                     _to_ty,
                 ) => {
                     let operand = codegen_operand(fx, operand);
                     crate::unsize::coerce_unsized_into(fx, operand, lval);
                 }
-                Rvalue::Cast(CastKind::DynStar, ref operand, _) => {
+                Rvalue::Cast(
+                    CastKind::PointerCoercion(PointerCoercion::DynStar, _),
+                    ref operand,
+                    _,
+                ) => {
                     let operand = codegen_operand(fx, operand);
                     crate::unsize::coerce_dyn_star(fx, operand, lval);
                 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index ad0e03fc263..f9c0f3ce941 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -34,7 +34,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
 
             mir::Rvalue::Cast(
-                mir::CastKind::PointerCoercion(PointerCoercion::Unsize),
+                mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _),
                 ref source,
                 _,
             ) => {
@@ -465,7 +465,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         let lladdr = bx.ptrtoint(llptr, llcast_ty);
                         OperandValue::Immediate(lladdr)
                     }
-                    mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => {
+                    mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => {
                         match *operand.layout.ty.kind() {
                             ty::FnDef(def_id, args) => {
                                 let instance = ty::Instance::resolve_for_fn_ptr(
@@ -481,7 +481,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
                         }
                     }
-                    mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)) => {
+                    mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _) => {
                         match *operand.layout.ty.kind() {
                             ty::Closure(def_id, args) => {
                                 let instance = Instance::resolve_closure(
@@ -496,11 +496,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
                         }
                     }
-                    mir::CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => {
+                    mir::CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _) => {
                         // This is a no-op at the LLVM level.
                         operand.val
                     }
-                    mir::CastKind::PointerCoercion(PointerCoercion::Unsize) => {
+                    mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _) => {
                         assert!(bx.cx().is_backend_scalar_pair(cast));
                         let (lldata, llextra) = operand.val.pointer_parts();
                         let (lldata, llextra) =
@@ -508,7 +508,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         OperandValue::Pair(lldata, llextra)
                     }
                     mir::CastKind::PointerCoercion(
-                        PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer,
+                        PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _
                     ) => {
                         bug!("{kind:?} is for borrowck, and should never appear in codegen");
                     }
@@ -526,7 +526,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             bug!("unexpected non-pair operand");
                         }
                     }
-                    mir::CastKind::DynStar => {
+                    mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _) => {
                         let (lldata, llextra) = operand.val.pointer_parts();
                         let (lldata, llextra) =
                             base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra);
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 2c33ff9d219..e1b60597997 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -440,6 +440,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     | PointerCoercion::UnsafeFnPointer
                     | PointerCoercion::ClosureFnPointer(_)
                     | PointerCoercion::ReifyFnPointer,
+                    _,
                 ),
                 _,
                 _,
@@ -447,8 +448,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 // These are all okay; they only change the type, not the data.
             }
 
-            Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), _, _) => {
-                // Unsizing is implemented for CTFE.
+            Rvalue::Cast(
+                CastKind::PointerCoercion(PointerCoercion::Unsize | PointerCoercion::DynStar, _),
+                _,
+                _,
+            ) => {
+                // Unsizing and `dyn*` coercions are implemented for CTFE.
             }
 
             Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
@@ -458,10 +463,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 // Since no pointer can ever get exposed (rejected above), this is easy to support.
             }
 
-            Rvalue::Cast(CastKind::DynStar, _, _) => {
-                // `dyn*` coercion is implemented for CTFE.
-            }
-
             Rvalue::Cast(_, _, _) => {}
 
             Rvalue::NullaryOp(
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 70d074cfdc5..85e7d91c2ad 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -32,7 +32,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             if cast_ty == dest.layout.ty { dest.layout } else { self.layout_of(cast_ty)? };
         // FIXME: In which cases should we trigger UB when the source is uninit?
         match cast_kind {
-            CastKind::PointerCoercion(PointerCoercion::Unsize) => {
+            CastKind::PointerCoercion(PointerCoercion::Unsize, _) => {
                 self.unsize_into(src, cast_layout, dest)?;
             }
 
@@ -68,11 +68,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
             CastKind::PointerCoercion(
                 PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer,
+                _,
             ) => {
                 bug!("{cast_kind:?} casts are for borrowck only, not runtime MIR");
             }
 
-            CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => {
+            CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => {
                 // All reifications must be monomorphic, bail out otherwise.
                 ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
 
@@ -94,7 +95,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 }
             }
 
-            CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => {
+            CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _) => {
                 let src = self.read_immediate(src)?;
                 match cast_ty.kind() {
                     ty::FnPtr(..) => {
@@ -105,7 +106,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 }
             }
 
-            CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)) => {
+            CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _) => {
                 // All reifications must be monomorphic, bail out otherwise.
                 ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
 
@@ -125,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 }
             }
 
-            CastKind::DynStar => {
+            CastKind::PointerCoercion(PointerCoercion::DynStar, _) => {
                 if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() {
                     // Initial cast from sized to dyn trait
                     let vtable = self.get_vtable_ptr(src.layout.ty, data)?;
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index aab0c4c116a..fcd2940b83a 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -32,13 +32,14 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
 use rustc_hir::{self as hir, ExprKind};
+use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_macros::{TypeFoldable, TypeVisitable};
-use rustc_middle::bug;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, VariantDef};
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::sym;
@@ -152,12 +153,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub enum CastError {
+enum CastError<'tcx> {
     ErrorGuaranteed(ErrorGuaranteed),
 
     CastToBool,
     CastToChar,
-    DifferingKinds,
+    DifferingKinds {
+        src_kind: PointerKind<'tcx>,
+        dst_kind: PointerKind<'tcx>,
+    },
     /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`).
     SizedUnsizedCast,
     IllegalCast,
@@ -177,7 +181,7 @@ pub enum CastError {
     ForeignNonExhaustiveAdt,
 }
 
-impl From<ErrorGuaranteed> for CastError {
+impl From<ErrorGuaranteed> for CastError<'_> {
     fn from(err: ErrorGuaranteed) -> Self {
         CastError::ErrorGuaranteed(err)
     }
@@ -251,7 +255,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         }
     }
 
-    fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
+    fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError<'tcx>) {
         match e {
             CastError::ErrorGuaranteed(_) => {
                 // an error has already been reported
@@ -303,10 +307,52 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             CastError::IllegalCast => {
                 make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx).emit();
             }
-            CastError::DifferingKinds => {
-                make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx)
-                    .with_note("vtable kinds may not match")
-                    .emit();
+            CastError::DifferingKinds { src_kind, dst_kind } => {
+                let mut err =
+                    make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx);
+
+                match (src_kind, dst_kind) {
+                    (PointerKind::VTable(_), PointerKind::VTable(_)) => {
+                        err.note("the trait objects may have different vtables");
+                    }
+                    (
+                        PointerKind::OfParam(_) | PointerKind::OfAlias(_),
+                        PointerKind::OfParam(_)
+                        | PointerKind::OfAlias(_)
+                        | PointerKind::VTable(_)
+                        | PointerKind::Length,
+                    )
+                    | (
+                        PointerKind::VTable(_) | PointerKind::Length,
+                        PointerKind::OfParam(_) | PointerKind::OfAlias(_),
+                    ) => {
+                        err.note("the pointers may have different metadata");
+                    }
+                    (PointerKind::VTable(_), PointerKind::Length)
+                    | (PointerKind::Length, PointerKind::VTable(_)) => {
+                        err.note("the pointers have different metadata");
+                    }
+                    (
+                        PointerKind::Thin,
+                        PointerKind::Thin
+                        | PointerKind::VTable(_)
+                        | PointerKind::Length
+                        | PointerKind::OfParam(_)
+                        | PointerKind::OfAlias(_),
+                    )
+                    | (
+                        PointerKind::VTable(_)
+                        | PointerKind::Length
+                        | PointerKind::OfParam(_)
+                        | PointerKind::OfAlias(_),
+                        PointerKind::Thin,
+                    )
+                    | (PointerKind::Length, PointerKind::Length) => {
+                        span_bug!(self.span, "unexpected cast error: {e:?}")
+                    }
+                }
+
+                err.emit();
             }
             CastError::CastToBool => {
                 let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
@@ -670,10 +716,20 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     /// Checks a cast, and report an error if one exists. In some cases, this
     /// can return Ok and create type errors in the fcx rather than returning
     /// directly. coercion-cast is handled in check instead of here.
-    fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
+    fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError<'tcx>> {
         use rustc_middle::ty::cast::CastTy::*;
         use rustc_middle::ty::cast::IntTy::*;
 
+        if self.cast_ty.is_dyn_star() {
+            if fcx.tcx.features().dyn_star {
+                span_bug!(self.span, "should be handled by `coerce`");
+            } else {
+                // Report "casting is invalid" rather than "non-primitive cast"
+                // if the feature is not enabled.
+                return Err(CastError::IllegalCast);
+            }
+        }
+
         let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty))
         {
             (Some(t_from), Some(t_cast)) => (t_from, t_cast),
@@ -780,16 +836,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
 
             (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
-
-            (_, DynStar) => {
-                if fcx.tcx.features().dyn_star {
-                    bug!("should be handled by `coerce`")
-                } else {
-                    Err(CastError::IllegalCast)
-                }
-            }
-
-            (DynStar, _) => Err(CastError::IllegalCast),
         }
     }
 
@@ -798,27 +844,34 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         fcx: &FnCtxt<'a, 'tcx>,
         m_src: ty::TypeAndMut<'tcx>,
         m_dst: ty::TypeAndMut<'tcx>,
-    ) -> Result<CastKind, CastError> {
+    ) -> Result<CastKind, CastError<'tcx>> {
         debug!("check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}");
-        // ptr-ptr cast. vtables must match.
+        // ptr-ptr cast. metadata must match.
 
         let src_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_src.ty, self.span)?);
         let dst_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_dst.ty, self.span)?);
 
-        match (src_kind, dst_kind) {
-            // We can't cast if target pointer kind is unknown
-            (_, None) => Err(CastError::UnknownCastPtrKind),
-            // Cast to thin pointer is OK
-            (_, Some(PointerKind::Thin)) => Ok(CastKind::PtrPtrCast),
+        // We can't cast if target pointer kind is unknown
+        let Some(dst_kind) = dst_kind else {
+            return Err(CastError::UnknownCastPtrKind);
+        };
+
+        // Cast to thin pointer is OK
+        if dst_kind == PointerKind::Thin {
+            return Ok(CastKind::PtrPtrCast);
+        }
 
-            // We can't cast to fat pointer if source pointer kind is unknown
-            (None, _) => Err(CastError::UnknownExprPtrKind),
+        // We can't cast to fat pointer if source pointer kind is unknown
+        let Some(src_kind) = src_kind else {
+            return Err(CastError::UnknownCastPtrKind);
+        };
 
+        match (src_kind, dst_kind) {
             // thin -> fat? report invalid cast (don't complain about vtable kinds)
-            (Some(PointerKind::Thin), _) => Err(CastError::SizedUnsizedCast),
+            (PointerKind::Thin, _) => Err(CastError::SizedUnsizedCast),
 
             // trait object -> trait object? need to do additional checks
-            (Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => {
+            (PointerKind::VTable(src_tty), PointerKind::VTable(dst_tty)) => {
                 match (src_tty.principal(), dst_tty.principal()) {
                     // A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure
                     // - `Src` and `Dst` traits are the same
@@ -834,7 +887,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
                         // and is unaffected by this check.
                         if src_principal.def_id() != dst_principal.def_id() {
-                            return Err(CastError::DifferingKinds);
+                            return Err(CastError::DifferingKinds { src_kind, dst_kind });
                         }
 
                         // We need to reconstruct trait object types.
@@ -860,7 +913,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         ));
 
                         // `dyn Src = dyn Dst`, this checks for matching traits/generics
-                        fcx.demand_eqtype(self.span, src_obj, dst_obj);
+                        // This is `demand_eqtype`, but inlined to give a better error.
+                        let cause = fcx.misc(self.span);
+                        if fcx
+                            .at(&cause, fcx.param_env)
+                            .eq(DefineOpaqueTypes::Yes, src_obj, dst_obj)
+                            .map(|infer_ok| fcx.register_infer_ok_obligations(infer_ok))
+                            .is_err()
+                        {
+                            return Err(CastError::DifferingKinds { src_kind, dst_kind });
+                        }
 
                         // Check that `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`.
                         // Emit an FCW otherwise.
@@ -905,17 +967,17 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
                     // dyn Trait -> dyn Auto? should be ok, but we used to not allow it.
                     // FIXME: allow this
-                    (Some(_), None) => Err(CastError::DifferingKinds),
+                    (Some(_), None) => Err(CastError::DifferingKinds { src_kind, dst_kind }),
 
                     // dyn Auto -> dyn Trait? not ok.
-                    (None, Some(_)) => Err(CastError::DifferingKinds),
+                    (None, Some(_)) => Err(CastError::DifferingKinds { src_kind, dst_kind }),
                 }
             }
 
             // fat -> fat? metadata kinds must match
-            (Some(src_kind), Some(dst_kind)) if src_kind == dst_kind => Ok(CastKind::PtrPtrCast),
+            (src_kind, dst_kind) if src_kind == dst_kind => Ok(CastKind::PtrPtrCast),
 
-            (_, _) => Err(CastError::DifferingKinds),
+            (_, _) => Err(CastError::DifferingKinds { src_kind, dst_kind }),
         }
     }
 
@@ -923,7 +985,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         &self,
         fcx: &FnCtxt<'a, 'tcx>,
         m_cast: ty::TypeAndMut<'tcx>,
-    ) -> Result<CastKind, CastError> {
+    ) -> Result<CastKind, CastError<'tcx>> {
         // fptr-ptr cast. must be to thin ptr
 
         match fcx.pointer_kind(m_cast.ty, self.span)? {
@@ -937,7 +999,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         &self,
         fcx: &FnCtxt<'a, 'tcx>,
         m_expr: ty::TypeAndMut<'tcx>,
-    ) -> Result<CastKind, CastError> {
+    ) -> Result<CastKind, CastError<'tcx>> {
         // ptr-addr cast. must be from thin ptr
 
         match fcx.pointer_kind(m_expr.ty, self.span)? {
@@ -952,7 +1014,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         fcx: &FnCtxt<'a, 'tcx>,
         m_expr: ty::TypeAndMut<'tcx>,
         m_cast: ty::TypeAndMut<'tcx>,
-    ) -> Result<CastKind, CastError> {
+    ) -> Result<CastKind, CastError<'tcx>> {
         // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
         if m_expr.mutbl >= m_cast.mutbl {
             if let ty::Array(ety, _) = m_expr.ty.kind() {
@@ -987,7 +1049,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         &self,
         fcx: &FnCtxt<'a, 'tcx>,
         m_cast: TypeAndMut<'tcx>,
-    ) -> Result<CastKind, CastError> {
+    ) -> Result<CastKind, CastError<'tcx>> {
         // ptr-addr cast. pointer must be thin.
         match fcx.pointer_kind(m_cast.ty, self.span)? {
             None => Err(CastError::UnknownCastPtrKind),
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 7be91d78e19..b08c5bc6d9a 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -769,7 +769,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         ));
 
         Ok(InferOk {
-            value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
+            value: (
+                vec![Adjustment { kind: Adjust::Pointer(PointerCoercion::DynStar), target: b }],
+                b,
+            ),
             obligations,
         })
     }
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 29feed56290..bb5f3511373 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -759,9 +759,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
         for adjustment in adjustments {
             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
             match adjustment.kind {
-                adjustment::Adjust::NeverToAny
-                | adjustment::Adjust::Pointer(_)
-                | adjustment::Adjust::DynStar => {
+                adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
                     self.consume_or_copy(&place_with_id, place_with_id.hir_id);
@@ -1296,8 +1294,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
             adjustment::Adjust::NeverToAny
             | adjustment::Adjust::Pointer(_)
             | adjustment::Adjust::Borrow(_)
-            | adjustment::Adjust::ReborrowPin(..)
-            | adjustment::Adjust::DynStar => {
+            | adjustment::Adjust::ReborrowPin(..) => {
                 // Result is an rvalue.
                 Ok(self.cat_rvalue(expr.hir_id, target))
             }
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 1002f64f849..70331214ac5 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -234,7 +234,9 @@ pub enum ConstraintCategory<'tcx> {
     UseAsStatic,
     TypeAnnotation,
     Cast {
-        /// Whether this is an unsizing cast and if yes, this contains the target type.
+        /// Whether this cast is a coercion that was automatically inserted by the compiler.
+        is_implicit_coercion: bool,
+        /// Whether this is an unsizing coercion and if yes, this contains the target type.
         /// Region variables are erased to ReErased.
         #[derive_where(skip)]
         unsize_to: Option<Ty<'tcx>>,
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index bc7dfa6205e..88ed90c3114 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -432,9 +432,8 @@ impl<'tcx> Rvalue<'tcx> {
                 | CastKind::IntToFloat
                 | CastKind::FnPtrToPtr
                 | CastKind::PtrToPtr
-                | CastKind::PointerCoercion(_)
+                | CastKind::PointerCoercion(_, _)
                 | CastKind::PointerWithExposedProvenance
-                | CastKind::DynStar
                 | CastKind::Transmute,
                 _,
                 _,
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 231eb198983..ae75f2d4187 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -579,7 +579,8 @@ pub struct CopyNonOverlapping<'tcx> {
     pub count: Operand<'tcx>,
 }
 
-/// Represents how a `TerminatorKind::Call` was constructed, used for diagnostics
+/// Represents how a [`TerminatorKind::Call`] was constructed.
+/// Used only for diagnostics.
 #[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, PartialEq, Hash, HashStable)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub enum CallSource {
@@ -1403,9 +1404,7 @@ pub enum CastKind {
     /// * [`PointerCoercion::MutToConstPointer`]
     ///
     /// Both are runtime nops, so should be [`CastKind::PtrToPtr`] instead in runtime MIR.
-    PointerCoercion(PointerCoercion),
-    /// Cast into a dyn* object.
-    DynStar,
+    PointerCoercion(PointerCoercion, CoercionSource),
     IntToInt,
     FloatToInt,
     FloatToFloat,
@@ -1421,6 +1420,16 @@ pub enum CastKind {
     Transmute,
 }
 
+/// Represents how a [`CastKind::PointerCoercion`] was constructed.
+/// Used only for diagnostics.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+pub enum CoercionSource {
+    /// The coercion was manually written by the user with an `as` cast.
+    AsCast,
+    /// The coercion was automatically inserted by the compiler.
+    Implicit,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub enum AggregateKind<'tcx> {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 32234d6b55d..e614d41899a 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -338,6 +338,8 @@ pub enum ExprKind<'tcx> {
     PointerCoercion {
         cast: PointerCoercion,
         source: ExprId,
+        /// Whether this coercion is written with an `as` cast in the source code.
+        is_from_as_cast: bool,
     },
     /// A `loop` expression.
     Loop {
@@ -453,12 +455,14 @@ pub enum ExprKind<'tcx> {
         source: ExprId,
         /// Type that the user gave to this expression
         user_ty: UserTy<'tcx>,
+        user_ty_span: Span,
     },
-    /// A type ascription on a value, e.g. `42: i32`.
+    /// A type ascription on a value, e.g. `type_ascribe!(42, i32)` or `42 as i32`.
     ValueTypeAscription {
         source: ExprId,
         /// Type that the user gave to this expression
         user_ty: UserTy<'tcx>,
+        user_ty_span: Span,
     },
     /// A closure definition.
     Closure(Box<ClosureExpr<'tcx>>),
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index e246ecebbec..58e2ebaeaf8 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -68,7 +68,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
         Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
         Use { source } => visitor.visit_expr(&visitor.thir()[source]),
         NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
-        PointerCoercion { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
+        PointerCoercion { source, cast: _, is_from_as_cast: _ } => {
+            visitor.visit_expr(&visitor.thir()[source])
+        }
         Let { expr, ref pat } => {
             visitor.visit_expr(&visitor.thir()[expr]);
             visitor.visit_pat(pat);
@@ -129,7 +131,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
                 visitor.visit_expr(&visitor.thir()[base.base]);
             }
         }
-        PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
+        PlaceTypeAscription { source, user_ty: _, user_ty_span: _ }
+        | ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
             visitor.visit_expr(&visitor.thir()[source])
         }
         Closure(box ClosureExpr {
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 5a32078760e..41a20e89cbf 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -35,6 +35,9 @@ pub enum PointerCoercion {
     /// type. Codegen backends and miri figure out what has to be done
     /// based on the precise source/target type at hand.
     Unsize,
+
+    /// Go from a pointer-like type to a `dyn*` object.
+    DynStar,
 }
 
 /// Represents coercing a value to a different type of value.
@@ -102,9 +105,6 @@ pub enum Adjust<'tcx> {
 
     Pointer(PointerCoercion),
 
-    /// Cast into a dyn* object.
-    DynStar,
-
     /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`.
     ReborrowPin(ty::Region<'tcx>, hir::Mutability),
 }
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index 46f37659536..b1316ceef5a 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -34,15 +34,12 @@ pub enum CastTy<'tcx> {
     FnPtr,
     /// Raw pointers.
     Ptr(ty::TypeAndMut<'tcx>),
-    /// Casting into a `dyn*` value.
-    DynStar,
 }
 
 /// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html)
 /// (or rustc_hir_analysis/check/cast.rs).
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum CastKind {
-    CoercionCast,
     PtrPtrCast,
     PtrAddrCast,
     AddrPtrCast,
@@ -53,7 +50,6 @@ pub enum CastKind {
     ArrayPtrCast,
     FnPtrPtrCast,
     FnPtrAddrCast,
-    DynStarCast,
 }
 
 impl<'tcx> CastTy<'tcx> {
@@ -71,7 +67,6 @@ impl<'tcx> CastTy<'tcx> {
             ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)),
             ty::RawPtr(ty, mutbl) => Some(CastTy::Ptr(ty::TypeAndMut { ty, mutbl })),
             ty::FnPtr(..) => Some(CastTy::FnPtr),
-            ty::Dynamic(_, _, ty::DynStar) => Some(CastTy::DynStar),
             _ => None,
         }
     }
@@ -86,7 +81,6 @@ pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKin
             mir::CastKind::PointerExposeProvenance
         }
         (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance,
-        (_, Some(CastTy::DynStar)) => mir::CastKind::DynStar,
         (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt,
         (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr,
 
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 2084bcae7b7..c7298e3ddfa 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -470,21 +470,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(place_builder)
             }
 
-            ExprKind::PlaceTypeAscription { source, ref user_ty } => {
+            ExprKind::PlaceTypeAscription { source, ref user_ty, user_ty_span } => {
                 let place_builder = unpack!(
                     block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
                 );
                 if let Some(user_ty) = user_ty {
+                    let ty_source_info = this.source_info(user_ty_span);
                     let annotation_index =
                         this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
-                            span: source_info.span,
+                            span: user_ty_span,
                             user_ty: user_ty.clone(),
                             inferred_ty: expr.ty,
                         });
 
                     let place = place_builder.to_place(this);
                     this.cfg.push(block, Statement {
-                        source_info,
+                        source_info: ty_source_info,
                         kind: StatementKind::AscribeUserType(
                             Box::new((place, UserTypeProjection {
                                 base: annotation_index,
@@ -496,20 +497,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
                 block.and(place_builder)
             }
-            ExprKind::ValueTypeAscription { source, ref user_ty } => {
+            ExprKind::ValueTypeAscription { source, ref user_ty, user_ty_span } => {
                 let source_expr = &this.thir[source];
                 let temp = unpack!(
                     block = this.as_temp(block, source_expr.temp_lifetime, source, mutability)
                 );
                 if let Some(user_ty) = user_ty {
+                    let ty_source_info = this.source_info(user_ty_span);
                     let annotation_index =
                         this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
-                            span: source_info.span,
+                            span: user_ty_span,
                             user_ty: user_ty.clone(),
                             inferred_ty: expr.ty,
                         });
                     this.cfg.push(block, Statement {
-                        source_info,
+                        source_info: ty_source_info,
                         kind: StatementKind::AscribeUserType(
                             Box::new((Place::from(temp), UserTypeProjection {
                                 base: annotation_index,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index ffedee8a1e8..fd949a53384 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -292,7 +292,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let cast_kind = mir_cast_kind(ty, expr.ty);
                 block.and(Rvalue::Cast(cast_kind, source, expr.ty))
             }
-            ExprKind::PointerCoercion { cast, source } => {
+            ExprKind::PointerCoercion { cast, source, is_from_as_cast } => {
                 let source = unpack!(
                     block = this.as_operand(
                         block,
@@ -302,7 +302,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         NeedsTemporary::No
                     )
                 );
-                block.and(Rvalue::Cast(CastKind::PointerCoercion(cast), source, expr.ty))
+                let origin =
+                    if is_from_as_cast { CoercionSource::AsCast } else { CoercionSource::Implicit };
+                block.and(Rvalue::Cast(CastKind::PointerCoercion(cast, origin), source, expr.ty))
             }
             ExprKind::Array { ref fields } => {
                 // (*) We would (maybe) be closer to codegen if we
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 63873aad02a..020c202f965 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -407,7 +407,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         source_info,
                         temp,
                         Rvalue::Cast(
-                            CastKind::PointerCoercion(PointerCoercion::Unsize),
+                            CastKind::PointerCoercion(
+                                PointerCoercion::Unsize,
+                                CoercionSource::Implicit,
+                            ),
                             Operand::Copy(val),
                             ty,
                         ),
@@ -421,7 +424,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         source_info,
                         slice,
                         Rvalue::Cast(
-                            CastKind::PointerCoercion(PointerCoercion::Unsize),
+                            CastKind::PointerCoercion(
+                                PointerCoercion::Unsize,
+                                CoercionSource::Implicit,
+                            ),
                             expect,
                             ty,
                         ),
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 55236933922..fbd45f59a4f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -104,16 +104,29 @@ impl<'tcx> Cx<'tcx> {
         };
 
         let kind = match adjustment.kind {
-            Adjust::Pointer(PointerCoercion::Unsize) => {
-                adjust_span(&mut expr);
+            Adjust::Pointer(cast) => {
+                if cast == PointerCoercion::Unsize {
+                    adjust_span(&mut expr);
+                }
+
+                let is_from_as_cast = if let hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Cast(..),
+                    span: cast_span,
+                    ..
+                }) = self.tcx.parent_hir_node(hir_expr.hir_id)
+                {
+                    // Use the whole span of the `x as T` expression for the coercion.
+                    span = *cast_span;
+                    true
+                } else {
+                    false
+                };
                 ExprKind::PointerCoercion {
-                    cast: PointerCoercion::Unsize,
+                    cast,
                     source: self.thir.exprs.push(expr),
+                    is_from_as_cast,
                 }
             }
-            Adjust::Pointer(cast) => {
-                ExprKind::PointerCoercion { cast, source: self.thir.exprs.push(expr) }
-            }
             Adjust::NeverToAny if adjustment.target.is_never() => return expr,
             Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) },
             Adjust::Deref(None) => {
@@ -146,7 +159,6 @@ impl<'tcx> Cx<'tcx> {
             Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
                 ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) }
             }
-            Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
             Adjust::ReborrowPin(region, mutbl) => {
                 debug!("apply ReborrowPin adjustment");
                 // Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }`
@@ -236,6 +248,7 @@ impl<'tcx> Cx<'tcx> {
             ExprKind::PointerCoercion {
                 source: self.mirror_expr(source),
                 cast: PointerCoercion::ArrayToPointer,
+                is_from_as_cast: true,
             }
         } else if let hir::ExprKind::Path(ref qpath) = source.kind
             && let res = self.typeck_results().qpath_res(qpath, source.hir_id)
@@ -841,6 +854,7 @@ impl<'tcx> Cx<'tcx> {
                     ExprKind::ValueTypeAscription {
                         source: cast_expr,
                         user_ty: Some(Box::new(*user_ty)),
+                        user_ty_span: cast_ty.span,
                     }
                 } else {
                     cast
@@ -852,9 +866,17 @@ impl<'tcx> Cx<'tcx> {
                 debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
                 let mirrored = self.mirror_expr(source);
                 if source.is_syntactic_place_expr() {
-                    ExprKind::PlaceTypeAscription { source: mirrored, user_ty }
+                    ExprKind::PlaceTypeAscription {
+                        source: mirrored,
+                        user_ty,
+                        user_ty_span: ty.span,
+                    }
                 } else {
-                    ExprKind::ValueTypeAscription { source: mirrored, user_ty }
+                    ExprKind::ValueTypeAscription {
+                        source: mirrored,
+                        user_ty,
+                        user_ty_span: ty.span,
+                    }
                 }
             }
             hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index ce7774f5948..61317925d09 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -292,9 +292,14 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_expr(*source, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl);
             }
-            PointerCoercion { cast, source } => {
+            PointerCoercion { cast, is_from_as_cast, source } => {
                 print_indented!(self, "Pointer {", depth_lvl);
                 print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1);
+                print_indented!(
+                    self,
+                    format!("is_from_as_cast: {:?}", is_from_as_cast),
+                    depth_lvl + 1
+                );
                 print_indented!(self, "source:", depth_lvl + 1);
                 self.print_expr(*source, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl);
@@ -454,16 +459,18 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_adt_expr(&**adt_expr, depth_lvl + 1);
                 print_indented!(self, "}", depth_lvl);
             }
-            PlaceTypeAscription { source, user_ty } => {
+            PlaceTypeAscription { source, user_ty, user_ty_span } => {
                 print_indented!(self, "PlaceTypeAscription {", depth_lvl);
                 print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, format!("user_ty_span: {:?}", user_ty_span), depth_lvl + 1);
                 print_indented!(self, "source:", depth_lvl + 1);
                 self.print_expr(*source, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl);
             }
-            ValueTypeAscription { source, user_ty } => {
+            ValueTypeAscription { source, user_ty, user_ty_span } => {
                 print_indented!(self, "ValueTypeAscription {", depth_lvl);
                 print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+                print_indented!(self, format!("user_ty_span: {:?}", user_ty_span), depth_lvl + 1);
                 print_indented!(self, "source:", depth_lvl + 1);
                 self.print_expr(*source, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl);
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 5395e1b0e94..6a22a58470c 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -42,6 +42,7 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
                             ref mut cast_kind @ CastKind::PointerCoercion(
                                 PointerCoercion::ArrayToPointer
                                 | PointerCoercion::MutToConstPointer,
+                                _,
                             ),
                             ..,
                         ),
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 2026b789315..88dc8e74a8c 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -189,7 +189,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 }
             }
             Rvalue::Cast(
-                CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize),
+                CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _),
                 operand,
                 _,
             ) => {
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 4d44669fa3e..f735d08fca5 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -576,7 +576,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     }
                     value.offset(Size::ZERO, to, &self.ecx).ok()?
                 }
-                CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) => {
+                CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => {
                     let src = self.evaluated[value].as_ref()?;
                     let to = self.ecx.layout_of(to).ok()?;
                     let dest = self.ecx.allocate(to, MemoryKind::Stack).ok()?;
@@ -593,7 +593,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     let ret = self.ecx.ptr_to_ptr(&src, to).ok()?;
                     ret.into()
                 }
-                CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer) => {
+                CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => {
                     let src = self.evaluated[value].as_ref()?;
                     let src = self.ecx.read_immediate(src).ok()?;
                     let to = self.ecx.layout_of(to).ok()?;
@@ -1138,7 +1138,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             (
                 UnOp::PtrMetadata,
                 Value::Cast {
-                    kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize),
+                    kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _),
                     from,
                     to,
                     ..
@@ -1342,7 +1342,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             return Some(value);
         }
 
-        if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_)) = kind {
+        if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_), _) = kind {
             // Each reification of a generic fn may get a different pointer.
             // Do not try to merge them.
             return self.new_opaque();
@@ -1429,7 +1429,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         // We have an unsizing cast, which assigns the length to fat pointer metadata.
         if let Value::Cast { kind, from, to, .. } = self.get(inner)
-            && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind
+            && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind
             && let Some(from) = from.builtin_deref(true)
             && let ty::Array(_, len) = from.kind()
             && let Some(to) = to.builtin_deref(true)
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
index f24de609e6b..cf5c5f85a9f 100644
--- a/compiler/rustc_mir_transform/src/mentioned_items.rs
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -70,11 +70,11 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
         match *rvalue {
             // We need to detect unsizing casts that required vtables.
             mir::Rvalue::Cast(
-                mir::CastKind::PointerCoercion(PointerCoercion::Unsize),
+                mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _)
+                | mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _),
                 ref operand,
                 target_ty,
-            )
-            | mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => {
+            ) => {
                 // This isn't monomorphized yet so we can't tell what the actual types are -- just
                 // add everything that may involve a vtable.
                 let source_ty = operand.ty(self.body, self.tcx);
@@ -96,7 +96,7 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
             }
             // Similarly, record closures that are turned into function pointers.
             mir::Rvalue::Cast(
-                mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
+                mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _),
                 ref operand,
                 _,
             ) => {
@@ -106,7 +106,7 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
             }
             // And finally, function pointer reification casts.
             mir::Rvalue::Cast(
-                mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer),
+                mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _),
                 ref operand,
                 _,
             ) => {
diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
index c206252c15a..71723f040b3 100644
--- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
+++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
@@ -7,9 +7,10 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::{
-    BasicBlock, BasicBlockData, Body, CallSource, CastKind, Const, ConstOperand, ConstValue, Local,
-    LocalDecl, MirSource, Operand, Place, PlaceElem, RETURN_PLACE, Rvalue, SourceInfo, Statement,
-    StatementKind, Terminator, TerminatorKind, UnwindAction, UnwindTerminateReason,
+    BasicBlock, BasicBlockData, Body, CallSource, CastKind, CoercionSource, Const, ConstOperand,
+    ConstValue, Local, LocalDecl, MirSource, Operand, Place, PlaceElem, RETURN_PLACE, Rvalue,
+    SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnwindAction,
+    UnwindTerminateReason,
 };
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::util::{AsyncDropGlueMorphology, Discr};
@@ -329,7 +330,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> {
     fn put_array_as_slice(&mut self, elem_ty: Ty<'tcx>) {
         let slice_ptr_ty = Ty::new_mut_ptr(self.tcx, Ty::new_slice(self.tcx, elem_ty));
         self.put_temp_rvalue(Rvalue::Cast(
-            CastKind::PointerCoercion(PointerCoercion::Unsize),
+            CastKind::PointerCoercion(PointerCoercion::Unsize, CoercionSource::Implicit),
             Operand::Copy(Self::SELF_PTR.into()),
             slice_ptr_ty,
         ))
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 914dddc1a56..eda0b8c75f3 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1128,12 +1128,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             Rvalue::Cast(kind, operand, target_type) => {
                 let op_ty = operand.ty(self.body, self.tcx);
                 match kind {
-                    CastKind::DynStar => {
-                        // FIXME(dyn-star): make sure nothing needs to be done here.
-                    }
                     // FIXME: Add Checks for these
                     CastKind::PointerWithExposedProvenance | CastKind::PointerExposeProvenance => {}
-                    CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => {
+                    CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _) => {
                         // FIXME: check signature compatibility.
                         check_kinds!(
                             op_ty,
@@ -1146,7 +1143,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             ty::FnPtr(..)
                         );
                     }
-                    CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => {
+                    CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _) => {
                         // FIXME: check safety and signature compatibility.
                         check_kinds!(
                             op_ty,
@@ -1159,7 +1156,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             ty::FnPtr(..)
                         );
                     }
-                    CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(..)) => {
+                    CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(..), _) => {
                         // FIXME: check safety, captures, and signature compatibility.
                         check_kinds!(
                             op_ty,
@@ -1172,7 +1169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             ty::FnPtr(..)
                         );
                     }
-                    CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) => {
+                    CastKind::PointerCoercion(PointerCoercion::MutToConstPointer, _) => {
                         // FIXME: check same pointee?
                         check_kinds!(
                             op_ty,
@@ -1188,7 +1185,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             self.fail(location, format!("After borrowck, MIR disallows {kind:?}"));
                         }
                     }
-                    CastKind::PointerCoercion(PointerCoercion::ArrayToPointer) => {
+                    CastKind::PointerCoercion(PointerCoercion::ArrayToPointer, _) => {
                         // FIXME: Check pointee types
                         check_kinds!(
                             op_ty,
@@ -1204,10 +1201,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             self.fail(location, format!("After borrowck, MIR disallows {kind:?}"));
                         }
                     }
-                    CastKind::PointerCoercion(PointerCoercion::Unsize) => {
+                    CastKind::PointerCoercion(PointerCoercion::Unsize, _) => {
                         // This is used for all `CoerceUnsized` types,
                         // not just pointers/references, so is hard to check.
                     }
+                    CastKind::PointerCoercion(PointerCoercion::DynStar, _) => {
+                        // FIXME(dyn-star): make sure nothing needs to be done here.
+                    }
                     CastKind::IntToInt | CastKind::IntToFloat => {
                         let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool();
                         let target_valid = target_type.is_numeric() || target_type.is_char();
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 8d137b8d8f9..fd3ae4435a6 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -665,11 +665,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
             // have to instantiate all methods of the trait being cast to, so we
             // can build the appropriate vtable.
             mir::Rvalue::Cast(
-                mir::CastKind::PointerCoercion(PointerCoercion::Unsize),
+                mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _)
+                | mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _),
                 ref operand,
                 target_ty,
-            )
-            | mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => {
+            ) => {
                 let source_ty = operand.ty(self.body, self.tcx);
                 // *Before* monomorphizing, record that we already handled this mention.
                 self.used_mentioned_items
@@ -694,7 +694,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 }
             }
             mir::Rvalue::Cast(
-                mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer),
+                mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _),
                 ref operand,
                 _,
             ) => {
@@ -705,7 +705,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 visit_fn_use(self.tcx, fn_ty, false, span, self.used_items);
             }
             mir::Rvalue::Cast(
-                mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
+                mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _),
                 ref operand,
                 _,
             ) => {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index f4c7fd7c900..0dbbc338e73 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -282,11 +282,12 @@ impl<'tcx> Stable<'tcx> for mir::CastKind {
     type T = stable_mir::mir::CastKind;
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
         use rustc_middle::mir::CastKind::*;
+        use rustc_middle::ty::adjustment::PointerCoercion;
         match self {
             PointerExposeProvenance => stable_mir::mir::CastKind::PointerExposeAddress,
             PointerWithExposedProvenance => stable_mir::mir::CastKind::PointerWithExposedProvenance,
-            PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
-            DynStar => stable_mir::mir::CastKind::DynStar,
+            PointerCoercion(PointerCoercion::DynStar, _) => stable_mir::mir::CastKind::DynStar,
+            PointerCoercion(c, _) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
             IntToInt => stable_mir::mir::CastKind::IntToInt,
             FloatToInt => stable_mir::mir::CastKind::FloatToInt,
             FloatToFloat => stable_mir::mir::CastKind::FloatToFloat,
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index e54ab1f7e24..ac9a0235762 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -119,6 +119,7 @@ impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion {
             }
             PointerCoercion::ArrayToPointer => stable_mir::mir::PointerCoercion::ArrayToPointer,
             PointerCoercion::Unsize => stable_mir::mir::PointerCoercion::Unsize,
+            PointerCoercion::DynStar => unreachable!("represented as `CastKind::DynStar` in smir"),
         }
     }
 }
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index 7c09fe1a085..ab9fc218d19 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -960,6 +960,7 @@ pub enum CastKind {
     PointerExposeAddress,
     PointerWithExposedProvenance,
     PointerCoercion(PointerCoercion),
+    // FIXME(smir-rename): change this to PointerCoercion(DynStar)
     DynStar,
     IntToInt,
     FloatToInt,
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index d9befb3c157..ce1895b7fb1 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -123,7 +123,7 @@ fn check_rvalue<'tcx>(
             | CastKind::FloatToFloat
             | CastKind::FnPtrToPtr
             | CastKind::PtrToPtr
-            | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer),
+            | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _),
             operand,
             _,
         ) => check_operand(tcx, operand, span, body, msrv),
@@ -131,12 +131,12 @@ fn check_rvalue<'tcx>(
             CastKind::PointerCoercion(
                 PointerCoercion::UnsafeFnPointer
                 | PointerCoercion::ClosureFnPointer(_)
-                | PointerCoercion::ReifyFnPointer,
+                | PointerCoercion::ReifyFnPointer, _
             ),
             _,
             _,
         ) => Err((span, "function pointer casts are not allowed in const fn".into())),
-        Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => {
+        Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize, _), op, cast_ty) => {
             let Some(pointee_ty) = cast_ty.builtin_deref(true) else {
                 // We cannot allow this for now.
                 return Err((span, "unsizing casts are only allowed for references right now".into()));
@@ -154,7 +154,7 @@ fn check_rvalue<'tcx>(
         Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
             Err((span, "casting pointers to ints is unstable in const fn".into()))
         },
-        Rvalue::Cast(CastKind::DynStar, _, _) => {
+        Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::DynStar, _), _, _) => {
             // FIXME(dyn-star)
             unimplemented!()
         },
diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr
index b40f83e8654..d0fd0e6fcc1 100644
--- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr
+++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr
@@ -2,7 +2,7 @@ error: Undefined Behavior: using vtable for `Baz` but `Bar` was expected
   --> tests/fail/dyn-upcast-trait-mismatch.rs:LL:CC
    |
 LL |         let _err = baz_fake as *const dyn Foo;
-   |                    ^^^^^^^^ using vtable for `Baz` but `Bar` was expected
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ using vtable for `Baz` but `Bar` was expected
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
index be636da4517..ae445ad9b91 100644
--- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
@@ -1,8 +1,8 @@
 // MIR for `address_of_reborrow` after SimplifyCfg-initial
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:8:5: 8:18, inferred_ty: *const [i32; 10]
-| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:10:5: 10:25, inferred_ty: *const dyn std::marker::Send
+| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10]
+| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send
 | 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
 | 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
 | 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
@@ -11,8 +11,8 @@
 | 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
 | 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
 | 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
-| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:19:5: 19:18, inferred_ty: *const [i32; 10]
-| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:21:5: 21:25, inferred_ty: *const dyn std::marker::Send
+| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10]
+| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send
 | 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
 | 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
 | 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
@@ -21,8 +21,8 @@
 | 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
 | 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
 | 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
-| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:29:5: 29:16, inferred_ty: *mut [i32; 10]
-| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:31:5: 31:23, inferred_ty: *mut dyn std::marker::Send
+| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10]
+| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send
 | 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
 | 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
 | 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
@@ -150,7 +150,7 @@ fn address_of_reborrow() -> () {
         StorageLive(_9);
         StorageLive(_10);
         _10 = &raw const (*_1);
-        _9 = move _10 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+        _9 = move _10 as *const dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
         StorageDead(_10);
         AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] });
         _8 = copy _9;
@@ -159,13 +159,13 @@ fn address_of_reborrow() -> () {
         StorageLive(_11);
         StorageLive(_12);
         _12 = &raw const (*_1);
-        _11 = move _12 as *const [i32] (PointerCoercion(Unsize));
+        _11 = move _12 as *const [i32] (PointerCoercion(Unsize, AsCast));
         StorageDead(_12);
         StorageDead(_11);
         StorageLive(_13);
         StorageLive(_14);
         _14 = &raw const (*_1);
-        _13 = move _14 as *const i32 (PointerCoercion(ArrayToPointer));
+        _13 = move _14 as *const i32 (PointerCoercion(ArrayToPointer, AsCast));
         StorageDead(_14);
         StorageDead(_13);
         StorageLive(_15);
@@ -179,14 +179,14 @@ fn address_of_reborrow() -> () {
         StorageLive(_17);
         StorageLive(_18);
         _18 = &raw const (*_1);
-        _17 = move _18 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+        _17 = move _18 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
         StorageDead(_18);
         FakeRead(ForLet(None), _17);
         AscribeUserType(_17, o, UserTypeProjection { base: UserType(7), projs: [] });
         StorageLive(_19);
         StorageLive(_20);
         _20 = &raw const (*_1);
-        _19 = move _20 as *const [i32] (PointerCoercion(Unsize));
+        _19 = move _20 as *const [i32] (PointerCoercion(Unsize, Implicit));
         StorageDead(_20);
         FakeRead(ForLet(None), _19);
         AscribeUserType(_19, o, UserTypeProjection { base: UserType(9), projs: [] });
@@ -204,7 +204,7 @@ fn address_of_reborrow() -> () {
         StorageLive(_25);
         StorageLive(_26);
         _26 = &raw const (*_3);
-        _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+        _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
         StorageDead(_26);
         AscribeUserType(_25, o, UserTypeProjection { base: UserType(11), projs: [] });
         _24 = copy _25;
@@ -213,7 +213,7 @@ fn address_of_reborrow() -> () {
         StorageLive(_27);
         StorageLive(_28);
         _28 = &raw const (*_3);
-        _27 = move _28 as *const [i32] (PointerCoercion(Unsize));
+        _27 = move _28 as *const [i32] (PointerCoercion(Unsize, AsCast));
         StorageDead(_28);
         StorageDead(_27);
         StorageLive(_29);
@@ -227,14 +227,14 @@ fn address_of_reborrow() -> () {
         StorageLive(_31);
         StorageLive(_32);
         _32 = &raw const (*_3);
-        _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+        _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
         StorageDead(_32);
         FakeRead(ForLet(None), _31);
         AscribeUserType(_31, o, UserTypeProjection { base: UserType(17), projs: [] });
         StorageLive(_33);
         StorageLive(_34);
         _34 = &raw const (*_3);
-        _33 = move _34 as *const [i32] (PointerCoercion(Unsize));
+        _33 = move _34 as *const [i32] (PointerCoercion(Unsize, Implicit));
         StorageDead(_34);
         FakeRead(ForLet(None), _33);
         AscribeUserType(_33, o, UserTypeProjection { base: UserType(19), projs: [] });
@@ -252,7 +252,7 @@ fn address_of_reborrow() -> () {
         StorageLive(_39);
         StorageLive(_40);
         _40 = &raw mut (*_3);
-        _39 = move _40 as *mut dyn std::marker::Send (PointerCoercion(Unsize));
+        _39 = move _40 as *mut dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
         StorageDead(_40);
         AscribeUserType(_39, o, UserTypeProjection { base: UserType(21), projs: [] });
         _38 = copy _39;
@@ -261,7 +261,7 @@ fn address_of_reborrow() -> () {
         StorageLive(_41);
         StorageLive(_42);
         _42 = &raw mut (*_3);
-        _41 = move _42 as *mut [i32] (PointerCoercion(Unsize));
+        _41 = move _42 as *mut [i32] (PointerCoercion(Unsize, AsCast));
         StorageDead(_42);
         StorageDead(_41);
         StorageLive(_43);
@@ -275,14 +275,14 @@ fn address_of_reborrow() -> () {
         StorageLive(_45);
         StorageLive(_46);
         _46 = &raw mut (*_3);
-        _45 = move _46 as *mut dyn std::marker::Send (PointerCoercion(Unsize));
+        _45 = move _46 as *mut dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
         StorageDead(_46);
         FakeRead(ForLet(None), _45);
         AscribeUserType(_45, o, UserTypeProjection { base: UserType(27), projs: [] });
         StorageLive(_47);
         StorageLive(_48);
         _48 = &raw mut (*_3);
-        _47 = move _48 as *mut [i32] (PointerCoercion(Unsize));
+        _47 = move _48 as *mut [i32] (PointerCoercion(Unsize, Implicit));
         StorageDead(_48);
         FakeRead(ForLet(None), _47);
         AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] });
diff --git a/tests/mir-opt/build_correct_coerce.main.built.after.mir b/tests/mir-opt/build_correct_coerce.main.built.after.mir
index 061174d69bb..583a5ecd227 100644
--- a/tests/mir-opt/build_correct_coerce.main.built.after.mir
+++ b/tests/mir-opt/build_correct_coerce.main.built.after.mir
@@ -9,7 +9,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);
-        _1 = foo as for<'a> fn(&'a (), &'a ()) (PointerCoercion(ReifyFnPointer));
+        _1 = foo as for<'a> fn(&'a (), &'a ()) (PointerCoercion(ReifyFnPointer, AsCast));
         FakeRead(ForLet(None), _1);
         _0 = const ();
         StorageDead(_1);
diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
index 296d71a319d..be972b62cbd 100644
--- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
+++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
@@ -39,7 +39,7 @@ fn main() -> () {
         StorageLive(_3);
         StorageLive(_4);
         _4 = copy _1;
-        _3 = move _4 as *const Test (PointerCoercion(MutToConstPointer));
+        _3 = move _4 as *const Test (PointerCoercion(MutToConstPointer, Implicit));
         StorageDead(_4);
         _2 = Test::x(move _3) -> [return: bb2, unwind: bb4];
     }
@@ -64,7 +64,7 @@ fn main() -> () {
         StorageLive(_11);
         StorageLive(_12);
         _12 = copy (*(*(*(*_5))));
-        _11 = move _12 as *const Test (PointerCoercion(MutToConstPointer));
+        _11 = move _12 as *const Test (PointerCoercion(MutToConstPointer, Implicit));
         StorageDead(_12);
         _10 = Test::x(move _11) -> [return: bb3, unwind: bb4];
     }
diff --git a/tests/mir-opt/building/storage_live_dead_in_statics.XXX.built.after.mir b/tests/mir-opt/building/storage_live_dead_in_statics.XXX.built.after.mir
index 683f63065f7..73ead005f8c 100644
--- a/tests/mir-opt/building/storage_live_dead_in_statics.XXX.built.after.mir
+++ b/tests/mir-opt/building/storage_live_dead_in_statics.XXX.built.after.mir
@@ -187,7 +187,7 @@ static XXX: &Foo = {
         StorageDead(_7);
         _5 = &_6;
         _4 = &(*_5);
-        _3 = move _4 as &[(u32, u32)] (PointerCoercion(Unsize));
+        _3 = move _4 as &[(u32, u32)] (PointerCoercion(Unsize, Implicit));
         StorageDead(_4);
         _2 = Foo { tup: const "hi", data: move _3 };
         StorageDead(_3);
diff --git a/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
index f412048b6ec..487f68a8d4d 100644
--- a/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
+++ b/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
@@ -22,7 +22,7 @@
 -         _2 = &_3;
 +         _6 = const BAR::promoted[0];
 +         _2 = &(*_6);
-          _1 = move _2 as &[&i32] (PointerCoercion(Unsize));
+          _1 = move _2 as &[&i32] (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_4);
           StorageDead(_2);
           _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2];
diff --git a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index bfefd2b8c95..0e4eed2c028 100644
--- a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -22,7 +22,7 @@
 -         _2 = &_3;
 +         _6 = const FOO::promoted[0];
 +         _2 = &(*_6);
-          _1 = move _2 as &[&i32] (PointerCoercion(Unsize));
+          _1 = move _2 as &[&i32] (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_4);
           StorageDead(_2);
           _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2];
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
index 52aa4da49ef..15d30140367 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
@@ -26,7 +26,7 @@
           _9 = const main::promoted[0];
           _3 = &(*_9);
           _2 = &raw const (*_3);
-          _1 = move _2 as *const [i32] (PointerCoercion(Unsize));
+          _1 = move _2 as *const [i32] (PointerCoercion(Unsize, Implicit));
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_5);
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
index 242ff0e664f..dd411d84f9f 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
@@ -26,7 +26,7 @@
           _9 = const main::promoted[0];
           _3 = &(*_9);
           _2 = &raw const (*_3);
-          _1 = move _2 as *const [i32] (PointerCoercion(Unsize));
+          _1 = move _2 as *const [i32] (PointerCoercion(Unsize, Implicit));
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_5);
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
index 52aa4da49ef..15d30140367 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
@@ -26,7 +26,7 @@
           _9 = const main::promoted[0];
           _3 = &(*_9);
           _2 = &raw const (*_3);
-          _1 = move _2 as *const [i32] (PointerCoercion(Unsize));
+          _1 = move _2 as *const [i32] (PointerCoercion(Unsize, Implicit));
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_5);
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
index 242ff0e664f..dd411d84f9f 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
@@ -26,7 +26,7 @@
           _9 = const main::promoted[0];
           _3 = &(*_9);
           _2 = &raw const (*_3);
-          _1 = move _2 as *const [i32] (PointerCoercion(Unsize));
+          _1 = move _2 as *const [i32] (PointerCoercion(Unsize, Implicit));
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_5);
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
index e5786bcf701..50a17326c2a 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
@@ -13,7 +13,7 @@
           StorageLive(_1);
           StorageLive(_2);
           StorageLive(_3);
-          _3 = main as fn() (PointerCoercion(ReifyFnPointer));
+          _3 = main as fn() (PointerCoercion(ReifyFnPointer, AsCast));
           _2 = move _3 as usize (PointerExposeProvenance);
           StorageDead(_3);
           _1 = move _2 as *const fn() (PointerWithExposedProvenance);
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.rs b/tests/mir-opt/const_prop/reify_fn_ptr.rs
index ffce4e97f5d..d56f21e586a 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.rs
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.rs
@@ -3,7 +3,7 @@
 
 fn main() {
     // CHECK-LABEL: fn main(
-    // CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer));
+    // CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer, AsCast));
     // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeProvenance);
     // CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerWithExposedProvenance);
     let _ = main as usize as *const fn();
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
index e834a5802c3..41ce94eda75 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
@@ -24,9 +24,9 @@
           _9 = const main::promoted[0];
           _4 = copy _9;
 -         _3 = copy _4;
--         _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+-         _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
 +         _3 = copy _9;
-+         _2 = copy _9 as &[u32] (PointerCoercion(Unsize));
++         _2 = copy _9 as &[u32] (PointerCoercion(Unsize, AsCast));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
index 55ffc501805..8cced96cd43 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
@@ -24,9 +24,9 @@
           _9 = const main::promoted[0];
           _4 = copy _9;
 -         _3 = copy _4;
--         _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+-         _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
 +         _3 = copy _9;
-+         _2 = copy _9 as &[u32] (PointerCoercion(Unsize));
++         _2 = copy _9 as &[u32] (PointerCoercion(Unsize, AsCast));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
index e834a5802c3..41ce94eda75 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
@@ -24,9 +24,9 @@
           _9 = const main::promoted[0];
           _4 = copy _9;
 -         _3 = copy _4;
--         _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+-         _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
 +         _3 = copy _9;
-+         _2 = copy _9 as &[u32] (PointerCoercion(Unsize));
++         _2 = copy _9 as &[u32] (PointerCoercion(Unsize, AsCast));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
index 55ffc501805..8cced96cd43 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
@@ -24,9 +24,9 @@
           _9 = const main::promoted[0];
           _4 = copy _9;
 -         _3 = copy _4;
--         _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+-         _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
 +         _3 = copy _9;
-+         _2 = copy _9 as &[u32] (PointerCoercion(Unsize));
++         _2 = copy _9 as &[u32] (PointerCoercion(Unsize, AsCast));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs
index 46604cfe1e0..ebd3c9e792d 100644
--- a/tests/mir-opt/const_prop/slice_len.rs
+++ b/tests/mir-opt/const_prop/slice_len.rs
@@ -7,7 +7,7 @@
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug a => [[a:_.*]];
-    // CHECK: [[slice:_.*]] = copy {{.*}} as &[u32] (PointerCoercion(Unsize));
+    // CHECK: [[slice:_.*]] = copy {{.*}} as &[u32] (PointerCoercion(Unsize, AsCast));
     // CHECK: assert(const true,
     // CHECK: [[a]] = const 2_u32;
     let a = (&[1u32, 2, 3] as &[u32])[1];
diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff
index f4411886f9a..6d967257df1 100644
--- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff
+++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff
@@ -47,7 +47,7 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = &_2;
-          _6 = move _7 as &[i32] (PointerCoercion(Unsize));
+          _6 = move _7 as &[i32] (PointerCoercion(Unsize, Implicit));
           StorageDead(_7);
           _5 = core::slice::<impl [i32]>::len(move _6) -> [return: bb1, unwind unreachable];
       }
diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff
index 833588aa4e9..3580c87c469 100644
--- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff
@@ -47,7 +47,7 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = &_2;
-          _6 = move _7 as &[i32] (PointerCoercion(Unsize));
+          _6 = move _7 as &[i32] (PointerCoercion(Unsize, Implicit));
           StorageDead(_7);
           _5 = core::slice::<impl [i32]>::len(move _6) -> [return: bb1, unwind continue];
       }
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
index c7870a7902b..e62fcb66e3a 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
@@ -89,7 +89,7 @@
 -         _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
 +         _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
           StorageDead(_5);
--         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
+-         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
 +         _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
           StorageDead(_4);
 -         _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
index f5de7a361bc..8183abd315a 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
@@ -93,7 +93,7 @@
 -         _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
 +         _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
           StorageDead(_5);
--         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
+-         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
 +         _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
           StorageDead(_4);
 -         _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
index 3b0bc6377da..4fa6ef29e06 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
@@ -89,7 +89,7 @@
 -         _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
 +         _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
           StorageDead(_5);
--         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
+-         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
 +         _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
           StorageDead(_4);
 -         _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
index 5dd7ad9a117..75329204563 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
@@ -93,7 +93,7 @@
 -         _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
 +         _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
           StorageDead(_5);
--         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
+-         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
 +         _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
           StorageDead(_4);
 -         _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
index 40632db667a..e71992316dc 100644
--- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff
@@ -32,7 +32,7 @@
           _14 = const main::promoted[0];
           _4 = copy _14;
           _3 = copy _4;
-          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
index 596b4ac9b1e..26de8595768 100644
--- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -32,7 +32,7 @@
           _14 = const main::promoted[0];
           _4 = copy _14;
           _3 = copy _4;
-          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
index 40632db667a..e71992316dc 100644
--- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff
@@ -32,7 +32,7 @@
           _14 = const main::promoted[0];
           _4 = copy _14;
           _3 = copy _4;
-          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
index 596b4ac9b1e..26de8595768 100644
--- a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -32,7 +32,7 @@
           _14 = const main::promoted[0];
           _4 = copy _14;
           _3 = copy _4;
-          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
diff --git a/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff b/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff
index 90654e05662..0d0477fe772 100644
--- a/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff
@@ -16,7 +16,7 @@
 +         nop;
           StorageLive(_3);
           _3 = &(*_1);
-          _2 = move _3 as &[i32] (PointerCoercion(Unsize));
+          _2 = move _3 as &[i32] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
           StorageLive(_4);
           _4 = &raw const (*_2);
diff --git a/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff b/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff
index 90654e05662..0d0477fe772 100644
--- a/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff
@@ -16,7 +16,7 @@
 +         nop;
           StorageLive(_3);
           _3 = &(*_1);
-          _2 = move _3 as &[i32] (PointerCoercion(Unsize));
+          _2 = move _3 as &[i32] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
           StorageLive(_4);
           _4 = &raw const (*_2);
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
index 292b812b50c..130b011630c 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
@@ -37,7 +37,7 @@
       bb0: {
 -         StorageLive(_1);
 +         nop;
-          _1 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer));
+          _1 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer, AsCast));
           StorageLive(_2);
           StorageLive(_3);
           _3 = copy _1;
@@ -50,7 +50,7 @@
           StorageDead(_2);
 -         StorageLive(_4);
 +         nop;
-          _4 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer));
+          _4 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer, AsCast));
           StorageLive(_5);
           StorageLive(_6);
           _6 = copy _4;
@@ -69,9 +69,9 @@
 +         nop;
           StorageLive(_9);
 -         _9 = copy _7;
--         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
+-         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
 +         _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -87,9 +87,9 @@
 +         nop;
           StorageLive(_13);
 -         _13 = copy _7;
--         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
+-         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
 +         _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
index a60d986132e..372a08d5473 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
@@ -37,7 +37,7 @@
       bb0: {
 -         StorageLive(_1);
 +         nop;
-          _1 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer));
+          _1 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer, AsCast));
           StorageLive(_2);
           StorageLive(_3);
           _3 = copy _1;
@@ -50,7 +50,7 @@
           StorageDead(_2);
 -         StorageLive(_4);
 +         nop;
-          _4 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer));
+          _4 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer, AsCast));
           StorageLive(_5);
           StorageLive(_6);
           _6 = copy _4;
@@ -69,9 +69,9 @@
 +         nop;
           StorageLive(_9);
 -         _9 = copy _7;
--         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
+-         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
 +         _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -87,9 +87,9 @@
 +         nop;
           StorageLive(_13);
 -         _13 = copy _7;
--         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
+-         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
 +         _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-abort.diff
index c58362e391c..43cd8ba7809 100644
--- a/tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-abort.diff
@@ -64,10 +64,10 @@
           _44 = const wide_ptr_provenance::promoted[1];
           _5 = &(*_44);
           _4 = &(*_5);
-          _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_4);
           _2 = &raw const (*_3);
--         _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_2);
 +         _1 = copy _2;
 +         nop;
@@ -82,10 +82,10 @@
           _43 = const wide_ptr_provenance::promoted[0];
           _11 = &(*_43);
           _10 = &(*_11);
-          _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_10);
           _8 = &raw const (*_9);
--         _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_8);
 +         _7 = copy _8;
 +         nop;
@@ -99,7 +99,7 @@
           StorageLive(_16);
           StorageLive(_17);
 -         _17 = copy _7;
--         _16 = move _17 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _16 = move _17 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _17 = copy _8;
 +         _16 = copy _8;
           StorageDead(_17);
@@ -121,7 +121,7 @@
           StorageLive(_21);
           StorageLive(_22);
 -         _22 = copy _7;
--         _21 = move _22 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _21 = move _22 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _22 = copy _8;
 +         _21 = copy _8;
           StorageDead(_22);
@@ -143,7 +143,7 @@
           StorageLive(_26);
           StorageLive(_27);
 -         _27 = copy _7;
--         _26 = move _27 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _26 = move _27 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _27 = copy _8;
 +         _26 = copy _8;
           StorageDead(_27);
@@ -165,7 +165,7 @@
           StorageLive(_31);
           StorageLive(_32);
 -         _32 = copy _7;
--         _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _32 = copy _8;
 +         _31 = copy _8;
           StorageDead(_32);
@@ -187,7 +187,7 @@
           StorageLive(_36);
           StorageLive(_37);
 -         _37 = copy _7;
--         _36 = move _37 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _36 = move _37 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _37 = copy _8;
 +         _36 = copy _8;
           StorageDead(_37);
@@ -209,7 +209,7 @@
           StorageLive(_41);
           StorageLive(_42);
 -         _42 = copy _7;
--         _41 = move _42 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _41 = move _42 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _42 = copy _8;
 +         _41 = copy _8;
           StorageDead(_42);
diff --git a/tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-unwind.diff
index b29ee862c81..49cca20153b 100644
--- a/tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.wide_ptr_provenance.GVN.panic-unwind.diff
@@ -64,10 +64,10 @@
           _44 = const wide_ptr_provenance::promoted[1];
           _5 = &(*_44);
           _4 = &(*_5);
-          _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_4);
           _2 = &raw const (*_3);
--         _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_2);
 +         _1 = copy _2;
 +         nop;
@@ -82,10 +82,10 @@
           _43 = const wide_ptr_provenance::promoted[0];
           _11 = &(*_43);
           _10 = &(*_11);
-          _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_10);
           _8 = &raw const (*_9);
--         _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_8);
 +         _7 = copy _8;
 +         nop;
@@ -99,7 +99,7 @@
           StorageLive(_16);
           StorageLive(_17);
 -         _17 = copy _7;
--         _16 = move _17 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _16 = move _17 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _17 = copy _8;
 +         _16 = copy _8;
           StorageDead(_17);
@@ -121,7 +121,7 @@
           StorageLive(_21);
           StorageLive(_22);
 -         _22 = copy _7;
--         _21 = move _22 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _21 = move _22 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _22 = copy _8;
 +         _21 = copy _8;
           StorageDead(_22);
@@ -143,7 +143,7 @@
           StorageLive(_26);
           StorageLive(_27);
 -         _27 = copy _7;
--         _26 = move _27 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _26 = move _27 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _27 = copy _8;
 +         _26 = copy _8;
           StorageDead(_27);
@@ -165,7 +165,7 @@
           StorageLive(_31);
           StorageLive(_32);
 -         _32 = copy _7;
--         _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _32 = copy _8;
 +         _31 = copy _8;
           StorageDead(_32);
@@ -187,7 +187,7 @@
           StorageLive(_36);
           StorageLive(_37);
 -         _37 = copy _7;
--         _36 = move _37 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _36 = move _37 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _37 = copy _8;
 +         _36 = copy _8;
           StorageDead(_37);
@@ -209,7 +209,7 @@
           StorageLive(_41);
           StorageLive(_42);
 -         _42 = copy _7;
--         _41 = move _42 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _41 = move _42 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _42 = copy _8;
 +         _41 = copy _8;
           StorageDead(_42);
diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff
index f4c38b7ab07..6b6152c1117 100644
--- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff
@@ -86,10 +86,10 @@
 -         _7 = &(*_1)[_8];
 +         _7 = &(*_1)[0 of 1];
           _6 = &(*_7);
-          _5 = move _6 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          _5 = move _6 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_6);
           _4 = &raw const (*_5);
--         _3 = move _4 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _3 = move _4 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_4);
 +         _3 = copy _4;
 +         nop;
@@ -115,10 +115,10 @@
 -         _15 = &(*_1)[_16];
 +         _15 = &(*_1)[1 of 2];
           _14 = &(*_15);
-          _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_14);
           _12 = &raw const (*_13);
--         _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_12);
 +         _11 = copy _12;
 +         nop;
@@ -132,7 +132,7 @@
           StorageLive(_22);
           StorageLive(_23);
 -         _23 = copy _11;
--         _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _23 = copy _12;
 +         _22 = copy _12;
           StorageDead(_23);
@@ -154,7 +154,7 @@
           StorageLive(_27);
           StorageLive(_28);
 -         _28 = copy _11;
--         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _28 = copy _12;
 +         _27 = copy _12;
           StorageDead(_28);
@@ -176,7 +176,7 @@
           StorageLive(_32);
           StorageLive(_33);
 -         _33 = copy _11;
--         _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _33 = copy _12;
 +         _32 = copy _12;
           StorageDead(_33);
@@ -198,7 +198,7 @@
           StorageLive(_37);
           StorageLive(_38);
 -         _38 = copy _11;
--         _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _38 = copy _12;
 +         _37 = copy _12;
           StorageDead(_38);
@@ -220,7 +220,7 @@
           StorageLive(_42);
           StorageLive(_43);
 -         _43 = copy _11;
--         _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _43 = copy _12;
 +         _42 = copy _12;
           StorageDead(_43);
@@ -242,7 +242,7 @@
           StorageLive(_47);
           StorageLive(_48);
 -         _48 = copy _11;
--         _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _48 = copy _12;
 +         _47 = copy _12;
           StorageDead(_48);
diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff
index 03f2d129a9b..093c1ec6ce3 100644
--- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff
@@ -86,10 +86,10 @@
 -         _7 = &(*_1)[_8];
 +         _7 = &(*_1)[0 of 1];
           _6 = &(*_7);
-          _5 = move _6 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          _5 = move _6 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_6);
           _4 = &raw const (*_5);
--         _3 = move _4 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _3 = move _4 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_4);
 +         _3 = copy _4;
 +         nop;
@@ -115,10 +115,10 @@
 -         _15 = &(*_1)[_16];
 +         _15 = &(*_1)[1 of 2];
           _14 = &(*_15);
-          _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
           StorageDead(_14);
           _12 = &raw const (*_13);
--         _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_12);
 +         _11 = copy _12;
 +         nop;
@@ -132,7 +132,7 @@
           StorageLive(_22);
           StorageLive(_23);
 -         _23 = copy _11;
--         _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _23 = copy _12;
 +         _22 = copy _12;
           StorageDead(_23);
@@ -154,7 +154,7 @@
           StorageLive(_27);
           StorageLive(_28);
 -         _28 = copy _11;
--         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _28 = copy _12;
 +         _27 = copy _12;
           StorageDead(_28);
@@ -176,7 +176,7 @@
           StorageLive(_32);
           StorageLive(_33);
 -         _33 = copy _11;
--         _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _33 = copy _12;
 +         _32 = copy _12;
           StorageDead(_33);
@@ -198,7 +198,7 @@
           StorageLive(_37);
           StorageLive(_38);
 -         _38 = copy _11;
--         _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _38 = copy _12;
 +         _37 = copy _12;
           StorageDead(_38);
@@ -220,7 +220,7 @@
           StorageLive(_42);
           StorageLive(_43);
 -         _43 = copy _11;
--         _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _43 = copy _12;
 +         _42 = copy _12;
           StorageDead(_43);
@@ -242,7 +242,7 @@
           StorageLive(_47);
           StorageLive(_48);
 -         _48 = copy _11;
--         _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+-         _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
 +         _48 = copy _12;
 +         _47 = copy _12;
           StorageDead(_48);
diff --git a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff
index 2d64d49ce5c..df79001ce75 100644
--- a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff
@@ -31,7 +31,7 @@
           _4 = copy _2;
 -         _0 = try_execute_query::<<Q as Query>::C>(move _4) -> [return: bb2, unwind unreachable];
 +         StorageLive(_5);
-+         _5 = copy _4 as &dyn Cache<V = <Q as Query>::V> (PointerCoercion(Unsize));
++         _5 = copy _4 as &dyn Cache<V = <Q as Query>::V> (PointerCoercion(Unsize, Implicit));
 +         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _5) -> [return: bb2, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff
index c5e9654e19c..014f950940c 100644
--- a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff
@@ -31,7 +31,7 @@
           _4 = copy _2;
 -         _0 = try_execute_query::<<Q as Query>::C>(move _4) -> [return: bb2, unwind continue];
 +         StorageLive(_5);
-+         _5 = copy _4 as &dyn Cache<V = <Q as Query>::V> (PointerCoercion(Unsize));
++         _5 = copy _4 as &dyn Cache<V = <Q as Query>::V> (PointerCoercion(Unsize, Implicit));
 +         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _5) -> [return: bb2, unwind continue];
       }
   
diff --git a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff
index f02ca623317..64d12461e8d 100644
--- a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff
@@ -14,7 +14,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = copy _1;
-          _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (PointerCoercion(Unsize));
+          _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
 -         _0 = mk_cycle::<<C as Cache>::V>(move _2) -> [return: bb1, unwind unreachable];
 +         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _2) -> [return: bb1, unwind unreachable];
diff --git a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff
index 31080dff4de..21791cb0d2a 100644
--- a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff
@@ -14,7 +14,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = copy _1;
-          _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (PointerCoercion(Unsize));
+          _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
 -         _0 = mk_cycle::<<C as Cache>::V>(move _2) -> [return: bb1, unwind continue];
 +         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _2) -> [return: bb1, unwind continue];
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
index f03691ad673..c02bab3524b 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
@@ -26,7 +26,7 @@
           StorageLive(_4);
           _4 = [copy _1, copy _1, copy _1];
           _3 = &_4;
-          _2 = copy _3 as &[T] (PointerCoercion(Unsize));
+          _2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
           nop;
           nop;
           goto -> bb2;
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
index 633e5c740a1..49be042588c 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
@@ -26,7 +26,7 @@
           StorageLive(_4);
           _4 = [copy _1, copy _1, copy _1];
           _3 = &_4;
-          _2 = copy _3 as &[T] (PointerCoercion(Unsize));
+          _2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
           nop;
           nop;
           goto -> bb2;
diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff
index 8223cbbb412..f052c8f63dc 100644
--- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff
@@ -24,7 +24,7 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
-          _6 = move _7 as &[u8] (PointerCoercion(Unsize));
+          _6 = move _7 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_7);
 -         _5 = PtrMetadata(move _6);
 +         _5 = const N;
diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff
index d8f33accbc0..3299e300431 100644
--- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff
@@ -24,7 +24,7 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
-          _6 = move _7 as &[u8] (PointerCoercion(Unsize));
+          _6 = move _7 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_7);
 -         _5 = PtrMetadata(move _6);
 +         _5 = const N;
diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff
index 1cb9963c00e..329eb80b3c4 100644
--- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff
@@ -27,7 +27,7 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
-          _6 = move _7 as &[u8] (PointerCoercion(Unsize));
+          _6 = move _7 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_7);
 -         _5 = PtrMetadata(move _6);
 +         _5 = const N;
diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff
index fa4e11ed201..ab007e133ec 100644
--- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff
@@ -27,7 +27,7 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
-          _6 = move _7 as &[u8] (PointerCoercion(Unsize));
+          _6 = move _7 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_7);
 -         _5 = PtrMetadata(move _6);
 +         _5 = const N;
diff --git a/tests/mir-opt/lower_array_len.array_len.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len.GVN.panic-abort.diff
index 9c1b9a708c5..369bd2f4732 100644
--- a/tests/mir-opt/lower_array_len.array_len.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_len.GVN.panic-abort.diff
@@ -11,7 +11,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = &(*_1);
-          _2 = move _3 as &[u8] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
 -         _0 = PtrMetadata(move _2);
 +         _0 = const N;
diff --git a/tests/mir-opt/lower_array_len.array_len.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len.GVN.panic-unwind.diff
index 9c1b9a708c5..369bd2f4732 100644
--- a/tests/mir-opt/lower_array_len.array_len.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_len.GVN.panic-unwind.diff
@@ -11,7 +11,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = &(*_1);
-          _2 = move _3 as &[u8] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
 -         _0 = PtrMetadata(move _2);
 +         _0 = const N;
diff --git a/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-abort.diff
index 97fa503ac2e..d9c289bf58a 100644
--- a/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-abort.diff
@@ -11,7 +11,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = &_1;
-          _2 = move _3 as &[u8] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
 -         _0 = PtrMetadata(move _2);
 +         _0 = const N;
diff --git a/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-unwind.diff
index 97fa503ac2e..d9c289bf58a 100644
--- a/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_len_by_value.GVN.panic-unwind.diff
@@ -11,7 +11,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = &_1;
-          _2 = move _3 as &[u8] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
 -         _0 = PtrMetadata(move _2);
 +         _0 = const N;
diff --git a/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff
index b5e8b66813a..180a7db0297 100644
--- a/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff
@@ -24,7 +24,7 @@
           StorageLive(_4);
           _4 = &_1;
           _3 = &(*_4);
-          _2 = move _3 as &[u8] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
           StorageDead(_4);
           StorageLive(_5);
diff --git a/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff
index b5e8b66813a..180a7db0297 100644
--- a/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff
@@ -24,7 +24,7 @@
           StorageLive(_4);
           _4 = &_1;
           _3 = &(*_4);
-          _2 = move _3 as &[u8] (PointerCoercion(Unsize));
+          _2 = move _3 as &[u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
           StorageDead(_4);
           StorageLive(_5);
diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff
index 0299c6acd80..49964f8b49e 100644
--- a/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff
@@ -23,7 +23,7 @@
           StorageLive(_4);
           _4 = &mut _1;
           _3 = &mut (*_4);
-          _2 = move _3 as &mut [u8] (PointerCoercion(Unsize));
+          _2 = move _3 as &mut [u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
           StorageDead(_4);
           StorageLive(_5);
diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff
index 0299c6acd80..49964f8b49e 100644
--- a/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff
@@ -23,7 +23,7 @@
           StorageLive(_4);
           _4 = &mut _1;
           _3 = &mut (*_4);
-          _2 = move _3 as &mut [u8] (PointerCoercion(Unsize));
+          _2 = move _3 as &mut [u8] (PointerCoercion(Unsize, Implicit));
           StorageDead(_3);
           StorageDead(_4);
           StorageLive(_5);
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 6cac8b109ee..87fbcca9177 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
@@ -93,7 +93,7 @@
       bb5: {
           StorageLive(_15);
           _16 = &_13;
-          _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize));
+          _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit));
           _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable;
       }
   
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 10fde25e317..13258c17160 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
@@ -93,7 +93,7 @@
       bb5: {
           StorageLive(_15);
           _16 = &_13;
-          _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize));
+          _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit));
           _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable;
       }
   
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
index d0f454e4569..cca2b3ae188 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
@@ -105,7 +105,7 @@ fn main() -> () {
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Safe)));
+        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Safe), Implicit));
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
index 685277d7a53..bcd3a47ac04 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
@@ -105,7 +105,7 @@ fn main() -> () {
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Safe)));
+        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Safe), Implicit));
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);
diff --git a/tests/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff
index 7cc5e335cb0..37a669d72b8 100644
--- a/tests/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff
@@ -21,7 +21,7 @@
 -         StorageLive(_4);
 -         _4 = &_1;
 -         _3 = &(*_4);
--         _2 = move _3 as &[u8] (PointerCoercion(Unsize));
+-         _2 = move _3 as &[u8] (PointerCoercion(Unsize, Implicit));
 -         StorageDead(_3);
 -         StorageDead(_4);
 -         StorageDead(_2);
diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
index 478dacc3276..a1df868cde0 100644
--- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
@@ -61,7 +61,7 @@
       }
   
       bb1: {
-          _3 = move _4 as std::boxed::Box<dyn std::fmt::Display> (PointerCoercion(Unsize));
+          _3 = move _4 as std::boxed::Box<dyn std::fmt::Display> (PointerCoercion(Unsize, Implicit));
           StorageDead(_4);
           _2 = Result::<Box<dyn std::fmt::Display>, <T as Err>::Err>::Ok(move _3);
           StorageDead(_3);
diff --git a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr
index b3bf2f924fc..89b15a7a659 100644
--- a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr
+++ b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr
@@ -75,7 +75,7 @@ LL |     reg.register_univ(Box::new(CapturePass::new(&reg.sess_mut)));
    |     ^^^^^^^^^^^^^^^^^^-----------------------------------------^
    |     |                 |                         |
    |     |                 |                         immutable borrow occurs here
-   |     |                 cast requires that `reg.sess_mut` is borrowed for `'a`
+   |     |                 coercion requires that `reg.sess_mut` is borrowed for `'a`
    |     mutable borrow occurs here
    |
    = note: due to object lifetime defaults, `Box<dyn for<'b> LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>`
@@ -119,7 +119,7 @@ LL |     reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
    |     ^^^^^^^^^^^^^^^^^^-------------------------------------------------^
    |     |                 |                             |
    |     |                 |                             first mutable borrow occurs here
-   |     |                 cast requires that `reg.sess_mut` is borrowed for `'a`
+   |     |                 coercion requires that `reg.sess_mut` is borrowed for `'a`
    |     second mutable borrow occurs here
    |
    = note: due to object lifetime defaults, `Box<dyn for<'b> LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>`
diff --git a/tests/ui/cast/casts-differing-anon.stderr b/tests/ui/cast/casts-differing-anon.stderr
index 8ddd97137c3..fc4882d2d27 100644
--- a/tests/ui/cast/casts-differing-anon.stderr
+++ b/tests/ui/cast/casts-differing-anon.stderr
@@ -4,7 +4,7 @@ error[E0606]: casting `*mut impl Debug + ?Sized` as `*mut impl Debug + ?Sized` i
 LL |     b_raw = f_raw as *mut _;
    |             ^^^^^^^^^^^^^^^
    |
-   = note: vtable kinds may not match
+   = note: the pointers may have different metadata
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.rs b/tests/ui/cast/ptr-to-trait-obj-different-args.rs
index c6038cfe864..bb103f789f5 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-args.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-different-args.rs
@@ -18,14 +18,14 @@ fn main() {
     let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
 
     let x: *const dyn Trait<X> = &();
-    let y: *const dyn Trait<Y> = x as _; //~ error: mismatched types
+    let y: *const dyn Trait<Y> = x as _; //~ error: casting `*const dyn Trait<X>` as `*const dyn Trait<Y>` is invalid
 
     _ = (b, y);
 }
 
 fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
-    let _: *const dyn Trait<T> = x as _; //~ error: mismatched types
-    let _: *const dyn Trait<X> = t as _; //~ error: mismatched types
+    let _: *const dyn Trait<T> = x as _; //~ error: casting `*const (dyn Trait<X> + 'static)` as `*const dyn Trait<T>` is invalid
+    let _: *const dyn Trait<X> = t as _; //~ error: casting `*const (dyn Trait<T> + 'static)` as `*const dyn Trait<X>` is invalid
 }
 
 trait Assocked {
@@ -33,5 +33,5 @@ trait Assocked {
 }
 
 fn change_assoc(x: *mut dyn Assocked<Assoc = u8>) -> *mut dyn Assocked<Assoc = u32> {
-    x as _ //~ error: mismatched types
+    x as _ //~ error: casting `*mut (dyn Assocked<Assoc = u8> + 'static)` as `*mut (dyn Assocked<Assoc = u32> + 'static)` is invalid
 }
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
index 8e60ca42f0a..e571a43959f 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
@@ -4,53 +4,40 @@ error[E0606]: casting `*const dyn A` as `*const dyn B` is invalid
 LL |     let b: *const dyn B = a as _;
    |                           ^^^^^^
    |
-   = note: vtable kinds may not match
+   = note: the trait objects may have different vtables
 
-error[E0308]: mismatched types
+error[E0606]: casting `*const dyn Trait<X>` as `*const dyn Trait<Y>` is invalid
   --> $DIR/ptr-to-trait-obj-different-args.rs:21:34
    |
 LL |     let y: *const dyn Trait<Y> = x as _;
-   |                                  ^^^^^^ expected `X`, found `Y`
+   |                                  ^^^^^^
    |
-   = note: expected trait object `dyn Trait<X>`
-              found trait object `dyn Trait<Y>`
-   = help: `dyn Trait<Y>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
+   = note: the trait objects may have different vtables
 
-error[E0308]: mismatched types
+error[E0606]: casting `*const (dyn Trait<X> + 'static)` as `*const dyn Trait<T>` is invalid
   --> $DIR/ptr-to-trait-obj-different-args.rs:27:34
    |
-LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
-   |            - found this type parameter
 LL |     let _: *const dyn Trait<T> = x as _;
-   |                                  ^^^^^^ expected `X`, found type parameter `T`
+   |                                  ^^^^^^
    |
-   = note: expected trait object `dyn Trait<X>`
-              found trait object `dyn Trait<T>`
-   = help: `dyn Trait<T>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
+   = note: the trait objects may have different vtables
 
-error[E0308]: mismatched types
+error[E0606]: casting `*const (dyn Trait<T> + 'static)` as `*const dyn Trait<X>` is invalid
   --> $DIR/ptr-to-trait-obj-different-args.rs:28:34
    |
-LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
-   |            - expected this type parameter
-LL |     let _: *const dyn Trait<T> = x as _;
 LL |     let _: *const dyn Trait<X> = t as _;
-   |                                  ^^^^^^ expected type parameter `T`, found `X`
+   |                                  ^^^^^^
    |
-   = note: expected trait object `dyn Trait<T>`
-              found trait object `dyn Trait<X>`
-   = help: `dyn Trait<X>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
+   = note: the trait objects may have different vtables
 
-error[E0308]: mismatched types
+error[E0606]: casting `*mut (dyn Assocked<Assoc = u8> + 'static)` as `*mut (dyn Assocked<Assoc = u32> + 'static)` is invalid
   --> $DIR/ptr-to-trait-obj-different-args.rs:36:5
    |
 LL |     x as _
-   |     ^^^^^^ expected `u8`, found `u32`
+   |     ^^^^^^
    |
-   = note: expected trait object `dyn Assocked<Assoc = u8>`
-              found trait object `dyn Assocked<Assoc = u32>`
+   = note: the trait objects may have different vtables
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0308, E0606.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0606`.
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr
index 5a5b4bfcacf..4e43d3b93fa 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr
@@ -1,11 +1,11 @@
 error: lifetime may not live long enough
-  --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17
+  --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:27
    |
 LL | fn m<'a>() {
    |      -- lifetime `'a` defined here
 LL |     let unsend: *const dyn Cat<'a> = &();
 LL |     let _send = unsend as *const S<dyn Cat<'static>>;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
    |
    = note: requirement occurs because of the type `S<dyn Cat<'_>>`, which makes the generic argument `dyn Cat<'_>` invariant
    = note: the struct `S<T>` is invariant over the parameter `T`
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr
index 5a5b4bfcacf..4e43d3b93fa 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr
@@ -1,11 +1,11 @@
 error: lifetime may not live long enough
-  --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17
+  --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:27
    |
 LL | fn m<'a>() {
    |      -- lifetime `'a` defined here
 LL |     let unsend: *const dyn Cat<'a> = &();
 LL |     let _send = unsend as *const S<dyn Cat<'static>>;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
    |
    = note: requirement occurs because of the type `S<dyn Cat<'_>>`, which makes the generic argument `dyn Cat<'_>` invariant
    = note: the struct `S<T>` is invariant over the parameter `T`
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
index 01c347bfae5..d7c6c50d8be 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
@@ -33,5 +33,10 @@ fn change_assoc_1<'a, 'b>(
            //~| error: lifetime may not live long enough
 }
 
+// This tests the default borrow check error, without the special casing for return values.
+fn require_static(_: *const dyn Trait<'static>) {}
+fn extend_to_static<'a>(ptr: *const dyn Trait<'a>) {
+    require_static(ptr as _) //~ error: lifetime may not live long enough
+}
 
 fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
index 7044e4dec1f..6069f4f3b55 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
@@ -132,5 +132,13 @@ help: `'b` and `'a` must be the same: replace one with the other
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 8 previous errors
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:39:20
+   |
+LL | fn extend_to_static<'a>(ptr: *const dyn Trait<'a>) {
+   |                     -- lifetime `'a` defined here
+LL |     require_static(ptr as _)
+   |                    ^^^^^^^^ cast requires that `'a` must outlive `'static`
+
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr
index 38c8ba96bc5..5687aba625f 100644
--- a/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr
@@ -4,7 +4,7 @@ error[E0606]: casting `*const (dyn Sub + 'static)` as `*const Wrapper<dyn Super>
 LL |     ptr as _
    |     ^^^^^^^^
    |
-   = note: vtable kinds may not match
+   = note: the trait objects may have different vtables
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dropck/dropck_trait_cycle_checked.stderr b/tests/ui/dropck/dropck_trait_cycle_checked.stderr
index 63fd07a9163..f32736f1a67 100644
--- a/tests/ui/dropck/dropck_trait_cycle_checked.stderr
+++ b/tests/ui/dropck/dropck_trait_cycle_checked.stderr
@@ -2,7 +2,7 @@ error[E0597]: `o2` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:111:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |              -- binding `o2` declared here                          -------- cast requires that `o2` is borrowed for `'static`
+   |              -- binding `o2` declared here                          -------- coercion requires that `o2` is borrowed for `'static`
 LL |     o1.set0(&o2);
    |             ^^^ borrowed value does not live long enough
 ...
@@ -15,7 +15,7 @@ error[E0597]: `o3` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:112:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |                  -- binding `o3` declared here                      -------- cast requires that `o3` is borrowed for `'static`
+   |                  -- binding `o3` declared here                      -------- coercion requires that `o3` is borrowed for `'static`
 LL |     o1.set0(&o2);
 LL |     o1.set1(&o3);
    |             ^^^ borrowed value does not live long enough
@@ -29,7 +29,7 @@ error[E0597]: `o2` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:113:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |              -- binding `o2` declared here                                    -------- cast requires that `o2` is borrowed for `'static`
+   |              -- binding `o2` declared here                                    -------- coercion requires that `o2` is borrowed for `'static`
 ...
 LL |     o2.set0(&o2);
    |             ^^^ borrowed value does not live long enough
@@ -43,7 +43,7 @@ error[E0597]: `o3` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:114:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |                  -- binding `o3` declared here                                -------- cast requires that `o3` is borrowed for `'static`
+   |                  -- binding `o3` declared here                                -------- coercion requires that `o3` is borrowed for `'static`
 ...
 LL |     o2.set1(&o3);
    |             ^^^ borrowed value does not live long enough
@@ -57,7 +57,7 @@ error[E0597]: `o1` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:115:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |          -- binding `o1` declared here                                                  -------- cast requires that `o1` is borrowed for `'static`
+   |          -- binding `o1` declared here                                                  -------- coercion requires that `o1` is borrowed for `'static`
 ...
 LL |     o3.set0(&o1);
    |             ^^^ borrowed value does not live long enough
@@ -71,7 +71,7 @@ error[E0597]: `o2` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:116:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |              -- binding `o2` declared here                                              -------- cast requires that `o2` is borrowed for `'static`
+   |              -- binding `o2` declared here                                              -------- coercion requires that `o2` is borrowed for `'static`
 ...
 LL |     o3.set1(&o2);
    |             ^^^ borrowed value does not live long enough
diff --git a/tests/ui/dyn-star/dyn-to-rigid.rs b/tests/ui/dyn-star/dyn-to-rigid.rs
index e80ee15902e..dc33e288f24 100644
--- a/tests/ui/dyn-star/dyn-to-rigid.rs
+++ b/tests/ui/dyn-star/dyn-to-rigid.rs
@@ -5,7 +5,7 @@ trait Tr {}
 
 fn f(x: dyn* Tr) -> usize {
     x as usize
-    //~^ ERROR casting `(dyn* Tr + 'static)` as `usize` is invalid
+    //~^ ERROR non-primitive cast: `(dyn* Tr + 'static)` as `usize`
 }
 
 fn main() {}
diff --git a/tests/ui/dyn-star/dyn-to-rigid.stderr b/tests/ui/dyn-star/dyn-to-rigid.stderr
index b198c5245de..49b8f268aa4 100644
--- a/tests/ui/dyn-star/dyn-to-rigid.stderr
+++ b/tests/ui/dyn-star/dyn-to-rigid.stderr
@@ -1,9 +1,9 @@
-error[E0606]: casting `(dyn* Tr + 'static)` as `usize` is invalid
+error[E0605]: non-primitive cast: `(dyn* Tr + 'static)` as `usize`
   --> $DIR/dyn-to-rigid.rs:7:5
    |
 LL |     x as usize
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0606`.
+For more information about this error, try `rustc --explain E0605`.
diff --git a/tests/ui/dyn-star/enum-cast.rs b/tests/ui/dyn-star/enum-cast.rs
new file mode 100644
index 00000000000..6e895e9527a
--- /dev/null
+++ b/tests/ui/dyn-star/enum-cast.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+
+// This used to ICE, because the compiler confused a pointer-like to dyn* coercion
+// with a c-like enum to integer cast.
+
+#![feature(dyn_star)]
+#![expect(incomplete_features)]
+
+enum E {
+    Num(usize),
+}
+
+trait Trait {}
+impl Trait for E {}
+
+fn main() {
+    let _ = E::Num(42) as dyn* Trait;
+}
diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr
index aad020e4ec9..5892596dc6a 100644
--- a/tests/ui/kindck/kindck-impl-type-params.stderr
+++ b/tests/ui/kindck/kindck-impl-type-params.stderr
@@ -112,13 +112,13 @@ LL |     struct Foo; // does not impl Copy
    |
 
 error: lifetime may not live long enough
-  --> $DIR/kindck-impl-type-params.rs:30:13
+  --> $DIR/kindck-impl-type-params.rs:30:19
    |
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
 LL |     let t: S<&'a isize> = S(marker::PhantomData);
 LL |     let a = &t as &dyn Gettable<&'a isize>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
index 598f1424191..e4cd54ac337 100644
--- a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
+++ b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
@@ -7,7 +7,7 @@ LL |     let refcell = RefCell::new(&mut foo);
    |                                ^^^^^^^^ borrowed value does not live long enough
 LL |
 LL |     let read = &refcell as &RefCell<dyn Read>;
-   |                -------- cast requires that `foo` is borrowed for `'static`
+   |                ------------------------------ cast requires that `foo` is borrowed for `'static`
 ...
 LL | }
    |  - `foo` dropped here while still borrowed
@@ -19,7 +19,7 @@ LL | fn inner(mut foo: &[u8]) {
    |                   - let's call the lifetime of this reference `'1`
 ...
 LL |     let read = &refcell as &RefCell<dyn Read>;
-   |                ^^^^^^^^ cast requires that `'1` must outlive `'static`
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr
index 142a52aef13..3d12ba9899b 100644
--- a/tests/ui/mismatched_types/cast-rfc0401.stderr
+++ b/tests/ui/mismatched_types/cast-rfc0401.stderr
@@ -4,7 +4,7 @@ error[E0606]: casting `*const U` as `*const V` is invalid
 LL |     u as *const V
    |     ^^^^^^^^^^^^^
    |
-   = note: vtable kinds may not match
+   = note: the pointers may have different metadata
 
 error[E0606]: casting `*const U` as `*const str` is invalid
   --> $DIR/cast-rfc0401.rs:8:5
@@ -12,7 +12,7 @@ error[E0606]: casting `*const U` as `*const str` is invalid
 LL |     u as *const str
    |     ^^^^^^^^^^^^^^^
    |
-   = note: vtable kinds may not match
+   = note: the pointers may have different metadata
 
 error[E0609]: no field `f` on type `fn() {main}`
   --> $DIR/cast-rfc0401.rs:65:18
@@ -208,7 +208,7 @@ error[E0606]: casting `*const dyn Foo` as `*const [u16]` is invalid
 LL |     let _ = cf as *const [u16];
    |             ^^^^^^^^^^^^^^^^^^
    |
-   = note: vtable kinds may not match
+   = note: the pointers have different metadata
 
 error[E0606]: casting `*const dyn Foo` as `*const dyn Bar` is invalid
   --> $DIR/cast-rfc0401.rs:69:13
@@ -216,7 +216,7 @@ error[E0606]: casting `*const dyn Foo` as `*const dyn Bar` is invalid
 LL |     let _ = cf as *const dyn Bar;
    |             ^^^^^^^^^^^^^^^^^^^^
    |
-   = note: vtable kinds may not match
+   = note: the trait objects may have different vtables
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
   --> $DIR/cast-rfc0401.rs:53:13
diff --git a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr
index 92298c6617f..a454ed26568 100644
--- a/tests/ui/nll/issue-54779-anon-static-lifetime.stderr
+++ b/tests/ui/nll/issue-54779-anon-static-lifetime.stderr
@@ -5,7 +5,7 @@ LL |         cx: &dyn DebugContext,
    |             - let's call the lifetime of this reference `'1`
 ...
 LL |         bar.debug_with(cx);
-   |                        ^^ cast requires that `'1` must outlive `'static`
+   |                        ^^ coercion requires that `'1` must outlive `'static`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/nll/user-annotations/cast_static_lifetime.stderr b/tests/ui/nll/user-annotations/cast_static_lifetime.stderr
index 35eec233ed5..efd14fe875d 100644
--- a/tests/ui/nll/user-annotations/cast_static_lifetime.stderr
+++ b/tests/ui/nll/user-annotations/cast_static_lifetime.stderr
@@ -4,10 +4,9 @@ error[E0597]: `x` does not live long enough
 LL |     let x = 22_u32;
    |         - binding `x` declared here
 LL |     let y: &u32 = (&x) as &'static u32;
-   |                   ^^^^----------------
+   |                   ^^^^    ------------ type annotation requires that `x` is borrowed for `'static`
    |                   |
    |                   borrowed value does not live long enough
-   |                   type annotation requires that `x` is borrowed for `'static`
 LL | }
    | - `x` dropped here while still borrowed
 
diff --git a/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
index 3e2706309b3..2ed0fadc065 100644
--- a/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
+++ b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
@@ -4,10 +4,9 @@ error[E0597]: `x` does not live long enough
 LL |     let x = 22_u32;
    |         - binding `x` declared here
 LL |     let y: &u32 = type_ascribe!(&x, &'static u32);
-   |                   --------------^^---------------
-   |                   |             |
-   |                   |             borrowed value does not live long enough
-   |                   type annotation requires that `x` is borrowed for `'static`
+   |                                 ^^  ------------ type annotation requires that `x` is borrowed for `'static`
+   |                                 |
+   |                                 borrowed value does not live long enough
 LL | }
    | - `x` dropped here while still borrowed
 
diff --git a/tests/ui/regions/regions-close-object-into-object-4.stderr b/tests/ui/regions/regions-close-object-into-object-4.stderr
index b8b414b7e12..f6a79be0947 100644
--- a/tests/ui/regions/regions-close-object-into-object-4.stderr
+++ b/tests/ui/regions/regions-close-object-into-object-4.stderr
@@ -30,12 +30,11 @@ error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:9:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |
    |     the parameter type `U` must be valid for the static lifetime...
    |     ...so that the type `U` will meet its required lifetime bounds
    |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 help: consider adding an explicit lifetime bound
    |
 LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
diff --git a/tests/ui/regions/regions-close-object-into-object-5.stderr b/tests/ui/regions/regions-close-object-into-object-5.stderr
index 4a2f4f847a3..881d9e03cdf 100644
--- a/tests/ui/regions/regions-close-object-into-object-5.stderr
+++ b/tests/ui/regions/regions-close-object-into-object-5.stderr
@@ -30,12 +30,11 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:5
    |
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |
    |     the parameter type `T` must be valid for the static lifetime...
    |     ...so that the type `T` will meet its required lifetime bounds
    |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 help: consider adding an explicit lifetime bound
    |
 LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
diff --git a/tests/ui/regions/regions-close-over-type-parameter-1.stderr b/tests/ui/regions/regions-close-over-type-parameter-1.stderr
index 1cd5b7f2250..7c8c5fe5cf6 100644
--- a/tests/ui/regions/regions-close-over-type-parameter-1.stderr
+++ b/tests/ui/regions/regions-close-over-type-parameter-1.stderr
@@ -2,7 +2,7 @@ error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:11:5
    |
 LL |     Box::new(v) as Box<dyn SomeTrait + 'static>
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |
    |     the parameter type `A` must be valid for the static lifetime...
    |     ...so that the type `A` will meet its required lifetime bounds
@@ -18,7 +18,7 @@ error[E0309]: the parameter type `A` may not live long enough
 LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
    |                     -- the parameter type `A` must be valid for the lifetime `'b` as defined here...
 LL |     Box::new(v) as Box<dyn SomeTrait + 'b>
-   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
    |
 help: consider adding an explicit lifetime bound
    |
diff --git a/tests/ui/suggestions/lifetimes/suggest-using-tick-underscore-lifetime-in-return-trait-object.stderr b/tests/ui/suggestions/lifetimes/suggest-using-tick-underscore-lifetime-in-return-trait-object.stderr
index 73fa5ddb146..fa203150444 100644
--- a/tests/ui/suggestions/lifetimes/suggest-using-tick-underscore-lifetime-in-return-trait-object.stderr
+++ b/tests/ui/suggestions/lifetimes/suggest-using-tick-underscore-lifetime-in-return-trait-object.stderr
@@ -4,7 +4,7 @@ error: lifetime may not live long enough
 LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
    |                       - let's call the lifetime of this reference `'1`
 LL |     Box::new(value) as Box<dyn Any>
-   |     ^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
    |
 help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound
    |
diff --git a/tests/ui/traits/trait-object-lifetime-default-note.rs b/tests/ui/traits/trait-object-lifetime-default-note.rs
index 31e3eb4ba41..275411ff61c 100644
--- a/tests/ui/traits/trait-object-lifetime-default-note.rs
+++ b/tests/ui/traits/trait-object-lifetime-default-note.rs
@@ -8,7 +8,7 @@ fn main() {
     //~| NOTE borrowed value does not live long enough
     //~| NOTE due to object lifetime defaults, `Box<dyn A>` actually means `Box<(dyn A + 'static)>`
     require_box(Box::new(r));
-    //~^ NOTE cast requires that `local` is borrowed for `'static`
+    //~^ NOTE coercion requires that `local` is borrowed for `'static`
 
     let _ = 0;
 } //~ NOTE `local` dropped here while still borrowed
diff --git a/tests/ui/traits/trait-object-lifetime-default-note.stderr b/tests/ui/traits/trait-object-lifetime-default-note.stderr
index 4244e34873a..8cb9bc0d800 100644
--- a/tests/ui/traits/trait-object-lifetime-default-note.stderr
+++ b/tests/ui/traits/trait-object-lifetime-default-note.stderr
@@ -7,7 +7,7 @@ LL |     let r = &local;
    |             ^^^^^^ borrowed value does not live long enough
 ...
 LL |     require_box(Box::new(r));
-   |                 ----------- cast requires that `local` is borrowed for `'static`
+   |                 ----------- coercion requires that `local` is borrowed for `'static`
 ...
 LL | }
    | - `local` dropped here while still borrowed
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr
index e6cb6a75399..0a969b611e9 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr
@@ -1,18 +1,18 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:11:13
+  --> $DIR/type-checking-test-3.rs:11:18
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
 LL |     let _ = x as &dyn Bar<'a>; // Error
-   |             ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |                  ^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:16:13
+  --> $DIR/type-checking-test-3.rs:16:18
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) {
    |                -- lifetime `'a` defined here
 LL |     let _ = x as &dyn Bar<'static>; // Error
-   |             ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |                  ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr
index ccced587577..090120a2327 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr
@@ -1,18 +1,18 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:19:13
+  --> $DIR/type-checking-test-4.rs:19:18
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
 LL |     let _ = x as &dyn Bar<'static, 'a>; // Error
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |                  ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:24:13
+  --> $DIR/type-checking-test-4.rs:24:18
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
 LL |     let _ = x as &dyn Bar<'a, 'static>; // Error
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |                  ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
   --> $DIR/type-checking-test-4.rs:30:5
diff --git a/tests/ui/traits/upcast_soundness_bug.rs b/tests/ui/traits/upcast_soundness_bug.rs
index 5eaa58f7efe..0ddae1d1417 100644
--- a/tests/ui/traits/upcast_soundness_bug.rs
+++ b/tests/ui/traits/upcast_soundness_bug.rs
@@ -57,7 +57,7 @@ pub fn user2() -> &'static dyn Trait<u8, u16> {
 fn main() {
     let p: *const dyn Trait<u8, u8> = &();
     let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
-    //~^ error: mismatched types
+    //~^ error: casting `*const dyn Trait<u8, u8>` as `*const dyn Trait<u8, u16>` is invalid
     let p = p as *const dyn Super<u16>; // <- this upcast accesses improper vtable entry
     // accessing from L__unnamed_2 the position for the 'Super<u16> vtable (pointer)',
     // thus reading 'null pointer for missing_method'
diff --git a/tests/ui/traits/upcast_soundness_bug.stderr b/tests/ui/traits/upcast_soundness_bug.stderr
index 5864abcdb41..19d1a5e5926 100644
--- a/tests/ui/traits/upcast_soundness_bug.stderr
+++ b/tests/ui/traits/upcast_soundness_bug.stderr
@@ -1,13 +1,11 @@
-error[E0308]: mismatched types
+error[E0606]: casting `*const dyn Trait<u8, u8>` as `*const dyn Trait<u8, u16>` is invalid
   --> $DIR/upcast_soundness_bug.rs:59:13
    |
 LL |     let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected trait object `dyn Trait<u8, u8>`
-              found trait object `dyn Trait<u8, u16>`
-   = help: `dyn Trait<u8, u16>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
+   = note: the trait objects may have different vtables
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0606`.