diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 51ee56080a2ce..be04fa7436b9a 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -337,9 +337,6 @@ declare_features! (
     /// Allows `#[track_caller]` to be used which provides
     /// accurate caller location reporting during panic (RFC 2091).
     (accepted, track_caller, "1.46.0", Some(47809)),
-    /// Allows dyn upcasting trait objects via supertraits.
-    /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
-    (accepted, trait_upcasting, "1.76.0", Some(65991)),
     /// Allows #[repr(transparent)] on univariant enums (RFC 2645).
     (accepted, transparent_enums, "1.42.0", Some(60405)),
     /// Allows indexing tuples.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 1ad75a692c7cd..eadb19f6fc36c 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -580,6 +580,9 @@ declare_features! (
     (unstable, thread_local, "1.0.0", Some(29594)),
     /// Allows defining `trait X = A + B;` alias items.
     (unstable, trait_alias, "1.24.0", Some(41517)),
+    /// Allows dyn upcasting trait objects via supertraits.
+    /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
+    (unstable, trait_upcasting, "1.56.0", Some(65991)),
     /// Allows for transmuting between arrays with sizes that contain generic consts.
     (unstable, transmute_generic_consts, "1.70.0", Some(109929)),
     /// Allows #[repr(transparent)] on unions (RFC 2645).
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 61236c07135cd..f08af9edcbbfc 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -627,6 +627,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         )];
 
         let mut has_unsized_tuple_coercion = false;
+        let mut has_trait_upcasting_coercion = None;
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -694,6 +695,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     // these here and emit a feature error if coercion doesn't fail
                     // due to another reason.
                     match impl_source {
+                        traits::ImplSource::Builtin(
+                            BuiltinImplSource::TraitUpcasting { .. },
+                            _,
+                        ) => {
+                            has_trait_upcasting_coercion =
+                                Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1)));
+                        }
                         traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
                             has_unsized_tuple_coercion = true;
                         }
@@ -704,6 +712,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             }
         }
 
+        if let Some((sub, sup)) = has_trait_upcasting_coercion
+            && !self.tcx().features().trait_upcasting
+        {
+            // Renders better when we erase regions, since they're not really the point here.
+            let (sub, sup) = self.tcx.erase_regions((sub, sup));
+            let mut err = feature_err(
+                &self.tcx.sess.parse_sess,
+                sym::trait_upcasting,
+                self.cause.span,
+                format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
+            );
+            err.note(format!("required when coercing `{source}` into `{target}`"));
+            err.emit();
+        }
+
         if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
             feature_err(
                 &self.tcx.sess.parse_sess,
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index 98bafc0f2637e..4673b801dc1db 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -5,6 +5,7 @@ use crate::{
 
 use rustc_hir as hir;
 use rustc_middle::ty;
+use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_span::sym;
 use rustc_trait_selection::traits::supertraits;
 
@@ -12,6 +13,9 @@ declare_lint! {
     /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
     /// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
     ///
+    /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized.
+    /// The `deref` functions will no longer be called implicitly, so there might be behavior change.
+    ///
     /// ### Example
     ///
     /// ```rust,compile_fail
@@ -40,10 +44,15 @@ declare_lint! {
     ///
     /// ### Explanation
     ///
-    /// The implicit dyn upcasting coercion take priority over those `Deref` impls.
+    /// The dyn upcasting coercion feature adds new coercion rules, taking priority
+    /// over certain other coercion rules, which will cause some behavior change.
     pub DEREF_INTO_DYN_SUPERTRAIT,
     Warn,
-    "`Deref` implementation usage with a supertrait trait object for output are shadow by implicit coercion",
+    "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
+        reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
+    };
 }
 
 declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index a4ab5527e3fc0..066c88cc6524a 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -39,7 +39,7 @@
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
-#![cfg_attr(bootstrap, feature(trait_upcasting))]
+#![feature(trait_upcasting)]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index ca6408bdf3ddb..9c0d3be0318c3 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -544,7 +544,6 @@ pub enum BuiltinSpecialModuleNameUsed {
 // deref_into_dyn_supertrait.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_supertrait_as_deref_target)]
-#[help]
 pub struct SupertraitAsDerefTarget<'a> {
     pub self_ty: Ty<'a>,
     pub supertrait_principal: PolyExistentialTraitRef<'a>,
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index e048268fad120..3206c6cf650e2 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -49,7 +49,7 @@
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
 #![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, feature(trait_upcasting))]
+#![feature(trait_upcasting)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
 #![feature(try_reserve_kind)]
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 73e06b8408562..38b1046ac53e2 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -9,10 +9,13 @@
 use hir::def_id::DefId;
 use hir::LangItem;
 use rustc_hir as hir;
+use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 
+use crate::traits;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::util;
 
 use super::BuiltinImplConditions;
@@ -723,6 +726,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         })
     }
 
+    /// Temporary migration for #89190
+    fn need_migrate_deref_output_trait_object(
+        &mut self,
+        ty: Ty<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        cause: &ObligationCause<'tcx>,
+    ) -> Option<ty::PolyExistentialTraitRef<'tcx>> {
+        let tcx = self.tcx();
+        if tcx.features().trait_upcasting {
+            return None;
+        }
+
+        // <ty as Deref>
+        let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
+
+        let obligation =
+            traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref));
+        if !self.infcx.predicate_may_hold(&obligation) {
+            return None;
+        }
+
+        self.infcx.probe(|_| {
+            let ty = traits::normalize_projection_type(
+                self,
+                param_env,
+                ty::AliasTy::new(tcx, tcx.lang_items().deref_target()?, trait_ref.args),
+                cause.clone(),
+                0,
+                // We're *intentionally* throwing these away,
+                // since we don't actually use them.
+                &mut vec![],
+            )
+            .ty()
+            .unwrap();
+
+            if let ty::Dynamic(data, ..) = ty.kind() { data.principal() } else { None }
+        })
+    }
+
     /// Searches for unsizing that might apply to `obligation`.
     fn assemble_candidates_for_unsizing(
         &mut self,
@@ -780,6 +822,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         let principal_a = a_data.principal().unwrap();
                         let target_trait_did = principal_def_id_b.unwrap();
                         let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
+                        if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object(
+                            source,
+                            obligation.param_env,
+                            &obligation.cause,
+                        ) {
+                            if deref_trait_ref.def_id() == target_trait_did {
+                                return;
+                            }
+                        }
 
                         for (idx, upcast_trait_ref) in
                             util::supertraits(self.tcx(), source_trait_ref).enumerate()
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c531117bed5ad..ac8b6f6b56714 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -111,7 +111,7 @@
 #![feature(slice_flatten)]
 #![feature(error_generic_member_access)]
 #![feature(error_in_core)]
-#![cfg_attr(bootstrap, feature(trait_upcasting))]
+#![feature(trait_upcasting)]
 #![feature(utf8_chunks)]
 #![feature(is_ascii_octdigit)]
 #![feature(get_many_mut)]
diff --git a/src/doc/unstable-book/src/language-features/trait-upcasting.md b/src/doc/unstable-book/src/language-features/trait-upcasting.md
new file mode 100644
index 0000000000000..3697ae38f9d81
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/trait-upcasting.md
@@ -0,0 +1,27 @@
+# `trait_upcasting`
+
+The tracking issue for this feature is: [#65991]
+
+[#65991]: https://github.com/rust-lang/rust/issues/65991
+
+------------------------
+
+The `trait_upcasting` feature adds support for trait upcasting coercion. This allows a
+trait object of type `dyn Bar` to be cast to a trait object of type `dyn Foo`
+so long as `Bar: Foo`.
+
+```rust,edition2018
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo {}
+
+trait Bar: Foo {}
+
+impl Foo for i32 {}
+
+impl<T: Foo + ?Sized> Bar for T {}
+
+let bar: &dyn Bar = &123;
+let foo: &dyn Foo = bar;
+```
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 1eb40ab826c45..70e9c443e90ec 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -11,7 +11,7 @@
 #![feature(round_ties_even)]
 #![feature(let_chains)]
 #![feature(lint_reasons)]
-#![cfg_attr(bootstrap, feature(trait_upcasting))]
+#![feature(trait_upcasting)]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
index 7d46ecd8f6ea8..648ac07c43ec9 100644
--- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
+++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
@@ -1,3 +1,6 @@
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
         10
diff --git a/src/tools/miri/tests/pass/box-custom-alloc.rs b/src/tools/miri/tests/pass/box-custom-alloc.rs
index 3d055961d15de..155e3d74ab9c1 100644
--- a/src/tools/miri/tests/pass/box-custom-alloc.rs
+++ b/src/tools/miri/tests/pass/box-custom-alloc.rs
@@ -1,6 +1,7 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
-#![feature(allocator_api)]
+#![allow(incomplete_features)] // for trait upcasting
+#![feature(allocator_api, trait_upcasting)]
 
 use std::alloc::Layout;
 use std::alloc::{AllocError, Allocator};
diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs
index ddaefeca3a3be..8432012a9ba52 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.rs
+++ b/src/tools/miri/tests/pass/dyn-upcast.rs
@@ -1,3 +1,6 @@
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
 fn main() {
     basic();
     diamond();
diff --git a/tests/ui/codegen/issue-99551.rs b/tests/ui/codegen/issue-99551.rs
index 9e203fba113c9..b223aff4e9492 100644
--- a/tests/ui/codegen/issue-99551.rs
+++ b/tests/ui/codegen/issue-99551.rs
@@ -1,4 +1,5 @@
 // build-pass
+#![feature(trait_upcasting)]
 
 pub trait A {}
 pub trait B {}
diff --git a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
index 0201c8897065c..a4eb669e32104 100644
--- a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
+++ b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
@@ -1,4 +1,4 @@
-#![feature(dyn_star)]
+#![feature(dyn_star, trait_upcasting)]
 //~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
 
 trait A: B {}
diff --git a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
index 7e2cf661369b9..1f7bfb1d5bdc5 100644
--- a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
+++ b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
@@ -1,7 +1,7 @@
 warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/no-unsize-coerce-dyn-trait.rs:1:12
    |
-LL | #![feature(dyn_star)]
+LL | #![feature(dyn_star, trait_upcasting)]
    |            ^^^^^^^^
    |
    = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
diff --git a/tests/ui/dyn-star/upcast.rs b/tests/ui/dyn-star/upcast.rs
index 7748cdda943c2..c667ac143a395 100644
--- a/tests/ui/dyn-star/upcast.rs
+++ b/tests/ui/dyn-star/upcast.rs
@@ -1,6 +1,6 @@
 // known-bug: #104800
 
-#![feature(dyn_star)]
+#![feature(dyn_star, trait_upcasting)]
 
 trait Foo: Bar {
     fn hello(&self);
diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr
index bdf77da713a0e..adef9525bf1fa 100644
--- a/tests/ui/dyn-star/upcast.stderr
+++ b/tests/ui/dyn-star/upcast.stderr
@@ -1,7 +1,7 @@
 warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/upcast.rs:3:12
    |
-LL | #![feature(dyn_star)]
+LL | #![feature(dyn_star, trait_upcasting)]
    |            ^^^^^^^^
    |
    = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
diff --git a/tests/ui/feature-gates/feature-gate-trait_upcasting.rs b/tests/ui/feature-gates/feature-gate-trait_upcasting.rs
new file mode 100644
index 0000000000000..e4102f1cfa75d
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-trait_upcasting.rs
@@ -0,0 +1,13 @@
+trait Foo {}
+
+trait Bar: Foo {}
+
+impl Foo for () {}
+
+impl Bar for () {}
+
+fn main() {
+    let bar: &dyn Bar = &();
+    let foo: &dyn Foo = bar;
+    //~^ ERROR trait upcasting coercion is experimental [E0658]
+}
diff --git a/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr b/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr
new file mode 100644
index 0000000000000..ce2f3c0a808ad
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr
@@ -0,0 +1,13 @@
+error[E0658]: cannot cast `dyn Bar` to `dyn Foo`, trait upcasting coercion is experimental
+  --> $DIR/feature-gate-trait_upcasting.rs:11:25
+   |
+LL |     let foo: &dyn Foo = bar;
+   |                         ^^^
+   |
+   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
+   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `&dyn Bar` into `&dyn Foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/next-solver/normalize-unsize-rhs.rs b/tests/ui/traits/next-solver/normalize-unsize-rhs.rs
index 6ca82d1b872c7..08bb0cf42e805 100644
--- a/tests/ui/traits/next-solver/normalize-unsize-rhs.rs
+++ b/tests/ui/traits/next-solver/normalize-unsize-rhs.rs
@@ -1,5 +1,6 @@
 // compile-flags: -Znext-solver
 // check-pass
+#![feature(trait_upcasting)]
 
 trait A {}
 trait B: A {}
diff --git a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs
index 2a482f7466865..8e0378e94f043 100644
--- a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs
+++ b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs
@@ -1,5 +1,6 @@
 // check-pass
 // compile-flags: -Znext-solver
+#![feature(trait_upcasting)]
 
 pub trait A {}
 pub trait B: A {}
diff --git a/tests/ui/traits/next-solver/upcast-right-substs.rs b/tests/ui/traits/next-solver/upcast-right-substs.rs
index 5e4d958c89591..5b4f6d4be0ca8 100644
--- a/tests/ui/traits/next-solver/upcast-right-substs.rs
+++ b/tests/ui/traits/next-solver/upcast-right-substs.rs
@@ -1,5 +1,6 @@
 // compile-flags: -Znext-solver
 // check-pass
+#![feature(trait_upcasting)]
 
 trait Foo: Bar<i32> + Bar<u32> {}
 
diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs
index 927a9d6b94f8a..4a5e445d1efbe 100644
--- a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs
+++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs
@@ -1,3 +1,4 @@
+#![feature(trait_upcasting)]
 #![feature(trait_alias)]
 
 // Although we *elaborate* `T: Alias` to `i32: B`, we should
diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr
index 1a410519a4edc..99c82b88d9c38 100644
--- a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr
+++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/alias-where-clause-isnt-supertrait.rs:26:5
+  --> $DIR/alias-where-clause-isnt-supertrait.rs:27:5
    |
 LL | fn test(x: &dyn C) -> &dyn B {
    |                       ------ expected `&dyn B` because of return type
diff --git a/tests/ui/traits/trait-upcasting/basic.rs b/tests/ui/traits/trait-upcasting/basic.rs
index 538cd8329cc64..570ec5160bfe9 100644
--- a/tests/ui/traits/trait-upcasting/basic.rs
+++ b/tests/ui/traits/trait-upcasting/basic.rs
@@ -1,5 +1,7 @@
 // run-pass
 
+#![feature(trait_upcasting)]
+
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs b/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs
index 4a379d9f875b8..eae5cf8d58d01 100644
--- a/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs
+++ b/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs
@@ -1,4 +1,5 @@
 // run-pass
+#![feature(trait_upcasting)]
 
 trait Foo<T: Default + ToString>: Bar<i32> + Bar<T> {}
 trait Bar<T: Default + ToString> {
diff --git a/tests/ui/traits/trait-upcasting/deref-lint-regions.stderr b/tests/ui/traits/trait-upcasting/deref-lint-regions.stderr
deleted file mode 100644
index 557a4420a3dbf..0000000000000
--- a/tests/ui/traits/trait-upcasting/deref-lint-regions.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-warning: this `Deref` implementation is covered by an implicit supertrait coercion
-  --> $DIR/deref-lint-regions.rs:8:1
-   |
-LL | impl<'a> Deref for dyn Foo<'a> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo<'_>` implements `Deref<Target = dyn Bar<'_>>` which conflicts with supertrait `Bar<'_>`
-LL |
-LL |     type Target = dyn Bar<'a>;
-   |     -------------------------- target type is a supertrait of `dyn Foo<'_>`
-   |
-   = help: consider removing this implementation or replacing it with a method instead
-   = note: `#[warn(deref_into_dyn_supertrait)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/traits/trait-upcasting/deref-lint.stderr b/tests/ui/traits/trait-upcasting/deref-lint.stderr
deleted file mode 100644
index 5a13659edf568..0000000000000
--- a/tests/ui/traits/trait-upcasting/deref-lint.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-warning: this `Deref` implementation is covered by an implicit supertrait coercion
-  --> $DIR/deref-lint.rs:9:1
-   |
-LL | impl<'a> Deref for dyn 'a + B {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn B` implements `Deref<Target = dyn A>` which conflicts with supertrait `A`
-...
-LL |     type Target = dyn A;
-   |     -------------------- target type is a supertrait of `dyn B`
-   |
-   = help: consider removing this implementation or replacing it with a method instead
-   = note: `#[warn(deref_into_dyn_supertrait)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs
index 366eae1a58a34..e4784fa41011b 100644
--- a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs
+++ b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs
@@ -15,6 +15,8 @@ impl Foo for () {
 }
 
 impl<'a> Deref for dyn Foo + 'a {
+    //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion
+    //~| WARN this will change its meaning in a future release!
     type Target = dyn Bar<u32> + 'a;
 
     fn deref(&self) -> &Self::Target {
@@ -30,5 +32,4 @@ fn main() {
     let x: &dyn Foo = &();
     let y = take_dyn(x);
     let z: u32 = y;
-    //~^ ERROR mismatched types
 }
diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr
index 193d09e350111..fa93e28c73bce 100644
--- a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr
+++ b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr
@@ -1,16 +1,19 @@
-error[E0308]: mismatched types
-  --> $DIR/deref-upcast-behavioral-change.rs:32:18
+error: this `Deref` implementation is covered by an implicit supertrait coercion
+  --> $DIR/deref-upcast-behavioral-change.rs:17:1
    |
-LL |     let z: u32 = y;
-   |            ---   ^ expected `u32`, found `i32`
-   |            |
-   |            expected due to this
+LL | impl<'a> Deref for dyn Foo + 'a {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref<Target = dyn Bar<u32>>` which conflicts with supertrait `Bar<i32>`
+...
+LL |     type Target = dyn Bar<u32> + 'a;
+   |     -------------------------------- target type is a supertrait of `dyn Foo`
    |
-help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
+note: the lint level is defined here
+  --> $DIR/deref-upcast-behavioral-change.rs:1:9
    |
-LL |     let z: u32 = y.try_into().unwrap();
-   |                   ++++++++++++++++++++
+LL | #![deny(deref_into_dyn_supertrait)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/diamond.rs b/tests/ui/traits/trait-upcasting/diamond.rs
index 9a78339a4ec84..a4f81c464b402 100644
--- a/tests/ui/traits/trait-upcasting/diamond.rs
+++ b/tests/ui/traits/trait-upcasting/diamond.rs
@@ -1,5 +1,7 @@
 // run-pass
 
+#![feature(trait_upcasting)]
+
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/fewer-associated.rs b/tests/ui/traits/trait-upcasting/fewer-associated.rs
index e7ca6fa5208ec..58e72d9d7ef57 100644
--- a/tests/ui/traits/trait-upcasting/fewer-associated.rs
+++ b/tests/ui/traits/trait-upcasting/fewer-associated.rs
@@ -3,6 +3,8 @@
 // revisions: current next
 //[next] compile-flags: -Znext-solver
 
+#![feature(trait_upcasting)]
+
 trait A: B {
     type Assoc;
 }
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
index 119b3109c6323..1538e2f3fd71a 100644
--- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/illegal-upcast-from-impl.rs:14:66
+  --> $DIR/illegal-upcast-from-impl.rs:16:66
    |
 LL | fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
    |                                        -----------------------   ^ expected trait `Super`, found trait `Sub`
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
index 119b3109c6323..1538e2f3fd71a 100644
--- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/illegal-upcast-from-impl.rs:14:66
+  --> $DIR/illegal-upcast-from-impl.rs:16:66
    |
 LL | fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
    |                                        -----------------------   ^ expected trait `Super`, found trait `Sub`
diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
index 5a493fd48b3f9..ffed8beb44845 100644
--- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
+++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
@@ -1,6 +1,8 @@
 // revisions: current next
 //[next] compile-flags: -Znext-solver
 
+#![feature(trait_upcasting)]
+
 trait Super {
     type Assoc;
 }
diff --git a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs
index 999f3b16f50d8..79fb643eacd01 100644
--- a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs
+++ b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs
@@ -1,4 +1,5 @@
 #![deny(deref_into_dyn_supertrait)]
+#![feature(trait_upcasting)] // remove this and the test compiles
 
 use std::ops::Deref;
 
diff --git a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr
index fcc80c6148f7d..6b6a26d1593fb 100644
--- a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr
+++ b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/inference-behavior-change-deref.rs:33:18
+  --> $DIR/inference-behavior-change-deref.rs:34:18
    |
 LL |     let z: u32 = y;
    |            ---   ^ expected `u32`, found `i32`
diff --git a/tests/ui/traits/trait-upcasting/invalid-upcast.rs b/tests/ui/traits/trait-upcasting/invalid-upcast.rs
index 9269a5e3e9ff6..e634bbd5ac6f5 100644
--- a/tests/ui/traits/trait-upcasting/invalid-upcast.rs
+++ b/tests/ui/traits/trait-upcasting/invalid-upcast.rs
@@ -1,3 +1,5 @@
+#![feature(trait_upcasting)]
+
 trait Foo {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/invalid-upcast.stderr b/tests/ui/traits/trait-upcasting/invalid-upcast.stderr
index e70b99d28c7e4..3aa21ee3dddfb 100644
--- a/tests/ui/traits/trait-upcasting/invalid-upcast.stderr
+++ b/tests/ui/traits/trait-upcasting/invalid-upcast.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:51:35
+  --> $DIR/invalid-upcast.rs:53:35
    |
 LL |     let _: &dyn std::fmt::Debug = baz;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Baz`
@@ -10,7 +10,7 @@ LL |     let _: &dyn std::fmt::Debug = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:53:24
+  --> $DIR/invalid-upcast.rs:55:24
    |
 LL |     let _: &dyn Send = baz;
    |            ---------   ^^^ expected trait `Send`, found trait `Baz`
@@ -21,7 +21,7 @@ LL |     let _: &dyn Send = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:55:24
+  --> $DIR/invalid-upcast.rs:57:24
    |
 LL |     let _: &dyn Sync = baz;
    |            ---------   ^^^ expected trait `Sync`, found trait `Baz`
@@ -32,7 +32,7 @@ LL |     let _: &dyn Sync = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:58:25
+  --> $DIR/invalid-upcast.rs:60:25
    |
 LL |     let bar: &dyn Bar = baz;
    |              --------   ^^^ expected trait `Bar`, found trait `Baz`
@@ -43,7 +43,7 @@ LL |     let bar: &dyn Bar = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:60:35
+  --> $DIR/invalid-upcast.rs:62:35
    |
 LL |     let _: &dyn std::fmt::Debug = bar;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Bar`
@@ -54,7 +54,7 @@ LL |     let _: &dyn std::fmt::Debug = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:62:24
+  --> $DIR/invalid-upcast.rs:64:24
    |
 LL |     let _: &dyn Send = bar;
    |            ---------   ^^^ expected trait `Send`, found trait `Bar`
@@ -65,7 +65,7 @@ LL |     let _: &dyn Send = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:64:24
+  --> $DIR/invalid-upcast.rs:66:24
    |
 LL |     let _: &dyn Sync = bar;
    |            ---------   ^^^ expected trait `Sync`, found trait `Bar`
@@ -76,7 +76,7 @@ LL |     let _: &dyn Sync = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:67:25
+  --> $DIR/invalid-upcast.rs:69:25
    |
 LL |     let foo: &dyn Foo = baz;
    |              --------   ^^^ expected trait `Foo`, found trait `Baz`
@@ -87,7 +87,7 @@ LL |     let foo: &dyn Foo = baz;
               found reference `&dyn Baz`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:69:35
+  --> $DIR/invalid-upcast.rs:71:35
    |
 LL |     let _: &dyn std::fmt::Debug = foo;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Foo`
@@ -98,7 +98,7 @@ LL |     let _: &dyn std::fmt::Debug = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:71:24
+  --> $DIR/invalid-upcast.rs:73:24
    |
 LL |     let _: &dyn Send = foo;
    |            ---------   ^^^ expected trait `Send`, found trait `Foo`
@@ -109,7 +109,7 @@ LL |     let _: &dyn Send = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:73:24
+  --> $DIR/invalid-upcast.rs:75:24
    |
 LL |     let _: &dyn Sync = foo;
    |            ---------   ^^^ expected trait `Sync`, found trait `Foo`
@@ -120,7 +120,7 @@ LL |     let _: &dyn Sync = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:76:25
+  --> $DIR/invalid-upcast.rs:78:25
    |
 LL |     let foo: &dyn Foo = bar;
    |              --------   ^^^ expected trait `Foo`, found trait `Bar`
@@ -131,7 +131,7 @@ LL |     let foo: &dyn Foo = bar;
               found reference `&dyn Bar`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:78:35
+  --> $DIR/invalid-upcast.rs:80:35
    |
 LL |     let _: &dyn std::fmt::Debug = foo;
    |            --------------------   ^^^ expected trait `Debug`, found trait `Foo`
@@ -142,7 +142,7 @@ LL |     let _: &dyn std::fmt::Debug = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:80:24
+  --> $DIR/invalid-upcast.rs:82:24
    |
 LL |     let _: &dyn Send = foo;
    |            ---------   ^^^ expected trait `Send`, found trait `Foo`
@@ -153,7 +153,7 @@ LL |     let _: &dyn Send = foo;
               found reference `&dyn Foo`
 
 error[E0308]: mismatched types
-  --> $DIR/invalid-upcast.rs:82:24
+  --> $DIR/invalid-upcast.rs:84:24
    |
 LL |     let _: &dyn Sync = foo;
    |            ---------   ^^^ expected trait `Sync`, found trait `Foo`
diff --git a/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs b/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
index 77ce627078f90..b672963ae9887 100644
--- a/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
+++ b/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
@@ -1,4 +1,5 @@
 // run-pass
+#![feature(trait_upcasting)]
 
 struct Test {
     func: Box<dyn FnMut() + 'static>,
diff --git a/tests/ui/traits/trait-upcasting/issue-11515.current.stderr b/tests/ui/traits/trait-upcasting/issue-11515.current.stderr
new file mode 100644
index 0000000000000..da7ac4cc04ebf
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/issue-11515.current.stderr
@@ -0,0 +1,13 @@
+error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental
+  --> $DIR/issue-11515.rs:10:38
+   |
+LL |     let test = Box::new(Test { func: closure });
+   |                                      ^^^^^^^
+   |
+   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
+   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/issue-11515.next.stderr b/tests/ui/traits/trait-upcasting/issue-11515.next.stderr
new file mode 100644
index 0000000000000..da7ac4cc04ebf
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/issue-11515.next.stderr
@@ -0,0 +1,13 @@
+error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental
+  --> $DIR/issue-11515.rs:10:38
+   |
+LL |     let test = Box::new(Test { func: closure });
+   |                                      ^^^^^^^
+   |
+   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
+   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/issue-11515.rs b/tests/ui/traits/trait-upcasting/issue-11515.rs
index a1edb53ec37b5..31ea2fb353cd2 100644
--- a/tests/ui/traits/trait-upcasting/issue-11515.rs
+++ b/tests/ui/traits/trait-upcasting/issue-11515.rs
@@ -1,4 +1,3 @@
-// check-pass
 // revisions: current next
 //[next] compile-flags: -Znext-solver
 
@@ -8,5 +7,5 @@ struct Test {
 
 fn main() {
     let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
-    let test = Box::new(Test { func: closure });
+    let test = Box::new(Test { func: closure }); //~ ERROR trait upcasting coercion is experimental [E0658]
 }
diff --git a/tests/ui/traits/trait-upcasting/lifetime.rs b/tests/ui/traits/trait-upcasting/lifetime.rs
index 6c65c38870f24..9825158c2dd38 100644
--- a/tests/ui/traits/trait-upcasting/lifetime.rs
+++ b/tests/ui/traits/trait-upcasting/lifetime.rs
@@ -1,5 +1,7 @@
 // run-pass
 
+#![feature(trait_upcasting)]
+
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/deref-lint-regions.rs b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs
similarity index 52%
rename from tests/ui/traits/trait-upcasting/deref-lint-regions.rs
rename to tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs
index 946305cbb2b4b..da1a9cc2775d0 100644
--- a/tests/ui/traits/trait-upcasting/deref-lint-regions.rs
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs
@@ -1,4 +1,4 @@
-// check-pass
+#![deny(deref_into_dyn_supertrait)]
 
 use std::ops::Deref;
 
@@ -6,7 +6,8 @@ trait Bar<'a> {}
 trait Foo<'a>: Bar<'a> {}
 
 impl<'a> Deref for dyn Foo<'a> {
-    //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion
+    //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion
+    //~| WARN this will change its meaning in a future release!
     type Target = dyn Bar<'a>;
 
     fn deref(&self) -> &Self::Target {
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr
new file mode 100644
index 0000000000000..a5f3660d4bcb0
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr
@@ -0,0 +1,19 @@
+error: this `Deref` implementation is covered by an implicit supertrait coercion
+  --> $DIR/migrate-lint-deny-regions.rs:8:1
+   |
+LL | impl<'a> Deref for dyn Foo<'a> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo<'_>` implements `Deref<Target = dyn Bar<'_>>` which conflicts with supertrait `Bar<'_>`
+...
+LL |     type Target = dyn Bar<'a>;
+   |     -------------------------- target type is a supertrait of `dyn Foo<'_>`
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
+note: the lint level is defined here
+  --> $DIR/migrate-lint-deny-regions.rs:1:9
+   |
+LL | #![deny(deref_into_dyn_supertrait)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/trait-upcasting/deref-lint.rs b/tests/ui/traits/trait-upcasting/migrate-lint-deny.rs
similarity index 58%
rename from tests/ui/traits/trait-upcasting/deref-lint.rs
rename to tests/ui/traits/trait-upcasting/migrate-lint-deny.rs
index 68838d2ae20dd..926b3649e01b3 100644
--- a/tests/ui/traits/trait-upcasting/deref-lint.rs
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny.rs
@@ -1,4 +1,4 @@
-// check-pass
+#![deny(deref_into_dyn_supertrait)]
 
 use std::ops::Deref;
 
@@ -7,7 +7,8 @@ trait A {}
 trait B: A {}
 
 impl<'a> Deref for dyn 'a + B {
-    //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion
+    //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion
+    //~| WARN this will change its meaning in a future release!
 
     type Target = dyn A;
     fn deref(&self) -> &Self::Target {
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr
new file mode 100644
index 0000000000000..29997a9b3d9c3
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr
@@ -0,0 +1,19 @@
+error: this `Deref` implementation is covered by an implicit supertrait coercion
+  --> $DIR/migrate-lint-deny.rs:9:1
+   |
+LL | impl<'a> Deref for dyn 'a + B {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn B` implements `Deref<Target = dyn A>` which conflicts with supertrait `A`
+...
+LL |     type Target = dyn A;
+   |     -------------------- target type is a supertrait of `dyn B`
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
+note: the lint level is defined here
+  --> $DIR/migrate-lint-deny.rs:1:9
+   |
+LL | #![deny(deref_into_dyn_supertrait)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs
index 2c9126c863d52..8a90a09ff0411 100644
--- a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs
@@ -10,6 +10,7 @@ trait Foo: Bar<i32> {
 
 impl<'a> Deref for dyn Foo + 'a {
     //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion
+    //~| WARN this will change its meaning in a future release!
     type Target = dyn Bar<u32> + 'a;
 
     fn deref(&self) -> &Self::Target {
diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr
index a447f9cf83b7a..6245da5a17604 100644
--- a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr
+++ b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr
@@ -3,11 +3,12 @@ warning: this `Deref` implementation is covered by an implicit supertrait coerci
    |
 LL | impl<'a> Deref for dyn Foo + 'a {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref<Target = dyn Bar<u32>>` which conflicts with supertrait `Bar<i32>`
-LL |
+...
 LL |     type Target = dyn Bar<u32> + 'a;
    |     -------------------------------- target type is a supertrait of `dyn Foo`
    |
-   = help: consider removing this implementation or replacing it with a method instead
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
    = note: `#[warn(deref_into_dyn_supertrait)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs
index 0e17c27671770..2e53a00a90e9c 100644
--- a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs
+++ b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs
@@ -1,4 +1,5 @@
 // check-fail
+#![feature(trait_upcasting)]
 
 trait Bar<T> {
     fn bar(&self, _: T) {}
diff --git a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr
index c888ccc1ebb0d..70ba1fcaf3838 100644
--- a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr
+++ b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/multiple-occurrence-ambiguousity.rs:19:26
+  --> $DIR/multiple-occurrence-ambiguousity.rs:20:26
    |
 LL |     let t: &dyn Bar<_> = s;
    |            -----------   ^ expected trait `Bar`, found trait `Foo`
diff --git a/tests/ui/traits/trait-upcasting/normalization.rs b/tests/ui/traits/trait-upcasting/normalization.rs
index b594969483a8c..24da1ec5dfb58 100644
--- a/tests/ui/traits/trait-upcasting/normalization.rs
+++ b/tests/ui/traits/trait-upcasting/normalization.rs
@@ -3,6 +3,8 @@
 // revisions: current next
 //[next] compile-flags: -Znext-solver
 
+#![feature(trait_upcasting)]
+
 trait Mirror {
     type Assoc;
 }
diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.rs b/tests/ui/traits/trait-upcasting/replace-vptr.rs
index 4a7304ec2d716..9ccfc9306ac0c 100644
--- a/tests/ui/traits/trait-upcasting/replace-vptr.rs
+++ b/tests/ui/traits/trait-upcasting/replace-vptr.rs
@@ -1,5 +1,7 @@
 // run-pass
 
+#![feature(trait_upcasting)]
+
 trait A {
     fn foo_a(&self);
 }
diff --git a/tests/ui/traits/trait-upcasting/struct.rs b/tests/ui/traits/trait-upcasting/struct.rs
index 64fa9ca1b5fa5..a3e41696956cb 100644
--- a/tests/ui/traits/trait-upcasting/struct.rs
+++ b/tests/ui/traits/trait-upcasting/struct.rs
@@ -1,5 +1,7 @@
 // run-pass
 
+#![feature(trait_upcasting)]
+
 use std::rc::Rc;
 use std::sync::Arc;
 
diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.rs b/tests/ui/traits/trait-upcasting/subtrait-method.rs
index 20277280440c5..136d15af0e8b2 100644
--- a/tests/ui/traits/trait-upcasting/subtrait-method.rs
+++ b/tests/ui/traits/trait-upcasting/subtrait-method.rs
@@ -1,3 +1,5 @@
+#![feature(trait_upcasting)]
+
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     fn a(&self) -> i32 {
         10
diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.stderr b/tests/ui/traits/trait-upcasting/subtrait-method.stderr
index 3fdf3f4816160..918159e845b9e 100644
--- a/tests/ui/traits/trait-upcasting/subtrait-method.stderr
+++ b/tests/ui/traits/trait-upcasting/subtrait-method.stderr
@@ -1,64 +1,64 @@
 error[E0599]: no method named `c` found for reference `&dyn Bar` in the current scope
-  --> $DIR/subtrait-method.rs:53:9
+  --> $DIR/subtrait-method.rs:55:9
    |
 LL |     bar.c();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:25:1
+  --> $DIR/subtrait-method.rs:27:1
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
 
 error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:57:9
+  --> $DIR/subtrait-method.rs:59:9
    |
 LL |     foo.b();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `b`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:15:1
+  --> $DIR/subtrait-method.rs:17:1
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
 
 error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:59:9
+  --> $DIR/subtrait-method.rs:61:9
    |
 LL |     foo.c();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:25:1
+  --> $DIR/subtrait-method.rs:27:1
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
 
 error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:63:9
+  --> $DIR/subtrait-method.rs:65:9
    |
 LL |     foo.b();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `b`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:15:1
+  --> $DIR/subtrait-method.rs:17:1
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
 
 error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
-  --> $DIR/subtrait-method.rs:65:9
+  --> $DIR/subtrait-method.rs:67:9
    |
 LL |     foo.c();
    |         ^ help: there is a method with a similar name: `a`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
-  --> $DIR/subtrait-method.rs:25:1
+  --> $DIR/subtrait-method.rs:27:1
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr
index 47ffa68b8ff88..10c22440a8346 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr
@@ -1,5 +1,5 @@
 error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-1.rs:17:13
+  --> $DIR/type-checking-test-1.rs:19:13
    |
 LL |     let _ = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr
index 47ffa68b8ff88..10c22440a8346 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr
@@ -1,5 +1,5 @@
 error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-1.rs:17:13
+  --> $DIR/type-checking-test-1.rs:19:13
    |
 LL |     let _ = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs
index 7d3deeeaa6173..54c3c5e0c28f5 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs
@@ -1,6 +1,8 @@
 // revisions: current next
 //[next] compile-flags: -Znext-solver
 
+#![feature(trait_upcasting)]
+
 trait Foo: Bar<i32> + Bar<u32> {}
 trait Bar<T> {
     fn bar(&self) -> Option<T> {
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs
index b4df0f5a90258..b024b27750bc6 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs
@@ -1,3 +1,5 @@
+#![feature(trait_upcasting)]
+
 trait Foo<T>: Bar<i32> + Bar<T> {}
 trait Bar<T> {
     fn bar(&self) -> Option<T> {
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr
index f84ea93dc6792..3e59b9d33634a 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr
@@ -1,11 +1,11 @@
 error[E0605]: non-primitive cast: `&dyn Foo<i32>` as `&dyn Bar<u32>`
-  --> $DIR/type-checking-test-2.rs:17:13
+  --> $DIR/type-checking-test-2.rs:19:13
    |
 LL |     let _ = x as &dyn Bar<u32>; // Error
    |             ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>`
-  --> $DIR/type-checking-test-2.rs:22:13
+  --> $DIR/type-checking-test-2.rs:24:13
    |
 LL |     let a = x as &dyn Bar<_>; // Ambiguous
    |             ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.rs b/tests/ui/traits/trait-upcasting/type-checking-test-3.rs
index 3685569d98d1a..b2db3a127974c 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-3.rs
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.rs
@@ -1,3 +1,5 @@
+#![feature(trait_upcasting)]
+
 trait Foo<'a>: Bar<'a> {}
 trait Bar<'a> {}
 
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 640a6066268de..e6cb6a753998f 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:9:13
+  --> $DIR/type-checking-test-3.rs:11:13
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
@@ -7,7 +7,7 @@ LL |     let _ = x as &dyn Bar<'a>; // Error
    |             ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-3.rs:14:13
+  --> $DIR/type-checking-test-3.rs:16:13
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) {
    |                -- lifetime `'a` defined here
diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.rs b/tests/ui/traits/trait-upcasting/type-checking-test-4.rs
index 65391502386de..f40c48f0d125f 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-4.rs
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.rs
@@ -1,3 +1,5 @@
+#![feature(trait_upcasting)]
+
 trait Foo<'a>: Bar<'a, 'a> {}
 trait Bar<'a, 'b> {
     fn get_b(&self) -> Option<&'a u32> {
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 7e7548955d39d..8d506e5807ece 100644
--- a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr
+++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:13:13
+  --> $DIR/type-checking-test-4.rs:15:13
    |
 LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
@@ -7,7 +7,7 @@ LL |     let _ = x as &dyn Bar<'static, 'a>; // Error
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:18:13
+  --> $DIR/type-checking-test-4.rs:20:13
    |
 LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
    |                -- lifetime `'a` defined here
@@ -15,7 +15,7 @@ LL |     let _ = x as &dyn Bar<'a, 'static>; // Error
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:24:5
+  --> $DIR/type-checking-test-4.rs:26:5
    |
 LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL |     y.get_b() // ERROR
    |     ^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:29:5
+  --> $DIR/type-checking-test-4.rs:31:5
    |
 LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
@@ -32,7 +32,7 @@ LL |     <_ as Bar>::get_b(x) // ERROR
    |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:34:5
+  --> $DIR/type-checking-test-4.rs:36:5
    |
 LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
@@ -40,7 +40,7 @@ LL |     <_ as Bar<'_, '_>>::get_b(x) // ERROR
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/type-checking-test-4.rs:42:5
+  --> $DIR/type-checking-test-4.rs:44:5
    |
 LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                -- lifetime `'a` defined here
diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr
new file mode 100644
index 0000000000000..f1f0cd3095773
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr
@@ -0,0 +1,13 @@
+error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
+  --> $DIR/upcast-through-struct-tail.rs:10:5
+   |
+LL |     x
+   |     ^
+   |
+   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
+   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `Box<Wrapper<(dyn A + 'a)>>` into `Box<Wrapper<(dyn B + 'a)>>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr
new file mode 100644
index 0000000000000..f1f0cd3095773
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr
@@ -0,0 +1,13 @@
+error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
+  --> $DIR/upcast-through-struct-tail.rs:10:5
+   |
+LL |     x
+   |     ^
+   |
+   = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
+   = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `Box<Wrapper<(dyn A + 'a)>>` into `Box<Wrapper<(dyn B + 'a)>>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs
index f8cf793e4a49c..948f058e5287b 100644
--- a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs
+++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs
@@ -1,4 +1,3 @@
-// check-pass
 // revisions: current next
 //[next] compile-flags: -Znext-solver
 
@@ -9,6 +8,7 @@ trait B {}
 
 fn test<'a>(x: Box<Wrapper<dyn A + 'a>>) -> Box<Wrapper<dyn B + 'a>> {
     x
+    //~^ ERROR cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental
 }
 
 fn main() {}
diff --git a/tests/ui/traits/upcast_soundness_bug.rs b/tests/ui/traits/upcast_soundness_bug.rs
new file mode 100644
index 0000000000000..32e32850925f7
--- /dev/null
+++ b/tests/ui/traits/upcast_soundness_bug.rs
@@ -0,0 +1,69 @@
+#![feature(trait_upcasting)]
+// known-bug: #120222
+// check-pass
+//! This will segfault at runtime.
+
+pub trait SupSupA {
+    fn method(&self) {}
+}
+pub trait SupSupB {}
+impl<T> SupSupA for T {}
+impl<T> SupSupB for T {}
+
+pub trait Super<T>: SupSupA + SupSupB {}
+
+pub trait Unimplemented {}
+
+pub trait Trait<T1, T2>: Super<T1> + Super<T2> {
+    fn missing_method(&self)
+    where
+        T1: Unimplemented,
+    {
+    }
+}
+
+impl<S, T> Super<T> for S {}
+
+impl<S, T1, T2> Trait<T1, T2> for S {}
+
+#[inline(never)]
+pub fn user1() -> &'static dyn Trait<u8, u8> {
+    &()
+    /* VTABLE:
+    .L__unnamed_2:
+            .quad   core::ptr::drop_in_place<()>
+            .asciz  "\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000"
+            .quad   example::SupSupA::method
+            .quad   .L__unnamed_4 // SupSupB vtable (pointer)
+            .zero   8             // null pointer for missing_method
+    */
+}
+
+#[inline(never)]
+pub fn user2() -> &'static dyn Trait<u8, u16> {
+    &()
+    /* VTABLE:
+    .L__unnamed_3:
+            .quad   core::ptr::drop_in_place<()>
+            .asciz  "\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000"
+            .quad   example::SupSupA::method
+            .quad   .L__unnamed_4 // SupSupB vtable (pointer)
+            .quad   .L__unnamed_5 // Super<u16> vtable (pointer)
+            .zero   8             // null pointer for missing_method
+    */
+}
+
+fn main() {
+    let p: *const dyn Trait<u8, u8> = &();
+    let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
+    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'
+
+    let p = p as *const dyn SupSupB; // <- this upcast dereferences (null) pointer from that entry
+    // to read the SupSupB vtable (pointer)
+
+    // SEGFAULT
+
+    println!("{:?}", p);
+}